grill-blog/users.ts

76 lines
1.9 KiB
TypeScript
Raw Permalink Normal View History

2024-05-13 22:50:54 +01:00
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,
});
}
}