import { validationResult } from 'express-validator'; import { SecurityManager } from '../managers/SecurityManager'; import { CryptoService } from '../services/CryptoService'; import { TemporalTokenMongoManager } from '../db/mongo/TemporalTokenMongoManager'; import { BaseController } from './BaseController'; import { MailerService } from '../services/mailer/MailerService'; import { NamespacesService } from '../services/NamespacesService'; import { UsersService } from '../services/UsersService'; import { Request, Response } from 'express'; export class UserController extends BaseController { security = new SecurityManager(); temporalTokenManager = new TemporalTokenMongoManager(); usersService = new UsersService(); mailService = new MailerService(); cryptoService = new CryptoService(); namespacesService = new NamespacesService(); constructor() { super(); } async getNamespaces(req: Request, res: Response) { return await this.namespacesService.getNamespaces(); } async getUser(req: Request, res: Response) { try { const { id } = req.params; const user = await this.usersService.getById(id); res.json(user).status(200).end(); } catch (error) { this.handleError(res, error); } } async createUser(req: Request, res: Response) { const user = req.body; try { const validation = validationResult(req); if (!validation.isEmpty()) { res.status(400).json({ errors: validation.array() }); return; } await this.usersService.createUser(user); res.status(201).end(); } catch (error) { this.handleError(res, error); } } async updateUserNamespace(req: Request, res: Response) { try { const { userId, namespaceId } = req.params; return await this.usersService.updateUserNamespace(userId, namespaceId); } catch (error) { this.handleError(res, error); } } async resetUserNamespace(req: Request, res: Response) { try { const { userId } = req.params; const defaultNS = await this.namespacesService.getDefaultNamespace(); if (!defaultNS._id) { throw new Error('Default namespace not found'); } return await this.usersService.updateUserNamespace(userId, defaultNS._id.toString()); } catch (error) { this.handleError(res, error); } } async updateUser(req: Request, res: Response) { const user = req.body; try { const validation = validationResult(req); if (!validation.isEmpty()) { res.status(400).json({ errors: validation.array() }); return; } const { id } = req.params; await this.usersService.updateUser(user, id); res.status(200).end(); } catch (error) { this.handleError(res, error); } } async deleteUser(req: Request, res: Response) { try { const { id } = req.params; await this.usersService.deleteUser(id); res.status(200).end(); } catch (error) { this.handleError(res, error); } } async listUsers(req: Request, res: Response): Promise { try { const { available = false } = req.query; let users = []; if (available) { const defaultNamespace = await this.namespacesService.getDefaultNamespace(); users = await this.usersService.listUsers({ not: defaultNamespace._id }); } else { users = await this.usersService.listUsers(); } res.json(users).status(200).end(); } catch (error) { this.handleError(res, error); } } async passwordRecovery(req: Request, res: Response) { try { const { username } = req.body; const user = await this.usersService.getByUsername(username); if (user === null) { res.status(404).json({ message: 'User not found', code: 'user-not-found'}).end(); return; } if (!user.email) { res.status(404).json({ message: 'Email not found', code: 'email-not-found'}).end(); return; } const { email, firstname, lastname, _id: userId } = user; const pin = this.cryptoService.generateRandomPin(8); const token = this.security.getHashedPassword(pin); const temporalToken = { userId, token, createdAt: new Date().getTime(), validUntil: new Date().getTime() + 1000 * 60 * 60 * 1, type: TemporalTokenMongoManager.Types.PASSWORD_RECOVERY, } if (!userId) { throw new Error('User not found'); } this.temporalTokenManager.deleteAllByUserAndType(userId.toString(), TemporalTokenMongoManager.Types.PASSWORD_RECOVERY); this.temporalTokenManager.addToken(temporalToken); await this.mailService.sendRecoveryPasswordEmail(firstname, lastname, email, pin); res.status(200).end(); } catch (error: any) { this.handleError(res, error, { code: 'critical', message: error.message }); } } }