"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.usersRouter = void 0; const express_1 = require("express"); const zod_1 = require("zod"); const client_1 = require("@prisma/client"); const users_service_1 = require("./users.service"); const users_schemas_1 = require("./users.schemas"); const validate_1 = require("../../middleware/validate"); const auth_middleware_1 = require("../../middleware/auth.middleware"); const rbac_middleware_1 = require("../../middleware/rbac.middleware"); const roles_1 = require("../../utils/roles"); const database_1 = require("../../config/database"); const email_service_1 = require("../../services/email.service"); const env_1 = require("../../config/env"); const logger_1 = require("../../utils/logger"); const provisioning_service_1 = require("../../services/user-provisioning/provisioning.service"); /** Check if user can manage other users (SUPER_ADMIN or canManageUsers permission) */ function canManageUsers(user) { const roles = (0, roles_1.getUserRoles)(user); if (roles.includes(client_1.UserRole.SUPER_ADMIN)) return true; return !!user.permissions?.canManageUsers; } /** Middleware: require user management permission */ function requireUserManagement(req, res, next) { if (!req.user) { res.status(401).json({ error: { message: 'Authentication required', code: 'AUTH_REQUIRED' } }); return; } if (!canManageUsers(req.user)) { res.status(403).json({ error: { message: 'Insufficient permissions', code: 'FORBIDDEN' } }); return; } next(); } const router = (0, express_1.Router)(); exports.usersRouter = router; // All user routes require authentication router.use(auth_middleware_1.authenticate); // GET /api/users — list users (any admin) router.get('/', (0, rbac_middleware_1.requireRole)(...roles_1.ADMIN_ROLES), (0, validate_1.validate)(users_schemas_1.listUsersSchema, 'query'), async (req, res, next) => { try { const result = await users_service_1.usersService.findAll(req.query); res.json(result); } catch (err) { next(err); } }); // GET /api/users/:id — get user (admin or self) router.get('/:id', async (req, res, next) => { try { const id = req.params.id; const isAdminUser = (0, roles_1.hasAnyRole)(req.user, roles_1.ADMIN_ROLES); const isSelf = req.user.id === id; if (!isAdminUser && !isSelf) { res.status(403).json({ error: { message: 'Insufficient permissions', code: 'FORBIDDEN' } }); return; } const user = await users_service_1.usersService.findById(id); res.json(user); } catch (err) { next(err); } }); // POST /api/users — create user (SUPER_ADMIN or canManageUsers) router.post('/', requireUserManagement, (0, validate_1.validate)(users_schemas_1.createUserSchema), async (req, res, next) => { try { const user = await users_service_1.usersService.create(req.body); res.status(201).json(user); } catch (err) { next(err); } }); // PUT /api/users/:id — update user (admin or self, role changes require user management perm) router.put('/:id', async (req, res, next) => { try { const id = req.params.id; const isAdminUser = (0, roles_1.hasAnyRole)(req.user, roles_1.ADMIN_ROLES); const isSelf = req.user.id === id; const canManage = canManageUsers(req.user); if (!isAdminUser && !isSelf) { res.status(403).json({ error: { message: 'Insufficient permissions', code: 'FORBIDDEN' } }); return; } // Only users with management permission can change role, roles, or status if (!canManage) { delete req.body.role; delete req.body.roles; delete req.body.status; delete req.body.permissions; } const parsed = users_schemas_1.updateUserSchema.parse(req.body); const user = await users_service_1.usersService.update(id, parsed); res.json(user); } catch (err) { next(err); } }); // POST /api/users/:id/approve — approve pending user (SUPER_ADMIN or canManageUsers) router.post('/:id/approve', requireUserManagement, async (req, res, next) => { try { const id = req.params.id; const user = await database_1.prisma.user.findUnique({ where: { id } }); if (!user) { res.status(404).json({ error: { message: 'User not found', code: 'USER_NOT_FOUND' } }); return; } if (user.status !== client_1.UserStatus.PENDING_APPROVAL) { res.status(400).json({ error: { message: 'User is not pending approval', code: 'INVALID_STATUS' } }); return; } await database_1.prisma.user.update({ where: { id }, data: { status: client_1.UserStatus.ACTIVE }, }); // Send approval notification email const adminUrl = env_1.env.ADMIN_URL || 'http://localhost:3000'; await email_service_1.emailService.sendAccountApprovedEmail({ recipientEmail: user.email, recipientName: user.name || 'there', loginUrl: `${adminUrl}/login`, }).catch(err => logger_1.logger.error('Failed to send approval email:', err)); // Fire-and-forget: provision approved user to eager services provisioning_service_1.userProvisioningService.onUserCreated({ id: user.id, email: user.email, name: user.name, role: user.role, roles: user.roles, status: 'ACTIVE', permissions: user.permissions, }).catch(err => logger_1.logger.warn('User provisioning hook (approve) failed:', err)); res.json({ message: 'User approved', userId: id }); } catch (err) { next(err); } }); // POST /api/users/:id/reject — reject pending user (SUPER_ADMIN or canManageUsers) const rejectSchema = zod_1.z.object({ reason: zod_1.z.string().max(500).optional(), }); router.post('/:id/reject', requireUserManagement, (0, validate_1.validate)(rejectSchema), async (req, res, next) => { try { const id = req.params.id; const user = await database_1.prisma.user.findUnique({ where: { id } }); if (!user) { res.status(404).json({ error: { message: 'User not found', code: 'USER_NOT_FOUND' } }); return; } if (user.status !== client_1.UserStatus.PENDING_APPROVAL) { res.status(400).json({ error: { message: 'User is not pending approval', code: 'INVALID_STATUS' } }); return; } await database_1.prisma.user.update({ where: { id }, data: { status: client_1.UserStatus.INACTIVE }, }); res.json({ message: 'User rejected', userId: id }); } catch (err) { next(err); } }); // GET /api/users/:id/contact — get linked Contact for a user (any admin) router.get('/:id/contact', (0, rbac_middleware_1.requireRole)(...roles_1.ADMIN_ROLES), async (req, res, next) => { try { const id = req.params.id; const contact = await database_1.prisma.contact.findFirst({ where: { userId: id, mergedIntoId: null }, select: { id: true, displayName: true, email: true, phone: true, tags: true, supportLevel: true, primarySource: true, profileToken: true, coverPhotoPath: true, }, }); res.json({ contact: contact || null }); } catch (err) { next(err); } }); // DELETE /api/users/:id — delete user (SUPER_ADMIN or canManageUsers) router.delete('/:id', requireUserManagement, async (req, res, next) => { try { const id = req.params.id; await users_service_1.usersService.delete(id); res.status(204).send(); } catch (err) { next(err); } }); //# sourceMappingURL=users.routes.js.map