76 lines
1.9 KiB
TypeScript
76 lines
1.9 KiB
TypeScript
import { BcryptCrypto, Crypto } from "./crypto.ts";
|
|
import { Database } from "./database.ts";
|
|
import { _, Err, Ok, Result } from "./utils.ts";
|
|
|
|
export type CreateUserReq = {
|
|
username: string;
|
|
password: string;
|
|
};
|
|
|
|
export type CreateUserError =
|
|
| "internal"
|
|
| "username empty"
|
|
| "password empty"
|
|
| "username taken";
|
|
|
|
export type UserInfoRes = {
|
|
id: number;
|
|
username: string;
|
|
};
|
|
export type UserInfoError =
|
|
| "internal"
|
|
| "not found";
|
|
|
|
export class Users {
|
|
public constructor(
|
|
private db: Database,
|
|
private crypto: Crypto = new BcryptCrypto(),
|
|
) {}
|
|
|
|
public async createUser(
|
|
req: CreateUserReq,
|
|
): Promise<Result<_, CreateUserError>> {
|
|
if (req.username === "") {
|
|
return Err("username empty");
|
|
}
|
|
if (req.password === "") {
|
|
return Err("password empty");
|
|
}
|
|
const userExistsResult = await this.db.userWithUsernameExists(
|
|
req.username,
|
|
);
|
|
if (!userExistsResult.ok) {
|
|
return Err("internal");
|
|
}
|
|
if (userExistsResult.value) {
|
|
return Err("username taken");
|
|
}
|
|
const passwordHash = await this.crypto.hash(req.password);
|
|
const createResult = await this.db.createUser({
|
|
username: req.username,
|
|
passwordHash,
|
|
});
|
|
if (!createResult.ok) {
|
|
return Err("internal");
|
|
}
|
|
return Ok(_);
|
|
}
|
|
|
|
public async userInfo(
|
|
id: number,
|
|
): Promise<Result<UserInfoRes, UserInfoError>> {
|
|
const queryResult = await this.db.userWithId(id);
|
|
if (!queryResult.ok) {
|
|
return Err("internal");
|
|
}
|
|
if (!queryResult.value.some) {
|
|
return Err("not found");
|
|
}
|
|
const user = queryResult.value.value;
|
|
return Ok({
|
|
id: user.id,
|
|
username: user.username,
|
|
});
|
|
}
|
|
}
|