diff --git a/src/main/java/org/example/team6backend/admin/AdminController.java b/src/main/java/org/example/team6backend/admin/AdminController.java index e0b7979..6d510f8 100644 --- a/src/main/java/org/example/team6backend/admin/AdminController.java +++ b/src/main/java/org/example/team6backend/admin/AdminController.java @@ -38,25 +38,41 @@ public ResponseEntity> getUsers(@RequestParam(required = fals @RequestParam(required = false) Boolean active, @RequestParam(required = false) String search, @PageableDefault(size = 20, sort = "createdAt", direction = Sort.Direction.DESC) Pageable pageable) { + log.info("GET /api/admin/users - Page: {}, Size: {}, Role: {}, Active: {}, Search: {}", + pageable.getPageNumber(), pageable.getPageSize(), role, active, search); + Page users = resolveUsers(email, name, role, active, search, pageable); + log.debug("Returning {} users out of {}", users.getNumberOfElements(), users.getTotalElements()); + return ResponseEntity.ok(userMapper.toResponsePage(users)); } @GetMapping("/users/pending") public ResponseEntity> getPendingUsers( @PageableDefault(size = 20, sort = "createdAt", direction = Sort.Direction.DESC) Pageable pageable) { - return ResponseEntity - .ok(userMapper.toResponsePage(userService.getUsersByRolePaginated(UserRole.PENDING, pageable))); + + log.info("GET /api/admin/users/pending - Page: {}, Size: {}", pageable.getPageNumber(), pageable.getPageSize()); + var pendingUsers = userService.getUsersByRolePaginated(UserRole.PENDING, pageable); + log.debug("Found {} pending users", pendingUsers.getTotalElements()); + + return ResponseEntity.ok(userMapper.toResponsePage(pendingUsers)); } @GetMapping("/users/{userId}") public ResponseEntity getUser(@PathVariable String userId) { - return ResponseEntity.ok(userMapper.toResponse(userService.getUserById(userId))); + log.info("GET /api/admin/users/{} - Admin fetching user", userId); + var user = userService.getUserById(userId); + log.debug("User found: {} ({})", user.getGithubLogin(), user.getRole()); + + return ResponseEntity.ok(userMapper.toResponse(user)); } @PostMapping("/users/{userId}/approve") public ResponseEntity approveUser(@PathVariable String userId) { + log.info("POST /api/admin/users/{}/approve - Approving pending user", userId); AppUser approvedUser = userService.approvePendingUser(userId); + log.info("User {} approved successfully. New role: {}", approvedUser.getGithubLogin(), approvedUser.getRole()); + return ResponseEntity.ok(userMapper.toResponse(approvedUser)); } @@ -64,7 +80,11 @@ public ResponseEntity approveUser(@PathVariable String userId) { public ResponseEntity updateUserRole(@PathVariable String userId, @Valid @RequestBody UpdateUserRoleRequest request, @AuthenticationPrincipal CustomUserDetails currentUser) { + log.info("PATCH /api/admin/users/{}/role - Admin {} changing role to {}", userId, + currentUser.getUser().getGithubLogin(), request.role()); + if (currentUser.getUser().getId().equals(userId)) { + log.warn("User {} attempted to change their own role", userId); throw new IllegalStateException("You cannot change your own role"); } @@ -73,12 +93,17 @@ public ResponseEntity updateUserRole(@PathVariable String userId, if (targetUser.getRole() == UserRole.ADMIN) { long adminCount = userService.getAllUsers().stream().filter(u -> u.getRole() == UserRole.ADMIN).count(); if (adminCount <= 1) { + log.warn("Attempt to remove last admin user {} by {}", userId, + currentUser.getUser().getGithubLogin()); throw new IllegalStateException("Cannot remove the last admin user"); } } } AppUser updatedUser = userService.updateUserRole(userId, request.role()); + log.info("User {} role changed from {} to {} by admin {}", updatedUser.getGithubLogin(), updatedUser.getRole(), + request.role(), currentUser.getUser().getGithubLogin()); + return ResponseEntity.ok(userMapper.toResponse(updatedUser)); } @@ -87,11 +112,18 @@ public ResponseEntity updateUserStatus(@PathVariable String userId @Valid @RequestBody UpdateUserStatusRequest request, @AuthenticationPrincipal CustomUserDetails currentUser) { + log.info("PATCH /api/admin/users/{}/status - Admin {} setting active={}", userId, + currentUser.getUser().getGithubLogin(), request.active()); + if (currentUser.getUser().getId().equals(userId) && !request.active()) { + log.warn("User {} attempted to deactivate their own account", userId); throw new IllegalStateException("You cannot deactivate your own account"); } AppUser updatedUser = userService.updateUserActiveStatus(userId, request.active()); + log.info("User {} active status changed to {} by admin {}", updatedUser.getGithubLogin(), + updatedUser.isActive(), currentUser.getUser().getGithubLogin()); + return ResponseEntity.ok(userMapper.toResponse(updatedUser)); } @@ -99,31 +131,45 @@ public ResponseEntity updateUserStatus(@PathVariable String userId public ResponseEntity deleteUser(@PathVariable String userId, @AuthenticationPrincipal CustomUserDetails currentUser) { + log.info("DELETE /api/admin/users/{} - Admin {} attempting to delete user", userId, + currentUser.getUser().getGithubLogin()); + if (currentUser.getUser().getId().equals(userId)) { + log.warn("User {} attempted to delete their own account", userId); throw new IllegalStateException("You cannot delete your own account"); } + var userToDelete = userService.getUserById(userId); userService.deleteUser(userId); + log.info("User {} ({}) deleted by admin {}", userToDelete.getGithubLogin(), userToDelete.getRole(), + currentUser.getUser().getGithubLogin()); + return ResponseEntity.noContent().build(); } @GetMapping("/stats") public ResponseEntity> getStats() { + log.info("GET /api/admin/stats - Fetching system statistics"); Map stats = Map.of("totalUsers", (long) userService.getAllUsers().size(), "pendingUsers", (long) userService.getUsersByRole(UserRole.PENDING).size(), "residents", (long) userService.getUsersByRole(UserRole.RESIDENT).size(), "handlers", (long) userService.getUsersByRole(UserRole.HANDLER).size(), "admins", (long) userService.getUsersByRole(UserRole.ADMIN).size()); + log.debug("Stats: Total={}, Pending={}, Residents={}, Handlers={}, Admins={}", stats.get("totalUsers"), + stats.get("pendingUsers"), stats.get("residents"), stats.get("handlers"), stats.get("admins")); + return ResponseEntity.ok(stats); } private Page resolveUsers(String email, String name, UserRole role, Boolean active, String search, Pageable pageable) { if (search != null && !search.trim().isEmpty()) { + log.debug("Using search filter: {}", search); return userService.searchUsers(search, pageable); } if (email != null || name != null || role != null || active != null) { + log.debug("Using filters - email: {}, name: {}, role: {}, active: {}", email, name, role, active); return userService.getUsersWithFilters(email, name, role, active, pageable); } diff --git a/src/main/java/org/example/team6backend/user/controller/UserController.java b/src/main/java/org/example/team6backend/user/controller/UserController.java index 8fa0be6..eb4b518 100644 --- a/src/main/java/org/example/team6backend/user/controller/UserController.java +++ b/src/main/java/org/example/team6backend/user/controller/UserController.java @@ -1,23 +1,49 @@ package org.example.team6backend.user.controller; import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; import org.example.team6backend.security.CustomUserDetails; import org.example.team6backend.user.dto.UserResponse; import org.example.team6backend.user.mapper.UserMapper; +import org.example.team6backend.user.service.UserService; +import org.springframework.http.ResponseEntity; import org.springframework.security.core.annotation.AuthenticationPrincipal; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.bind.annotation.*; +@Slf4j @RestController @RequestMapping("/api/users") @RequiredArgsConstructor public class UserController { + private final UserService userService; private final UserMapper userMapper; @GetMapping("/me") - public UserResponse getCurrentUser(@AuthenticationPrincipal CustomUserDetails userDetails) { - return userMapper.toResponse(userDetails.getUser()); + public ResponseEntity getCurrentUser(@AuthenticationPrincipal CustomUserDetails userDetails) { + log.info("GET /api/users/me - User: {}", userDetails.getUser().getGithubLogin()); + return ResponseEntity.ok(userMapper.toResponse(userDetails.getUser())); + } + + @GetMapping("/{userId}") + public ResponseEntity getUserById(@PathVariable String userId) { + log.info("GET /api/users/{} - Fetching user by ID", userId); + var user = userService.getUserById(userId); + log.debug("User found: {} ({})", user.getGithubLogin(), user.getRole()); + return ResponseEntity.ok(userMapper.toResponse(user)); + } + + @GetMapping("/role/{role}") + public ResponseEntity getUsersByRole(@PathVariable String role) { + log.info("GET /api/users/role/{} - Fetching users by role", role); + try { + var userRole = org.example.team6backend.user.entity.UserRole.valueOf(role.toUpperCase()); + var users = userService.getUsersByRole(userRole); + log.debug("Found {} users with role {}", users.size(), role); + return ResponseEntity.ok(users.stream().map(userMapper::toResponse).toList()); + } catch (IllegalArgumentException e) { + log.warn("Invalid role requested: {}", role); + return ResponseEntity.badRequest().body("Invalid role: " + role); + } } }