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> { 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> { 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, }); } }