feat(audit): emit GROUP_MEMBERSHIP_CHANGED when admin updates user groups
Adds actorId param to adminUpdateUser(), captures beforeGroups before mutation, computes added/removed group names, emits logAfterCommit only when the group set actually changes. Payload contains group names, not permission strings. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -86,9 +86,11 @@ public class UserController {
|
||||
|
||||
@PutMapping("/users/{id}")
|
||||
@RequirePermission(Permission.ADMIN_USER)
|
||||
public ResponseEntity<AppUser> adminUpdateUser(@PathVariable UUID id,
|
||||
public ResponseEntity<AppUser> adminUpdateUser(Authentication authentication,
|
||||
@PathVariable UUID id,
|
||||
@RequestBody AdminUpdateUserRequest dto) {
|
||||
AppUser updated = userService.adminUpdateUser(id, dto);
|
||||
AppUser actor = userService.findByEmail(authentication.getName());
|
||||
AppUser updated = userService.adminUpdateUser(actor.getId(), id, dto);
|
||||
updated.setPassword(null);
|
||||
return ResponseEntity.ok(updated);
|
||||
}
|
||||
|
||||
@@ -28,6 +28,8 @@ import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
import static java.util.stream.Collectors.toSet;
|
||||
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
@@ -156,7 +158,7 @@ public class UserService {
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public AppUser adminUpdateUser(UUID id, AdminUpdateUserRequest dto) {
|
||||
public AppUser adminUpdateUser(UUID actorId, UUID id, AdminUpdateUserRequest dto) {
|
||||
AppUser user = getById(id);
|
||||
|
||||
if (dto.getEmail() != null && !dto.getEmail().isBlank()) {
|
||||
@@ -181,8 +183,22 @@ public class UserService {
|
||||
}
|
||||
|
||||
if (dto.getGroupIds() != null) {
|
||||
Set<UserGroup> groups = new HashSet<>(groupRepository.findAllById(dto.getGroupIds()));
|
||||
user.setGroups(groups);
|
||||
Set<UUID> beforeIds = user.getGroups().stream().map(UserGroup::getId).collect(toSet());
|
||||
Set<UserGroup> beforeGroups = new HashSet<>(user.getGroups());
|
||||
Set<UserGroup> newGroups = new HashSet<>(groupRepository.findAllById(dto.getGroupIds()));
|
||||
user.setGroups(newGroups);
|
||||
Set<UUID> afterIds = newGroups.stream().map(UserGroup::getId).collect(toSet());
|
||||
if (!beforeIds.equals(afterIds)) {
|
||||
List<String> added = newGroups.stream()
|
||||
.filter(g -> !beforeIds.contains(g.getId()))
|
||||
.map(UserGroup::getName).toList();
|
||||
List<String> removed = beforeGroups.stream()
|
||||
.filter(g -> !afterIds.contains(g.getId()))
|
||||
.map(UserGroup::getName).toList();
|
||||
auditService.logAfterCommit(AuditKind.GROUP_MEMBERSHIP_CHANGED, actorId, null,
|
||||
Map.of("userId", id.toString(), "email", user.getEmail(),
|
||||
"addedGroups", added, "removedGroups", removed));
|
||||
}
|
||||
}
|
||||
|
||||
return userRepository.save(user);
|
||||
|
||||
Reference in New Issue
Block a user