const db = require('../db/models'); const UsersDBApi = require('../db/api/users'); const { createEntityService } = require('../factories/service.factory'); const ValidationError = require('./notifications/errors/validation'); const config = require('../config'); const AuthService = require('./auth'); // Generate base service from factory const BaseUsersService = createEntityService(UsersDBApi, { entityName: 'Users' }); /** * Users service with email invitation functionality * Extends factory-generated service with custom user logic */ class UsersService extends BaseUsersService { /** * Create user with email validation and optional invitation */ static async create(data, currentUser, sendInvitationEmails = true, host) { const transaction = await db.sequelize.transaction(); const email = data.email; try { if (!email) { throw new ValidationError('iam.errors.emailRequired'); } const existingUser = await UsersDBApi.findBy({ email }, { transaction }); if (existingUser) { throw new ValidationError('iam.errors.userAlreadyExists'); } await UsersDBApi.create({ data }, { currentUser, transaction }); await transaction.commit(); // Send invitation email after successful commit if (sendInvitationEmails) { AuthService.sendPasswordResetEmail(email, 'invitation', host); } } catch (error) { await transaction.rollback(); throw error; } } /** * Remove user with self-deletion and permission checks */ static async remove(id, currentUser) { if (currentUser.id === id) { throw new ValidationError('iam.errors.deletingHimself'); } if (currentUser.app_role?.name !== config.roles.admin) { throw new ValidationError('errors.forbidden.message'); } // Delegate to parent (factory) implementation return super.remove(id, currentUser); } } module.exports = UsersService;