UNPKG

@fdm-monster/server

Version:

FDM Monster is a bulk OctoPrint, Klipper, PrusaLink and BambuLab manager to set up, configure and monitor 3D printers. Our aim is to provide neat overview over your farm.

144 lines (143 loc) 5.91 kB
import { InternalServerException, NotFoundException } from "../../exceptions/runtime.exceptions.js"; import { BaseService } from "./base.service.js"; import { validateInput } from "../../handlers/validators.js"; import { User } from "../../entities/user.entity.js"; import { ROLES } from "../../constants/authorization.constants.js"; import { UserDto } from "../interfaces/user.dto.js"; import "../../entities/index.js"; import { newPasswordSchema, registerUserSchema } from "../validators/user-service.validation.js"; import { comparePasswordHash, hashPassword } from "../../utils/crypto.utils.js"; import { In } from "typeorm"; //#region src/services/orm/user.service.ts var UserService = class extends BaseService(User, UserDto) { constructor(typeormService, userRoleService, roleService) { super(typeormService); this.userRoleService = userRoleService; this.roleService = roleService; } toDto(user) { const roleIds = (user.roles ?? []).map((r) => r.roleId); return { id: user.id, createdAt: user.createdAt, isVerified: user.isVerified, isDemoUser: user.isDemoUser, isRootUser: user.isRootUser, username: user.username, needsPasswordChange: user.needsPasswordChange, roles: this.roleService.roleIdsToRoleNames(roleIds) }; } listUsers(limit) { return this.list({ take: limit }); } async getUser(userId) { return this.get(userId); } async getUserRoles(userId) { const roleIds = (await this.userRoleService.listUserRoles(userId)).map((ur) => ur.roleId); return this.roleService.roleIdsToRoleNames(roleIds); } findRootUsers() { return this.repository.findBy({ isRootUser: true }); } findVerifiedUsers() { return this.repository.findBy({ isVerified: true }); } async isUserRootUser(userId) { return (await this.get(userId)).isRootUser; } async deleteUser(userId) { const user = await this.getUser(userId); if (user.isRootUser) throw new InternalServerException("Cannot delete a root user"); if (!user.roles?.length) throw new InternalServerException("User:roles relation not loaded, cannot perform deletion role check"); const role = this.roleService.getRoleByName(ROLES.ADMIN); if (user.roles.find((r) => r.roleId == role.id)) { const administrators = await this.findUsersByRoleId(role.id); if (administrators?.length === 1 && administrators[0].id === userId) throw new InternalServerException("Cannot delete the last user with ADMIN role"); } await this.delete(userId); } findRawByUsername(username) { return this.repository.findOneBy({ username }); } async getDemoUserId() { return (await this.repository.findOneBy({ isDemoUser: true }))?.id; } async setIsRootUserById(userId, isRootUser) { if (!await this.getUser(userId)) throw new NotFoundException("User not found"); if (!isRootUser) { const rootUsers = await this.findRootUsers(); if (rootUsers.length === 1 && rootUsers[0].id === userId) throw new InternalServerException("Cannot set the last root user to non-root user"); } await this.update(userId, { isRootUser }); } async setUserRoles(userId, roles) { const roleIds = roles.map((roleName) => this.roleService.getRoleByName(roleName).id); await this.userRoleService.setUserRoles(userId, roleIds); return await this.get(userId); } async setVerifiedById(userId, isVerified) { const user = await this.getUser(userId); if (!user) throw new NotFoundException("User not found"); if (!isVerified) { if (user.isRootUser) throw new InternalServerException("Cannot set a owner (root user) to unverified"); if ((await this.findVerifiedUsers()).length === 1) throw new InternalServerException("Cannot set the last user to unverified"); } await this.update(userId, { isVerified }); } async updatePasswordById(userId, oldPassword, newPassword) { const user = await this.getUser(userId); if (!user) throw new NotFoundException("User not found"); if (!comparePasswordHash(oldPassword, user.passwordHash)) throw new NotFoundException("User old password incorrect"); const { password } = await validateInput({ password: newPassword }, newPasswordSchema); const passwordHash = hashPassword(password); return await this.update(userId, { passwordHash, needsPasswordChange: false }); } async updatePasswordUnsafeByUsername(username, newPassword) { const { password } = await validateInput({ password: newPassword }, newPasswordSchema); const passwordHash = hashPassword(password); const user = await this.findRawByUsername(username); if (!user) throw new NotFoundException("User not found"); return await this.update(user.id, { passwordHash, needsPasswordChange: false }); } async updatePasswordHashUnsafeByUsername(username, passwordHash) { const user = await this.findRawByUsername(username); if (!user) throw new NotFoundException("User not found"); return await this.update(user.id, { passwordHash, needsPasswordChange: false }); } updateUsernameById(userId, newUsername) { return this.update(userId, { username: newUsername }); } async register(input) { const { username, password, roles, isDemoUser, isRootUser, needsPasswordChange, isVerified } = await validateInput(input, registerUserSchema); const passwordHash = hashPassword(password); const result = await this.create({ username, passwordHash, isVerified: isVerified ?? false, isDemoUser: isDemoUser ?? false, isRootUser: isRootUser ?? false, needsPasswordChange: needsPasswordChange ?? true }); const roleIds = roles.map((roleName) => this.roleService.getRoleByName(roleName).id); await this.userRoleService.setUserRoles(result.id, roleIds); return this.get(result.id); } async findUsersByRoleId(roleId) { const ids = (await this.userRoleService.listByRoleId(roleId)).map((u) => u.id); return this.repository.findBy({ id: In(ids) }); } }; //#endregion export { UserService }; //# sourceMappingURL=user.service.js.map