mirror of https://github.com/wg-easy/wg-easy
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
105 lines
2.6 KiB
105 lines
2.6 KiB
import type { DBType } from '#db/sqlite';
|
|
import { eq, sql } from 'drizzle-orm';
|
|
import { user } from './schema';
|
|
import type { ID } from '../../schema';
|
|
|
|
function createPreparedStatement(db: DBType) {
|
|
return {
|
|
findAll: db.query.user.findMany().prepare(),
|
|
findById: db.query.user
|
|
.findFirst({ where: eq(user.id, sql.placeholder('id')) })
|
|
.prepare(),
|
|
findByUsername: db.query.user
|
|
.findFirst({
|
|
where: eq(user.username, sql.placeholder('username')),
|
|
})
|
|
.prepare(),
|
|
update: db
|
|
.update(user)
|
|
.set({
|
|
name: sql.placeholder('name') as never as string,
|
|
email: sql.placeholder('email') as never as string,
|
|
})
|
|
.where(eq(user.id, sql.placeholder('id')))
|
|
.prepare(),
|
|
};
|
|
}
|
|
|
|
export class UserService {
|
|
#db: DBType;
|
|
#statements: ReturnType<typeof createPreparedStatement>;
|
|
|
|
constructor(db: DBType) {
|
|
this.#db = db;
|
|
this.#statements = createPreparedStatement(db);
|
|
}
|
|
|
|
async getAll() {
|
|
return this.#statements.findAll.execute();
|
|
}
|
|
|
|
async get(id: ID) {
|
|
return this.#statements.findById.execute({ id });
|
|
}
|
|
|
|
async getByUsername(username: string) {
|
|
return this.#statements.findByUsername.execute({ username });
|
|
}
|
|
|
|
async create(username: string, password: string) {
|
|
const hash = await hashPassword(password);
|
|
|
|
return this.#db.transaction(async (tx) => {
|
|
const oldUser = await this.getByUsername(username);
|
|
|
|
if (oldUser) {
|
|
throw new Error('User already exists');
|
|
}
|
|
|
|
const userCount = await tx.$count(user);
|
|
|
|
await tx.insert(user).values({
|
|
password: hash,
|
|
username,
|
|
email: null,
|
|
name: 'Administrator',
|
|
role: userCount === 0 ? roles.ADMIN : roles.CLIENT,
|
|
enabled: true,
|
|
});
|
|
});
|
|
}
|
|
|
|
async update(id: ID, name: string, email: string | null) {
|
|
return this.#statements.update.execute({ id, name, email });
|
|
}
|
|
|
|
async updatePassword(id: ID, currentPassword: string, newPassword: string) {
|
|
const hash = await hashPassword(newPassword);
|
|
|
|
return this.#db.transaction(async (tx) => {
|
|
// get user again to avoid password changing while request
|
|
const txUser = await tx.query.user
|
|
.findFirst({ where: eq(user.id, id) })
|
|
.execute();
|
|
|
|
if (!txUser) {
|
|
throw new Error('User not found');
|
|
}
|
|
|
|
const passwordValid = await isPasswordValid(
|
|
currentPassword,
|
|
txUser.password
|
|
);
|
|
|
|
if (!passwordValid) {
|
|
throw new Error('Invalid password');
|
|
}
|
|
|
|
await tx
|
|
.update(user)
|
|
.set({ password: hash })
|
|
.where(eq(user.id, id))
|
|
.execute();
|
|
});
|
|
}
|
|
}
|
|
|