Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions starter/studio-platform-starter-user/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,9 @@ studio:
- `/api/mgmt/roles`
- `/api/self`

기본 사용자 관리 API에는 `DELETE /api/mgmt/users/{id}`가 포함된다. 이 엔드포인트는
`features:user` admin 권한을 요구하며, 성공 시 `204 No Content`를 반환한다.

기본 컨트롤러는 `ApplicationUserMapper`/`ApplicationUserService` 빈이 있을 때만 등록된다.
커스텀 컨트롤러를 제공할 때는 `UserMgmtApi`/`UserPublicApi`/`UserAuthPublicApi`/`UserMeApi`
인터페이스를 구현하면 기본 컨트롤러가 자동으로 비활성화된다.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,10 @@ public ApplicationUser update(Long userId, Consumer<ApplicationUser> mutator) {
}

@Transactional
@Caching(evict = {
@CacheEvict(cacheNames = CacheNames.User.BY_USER_ID, key = "#userId"),
@CacheEvict(cacheNames = CacheNames.User.BY_USERNAME, allEntries = true)
})
public void delete(Long userId) {
ApplicationUser u = get(userId);
userRepo.delete(u);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,14 @@ public ResponseEntity<ApiResponse<UserDto>> update(@PathVariable Long id, @Reque
return ResponseEntity.ok(ApiResponse.ok(userMapper.toDto(updated)));
}

@DeleteMapping("/{id}")
@PreAuthorize("@endpointAuthz.can('features:user','admin')")
@Override
public ResponseEntity<Void> delete(@PathVariable Long id) {
userService.delete(id);
return ResponseEntity.noContent().build();
}

@GetMapping("/password-policy")
@PreAuthorize("@endpointAuthz.can('features:user','admin')")
@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,16 @@ void passwordResetDelegatesActorUsername() {
verify(userService).resetPassword(eq(10L), eq("NextPassword123!"), eq("admin"), eq("test-reason"));
}

@Test
void deleteDelegatesToUserService() {
UserMgmtController controller = controller();

var response = controller.delete(10L);

assertEquals(204, response.getStatusCode().value());
verify(userService).delete(10L);
}

@Test
void updateUserRolesDelegatesDistinctRoleIds() {
UserMgmtController controller = controller();
Expand Down
8 changes: 8 additions & 0 deletions studio-platform-user/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ Response: `ApiResponse<MeProfileDto>`
Password policy is defined by configuration and enforced on:
- **Self password change**: `PUT /api/self/password`
- **Admin reset**: `POST /api/mgmt/users/{id}/password`
- **Admin delete**: `DELETE /api/mgmt/users/{id}` removes the user through the configured `ApplicationUserService` implementation.

### Policy Config (YAML)
```yaml
Expand Down Expand Up @@ -117,6 +118,13 @@ Returns current password policy configuration for admin UI.

Response: `ApiResponse<PasswordPolicyDto>`

### DELETE /api/mgmt/users/{id}
Deletes a user from the admin API.

Auth: `features:user` admin permission

Response: `204 No Content`

## Example Requests

### PATCH
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,10 @@ ResponseEntity<ApiResponse<Page<UserDto>>> find(

ResponseEntity<ApiResponse<UserDto>> update(Long id, @RequestBody UpdateUserRequest req);

default ResponseEntity<Void> delete(Long id) {
throw new UnsupportedOperationException("User delete endpoint is not implemented");
}

ResponseEntity<ApiResponse<PasswordPolicyDto>> passwordPolicy();

ResponseEntity<Void> passwordReset(Long id, @Valid @RequestBody ChangePasswordRequest req,
Expand Down
Loading