fix: null safety in role/group creation, add user create/update endpoints
- RoleAdminController.createRole: default null description to "" and null scope to "custom"
- RoleAdminController.updateRole: pass null audit details to avoid NPE when name is null
- GroupAdminController.updateGroup: pass null audit details to avoid NPE when name is null
- UserAdminController: add POST / createUser endpoint with default VIEWER role assignment
- UserAdminController: add PUT /{userId} updateUser endpoint for displayName/email updates
This commit is contained in:
@@ -111,7 +111,7 @@ public class GroupAdminController {
|
||||
|
||||
groupRepository.update(id, request.name(), request.parentGroupId());
|
||||
auditService.log("update_group", AuditCategory.RBAC, id.toString(),
|
||||
Map.of("name", request.name()), AuditResult.SUCCESS, httpRequest);
|
||||
null, AuditResult.SUCCESS, httpRequest);
|
||||
return ResponseEntity.ok().build();
|
||||
}
|
||||
|
||||
|
||||
@@ -69,7 +69,9 @@ public class RoleAdminController {
|
||||
@ApiResponse(responseCode = "200", description = "Role created")
|
||||
public ResponseEntity<Map<String, UUID>> createRole(@RequestBody CreateRoleRequest request,
|
||||
HttpServletRequest httpRequest) {
|
||||
UUID id = roleRepository.create(request.name(), request.description(), request.scope());
|
||||
String desc = request.description() != null ? request.description() : "";
|
||||
String sc = request.scope() != null ? request.scope() : "custom";
|
||||
UUID id = roleRepository.create(request.name(), desc, sc);
|
||||
auditService.log("create_role", AuditCategory.RBAC, id.toString(),
|
||||
Map.of("name", request.name()), AuditResult.SUCCESS, httpRequest);
|
||||
return ResponseEntity.ok(Map.of("id", id));
|
||||
@@ -93,7 +95,7 @@ public class RoleAdminController {
|
||||
}
|
||||
roleRepository.update(id, request.name(), request.description(), request.scope());
|
||||
auditService.log("update_role", AuditCategory.RBAC, id.toString(),
|
||||
Map.of("name", request.name()), AuditResult.SUCCESS, httpRequest);
|
||||
null, AuditResult.SUCCESS, httpRequest);
|
||||
return ResponseEntity.ok().build();
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,9 @@ import com.cameleer3.server.core.admin.AuditCategory;
|
||||
import com.cameleer3.server.core.admin.AuditResult;
|
||||
import com.cameleer3.server.core.admin.AuditService;
|
||||
import com.cameleer3.server.core.rbac.RbacService;
|
||||
import com.cameleer3.server.core.rbac.SystemRole;
|
||||
import com.cameleer3.server.core.rbac.UserDetail;
|
||||
import com.cameleer3.server.core.security.UserInfo;
|
||||
import com.cameleer3.server.core.security.UserRepository;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.responses.ApiResponse;
|
||||
@@ -16,9 +18,12 @@ import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.PutMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
@@ -63,6 +68,43 @@ public class UserAdminController {
|
||||
return ResponseEntity.ok(detail);
|
||||
}
|
||||
|
||||
@PostMapping
|
||||
@Operation(summary = "Create a local user")
|
||||
@ApiResponse(responseCode = "200", description = "User created")
|
||||
public ResponseEntity<UserDetail> createUser(@RequestBody CreateUserRequest request,
|
||||
HttpServletRequest httpRequest) {
|
||||
String userId = "user:" + request.username();
|
||||
UserInfo user = new UserInfo(userId, "local",
|
||||
request.email() != null ? request.email() : "",
|
||||
request.displayName() != null ? request.displayName() : request.username(),
|
||||
Instant.now());
|
||||
userRepository.upsert(user);
|
||||
rbacService.assignRoleToUser(userId, SystemRole.VIEWER_ID);
|
||||
auditService.log("create_user", AuditCategory.USER_MGMT, userId,
|
||||
Map.of("username", request.username()), AuditResult.SUCCESS, httpRequest);
|
||||
return ResponseEntity.ok(rbacService.getUser(userId));
|
||||
}
|
||||
|
||||
@PutMapping("/{userId}")
|
||||
@Operation(summary = "Update user display name or email")
|
||||
@ApiResponse(responseCode = "200", description = "User updated")
|
||||
@ApiResponse(responseCode = "404", description = "User not found")
|
||||
public ResponseEntity<Void> updateUser(@PathVariable String userId,
|
||||
@RequestBody UpdateUserRequest request,
|
||||
HttpServletRequest httpRequest) {
|
||||
var existing = userRepository.findById(userId);
|
||||
if (existing.isEmpty()) return ResponseEntity.notFound().build();
|
||||
var user = existing.get();
|
||||
var updated = new UserInfo(user.userId(), user.provider(),
|
||||
request.email() != null ? request.email() : user.email(),
|
||||
request.displayName() != null ? request.displayName() : user.displayName(),
|
||||
user.createdAt());
|
||||
userRepository.upsert(updated);
|
||||
auditService.log("update_user", AuditCategory.USER_MGMT, userId,
|
||||
null, AuditResult.SUCCESS, httpRequest);
|
||||
return ResponseEntity.ok().build();
|
||||
}
|
||||
|
||||
@PostMapping("/{userId}/roles/{roleId}")
|
||||
@Operation(summary = "Assign a role to a user")
|
||||
@ApiResponse(responseCode = "200", description = "Role assigned")
|
||||
@@ -122,4 +164,7 @@ public class UserAdminController {
|
||||
null, AuditResult.SUCCESS, httpRequest);
|
||||
return ResponseEntity.noContent().build();
|
||||
}
|
||||
|
||||
public record CreateUserRequest(String username, String displayName, String email) {}
|
||||
public record UpdateUserRequest(String displayName, String email) {}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user