initial commit, boilerplate stuff
This commit is contained in:
130
api/services/user-service.ts
Normal file
130
api/services/user-service.ts
Normal file
@@ -0,0 +1,130 @@
|
||||
import {
|
||||
APIErrorCode,
|
||||
APIException,
|
||||
type RegisterUserRequest,
|
||||
type UpdateUserRequest,
|
||||
type User,
|
||||
} from "../model/interfaces.ts";
|
||||
import { db, isUserRow, userApiToRow, userRowToApi } from "../model/db.ts";
|
||||
|
||||
import { hashPassword } from "../lib/jwt.ts";
|
||||
|
||||
export async function createUser(
|
||||
request: RegisterUserRequest,
|
||||
): Promise<User> {
|
||||
const userId = crypto.randomUUID();
|
||||
const createdAt = new Date();
|
||||
|
||||
const existingUser = db.prepare(
|
||||
"SELECT id FROM users WHERE username = ?;",
|
||||
).get(request.username);
|
||||
|
||||
if (existingUser) {
|
||||
throw new APIException(
|
||||
APIErrorCode.VALIDATION_ERROR,
|
||||
400,
|
||||
"Username already exists",
|
||||
);
|
||||
}
|
||||
|
||||
const passwordHash = await hashPassword(request.password);
|
||||
|
||||
db.prepare(
|
||||
`INSERT INTO users (id, username, password_hash, is_admin, created_at)
|
||||
VALUES (?, ?, ?, ?, ?);`,
|
||||
).run(
|
||||
userId,
|
||||
request.username,
|
||||
passwordHash,
|
||||
0,
|
||||
createdAt.toISOString(),
|
||||
);
|
||||
|
||||
return {
|
||||
id: userId,
|
||||
username: request.username,
|
||||
passwordHash,
|
||||
isAdmin: false,
|
||||
createdAt,
|
||||
};
|
||||
}
|
||||
|
||||
export function getUserById(userId: string): User {
|
||||
const userRow = db.prepare(
|
||||
`SELECT id, username, password_hash, is_admin, created_at
|
||||
FROM users WHERE id = ?`,
|
||||
).get(userId);
|
||||
|
||||
if (!userRow || !isUserRow(userRow)) {
|
||||
throw new APIException(APIErrorCode.NOT_FOUND, 404, "User not found");
|
||||
}
|
||||
|
||||
return userRowToApi(userRow);
|
||||
}
|
||||
|
||||
export function getUserByUsername(username: string): User {
|
||||
const userRow = db.prepare(
|
||||
`SELECT id, username, password_hash, is_admin, created_at
|
||||
FROM users WHERE username = ?`,
|
||||
).get(username);
|
||||
|
||||
if (!userRow || !isUserRow(userRow)) {
|
||||
throw new APIException(APIErrorCode.NOT_FOUND, 404, "User not found");
|
||||
}
|
||||
|
||||
return userRowToApi(userRow);
|
||||
}
|
||||
|
||||
export function listUsers(): User[] {
|
||||
const userRows = db.prepare(
|
||||
`SELECT id, username, password_hash, is_admin, created_at FROM users`,
|
||||
).all();
|
||||
|
||||
if (!userRows || !userRows.every(isUserRow)) {
|
||||
throw new APIException(APIErrorCode.NOT_FOUND, 404, "No user found");
|
||||
}
|
||||
|
||||
return userRows.map(userRowToApi);
|
||||
}
|
||||
|
||||
export async function updateUser(
|
||||
userId: string,
|
||||
request: UpdateUserRequest,
|
||||
): Promise<User> {
|
||||
const user = getUserById(userId);
|
||||
|
||||
const { password, ...requestFields } = request;
|
||||
|
||||
const updatedUser: User = {
|
||||
...user,
|
||||
passwordHash: password ? await hashPassword(password) : user.passwordHash,
|
||||
...requestFields,
|
||||
};
|
||||
|
||||
const updatedUserRow = userApiToRow(updatedUser);
|
||||
|
||||
const userResult = db.prepare(
|
||||
`UPDATE users SET username = ?, password_hash = ?, is_admin = ? WHERE id = ?`,
|
||||
).run(
|
||||
updatedUserRow.username,
|
||||
updatedUserRow.password_hash,
|
||||
updatedUserRow.is_admin,
|
||||
updatedUserRow.id,
|
||||
);
|
||||
|
||||
if (userResult.changes === 0) {
|
||||
throw new APIException(APIErrorCode.NOT_FOUND, 404, "Dump not found");
|
||||
}
|
||||
|
||||
return updatedUser;
|
||||
}
|
||||
|
||||
export function deleteUser(userId: string): void {
|
||||
const result = db.prepare(
|
||||
`DELETE FROM users WHERE id = ?;`,
|
||||
).run(userId);
|
||||
|
||||
if (result.changes === 0) {
|
||||
throw new APIException(APIErrorCode.NOT_FOUND, 404, "User not found");
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user