diff --git a/src/controllers/admin.controller.ts b/src/controllers/admin.controller.ts index 47df64d..11fcd4d 100644 --- a/src/controllers/admin.controller.ts +++ b/src/controllers/admin.controller.ts @@ -2,7 +2,7 @@ import { Request, Response } from 'express'; import { Holiday, HolidayType } from '@models/Holiday'; import { holidayService } from '@services/holiday.service'; import { sequelize } from '@config/database'; -import { QueryTypes } from 'sequelize'; +import { QueryTypes, Op } from 'sequelize'; import logger from '@utils/logger'; import { initializeHolidaysCache, clearWorkingHoursCache } from '@utils/tatTimeUtils'; import { clearConfigCache } from '@services/configReader.service'; @@ -520,32 +520,49 @@ export const updateUserRole = async (req: Request, res: Response): Promise }; /** - * Get All Users by Role + * Get All Users by Role (with pagination and filtering) * - * Purpose: List all users with a specific role + * Purpose: List all users with optional role filtering and pagination * * Access: ADMIN only * - * Query: ?role=ADMIN | MANAGEMENT | USER + * Query: + * - ?role=ADMIN | MANAGEMENT | USER | ALL | ELEVATED (default: ELEVATED for ADMIN+MANAGEMENT only) + * - ?page=1 (default) + * - ?limit=10 (default) */ export const getUsersByRole = async (req: Request, res: Response): Promise => { try { - const { role } = req.query; + const { role, page = '1', limit = '10' } = req.query; + + const pageNum = parseInt(page as string) || 1; + const limitNum = Math.min(parseInt(limit as string) || 10, 100); // Max 100 per page + const offset = (pageNum - 1) * limitNum; const whereClause: any = { isActive: true }; - if (role) { + // Handle role filtering + if (role && role !== 'ALL' && role !== 'ELEVATED') { const validRoles: UserRole[] = ['USER', 'MANAGEMENT', 'ADMIN']; if (!validRoles.includes(role as UserRole)) { res.status(400).json({ success: false, - error: 'Invalid role. Must be USER, MANAGEMENT, or ADMIN' + error: 'Invalid role. Must be USER, MANAGEMENT, ADMIN, ALL, or ELEVATED' }); return; } whereClause.role = role; + } else if (role === 'ELEVATED' || !role) { + // Default: Show only ADMIN and MANAGEMENT (elevated users) + whereClause.role = { [Op.in]: ['ADMIN', 'MANAGEMENT'] }; } + // If role === 'ALL', don't filter by role (show all users) + // Get total count for pagination + const totalUsers = await User.count({ where: whereClause }); + const totalPages = Math.ceil(totalUsers / limitNum); + + // Get paginated users const users = await User.findAll({ where: whereClause, attributes: [ @@ -565,23 +582,49 @@ export const getUsersByRole = async (req: Request, res: Response): Promise order: [ ['role', 'ASC'], // ADMIN first, then MANAGEMENT, then USER ['displayName', 'ASC'] - ] + ], + limit: limitNum, + offset: offset + }); + + // Get role summary (across all users, not just current page) + const roleStats = await sequelize.query(` + SELECT + role, + COUNT(*) as count + FROM users + WHERE is_active = true + GROUP BY role + ORDER BY + CASE role + WHEN 'ADMIN' THEN 1 + WHEN 'MANAGEMENT' THEN 2 + WHEN 'USER' THEN 3 + END + `, { + type: QueryTypes.SELECT }); - // Group by role for summary const summary = { - ADMIN: users.filter(u => u.role === 'ADMIN').length, - MANAGEMENT: users.filter(u => u.role === 'MANAGEMENT').length, - USER: users.filter(u => u.role === 'USER').length, - total: users.length + ADMIN: parseInt((roleStats.find((s: any) => s.role === 'ADMIN') as any)?.count || '0'), + MANAGEMENT: parseInt((roleStats.find((s: any) => s.role === 'MANAGEMENT') as any)?.count || '0'), + USER: parseInt((roleStats.find((s: any) => s.role === 'USER') as any)?.count || '0') }; res.json({ success: true, data: { users: users, + pagination: { + currentPage: pageNum, + totalPages: totalPages, + totalUsers: totalUsers, + limit: limitNum, + hasNextPage: pageNum < totalPages, + hasPrevPage: pageNum > 1 + }, summary, - filter: role || 'all' + filter: role || 'ELEVATED' } }); } catch (error) {