import { env } from "cloudflare:workers"; import { batch, first, stmt } from "./db"; import { hashPassword, randomId } from "./crypto"; import { badRequest, conflict } from "./errors"; export async function accountNameTaken(name: string): Promise { return (await first<{ id: string }>("SELECT id FROM accounts WHERE name = ?", name)) !== null; } export function signupsEnabled(): boolean { return env.SIGNUPS_ENABLED !== "false"; } export function githubOAuthEnabled(): boolean { return Boolean(env.GITHUB_CLIENT_ID && env.GITHUB_CLIENT_SECRET); } export async function createUser(input: { name: string; email: string; password: string | null; githubId: string | null; displayName: string | null; }): Promise { if (await accountNameTaken(input.name)) throw conflict("That username is already taken"); if (await first<{ account_id: string }>("SELECT account_id FROM users WHERE email = ?", input.email)) { throw conflict("An account with that email already exists"); } const isFirstUser = (await first<{ count: number }>("SELECT COUNT(*) AS count FROM users"))?.count === 0; if (!isFirstUser && !signupsEnabled()) throw badRequest("Sign ups are disabled on this instance"); const id = randomId(); const passwordHash = input.password ? await hashPassword(input.password) : null; await batch([ stmt( "INSERT INTO accounts (id, name, kind, display_name, created_at) VALUES (?, ?, 'user', ?, ?)", id, input.name, input.displayName, Date.now(), ), stmt( "INSERT INTO users (account_id, email, password_hash, github_id, is_admin) VALUES (?, ?, ?, ?, ?)", id, input.email, passwordHash, input.githubId, isFirstUser ? 1 : 0, ), ]); return id; } export async function createOrg(name: string, displayName: string | null, ownerId: string): Promise { if (await accountNameTaken(name)) throw conflict("That name is already taken"); const id = randomId(); const now = Date.now(); await batch([ stmt( "INSERT INTO accounts (id, name, kind, display_name, created_at) VALUES (?, ?, 'org', ?, ?)", id, name, displayName, now, ), stmt("INSERT INTO org_members (org_id, user_id, role, created_at) VALUES (?, ?, 'owner', ?)", id, ownerId, now), ]); return id; }