From e8f06aa583ea938f305eafa851cbd98559093160 Mon Sep 17 00:00:00 2001 From: JanooGwan Date: Tue, 27 Jan 2026 11:29:44 +0900 Subject: [PATCH 1/6] =?UTF-8?q?refactor:=20ClubApi=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package-lock.json | 6 + .../domain/club/controller/ClubApi.java | 497 ------------------ .../club/controller/ClubApplicationApi.java | 128 +++++ .../domain/club/controller/ClubBasicApi.java | 153 ++++++ .../club/controller/ClubController.java | 7 +- .../domain/club/controller/ClubMemberApi.java | 122 +++++ .../club/controller/ClubPositionApi.java | 91 ++++ .../club/controller/ClubRecruitmentApi.java | 78 +++ 8 files changed, 584 insertions(+), 498 deletions(-) create mode 100644 package-lock.json delete mode 100644 src/main/java/gg/agit/konect/domain/club/controller/ClubApi.java create mode 100644 src/main/java/gg/agit/konect/domain/club/controller/ClubApplicationApi.java create mode 100644 src/main/java/gg/agit/konect/domain/club/controller/ClubBasicApi.java create mode 100644 src/main/java/gg/agit/konect/domain/club/controller/ClubMemberApi.java create mode 100644 src/main/java/gg/agit/konect/domain/club/controller/ClubPositionApi.java create mode 100644 src/main/java/gg/agit/konect/domain/club/controller/ClubRecruitmentApi.java diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 00000000..0768fb21 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,6 @@ +{ + "name": "KONECT_BACK_END", + "lockfileVersion": 3, + "requires": true, + "packages": {} +} diff --git a/src/main/java/gg/agit/konect/domain/club/controller/ClubApi.java b/src/main/java/gg/agit/konect/domain/club/controller/ClubApi.java deleted file mode 100644 index 60ff4de2..00000000 --- a/src/main/java/gg/agit/konect/domain/club/controller/ClubApi.java +++ /dev/null @@ -1,497 +0,0 @@ -package gg.agit.konect.domain.club.controller; - -import org.springdoc.core.annotations.ParameterObject; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.DeleteMapping; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.ModelAttribute; -import org.springframework.web.bind.annotation.PatchMapping; -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 gg.agit.konect.domain.club.dto.ClubApplicationAnswersResponse; -import gg.agit.konect.domain.club.dto.ClubAppliedClubsResponse; -import gg.agit.konect.domain.club.dto.ClubApplicationsResponse; -import gg.agit.konect.domain.club.dto.ClubApplyQuestionsReplaceRequest; -import gg.agit.konect.domain.club.dto.ClubApplyQuestionsResponse; -import gg.agit.konect.domain.club.dto.ClubApplyRequest; -import gg.agit.konect.domain.club.dto.ClubBasicInfoUpdateRequest; -import gg.agit.konect.domain.club.dto.ClubCondition; -import gg.agit.konect.domain.club.dto.ClubCreateRequest; -import gg.agit.konect.domain.club.dto.ClubDetailResponse; -import gg.agit.konect.domain.club.dto.ClubDetailUpdateRequest; -import gg.agit.konect.domain.club.dto.ClubFeeInfoReplaceRequest; -import gg.agit.konect.domain.club.dto.ClubFeeInfoResponse; -import gg.agit.konect.domain.club.dto.ClubMemberAddRequest; -import gg.agit.konect.domain.club.dto.ClubMemberCondition; -import gg.agit.konect.domain.club.dto.ClubMembersResponse; -import gg.agit.konect.domain.club.dto.ClubMembershipsResponse; -import gg.agit.konect.domain.club.dto.ClubPositionCreateRequest; -import gg.agit.konect.domain.club.dto.ClubPositionUpdateRequest; -import gg.agit.konect.domain.club.dto.ClubPositionsResponse; -import gg.agit.konect.domain.club.dto.ClubProfileUpdateRequest; -import gg.agit.konect.domain.club.dto.ClubRecruitmentCreateRequest; -import gg.agit.konect.domain.club.dto.ClubRecruitmentResponse; -import gg.agit.konect.domain.club.dto.ClubRecruitmentUpdateRequest; -import gg.agit.konect.domain.club.dto.ClubTagsResponse; -import gg.agit.konect.domain.club.dto.ClubsResponse; -import gg.agit.konect.domain.club.dto.MemberPositionChangeRequest; -import gg.agit.konect.domain.club.dto.PresidentTransferRequest; -import gg.agit.konect.domain.club.dto.VicePresidentChangeRequest; -import gg.agit.konect.global.auth.annotation.UserId; -import io.swagger.v3.oas.annotations.Operation; -import io.swagger.v3.oas.annotations.tags.Tag; -import jakarta.validation.Valid; - -@Tag(name = "(Normal) Club: 동아리", description = "동아리 API") -@RequestMapping("/clubs") -public interface ClubApi { - - @Operation(summary = "페이지 네이션으로 동아리 리스트를 조회한다.", description = """ - - isRecruiting가 true일 경우, 모집 중인 동아리만 조회하며 모집일(마감일)이 빠른 순으로 정렬됩니다. - - isRecruiting가 false일 경우, 전체 동아리를 조회하되 모집 중인 동아리를 먼저 보여줍니다. - - status은 BEFORE(모집 전), ONGOING(모집 중), CLOSED(모집 마감)으로 반환됩니다. - """) - @GetMapping - ResponseEntity getClubs( - @Valid @ParameterObject @ModelAttribute ClubCondition condition, - @UserId Integer userId - ); - - @Operation(summary = "동아리의 상세 정보를 조회한다.", description = """ - - recruitmentStatus는 모집 기간에 따라 BEFORE(모집 전), ONGOING(모집 중), CLOSED(모집 마감)으로 반환됩니다. - - 모집 일정 데이터가 존재하지 않는다면 CLOSED(모집 마감)으로 간주되며, startDate, endDate는 null로 반환됩니다. - - 동아리 멤버이거나 지원 이력이 존재할 경우 isApplied는 true로 반환됩니다. - """) - @GetMapping("/{clubId}") - ResponseEntity getClubDetail( - @PathVariable(name = "clubId") Integer clubId, - @UserId Integer userId - ); - - @Operation(summary = "새로운 동아리를 생성한다.", description = """ - 새로운 동아리를 생성하고, 생성한 사용자를 회장으로 등록합니다. - - ## 에러 - - NOT_FOUND_USER (404): 유저를 찾을 수 없습니다. - """) - @PostMapping - ResponseEntity createClub( - @Valid @RequestBody ClubCreateRequest request, - @UserId Integer userId - ); - - @Operation(summary = "동아리 프로필을 수정한다.", description = """ - 동아리 회장 또는 부회장만 동아리 프로필을 수정할 수 있습니다. - 수정 가능 항목: 한 줄 소개, 로고 이미지, 태그 - 동아리명과 분과는 수정할 수 없으며, 변경이 필요한 경우 문의하기를 통해 어드민에게 요청하세요. - - ## 에러 - - FORBIDDEN_CLUB_MANAGER_ACCESS (403): 동아리 매니저 권한이 없습니다. - - NOT_FOUND_CLUB (404): 동아리를 찾을 수 없습니다. - - NOT_FOUND_USER (404): 유저를 찾을 수 없습니다. - """) - @PutMapping("/{clubId}/profile") - ResponseEntity updateProfile( - @PathVariable(name = "clubId") Integer clubId, - @Valid @RequestBody ClubProfileUpdateRequest request, - @UserId Integer userId - ); - - @Operation(summary = "동아리 상세정보를 수정한다.", description = """ - 동아리 회장 또는 부회장만 동아리 상세정보를 수정할 수 있습니다. - 수정 가능 항목: 동방 위치, 상세 소개 - - ## 에러 - - FORBIDDEN_CLUB_MANAGER_ACCESS (403): 동아리 매니저 권한이 없습니다. - - NOT_FOUND_CLUB (404): 동아리를 찾을 수 없습니다. - - NOT_FOUND_USER (404): 유저를 찾을 수 없습니다. - """) - @PutMapping("/{clubId}/details") - ResponseEntity updateDetails( - @PathVariable(name = "clubId") Integer clubId, - @Valid @RequestBody ClubDetailUpdateRequest request, - @UserId Integer userId - ); - - @Operation(summary = "동아리 기본정보를 수정한다 (어드민 전용).", description = """ - 어드민만 동아리 기본정보를 수정할 수 있습니다. - 수정 가능 항목: 동아리명, 분과 - 일반 관리자는 이 API를 사용할 수 없으며, 변경이 필요한 경우 문의하기를 통해 어드민에게 요청하세요. - - ## 에러 - - FORBIDDEN_CLUB_MANAGER_ACCESS (403): 어드민 권한이 없습니다. - - NOT_FOUND_CLUB (404): 동아리를 찾을 수 없습니다. - - NOT_FOUND_USER (404): 유저를 찾을 수 없습니다. - """) - @PutMapping("/{clubId}/basic-info") - ResponseEntity updateBasicInfo( - @PathVariable(name = "clubId") Integer clubId, - @Valid @RequestBody ClubBasicInfoUpdateRequest request, - @UserId Integer userId - ); - - @Operation(summary = "사용 가능한 전체 태그 목록을 조회한다.") - @GetMapping("/tags") - ResponseEntity getTags(); - - @Operation(summary = "가입한 동아리 리스트를 조회한다.") - @GetMapping("/joined") - ResponseEntity getJoinedClubs( - @UserId Integer userId - ); - - @Operation(summary = "관리자 권한을 가지고 있는 동아리 리스트를 조회한다.") - @GetMapping("/managed") - ResponseEntity getManagedClubs( - @UserId Integer userId - ); - - @Operation(summary = "가입 승인 대기 중인 동아리 리스트를 조회한다.") - @GetMapping("/applied") - ResponseEntity getAppliedClubs( - @UserId Integer userId - ); - - @Operation(summary = "동아리 지원 내역을 조회한다.", description = """ - - 동아리 관리자만 해당 동아리의 지원 내역을 조회할 수 있습니다. - - 현재 지정된 모집 일정 범위에 지원한 내역만 볼 수 있습니다. - - 상시 모집의 경우 모든 내역을 봅니다. - - ## 에러 - - FORBIDDEN_CLUB_MANAGER_ACCESS (403): 동아리 매니저 권한이 없습니다. - - NOT_FOUND_CLUB (404): 동아리를 찾을 수 없습니다. - - NOT_FOUND_CLUB_RECRUITMENT (404): 동아리 모집 공고를 찾을 수 없습니다. - """) - @GetMapping("/{clubId}/applications") - ResponseEntity getClubApplications( - @PathVariable(name = "clubId") Integer clubId, - @UserId Integer userId - ); - - @Operation(summary = "동아리 지원 답변을 조회한다.", description = """ - - 동아리 관리자만 해당 동아리의 지원 답변을 조회할 수 있습니다. - - ## 에러 - - FORBIDDEN_CLUB_MANAGER_ACCESS (403): 동아리 매니저 권한이 없습니다. - - NOT_FOUND_CLUB (404): 동아리를 찾을 수 없습니다. - - NOT_FOUND_CLUB_APPLY (404): 동아리 지원 내역을 찾을 수 없습니다. - """) - @GetMapping("/{clubId}/applications/{applicationId}") - ResponseEntity getClubApplicationAnswers( - @PathVariable(name = "clubId") Integer clubId, - @PathVariable(name = "applicationId") Integer applicationId, - @UserId Integer userId - ); - - @Operation(summary = "동아리 멤버 리스트를 조회한다.", description = """ - 동아리 회원만 멤버 리스트를 조회할 수 있습니다. - positionGroup 파라미터로 특정 직책 그룹의 회원만 필터링할 수 있습니다. - - ## 에러 - - FORBIDDEN_CLUB_MEMBER_ACCESS (403): 동아리 멤버 조회 권한이 없습니다. - """) - @GetMapping("/{clubId}/members") - ResponseEntity getClubMembers( - @PathVariable(name = "clubId") Integer clubId, - @Valid @ParameterObject @ModelAttribute ClubMemberCondition condition, - @UserId Integer userId - ); - - @Operation(summary = "동아리 가입 신청을 한다.", description = """ - 동아리 가입 신청서를 제출합니다. - 설문 질문이 없는 경우 answers는 빈 배열을 전달합니다. - - - ALREADY_APPLIED_CLUB (409): 이미 가입 신청을 완료한 사용자입니다. - - NOT_FOUND_CLUB_APPLY_QUESTION (404): 존재하지 않는 가입 문항입니다. - - DUPLICATE_CLUB_APPLY_QUESTION (409): 중복된 id의 가입 문항이 포함되어 있습니다. - - REQUIRED_CLUB_APPLY_ANSWER_MISSING (400): 필수 가입 답변이 누락되었습니다. - """) - @PostMapping("/{clubId}/apply") - ResponseEntity applyClub( - @PathVariable(name = "clubId") Integer clubId, - @Valid @RequestBody ClubApplyRequest request, - @UserId Integer userId - ); - - @Operation(summary = "동아리 회비 정보를 조회한다.", description = """ - 동아리 가입 신청을 완료했거나 동아리 관리자 권한이 있는 사용자만 회비 계좌 정보를 조회할 수 있습니다. - - ## 에러 - - FORBIDDEN_CLUB_FEE_INFO (403): 회비 정보 조회 권한이 없습니다. - """) - @GetMapping("/{clubId}/fee") - ResponseEntity getFeeInfo( - @PathVariable(name = "clubId") Integer clubId, - @UserId Integer userId - ); - - @Operation(summary = "동아리 회비 정보를 덮어써서 대체한다.", description = """ - 요청 본문이 최종 상태가 됩니다. - - 모든 필드를 전달하면 생성/수정합니다. - - 모든 필드가 null이면 회비 정보를 삭제합니다. - - 일부 필드가 누락된 경우 에러가 발생합니다. - - ## 에러 - - FORBIDDEN_CLUB_MANAGER_ACCESS (403): 동아리 매니저 권한이 없습니다. - - INVALID_REQUEST_BODY (400): 요청 본문의 형식이 올바르지 않거나 필수 값이 누락된 경우 - """) - @PutMapping("/{clubId}/fee") - ResponseEntity replaceFeeInfo( - @PathVariable(name = "clubId") Integer clubId, - @Valid @RequestBody ClubFeeInfoReplaceRequest request, - @UserId Integer userId - ); - - @Operation(summary = "동아리 가입 문항을 조회한다.") - @GetMapping("/{clubId}/questions") - ResponseEntity getApplyQuestions( - @PathVariable(name = "clubId") Integer clubId, - @UserId Integer userId - ); - - @Operation(summary = "동아리 가입 문항을 덮어써서 대체한다.", description = """ - 요청에 포함된 문항 목록이 최종 상태가 됩니다. - - questionId가 있으면 수정 - - questionId가 없으면 생성 - - 요청에 없는 기존 문항은 삭제됩니다. - - 저장된 문항 목록을 반환합니다. - - ## 에러 - - FORBIDDEN_CLUB_MANAGER_ACCESS (403): 동아리 매니저 권한이 없습니다. - - NOT_FOUND_CLUB_APPLY_QUESTION (404): 존재하지 않는 가입 문항입니다. - - DUPLICATE_CLUB_APPLY_QUESTION (409): 중복된 id의 가입 문항이 포함되어 있습니다. - """) - @PutMapping("/{clubId}/questions") - ResponseEntity replaceApplyQuestions( - @PathVariable(name = "clubId") Integer clubId, - @Valid @RequestBody ClubApplyQuestionsReplaceRequest request, - @UserId Integer userId - ); - - @Operation(summary = "동아리 모집 정보를 조회한다.", description = """ - 동아리의 모집 공고 상세 정보를 조회합니다. - - - status는 모집 기간에 따라 BEFORE(모집 전), ONGOING(모집 중), CLOSED(모집 마감)으로 반환됩니다. - - 동아리 멤버이거나 지원 이력이 존재할 경우 isApplied는 true로 반환됩니다. - - ## 에러 - - NOT_FOUND_CLUB (404): 동아리를 찾을 수 없습니다. - - NOT_FOUND_USER (404): 유저를 찾을 수 없습니다. - - NOT_FOUND_CLUB_RECRUITMENT (404): 동아리 모집 공고를 찾을 수 없습니다. - """) - @GetMapping("/{clubId}/recruitments") - ResponseEntity getRecruitments( - @PathVariable(name = "clubId") Integer clubId, - @UserId Integer userId - ); - - @Operation(summary = "동아리 모집 정보를 생성한다.", description = """ - 동아리 회장만 모집 공고를 생성할 수 있습니다. - 한 동아리당 하나의 모집 공고만 생성 가능합니다. - - ## 에러 - - INVALID_RECRUITMENT_DATE_NOT_ALLOWED (400): 상시 모집인 경우 모집 시작일과 마감일을 지정할 수 없습니다. - - INVALID_RECRUITMENT_DATE_REQUIRED (400): 상시 모집이 아닐 경우 모집 시작일과 마감일이 필수입니다. - - INVALID_RECRUITMENT_PERIOD (400): 모집 시작일은 모집 마감일보다 이전이어야 합니다. - - FORBIDDEN_CLUB_RECRUITMENT_CREATE (403): 동아리 모집 공고를 생성할 권한이 없습니다. - - NOT_FOUND_CLUB (404): 동아리를 찾을 수 없습니다. - - NOT_FOUND_USER (404): 유저를 찾을 수 없습니다. - - ALREADY_EXIST_CLUB_RECRUITMENT (409): 이미 동아리 모집 공고가 존재합니다. - """) - @PostMapping("/{clubId}/recruitments") - ResponseEntity createRecruitment( - @RequestBody @Valid ClubRecruitmentCreateRequest request, - @PathVariable(name = "clubId") Integer clubId, - @UserId Integer userId - ); - - @Operation(summary = "동아리 모집 정보를 수정한다.", description = """ - 동아리 회장 또는 부회장만 모집 공고를 수정할 수 있습니다. - - ## 에러 - - INVALID_RECRUITMENT_DATE_NOT_ALLOWED (400): 상시 모집인 경우 모집 시작일과 마감일을 지정할 수 없습니다. - - INVALID_RECRUITMENT_DATE_REQUIRED (400): 상시 모집이 아닐 경우 모집 시작일과 마감일이 필수입니다. - - INVALID_RECRUITMENT_PERIOD (400): 모집 시작일은 모집 마감일보다 이전이어야 합니다. - - FORBIDDEN_CLUB_MANAGER_ACCESS (403): 동아리 매니저 권한이 없습니다. - - NOT_FOUND_CLUB (404): 동아리를 찾을 수 없습니다. - - NOT_FOUND_USER (404): 유저를 찾을 수 없습니다. - - NOT_FOUND_CLUB_RECRUITMENT (404): 동아리 모집 공고를 찾을 수 없습니다. - """) - @PutMapping("/{clubId}/recruitments") - ResponseEntity updateRecruitment( - @Valid @RequestBody ClubRecruitmentUpdateRequest request, - @PathVariable(name = "clubId") Integer clubId, - @UserId Integer userId - ); - - @Operation(summary = "동아리 직책 목록을 조회한다.", description = """ - 동아리의 모든 직책을 우선순위 순으로 조회합니다. - 각 직책의 회원 수, 수정/삭제 가능 여부도 함께 반환됩니다. - - ## 에러 - - NOT_FOUND_CLUB (404): 동아리를 찾을 수 없습니다. - """) - @GetMapping("/{clubId}/positions") - ResponseEntity getClubPositions( - @PathVariable(name = "clubId") Integer clubId, - @UserId Integer userId - ); - - @Operation(summary = "동아리 직책을 생성한다.", description = """ - 동아리 회장 또는 부회장만 직책을 생성할 수 있습니다. - PRESIDENT와 VICE_PRESIDENT 직책은 생성할 수 없으며, MANAGER 또는 MEMBER 그룹의 직책만 생성 가능합니다. - - ## 에러 - - POSITION_NAME_DUPLICATED (400): 동일한 직책 이름이 이미 존재합니다. - - FORBIDDEN_CLUB_MANAGER_ACCESS (403): 동아리 매니저 권한이 없습니다. - - NOT_FOUND_CLUB (404): 동아리를 찾을 수 없습니다. - """) - @PostMapping("/{clubId}/positions") - ResponseEntity createClubPosition( - @PathVariable(name = "clubId") Integer clubId, - @Valid @RequestBody ClubPositionCreateRequest request, - @UserId Integer userId - ); - - @Operation(summary = "동아리 직책의 이름을 수정한다.", description = """ - 동아리 회장 또는 부회장만 직책 이름을 수정할 수 있습니다. - PRESIDENT와 VICE_PRESIDENT 직책의 이름은 변경할 수 없습니다. - - ## 에러 - - POSITION_NAME_DUPLICATED (400): 동일한 직책 이름이 이미 존재합니다. - - FORBIDDEN_CLUB_MANAGER_ACCESS (403): 동아리 매니저 권한이 없습니다. - - FORBIDDEN_POSITION_NAME_CHANGE (403): 해당 직책의 이름은 변경할 수 없습니다. - - NOT_FOUND_CLUB (404): 동아리를 찾을 수 없습니다. - - NOT_FOUND_CLUB_POSITION (404): 동아리 직책을 찾을 수 없습니다. - """) - @PatchMapping("/{clubId}/positions/{positionId}") - ResponseEntity updateClubPositionName( - @PathVariable(name = "clubId") Integer clubId, - @PathVariable(name = "positionId") Integer positionId, - @Valid @RequestBody ClubPositionUpdateRequest request, - @UserId Integer userId - ); - - @Operation(summary = "동아리 직책을 삭제한다.", description = """ - 동아리 회장 또는 부회장만 직책을 삭제할 수 있습니다. - PRESIDENT와 VICE_PRESIDENT 직책은 삭제할 수 없습니다. - 해당 직책을 사용 중인 회원이 없어야 하며, 해당 그룹에 최소 2개의 직책이 있어야 삭제 가능합니다. - - ## 에러 - - CANNOT_DELETE_ESSENTIAL_POSITION (400): 필수 직책은 삭제할 수 없습니다. - - POSITION_IN_USE (400): 해당 직책을 사용 중인 회원이 있어 삭제할 수 없습니다. - - INSUFFICIENT_POSITION_COUNT (400): 해당 그룹에 최소 2개의 직책이 있어야 삭제 가능합니다. - - FORBIDDEN_CLUB_MANAGER_ACCESS (403): 동아리 매니저 권한이 없습니다. - - NOT_FOUND_CLUB (404): 동아리를 찾을 수 없습니다. - - NOT_FOUND_CLUB_POSITION (404): 동아리 직책을 찾을 수 없습니다. - """) - @DeleteMapping("/{clubId}/positions/{positionId}") - ResponseEntity deleteClubPosition( - @PathVariable(name = "clubId") Integer clubId, - @PathVariable(name = "positionId") Integer positionId, - @UserId Integer userId - ); - - @Operation(summary = "동아리 회원의 직책을 변경한다.", description = """ - 동아리 회장 또는 부회장만 회원의 직책을 변경할 수 있습니다. - 자기 자신의 직책은 변경할 수 없으며, 상위 직급만 하위 직급의 회원을 관리할 수 있습니다. - - ## 에러 - - CANNOT_CHANGE_OWN_POSITION (400): 자기 자신의 직책은 변경할 수 없습니다. - - CANNOT_MANAGE_HIGHER_POSITION (400): 자신보다 높은 직급의 회원은 관리할 수 없습니다. - - VICE_PRESIDENT_ALREADY_EXISTS (409): 부회장은 이미 존재합니다. - - MANAGER_LIMIT_EXCEEDED (400): 운영진은 최대 20명까지 임명 가능합니다. - - FORBIDDEN_MEMBER_POSITION_CHANGE (403): 회원 직책 변경 권한이 없습니다. - - NOT_FOUND_CLUB (404): 동아리를 찾을 수 없습니다. - - NOT_FOUND_CLUB_MEMBER (404): 동아리 회원을 찾을 수 없습니다. - - NOT_FOUND_CLUB_POSITION (404): 동아리 직책을 찾을 수 없습니다. - """) - @PatchMapping("/{clubId}/members/{memberId}/position") - ResponseEntity changeMemberPosition( - @PathVariable(name = "clubId") Integer clubId, - @PathVariable(name = "memberId") Integer memberId, - @Valid @RequestBody MemberPositionChangeRequest request, - @UserId Integer userId - ); - - @Operation(summary = "동아리 회장 권한을 위임한다.", description = """ - 현재 회장만 회장 권한을 다른 회원에게 위임할 수 있습니다. - 회장 위임 시 현재 회장은 일반회원으로 강등됩니다. - - ## 에러 - - ILLEGAL_ARGUMENT (400): 자기 자신에게는 위임할 수 없습니다. - - FORBIDDEN_CLUB_MANAGER_ACCESS (403): 동아리 회장 권한이 없습니다. - - NOT_FOUND_CLUB (404): 동아리를 찾을 수 없습니다. - - NOT_FOUND_CLUB_MEMBER (404): 동아리 회원을 찾을 수 없습니다. - - NOT_FOUND_CLUB_PRESIDENT (404): 동아리 회장을 찾을 수 없습니다. - - NOT_FOUND_CLUB_POSITION (404): 동아리 직책을 찾을 수 없습니다. - """) - @PostMapping("/{clubId}/president/transfer") - ResponseEntity transferPresident( - @PathVariable(name = "clubId") Integer clubId, - @Valid @RequestBody PresidentTransferRequest request, - @UserId Integer userId - ); - - @Operation(summary = "동아리 부회장을 변경한다.", description = """ - 동아리 회장만 부회장을 임명하거나 해제할 수 있습니다. - vicePresidentUserId가 null이면 부회장을 해제하고, 값이 있으면 해당 회원을 부회장으로 임명합니다. - - ## 에러 - - CANNOT_CHANGE_OWN_POSITION (400): 자기 자신을 부회장으로 임명할 수 없습니다. - - FORBIDDEN_CLUB_MANAGER_ACCESS (403): 동아리 회장 권한이 없습니다. - - NOT_FOUND_CLUB (404): 동아리를 찾을 수 없습니다. - - NOT_FOUND_CLUB_MEMBER (404): 동아리 회원을 찾을 수 없습니다. - - NOT_FOUND_CLUB_POSITION (404): 동아리 직책을 찾을 수 없습니다. - """) - @PatchMapping("/{clubId}/vice-president") - ResponseEntity changeVicePresident( - @PathVariable(name = "clubId") Integer clubId, - @Valid @RequestBody VicePresidentChangeRequest request, - @UserId Integer userId - ); - - @Operation(summary = "동아리에 회원을 직접 추가한다.", description = """ - 동아리 회장 또는 부회장만 회원을 직접 추가할 수 있습니다. - 회장 직책으로는 추가할 수 없으며, 부회장과 운영진은 인원 제한이 있습니다. - - ## 에러 - - ALREADY_CLUB_MEMBER (409): 이미 동아리 회원입니다. - - VICE_PRESIDENT_ALREADY_EXISTS (409): 부회장은 이미 존재합니다. - - MANAGER_LIMIT_EXCEEDED (400): 운영진은 최대 20명까지 임명 가능합니다. - - FORBIDDEN_MEMBER_POSITION_CHANGE (403): 회원 추가 권한이 없습니다. - - NOT_FOUND_CLUB (404): 동아리를 찾을 수 없습니다. - - NOT_FOUND_USER (404): 유저를 찾을 수 없습니다. - - NOT_FOUND_CLUB_POSITION (404): 동아리 직책을 찾을 수 없습니다. - """) - @PostMapping("/{clubId}/members") - ResponseEntity addMember( - @PathVariable(name = "clubId") Integer clubId, - @Valid @RequestBody ClubMemberAddRequest request, - @UserId Integer userId - ); - - @Operation(summary = "동아리 회원을 강제 탈퇴시킨다.", description = """ - 동아리 회장 또는 부회장만 회원을 강제 탈퇴시킬 수 있습니다. - 일반회원만 강제 탈퇴 가능하며, 부회장이나 운영진은 먼저 직책을 변경한 후 탈퇴시켜야 합니다. - - ## 에러 - - CANNOT_REMOVE_SELF (400): 자기 자신을 강제 탈퇴시킬 수 없습니다. - - CANNOT_REMOVE_NON_MEMBER (400): 일반회원만 강제 탈퇴할 수 있습니다. - - CANNOT_DELETE_CLUB_PRESIDENT (400): 회장은 강제 탈퇴시킬 수 없습니다. - - CANNOT_MANAGE_HIGHER_POSITION (400): 자신보다 높은 직급의 회원은 관리할 수 없습니다. - - FORBIDDEN_MEMBER_POSITION_CHANGE (403): 회원 관리 권한이 없습니다. - - NOT_FOUND_CLUB (404): 동아리를 찾을 수 없습니다. - - NOT_FOUND_CLUB_MEMBER (404): 동아리 회원을 찾을 수 없습니다. - """) - @DeleteMapping("/{clubId}/members/{memberId}") - ResponseEntity removeMember( - @PathVariable(name = "clubId") Integer clubId, - @PathVariable(name = "memberId") Integer memberId, - @UserId Integer userId - ); -} diff --git a/src/main/java/gg/agit/konect/domain/club/controller/ClubApplicationApi.java b/src/main/java/gg/agit/konect/domain/club/controller/ClubApplicationApi.java new file mode 100644 index 00000000..eb7d8af1 --- /dev/null +++ b/src/main/java/gg/agit/konect/domain/club/controller/ClubApplicationApi.java @@ -0,0 +1,128 @@ +package gg.agit.konect.domain.club.controller; + +import org.springframework.http.ResponseEntity; +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 gg.agit.konect.domain.club.dto.ClubApplicationAnswersResponse; +import gg.agit.konect.domain.club.dto.ClubApplicationsResponse; +import gg.agit.konect.domain.club.dto.ClubApplyQuestionsReplaceRequest; +import gg.agit.konect.domain.club.dto.ClubApplyQuestionsResponse; +import gg.agit.konect.domain.club.dto.ClubApplyRequest; +import gg.agit.konect.domain.club.dto.ClubFeeInfoReplaceRequest; +import gg.agit.konect.domain.club.dto.ClubFeeInfoResponse; +import gg.agit.konect.global.auth.annotation.UserId; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.validation.Valid; + +@Tag(name = "Club Application: 지원 및 신청 관리", description = "동아리 지원, 지원서 관리, 회비 정보 API") +@RequestMapping("/clubs") +public interface ClubApplicationApi { + + @Operation(summary = "동아리 가입 신청을 한다.", description = """ + 동아리 가입 신청서를 제출합니다. + 설문 질문이 없는 경우 answers는 빈 배열을 전달합니다. + + - ALREADY_APPLIED_CLUB (409): 이미 가입 신청을 완료한 사용자입니다. + - NOT_FOUND_CLUB_APPLY_QUESTION (404): 존재하지 않는 가입 문항입니다. + - DUPLICATE_CLUB_APPLY_QUESTION (409): 중복된 id의 가입 문항이 포함되어 있습니다. + - REQUIRED_CLUB_APPLY_ANSWER_MISSING (400): 필수 가입 답변이 누락되었습니다. + """) + @PostMapping("/{clubId}/apply") + ResponseEntity applyClub( + @PathVariable(name = "clubId") Integer clubId, + @Valid @RequestBody ClubApplyRequest request, + @UserId Integer userId + ); + + @Operation(summary = "동아리 지원 내역을 조회한다.", description = """ + - 동아리 관리자만 해당 동아리의 지원 내역을 조회할 수 있습니다. + - 현재 지정된 모집 일정 범위에 지원한 내역만 볼 수 있습니다. + - 상시 모집의 경우 모든 내역을 봅니다. + + ## 에러 + - FORBIDDEN_CLUB_MANAGER_ACCESS (403): 동아리 매니저 권한이 없습니다. + - NOT_FOUND_CLUB (404): 동아리를 찾을 수 없습니다. + - NOT_FOUND_CLUB_RECRUITMENT (404): 동아리 모집 공고를 찾을 수 없습니다. + """) + @GetMapping("/{clubId}/applications") + ResponseEntity getClubApplications( + @PathVariable(name = "clubId") Integer clubId, + @UserId Integer userId + ); + + @Operation(summary = "동아리 지원 답변을 조회한다.", description = """ + - 동아리 관리자만 해당 동아리의 지원 답변을 조회할 수 있습니다. + + ## 에러 + - FORBIDDEN_CLUB_MANAGER_ACCESS (403): 동아리 매니저 권한이 없습니다. + - NOT_FOUND_CLUB (404): 동아리를 찾을 수 없습니다. + - NOT_FOUND_CLUB_APPLY (404): 동아리 지원 내역을 찾을 수 없습니다. + """) + @GetMapping("/{clubId}/applications/{applicationId}") + ResponseEntity getClubApplicationAnswers( + @PathVariable(name = "clubId") Integer clubId, + @PathVariable(name = "applicationId") Integer applicationId, + @UserId Integer userId + ); + + @Operation(summary = "동아리 가입 문항을 조회한다.") + @GetMapping("/{clubId}/questions") + ResponseEntity getApplyQuestions( + @PathVariable(name = "clubId") Integer clubId, + @UserId Integer userId + ); + + @Operation(summary = "동아리 가입 문항을 덮어써서 대체한다.", description = """ + 요청에 포함된 문항 목록이 최종 상태가 됩니다. + - questionId가 있으면 수정 + - questionId가 없으면 생성 + - 요청에 없는 기존 문항은 삭제됩니다. + - 저장된 문항 목록을 반환합니다. + + ## 에러 + - FORBIDDEN_CLUB_MANAGER_ACCESS (403): 동아리 매니저 권한이 없습니다. + - NOT_FOUND_CLUB_APPLY_QUESTION (404): 존재하지 않는 가입 문항입니다. + - DUPLICATE_CLUB_APPLY_QUESTION (409): 중복된 id의 가입 문항이 포함되어 있습니다. + """) + @PutMapping("/{clubId}/questions") + ResponseEntity replaceApplyQuestions( + @PathVariable(name = "clubId") Integer clubId, + @Valid @RequestBody ClubApplyQuestionsReplaceRequest request, + @UserId Integer userId + ); + + @Operation(summary = "동아리 회비 정보를 조회한다.", description = """ + 동아리 가입 신청을 완료했거나 동아리 관리자 권한이 있는 사용자만 회비 계좌 정보를 조회할 수 있습니다. + + ## 에러 + - FORBIDDEN_CLUB_FEE_INFO (403): 회비 정보 조회 권한이 없습니다. + """) + @GetMapping("/{clubId}/fee") + ResponseEntity getFeeInfo( + @PathVariable(name = "clubId") Integer clubId, + @UserId Integer userId + ); + + @Operation(summary = "동아리 회비 정보를 덮어써서 대체한다.", description = """ + 요청 본문이 최종 상태가 됩니다. + - 모든 필드를 전달하면 생성/수정합니다. + - 모든 필드가 null이면 회비 정보를 삭제합니다. + - 일부 필드가 누락된 경우 에러가 발생합니다. + + ## 에러 + - FORBIDDEN_CLUB_MANAGER_ACCESS (403): 동아리 매니저 권한이 없습니다. + - INVALID_REQUEST_BODY (400): 요청 본문의 형식이 올바르지 않거나 필수 값이 누락된 경우 + """) + @PutMapping("/{clubId}/fee") + ResponseEntity replaceFeeInfo( + @PathVariable(name = "clubId") Integer clubId, + @Valid @RequestBody ClubFeeInfoReplaceRequest request, + @UserId Integer userId + ); +} diff --git a/src/main/java/gg/agit/konect/domain/club/controller/ClubBasicApi.java b/src/main/java/gg/agit/konect/domain/club/controller/ClubBasicApi.java new file mode 100644 index 00000000..743d6aab --- /dev/null +++ b/src/main/java/gg/agit/konect/domain/club/controller/ClubBasicApi.java @@ -0,0 +1,153 @@ +package gg.agit.konect.domain.club.controller; + +import org.springdoc.core.annotations.ParameterObject; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.ModelAttribute; +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 gg.agit.konect.domain.club.dto.ClubAppliedClubsResponse; +import gg.agit.konect.domain.club.dto.ClubBasicInfoUpdateRequest; +import gg.agit.konect.domain.club.dto.ClubCondition; +import gg.agit.konect.domain.club.dto.ClubCreateRequest; +import gg.agit.konect.domain.club.dto.ClubDetailResponse; +import gg.agit.konect.domain.club.dto.ClubDetailUpdateRequest; +import gg.agit.konect.domain.club.dto.ClubMemberCondition; +import gg.agit.konect.domain.club.dto.ClubMembersResponse; +import gg.agit.konect.domain.club.dto.ClubMembershipsResponse; +import gg.agit.konect.domain.club.dto.ClubProfileUpdateRequest; +import gg.agit.konect.domain.club.dto.ClubTagsResponse; +import gg.agit.konect.domain.club.dto.ClubsResponse; +import gg.agit.konect.global.auth.annotation.UserId; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.validation.Valid; + +@Tag(name = "Club: 동아리 기본 관리", description = "동아리 조회, 생성, 수정 및 기본 관리 API") +@RequestMapping("/clubs") +public interface ClubBasicApi { + + @Operation(summary = "페이지 네이션으로 동아리 리스트를 조회한다.", description = """ + - isRecruiting가 true일 경우, 모집 중인 동아리만 조회하며 모집일(마감일)이 빠른 순으로 정렬됩니다. + - isRecruiting가 false일 경우, 전체 동아리를 조회하되 모집 중인 동아리를 먼저 보여줍니다. + - status은 BEFORE(모집 전), ONGOING(모집 중), CLOSED(모집 마감)으로 반환됩니다. + """) + @GetMapping + ResponseEntity getClubs( + @Valid @ParameterObject @ModelAttribute ClubCondition condition, + @UserId Integer userId + ); + + @Operation(summary = "동아리의 상세 정보를 조회한다.", description = """ + - recruitmentStatus는 모집 기간에 따라 BEFORE(모집 전), ONGOING(모집 중), CLOSED(모집 마감)으로 반환됩니다. + - 모집 일정 데이터가 존재하지 않는다면 CLOSED(모집 마감)으로 간주되며, startDate, endDate는 null로 반환됩니다. + - 동아리 멤버이거나 지원 이력이 존재할 경우 isApplied는 true로 반환됩니다. + """) + @GetMapping("/{clubId}") + ResponseEntity getClubDetail( + @PathVariable(name = "clubId") Integer clubId, + @UserId Integer userId + ); + + @Operation(summary = "새로운 동아리를 생성한다.", description = """ + 새로운 동아리를 생성하고, 생성한 사용자를 회장으로 등록합니다. + + ## 에러 + - NOT_FOUND_USER (404): 유저를 찾을 수 없습니다. + """) + @PostMapping + ResponseEntity createClub( + @Valid @RequestBody ClubCreateRequest request, + @UserId Integer userId + ); + + @Operation(summary = "동아리 프로필을 수정한다.", description = """ + 동아리 회장 또는 부회장만 동아리 프로필을 수정할 수 있습니다. + 수정 가능 항목: 한 줄 소개, 로고 이미지, 태그 + 동아리명과 분과는 수정할 수 없으며, 변경이 필요한 경우 문의하기를 통해 어드민에게 요청하세요. + + ## 에러 + - FORBIDDEN_CLUB_MANAGER_ACCESS (403): 동아리 매니저 권한이 없습니다. + - NOT_FOUND_CLUB (404): 동아리를 찾을 수 없습니다. + - NOT_FOUND_USER (404): 유저를 찾을 수 없습니다. + """) + @PutMapping("/{clubId}/profile") + ResponseEntity updateProfile( + @PathVariable(name = "clubId") Integer clubId, + @Valid @RequestBody ClubProfileUpdateRequest request, + @UserId Integer userId + ); + + @Operation(summary = "동아리 상세정보를 수정한다.", description = """ + 동아리 회장 또는 부회장만 동아리 상세정보를 수정할 수 있습니다. + 수정 가능 항목: 동방 위치, 상세 소개 + + ## 에러 + - FORBIDDEN_CLUB_MANAGER_ACCESS (403): 동아리 매니저 권한이 없습니다. + - NOT_FOUND_CLUB (404): 동아리를 찾을 수 없습니다. + - NOT_FOUND_USER (404): 유저를 찾을 수 없습니다. + """) + @PutMapping("/{clubId}/details") + ResponseEntity updateDetails( + @PathVariable(name = "clubId") Integer clubId, + @Valid @RequestBody ClubDetailUpdateRequest request, + @UserId Integer userId + ); + + @Operation(summary = "동아리 기본정보를 수정한다 (어드민 전용).", description = """ + 어드민만 동아리 기본정보를 수정할 수 있습니다. + 수정 가능 항목: 동아리명, 분과 + 일반 관리자는 이 API를 사용할 수 없으며, 변경이 필요한 경우 문의하기를 통해 어드민에게 요청하세요. + + ## 에러 + - FORBIDDEN_CLUB_MANAGER_ACCESS (403): 어드민 권한이 없습니다. + - NOT_FOUND_CLUB (404): 동아리를 찾을 수 없습니다. + - NOT_FOUND_USER (404): 유저를 찾을 수 없습니다. + """) + @PutMapping("/{clubId}/basic-info") + ResponseEntity updateBasicInfo( + @PathVariable(name = "clubId") Integer clubId, + @Valid @RequestBody ClubBasicInfoUpdateRequest request, + @UserId Integer userId + ); + + @Operation(summary = "사용 가능한 전체 태그 목록을 조회한다.") + @GetMapping("/tags") + ResponseEntity getTags(); + + @Operation(summary = "가입한 동아리 리스트를 조회한다.") + @GetMapping("/joined") + ResponseEntity getJoinedClubs( + @UserId Integer userId + ); + + @Operation(summary = "관리자 권한을 가지고 있는 동아리 리스트를 조회한다.") + @GetMapping("/managed") + ResponseEntity getManagedClubs( + @UserId Integer userId + ); + + @Operation(summary = "가입 승인 대기 중인 동아리 리스트를 조회한다.") + @GetMapping("/applied") + ResponseEntity getAppliedClubs( + @UserId Integer userId + ); + + @Operation(summary = "동아리 멤버 리스트를 조회한다.", description = """ + 동아리 회원만 멤버 리스트를 조회할 수 있습니다. + positionGroup 파라미터로 특정 직책 그룹의 회원만 필터링할 수 있습니다. + + ## 에러 + - FORBIDDEN_CLUB_MEMBER_ACCESS (403): 동아리 멤버 조회 권한이 없습니다. + """) + @GetMapping("/{clubId}/members") + ResponseEntity getClubMembers( + @PathVariable(name = "clubId") Integer clubId, + @Valid @ParameterObject @ModelAttribute ClubMemberCondition condition, + @UserId Integer userId + ); +} diff --git a/src/main/java/gg/agit/konect/domain/club/controller/ClubController.java b/src/main/java/gg/agit/konect/domain/club/controller/ClubController.java index 861b56b5..ed817616 100644 --- a/src/main/java/gg/agit/konect/domain/club/controller/ClubController.java +++ b/src/main/java/gg/agit/konect/domain/club/controller/ClubController.java @@ -47,7 +47,12 @@ @RestController @RequiredArgsConstructor @RequestMapping("/clubs") -public class ClubController implements ClubApi { +public class ClubController implements + ClubBasicApi, + ClubRecruitmentApi, + ClubApplicationApi, + ClubPositionApi, + ClubMemberApi { private final ClubService clubService; private final ClubPositionService clubPositionService; diff --git a/src/main/java/gg/agit/konect/domain/club/controller/ClubMemberApi.java b/src/main/java/gg/agit/konect/domain/club/controller/ClubMemberApi.java new file mode 100644 index 00000000..7e9e4484 --- /dev/null +++ b/src/main/java/gg/agit/konect/domain/club/controller/ClubMemberApi.java @@ -0,0 +1,122 @@ +package gg.agit.konect.domain.club.controller; + +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.PatchMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; + +import gg.agit.konect.domain.club.dto.ClubMemberAddRequest; +import gg.agit.konect.domain.club.dto.MemberPositionChangeRequest; +import gg.agit.konect.domain.club.dto.PresidentTransferRequest; +import gg.agit.konect.domain.club.dto.VicePresidentChangeRequest; +import gg.agit.konect.global.auth.annotation.UserId; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.validation.Valid; + +@Tag(name = "Club Member: 회원 관리", description = "동아리 회원 직책 변경, 추가, 제거 API") +@RequestMapping("/clubs") +public interface ClubMemberApi { + + @Operation(summary = "동아리 회원의 직책을 변경한다.", description = """ + 동아리 회장 또는 부회장만 회원의 직책을 변경할 수 있습니다. + 자기 자신의 직책은 변경할 수 없으며, 상위 직급만 하위 직급의 회원을 관리할 수 있습니다. + + ## 에러 + - CANNOT_CHANGE_OWN_POSITION (400): 자기 자신의 직책은 변경할 수 없습니다. + - CANNOT_MANAGE_HIGHER_POSITION (400): 자신보다 높은 직급의 회원은 관리할 수 없습니다. + - VICE_PRESIDENT_ALREADY_EXISTS (409): 부회장은 이미 존재합니다. + - MANAGER_LIMIT_EXCEEDED (400): 운영진은 최대 20명까지 임명 가능합니다. + - FORBIDDEN_MEMBER_POSITION_CHANGE (403): 회원 직책 변경 권한이 없습니다. + - NOT_FOUND_CLUB (404): 동아리를 찾을 수 없습니다. + - NOT_FOUND_CLUB_MEMBER (404): 동아리 회원을 찾을 수 없습니다. + - NOT_FOUND_CLUB_POSITION (404): 동아리 직책을 찾을 수 없습니다. + """) + @PatchMapping("/{clubId}/members/{memberId}/position") + ResponseEntity changeMemberPosition( + @PathVariable(name = "clubId") Integer clubId, + @PathVariable(name = "memberId") Integer memberId, + @Valid @RequestBody MemberPositionChangeRequest request, + @UserId Integer userId + ); + + @Operation(summary = "동아리 회장 권한을 위임한다.", description = """ + 현재 회장만 회장 권한을 다른 회원에게 위임할 수 있습니다. + 회장 위임 시 현재 회장은 일반회원으로 강등됩니다. + + ## 에러 + - ILLEGAL_ARGUMENT (400): 자기 자신에게는 위임할 수 없습니다. + - FORBIDDEN_CLUB_MANAGER_ACCESS (403): 동아리 회장 권한이 없습니다. + - NOT_FOUND_CLUB (404): 동아리를 찾을 수 없습니다. + - NOT_FOUND_CLUB_MEMBER (404): 동아리 회원을 찾을 수 없습니다. + - NOT_FOUND_CLUB_PRESIDENT (404): 동아리 회장을 찾을 수 없습니다. + - NOT_FOUND_CLUB_POSITION (404): 동아리 직책을 찾을 수 없습니다. + """) + @PostMapping("/{clubId}/president/transfer") + ResponseEntity transferPresident( + @PathVariable(name = "clubId") Integer clubId, + @Valid @RequestBody PresidentTransferRequest request, + @UserId Integer userId + ); + + @Operation(summary = "동아리 부회장을 변경한다.", description = """ + 동아리 회장만 부회장을 임명하거나 해제할 수 있습니다. + vicePresidentUserId가 null이면 부회장을 해제하고, 값이 있으면 해당 회원을 부회장으로 임명합니다. + + ## 에러 + - CANNOT_CHANGE_OWN_POSITION (400): 자기 자신을 부회장으로 임명할 수 없습니다. + - FORBIDDEN_CLUB_MANAGER_ACCESS (403): 동아리 회장 권한이 없습니다. + - NOT_FOUND_CLUB (404): 동아리를 찾을 수 없습니다. + - NOT_FOUND_CLUB_MEMBER (404): 동아리 회원을 찾을 수 없습니다. + - NOT_FOUND_CLUB_POSITION (404): 동아리 직책을 찾을 수 없습니다. + """) + @PatchMapping("/{clubId}/vice-president") + ResponseEntity changeVicePresident( + @PathVariable(name = "clubId") Integer clubId, + @Valid @RequestBody VicePresidentChangeRequest request, + @UserId Integer userId + ); + + @Operation(summary = "동아리에 회원을 직접 추가한다.", description = """ + 동아리 회장 또는 부회장만 회원을 직접 추가할 수 있습니다. + 회장 직책으로는 추가할 수 없으며, 부회장과 운영진은 인원 제한이 있습니다. + + ## 에러 + - ALREADY_CLUB_MEMBER (409): 이미 동아리 회원입니다. + - VICE_PRESIDENT_ALREADY_EXISTS (409): 부회장은 이미 존재합니다. + - MANAGER_LIMIT_EXCEEDED (400): 운영진은 최대 20명까지 임명 가능합니다. + - FORBIDDEN_MEMBER_POSITION_CHANGE (403): 회원 추가 권한이 없습니다. + - NOT_FOUND_CLUB (404): 동아리를 찾을 수 없습니다. + - NOT_FOUND_USER (404): 유저를 찾을 수 없습니다. + - NOT_FOUND_CLUB_POSITION (404): 동아리 직책을 찾을 수 없습니다. + """) + @PostMapping("/{clubId}/members") + ResponseEntity addMember( + @PathVariable(name = "clubId") Integer clubId, + @Valid @RequestBody ClubMemberAddRequest request, + @UserId Integer userId + ); + + @Operation(summary = "동아리 회원을 강제 탈퇴시킨다.", description = """ + 동아리 회장 또는 부회장만 회원을 강제 탈퇴시킬 수 있습니다. + 일반회원만 강제 탈퇴 가능하며, 부회장이나 운영진은 먼저 직책을 변경한 후 탈퇴시켜야 합니다. + + ## 에러 + - CANNOT_REMOVE_SELF (400): 자기 자신을 강제 탈퇴시킬 수 없습니다. + - CANNOT_REMOVE_NON_MEMBER (400): 일반회원만 강제 탈퇴할 수 있습니다. + - CANNOT_DELETE_CLUB_PRESIDENT (400): 회장은 강제 탈퇴시킬 수 없습니다. + - CANNOT_MANAGE_HIGHER_POSITION (400): 자신보다 높은 직급의 회원은 관리할 수 없습니다. + - FORBIDDEN_MEMBER_POSITION_CHANGE (403): 회원 관리 권한이 없습니다. + - NOT_FOUND_CLUB (404): 동아리를 찾을 수 없습니다. + - NOT_FOUND_CLUB_MEMBER (404): 동아리 회원을 찾을 수 없습니다. + """) + @DeleteMapping("/{clubId}/members/{memberId}") + ResponseEntity removeMember( + @PathVariable(name = "clubId") Integer clubId, + @PathVariable(name = "memberId") Integer memberId, + @UserId Integer userId + ); +} diff --git a/src/main/java/gg/agit/konect/domain/club/controller/ClubPositionApi.java b/src/main/java/gg/agit/konect/domain/club/controller/ClubPositionApi.java new file mode 100644 index 00000000..9f861024 --- /dev/null +++ b/src/main/java/gg/agit/konect/domain/club/controller/ClubPositionApi.java @@ -0,0 +1,91 @@ +package gg.agit.konect.domain.club.controller; + +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PatchMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; + +import gg.agit.konect.domain.club.dto.ClubPositionCreateRequest; +import gg.agit.konect.domain.club.dto.ClubPositionUpdateRequest; +import gg.agit.konect.domain.club.dto.ClubPositionsResponse; +import gg.agit.konect.global.auth.annotation.UserId; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.validation.Valid; + +@Tag(name = "Club Position: 직책 관리", description = "동아리 직책 생성, 수정, 삭제 API") +@RequestMapping("/clubs") +public interface ClubPositionApi { + + @Operation(summary = "동아리 직책 목록을 조회한다.", description = """ + 동아리의 모든 직책을 우선순위 순으로 조회합니다. + 각 직책의 회원 수, 수정/삭제 가능 여부도 함께 반환됩니다. + + ## 에러 + - NOT_FOUND_CLUB (404): 동아리를 찾을 수 없습니다. + """) + @GetMapping("/{clubId}/positions") + ResponseEntity getClubPositions( + @PathVariable(name = "clubId") Integer clubId, + @UserId Integer userId + ); + + @Operation(summary = "동아리 직책을 생성한다.", description = """ + 동아리 회장 또는 부회장만 직책을 생성할 수 있습니다. + PRESIDENT와 VICE_PRESIDENT 직책은 생성할 수 없으며, MANAGER 또는 MEMBER 그룹의 직책만 생성 가능합니다. + + ## 에러 + - POSITION_NAME_DUPLICATED (400): 동일한 직책 이름이 이미 존재합니다. + - FORBIDDEN_CLUB_MANAGER_ACCESS (403): 동아리 매니저 권한이 없습니다. + - NOT_FOUND_CLUB (404): 동아리를 찾을 수 없습니다. + """) + @PostMapping("/{clubId}/positions") + ResponseEntity createClubPosition( + @PathVariable(name = "clubId") Integer clubId, + @Valid @RequestBody ClubPositionCreateRequest request, + @UserId Integer userId + ); + + @Operation(summary = "동아리 직책의 이름을 수정한다.", description = """ + 동아리 회장 또는 부회장만 직책 이름을 수정할 수 있습니다. + PRESIDENT와 VICE_PRESIDENT 직책의 이름은 변경할 수 없습니다. + + ## 에러 + - POSITION_NAME_DUPLICATED (400): 동일한 직책 이름이 이미 존재합니다. + - FORBIDDEN_CLUB_MANAGER_ACCESS (403): 동아리 매니저 권한이 없습니다. + - FORBIDDEN_POSITION_NAME_CHANGE (403): 해당 직책의 이름은 변경할 수 없습니다. + - NOT_FOUND_CLUB (404): 동아리를 찾을 수 없습니다. + - NOT_FOUND_CLUB_POSITION (404): 동아리 직책을 찾을 수 없습니다. + """) + @PatchMapping("/{clubId}/positions/{positionId}") + ResponseEntity updateClubPositionName( + @PathVariable(name = "clubId") Integer clubId, + @PathVariable(name = "positionId") Integer positionId, + @Valid @RequestBody ClubPositionUpdateRequest request, + @UserId Integer userId + ); + + @Operation(summary = "동아리 직책을 삭제한다.", description = """ + 동아리 회장 또는 부회장만 직책을 삭제할 수 있습니다. + PRESIDENT와 VICE_PRESIDENT 직책은 삭제할 수 없습니다. + 해당 직책을 사용 중인 회원이 없어야 하며, 해당 그룹에 최소 2개의 직책이 있어야 삭제 가능합니다. + + ## 에러 + - CANNOT_DELETE_ESSENTIAL_POSITION (400): 필수 직책은 삭제할 수 없습니다. + - POSITION_IN_USE (400): 해당 직책을 사용 중인 회원이 있어 삭제할 수 없습니다. + - INSUFFICIENT_POSITION_COUNT (400): 해당 그룹에 최소 2개의 직책이 있어야 삭제 가능합니다. + - FORBIDDEN_CLUB_MANAGER_ACCESS (403): 동아리 매니저 권한이 없습니다. + - NOT_FOUND_CLUB (404): 동아리를 찾을 수 없습니다. + - NOT_FOUND_CLUB_POSITION (404): 동아리 직책을 찾을 수 없습니다. + """) + @DeleteMapping("/{clubId}/positions/{positionId}") + ResponseEntity deleteClubPosition( + @PathVariable(name = "clubId") Integer clubId, + @PathVariable(name = "positionId") Integer positionId, + @UserId Integer userId + ); +} diff --git a/src/main/java/gg/agit/konect/domain/club/controller/ClubRecruitmentApi.java b/src/main/java/gg/agit/konect/domain/club/controller/ClubRecruitmentApi.java new file mode 100644 index 00000000..1adfb31a --- /dev/null +++ b/src/main/java/gg/agit/konect/domain/club/controller/ClubRecruitmentApi.java @@ -0,0 +1,78 @@ +package gg.agit.konect.domain.club.controller; + +import org.springframework.http.ResponseEntity; +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 gg.agit.konect.domain.club.dto.ClubRecruitmentCreateRequest; +import gg.agit.konect.domain.club.dto.ClubRecruitmentResponse; +import gg.agit.konect.domain.club.dto.ClubRecruitmentUpdateRequest; +import gg.agit.konect.global.auth.annotation.UserId; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.validation.Valid; + +@Tag(name = "Club Recruitment: 모집 공고", description = "동아리 모집 공고 관리 API") +@RequestMapping("/clubs") +public interface ClubRecruitmentApi { + + @Operation(summary = "동아리 모집 정보를 조회한다.", description = """ + 동아리의 모집 공고 상세 정보를 조회합니다. + + - status는 모집 기간에 따라 BEFORE(모집 전), ONGOING(모집 중), CLOSED(모집 마감)으로 반환됩니다. + - 동아리 멤버이거나 지원 이력이 존재할 경우 isApplied는 true로 반환됩니다. + + ## 에러 + - NOT_FOUND_CLUB (404): 동아리를 찾을 수 없습니다. + - NOT_FOUND_USER (404): 유저를 찾을 수 없습니다. + - NOT_FOUND_CLUB_RECRUITMENT (404): 동아리 모집 공고를 찾을 수 없습니다. + """) + @GetMapping("/{clubId}/recruitments") + ResponseEntity getRecruitments( + @PathVariable(name = "clubId") Integer clubId, + @UserId Integer userId + ); + + @Operation(summary = "동아리 모집 정보를 생성한다.", description = """ + 동아리 회장만 모집 공고를 생성할 수 있습니다. + 한 동아리당 하나의 모집 공고만 생성 가능합니다. + + ## 에러 + - INVALID_RECRUITMENT_DATE_NOT_ALLOWED (400): 상시 모집인 경우 모집 시작일과 마감일을 지정할 수 없습니다. + - INVALID_RECRUITMENT_DATE_REQUIRED (400): 상시 모집이 아닐 경우 모집 시작일과 마감일이 필수입니다. + - INVALID_RECRUITMENT_PERIOD (400): 모집 시작일은 모집 마감일보다 이전이어야 합니다. + - FORBIDDEN_CLUB_RECRUITMENT_CREATE (403): 동아리 모집 공고를 생성할 권한이 없습니다. + - NOT_FOUND_CLUB (404): 동아리를 찾을 수 없습니다. + - NOT_FOUND_USER (404): 유저를 찾을 수 없습니다. + - ALREADY_EXIST_CLUB_RECRUITMENT (409): 이미 동아리 모집 공고가 존재합니다. + """) + @PostMapping("/{clubId}/recruitments") + ResponseEntity createRecruitment( + @RequestBody @Valid ClubRecruitmentCreateRequest request, + @PathVariable(name = "clubId") Integer clubId, + @UserId Integer userId + ); + + @Operation(summary = "동아리 모집 정보를 수정한다.", description = """ + 동아리 회장 또는 부회장만 모집 공고를 수정할 수 있습니다. + + ## 에러 + - INVALID_RECRUITMENT_DATE_NOT_ALLOWED (400): 상시 모집인 경우 모집 시작일과 마감일을 지정할 수 없습니다. + - INVALID_RECRUITMENT_DATE_REQUIRED (400): 상시 모집이 아닐 경우 모집 시작일과 마감일이 필수입니다. + - INVALID_RECRUITMENT_PERIOD (400): 모집 시작일은 모집 마감일보다 이전이어야 합니다. + - FORBIDDEN_CLUB_MANAGER_ACCESS (403): 동아리 매니저 권한이 없습니다. + - NOT_FOUND_CLUB (404): 동아리를 찾을 수 없습니다. + - NOT_FOUND_USER (404): 유저를 찾을 수 없습니다. + - NOT_FOUND_CLUB_RECRUITMENT (404): 동아리 모집 공고를 찾을 수 없습니다. + """) + @PutMapping("/{clubId}/recruitments") + ResponseEntity updateRecruitment( + @Valid @RequestBody ClubRecruitmentUpdateRequest request, + @PathVariable(name = "clubId") Integer clubId, + @UserId Integer userId + ); +} From 4a352eb3e856e153a36aa159ec61175b661695aa Mon Sep 17 00:00:00 2001 From: JanooGwan Date: Tue, 27 Jan 2026 11:50:31 +0900 Subject: [PATCH 2/6] =?UTF-8?q?fix:=20Swagger=20=EB=82=B4=EC=9A=A9=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../agit/konect/domain/club/controller/ClubApplicationApi.java | 2 +- .../gg/agit/konect/domain/club/controller/ClubBasicApi.java | 2 +- .../gg/agit/konect/domain/club/controller/ClubMemberApi.java | 2 +- .../gg/agit/konect/domain/club/controller/ClubPositionApi.java | 2 +- .../agit/konect/domain/club/controller/ClubRecruitmentApi.java | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/main/java/gg/agit/konect/domain/club/controller/ClubApplicationApi.java b/src/main/java/gg/agit/konect/domain/club/controller/ClubApplicationApi.java index eb7d8af1..6f220449 100644 --- a/src/main/java/gg/agit/konect/domain/club/controller/ClubApplicationApi.java +++ b/src/main/java/gg/agit/konect/domain/club/controller/ClubApplicationApi.java @@ -20,7 +20,7 @@ import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.validation.Valid; -@Tag(name = "Club Application: 지원 및 신청 관리", description = "동아리 지원, 지원서 관리, 회비 정보 API") +@Tag(name = "(Normal) Club - Application: 지원 및 신청", description = "동아리 지원, 지원서 관리, 회비 정보 API") @RequestMapping("/clubs") public interface ClubApplicationApi { diff --git a/src/main/java/gg/agit/konect/domain/club/controller/ClubBasicApi.java b/src/main/java/gg/agit/konect/domain/club/controller/ClubBasicApi.java index 743d6aab..ef2f795b 100644 --- a/src/main/java/gg/agit/konect/domain/club/controller/ClubBasicApi.java +++ b/src/main/java/gg/agit/konect/domain/club/controller/ClubBasicApi.java @@ -27,7 +27,7 @@ import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.validation.Valid; -@Tag(name = "Club: 동아리 기본 관리", description = "동아리 조회, 생성, 수정 및 기본 관리 API") +@Tag(name = "(Normal) Club - Basic: 기본 관리", description = "동아리 조회, 생성, 수정 및 기본 관리 API") @RequestMapping("/clubs") public interface ClubBasicApi { diff --git a/src/main/java/gg/agit/konect/domain/club/controller/ClubMemberApi.java b/src/main/java/gg/agit/konect/domain/club/controller/ClubMemberApi.java index 7e9e4484..ff7f9549 100644 --- a/src/main/java/gg/agit/konect/domain/club/controller/ClubMemberApi.java +++ b/src/main/java/gg/agit/konect/domain/club/controller/ClubMemberApi.java @@ -17,7 +17,7 @@ import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.validation.Valid; -@Tag(name = "Club Member: 회원 관리", description = "동아리 회원 직책 변경, 추가, 제거 API") +@Tag(name = "(Normal) Club - Member: 회원 관리", description = "동아리 회원 직책 변경, 추가, 제거 API") @RequestMapping("/clubs") public interface ClubMemberApi { diff --git a/src/main/java/gg/agit/konect/domain/club/controller/ClubPositionApi.java b/src/main/java/gg/agit/konect/domain/club/controller/ClubPositionApi.java index 9f861024..9d852cb0 100644 --- a/src/main/java/gg/agit/konect/domain/club/controller/ClubPositionApi.java +++ b/src/main/java/gg/agit/konect/domain/club/controller/ClubPositionApi.java @@ -17,7 +17,7 @@ import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.validation.Valid; -@Tag(name = "Club Position: 직책 관리", description = "동아리 직책 생성, 수정, 삭제 API") +@Tag(name = "(Normal) Club - Position: 직책 관리", description = "동아리 직책 생성, 수정, 삭제 API") @RequestMapping("/clubs") public interface ClubPositionApi { diff --git a/src/main/java/gg/agit/konect/domain/club/controller/ClubRecruitmentApi.java b/src/main/java/gg/agit/konect/domain/club/controller/ClubRecruitmentApi.java index 1adfb31a..1030ed28 100644 --- a/src/main/java/gg/agit/konect/domain/club/controller/ClubRecruitmentApi.java +++ b/src/main/java/gg/agit/konect/domain/club/controller/ClubRecruitmentApi.java @@ -16,7 +16,7 @@ import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.validation.Valid; -@Tag(name = "Club Recruitment: 모집 공고", description = "동아리 모집 공고 관리 API") +@Tag(name = "(Normal) Club - Recruitment: 모집 공고", description = "동아리 모집 공고 관리 API") @RequestMapping("/clubs") public interface ClubRecruitmentApi { From a5c3315036dc57d7e1ae48e7bf3816cd22af028c Mon Sep 17 00:00:00 2001 From: JanooGwan Date: Tue, 27 Jan 2026 12:07:17 +0900 Subject: [PATCH 3/6] =?UTF-8?q?refactor:=20Swagger=20=EB=82=B4=EC=9A=A9=20?= =?UTF-8?q?=EC=88=98=EC=A0=952?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/ClubApplicationController.java | 98 +++++ .../club/controller/ClubBasicController.java | 125 +++++++ .../club/controller/ClubController.java | 349 ------------------ .../club/controller/ClubMemberController.java | 75 ++++ .../controller/ClubPositionController.java | 65 ++++ .../controller/ClubRecruitmentController.java | 52 +++ .../konect/global/config/SwaggerConfig.java | 7 + 7 files changed, 422 insertions(+), 349 deletions(-) create mode 100644 src/main/java/gg/agit/konect/domain/club/controller/ClubApplicationController.java create mode 100644 src/main/java/gg/agit/konect/domain/club/controller/ClubBasicController.java delete mode 100644 src/main/java/gg/agit/konect/domain/club/controller/ClubController.java create mode 100644 src/main/java/gg/agit/konect/domain/club/controller/ClubMemberController.java create mode 100644 src/main/java/gg/agit/konect/domain/club/controller/ClubPositionController.java create mode 100644 src/main/java/gg/agit/konect/domain/club/controller/ClubRecruitmentController.java diff --git a/src/main/java/gg/agit/konect/domain/club/controller/ClubApplicationController.java b/src/main/java/gg/agit/konect/domain/club/controller/ClubApplicationController.java new file mode 100644 index 00000000..e6e62b18 --- /dev/null +++ b/src/main/java/gg/agit/konect/domain/club/controller/ClubApplicationController.java @@ -0,0 +1,98 @@ +package gg.agit.konect.domain.club.controller; + +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import gg.agit.konect.domain.club.dto.ClubApplicationAnswersResponse; +import gg.agit.konect.domain.club.dto.ClubApplicationsResponse; +import gg.agit.konect.domain.club.dto.ClubApplyQuestionsReplaceRequest; +import gg.agit.konect.domain.club.dto.ClubApplyQuestionsResponse; +import gg.agit.konect.domain.club.dto.ClubApplyRequest; +import gg.agit.konect.domain.club.dto.ClubFeeInfoReplaceRequest; +import gg.agit.konect.domain.club.dto.ClubFeeInfoResponse; +import gg.agit.konect.domain.club.service.ClubService; +import gg.agit.konect.global.auth.annotation.UserId; +import jakarta.validation.Valid; +import lombok.RequiredArgsConstructor; + +@RestController +@RequiredArgsConstructor +@RequestMapping("/clubs") +public class ClubApplicationController implements ClubApplicationApi { + + private final ClubService clubService; + + @Override + public ResponseEntity applyClub( + @PathVariable(name = "clubId") Integer clubId, + @Valid @RequestBody ClubApplyRequest request, + @UserId Integer userId + ) { + ClubFeeInfoResponse response = clubService.applyClub(clubId, userId, request); + return ResponseEntity.ok(response); + } + + @Override + public ResponseEntity getClubApplications( + @PathVariable(name = "clubId") Integer clubId, + @UserId Integer userId + ) { + ClubApplicationsResponse response = clubService.getClubApplications(clubId, userId); + return ResponseEntity.ok(response); + } + + @Override + public ResponseEntity getClubApplicationAnswers( + @PathVariable(name = "clubId") Integer clubId, + @PathVariable(name = "applicationId") Integer applicationId, + @UserId Integer userId + ) { + ClubApplicationAnswersResponse response = clubService.getClubApplicationAnswers( + clubId, + applicationId, + userId + ); + return ResponseEntity.ok(response); + } + + @Override + public ResponseEntity getApplyQuestions( + @PathVariable(name = "clubId") Integer clubId, + @UserId Integer userId + ) { + ClubApplyQuestionsResponse response = clubService.getApplyQuestions(clubId, userId); + return ResponseEntity.ok(response); + } + + @Override + public ResponseEntity replaceApplyQuestions( + @PathVariable(name = "clubId") Integer clubId, + @Valid @RequestBody ClubApplyQuestionsReplaceRequest request, + @UserId Integer userId + ) { + ClubApplyQuestionsResponse response = clubService.replaceApplyQuestions(clubId, userId, request); + return ResponseEntity.ok(response); + } + + @Override + public ResponseEntity getFeeInfo( + @PathVariable(name = "clubId") Integer clubId, + @UserId Integer userId + ) { + ClubFeeInfoResponse response = clubService.getFeeInfo(clubId, userId); + return ResponseEntity.ok(response); + } + + @Override + public ResponseEntity replaceFeeInfo( + @PathVariable(name = "clubId") Integer clubId, + @Valid @RequestBody ClubFeeInfoReplaceRequest request, + @UserId Integer userId + ) { + ClubFeeInfoResponse response = clubService.replaceFeeInfo(clubId, userId, request); + return ResponseEntity.ok(response); + } +} diff --git a/src/main/java/gg/agit/konect/domain/club/controller/ClubBasicController.java b/src/main/java/gg/agit/konect/domain/club/controller/ClubBasicController.java new file mode 100644 index 00000000..563e6b95 --- /dev/null +++ b/src/main/java/gg/agit/konect/domain/club/controller/ClubBasicController.java @@ -0,0 +1,125 @@ +package gg.agit.konect.domain.club.controller; + +import org.springdoc.core.annotations.ParameterObject; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.ModelAttribute; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import gg.agit.konect.domain.club.dto.ClubAppliedClubsResponse; +import gg.agit.konect.domain.club.dto.ClubBasicInfoUpdateRequest; +import gg.agit.konect.domain.club.dto.ClubCondition; +import gg.agit.konect.domain.club.dto.ClubCreateRequest; +import gg.agit.konect.domain.club.dto.ClubDetailResponse; +import gg.agit.konect.domain.club.dto.ClubDetailUpdateRequest; +import gg.agit.konect.domain.club.dto.ClubMemberCondition; +import gg.agit.konect.domain.club.dto.ClubMembersResponse; +import gg.agit.konect.domain.club.dto.ClubMembershipsResponse; +import gg.agit.konect.domain.club.dto.ClubProfileUpdateRequest; +import gg.agit.konect.domain.club.dto.ClubTagsResponse; +import gg.agit.konect.domain.club.dto.ClubsResponse; +import gg.agit.konect.domain.club.service.ClubService; +import gg.agit.konect.global.auth.annotation.UserId; +import jakarta.validation.Valid; +import lombok.RequiredArgsConstructor; + +@RestController +@RequiredArgsConstructor +@RequestMapping("/clubs") +public class ClubBasicController implements ClubBasicApi { + + private final ClubService clubService; + + @Override + public ResponseEntity getClubs( + @Valid @ParameterObject @ModelAttribute ClubCondition condition, + @UserId Integer userId + ) { + ClubsResponse response = clubService.getClubs(condition, userId); + return ResponseEntity.ok(response); + } + + @Override + public ResponseEntity getClubDetail( + @PathVariable(name = "clubId") Integer clubId, + @UserId Integer userId + ) { + ClubDetailResponse response = clubService.getClubDetail(clubId, userId); + return ResponseEntity.ok(response); + } + + @Override + public ResponseEntity createClub( + @Valid @RequestBody ClubCreateRequest request, + @UserId Integer userId + ) { + ClubDetailResponse response = clubService.createClub(userId, request); + return ResponseEntity.ok(response); + } + + @Override + public ResponseEntity updateProfile( + @PathVariable(name = "clubId") Integer clubId, + @Valid @RequestBody ClubProfileUpdateRequest request, + @UserId Integer userId + ) { + clubService.updateProfile(clubId, userId, request); + return ResponseEntity.noContent().build(); + } + + @Override + public ResponseEntity updateDetails( + @PathVariable(name = "clubId") Integer clubId, + @Valid @RequestBody ClubDetailUpdateRequest request, + @UserId Integer userId + ) { + clubService.updateDetails(clubId, userId, request); + return ResponseEntity.noContent().build(); + } + + @Override + public ResponseEntity updateBasicInfo( + @PathVariable(name = "clubId") Integer clubId, + @Valid @RequestBody ClubBasicInfoUpdateRequest request, + @UserId Integer userId + ) { + clubService.updateBasicInfo(clubId, userId, request); + return ResponseEntity.noContent().build(); + } + + @Override + public ResponseEntity getTags() { + ClubTagsResponse response = clubService.getTags(); + return ResponseEntity.ok(response); + } + + @Override + public ResponseEntity getJoinedClubs(@UserId Integer userId) { + ClubMembershipsResponse response = clubService.getJoinedClubs(userId); + return ResponseEntity.ok(response); + } + + @Override + public ResponseEntity getManagedClubs(@UserId Integer userId) { + ClubMembershipsResponse response = clubService.getManagedClubs(userId); + return ResponseEntity.ok(response); + } + + @Override + public ResponseEntity getAppliedClubs(@UserId Integer userId) { + ClubAppliedClubsResponse response = clubService.getAppliedClubs(userId); + return ResponseEntity.ok(response); + } + + @Override + public ResponseEntity getClubMembers( + @PathVariable(name = "clubId") Integer clubId, + @Valid @ParameterObject @ModelAttribute ClubMemberCondition condition, + @UserId Integer userId + ) { + ClubMembersResponse response = clubService.getClubMembers(clubId, userId, condition); + return ResponseEntity.ok(response); + } +} diff --git a/src/main/java/gg/agit/konect/domain/club/controller/ClubController.java b/src/main/java/gg/agit/konect/domain/club/controller/ClubController.java deleted file mode 100644 index ed817616..00000000 --- a/src/main/java/gg/agit/konect/domain/club/controller/ClubController.java +++ /dev/null @@ -1,349 +0,0 @@ -package gg.agit.konect.domain.club.controller; - -import org.springdoc.core.annotations.ParameterObject; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.ModelAttribute; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; - -import gg.agit.konect.domain.club.dto.ClubApplicationAnswersResponse; -import gg.agit.konect.domain.club.dto.ClubAppliedClubsResponse; -import gg.agit.konect.domain.club.dto.ClubApplicationsResponse; -import gg.agit.konect.domain.club.dto.ClubApplyQuestionsReplaceRequest; -import gg.agit.konect.domain.club.dto.ClubApplyQuestionsResponse; -import gg.agit.konect.domain.club.dto.ClubApplyRequest; -import gg.agit.konect.domain.club.dto.ClubBasicInfoUpdateRequest; -import gg.agit.konect.domain.club.dto.ClubCondition; -import gg.agit.konect.domain.club.dto.ClubCreateRequest; -import gg.agit.konect.domain.club.dto.ClubDetailResponse; -import gg.agit.konect.domain.club.dto.ClubDetailUpdateRequest; -import gg.agit.konect.domain.club.dto.ClubFeeInfoReplaceRequest; -import gg.agit.konect.domain.club.dto.ClubFeeInfoResponse; -import gg.agit.konect.domain.club.dto.ClubMemberAddRequest; -import gg.agit.konect.domain.club.dto.ClubMemberCondition; -import gg.agit.konect.domain.club.dto.ClubMembersResponse; -import gg.agit.konect.domain.club.dto.ClubMembershipsResponse; -import gg.agit.konect.domain.club.dto.ClubPositionCreateRequest; -import gg.agit.konect.domain.club.dto.ClubPositionUpdateRequest; -import gg.agit.konect.domain.club.dto.ClubPositionsResponse; -import gg.agit.konect.domain.club.dto.ClubProfileUpdateRequest; -import gg.agit.konect.domain.club.dto.ClubRecruitmentCreateRequest; -import gg.agit.konect.domain.club.dto.ClubRecruitmentResponse; -import gg.agit.konect.domain.club.dto.ClubRecruitmentUpdateRequest; -import gg.agit.konect.domain.club.dto.ClubTagsResponse; -import gg.agit.konect.domain.club.dto.ClubsResponse; -import gg.agit.konect.domain.club.dto.MemberPositionChangeRequest; -import gg.agit.konect.domain.club.dto.PresidentTransferRequest; -import gg.agit.konect.domain.club.dto.VicePresidentChangeRequest; -import gg.agit.konect.domain.club.service.ClubMemberManagementService; -import gg.agit.konect.domain.club.service.ClubPositionService; -import gg.agit.konect.domain.club.service.ClubService; -import gg.agit.konect.global.auth.annotation.UserId; -import jakarta.validation.Valid; -import lombok.RequiredArgsConstructor; - -@RestController -@RequiredArgsConstructor -@RequestMapping("/clubs") -public class ClubController implements - ClubBasicApi, - ClubRecruitmentApi, - ClubApplicationApi, - ClubPositionApi, - ClubMemberApi { - - private final ClubService clubService; - private final ClubPositionService clubPositionService; - private final ClubMemberManagementService clubMemberManagementService; - - @Override - public ResponseEntity getClubs( - @Valid @ParameterObject @ModelAttribute ClubCondition condition, - @UserId Integer userId - ) { - ClubsResponse response = clubService.getClubs(condition, userId); - return ResponseEntity.ok(response); - } - - @Override - public ResponseEntity getClubDetail( - @PathVariable(name = "clubId") Integer clubId, - @UserId Integer userId - ) { - ClubDetailResponse response = clubService.getClubDetail(clubId, userId); - return ResponseEntity.ok(response); - } - - @Override - public ResponseEntity createClub( - @Valid @RequestBody ClubCreateRequest request, - @UserId Integer userId - ) { - ClubDetailResponse response = clubService.createClub(userId, request); - return ResponseEntity.ok(response); - } - - @Override - public ResponseEntity updateProfile( - @PathVariable(name = "clubId") Integer clubId, - @Valid @RequestBody ClubProfileUpdateRequest request, - @UserId Integer userId - ) { - clubService.updateProfile(clubId, userId, request); - return ResponseEntity.noContent().build(); - } - - @Override - public ResponseEntity updateDetails( - @PathVariable(name = "clubId") Integer clubId, - @Valid @RequestBody ClubDetailUpdateRequest request, - @UserId Integer userId - ) { - clubService.updateDetails(clubId, userId, request); - return ResponseEntity.noContent().build(); - } - - @Override - public ResponseEntity updateBasicInfo( - @PathVariable(name = "clubId") Integer clubId, - @Valid @RequestBody ClubBasicInfoUpdateRequest request, - @UserId Integer userId - ) { - clubService.updateBasicInfo(clubId, userId, request); - return ResponseEntity.noContent().build(); - } - - @Override - public ResponseEntity getTags() { - ClubTagsResponse response = clubService.getTags(); - return ResponseEntity.ok(response); - } - - @Override - public ResponseEntity getJoinedClubs(@UserId Integer userId) { - ClubMembershipsResponse response = clubService.getJoinedClubs(userId); - return ResponseEntity.ok(response); - } - - @Override - public ResponseEntity getManagedClubs( - @UserId Integer userId - ) { - ClubMembershipsResponse response = clubService.getManagedClubs(userId); - return ResponseEntity.ok(response); - } - - @Override - public ResponseEntity getAppliedClubs( - @UserId Integer userId - ) { - ClubAppliedClubsResponse response = clubService.getAppliedClubs(userId); - return ResponseEntity.ok(response); - } - - @Override - public ResponseEntity getClubApplications( - @PathVariable(name = "clubId") Integer clubId, - @UserId Integer userId - ) { - ClubApplicationsResponse response = clubService.getClubApplications(clubId, userId); - return ResponseEntity.ok(response); - } - - @Override - public ResponseEntity getClubApplicationAnswers( - @PathVariable(name = "clubId") Integer clubId, - @PathVariable(name = "applicationId") Integer applicationId, - @UserId Integer userId - ) { - ClubApplicationAnswersResponse response = clubService.getClubApplicationAnswers( - clubId, - applicationId, - userId - ); - - return ResponseEntity.ok(response); - } - - @Override - public ResponseEntity getClubMembers( - @PathVariable(name = "clubId") Integer clubId, - @Valid @ParameterObject @ModelAttribute ClubMemberCondition condition, - @UserId Integer userId - ) { - ClubMembersResponse response = clubService.getClubMembers(clubId, userId, condition); - return ResponseEntity.ok(response); - } - - @Override - public ResponseEntity applyClub( - @PathVariable(name = "clubId") Integer clubId, - @Valid @RequestBody ClubApplyRequest request, - @UserId Integer userId - ) { - ClubFeeInfoResponse response = clubService.applyClub(clubId, userId, request); - return ResponseEntity.ok(response); - } - - @Override - public ResponseEntity getFeeInfo( - @PathVariable(name = "clubId") Integer clubId, - @UserId Integer userId - ) { - ClubFeeInfoResponse response = clubService.getFeeInfo(clubId, userId); - return ResponseEntity.ok(response); - } - - @Override - public ResponseEntity replaceFeeInfo( - @PathVariable(name = "clubId") Integer clubId, - @Valid @RequestBody ClubFeeInfoReplaceRequest request, - @UserId Integer userId - ) { - ClubFeeInfoResponse response = clubService.replaceFeeInfo(clubId, userId, request); - return ResponseEntity.ok(response); - } - - @Override - public ResponseEntity getApplyQuestions( - @PathVariable(name = "clubId") Integer clubId, - @UserId Integer userId - ) { - ClubApplyQuestionsResponse response = clubService.getApplyQuestions(clubId, userId); - return ResponseEntity.ok(response); - } - - @Override - public ResponseEntity replaceApplyQuestions( - @PathVariable(name = "clubId") Integer clubId, - @Valid @RequestBody ClubApplyQuestionsReplaceRequest request, - @UserId Integer userId - ) { - ClubApplyQuestionsResponse response = clubService.replaceApplyQuestions(clubId, userId, request); - return ResponseEntity.ok(response); - } - - @Override - public ResponseEntity getRecruitments( - @PathVariable(name = "clubId") Integer clubId, - @UserId Integer userId - ) { - ClubRecruitmentResponse response = clubService.getRecruitment(clubId, userId); - return ResponseEntity.ok(response); - } - - @Override - public ResponseEntity createRecruitment( - @RequestBody @Valid ClubRecruitmentCreateRequest request, - @PathVariable(name = "clubId") Integer clubId, - @UserId Integer userId - ) { - clubService.createRecruitment(clubId, userId, request); - return ResponseEntity.ok().build(); - } - - @Override - public ResponseEntity updateRecruitment( - @Valid @RequestBody ClubRecruitmentUpdateRequest request, - @PathVariable(name = "clubId") Integer clubId, - @UserId Integer userId - ) { - clubService.updateRecruitment(clubId, userId, request); - return ResponseEntity.noContent().build(); - } - - @Override - public ResponseEntity getClubPositions( - @PathVariable(name = "clubId") Integer clubId, - @UserId Integer userId - ) { - ClubPositionsResponse response = clubPositionService.getClubPositions(clubId, userId); - return ResponseEntity.ok(response); - } - - @Override - public ResponseEntity createClubPosition( - @PathVariable(name = "clubId") Integer clubId, - @Valid @RequestBody ClubPositionCreateRequest request, - @UserId Integer userId - ) { - ClubPositionsResponse response = clubPositionService.createClubPosition(clubId, userId, request); - return ResponseEntity.ok(response); - } - - @Override - public ResponseEntity updateClubPositionName( - @PathVariable(name = "clubId") Integer clubId, - @PathVariable(name = "positionId") Integer positionId, - @Valid @RequestBody ClubPositionUpdateRequest request, - @UserId Integer userId - ) { - ClubPositionsResponse response = clubPositionService.updateClubPositionName( - clubId, positionId, userId, request - ); - return ResponseEntity.ok(response); - } - - @Override - public ResponseEntity deleteClubPosition( - @PathVariable(name = "clubId") Integer clubId, - @PathVariable(name = "positionId") Integer positionId, - @UserId Integer userId - ) { - clubPositionService.deleteClubPosition(clubId, positionId, userId); - return ResponseEntity.noContent().build(); - } - - @Override - public ResponseEntity changeMemberPosition( - @PathVariable(name = "clubId") Integer clubId, - @PathVariable(name = "memberId") Integer memberId, - @Valid @RequestBody MemberPositionChangeRequest request, - @UserId Integer userId - ) { - clubMemberManagementService.changeMemberPosition(clubId, memberId, userId, request); - return ResponseEntity.noContent().build(); - } - - @Override - public ResponseEntity transferPresident( - @PathVariable(name = "clubId") Integer clubId, - @Valid @RequestBody PresidentTransferRequest request, - @UserId Integer userId - ) { - clubMemberManagementService.transferPresident(clubId, userId, request); - return ResponseEntity.noContent().build(); - } - - @Override - public ResponseEntity changeVicePresident( - @PathVariable(name = "clubId") Integer clubId, - @Valid @RequestBody VicePresidentChangeRequest request, - @UserId Integer userId - ) { - clubMemberManagementService.changeVicePresident(clubId, userId, request); - return ResponseEntity.noContent().build(); - } - - @Override - public ResponseEntity addMember( - @PathVariable(name = "clubId") Integer clubId, - @Valid @RequestBody ClubMemberAddRequest request, - @UserId Integer userId - ) { - clubMemberManagementService.addMember(clubId, userId, request); - return ResponseEntity.ok().build(); - } - - @Override - public ResponseEntity removeMember( - @PathVariable(name = "clubId") Integer clubId, - @PathVariable(name = "memberId") Integer memberId, - @UserId Integer userId - ) { - clubMemberManagementService.removeMember(clubId, memberId, userId); - return ResponseEntity.noContent().build(); - } -} diff --git a/src/main/java/gg/agit/konect/domain/club/controller/ClubMemberController.java b/src/main/java/gg/agit/konect/domain/club/controller/ClubMemberController.java new file mode 100644 index 00000000..da2d8eed --- /dev/null +++ b/src/main/java/gg/agit/konect/domain/club/controller/ClubMemberController.java @@ -0,0 +1,75 @@ +package gg.agit.konect.domain.club.controller; + +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import gg.agit.konect.domain.club.dto.ClubMemberAddRequest; +import gg.agit.konect.domain.club.dto.MemberPositionChangeRequest; +import gg.agit.konect.domain.club.dto.PresidentTransferRequest; +import gg.agit.konect.domain.club.dto.VicePresidentChangeRequest; +import gg.agit.konect.domain.club.service.ClubMemberManagementService; +import gg.agit.konect.global.auth.annotation.UserId; +import jakarta.validation.Valid; +import lombok.RequiredArgsConstructor; + +@RestController +@RequiredArgsConstructor +@RequestMapping("/clubs") +public class ClubMemberController implements ClubMemberApi { + + private final ClubMemberManagementService clubMemberManagementService; + + @Override + public ResponseEntity changeMemberPosition( + @PathVariable(name = "clubId") Integer clubId, + @PathVariable(name = "memberId") Integer memberId, + @Valid @RequestBody MemberPositionChangeRequest request, + @UserId Integer userId + ) { + clubMemberManagementService.changeMemberPosition(clubId, memberId, userId, request); + return ResponseEntity.noContent().build(); + } + + @Override + public ResponseEntity transferPresident( + @PathVariable(name = "clubId") Integer clubId, + @Valid @RequestBody PresidentTransferRequest request, + @UserId Integer userId + ) { + clubMemberManagementService.transferPresident(clubId, userId, request); + return ResponseEntity.noContent().build(); + } + + @Override + public ResponseEntity changeVicePresident( + @PathVariable(name = "clubId") Integer clubId, + @Valid @RequestBody VicePresidentChangeRequest request, + @UserId Integer userId + ) { + clubMemberManagementService.changeVicePresident(clubId, userId, request); + return ResponseEntity.noContent().build(); + } + + @Override + public ResponseEntity addMember( + @PathVariable(name = "clubId") Integer clubId, + @Valid @RequestBody ClubMemberAddRequest request, + @UserId Integer userId + ) { + clubMemberManagementService.addMember(clubId, userId, request); + return ResponseEntity.ok().build(); + } + + @Override + public ResponseEntity removeMember( + @PathVariable(name = "clubId") Integer clubId, + @PathVariable(name = "memberId") Integer memberId, + @UserId Integer userId + ) { + clubMemberManagementService.removeMember(clubId, memberId, userId); + return ResponseEntity.noContent().build(); + } +} diff --git a/src/main/java/gg/agit/konect/domain/club/controller/ClubPositionController.java b/src/main/java/gg/agit/konect/domain/club/controller/ClubPositionController.java new file mode 100644 index 00000000..804dbc33 --- /dev/null +++ b/src/main/java/gg/agit/konect/domain/club/controller/ClubPositionController.java @@ -0,0 +1,65 @@ +package gg.agit.konect.domain.club.controller; + +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import gg.agit.konect.domain.club.dto.ClubPositionCreateRequest; +import gg.agit.konect.domain.club.dto.ClubPositionUpdateRequest; +import gg.agit.konect.domain.club.dto.ClubPositionsResponse; +import gg.agit.konect.domain.club.service.ClubPositionService; +import gg.agit.konect.global.auth.annotation.UserId; +import jakarta.validation.Valid; +import lombok.RequiredArgsConstructor; + +@RestController +@RequiredArgsConstructor +@RequestMapping("/clubs") +public class ClubPositionController implements ClubPositionApi { + + private final ClubPositionService clubPositionService; + + @Override + public ResponseEntity getClubPositions( + @PathVariable(name = "clubId") Integer clubId, + @UserId Integer userId + ) { + ClubPositionsResponse response = clubPositionService.getClubPositions(clubId, userId); + return ResponseEntity.ok(response); + } + + @Override + public ResponseEntity createClubPosition( + @PathVariable(name = "clubId") Integer clubId, + @Valid @RequestBody ClubPositionCreateRequest request, + @UserId Integer userId + ) { + ClubPositionsResponse response = clubPositionService.createClubPosition(clubId, userId, request); + return ResponseEntity.ok(response); + } + + @Override + public ResponseEntity updateClubPositionName( + @PathVariable(name = "clubId") Integer clubId, + @PathVariable(name = "positionId") Integer positionId, + @Valid @RequestBody ClubPositionUpdateRequest request, + @UserId Integer userId + ) { + ClubPositionsResponse response = clubPositionService.updateClubPositionName( + clubId, positionId, userId, request + ); + return ResponseEntity.ok(response); + } + + @Override + public ResponseEntity deleteClubPosition( + @PathVariable(name = "clubId") Integer clubId, + @PathVariable(name = "positionId") Integer positionId, + @UserId Integer userId + ) { + clubPositionService.deleteClubPosition(clubId, positionId, userId); + return ResponseEntity.noContent().build(); + } +} diff --git a/src/main/java/gg/agit/konect/domain/club/controller/ClubRecruitmentController.java b/src/main/java/gg/agit/konect/domain/club/controller/ClubRecruitmentController.java new file mode 100644 index 00000000..3eef1e04 --- /dev/null +++ b/src/main/java/gg/agit/konect/domain/club/controller/ClubRecruitmentController.java @@ -0,0 +1,52 @@ +package gg.agit.konect.domain.club.controller; + +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import gg.agit.konect.domain.club.dto.ClubRecruitmentCreateRequest; +import gg.agit.konect.domain.club.dto.ClubRecruitmentResponse; +import gg.agit.konect.domain.club.dto.ClubRecruitmentUpdateRequest; +import gg.agit.konect.domain.club.service.ClubService; +import gg.agit.konect.global.auth.annotation.UserId; +import jakarta.validation.Valid; +import lombok.RequiredArgsConstructor; + +@RestController +@RequiredArgsConstructor +@RequestMapping("/clubs") +public class ClubRecruitmentController implements ClubRecruitmentApi { + + private final ClubService clubService; + + @Override + public ResponseEntity getRecruitments( + @PathVariable(name = "clubId") Integer clubId, + @UserId Integer userId + ) { + ClubRecruitmentResponse response = clubService.getRecruitment(clubId, userId); + return ResponseEntity.ok(response); + } + + @Override + public ResponseEntity createRecruitment( + @RequestBody @Valid ClubRecruitmentCreateRequest request, + @PathVariable(name = "clubId") Integer clubId, + @UserId Integer userId + ) { + clubService.createRecruitment(clubId, userId, request); + return ResponseEntity.ok().build(); + } + + @Override + public ResponseEntity updateRecruitment( + @Valid @RequestBody ClubRecruitmentUpdateRequest request, + @PathVariable(name = "clubId") Integer clubId, + @UserId Integer userId + ) { + clubService.updateRecruitment(clubId, userId, request); + return ResponseEntity.noContent().build(); + } +} diff --git a/src/main/java/gg/agit/konect/global/config/SwaggerConfig.java b/src/main/java/gg/agit/konect/global/config/SwaggerConfig.java index 9c32f24b..bfc1defb 100644 --- a/src/main/java/gg/agit/konect/global/config/SwaggerConfig.java +++ b/src/main/java/gg/agit/konect/global/config/SwaggerConfig.java @@ -40,6 +40,13 @@ public GroupedOpenApi publicApi() { .group("Public API") .pathsToMatch("/**") .pathsToExclude("/admin/**") + .addOpenApiCustomizer(openApi -> openApi.setTags( + openApi.getTags() != null + ? openApi.getTags().stream() + .sorted((a, b) -> a.getName().compareTo(b.getName())) + .toList() + : null + )) .build(); } From 54d6facfc92245f914896ebbd8023ec981420541 Mon Sep 17 00:00:00 2001 From: JanooGwan Date: Tue, 27 Jan 2026 15:46:06 +0900 Subject: [PATCH 4/6] =?UTF-8?q?fix:=20Club=20=EC=98=81=EC=97=AD=EB=A7=88?= =?UTF-8?q?=EB=8B=A4=20=EC=97=94=EB=93=9C=ED=8F=AC=EC=9D=B8=ED=8A=B8=20?= =?UTF-8?q?=EC=A4=91=EC=B2=A9=EB=90=98=EB=8A=94=20=ED=98=84=EC=83=81=20?= =?UTF-8?q?=ED=95=B4=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../club/controller/ClubApplicationApi.java | 2 - .../domain/club/controller/ClubBasicApi.java | 2 - .../club/controller/ClubController.java | 698 +++++++++--------- .../domain/club/controller/ClubMemberApi.java | 2 - .../club/controller/ClubPositionApi.java | 2 - .../club/controller/ClubRecruitmentApi.java | 2 - 6 files changed, 349 insertions(+), 359 deletions(-) diff --git a/src/main/java/gg/agit/konect/domain/club/controller/ClubApplicationApi.java b/src/main/java/gg/agit/konect/domain/club/controller/ClubApplicationApi.java index 965bad5d..d81bc9e8 100644 --- a/src/main/java/gg/agit/konect/domain/club/controller/ClubApplicationApi.java +++ b/src/main/java/gg/agit/konect/domain/club/controller/ClubApplicationApi.java @@ -17,10 +17,8 @@ import gg.agit.konect.domain.club.dto.ClubFeeInfoResponse; import gg.agit.konect.global.auth.annotation.UserId; import io.swagger.v3.oas.annotations.Operation; -import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.validation.Valid; -@Tag(name = "(Normal) Club - Application: 지원 및 신청", description = "동아리 지원, 지원서 관리, 회비 정보 API") @RequestMapping("/clubs") public interface ClubApplicationApi { diff --git a/src/main/java/gg/agit/konect/domain/club/controller/ClubBasicApi.java b/src/main/java/gg/agit/konect/domain/club/controller/ClubBasicApi.java index e0900a12..54635a4a 100644 --- a/src/main/java/gg/agit/konect/domain/club/controller/ClubBasicApi.java +++ b/src/main/java/gg/agit/konect/domain/club/controller/ClubBasicApi.java @@ -24,10 +24,8 @@ import gg.agit.konect.domain.club.dto.ClubsResponse; import gg.agit.konect.global.auth.annotation.UserId; import io.swagger.v3.oas.annotations.Operation; -import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.validation.Valid; -@Tag(name = "(Normal) Club - Basic: 기본 관리", description = "동아리 조회, 생성, 수정 및 기본 관리 API") @RequestMapping("/clubs") public interface ClubBasicApi { diff --git a/src/main/java/gg/agit/konect/domain/club/controller/ClubController.java b/src/main/java/gg/agit/konect/domain/club/controller/ClubController.java index 419aab70..ed817616 100644 --- a/src/main/java/gg/agit/konect/domain/club/controller/ClubController.java +++ b/src/main/java/gg/agit/konect/domain/club/controller/ClubController.java @@ -1,349 +1,349 @@ -package gg.agit.konect.domain.club.controller; - -import org.springdoc.core.annotations.ParameterObject; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.ModelAttribute; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; - -import gg.agit.konect.domain.club.dto.ClubApplicationAnswersResponse; -import gg.agit.konect.domain.club.dto.ClubAppliedClubsResponse; -import gg.agit.konect.domain.club.dto.ClubApplicationsResponse; -import gg.agit.konect.domain.club.dto.ClubApplyQuestionsReplaceRequest; -import gg.agit.konect.domain.club.dto.ClubApplyQuestionsResponse; -import gg.agit.konect.domain.club.dto.ClubApplyRequest; -import gg.agit.konect.domain.club.dto.ClubBasicInfoUpdateRequest; -import gg.agit.konect.domain.club.dto.ClubCondition; -import gg.agit.konect.domain.club.dto.ClubCreateRequest; -import gg.agit.konect.domain.club.dto.ClubDetailResponse; -import gg.agit.konect.domain.club.dto.ClubDetailUpdateRequest; -import gg.agit.konect.domain.club.dto.ClubFeeInfoReplaceRequest; -import gg.agit.konect.domain.club.dto.ClubFeeInfoResponse; -import gg.agit.konect.domain.club.dto.ClubMemberAddRequest; -import gg.agit.konect.domain.club.dto.ClubMemberCondition; -import gg.agit.konect.domain.club.dto.ClubMembersResponse; -import gg.agit.konect.domain.club.dto.ClubMembershipsResponse; -import gg.agit.konect.domain.club.dto.ClubPositionCreateRequest; -import gg.agit.konect.domain.club.dto.ClubPositionUpdateRequest; -import gg.agit.konect.domain.club.dto.ClubPositionsResponse; -import gg.agit.konect.domain.club.dto.ClubProfileUpdateRequest; -import gg.agit.konect.domain.club.dto.ClubRecruitmentCreateRequest; -import gg.agit.konect.domain.club.dto.ClubRecruitmentResponse; -import gg.agit.konect.domain.club.dto.ClubRecruitmentUpdateRequest; -import gg.agit.konect.domain.club.dto.ClubTagsResponse; -import gg.agit.konect.domain.club.dto.ClubsResponse; -import gg.agit.konect.domain.club.dto.MemberPositionChangeRequest; -import gg.agit.konect.domain.club.dto.PresidentTransferRequest; -import gg.agit.konect.domain.club.dto.VicePresidentChangeRequest; -import gg.agit.konect.domain.club.service.ClubMemberManagementService; -import gg.agit.konect.domain.club.service.ClubPositionService; -import gg.agit.konect.domain.club.service.ClubService; -import gg.agit.konect.global.auth.annotation.UserId; -import jakarta.validation.Valid; -import lombok.RequiredArgsConstructor; - -@RestController -@RequiredArgsConstructor -@RequestMapping("/clubs") -public class ClubController implements - ClubBasicApi, - ClubRecruitmentApi, - ClubApplicationApi, - ClubPositionApi, - ClubMemberApi { - - private final ClubService clubService; - private final ClubPositionService clubPositionService; - private final ClubMemberManagementService clubMemberManagementService; - - @Override - public ResponseEntity getClubs( - @Valid @ParameterObject @ModelAttribute ClubCondition condition, - @UserId Integer userId - ) { - ClubsResponse response = clubService.getClubs(condition, userId); - return ResponseEntity.ok(response); - } - - @Override - public ResponseEntity getClubDetail( - @PathVariable(name = "clubId") Integer clubId, - @UserId Integer userId - ) { - ClubDetailResponse response = clubService.getClubDetail(clubId, userId); - return ResponseEntity.ok(response); - } - - @Override - public ResponseEntity createClub( - @Valid @RequestBody ClubCreateRequest request, - @UserId Integer userId - ) { - ClubDetailResponse response = clubService.createClub(userId, request); - return ResponseEntity.ok(response); - } - - @Override - public ResponseEntity updateProfile( - @PathVariable(name = "clubId") Integer clubId, - @Valid @RequestBody ClubProfileUpdateRequest request, - @UserId Integer userId - ) { - clubService.updateProfile(clubId, userId, request); - return ResponseEntity.noContent().build(); - } - - @Override - public ResponseEntity updateDetails( - @PathVariable(name = "clubId") Integer clubId, - @Valid @RequestBody ClubDetailUpdateRequest request, - @UserId Integer userId - ) { - clubService.updateDetails(clubId, userId, request); - return ResponseEntity.noContent().build(); - } - - @Override - public ResponseEntity updateBasicInfo( - @PathVariable(name = "clubId") Integer clubId, - @Valid @RequestBody ClubBasicInfoUpdateRequest request, - @UserId Integer userId - ) { - clubService.updateBasicInfo(clubId, userId, request); - return ResponseEntity.noContent().build(); - } - - @Override - public ResponseEntity getTags() { - ClubTagsResponse response = clubService.getTags(); - return ResponseEntity.ok(response); - } - - @Override - public ResponseEntity getJoinedClubs(@UserId Integer userId) { - ClubMembershipsResponse response = clubService.getJoinedClubs(userId); - return ResponseEntity.ok(response); - } - - @Override - public ResponseEntity getManagedClubs( - @UserId Integer userId - ) { - ClubMembershipsResponse response = clubService.getManagedClubs(userId); - return ResponseEntity.ok(response); - } - - @Override - public ResponseEntity getAppliedClubs( - @UserId Integer userId - ) { - ClubAppliedClubsResponse response = clubService.getAppliedClubs(userId); - return ResponseEntity.ok(response); - } - - @Override - public ResponseEntity getClubApplications( - @PathVariable(name = "clubId") Integer clubId, - @UserId Integer userId - ) { - ClubApplicationsResponse response = clubService.getClubApplications(clubId, userId); - return ResponseEntity.ok(response); - } - - @Override - public ResponseEntity getClubApplicationAnswers( - @PathVariable(name = "clubId") Integer clubId, - @PathVariable(name = "applicationId") Integer applicationId, - @UserId Integer userId - ) { - ClubApplicationAnswersResponse response = clubService.getClubApplicationAnswers( - clubId, - applicationId, - userId - ); - - return ResponseEntity.ok(response); - } - - @Override - public ResponseEntity getClubMembers( - @PathVariable(name = "clubId") Integer clubId, - @Valid @ParameterObject @ModelAttribute ClubMemberCondition condition, - @UserId Integer userId - ) { - ClubMembersResponse response = clubService.getClubMembers(clubId, userId, condition); - return ResponseEntity.ok(response); - } - - @Override - public ResponseEntity applyClub( - @PathVariable(name = "clubId") Integer clubId, - @Valid @RequestBody ClubApplyRequest request, - @UserId Integer userId - ) { - ClubFeeInfoResponse response = clubService.applyClub(clubId, userId, request); - return ResponseEntity.ok(response); - } - - @Override - public ResponseEntity getFeeInfo( - @PathVariable(name = "clubId") Integer clubId, - @UserId Integer userId - ) { - ClubFeeInfoResponse response = clubService.getFeeInfo(clubId, userId); - return ResponseEntity.ok(response); - } - - @Override - public ResponseEntity replaceFeeInfo( - @PathVariable(name = "clubId") Integer clubId, - @Valid @RequestBody ClubFeeInfoReplaceRequest request, - @UserId Integer userId - ) { - ClubFeeInfoResponse response = clubService.replaceFeeInfo(clubId, userId, request); - return ResponseEntity.ok(response); - } - - @Override - public ResponseEntity getApplyQuestions( - @PathVariable(name = "clubId") Integer clubId, - @UserId Integer userId - ) { - ClubApplyQuestionsResponse response = clubService.getApplyQuestions(clubId, userId); - return ResponseEntity.ok(response); - } - - @Override - public ResponseEntity replaceApplyQuestions( - @PathVariable(name = "clubId") Integer clubId, - @Valid @RequestBody ClubApplyQuestionsReplaceRequest request, - @UserId Integer userId - ) { - ClubApplyQuestionsResponse response = clubService.replaceApplyQuestions(clubId, userId, request); - return ResponseEntity.ok(response); - } - - @Override - public ResponseEntity getRecruitments( - @PathVariable(name = "clubId") Integer clubId, - @UserId Integer userId - ) { - ClubRecruitmentResponse response = clubService.getRecruitment(clubId, userId); - return ResponseEntity.ok(response); - } - - @Override - public ResponseEntity createRecruitment( - @RequestBody @Valid ClubRecruitmentCreateRequest request, - @PathVariable(name = "clubId") Integer clubId, - @UserId Integer userId - ) { - clubService.createRecruitment(clubId, userId, request); - return ResponseEntity.ok().build(); - } - - @Override - public ResponseEntity updateRecruitment( - @Valid @RequestBody ClubRecruitmentUpdateRequest request, - @PathVariable(name = "clubId") Integer clubId, - @UserId Integer userId - ) { - clubService.updateRecruitment(clubId, userId, request); - return ResponseEntity.noContent().build(); - } - - @Override - public ResponseEntity getClubPositions( - @PathVariable(name = "clubId") Integer clubId, - @UserId Integer userId - ) { - ClubPositionsResponse response = clubPositionService.getClubPositions(clubId, userId); - return ResponseEntity.ok(response); - } - - @Override - public ResponseEntity createClubPosition( - @PathVariable(name = "clubId") Integer clubId, - @Valid @RequestBody ClubPositionCreateRequest request, - @UserId Integer userId - ) { - ClubPositionsResponse response = clubPositionService.createClubPosition(clubId, userId, request); - return ResponseEntity.ok(response); - } - - @Override - public ResponseEntity updateClubPositionName( - @PathVariable(name = "clubId") Integer clubId, - @PathVariable(name = "positionId") Integer positionId, - @Valid @RequestBody ClubPositionUpdateRequest request, - @UserId Integer userId - ) { - ClubPositionsResponse response = clubPositionService.updateClubPositionName( - clubId, positionId, userId, request - ); - return ResponseEntity.ok(response); - } - - @Override - public ResponseEntity deleteClubPosition( - @PathVariable(name = "clubId") Integer clubId, - @PathVariable(name = "positionId") Integer positionId, - @UserId Integer userId - ) { - clubPositionService.deleteClubPosition(clubId, positionId, userId); - return ResponseEntity.noContent().build(); - } - - @Override - public ResponseEntity changeMemberPosition( - @PathVariable(name = "clubId") Integer clubId, - @PathVariable(name = "memberId") Integer memberId, - @Valid @RequestBody MemberPositionChangeRequest request, - @UserId Integer userId - ) { - clubMemberManagementService.changeMemberPosition(clubId, memberId, userId, request); - return ResponseEntity.noContent().build(); - } - - @Override - public ResponseEntity transferPresident( - @PathVariable(name = "clubId") Integer clubId, - @Valid @RequestBody PresidentTransferRequest request, - @UserId Integer userId - ) { - clubMemberManagementService.transferPresident(clubId, userId, request); - return ResponseEntity.noContent().build(); - } - - @Override - public ResponseEntity changeVicePresident( - @PathVariable(name = "clubId") Integer clubId, - @Valid @RequestBody VicePresidentChangeRequest request, - @UserId Integer userId - ) { - clubMemberManagementService.changeVicePresident(clubId, userId, request); - return ResponseEntity.noContent().build(); - } - - @Override - public ResponseEntity addMember( - @PathVariable(name = "clubId") Integer clubId, - @Valid @RequestBody ClubMemberAddRequest request, - @UserId Integer userId - ) { - clubMemberManagementService.addMember(clubId, userId, request); - return ResponseEntity.ok().build(); - } - - @Override - public ResponseEntity removeMember( - @PathVariable(name = "clubId") Integer clubId, - @PathVariable(name = "memberId") Integer memberId, - @UserId Integer userId - ) { - clubMemberManagementService.removeMember(clubId, memberId, userId); - return ResponseEntity.noContent().build(); - } -} +package gg.agit.konect.domain.club.controller; + +import org.springdoc.core.annotations.ParameterObject; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.ModelAttribute; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import gg.agit.konect.domain.club.dto.ClubApplicationAnswersResponse; +import gg.agit.konect.domain.club.dto.ClubAppliedClubsResponse; +import gg.agit.konect.domain.club.dto.ClubApplicationsResponse; +import gg.agit.konect.domain.club.dto.ClubApplyQuestionsReplaceRequest; +import gg.agit.konect.domain.club.dto.ClubApplyQuestionsResponse; +import gg.agit.konect.domain.club.dto.ClubApplyRequest; +import gg.agit.konect.domain.club.dto.ClubBasicInfoUpdateRequest; +import gg.agit.konect.domain.club.dto.ClubCondition; +import gg.agit.konect.domain.club.dto.ClubCreateRequest; +import gg.agit.konect.domain.club.dto.ClubDetailResponse; +import gg.agit.konect.domain.club.dto.ClubDetailUpdateRequest; +import gg.agit.konect.domain.club.dto.ClubFeeInfoReplaceRequest; +import gg.agit.konect.domain.club.dto.ClubFeeInfoResponse; +import gg.agit.konect.domain.club.dto.ClubMemberAddRequest; +import gg.agit.konect.domain.club.dto.ClubMemberCondition; +import gg.agit.konect.domain.club.dto.ClubMembersResponse; +import gg.agit.konect.domain.club.dto.ClubMembershipsResponse; +import gg.agit.konect.domain.club.dto.ClubPositionCreateRequest; +import gg.agit.konect.domain.club.dto.ClubPositionUpdateRequest; +import gg.agit.konect.domain.club.dto.ClubPositionsResponse; +import gg.agit.konect.domain.club.dto.ClubProfileUpdateRequest; +import gg.agit.konect.domain.club.dto.ClubRecruitmentCreateRequest; +import gg.agit.konect.domain.club.dto.ClubRecruitmentResponse; +import gg.agit.konect.domain.club.dto.ClubRecruitmentUpdateRequest; +import gg.agit.konect.domain.club.dto.ClubTagsResponse; +import gg.agit.konect.domain.club.dto.ClubsResponse; +import gg.agit.konect.domain.club.dto.MemberPositionChangeRequest; +import gg.agit.konect.domain.club.dto.PresidentTransferRequest; +import gg.agit.konect.domain.club.dto.VicePresidentChangeRequest; +import gg.agit.konect.domain.club.service.ClubMemberManagementService; +import gg.agit.konect.domain.club.service.ClubPositionService; +import gg.agit.konect.domain.club.service.ClubService; +import gg.agit.konect.global.auth.annotation.UserId; +import jakarta.validation.Valid; +import lombok.RequiredArgsConstructor; + +@RestController +@RequiredArgsConstructor +@RequestMapping("/clubs") +public class ClubController implements + ClubBasicApi, + ClubRecruitmentApi, + ClubApplicationApi, + ClubPositionApi, + ClubMemberApi { + + private final ClubService clubService; + private final ClubPositionService clubPositionService; + private final ClubMemberManagementService clubMemberManagementService; + + @Override + public ResponseEntity getClubs( + @Valid @ParameterObject @ModelAttribute ClubCondition condition, + @UserId Integer userId + ) { + ClubsResponse response = clubService.getClubs(condition, userId); + return ResponseEntity.ok(response); + } + + @Override + public ResponseEntity getClubDetail( + @PathVariable(name = "clubId") Integer clubId, + @UserId Integer userId + ) { + ClubDetailResponse response = clubService.getClubDetail(clubId, userId); + return ResponseEntity.ok(response); + } + + @Override + public ResponseEntity createClub( + @Valid @RequestBody ClubCreateRequest request, + @UserId Integer userId + ) { + ClubDetailResponse response = clubService.createClub(userId, request); + return ResponseEntity.ok(response); + } + + @Override + public ResponseEntity updateProfile( + @PathVariable(name = "clubId") Integer clubId, + @Valid @RequestBody ClubProfileUpdateRequest request, + @UserId Integer userId + ) { + clubService.updateProfile(clubId, userId, request); + return ResponseEntity.noContent().build(); + } + + @Override + public ResponseEntity updateDetails( + @PathVariable(name = "clubId") Integer clubId, + @Valid @RequestBody ClubDetailUpdateRequest request, + @UserId Integer userId + ) { + clubService.updateDetails(clubId, userId, request); + return ResponseEntity.noContent().build(); + } + + @Override + public ResponseEntity updateBasicInfo( + @PathVariable(name = "clubId") Integer clubId, + @Valid @RequestBody ClubBasicInfoUpdateRequest request, + @UserId Integer userId + ) { + clubService.updateBasicInfo(clubId, userId, request); + return ResponseEntity.noContent().build(); + } + + @Override + public ResponseEntity getTags() { + ClubTagsResponse response = clubService.getTags(); + return ResponseEntity.ok(response); + } + + @Override + public ResponseEntity getJoinedClubs(@UserId Integer userId) { + ClubMembershipsResponse response = clubService.getJoinedClubs(userId); + return ResponseEntity.ok(response); + } + + @Override + public ResponseEntity getManagedClubs( + @UserId Integer userId + ) { + ClubMembershipsResponse response = clubService.getManagedClubs(userId); + return ResponseEntity.ok(response); + } + + @Override + public ResponseEntity getAppliedClubs( + @UserId Integer userId + ) { + ClubAppliedClubsResponse response = clubService.getAppliedClubs(userId); + return ResponseEntity.ok(response); + } + + @Override + public ResponseEntity getClubApplications( + @PathVariable(name = "clubId") Integer clubId, + @UserId Integer userId + ) { + ClubApplicationsResponse response = clubService.getClubApplications(clubId, userId); + return ResponseEntity.ok(response); + } + + @Override + public ResponseEntity getClubApplicationAnswers( + @PathVariable(name = "clubId") Integer clubId, + @PathVariable(name = "applicationId") Integer applicationId, + @UserId Integer userId + ) { + ClubApplicationAnswersResponse response = clubService.getClubApplicationAnswers( + clubId, + applicationId, + userId + ); + + return ResponseEntity.ok(response); + } + + @Override + public ResponseEntity getClubMembers( + @PathVariable(name = "clubId") Integer clubId, + @Valid @ParameterObject @ModelAttribute ClubMemberCondition condition, + @UserId Integer userId + ) { + ClubMembersResponse response = clubService.getClubMembers(clubId, userId, condition); + return ResponseEntity.ok(response); + } + + @Override + public ResponseEntity applyClub( + @PathVariable(name = "clubId") Integer clubId, + @Valid @RequestBody ClubApplyRequest request, + @UserId Integer userId + ) { + ClubFeeInfoResponse response = clubService.applyClub(clubId, userId, request); + return ResponseEntity.ok(response); + } + + @Override + public ResponseEntity getFeeInfo( + @PathVariable(name = "clubId") Integer clubId, + @UserId Integer userId + ) { + ClubFeeInfoResponse response = clubService.getFeeInfo(clubId, userId); + return ResponseEntity.ok(response); + } + + @Override + public ResponseEntity replaceFeeInfo( + @PathVariable(name = "clubId") Integer clubId, + @Valid @RequestBody ClubFeeInfoReplaceRequest request, + @UserId Integer userId + ) { + ClubFeeInfoResponse response = clubService.replaceFeeInfo(clubId, userId, request); + return ResponseEntity.ok(response); + } + + @Override + public ResponseEntity getApplyQuestions( + @PathVariable(name = "clubId") Integer clubId, + @UserId Integer userId + ) { + ClubApplyQuestionsResponse response = clubService.getApplyQuestions(clubId, userId); + return ResponseEntity.ok(response); + } + + @Override + public ResponseEntity replaceApplyQuestions( + @PathVariable(name = "clubId") Integer clubId, + @Valid @RequestBody ClubApplyQuestionsReplaceRequest request, + @UserId Integer userId + ) { + ClubApplyQuestionsResponse response = clubService.replaceApplyQuestions(clubId, userId, request); + return ResponseEntity.ok(response); + } + + @Override + public ResponseEntity getRecruitments( + @PathVariable(name = "clubId") Integer clubId, + @UserId Integer userId + ) { + ClubRecruitmentResponse response = clubService.getRecruitment(clubId, userId); + return ResponseEntity.ok(response); + } + + @Override + public ResponseEntity createRecruitment( + @RequestBody @Valid ClubRecruitmentCreateRequest request, + @PathVariable(name = "clubId") Integer clubId, + @UserId Integer userId + ) { + clubService.createRecruitment(clubId, userId, request); + return ResponseEntity.ok().build(); + } + + @Override + public ResponseEntity updateRecruitment( + @Valid @RequestBody ClubRecruitmentUpdateRequest request, + @PathVariable(name = "clubId") Integer clubId, + @UserId Integer userId + ) { + clubService.updateRecruitment(clubId, userId, request); + return ResponseEntity.noContent().build(); + } + + @Override + public ResponseEntity getClubPositions( + @PathVariable(name = "clubId") Integer clubId, + @UserId Integer userId + ) { + ClubPositionsResponse response = clubPositionService.getClubPositions(clubId, userId); + return ResponseEntity.ok(response); + } + + @Override + public ResponseEntity createClubPosition( + @PathVariable(name = "clubId") Integer clubId, + @Valid @RequestBody ClubPositionCreateRequest request, + @UserId Integer userId + ) { + ClubPositionsResponse response = clubPositionService.createClubPosition(clubId, userId, request); + return ResponseEntity.ok(response); + } + + @Override + public ResponseEntity updateClubPositionName( + @PathVariable(name = "clubId") Integer clubId, + @PathVariable(name = "positionId") Integer positionId, + @Valid @RequestBody ClubPositionUpdateRequest request, + @UserId Integer userId + ) { + ClubPositionsResponse response = clubPositionService.updateClubPositionName( + clubId, positionId, userId, request + ); + return ResponseEntity.ok(response); + } + + @Override + public ResponseEntity deleteClubPosition( + @PathVariable(name = "clubId") Integer clubId, + @PathVariable(name = "positionId") Integer positionId, + @UserId Integer userId + ) { + clubPositionService.deleteClubPosition(clubId, positionId, userId); + return ResponseEntity.noContent().build(); + } + + @Override + public ResponseEntity changeMemberPosition( + @PathVariable(name = "clubId") Integer clubId, + @PathVariable(name = "memberId") Integer memberId, + @Valid @RequestBody MemberPositionChangeRequest request, + @UserId Integer userId + ) { + clubMemberManagementService.changeMemberPosition(clubId, memberId, userId, request); + return ResponseEntity.noContent().build(); + } + + @Override + public ResponseEntity transferPresident( + @PathVariable(name = "clubId") Integer clubId, + @Valid @RequestBody PresidentTransferRequest request, + @UserId Integer userId + ) { + clubMemberManagementService.transferPresident(clubId, userId, request); + return ResponseEntity.noContent().build(); + } + + @Override + public ResponseEntity changeVicePresident( + @PathVariable(name = "clubId") Integer clubId, + @Valid @RequestBody VicePresidentChangeRequest request, + @UserId Integer userId + ) { + clubMemberManagementService.changeVicePresident(clubId, userId, request); + return ResponseEntity.noContent().build(); + } + + @Override + public ResponseEntity addMember( + @PathVariable(name = "clubId") Integer clubId, + @Valid @RequestBody ClubMemberAddRequest request, + @UserId Integer userId + ) { + clubMemberManagementService.addMember(clubId, userId, request); + return ResponseEntity.ok().build(); + } + + @Override + public ResponseEntity removeMember( + @PathVariable(name = "clubId") Integer clubId, + @PathVariable(name = "memberId") Integer memberId, + @UserId Integer userId + ) { + clubMemberManagementService.removeMember(clubId, memberId, userId); + return ResponseEntity.noContent().build(); + } +} diff --git a/src/main/java/gg/agit/konect/domain/club/controller/ClubMemberApi.java b/src/main/java/gg/agit/konect/domain/club/controller/ClubMemberApi.java index 8ed871d2..d6d58f08 100644 --- a/src/main/java/gg/agit/konect/domain/club/controller/ClubMemberApi.java +++ b/src/main/java/gg/agit/konect/domain/club/controller/ClubMemberApi.java @@ -14,10 +14,8 @@ import gg.agit.konect.domain.club.dto.VicePresidentChangeRequest; import gg.agit.konect.global.auth.annotation.UserId; import io.swagger.v3.oas.annotations.Operation; -import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.validation.Valid; -@Tag(name = "(Normal) Club - Member: 회원 관리", description = "동아리 회원 직책 변경, 추가, 제거 API") @RequestMapping("/clubs") public interface ClubMemberApi { diff --git a/src/main/java/gg/agit/konect/domain/club/controller/ClubPositionApi.java b/src/main/java/gg/agit/konect/domain/club/controller/ClubPositionApi.java index 9bed1baa..c1194495 100644 --- a/src/main/java/gg/agit/konect/domain/club/controller/ClubPositionApi.java +++ b/src/main/java/gg/agit/konect/domain/club/controller/ClubPositionApi.java @@ -14,10 +14,8 @@ import gg.agit.konect.domain.club.dto.ClubPositionsResponse; import gg.agit.konect.global.auth.annotation.UserId; import io.swagger.v3.oas.annotations.Operation; -import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.validation.Valid; -@Tag(name = "(Normal) Club - Position: 직책 관리", description = "동아리 직책 생성, 수정, 삭제 API") @RequestMapping("/clubs") public interface ClubPositionApi { diff --git a/src/main/java/gg/agit/konect/domain/club/controller/ClubRecruitmentApi.java b/src/main/java/gg/agit/konect/domain/club/controller/ClubRecruitmentApi.java index dc3b0663..15c15ac9 100644 --- a/src/main/java/gg/agit/konect/domain/club/controller/ClubRecruitmentApi.java +++ b/src/main/java/gg/agit/konect/domain/club/controller/ClubRecruitmentApi.java @@ -13,10 +13,8 @@ import gg.agit.konect.domain.club.dto.ClubRecruitmentUpdateRequest; import gg.agit.konect.global.auth.annotation.UserId; import io.swagger.v3.oas.annotations.Operation; -import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.validation.Valid; -@Tag(name = "(Normal) Club - Recruitment: 모집 공고", description = "동아리 모집 공고 관리 API") @RequestMapping("/clubs") public interface ClubRecruitmentApi { From 2546bb01299c6d18b26c676342942872542b2083 Mon Sep 17 00:00:00 2001 From: JanooGwan Date: Wed, 28 Jan 2026 21:13:12 +0900 Subject: [PATCH 5/6] =?UTF-8?q?fix:=20Swagger=20=EC=83=81=20=EB=88=84?= =?UTF-8?q?=EB=9D=BD=EB=90=9C=20=EC=97=94=EB=93=9C=ED=8F=AC=EC=9D=B8?= =?UTF-8?q?=ED=8A=B8=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../club/controller/ClubApplicationApi.java | 33 +++++++++++++++++++ .../domain/club/controller/ClubBasicApi.java | 14 ++++++++ .../club/controller/ClubController.java | 30 +++++++++++++++++ 3 files changed, 77 insertions(+) diff --git a/src/main/java/gg/agit/konect/domain/club/controller/ClubApplicationApi.java b/src/main/java/gg/agit/konect/domain/club/controller/ClubApplicationApi.java index d81bc9e8..8ba2b362 100644 --- a/src/main/java/gg/agit/konect/domain/club/controller/ClubApplicationApi.java +++ b/src/main/java/gg/agit/konect/domain/club/controller/ClubApplicationApi.java @@ -71,6 +71,39 @@ ResponseEntity getClubApplicationAnswers( @UserId Integer userId ); + @Operation(summary = "동아리 가입 신청을 승인한다.", tags = TAG, description = """ + 동아리 회장 또는 부회장만 가입 신청을 승인할 수 있습니다. + 승인 시 지원자는 일반회원으로 등록되며, 지원 내역은 삭제됩니다. + + ## 에러 + - ALREADY_CLUB_MEMBER (409): 이미 동아리 회원입니다. + - FORBIDDEN_CLUB_MANAGER_ACCESS (403): 동아리 매니저 권한이 없습니다. + - NOT_FOUND_CLUB (404): 동아리를 찾을 수 없습니다. + - NOT_FOUND_CLUB_APPLY (404): 동아리 지원 내역을 찾을 수 없습니다. + """) + @PostMapping("/{clubId}/applications/{applicationId}/approve") + ResponseEntity approveClubApplication( + @PathVariable(name = "clubId") Integer clubId, + @PathVariable(name = "applicationId") Integer applicationId, + @UserId Integer userId + ); + + @Operation(summary = "동아리 가입 신청을 거절한다.", tags = TAG, description = """ + 동아리 회장 또는 부회장만 가입 신청을 거절할 수 있습니다. + 거절 시 지원 내역은 삭제됩니다. + + ## 에러 + - FORBIDDEN_CLUB_MANAGER_ACCESS (403): 동아리 매니저 권한이 없습니다. + - NOT_FOUND_CLUB (404): 동아리를 찾을 수 없습니다. + - NOT_FOUND_CLUB_APPLY (404): 동아리 지원 내역을 찾을 수 없습니다. + """) + @PostMapping("/{clubId}/applications/{applicationId}/reject") + ResponseEntity rejectClubApplication( + @PathVariable(name = "clubId") Integer clubId, + @PathVariable(name = "applicationId") Integer applicationId, + @UserId Integer userId + ); + @Operation(summary = "동아리 가입 문항을 조회한다.", tags = TAG) @GetMapping("/{clubId}/questions") ResponseEntity getApplyQuestions( diff --git a/src/main/java/gg/agit/konect/domain/club/controller/ClubBasicApi.java b/src/main/java/gg/agit/konect/domain/club/controller/ClubBasicApi.java index 54635a4a..d23f2ce1 100644 --- a/src/main/java/gg/agit/konect/domain/club/controller/ClubBasicApi.java +++ b/src/main/java/gg/agit/konect/domain/club/controller/ClubBasicApi.java @@ -20,6 +20,7 @@ import gg.agit.konect.domain.club.dto.ClubMembersResponse; import gg.agit.konect.domain.club.dto.ClubMembershipsResponse; import gg.agit.konect.domain.club.dto.ClubProfileUpdateRequest; +import gg.agit.konect.domain.club.dto.MyManagedClubResponse; import gg.agit.konect.domain.club.dto.ClubTagsResponse; import gg.agit.konect.domain.club.dto.ClubsResponse; import gg.agit.konect.global.auth.annotation.UserId; @@ -131,6 +132,19 @@ ResponseEntity getManagedClubs( @UserId Integer userId ); + @Operation(summary = "관리 중인 동아리의 상세 정보를 조회한다.", tags = TAG, description = """ + 동아리 관리자(회장, 부회장, 운영진)만 조회할 수 있습니다. + + ## 에러 + - FORBIDDEN_CLUB_MANAGER_ACCESS (403): 동아리 매니저 권한이 없습니다. + - NOT_FOUND_CLUB (404): 동아리를 찾을 수 없습니다. + """) + @GetMapping("/managed/{clubId}") + ResponseEntity getManagedClubDetail( + @PathVariable(name = "clubId") Integer clubId, + @UserId Integer userId + ); + @Operation(summary = "가입 승인 대기 중인 동아리 리스트를 조회한다.", tags = TAG) @GetMapping("/applied") ResponseEntity getAppliedClubs( diff --git a/src/main/java/gg/agit/konect/domain/club/controller/ClubController.java b/src/main/java/gg/agit/konect/domain/club/controller/ClubController.java index ed817616..154e7f1b 100644 --- a/src/main/java/gg/agit/konect/domain/club/controller/ClubController.java +++ b/src/main/java/gg/agit/konect/domain/club/controller/ClubController.java @@ -25,6 +25,7 @@ import gg.agit.konect.domain.club.dto.ClubMemberCondition; import gg.agit.konect.domain.club.dto.ClubMembersResponse; import gg.agit.konect.domain.club.dto.ClubMembershipsResponse; +import gg.agit.konect.domain.club.dto.MyManagedClubResponse; import gg.agit.konect.domain.club.dto.ClubPositionCreateRequest; import gg.agit.konect.domain.club.dto.ClubPositionUpdateRequest; import gg.agit.konect.domain.club.dto.ClubPositionsResponse; @@ -135,6 +136,15 @@ public ResponseEntity getManagedClubs( return ResponseEntity.ok(response); } + @Override + public ResponseEntity getManagedClubDetail( + @PathVariable(name = "clubId") Integer clubId, + @UserId Integer userId + ) { + MyManagedClubResponse response = clubService.getManagedClubDetail(clubId, userId); + return ResponseEntity.ok(response); + } + @Override public ResponseEntity getAppliedClubs( @UserId Integer userId @@ -167,6 +177,26 @@ public ResponseEntity getClubApplicationAnswers( return ResponseEntity.ok(response); } + @Override + public ResponseEntity approveClubApplication( + @PathVariable(name = "clubId") Integer clubId, + @PathVariable(name = "applicationId") Integer applicationId, + @UserId Integer userId + ) { + clubService.approveClubApplication(clubId, applicationId, userId); + return ResponseEntity.ok().build(); + } + + @Override + public ResponseEntity rejectClubApplication( + @PathVariable(name = "clubId") Integer clubId, + @PathVariable(name = "applicationId") Integer applicationId, + @UserId Integer userId + ) { + clubService.rejectClubApplication(clubId, applicationId, userId); + return ResponseEntity.ok().build(); + } + @Override public ResponseEntity getClubMembers( @PathVariable(name = "clubId") Integer clubId, From e871646b2fe4b5ead0009810ee4df88aadbdee04 Mon Sep 17 00:00:00 2001 From: JanooGwan Date: Thu, 29 Jan 2026 11:40:55 +0900 Subject: [PATCH 6/6] =?UTF-8?q?refactor:=20Controller=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../club/controller/ClubApplicationApi.java | 22 +- .../controller/ClubApplicationController.java | 118 ++++++ .../domain/club/controller/ClubBasicApi.java | 26 +- .../club/controller/ClubBasicController.java | 128 ++++++ .../club/controller/ClubController.java | 372 ------------------ .../domain/club/controller/ClubMemberApi.java | 14 +- .../club/controller/ClubMemberController.java | 75 ++++ .../club/controller/ClubPositionApi.java | 12 +- .../controller/ClubPositionController.java | 65 +++ .../club/controller/ClubRecruitmentApi.java | 10 +- .../controller/ClubRecruitmentController.java | 52 +++ 11 files changed, 480 insertions(+), 414 deletions(-) create mode 100644 src/main/java/gg/agit/konect/domain/club/controller/ClubApplicationController.java create mode 100644 src/main/java/gg/agit/konect/domain/club/controller/ClubBasicController.java delete mode 100644 src/main/java/gg/agit/konect/domain/club/controller/ClubController.java create mode 100644 src/main/java/gg/agit/konect/domain/club/controller/ClubMemberController.java create mode 100644 src/main/java/gg/agit/konect/domain/club/controller/ClubPositionController.java create mode 100644 src/main/java/gg/agit/konect/domain/club/controller/ClubRecruitmentController.java diff --git a/src/main/java/gg/agit/konect/domain/club/controller/ClubApplicationApi.java b/src/main/java/gg/agit/konect/domain/club/controller/ClubApplicationApi.java index 8ba2b362..44674295 100644 --- a/src/main/java/gg/agit/konect/domain/club/controller/ClubApplicationApi.java +++ b/src/main/java/gg/agit/konect/domain/club/controller/ClubApplicationApi.java @@ -17,14 +17,14 @@ import gg.agit.konect.domain.club.dto.ClubFeeInfoResponse; import gg.agit.konect.global.auth.annotation.UserId; import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.validation.Valid; +@Tag(name = "(Normal) Club - Application: 지원 및 신청") @RequestMapping("/clubs") public interface ClubApplicationApi { - String TAG = "(Normal) Club - Application: 지원 및 신청"; - - @Operation(summary = "동아리 가입 신청을 한다.", tags = TAG, description = """ + @Operation(summary = "동아리 가입 신청을 한다.", description = """ 동아리 가입 신청서를 제출합니다. 설문 질문이 없는 경우 answers는 빈 배열을 전달합니다. @@ -40,7 +40,7 @@ ResponseEntity applyClub( @UserId Integer userId ); - @Operation(summary = "동아리 지원 내역을 조회한다.", tags = TAG, description = """ + @Operation(summary = "동아리 지원 내역을 조회한다.", description = """ - 동아리 관리자만 해당 동아리의 지원 내역을 조회할 수 있습니다. - 현재 지정된 모집 일정 범위에 지원한 내역만 볼 수 있습니다. - 상시 모집의 경우 모든 내역을 봅니다. @@ -56,7 +56,7 @@ ResponseEntity getClubApplications( @UserId Integer userId ); - @Operation(summary = "동아리 지원 답변을 조회한다.", tags = TAG, description = """ + @Operation(summary = "동아리 지원 답변을 조회한다.", description = """ - 동아리 관리자만 해당 동아리의 지원 답변을 조회할 수 있습니다. ## 에러 @@ -71,7 +71,7 @@ ResponseEntity getClubApplicationAnswers( @UserId Integer userId ); - @Operation(summary = "동아리 가입 신청을 승인한다.", tags = TAG, description = """ + @Operation(summary = "동아리 가입 신청을 승인한다.", description = """ 동아리 회장 또는 부회장만 가입 신청을 승인할 수 있습니다. 승인 시 지원자는 일반회원으로 등록되며, 지원 내역은 삭제됩니다. @@ -88,7 +88,7 @@ ResponseEntity approveClubApplication( @UserId Integer userId ); - @Operation(summary = "동아리 가입 신청을 거절한다.", tags = TAG, description = """ + @Operation(summary = "동아리 가입 신청을 거절한다.", description = """ 동아리 회장 또는 부회장만 가입 신청을 거절할 수 있습니다. 거절 시 지원 내역은 삭제됩니다. @@ -104,14 +104,14 @@ ResponseEntity rejectClubApplication( @UserId Integer userId ); - @Operation(summary = "동아리 가입 문항을 조회한다.", tags = TAG) + @Operation(summary = "동아리 가입 문항을 조회한다.") @GetMapping("/{clubId}/questions") ResponseEntity getApplyQuestions( @PathVariable(name = "clubId") Integer clubId, @UserId Integer userId ); - @Operation(summary = "동아리 가입 문항을 덮어써서 대체한다.", tags = TAG, description = """ + @Operation(summary = "동아리 가입 문항을 덮어써서 대체한다.", description = """ 요청에 포함된 문항 목록이 최종 상태가 됩니다. - questionId가 있으면 수정 - questionId가 없으면 생성 @@ -130,7 +130,7 @@ ResponseEntity replaceApplyQuestions( @UserId Integer userId ); - @Operation(summary = "동아리 회비 정보를 조회한다.", tags = TAG, description = """ + @Operation(summary = "동아리 회비 정보를 조회한다.", description = """ 동아리 가입 신청을 완료했거나 동아리 관리자 권한이 있는 사용자만 회비 계좌 정보를 조회할 수 있습니다. ## 에러 @@ -142,7 +142,7 @@ ResponseEntity getFeeInfo( @UserId Integer userId ); - @Operation(summary = "동아리 회비 정보를 덮어써서 대체한다.", tags = TAG, description = """ + @Operation(summary = "동아리 회비 정보를 덮어써서 대체한다.", description = """ 요청 본문이 최종 상태가 됩니다. - 모든 필드를 전달하면 생성/수정합니다. - 모든 필드가 null이면 회비 정보를 삭제합니다. diff --git a/src/main/java/gg/agit/konect/domain/club/controller/ClubApplicationController.java b/src/main/java/gg/agit/konect/domain/club/controller/ClubApplicationController.java new file mode 100644 index 00000000..0a4fedd7 --- /dev/null +++ b/src/main/java/gg/agit/konect/domain/club/controller/ClubApplicationController.java @@ -0,0 +1,118 @@ +package gg.agit.konect.domain.club.controller; + +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import gg.agit.konect.domain.club.dto.ClubApplicationAnswersResponse; +import gg.agit.konect.domain.club.dto.ClubApplicationsResponse; +import gg.agit.konect.domain.club.dto.ClubApplyQuestionsReplaceRequest; +import gg.agit.konect.domain.club.dto.ClubApplyQuestionsResponse; +import gg.agit.konect.domain.club.dto.ClubApplyRequest; +import gg.agit.konect.domain.club.dto.ClubFeeInfoReplaceRequest; +import gg.agit.konect.domain.club.dto.ClubFeeInfoResponse; +import gg.agit.konect.domain.club.service.ClubService; +import gg.agit.konect.global.auth.annotation.UserId; +import jakarta.validation.Valid; +import lombok.RequiredArgsConstructor; + +@RestController +@RequiredArgsConstructor +@RequestMapping("/clubs") +public class ClubApplicationController implements ClubApplicationApi { + + private final ClubService clubService; + + @Override + public ResponseEntity applyClub( + @PathVariable(name = "clubId") Integer clubId, + @Valid @RequestBody ClubApplyRequest request, + @UserId Integer userId + ) { + ClubFeeInfoResponse response = clubService.applyClub(clubId, userId, request); + return ResponseEntity.ok(response); + } + + @Override + public ResponseEntity getClubApplications( + @PathVariable(name = "clubId") Integer clubId, + @UserId Integer userId + ) { + ClubApplicationsResponse response = clubService.getClubApplications(clubId, userId); + return ResponseEntity.ok(response); + } + + @Override + public ResponseEntity getClubApplicationAnswers( + @PathVariable(name = "clubId") Integer clubId, + @PathVariable(name = "applicationId") Integer applicationId, + @UserId Integer userId + ) { + ClubApplicationAnswersResponse response = clubService.getClubApplicationAnswers( + clubId, + applicationId, + userId + ); + return ResponseEntity.ok(response); + } + + @Override + public ResponseEntity approveClubApplication( + @PathVariable(name = "clubId") Integer clubId, + @PathVariable(name = "applicationId") Integer applicationId, + @UserId Integer userId + ) { + clubService.approveClubApplication(clubId, applicationId, userId); + return ResponseEntity.ok().build(); + } + + @Override + public ResponseEntity rejectClubApplication( + @PathVariable(name = "clubId") Integer clubId, + @PathVariable(name = "applicationId") Integer applicationId, + @UserId Integer userId + ) { + clubService.rejectClubApplication(clubId, applicationId, userId); + return ResponseEntity.ok().build(); + } + + @Override + public ResponseEntity getApplyQuestions( + @PathVariable(name = "clubId") Integer clubId, + @UserId Integer userId + ) { + ClubApplyQuestionsResponse response = clubService.getApplyQuestions(clubId, userId); + return ResponseEntity.ok(response); + } + + @Override + public ResponseEntity replaceApplyQuestions( + @PathVariable(name = "clubId") Integer clubId, + @Valid @RequestBody ClubApplyQuestionsReplaceRequest request, + @UserId Integer userId + ) { + ClubApplyQuestionsResponse response = clubService.replaceApplyQuestions(clubId, userId, request); + return ResponseEntity.ok(response); + } + + @Override + public ResponseEntity getFeeInfo( + @PathVariable(name = "clubId") Integer clubId, + @UserId Integer userId + ) { + ClubFeeInfoResponse response = clubService.getFeeInfo(clubId, userId); + return ResponseEntity.ok(response); + } + + @Override + public ResponseEntity replaceFeeInfo( + @PathVariable(name = "clubId") Integer clubId, + @Valid @RequestBody ClubFeeInfoReplaceRequest request, + @UserId Integer userId + ) { + ClubFeeInfoResponse response = clubService.replaceFeeInfo(clubId, userId, request); + return ResponseEntity.ok(response); + } +} diff --git a/src/main/java/gg/agit/konect/domain/club/controller/ClubBasicApi.java b/src/main/java/gg/agit/konect/domain/club/controller/ClubBasicApi.java index 574de3e6..99683fe3 100644 --- a/src/main/java/gg/agit/konect/domain/club/controller/ClubBasicApi.java +++ b/src/main/java/gg/agit/konect/domain/club/controller/ClubBasicApi.java @@ -24,14 +24,14 @@ import gg.agit.konect.domain.club.dto.MyManagedClubResponse; import gg.agit.konect.global.auth.annotation.UserId; import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.validation.Valid; +@Tag(name = "(Normal) Club - Basic: 기본 관리") @RequestMapping("/clubs") public interface ClubBasicApi { - String TAG = "(Normal) Club - Basic: 기본 관리"; - - @Operation(summary = "페이지 네이션으로 동아리 리스트를 조회한다.", tags = TAG, description = """ + @Operation(summary = "페이지 네이션으로 동아리 리스트를 조회한다.", description = """ - isRecruiting가 true일 경우, 모집 중인 동아리만 조회하며 모집일(마감일)이 빠른 순으로 정렬됩니다. - isRecruiting가 false일 경우, 전체 동아리를 조회하되 모집 중인 동아리를 먼저 보여줍니다. - status은 BEFORE(모집 전), ONGOING(모집 중), CLOSED(모집 마감)으로 반환됩니다. @@ -42,7 +42,7 @@ ResponseEntity getClubs( @UserId Integer userId ); - @Operation(summary = "동아리의 상세 정보를 조회한다.", tags = TAG, description = """ + @Operation(summary = "동아리의 상세 정보를 조회한다.", description = """ - recruitmentStatus는 모집 기간에 따라 BEFORE(모집 전), ONGOING(모집 중), CLOSED(모집 마감)으로 반환됩니다. - 모집 일정 데이터가 존재하지 않는다면 CLOSED(모집 마감)으로 간주되며, startDate, endDate는 null로 반환됩니다. - 동아리 멤버이거나 지원 이력이 존재할 경우 isApplied는 true로 반환됩니다. @@ -53,7 +53,7 @@ ResponseEntity getClubDetail( @UserId Integer userId ); - @Operation(summary = "새로운 동아리를 생성한다.", tags = TAG, description = """ + @Operation(summary = "새로운 동아리를 생성한다.", description = """ 새로운 동아리를 생성하고, 생성한 사용자를 회장으로 등록합니다. ## 에러 @@ -65,7 +65,7 @@ ResponseEntity createClub( @UserId Integer userId ); - @Operation(summary = "동아리 프로필을 수정한다.", tags = TAG, description = """ + @Operation(summary = "동아리 프로필을 수정한다.", description = """ 동아리 회장 또는 부회장만 동아리 프로필을 수정할 수 있습니다. 수정 가능 항목: 한 줄 소개, 로고 이미지, 태그 동아리명과 분과는 수정할 수 없으며, 변경이 필요한 경우 문의하기를 통해 어드민에게 요청하세요. @@ -82,7 +82,7 @@ ResponseEntity updateProfile( @UserId Integer userId ); - @Operation(summary = "동아리 상세정보를 수정한다.", tags = TAG, description = """ + @Operation(summary = "동아리 상세정보를 수정한다.", description = """ 동아리 회장 또는 부회장만 동아리 상세정보를 수정할 수 있습니다. 수정 가능 항목: 동방 위치, 상세 소개 @@ -98,7 +98,7 @@ ResponseEntity updateDetails( @UserId Integer userId ); - @Operation(summary = "동아리 기본정보를 수정한다 (어드민 전용).", tags = TAG, description = """ + @Operation(summary = "동아리 기본정보를 수정한다 (어드민 전용).", description = """ 어드민만 동아리 기본정보를 수정할 수 있습니다. 수정 가능 항목: 동아리명, 분과 일반 관리자는 이 API를 사용할 수 없으며, 변경이 필요한 경우 문의하기를 통해 어드민에게 요청하세요. @@ -115,19 +115,19 @@ ResponseEntity updateBasicInfo( @UserId Integer userId ); - @Operation(summary = "가입한 동아리 리스트를 조회한다.", tags = TAG) + @Operation(summary = "가입한 동아리 리스트를 조회한다.") @GetMapping("/joined") ResponseEntity getJoinedClubs( @UserId Integer userId ); - @Operation(summary = "관리자 권한을 가지고 있는 동아리 리스트를 조회한다.", tags = TAG) + @Operation(summary = "관리자 권한을 가지고 있는 동아리 리스트를 조회한다.") @GetMapping("/managed") ResponseEntity getManagedClubs( @UserId Integer userId ); - @Operation(summary = "관리 중인 동아리의 상세 정보를 조회한다.", tags = TAG, description = """ + @Operation(summary = "관리 중인 동아리의 상세 정보를 조회한다.", description = """ 동아리 관리자(회장, 부회장, 운영진)만 조회할 수 있습니다. ## 에러 @@ -140,13 +140,13 @@ ResponseEntity getManagedClubDetail( @UserId Integer userId ); - @Operation(summary = "가입 승인 대기 중인 동아리 리스트를 조회한다.", tags = TAG) + @Operation(summary = "가입 승인 대기 중인 동아리 리스트를 조회한다.") @GetMapping("/applied") ResponseEntity getAppliedClubs( @UserId Integer userId ); - @Operation(summary = "동아리 멤버 리스트를 조회한다.", tags = TAG, description = """ + @Operation(summary = "동아리 멤버 리스트를 조회한다.", description = """ 동아리 회원만 멤버 리스트를 조회할 수 있습니다. positionGroup 파라미터로 특정 직책 그룹의 회원만 필터링할 수 있습니다. diff --git a/src/main/java/gg/agit/konect/domain/club/controller/ClubBasicController.java b/src/main/java/gg/agit/konect/domain/club/controller/ClubBasicController.java new file mode 100644 index 00000000..a52bd1cc --- /dev/null +++ b/src/main/java/gg/agit/konect/domain/club/controller/ClubBasicController.java @@ -0,0 +1,128 @@ +package gg.agit.konect.domain.club.controller; + +import org.springdoc.core.annotations.ParameterObject; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.ModelAttribute; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import gg.agit.konect.domain.club.dto.ClubAppliedClubsResponse; +import gg.agit.konect.domain.club.dto.ClubBasicInfoUpdateRequest; +import gg.agit.konect.domain.club.dto.ClubCondition; +import gg.agit.konect.domain.club.dto.ClubCreateRequest; +import gg.agit.konect.domain.club.dto.ClubDetailResponse; +import gg.agit.konect.domain.club.dto.ClubDetailUpdateRequest; +import gg.agit.konect.domain.club.dto.ClubMemberCondition; +import gg.agit.konect.domain.club.dto.ClubMembersResponse; +import gg.agit.konect.domain.club.dto.ClubMembershipsResponse; +import gg.agit.konect.domain.club.dto.ClubProfileUpdateRequest; +import gg.agit.konect.domain.club.dto.ClubsResponse; +import gg.agit.konect.domain.club.dto.MyManagedClubResponse; +import gg.agit.konect.domain.club.service.ClubService; +import gg.agit.konect.global.auth.annotation.UserId; +import jakarta.validation.Valid; +import lombok.RequiredArgsConstructor; + +@RestController +@RequiredArgsConstructor +@RequestMapping("/clubs") +public class ClubBasicController implements ClubBasicApi { + + private final ClubService clubService; + + @Override + public ResponseEntity getClubs( + @Valid @ParameterObject @ModelAttribute ClubCondition condition, + @UserId Integer userId + ) { + ClubsResponse response = clubService.getClubs(condition, userId); + return ResponseEntity.ok(response); + } + + @Override + public ResponseEntity getClubDetail( + @PathVariable(name = "clubId") Integer clubId, + @UserId Integer userId + ) { + ClubDetailResponse response = clubService.getClubDetail(clubId, userId); + return ResponseEntity.ok(response); + } + + @Override + public ResponseEntity createClub( + @Valid @RequestBody ClubCreateRequest request, + @UserId Integer userId + ) { + ClubDetailResponse response = clubService.createClub(userId, request); + return ResponseEntity.ok(response); + } + + @Override + public ResponseEntity updateProfile( + @PathVariable(name = "clubId") Integer clubId, + @Valid @RequestBody ClubProfileUpdateRequest request, + @UserId Integer userId + ) { + clubService.updateProfile(clubId, userId, request); + return ResponseEntity.noContent().build(); + } + + @Override + public ResponseEntity updateDetails( + @PathVariable(name = "clubId") Integer clubId, + @Valid @RequestBody ClubDetailUpdateRequest request, + @UserId Integer userId + ) { + clubService.updateDetails(clubId, userId, request); + return ResponseEntity.noContent().build(); + } + + @Override + public ResponseEntity updateBasicInfo( + @PathVariable(name = "clubId") Integer clubId, + @Valid @RequestBody ClubBasicInfoUpdateRequest request, + @UserId Integer userId + ) { + clubService.updateBasicInfo(clubId, userId, request); + return ResponseEntity.noContent().build(); + } + + @Override + public ResponseEntity getJoinedClubs(@UserId Integer userId) { + ClubMembershipsResponse response = clubService.getJoinedClubs(userId); + return ResponseEntity.ok(response); + } + + @Override + public ResponseEntity getManagedClubs(@UserId Integer userId) { + ClubMembershipsResponse response = clubService.getManagedClubs(userId); + return ResponseEntity.ok(response); + } + + @Override + public ResponseEntity getManagedClubDetail( + @PathVariable(name = "clubId") Integer clubId, + @UserId Integer userId + ) { + MyManagedClubResponse response = clubService.getManagedClubDetail(clubId, userId); + return ResponseEntity.ok(response); + } + + @Override + public ResponseEntity getAppliedClubs(@UserId Integer userId) { + ClubAppliedClubsResponse response = clubService.getAppliedClubs(userId); + return ResponseEntity.ok(response); + } + + @Override + public ResponseEntity getClubMembers( + @PathVariable(name = "clubId") Integer clubId, + @Valid @ParameterObject @ModelAttribute ClubMemberCondition condition, + @UserId Integer userId + ) { + ClubMembersResponse response = clubService.getClubMembers(clubId, userId, condition); + return ResponseEntity.ok(response); + } +} diff --git a/src/main/java/gg/agit/konect/domain/club/controller/ClubController.java b/src/main/java/gg/agit/konect/domain/club/controller/ClubController.java deleted file mode 100644 index a7c3089b..00000000 --- a/src/main/java/gg/agit/konect/domain/club/controller/ClubController.java +++ /dev/null @@ -1,372 +0,0 @@ -package gg.agit.konect.domain.club.controller; - -import org.springdoc.core.annotations.ParameterObject; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.ModelAttribute; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; - -import gg.agit.konect.domain.club.dto.ClubApplicationAnswersResponse; -import gg.agit.konect.domain.club.dto.ClubAppliedClubsResponse; -import gg.agit.konect.domain.club.dto.ClubApplicationsResponse; -import gg.agit.konect.domain.club.dto.ClubApplyQuestionsReplaceRequest; -import gg.agit.konect.domain.club.dto.ClubApplyQuestionsResponse; -import gg.agit.konect.domain.club.dto.ClubApplyRequest; -import gg.agit.konect.domain.club.dto.ClubBasicInfoUpdateRequest; -import gg.agit.konect.domain.club.dto.ClubCondition; -import gg.agit.konect.domain.club.dto.ClubCreateRequest; -import gg.agit.konect.domain.club.dto.ClubDetailResponse; -import gg.agit.konect.domain.club.dto.ClubDetailUpdateRequest; -import gg.agit.konect.domain.club.dto.ClubFeeInfoReplaceRequest; -import gg.agit.konect.domain.club.dto.ClubFeeInfoResponse; -import gg.agit.konect.domain.club.dto.ClubMemberAddRequest; -import gg.agit.konect.domain.club.dto.ClubMemberCondition; -import gg.agit.konect.domain.club.dto.ClubMembersResponse; -import gg.agit.konect.domain.club.dto.ClubMembershipsResponse; -import gg.agit.konect.domain.club.dto.MyManagedClubResponse; -import gg.agit.konect.domain.club.dto.ClubPositionCreateRequest; -import gg.agit.konect.domain.club.dto.ClubPositionUpdateRequest; -import gg.agit.konect.domain.club.dto.ClubPositionsResponse; -import gg.agit.konect.domain.club.dto.ClubProfileUpdateRequest; -import gg.agit.konect.domain.club.dto.ClubRecruitmentCreateRequest; -import gg.agit.konect.domain.club.dto.ClubRecruitmentResponse; -import gg.agit.konect.domain.club.dto.ClubRecruitmentUpdateRequest; -import gg.agit.konect.domain.club.dto.ClubsResponse; -import gg.agit.konect.domain.club.dto.MemberPositionChangeRequest; -import gg.agit.konect.domain.club.dto.PresidentTransferRequest; -import gg.agit.konect.domain.club.dto.VicePresidentChangeRequest; -import gg.agit.konect.domain.club.service.ClubMemberManagementService; -import gg.agit.konect.domain.club.service.ClubPositionService; -import gg.agit.konect.domain.club.service.ClubService; -import gg.agit.konect.global.auth.annotation.UserId; -import jakarta.validation.Valid; -import lombok.RequiredArgsConstructor; - -@RestController -@RequiredArgsConstructor -@RequestMapping("/clubs") -public class ClubController implements - ClubBasicApi, - ClubRecruitmentApi, - ClubApplicationApi, - ClubPositionApi, - ClubMemberApi { - - private final ClubService clubService; - private final ClubPositionService clubPositionService; - private final ClubMemberManagementService clubMemberManagementService; - - @Override - public ResponseEntity getClubs( - @Valid @ParameterObject @ModelAttribute ClubCondition condition, - @UserId Integer userId - ) { - ClubsResponse response = clubService.getClubs(condition, userId); - return ResponseEntity.ok(response); - } - - @Override - public ResponseEntity getClubDetail( - @PathVariable(name = "clubId") Integer clubId, - @UserId Integer userId - ) { - ClubDetailResponse response = clubService.getClubDetail(clubId, userId); - return ResponseEntity.ok(response); - } - - @Override - public ResponseEntity createClub( - @Valid @RequestBody ClubCreateRequest request, - @UserId Integer userId - ) { - ClubDetailResponse response = clubService.createClub(userId, request); - return ResponseEntity.ok(response); - } - - @Override - public ResponseEntity updateProfile( - @PathVariable(name = "clubId") Integer clubId, - @Valid @RequestBody ClubProfileUpdateRequest request, - @UserId Integer userId - ) { - clubService.updateProfile(clubId, userId, request); - return ResponseEntity.noContent().build(); - } - - @Override - public ResponseEntity updateDetails( - @PathVariable(name = "clubId") Integer clubId, - @Valid @RequestBody ClubDetailUpdateRequest request, - @UserId Integer userId - ) { - clubService.updateDetails(clubId, userId, request); - return ResponseEntity.noContent().build(); - } - - @Override - public ResponseEntity updateBasicInfo( - @PathVariable(name = "clubId") Integer clubId, - @Valid @RequestBody ClubBasicInfoUpdateRequest request, - @UserId Integer userId - ) { - clubService.updateBasicInfo(clubId, userId, request); - return ResponseEntity.noContent().build(); - } - - @Override - public ResponseEntity getJoinedClubs(@UserId Integer userId) { - ClubMembershipsResponse response = clubService.getJoinedClubs(userId); - return ResponseEntity.ok(response); - } - - @Override - public ResponseEntity getManagedClubs( - @UserId Integer userId - ) { - ClubMembershipsResponse response = clubService.getManagedClubs(userId); - return ResponseEntity.ok(response); - } - - @Override - public ResponseEntity getManagedClubDetail( - @PathVariable(name = "clubId") Integer clubId, - @UserId Integer userId - ) { - MyManagedClubResponse response = clubService.getManagedClubDetail(clubId, userId); - return ResponseEntity.ok(response); - } - - @Override - public ResponseEntity getAppliedClubs( - @UserId Integer userId - ) { - ClubAppliedClubsResponse response = clubService.getAppliedClubs(userId); - return ResponseEntity.ok(response); - } - - @Override - public ResponseEntity getClubApplications( - @PathVariable(name = "clubId") Integer clubId, - @UserId Integer userId - ) { - ClubApplicationsResponse response = clubService.getClubApplications(clubId, userId); - return ResponseEntity.ok(response); - } - - @Override - public ResponseEntity getClubApplicationAnswers( - @PathVariable(name = "clubId") Integer clubId, - @PathVariable(name = "applicationId") Integer applicationId, - @UserId Integer userId - ) { - ClubApplicationAnswersResponse response = clubService.getClubApplicationAnswers( - clubId, - applicationId, - userId - ); - - return ResponseEntity.ok(response); - } - - @Override - public ResponseEntity approveClubApplication( - @PathVariable(name = "clubId") Integer clubId, - @PathVariable(name = "applicationId") Integer applicationId, - @UserId Integer userId - ) { - clubService.approveClubApplication(clubId, applicationId, userId); - return ResponseEntity.ok().build(); - } - - @Override - public ResponseEntity rejectClubApplication( - @PathVariable(name = "clubId") Integer clubId, - @PathVariable(name = "applicationId") Integer applicationId, - @UserId Integer userId - ) { - clubService.rejectClubApplication(clubId, applicationId, userId); - return ResponseEntity.ok().build(); - } - - @Override - public ResponseEntity getClubMembers( - @PathVariable(name = "clubId") Integer clubId, - @Valid @ParameterObject @ModelAttribute ClubMemberCondition condition, - @UserId Integer userId - ) { - ClubMembersResponse response = clubService.getClubMembers(clubId, userId, condition); - return ResponseEntity.ok(response); - } - - @Override - public ResponseEntity applyClub( - @PathVariable(name = "clubId") Integer clubId, - @Valid @RequestBody ClubApplyRequest request, - @UserId Integer userId - ) { - ClubFeeInfoResponse response = clubService.applyClub(clubId, userId, request); - return ResponseEntity.ok(response); - } - - @Override - public ResponseEntity getFeeInfo( - @PathVariable(name = "clubId") Integer clubId, - @UserId Integer userId - ) { - ClubFeeInfoResponse response = clubService.getFeeInfo(clubId, userId); - return ResponseEntity.ok(response); - } - - @Override - public ResponseEntity replaceFeeInfo( - @PathVariable(name = "clubId") Integer clubId, - @Valid @RequestBody ClubFeeInfoReplaceRequest request, - @UserId Integer userId - ) { - ClubFeeInfoResponse response = clubService.replaceFeeInfo(clubId, userId, request); - return ResponseEntity.ok(response); - } - - @Override - public ResponseEntity getApplyQuestions( - @PathVariable(name = "clubId") Integer clubId, - @UserId Integer userId - ) { - ClubApplyQuestionsResponse response = clubService.getApplyQuestions(clubId, userId); - return ResponseEntity.ok(response); - } - - @Override - public ResponseEntity replaceApplyQuestions( - @PathVariable(name = "clubId") Integer clubId, - @Valid @RequestBody ClubApplyQuestionsReplaceRequest request, - @UserId Integer userId - ) { - ClubApplyQuestionsResponse response = clubService.replaceApplyQuestions(clubId, userId, request); - return ResponseEntity.ok(response); - } - - @Override - public ResponseEntity getRecruitments( - @PathVariable(name = "clubId") Integer clubId, - @UserId Integer userId - ) { - ClubRecruitmentResponse response = clubService.getRecruitment(clubId, userId); - return ResponseEntity.ok(response); - } - - @Override - public ResponseEntity createRecruitment( - @RequestBody @Valid ClubRecruitmentCreateRequest request, - @PathVariable(name = "clubId") Integer clubId, - @UserId Integer userId - ) { - clubService.createRecruitment(clubId, userId, request); - return ResponseEntity.ok().build(); - } - - @Override - public ResponseEntity updateRecruitment( - @Valid @RequestBody ClubRecruitmentUpdateRequest request, - @PathVariable(name = "clubId") Integer clubId, - @UserId Integer userId - ) { - clubService.updateRecruitment(clubId, userId, request); - return ResponseEntity.noContent().build(); - } - - @Override - public ResponseEntity getClubPositions( - @PathVariable(name = "clubId") Integer clubId, - @UserId Integer userId - ) { - ClubPositionsResponse response = clubPositionService.getClubPositions(clubId, userId); - return ResponseEntity.ok(response); - } - - @Override - public ResponseEntity createClubPosition( - @PathVariable(name = "clubId") Integer clubId, - @Valid @RequestBody ClubPositionCreateRequest request, - @UserId Integer userId - ) { - ClubPositionsResponse response = clubPositionService.createClubPosition(clubId, userId, request); - return ResponseEntity.ok(response); - } - - @Override - public ResponseEntity updateClubPositionName( - @PathVariable(name = "clubId") Integer clubId, - @PathVariable(name = "positionId") Integer positionId, - @Valid @RequestBody ClubPositionUpdateRequest request, - @UserId Integer userId - ) { - ClubPositionsResponse response = clubPositionService.updateClubPositionName( - clubId, positionId, userId, request - ); - return ResponseEntity.ok(response); - } - - @Override - public ResponseEntity deleteClubPosition( - @PathVariable(name = "clubId") Integer clubId, - @PathVariable(name = "positionId") Integer positionId, - @UserId Integer userId - ) { - clubPositionService.deleteClubPosition(clubId, positionId, userId); - return ResponseEntity.noContent().build(); - } - - @Override - public ResponseEntity changeMemberPosition( - @PathVariable(name = "clubId") Integer clubId, - @PathVariable(name = "memberId") Integer memberId, - @Valid @RequestBody MemberPositionChangeRequest request, - @UserId Integer userId - ) { - clubMemberManagementService.changeMemberPosition(clubId, memberId, userId, request); - return ResponseEntity.noContent().build(); - } - - @Override - public ResponseEntity transferPresident( - @PathVariable(name = "clubId") Integer clubId, - @Valid @RequestBody PresidentTransferRequest request, - @UserId Integer userId - ) { - clubMemberManagementService.transferPresident(clubId, userId, request); - return ResponseEntity.noContent().build(); - } - - @Override - public ResponseEntity changeVicePresident( - @PathVariable(name = "clubId") Integer clubId, - @Valid @RequestBody VicePresidentChangeRequest request, - @UserId Integer userId - ) { - clubMemberManagementService.changeVicePresident(clubId, userId, request); - return ResponseEntity.noContent().build(); - } - - @Override - public ResponseEntity addMember( - @PathVariable(name = "clubId") Integer clubId, - @Valid @RequestBody ClubMemberAddRequest request, - @UserId Integer userId - ) { - clubMemberManagementService.addMember(clubId, userId, request); - return ResponseEntity.ok().build(); - } - - @Override - public ResponseEntity removeMember( - @PathVariable(name = "clubId") Integer clubId, - @PathVariable(name = "memberId") Integer memberId, - @UserId Integer userId - ) { - clubMemberManagementService.removeMember(clubId, memberId, userId); - return ResponseEntity.noContent().build(); - } -} diff --git a/src/main/java/gg/agit/konect/domain/club/controller/ClubMemberApi.java b/src/main/java/gg/agit/konect/domain/club/controller/ClubMemberApi.java index d6d58f08..eab747b3 100644 --- a/src/main/java/gg/agit/konect/domain/club/controller/ClubMemberApi.java +++ b/src/main/java/gg/agit/konect/domain/club/controller/ClubMemberApi.java @@ -14,14 +14,14 @@ import gg.agit.konect.domain.club.dto.VicePresidentChangeRequest; import gg.agit.konect.global.auth.annotation.UserId; import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.validation.Valid; +@Tag(name = "(Normal) Club - Member: 회원 관리") @RequestMapping("/clubs") public interface ClubMemberApi { - String TAG = "(Normal) Club - Member: 회원 관리"; - - @Operation(summary = "동아리 회원의 직책을 변경한다.", tags = TAG, description = """ + @Operation(summary = "동아리 회원의 직책을 변경한다.", description = """ 동아리 회장 또는 부회장만 회원의 직책을 변경할 수 있습니다. 자기 자신의 직책은 변경할 수 없으며, 상위 직급만 하위 직급의 회원을 관리할 수 있습니다. @@ -43,7 +43,7 @@ ResponseEntity changeMemberPosition( @UserId Integer userId ); - @Operation(summary = "동아리 회장 권한을 위임한다.", tags = TAG, description = """ + @Operation(summary = "동아리 회장 권한을 위임한다.", description = """ 현재 회장만 회장 권한을 다른 회원에게 위임할 수 있습니다. 회장 위임 시 현재 회장은 일반회원으로 강등됩니다. @@ -62,7 +62,7 @@ ResponseEntity transferPresident( @UserId Integer userId ); - @Operation(summary = "동아리 부회장을 변경한다.", tags = TAG, description = """ + @Operation(summary = "동아리 부회장을 변경한다.", description = """ 동아리 회장만 부회장을 임명하거나 해제할 수 있습니다. vicePresidentUserId가 null이면 부회장을 해제하고, 값이 있으면 해당 회원을 부회장으로 임명합니다. @@ -80,7 +80,7 @@ ResponseEntity changeVicePresident( @UserId Integer userId ); - @Operation(summary = "동아리에 회원을 직접 추가한다.", tags = TAG, description = """ + @Operation(summary = "동아리에 회원을 직접 추가한다.", description = """ 동아리 회장 또는 부회장만 회원을 직접 추가할 수 있습니다. 회장 직책으로는 추가할 수 없으며, 부회장과 운영진은 인원 제한이 있습니다. @@ -100,7 +100,7 @@ ResponseEntity addMember( @UserId Integer userId ); - @Operation(summary = "동아리 회원을 강제 탈퇴시킨다.", tags = TAG, description = """ + @Operation(summary = "동아리 회원을 강제 탈퇴시킨다.", description = """ 동아리 회장 또는 부회장만 회원을 강제 탈퇴시킬 수 있습니다. 일반회원만 강제 탈퇴 가능하며, 부회장이나 운영진은 먼저 직책을 변경한 후 탈퇴시켜야 합니다. diff --git a/src/main/java/gg/agit/konect/domain/club/controller/ClubMemberController.java b/src/main/java/gg/agit/konect/domain/club/controller/ClubMemberController.java new file mode 100644 index 00000000..7fb81403 --- /dev/null +++ b/src/main/java/gg/agit/konect/domain/club/controller/ClubMemberController.java @@ -0,0 +1,75 @@ +package gg.agit.konect.domain.club.controller; + +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import gg.agit.konect.domain.club.dto.ClubMemberAddRequest; +import gg.agit.konect.domain.club.dto.MemberPositionChangeRequest; +import gg.agit.konect.domain.club.dto.PresidentTransferRequest; +import gg.agit.konect.domain.club.dto.VicePresidentChangeRequest; +import gg.agit.konect.domain.club.service.ClubMemberManagementService; +import gg.agit.konect.global.auth.annotation.UserId; +import jakarta.validation.Valid; +import lombok.RequiredArgsConstructor; + +@RestController +@RequiredArgsConstructor +@RequestMapping("/clubs") +public class ClubMemberController implements ClubMemberApi { + + private final ClubMemberManagementService clubMemberManagementService; + + @Override + public ResponseEntity changeMemberPosition( + @PathVariable(name = "clubId") Integer clubId, + @PathVariable(name = "memberId") Integer memberId, + @Valid @RequestBody MemberPositionChangeRequest request, + @UserId Integer userId + ) { + clubMemberManagementService.changeMemberPosition(clubId, memberId, userId, request); + return ResponseEntity.noContent().build(); + } + + @Override + public ResponseEntity transferPresident( + @PathVariable(name = "clubId") Integer clubId, + @Valid @RequestBody PresidentTransferRequest request, + @UserId Integer userId + ) { + clubMemberManagementService.transferPresident(clubId, userId, request); + return ResponseEntity.noContent().build(); + } + + @Override + public ResponseEntity changeVicePresident( + @PathVariable(name = "clubId") Integer clubId, + @Valid @RequestBody VicePresidentChangeRequest request, + @UserId Integer userId + ) { + clubMemberManagementService.changeVicePresident(clubId, userId, request); + return ResponseEntity.noContent().build(); + } + + @Override + public ResponseEntity addMember( + @PathVariable(name = "clubId") Integer clubId, + @Valid @RequestBody ClubMemberAddRequest request, + @UserId Integer userId + ) { + clubMemberManagementService.addMember(clubId, userId, request); + return ResponseEntity.ok().build(); + } + + @Override + public ResponseEntity removeMember( + @PathVariable(name = "clubId") Integer clubId, + @PathVariable(name = "memberId") Integer memberId, + @UserId Integer userId + ) { + clubMemberManagementService.removeMember(clubId, memberId, userId); + return ResponseEntity.noContent().build(); + } +} diff --git a/src/main/java/gg/agit/konect/domain/club/controller/ClubPositionApi.java b/src/main/java/gg/agit/konect/domain/club/controller/ClubPositionApi.java index c1194495..c2b85842 100644 --- a/src/main/java/gg/agit/konect/domain/club/controller/ClubPositionApi.java +++ b/src/main/java/gg/agit/konect/domain/club/controller/ClubPositionApi.java @@ -14,14 +14,14 @@ import gg.agit.konect.domain.club.dto.ClubPositionsResponse; import gg.agit.konect.global.auth.annotation.UserId; import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.validation.Valid; +@Tag(name = "(Normal) Club - Position: 직책 관리") @RequestMapping("/clubs") public interface ClubPositionApi { - String TAG = "(Normal) Club - Position: 직책 관리"; - - @Operation(summary = "동아리 직책 목록을 조회한다.", tags = TAG, description = """ + @Operation(summary = "동아리 직책 목록을 조회한다.", description = """ 동아리의 모든 직책을 우선순위 순으로 조회합니다. 각 직책의 회원 수, 수정/삭제 가능 여부도 함께 반환됩니다. @@ -34,7 +34,7 @@ ResponseEntity getClubPositions( @UserId Integer userId ); - @Operation(summary = "동아리 직책을 생성한다.", tags = TAG, description = """ + @Operation(summary = "동아리 직책을 생성한다.", description = """ 동아리 회장 또는 부회장만 직책을 생성할 수 있습니다. PRESIDENT와 VICE_PRESIDENT 직책은 생성할 수 없으며, MANAGER 또는 MEMBER 그룹의 직책만 생성 가능합니다. @@ -50,7 +50,7 @@ ResponseEntity createClubPosition( @UserId Integer userId ); - @Operation(summary = "동아리 직책의 이름을 수정한다.", tags = TAG, description = """ + @Operation(summary = "동아리 직책의 이름을 수정한다.", description = """ 동아리 회장 또는 부회장만 직책 이름을 수정할 수 있습니다. PRESIDENT와 VICE_PRESIDENT 직책의 이름은 변경할 수 없습니다. @@ -69,7 +69,7 @@ ResponseEntity updateClubPositionName( @UserId Integer userId ); - @Operation(summary = "동아리 직책을 삭제한다.", tags = TAG, description = """ + @Operation(summary = "동아리 직책을 삭제한다.", description = """ 동아리 회장 또는 부회장만 직책을 삭제할 수 있습니다. PRESIDENT와 VICE_PRESIDENT 직책은 삭제할 수 없습니다. 해당 직책을 사용 중인 회원이 없어야 하며, 해당 그룹에 최소 2개의 직책이 있어야 삭제 가능합니다. diff --git a/src/main/java/gg/agit/konect/domain/club/controller/ClubPositionController.java b/src/main/java/gg/agit/konect/domain/club/controller/ClubPositionController.java new file mode 100644 index 00000000..e11aea46 --- /dev/null +++ b/src/main/java/gg/agit/konect/domain/club/controller/ClubPositionController.java @@ -0,0 +1,65 @@ +package gg.agit.konect.domain.club.controller; + +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import gg.agit.konect.domain.club.dto.ClubPositionCreateRequest; +import gg.agit.konect.domain.club.dto.ClubPositionUpdateRequest; +import gg.agit.konect.domain.club.dto.ClubPositionsResponse; +import gg.agit.konect.domain.club.service.ClubPositionService; +import gg.agit.konect.global.auth.annotation.UserId; +import jakarta.validation.Valid; +import lombok.RequiredArgsConstructor; + +@RestController +@RequiredArgsConstructor +@RequestMapping("/clubs") +public class ClubPositionController implements ClubPositionApi { + + private final ClubPositionService clubPositionService; + + @Override + public ResponseEntity getClubPositions( + @PathVariable(name = "clubId") Integer clubId, + @UserId Integer userId + ) { + ClubPositionsResponse response = clubPositionService.getClubPositions(clubId, userId); + return ResponseEntity.ok(response); + } + + @Override + public ResponseEntity createClubPosition( + @PathVariable(name = "clubId") Integer clubId, + @Valid @RequestBody ClubPositionCreateRequest request, + @UserId Integer userId + ) { + ClubPositionsResponse response = clubPositionService.createClubPosition(clubId, userId, request); + return ResponseEntity.ok(response); + } + + @Override + public ResponseEntity updateClubPositionName( + @PathVariable(name = "clubId") Integer clubId, + @PathVariable(name = "positionId") Integer positionId, + @Valid @RequestBody ClubPositionUpdateRequest request, + @UserId Integer userId + ) { + ClubPositionsResponse response = clubPositionService.updateClubPositionName( + clubId, positionId, userId, request + ); + return ResponseEntity.ok(response); + } + + @Override + public ResponseEntity deleteClubPosition( + @PathVariable(name = "clubId") Integer clubId, + @PathVariable(name = "positionId") Integer positionId, + @UserId Integer userId + ) { + clubPositionService.deleteClubPosition(clubId, positionId, userId); + return ResponseEntity.noContent().build(); + } +} diff --git a/src/main/java/gg/agit/konect/domain/club/controller/ClubRecruitmentApi.java b/src/main/java/gg/agit/konect/domain/club/controller/ClubRecruitmentApi.java index 15c15ac9..e6f1725f 100644 --- a/src/main/java/gg/agit/konect/domain/club/controller/ClubRecruitmentApi.java +++ b/src/main/java/gg/agit/konect/domain/club/controller/ClubRecruitmentApi.java @@ -13,14 +13,14 @@ import gg.agit.konect.domain.club.dto.ClubRecruitmentUpdateRequest; import gg.agit.konect.global.auth.annotation.UserId; import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.validation.Valid; +@Tag(name = "(Normal) Club - Recruitment: 모집 공고") @RequestMapping("/clubs") public interface ClubRecruitmentApi { - String TAG = "(Normal) Club - Recruitment: 모집 공고"; - - @Operation(summary = "동아리 모집 정보를 조회한다.", tags = TAG, description = """ + @Operation(summary = "동아리 모집 정보를 조회한다.", description = """ 동아리의 모집 공고 상세 정보를 조회합니다. - status는 모집 기간에 따라 BEFORE(모집 전), ONGOING(모집 중), CLOSED(모집 마감)으로 반환됩니다. @@ -37,7 +37,7 @@ ResponseEntity getRecruitments( @UserId Integer userId ); - @Operation(summary = "동아리 모집 정보를 생성한다.", tags = TAG, description = """ + @Operation(summary = "동아리 모집 정보를 생성한다.", description = """ 동아리 회장만 모집 공고를 생성할 수 있습니다. 한 동아리당 하나의 모집 공고만 생성 가능합니다. @@ -57,7 +57,7 @@ ResponseEntity createRecruitment( @UserId Integer userId ); - @Operation(summary = "동아리 모집 정보를 수정한다.", tags = TAG, description = """ + @Operation(summary = "동아리 모집 정보를 수정한다.", description = """ 동아리 회장 또는 부회장만 모집 공고를 수정할 수 있습니다. ## 에러 diff --git a/src/main/java/gg/agit/konect/domain/club/controller/ClubRecruitmentController.java b/src/main/java/gg/agit/konect/domain/club/controller/ClubRecruitmentController.java new file mode 100644 index 00000000..75563ddf --- /dev/null +++ b/src/main/java/gg/agit/konect/domain/club/controller/ClubRecruitmentController.java @@ -0,0 +1,52 @@ +package gg.agit.konect.domain.club.controller; + +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import gg.agit.konect.domain.club.dto.ClubRecruitmentCreateRequest; +import gg.agit.konect.domain.club.dto.ClubRecruitmentResponse; +import gg.agit.konect.domain.club.dto.ClubRecruitmentUpdateRequest; +import gg.agit.konect.domain.club.service.ClubService; +import gg.agit.konect.global.auth.annotation.UserId; +import jakarta.validation.Valid; +import lombok.RequiredArgsConstructor; + +@RestController +@RequiredArgsConstructor +@RequestMapping("/clubs") +public class ClubRecruitmentController implements ClubRecruitmentApi { + + private final ClubService clubService; + + @Override + public ResponseEntity getRecruitments( + @PathVariable(name = "clubId") Integer clubId, + @UserId Integer userId + ) { + ClubRecruitmentResponse response = clubService.getRecruitment(clubId, userId); + return ResponseEntity.ok(response); + } + + @Override + public ResponseEntity createRecruitment( + @RequestBody @Valid ClubRecruitmentCreateRequest request, + @PathVariable(name = "clubId") Integer clubId, + @UserId Integer userId + ) { + clubService.createRecruitment(clubId, userId, request); + return ResponseEntity.ok().build(); + } + + @Override + public ResponseEntity updateRecruitment( + @Valid @RequestBody ClubRecruitmentUpdateRequest request, + @PathVariable(name = "clubId") Integer clubId, + @UserId Integer userId + ) { + clubService.updateRecruitment(clubId, userId, request); + return ResponseEntity.noContent().build(); + } +}