package com.gcsc.guide.controller; import com.gcsc.guide.dto.AddPermissionRequest; import com.gcsc.guide.dto.CreateRoleRequest; import com.gcsc.guide.dto.RoleResponse; import com.gcsc.guide.service.RoleService; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.media.ArraySchema; import io.swagger.v3.oas.annotations.media.Content; import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.responses.ApiResponse; import io.swagger.v3.oas.annotations.responses.ApiResponses; import io.swagger.v3.oas.annotations.security.SecurityRequirement; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; import java.net.URI; import java.util.List; @RestController @RequestMapping("/api/admin/roles") @RequiredArgsConstructor @Tag(name = "03. 관리자 - 롤/권한", description = "롤 CRUD 및 URL 패턴 기반 권한 관리") @SecurityRequirement(name = "Bearer JWT") public class AdminRoleController { private final RoleService roleService; @Operation(summary = "전체 롤 목록 조회", description = "등록된 모든 롤과 각 롤에 할당된 URL 패턴을 조회합니다.") @ApiResponses({ @ApiResponse(responseCode = "200", description = "조회 성공", content = @Content(array = @ArraySchema(schema = @Schema(implementation = RoleResponse.class)))), @ApiResponse(responseCode = "401", description = "인증 실패", content = @Content), @ApiResponse(responseCode = "403", description = "관리자 권한 필요", content = @Content) }) @GetMapping public ResponseEntity> getRoles() { return ResponseEntity.ok(roleService.getRoles()); } @Operation(summary = "롤 생성", description = "새로운 롤을 생성합니다. 생성 후 URL 패턴을 별도로 추가해야 합니다.") @ApiResponses({ @ApiResponse(responseCode = "201", description = "롤 생성 성공", content = @Content(schema = @Schema(implementation = RoleResponse.class))), @ApiResponse(responseCode = "401", description = "인증 실패", content = @Content), @ApiResponse(responseCode = "403", description = "관리자 권한 필요", content = @Content) }) @PostMapping public ResponseEntity createRole(@Valid @RequestBody CreateRoleRequest request) { RoleResponse role = roleService.createRole(request.name(), request.description()); return ResponseEntity.created(URI.create("/api/admin/roles/" + role.id())).body(role); } @Operation(summary = "롤 수정", description = "기존 롤의 이름과 설명을 수정합니다.") @ApiResponses({ @ApiResponse(responseCode = "200", description = "롤 수정 성공", content = @Content(schema = @Schema(implementation = RoleResponse.class))), @ApiResponse(responseCode = "401", description = "인증 실패", content = @Content), @ApiResponse(responseCode = "403", description = "관리자 권한 필요", content = @Content), @ApiResponse(responseCode = "404", description = "롤을 찾을 수 없음", content = @Content) }) @PutMapping("/{id}") public ResponseEntity updateRole( @Parameter(description = "롤 ID", required = true) @PathVariable Long id, @Valid @RequestBody CreateRoleRequest request) { return ResponseEntity.ok(roleService.updateRole(id, request.name(), request.description())); } @Operation(summary = "롤 삭제", description = "롤을 삭제합니다. 해당 롤에 연결된 URL 패턴도 함께 삭제됩니다.") @ApiResponses({ @ApiResponse(responseCode = "204", description = "롤 삭제 성공"), @ApiResponse(responseCode = "401", description = "인증 실패", content = @Content), @ApiResponse(responseCode = "403", description = "관리자 권한 필요", content = @Content), @ApiResponse(responseCode = "404", description = "롤을 찾을 수 없음", content = @Content) }) @DeleteMapping("/{id}") public ResponseEntity deleteRole( @Parameter(description = "롤 ID", required = true) @PathVariable Long id) { roleService.deleteRole(id); return ResponseEntity.noContent().build(); } @Operation(summary = "롤의 URL 패턴 목록 조회", description = "특정 롤에 할당된 URL 패턴(권한) 목록을 조회합니다.") @ApiResponses({ @ApiResponse(responseCode = "200", description = "조회 성공", content = @Content(array = @ArraySchema(schema = @Schema(implementation = String.class)))), @ApiResponse(responseCode = "401", description = "인증 실패", content = @Content), @ApiResponse(responseCode = "403", description = "관리자 권한 필요", content = @Content), @ApiResponse(responseCode = "404", description = "롤을 찾을 수 없음", content = @Content) }) @GetMapping("/{id}/permissions") public ResponseEntity> getPermissions( @Parameter(description = "롤 ID", required = true) @PathVariable Long id) { return ResponseEntity.ok(roleService.getPermissions(id)); } @Operation(summary = "URL 패턴 추가", description = "롤에 새로운 URL 패턴(권한)을 추가합니다. Ant-style 패턴을 지원합니다 (예: /dev/**, /dev/front/**).") @ApiResponses({ @ApiResponse(responseCode = "200", description = "URL 패턴 추가 성공", content = @Content(schema = @Schema(implementation = RoleResponse.class))), @ApiResponse(responseCode = "401", description = "인증 실패", content = @Content), @ApiResponse(responseCode = "403", description = "관리자 권한 필요", content = @Content), @ApiResponse(responseCode = "404", description = "롤을 찾을 수 없음", content = @Content) }) @PostMapping("/{id}/permissions") public ResponseEntity addPermission( @Parameter(description = "롤 ID", required = true) @PathVariable Long id, @Valid @RequestBody AddPermissionRequest request) { return ResponseEntity.ok(roleService.addPermission(id, request.urlPattern())); } @Operation(summary = "URL 패턴 삭제", description = "특정 URL 패턴(권한)을 삭제합니다.") @ApiResponses({ @ApiResponse(responseCode = "204", description = "URL 패턴 삭제 성공"), @ApiResponse(responseCode = "401", description = "인증 실패", content = @Content), @ApiResponse(responseCode = "403", description = "관리자 권한 필요", content = @Content), @ApiResponse(responseCode = "404", description = "URL 패턴을 찾을 수 없음", content = @Content) }) @DeleteMapping("/permissions/{permissionId}") public ResponseEntity deletePermission( @Parameter(description = "URL 패턴 ID", required = true) @PathVariable Long permissionId) { roleService.deletePermission(permissionId); return ResponseEntity.noContent().build(); } }