import { Router } from "express"; import { UserHandler } from "../handlers/UserHandler.js"; import { CreateUserRequest } from "../dtos/CreateUserRequest.js"; import { UserRepository } from "../repositories/UserRepository.js"; import { UserDtoEntityMapper } from "../mappers/UserDtoEntityMapper.js"; import { asyncHandler } from "../utils/asyncHandler.js"; import { CreateUserResponse } from "../dtos/CreateUserResponse.js"; import { UserDto } from "../dtos/UserDto.js"; import { requireAdmin, requireAdminOrOwner, requireAdminOrSelf } from "../middleware/authorizationMiddleware.js"; import { UserListResponse } from "../dtos/UserListResponse.js"; import { HttpStatusCode } from "../apiHelpers/HttpStatusCodes.js"; import { InternalServerError, NotFoundError } from "../errors/httpErrors.js"; import { ChangeUserPasswordRequest } from "../dtos/ChangeUserPasswordRequest.js"; export const userBasicRoute = "/user"; /** * Handles all user related routes */ const router = Router(); // Inject repo + mapper here const handler = new UserHandler(new UserRepository(), new UserDtoEntityMapper()); /** * Create a new user (admin only) * Consumes CreateUserRequest * Responds with UserDto */ router.post( "/create", requireAdmin, asyncHandler(async (req, res) => { const request: CreateUserRequest = req.body; const user: UserDto = await handler.createUser(request); const response: CreateUserResponse = { userData: user }; res.status(HttpStatusCode.CREATED).json(response); }) ); /** * Update existing user * Consumes UserDto * Responds with UserDto * Does not allow for password change. Use change-password instead * * Users can update their own data, admins can update any user */ router.post( "/update", requireAdminOrSelf, // Checks req.body.id or req.body.userId asyncHandler(async (req, res) => { const dto: UserDto = req.body; const response = await handler.updateUserData(dto); res.status(HttpStatusCode.OK).json(response); }) ); /** * Update password of existing user * Consumes ChangeUserPasswordRequest * Responds with code 200 indicating success * * Users can change their own password, admins can change any password */ router.post( "/change-password", requireAdminOrOwner(req => req.body.userId), asyncHandler(async (req, res) => { const requestData: ChangeUserPasswordRequest = req.body; const success = await handler.changePassword(requestData); if (!success) { throw new InternalServerError("Failed to change password"); } res.status(HttpStatusCode.OK).json({ message: "Password changed successfully" }); }) ); /** * Get all users (admin only) * Responds with array of UserDto */ router.get( "/all", requireAdmin, asyncHandler(async (req, res) => { const users = await handler.getAllUsers(); const response: UserListResponse = { valueList: users }; res.status(HttpStatusCode.OK).json(response); }) ); /** * Get user data for current user * Responds with UserDto */ router.get( "/me", asyncHandler(async (req, res) => { const id = req.currentUser?.id; if (id) { const responseDto = await handler.getUserById(id); res.status(HttpStatusCode.OK).json(responseDto); } else { throw new NotFoundError("There is no user id for current session!"); } }) ); /** * Get specific user by ID * Responds with UserDto * * Users can get their own data, admins can get any user's data */ router.get( "/:userId", requireAdminOrOwner(req => req.params.userId), asyncHandler(async (req, res) => { const userId = req.params.userId; const responseDto = await handler.getUserById(userId); res.status(HttpStatusCode.OK).json(responseDto); }) ); export default router;