import { Request, Response } from 'express'; import { ApiResponse } from '../types/index.js'; import { getAllUsers, getUserByUsername, createNewUser, updateUser, deleteUser, getUserCount, getAdminCount, } from '../services/userService.js'; import { loadSettings } from '../config/index.js'; import { validatePasswordStrength } from '../utils/passwordValidation.js'; // Admin permission check middleware function const requireAdmin = (req: Request, res: Response): boolean => { const settings = loadSettings(); if (settings.systemConfig?.routing?.skipAuth) { return true; } const user = (req as any).user; if (!user || !user.isAdmin) { res.status(403).json({ success: false, message: 'Admin privileges required', }); return false; } return true; }; // Get all users (admin only) export const getUsers = (req: Request, res: Response): void => { if (!requireAdmin(req, res)) return; try { const users = getAllUsers().map(({ password: _, ...user }) => user); // Remove password from response const response: ApiResponse = { success: true, data: users, }; res.json(response); } catch (error) { res.status(500).json({ success: false, message: 'Failed to get users information', }); } }; // Get a specific user by username (admin only) export const getUser = (req: Request, res: Response): void => { if (!requireAdmin(req, res)) return; try { const { username } = req.params; if (!username) { res.status(400).json({ success: false, message: 'Username is required', }); return; } const user = getUserByUsername(username); if (!user) { res.status(404).json({ success: false, message: 'User not found', }); return; } const { password: _, ...userData } = user; // Remove password from response const response: ApiResponse = { success: true, data: userData, }; res.json(response); } catch (error) { res.status(500).json({ success: false, message: 'Failed to get user information', }); } }; // Create a new user (admin only) export const createUser = async (req: Request, res: Response): Promise => { if (!requireAdmin(req, res)) return; try { const { username, password, isAdmin } = req.body; if (!username || !password) { res.status(400).json({ success: false, message: 'Username and password are required', }); return; } // Validate password strength const validationResult = validatePasswordStrength(password); if (!validationResult.isValid) { res.status(400).json({ success: false, message: 'Password does not meet security requirements', errors: validationResult.errors, }); return; } const newUser = await createNewUser(username, password, isAdmin || false); if (!newUser) { res.status(400).json({ success: false, message: 'Failed to create user or username already exists', }); return; } const { password: _, ...userData } = newUser; // Remove password from response const response: ApiResponse = { success: true, data: userData, message: 'User created successfully', }; res.status(201).json(response); } catch (error) { res.status(500).json({ success: false, message: 'Internal server error', }); } }; // Update an existing user (admin only) export const updateExistingUser = async (req: Request, res: Response): Promise => { if (!requireAdmin(req, res)) return; try { const { username } = req.params; const { isAdmin, newPassword } = req.body; if (!username) { res.status(400).json({ success: false, message: 'Username is required', }); return; } // Check if trying to change admin status if (isAdmin !== undefined) { const currentUser = getUserByUsername(username); if (!currentUser) { res.status(404).json({ success: false, message: 'User not found', }); return; } // Prevent removing admin status from the last admin if (currentUser.isAdmin && !isAdmin && getAdminCount() === 1) { res.status(400).json({ success: false, message: 'Cannot remove admin status from the last admin user', }); return; } } const updateData: any = {}; if (isAdmin !== undefined) updateData.isAdmin = isAdmin; if (newPassword) { // Validate new password strength const validationResult = validatePasswordStrength(newPassword); if (!validationResult.isValid) { res.status(400).json({ success: false, message: 'Password does not meet security requirements', errors: validationResult.errors, }); return; } updateData.newPassword = newPassword; } if (Object.keys(updateData).length === 0) { res.status(400).json({ success: false, message: 'At least one field (isAdmin or newPassword) is required to update', }); return; } const updatedUser = await updateUser(username, updateData); if (!updatedUser) { res.status(404).json({ success: false, message: 'User not found or update failed', }); return; } const { password: _, ...userData } = updatedUser; // Remove password from response const response: ApiResponse = { success: true, data: userData, message: 'User updated successfully', }; res.json(response); } catch (error) { res.status(500).json({ success: false, message: 'Internal server error', }); } }; // Delete a user (admin only) export const deleteExistingUser = (req: Request, res: Response): void => { if (!requireAdmin(req, res)) return; try { const { username } = req.params; if (!username) { res.status(400).json({ success: false, message: 'Username is required', }); return; } // Check if trying to delete the current admin user const currentUser = (req as any).user; if (currentUser.username === username) { res.status(400).json({ success: false, message: 'Cannot delete your own account', }); return; } const success = deleteUser(username); if (!success) { res.status(400).json({ success: false, message: 'User not found, failed to delete, or cannot delete the last admin', }); return; } res.json({ success: true, message: 'User deleted successfully', }); } catch (error) { res.status(500).json({ success: false, message: 'Internal server error', }); } }; // Get user statistics (admin only) export const getUserStats = (req: Request, res: Response): void => { if (!requireAdmin(req, res)) return; try { const totalUsers = getUserCount(); const adminUsers = getAdminCount(); const regularUsers = totalUsers - adminUsers; const response: ApiResponse = { success: true, data: { totalUsers, adminUsers, regularUsers, }, }; res.json(response); } catch (error) { res.status(500).json({ success: false, message: 'Failed to get user statistics', }); } };