diff --git a/build.gradle b/build.gradle index 21cbfd6..667a4d3 100644 --- a/build.gradle +++ b/build.gradle @@ -1,64 +1,62 @@ plugins { - id 'java' - id 'org.springframework.boot' version '3.2.5' - id 'io.spring.dependency-management' version '1.1.4' + id 'java' + id 'org.springframework.boot' version '3.2.5' + id 'io.spring.dependency-management' version '1.1.4' } group = 'com.example' version = '0.0.1-SNAPSHOT' java { - sourceCompatibility = '17' + sourceCompatibility = '17' } configurations { - compileOnly { - extendsFrom annotationProcessor - } + compileOnly { + extendsFrom annotationProcessor + } } repositories { - mavenCentral() + mavenCentral() } dependencies { - implementation 'io.jsonwebtoken:jjwt-api:0.12.5' - implementation 'io.jsonwebtoken:jjwt-impl:0.12.5' - implementation 'io.jsonwebtoken:jjwt-jackson:0.12.5' - implementation 'org.springframework.boot:spring-boot-starter-oauth2-client' - implementation 'org.springframework.boot:spring-boot-starter-data-jpa' - - implementation 'org.springframework.boot:spring-boot-starter-mustache' - implementation 'org.springframework.boot:spring-boot-starter-security' - implementation 'org.springframework.boot:spring-boot-starter-thymeleaf' - implementation 'org.springframework.boot:spring-boot-starter-web' - implementation 'org.thymeleaf.extras:thymeleaf-extras-springsecurity6' - implementation 'org.springframework.boot:spring-boot-starter-validation' - implementation 'org.springframework.boot:spring-boot-starter-mail' - implementation 'org.springframework.boot:spring-boot-starter-data-redis' - implementation 'org.springframework.cloud:spring-cloud-starter-aws:2.2.6.RELEASE' - implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.2.0' - - //Querydsl 추가 - implementation 'com.querydsl:querydsl-jpa:5.0.0:jakarta' - annotationProcessor "com.querydsl:querydsl-apt:${dependencyManagement.importedProperties['querydsl.version']}:jakarta" - annotationProcessor "jakarta.annotation:jakarta.annotation-api" - annotationProcessor "jakarta.persistence:jakarta.persistence-api" - - compileOnly 'org.projectlombok:lombok' - runtimeOnly 'com.mysql:mysql-connector-j' - annotationProcessor 'org.projectlombok:lombok' - testImplementation 'org.springframework.boot:spring-boot-starter-test' - testImplementation 'org.springframework.security:spring-security-test' + implementation 'io.jsonwebtoken:jjwt-api:0.12.5' + implementation 'io.jsonwebtoken:jjwt-impl:0.12.5' + implementation 'io.jsonwebtoken:jjwt-jackson:0.12.5' + implementation 'org.springframework.boot:spring-boot-starter-oauth2-client' + implementation 'org.springframework.boot:spring-boot-starter-data-jpa' + + implementation 'org.springframework.boot:spring-boot-starter-security' + implementation 'org.springframework.boot:spring-boot-starter-web' + implementation 'org.thymeleaf.extras:thymeleaf-extras-springsecurity6' + implementation 'org.springframework.boot:spring-boot-starter-validation' + implementation 'org.springframework.boot:spring-boot-starter-mail' + implementation 'org.springframework.boot:spring-boot-starter-data-redis' + implementation 'org.springframework.cloud:spring-cloud-starter-aws:2.2.6.RELEASE' + implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.2.0' + + //Querydsl 추가 + implementation 'com.querydsl:querydsl-jpa:5.0.0:jakarta' + annotationProcessor "com.querydsl:querydsl-apt:${dependencyManagement.importedProperties['querydsl.version']}:jakarta" + annotationProcessor "jakarta.annotation:jakarta.annotation-api" + annotationProcessor "jakarta.persistence:jakarta.persistence-api" + + compileOnly 'org.projectlombok:lombok' + runtimeOnly 'com.mysql:mysql-connector-j' + annotationProcessor 'org.projectlombok:lombok' + testImplementation 'org.springframework.boot:spring-boot-starter-test' + testImplementation 'org.springframework.security:spring-security-test' } tasks.named('bootBuildImage') { - builder = 'paketobuildpacks/builder-jammy-base:latest' + builder = 'paketobuildpacks/builder-jammy-base:latest' } tasks.named('test') { - useJUnitPlatform() + useJUnitPlatform() } \ No newline at end of file diff --git a/src/main/java/com/cotato/squadus/api/admin/controller/AdminController.java b/src/main/java/com/cotato/squadus/api/admin/controller/AdminController.java index 6f2760b..4bd531e 100644 --- a/src/main/java/com/cotato/squadus/api/admin/controller/AdminController.java +++ b/src/main/java/com/cotato/squadus/api/admin/controller/AdminController.java @@ -8,9 +8,9 @@ @ResponseBody public class AdminController { - @GetMapping("/admin") - public String adminP() { + @GetMapping("/admin") + public String adminP() { - return "admin Controller"; - } + return "admin Controller"; + } } \ No newline at end of file diff --git a/src/main/java/com/cotato/squadus/api/admin/controller/ClubAdminController.java b/src/main/java/com/cotato/squadus/api/admin/controller/ClubAdminController.java index bc22031..5037cf7 100644 --- a/src/main/java/com/cotato/squadus/api/admin/controller/ClubAdminController.java +++ b/src/main/java/com/cotato/squadus/api/admin/controller/ClubAdminController.java @@ -1,14 +1,20 @@ package com.cotato.squadus.api.admin.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.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + import com.cotato.squadus.api.admin.dto.ClubApplicationListResponse; import com.cotato.squadus.api.admin.dto.ClubJoinApprovalResponse; import com.cotato.squadus.api.admin.dto.ClubJoinDenialResponse; import com.cotato.squadus.domain.club.admin.service.ClubAdminService; + import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; import lombok.RequiredArgsConstructor; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.*; @Tag(name = "동아리 관리", description = "동아리 관리 관련 API") @RestController @@ -16,26 +22,30 @@ @RequiredArgsConstructor public class ClubAdminController { - private final ClubAdminService clubAdminService; - - @PostMapping("/approval/{applicationId}") - @Operation(summary = "동아리 가입 신청 승인", description = "ADMIN 회원인지 검증 후 applicationId를 통해 가입을 승인합니다") - public ResponseEntity approveClubMember(@PathVariable Long clubId, @PathVariable Long applicationId) { - ClubJoinApprovalResponse clubJoinApprovalResponse = clubAdminService.approveApply(clubId, applicationId); - return ResponseEntity.ok(clubJoinApprovalResponse); - } - - @PostMapping("/denial/{applicationId}") - @Operation(summary = "동아리 가입 신청 거절", description = "applicationId를 통해 가입을 거절합니다.") - public ResponseEntity denyClubMember(@PathVariable Long clubId, @PathVariable Long applicationId) { - ClubJoinDenialResponse clubJoinDenialResponse = clubAdminService.denyApply(clubId, applicationId); - return ResponseEntity.ok(clubJoinDenialResponse); - } - - @GetMapping("/applications/{recruitingPostId}") - @Operation(summary = "동아리 가입 신청 내역 조회", description = "clubId를 통해 해당 동아리의 가입 신청 내역을 조회합니다.") - public ResponseEntity findAllClubApplyByRecruitingPostId(@PathVariable Long clubId, @PathVariable Long recruitingPostId) { - ClubApplicationListResponse allClubApplyByRecruitingPostId = clubAdminService.findAllClubApplyByRecruitingPostId(clubId, recruitingPostId); - return ResponseEntity.ok(allClubApplyByRecruitingPostId); - } + private final ClubAdminService clubAdminService; + + @PostMapping("/approval/{applicationId}") + @Operation(summary = "동아리 가입 신청 승인", description = "ADMIN 회원인지 검증 후 applicationId를 통해 가입을 승인합니다") + public ResponseEntity approveClubMember(@PathVariable Long clubId, + @PathVariable Long applicationId) { + ClubJoinApprovalResponse clubJoinApprovalResponse = clubAdminService.approveApply(clubId, applicationId); + return ResponseEntity.ok(clubJoinApprovalResponse); + } + + @PostMapping("/denial/{applicationId}") + @Operation(summary = "동아리 가입 신청 거절", description = "applicationId를 통해 가입을 거절합니다.") + public ResponseEntity denyClubMember(@PathVariable Long clubId, + @PathVariable Long applicationId) { + ClubJoinDenialResponse clubJoinDenialResponse = clubAdminService.denyApply(clubId, applicationId); + return ResponseEntity.ok(clubJoinDenialResponse); + } + + @GetMapping("/applications/{recruitingPostId}") + @Operation(summary = "동아리 가입 신청 내역 조회", description = "clubId를 통해 해당 동아리의 가입 신청 내역을 조회합니다.") + public ResponseEntity findAllClubApplyByRecruitingPostId(@PathVariable Long clubId, + @PathVariable Long recruitingPostId) { + ClubApplicationListResponse allClubApplyByRecruitingPostId = clubAdminService.findAllClubApplyByRecruitingPostId( + clubId, recruitingPostId); + return ResponseEntity.ok(allClubApplyByRecruitingPostId); + } } diff --git a/src/main/java/com/cotato/squadus/api/admin/dto/ArticleDto.java b/src/main/java/com/cotato/squadus/api/admin/dto/ArticleDto.java index 1b9c185..6ae077f 100644 --- a/src/main/java/com/cotato/squadus/api/admin/dto/ArticleDto.java +++ b/src/main/java/com/cotato/squadus/api/admin/dto/ArticleDto.java @@ -1,30 +1,31 @@ package com.cotato.squadus.api.admin.dto; +import java.time.LocalDateTime; + import lombok.Builder; import lombok.Getter; import lombok.Setter; -import java.time.LocalDateTime; - @Getter @Setter public class ArticleDto { - private String title; - private String subtitle; - private String type; - private LocalDateTime createdAt; - private String tag; - private String content; - private Long views; + private String title; + private String subtitle; + private String type; + private LocalDateTime createdAt; + private String tag; + private String content; + private Long views; - @Builder - public ArticleDto(String title, String subtitle, String type, LocalDateTime createdAt, String tag, String content, Long views) { - this.title = title; - this.subtitle = subtitle; - this.type = type; - this.tag = tag; - this.content = content; - this.views = views; - } + @Builder + public ArticleDto(String title, String subtitle, String type, LocalDateTime createdAt, String tag, String content, + Long views) { + this.title = title; + this.subtitle = subtitle; + this.type = type; + this.tag = tag; + this.content = content; + this.views = views; + } } diff --git a/src/main/java/com/cotato/squadus/api/admin/dto/ClubApplicationInfoResponse.java b/src/main/java/com/cotato/squadus/api/admin/dto/ClubApplicationInfoResponse.java index 2d418ef..edf66d5 100644 --- a/src/main/java/com/cotato/squadus/api/admin/dto/ClubApplicationInfoResponse.java +++ b/src/main/java/com/cotato/squadus/api/admin/dto/ClubApplicationInfoResponse.java @@ -3,15 +3,15 @@ import com.cotato.squadus.domain.club.common.entity.ClubApplication; public record ClubApplicationInfoResponse( - Long applicationId, - Long recruitingPostId, - MemberClubApplicationInfo memberClubApplicationInfo + Long applicationId, + Long recruitingPostId, + MemberClubApplicationInfo memberClubApplicationInfo ) { - public static ClubApplicationInfoResponse from(ClubApplication clubApplication) { - return new ClubApplicationInfoResponse( - clubApplication.getApplicationIdx(), - clubApplication.getRecruitingPost().getPostId(), - MemberClubApplicationInfo.from(clubApplication) - ); - } + public static ClubApplicationInfoResponse from(ClubApplication clubApplication) { + return new ClubApplicationInfoResponse( + clubApplication.getApplicationIdx(), + clubApplication.getRecruitingPost().getPostId(), + MemberClubApplicationInfo.from(clubApplication) + ); + } } diff --git a/src/main/java/com/cotato/squadus/api/admin/dto/ClubApplicationListResponse.java b/src/main/java/com/cotato/squadus/api/admin/dto/ClubApplicationListResponse.java index 1e0d636..52efc18 100644 --- a/src/main/java/com/cotato/squadus/api/admin/dto/ClubApplicationListResponse.java +++ b/src/main/java/com/cotato/squadus/api/admin/dto/ClubApplicationListResponse.java @@ -3,9 +3,9 @@ import java.util.List; public record ClubApplicationListResponse( - List clubApplicationInfoResponseList + List clubApplicationInfoResponseList ) { - public static ClubApplicationListResponse from(List clubApplicationInfoResponseList) { - return new ClubApplicationListResponse(clubApplicationInfoResponseList); - } + public static ClubApplicationListResponse from(List clubApplicationInfoResponseList) { + return new ClubApplicationListResponse(clubApplicationInfoResponseList); + } } diff --git a/src/main/java/com/cotato/squadus/api/admin/dto/ClubJoinApprovalResponse.java b/src/main/java/com/cotato/squadus/api/admin/dto/ClubJoinApprovalResponse.java index 060426f..d3131c0 100644 --- a/src/main/java/com/cotato/squadus/api/admin/dto/ClubJoinApprovalResponse.java +++ b/src/main/java/com/cotato/squadus/api/admin/dto/ClubJoinApprovalResponse.java @@ -1,6 +1,6 @@ package com.cotato.squadus.api.admin.dto; public record ClubJoinApprovalResponse( - Long clubMemberId + Long clubMemberId ) { } diff --git a/src/main/java/com/cotato/squadus/api/admin/dto/ClubJoinDenialResponse.java b/src/main/java/com/cotato/squadus/api/admin/dto/ClubJoinDenialResponse.java index d5d883d..de800b1 100644 --- a/src/main/java/com/cotato/squadus/api/admin/dto/ClubJoinDenialResponse.java +++ b/src/main/java/com/cotato/squadus/api/admin/dto/ClubJoinDenialResponse.java @@ -1,7 +1,7 @@ package com.cotato.squadus.api.admin.dto; public record ClubJoinDenialResponse( - Long applicationId + Long applicationId ) { } diff --git a/src/main/java/com/cotato/squadus/api/admin/dto/MemberClubApplicationInfo.java b/src/main/java/com/cotato/squadus/api/admin/dto/MemberClubApplicationInfo.java index 3c22603..d6f8d30 100644 --- a/src/main/java/com/cotato/squadus/api/admin/dto/MemberClubApplicationInfo.java +++ b/src/main/java/com/cotato/squadus/api/admin/dto/MemberClubApplicationInfo.java @@ -3,16 +3,16 @@ import com.cotato.squadus.domain.club.common.entity.ClubApplication; public record MemberClubApplicationInfo( - Long memberIdx, - String username, - String university + Long memberIdx, + String username, + String university ) { - public static MemberClubApplicationInfo from(ClubApplication clubApplication) { - return new MemberClubApplicationInfo( - clubApplication.getMember().getMemberIdx(), - clubApplication.getMember().getUsername(), - clubApplication.getMember().getUniversity() - ); - } + public static MemberClubApplicationInfo from(ClubApplication clubApplication) { + return new MemberClubApplicationInfo( + clubApplication.getMember().getMemberIdx(), + clubApplication.getMember().getUsername(), + clubApplication.getMember().getUniversity() + ); + } } diff --git a/src/main/java/com/cotato/squadus/api/article/controller/ArticleController.java b/src/main/java/com/cotato/squadus/api/article/controller/ArticleController.java index 5443431..837c708 100644 --- a/src/main/java/com/cotato/squadus/api/article/controller/ArticleController.java +++ b/src/main/java/com/cotato/squadus/api/article/controller/ArticleController.java @@ -1,25 +1,35 @@ package com.cotato.squadus.api.article.controller; -import com.cotato.squadus.api.article.dto.*; -import com.cotato.squadus.api.post.dto.ClubPostCreateRequest; -import com.cotato.squadus.domain.club.article.service.ArticleService; -import io.swagger.v3.oas.annotations.Operation; -import io.swagger.v3.oas.annotations.Parameter; -import io.swagger.v3.oas.annotations.media.Schema; -import io.swagger.v3.oas.annotations.tags.Tag; -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; +import java.util.List; + import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.data.web.PageableDefault; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.*; +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.RequestMapping; +import org.springframework.web.bind.annotation.RequestPart; +import org.springframework.web.bind.annotation.RestController; import org.springframework.web.multipart.MultipartFile; -import java.util.List; +import com.cotato.squadus.api.article.dto.ArticleListResponse; +import com.cotato.squadus.api.article.dto.ArticleRequest; +import com.cotato.squadus.api.article.dto.ArticleResponse; +import com.cotato.squadus.api.article.dto.ArticleResponseListWrapper; +import com.cotato.squadus.api.article.dto.ArticleSummaryResponse; +import com.cotato.squadus.domain.club.article.service.ArticleService; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; @Tag(name = "아티클", description = "아티클 관련 API") @Slf4j @@ -28,62 +38,60 @@ @RequiredArgsConstructor public class ArticleController { - private final ArticleService articleService; - - @GetMapping("/{articleId}") - @Operation(summary = "아티클 단건 조회", description = "articleId를 바탕으로 아티클 하나에 대한 정보를 조회합니다") - public ResponseEntity getArticleById(@PathVariable Long articleId) { - ArticleResponse article = articleService.findArticleById(articleId); - log.info("ArticleId로 기사 조회 : {} ", article); - return ResponseEntity.ok(article); - } - - @PostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE, produces = MediaType.APPLICATION_JSON_VALUE) - @Operation(summary = "아티클 단건 생성", description = "article에 대한 정보를 바탕으로 아티클 하나를 생성합니다") - public ResponseEntity createArticle( - @Parameter(description = "아티클 생성 정보", schema = @Schema(implementation = ArticleRequest.class)) - @RequestPart("articleRequest") String articleRequestString, - @Parameter(description = "multipart/form-data 형식의 이미지를 input으로 받습니다. 이때 key 값은 image입니다.") - @RequestPart(value = "image", required = false) MultipartFile imageFile) { - // JSON String을 객체로 변환 - ObjectMapper objectMapper = new ObjectMapper(); - ArticleRequest articleRequest; - try { - articleRequest = objectMapper.readValue(articleRequestString, ArticleRequest.class); - } catch (JsonProcessingException e) { - throw new RuntimeException("Invalid JSON format", e); - } + private final ArticleService articleService; - ArticleResponse article = articleService.createArticle(articleRequest, imageFile); - log.info("새 기사 생성 : {} ", article); - return ResponseEntity.ok(article); - } + @GetMapping("/{articleId}") + @Operation(summary = "아티클 단건 조회", description = "articleId를 바탕으로 아티클 하나에 대한 정보를 조회합니다") + public ResponseEntity getArticleById(@PathVariable Long articleId) { + ArticleResponse article = articleService.findArticleById(articleId); + log.info("ArticleId로 기사 조회 : {} ", article); + return ResponseEntity.ok(article); + } - @GetMapping - @Operation(summary = "아티클 요약 전체 조회(페이징 단위: 10)", description = "article에 대한 정보를 10개 단위로 페이징 하여 조회합니다.") - public ResponseEntity> getAllArticleSummaries( - @PageableDefault(size = 10) Pageable pageable) { - Page articles = articleService.findAllArticleSummaries(pageable); - log.info("모든 기사 요약 조회, 페이지 정보 : {} ", pageable); - return ResponseEntity.ok(articles); - } + @PostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE, produces = MediaType.APPLICATION_JSON_VALUE) + @Operation(summary = "아티클 단건 생성", description = "article에 대한 정보를 바탕으로 아티클 하나를 생성합니다") + public ResponseEntity createArticle( + @Parameter(description = "아티클 생성 정보", schema = @Schema(implementation = ArticleRequest.class)) + @RequestPart("articleRequest") String articleRequestString, + @Parameter(description = "multipart/form-data 형식의 이미지를 input으로 받습니다. 이때 key 값은 image입니다.") + @RequestPart(value = "image", required = false) MultipartFile imageFile) { + // JSON String을 객체로 변환 + ObjectMapper objectMapper = new ObjectMapper(); + ArticleRequest articleRequest; + try { + articleRequest = objectMapper.readValue(articleRequestString, ArticleRequest.class); + } catch (JsonProcessingException e) { + throw new RuntimeException("Invalid JSON format", e); + } - @GetMapping("/all") - @Operation(summary = "아티클 요약 전체 조회(페이징 없음)", description = "모든 아티클을 조회합니다.") - public ResponseEntity getAllArticles() { - List articles = articleService.getAllArticles(); - log.info("모든 기사 요약 조회"); - return ResponseEntity.ok(ArticleListResponse.from(articles)); - } + ArticleResponse article = articleService.createArticle(articleRequest, imageFile); + log.info("새 기사 생성 : {} ", article); + return ResponseEntity.ok(article); + } - @GetMapping("/allData") - @Operation(summary = "아티클 요약x 전체 조회(페이징 없음)", description = "모든 아티클을 요약 없이 조회합니다.") - public ResponseEntity getAllArticlesWithAllData() { - List articles = articleService.getAllArticlesWithAllData(); - log.info("모든 기사 요약 조회"); - return ResponseEntity.ok(ArticleResponseListWrapper.from(articles)); - } + @GetMapping + @Operation(summary = "아티클 요약 전체 조회(페이징 단위: 10)", description = "article에 대한 정보를 10개 단위로 페이징 하여 조회합니다.") + public ResponseEntity> getAllArticleSummaries( + @PageableDefault(size = 10) Pageable pageable) { + Page articles = articleService.findAllArticleSummaries(pageable); + log.info("모든 기사 요약 조회, 페이지 정보 : {} ", pageable); + return ResponseEntity.ok(articles); + } + @GetMapping("/all") + @Operation(summary = "아티클 요약 전체 조회(페이징 없음)", description = "모든 아티클을 조회합니다.") + public ResponseEntity getAllArticles() { + List articles = articleService.getAllArticles(); + log.info("모든 기사 요약 조회"); + return ResponseEntity.ok(ArticleListResponse.from(articles)); + } + @GetMapping("/allData") + @Operation(summary = "아티클 요약x 전체 조회(페이징 없음)", description = "모든 아티클을 요약 없이 조회합니다.") + public ResponseEntity getAllArticlesWithAllData() { + List articles = articleService.getAllArticlesWithAllData(); + log.info("모든 기사 요약 조회"); + return ResponseEntity.ok(ArticleResponseListWrapper.from(articles)); + } } diff --git a/src/main/java/com/cotato/squadus/api/article/dto/ArticleListResponse.java b/src/main/java/com/cotato/squadus/api/article/dto/ArticleListResponse.java index a757229..6f31304 100644 --- a/src/main/java/com/cotato/squadus/api/article/dto/ArticleListResponse.java +++ b/src/main/java/com/cotato/squadus/api/article/dto/ArticleListResponse.java @@ -3,7 +3,7 @@ import java.util.List; public record ArticleListResponse(List articles) { - public static ArticleListResponse from(List articles) { - return new ArticleListResponse(articles); - } + public static ArticleListResponse from(List articles) { + return new ArticleListResponse(articles); + } } \ No newline at end of file diff --git a/src/main/java/com/cotato/squadus/api/article/dto/ArticleRequest.java b/src/main/java/com/cotato/squadus/api/article/dto/ArticleRequest.java index 0cb7b2a..86c16e0 100644 --- a/src/main/java/com/cotato/squadus/api/article/dto/ArticleRequest.java +++ b/src/main/java/com/cotato/squadus/api/article/dto/ArticleRequest.java @@ -6,10 +6,10 @@ @Getter @Setter public class ArticleRequest { - private String title; - private String subtitle; - private String type; - private String tag; - private String content; - private Long views; + private String title; + private String subtitle; + private String type; + private String tag; + private String content; + private Long views; } diff --git a/src/main/java/com/cotato/squadus/api/article/dto/ArticleResponse.java b/src/main/java/com/cotato/squadus/api/article/dto/ArticleResponse.java index f6a79d9..59c42e2 100644 --- a/src/main/java/com/cotato/squadus/api/article/dto/ArticleResponse.java +++ b/src/main/java/com/cotato/squadus/api/article/dto/ArticleResponse.java @@ -1,34 +1,34 @@ package com.cotato.squadus.api.article.dto; -import com.cotato.squadus.domain.club.article.entity.Article; - import java.time.LocalDateTime; +import com.cotato.squadus.domain.club.article.entity.Article; + public record ArticleResponse( - Long articleId, - String title, - String subtitle, - String type, - String tag, - String content, - Long views, - String imageUrl, - LocalDateTime createdAt, - LocalDateTime modifiedAt + Long articleId, + String title, + String subtitle, + String type, + String tag, + String content, + Long views, + String imageUrl, + LocalDateTime createdAt, + LocalDateTime modifiedAt ) { - public static ArticleResponse from(Article article) { - return new ArticleResponse( - article.getArticleIdx(), - article.getTitle(), - article.getSubtitle(), - article.getType(), - article.getTag(), - article.getContent(), - article.getViews(), - article.getImageUrl(), - article.getCreatedAt(), - article.getModifiedAt() - ); - } + public static ArticleResponse from(Article article) { + return new ArticleResponse( + article.getArticleIdx(), + article.getTitle(), + article.getSubtitle(), + article.getType(), + article.getTag(), + article.getContent(), + article.getViews(), + article.getImageUrl(), + article.getCreatedAt(), + article.getModifiedAt() + ); + } } diff --git a/src/main/java/com/cotato/squadus/api/article/dto/ArticleResponseListWrapper.java b/src/main/java/com/cotato/squadus/api/article/dto/ArticleResponseListWrapper.java index 207dc62..d7bb9d2 100644 --- a/src/main/java/com/cotato/squadus/api/article/dto/ArticleResponseListWrapper.java +++ b/src/main/java/com/cotato/squadus/api/article/dto/ArticleResponseListWrapper.java @@ -4,7 +4,7 @@ public record ArticleResponseListWrapper(List articles) { - public static ArticleResponseListWrapper from(List articles) { - return new ArticleResponseListWrapper(articles); - } + public static ArticleResponseListWrapper from(List articles) { + return new ArticleResponseListWrapper(articles); + } } \ No newline at end of file diff --git a/src/main/java/com/cotato/squadus/api/article/dto/ArticleSummaryResponse.java b/src/main/java/com/cotato/squadus/api/article/dto/ArticleSummaryResponse.java index 43543dc..0742f08 100644 --- a/src/main/java/com/cotato/squadus/api/article/dto/ArticleSummaryResponse.java +++ b/src/main/java/com/cotato/squadus/api/article/dto/ArticleSummaryResponse.java @@ -1,15 +1,14 @@ package com.cotato.squadus.api.article.dto; import com.cotato.squadus.domain.club.article.entity.Article; -import lombok.Getter; public record ArticleSummaryResponse(Long articleId, String title, String subtitle) { - public static ArticleSummaryResponse from(Article article) { - return new ArticleSummaryResponse( - article.getArticleIdx(), - article.getTitle(), - article.getSubtitle() - ); - } + public static ArticleSummaryResponse from(Article article) { + return new ArticleSummaryResponse( + article.getArticleIdx(), + article.getTitle(), + article.getSubtitle() + ); + } } diff --git a/src/main/java/com/cotato/squadus/api/auth/controller/EmailController.java b/src/main/java/com/cotato/squadus/api/auth/controller/EmailController.java index f037006..ecfb97f 100644 --- a/src/main/java/com/cotato/squadus/api/auth/controller/EmailController.java +++ b/src/main/java/com/cotato/squadus/api/auth/controller/EmailController.java @@ -1,57 +1,62 @@ package com.cotato.squadus.api.auth.controller; +import java.util.HashMap; +import java.util.Map; + +import org.springframework.security.core.annotation.AuthenticationPrincipal; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + import com.cotato.squadus.api.auth.dto.EmailRequestDto; import com.cotato.squadus.api.auth.dto.EmailResponseDto; import com.cotato.squadus.common.config.auth.CustomOAuth2Member; import com.cotato.squadus.domain.auth.service.EmailSendService; + import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; -import org.springframework.security.core.annotation.AuthenticationPrincipal; -import org.springframework.web.bind.annotation.*; - -import java.util.HashMap; -import java.util.Map; @Tag(name = "학교 인증 이메일", description = "학교 이메일 인증 관련 API") @RestController @RequestMapping("/v1/api/email") @RequiredArgsConstructor public class EmailController { - private final EmailSendService emailSendService; - - - @GetMapping("/test") - public String helloTest(){ - return "Hello World"; - } - - - /* Send Email: 인증번호 전송 버튼 click */ - @PostMapping("/signup") - @Operation(summary = "이메일 인증 요청", description = "이메일 주소를 통해 학교 이메일 인증을 요청합니다") - public Map mailSend(@RequestBody @Valid EmailRequestDto emailRequestDto) { - String code = emailSendService.joinEmail(emailRequestDto.getEmail()); - // response를 JSON 문자열으로 반환 - Map response = new HashMap<>(); - response.put("code", code); - - return response; - } - - /* Email Auth: 인증번호 입력 후 인증 버튼 click */ - @PostMapping("/signup/emailAuth") - @Operation(summary = "이메일 인증 인증번호 확인", description = "이메일 주소로 받은 인증 번호와 이메일 주소를 통해 학교인증을 완료합니다") - public String authCheck(@AuthenticationPrincipal CustomOAuth2Member customOAuth2Member, @RequestBody @Valid EmailResponseDto emailResponseDto) { - Boolean checked = emailSendService.checkAuthNum(emailResponseDto.getEmail(), emailResponseDto.getAuthNum(), customOAuth2Member); - if (checked) { - return "이메일 인증 성공!"; - } - else { - throw new NullPointerException("이메일 인증 실패!"); - } - } + private final EmailSendService emailSendService; + + @GetMapping("/test") + public String helloTest() { + return "Hello World"; + } + + /* Send Email: 인증번호 전송 버튼 click */ + @PostMapping("/signup") + @Operation(summary = "이메일 인증 요청", description = "이메일 주소를 통해 학교 이메일 인증을 요청합니다") + public Map mailSend(@RequestBody @Valid EmailRequestDto emailRequestDto) { + String code = emailSendService.joinEmail(emailRequestDto.getEmail()); + // response를 JSON 문자열으로 반환 + Map response = new HashMap<>(); + response.put("code", code); + + return response; + } + + /* Email Auth: 인증번호 입력 후 인증 버튼 click */ + @PostMapping("/signup/emailAuth") + @Operation(summary = "이메일 인증 인증번호 확인", description = "이메일 주소로 받은 인증 번호와 이메일 주소를 통해 학교인증을 완료합니다") + public String authCheck(@AuthenticationPrincipal CustomOAuth2Member customOAuth2Member, + @RequestBody @Valid EmailResponseDto emailResponseDto) { + Boolean checked = emailSendService.checkAuthNum(emailResponseDto.getEmail(), emailResponseDto.getAuthNum(), + customOAuth2Member); + if (checked) { + return "이메일 인증 성공!"; + } else { + throw new NullPointerException("이메일 인증 실패!"); + } + } } diff --git a/src/main/java/com/cotato/squadus/api/auth/controller/ReissueController.java b/src/main/java/com/cotato/squadus/api/auth/controller/ReissueController.java index c27ca45..1078112 100644 --- a/src/main/java/com/cotato/squadus/api/auth/controller/ReissueController.java +++ b/src/main/java/com/cotato/squadus/api/auth/controller/ReissueController.java @@ -1,8 +1,16 @@ package com.cotato.squadus.api.auth.controller; +import java.util.Map; + +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RestController; + import com.cotato.squadus.common.config.jwt.JWTUtil; import com.cotato.squadus.common.config.jwt.RefreshRepository; import com.cotato.squadus.domain.auth.service.RefreshService; + import io.jsonwebtoken.ExpiredJwtException; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; @@ -10,12 +18,6 @@ import jakarta.servlet.http.HttpServletResponse; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RestController; - -import java.util.Map; @Tag(name = "토큰 재발급", description = "Access Token 재발급 관련 API") @RestController @@ -23,49 +25,49 @@ @RequiredArgsConstructor public class ReissueController { - private final JWTUtil jwtUtil; - private final RefreshRepository refreshRepository; - private final RefreshService refreshService; + private final JWTUtil jwtUtil; + private final RefreshRepository refreshRepository; + private final RefreshService refreshService; - @PostMapping("/reissue") - @Operation(summary = "Access token 재발급", description = "Refresh token을 바탕으로 Access token을 재발급합니다") - public ResponseEntity reissue(HttpServletRequest request, HttpServletResponse response) { + @PostMapping("/reissue") + @Operation(summary = "Access token 재발급", description = "Refresh token을 바탕으로 Access token을 재발급합니다") + public ResponseEntity reissue(HttpServletRequest request, HttpServletResponse response) { - // 헤더에서 리프레시 토큰 가져오기 - String refresh = request.getHeader("refresh"); - if (refresh == null) { - return new ResponseEntity<>("refresh token is missing", HttpStatus.BAD_REQUEST); - } + // 헤더에서 리프레시 토큰 가져오기 + String refresh = request.getHeader("refresh"); + if (refresh == null) { + return new ResponseEntity<>("refresh token is missing", HttpStatus.BAD_REQUEST); + } - // 만료 여부 확인 - try { - jwtUtil.isExpired(refresh); - } catch (ExpiredJwtException e) { - return new ResponseEntity<>("refresh token expired", HttpStatus.BAD_REQUEST); - } + // 만료 여부 확인 + try { + jwtUtil.isExpired(refresh); + } catch (ExpiredJwtException e) { + return new ResponseEntity<>("refresh token expired", HttpStatus.BAD_REQUEST); + } - // 리프레시 토큰인지 확인 - String category = jwtUtil.getCategory(refresh); - if (!category.equals("refresh")) { - return new ResponseEntity<>("invalid refresh token", HttpStatus.BAD_REQUEST); - } + // 리프레시 토큰인지 확인 + String category = jwtUtil.getCategory(refresh); + if (!category.equals("refresh")) { + return new ResponseEntity<>("invalid refresh token", HttpStatus.BAD_REQUEST); + } - // DB에 저장된 토큰인지 확인 - Boolean isExist = refreshRepository.existsByRefresh(refresh); - if (!isExist) { - return new ResponseEntity<>("invalid refresh token", HttpStatus.BAD_REQUEST); - } + // DB에 저장된 토큰인지 확인 + Boolean isExist = refreshRepository.existsByRefresh(refresh); + if (!isExist) { + return new ResponseEntity<>("invalid refresh token", HttpStatus.BAD_REQUEST); + } - Map map = refreshService.reissueRefreshToken(refresh); + Map map = refreshService.reissueRefreshToken(refresh); - // 새로운 Access Token과 Refresh Token 생성 - String newAccess = map.get("access"); - String newRefresh = map.get("refresh"); + // 새로운 Access Token과 Refresh Token 생성 + String newAccess = map.get("access"); + String newRefresh = map.get("refresh"); - // 헤더에 토큰 추가 - response.setHeader("access", newAccess); - response.setHeader("refresh", newRefresh); + // 헤더에 토큰 추가 + response.setHeader("access", newAccess); + response.setHeader("refresh", newRefresh); - return new ResponseEntity<>(HttpStatus.OK); - } + return new ResponseEntity<>(HttpStatus.OK); + } } diff --git a/src/main/java/com/cotato/squadus/api/auth/dto/EmailRequestDto.java b/src/main/java/com/cotato/squadus/api/auth/dto/EmailRequestDto.java index 13831fd..b69d118 100644 --- a/src/main/java/com/cotato/squadus/api/auth/dto/EmailRequestDto.java +++ b/src/main/java/com/cotato/squadus/api/auth/dto/EmailRequestDto.java @@ -6,5 +6,5 @@ @Getter @Setter public class EmailRequestDto { - private String email; + private String email; } diff --git a/src/main/java/com/cotato/squadus/api/auth/dto/EmailResponseDto.java b/src/main/java/com/cotato/squadus/api/auth/dto/EmailResponseDto.java index 6b1df94..10a2e49 100644 --- a/src/main/java/com/cotato/squadus/api/auth/dto/EmailResponseDto.java +++ b/src/main/java/com/cotato/squadus/api/auth/dto/EmailResponseDto.java @@ -5,6 +5,6 @@ @Data public class EmailResponseDto { - private String email; - private String authNum; + private String email; + private String authNum; } diff --git a/src/main/java/com/cotato/squadus/api/auth/dto/JoinRequest.java b/src/main/java/com/cotato/squadus/api/auth/dto/JoinRequest.java index 57de673..afc3892 100644 --- a/src/main/java/com/cotato/squadus/api/auth/dto/JoinRequest.java +++ b/src/main/java/com/cotato/squadus/api/auth/dto/JoinRequest.java @@ -7,7 +7,7 @@ @Setter public class JoinRequest { - private String username; - private String password; - private String email; + private String username; + private String password; + private String email; } diff --git a/src/main/java/com/cotato/squadus/api/auth/dto/LoginRequest.java b/src/main/java/com/cotato/squadus/api/auth/dto/LoginRequest.java index 405d3f4..550e897 100644 --- a/src/main/java/com/cotato/squadus/api/auth/dto/LoginRequest.java +++ b/src/main/java/com/cotato/squadus/api/auth/dto/LoginRequest.java @@ -2,6 +2,7 @@ import com.cotato.squadus.domain.auth.entity.Member; import com.cotato.squadus.domain.auth.enums.MemberRole; + import lombok.Builder; import lombok.Getter; import lombok.Setter; @@ -10,24 +11,23 @@ @Setter public class LoginRequest { - private String uniqueId; - private String username; - private String email; - private MemberRole memberRole; - - public LoginRequest(Member member) { - this.uniqueId = member.getUniqueId(); - this.username = member.getUsername(); - this.email = member.getEmail(); - this.memberRole = member.getMemberRole(); - } + private String uniqueId; + private String username; + private String email; + private MemberRole memberRole; - @Builder - public LoginRequest(String uniqueId, String username, MemberRole memberRole) { - this.uniqueId = uniqueId; - this.username = username; - this.memberRole = memberRole; - } + public LoginRequest(Member member) { + this.uniqueId = member.getUniqueId(); + this.username = member.getUsername(); + this.email = member.getEmail(); + this.memberRole = member.getMemberRole(); + } + @Builder + public LoginRequest(String uniqueId, String username, MemberRole memberRole) { + this.uniqueId = uniqueId; + this.username = username; + this.memberRole = memberRole; + } } diff --git a/src/main/java/com/cotato/squadus/api/auth/dto/LoginResponse.java b/src/main/java/com/cotato/squadus/api/auth/dto/LoginResponse.java index 263ed2f..f568fc0 100644 --- a/src/main/java/com/cotato/squadus/api/auth/dto/LoginResponse.java +++ b/src/main/java/com/cotato/squadus/api/auth/dto/LoginResponse.java @@ -8,6 +8,6 @@ @Setter @AllArgsConstructor public class LoginResponse { - private String accessToken; - private String refreshToken; + private String accessToken; + private String refreshToken; } diff --git a/src/main/java/com/cotato/squadus/api/auth/dto/OAuth2Attribute.java b/src/main/java/com/cotato/squadus/api/auth/dto/OAuth2Attribute.java index 9dcbee3..92b4693 100644 --- a/src/main/java/com/cotato/squadus/api/auth/dto/OAuth2Attribute.java +++ b/src/main/java/com/cotato/squadus/api/auth/dto/OAuth2Attribute.java @@ -1,74 +1,74 @@ package com.cotato.squadus.api.auth.dto; +import java.util.Map; + import com.cotato.squadus.domain.auth.entity.Member; import com.cotato.squadus.domain.auth.enums.MemberRole; + import lombok.Builder; import lombok.Getter; -import java.util.Map; - @Getter @Builder public class OAuth2Attribute { - private Map attributes; - private String username; - private String email; - private String providerId; - - - public static OAuth2Attribute of(String registrationId, Map attributes) { - if(registrationId.equals("google")){ - return ofGoogle(attributes); - } else if (registrationId.equals("kakao")) { - return ofKakao(attributes); - } - return ofNaver(attributes); - } - + private Map attributes; + private String username; + private String email; + private String providerId; + public static OAuth2Attribute of(String registrationId, Map attributes) { + if (registrationId.equals("google")) { + return ofGoogle(attributes); + } else if (registrationId.equals("kakao")) { + return ofKakao(attributes); + } + return ofNaver(attributes); + } - private static OAuth2Attribute ofGoogle(Map attributes) { - return OAuth2Attribute.builder() - .username(attributes.get("name").toString()) - .email(attributes.get("email").toString()) - .providerId(attributes.get("sub").toString()) - .attributes(attributes) - .build(); - } + private static OAuth2Attribute ofGoogle(Map attributes) { + return OAuth2Attribute.builder() + .username(attributes.get("name").toString()) + .email(attributes.get("email").toString()) + .providerId(attributes.get("sub").toString()) + .attributes(attributes) + .build(); + } - private static OAuth2Attribute ofKakao(Map attributes) { - Map kakao_account = (Map) attributes.get("kakao_account"); // 카카오로 받은 데이터에서 계정 정보가 담긴 kakao_account 값을 꺼낸다. - Map profile = (Map) kakao_account.get("profile"); // 마찬가지로 profile(nickname, image_url.. 등) 정보가 담긴 값을 꺼낸다. + private static OAuth2Attribute ofKakao(Map attributes) { + Map kakao_account = (Map)attributes.get( + "kakao_account"); // 카카오로 받은 데이터에서 계정 정보가 담긴 kakao_account 값을 꺼낸다. + Map profile = (Map)kakao_account.get( + "profile"); // 마찬가지로 profile(nickname, image_url.. 등) 정보가 담긴 값을 꺼낸다. - return OAuth2Attribute.builder() - .username(profile.get("nickname").toString()) - .email(kakao_account.get("email").toString()) - .providerId(attributes.get("id").toString()) - .attributes(attributes) - .build(); - } + return OAuth2Attribute.builder() + .username(profile.get("nickname").toString()) + .email(kakao_account.get("email").toString()) + .providerId(attributes.get("id").toString()) + .attributes(attributes) + .build(); + } - private static OAuth2Attribute ofNaver(Map attributes) { - Map attributesMap = (Map) attributes.get("response"); + private static OAuth2Attribute ofNaver(Map attributes) { + Map attributesMap = (Map)attributes.get("response"); - return OAuth2Attribute.builder() - .username(attributesMap.get("name").toString()) - .email(attributesMap.get("email").toString()) - .providerId(attributesMap.get("id").toString()) - .attributes(attributesMap) - .build(); - } + return OAuth2Attribute.builder() + .username(attributesMap.get("name").toString()) + .email(attributesMap.get("email").toString()) + .providerId(attributesMap.get("id").toString()) + .attributes(attributesMap) + .build(); + } - public Member toEntity(String uniqueId){ - return Member.builder() - .username(username) - .email(email) - .uniqueId(uniqueId) - .memberRole(MemberRole.MEMBER.toString()) - .profileImage("default profile img") - .university("uncertified") - .build(); - } + public Member toEntity(String uniqueId) { + return Member.builder() + .username(username) + .email(email) + .uniqueId(uniqueId) + .memberRole(MemberRole.MEMBER.toString()) + .profileImage("default profile img") + .university("uncertified") + .build(); + } } \ No newline at end of file diff --git a/src/main/java/com/cotato/squadus/api/club/controller/ClubController.java b/src/main/java/com/cotato/squadus/api/club/controller/ClubController.java index ea50ec4..9ce4a10 100644 --- a/src/main/java/com/cotato/squadus/api/club/controller/ClubController.java +++ b/src/main/java/com/cotato/squadus/api/club/controller/ClubController.java @@ -1,24 +1,41 @@ package com.cotato.squadus.api.club.controller; -import com.cotato.squadus.api.club.dto.*; +import java.util.List; + +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.security.core.annotation.AuthenticationPrincipal; +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 org.springframework.web.bind.annotation.RequestPart; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.multipart.MultipartFile; + +import com.cotato.squadus.api.club.dto.ClubApplyRequest; +import com.cotato.squadus.api.club.dto.ClubApplyResponse; +import com.cotato.squadus.api.club.dto.ClubCreateRequest; +import com.cotato.squadus.api.club.dto.ClubCreateResponse; +import com.cotato.squadus.api.club.dto.ClubInfoResponse; +import com.cotato.squadus.api.club.dto.ClubMemberInfoResponseList; +import com.cotato.squadus.api.club.dto.ClubRankResponse; +import com.cotato.squadus.api.club.dto.ClubUpdateRequest; +import com.cotato.squadus.api.club.dto.ClubUpdateResponse; import com.cotato.squadus.common.config.auth.CustomOAuth2Member; import com.cotato.squadus.domain.auth.service.ClubMemberService; import com.cotato.squadus.domain.club.common.enums.SportsCategory; import com.cotato.squadus.domain.club.common.service.ClubService; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; + import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.tags.Tag; import lombok.RequiredArgsConstructor; -import org.springframework.http.MediaType; -import org.springframework.http.ResponseEntity; -import org.springframework.security.core.annotation.AuthenticationPrincipal; -import org.springframework.web.bind.annotation.*; -import org.springframework.web.multipart.MultipartFile; - -import java.util.List; @Tag(name = "동아리", description = "동아리 관련 API") @RestController @@ -26,79 +43,79 @@ @RequiredArgsConstructor public class ClubController { - private final ClubService clubService; - private final ClubMemberService clubMemberService; - - @PostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE) - @Operation(summary = "동아리 생성", description = "동아리에 대한 정보를 바탕으로 동아리를 생성합니다") - public ResponseEntity createClub( - @AuthenticationPrincipal CustomOAuth2Member customOAuth2Member, - @Parameter(description = "동아리 생성 요청 정보", schema = @Schema(implementation = ClubCreateRequest.class)) - @RequestPart("clubCreateRequest") String clubCreateRequestString, - @RequestPart(value = "logoImage", required = false) MultipartFile logoImage) { - - // JSON String을 객체로 변환 - ObjectMapper objectMapper = new ObjectMapper(); - ClubCreateRequest clubCreateRequest; - try { - clubCreateRequest = objectMapper.readValue(clubCreateRequestString, ClubCreateRequest.class); - } catch (JsonProcessingException e) { - throw new RuntimeException("Invalid JSON format", e); - } - ClubCreateResponse clubCreateResponse = clubService.createClub(customOAuth2Member, clubCreateRequest, logoImage); - return ResponseEntity.ok(clubCreateResponse); - } - - @GetMapping("/{clubId}") - @Operation(summary = "동아리 기본 정보 조회", description = "clubId를 바탕으로 동아리에 대한 정보를 반환합니다.") - public ResponseEntity findClubInfo(@PathVariable Long clubId) { - ClubInfoResponse clubInfoResponse = clubService.findClubInfo(clubId); - return ResponseEntity.ok(clubInfoResponse); - } - - @GetMapping("/{clubId}/members") - @Operation(summary = "동아리원 전체 조회", description = "clubId를 바탕으로 동아리원을 조회합니다.") - public ResponseEntity findAllClubMemberInfo(@PathVariable Long clubId) { - ClubMemberInfoResponseList clubMemberInfoResponseList = clubMemberService.findAllClubMemberInfo(clubId); - return ResponseEntity.ok(clubMemberInfoResponseList); - } - - - @PostMapping("/{clubId}") - @Operation(summary = "동아리 가입 신청", description = "clubId와 동아리 가입에 대한 정보를 바탕으로 동아리 가입을 신청합니다") - public ResponseEntity joinClub(@AuthenticationPrincipal CustomOAuth2Member customOAuth2Member, @PathVariable Long clubId, @RequestBody ClubApplyRequest clubApplyRequest) { - ClubApplyResponse clubApplyResponse = clubService.joinClub(customOAuth2Member, clubId, clubApplyRequest); - return ResponseEntity.ok(clubApplyResponse); - } - - @PatchMapping(value = "/{clubId}", consumes = MediaType.MULTIPART_FORM_DATA_VALUE) - @Operation(summary = "동아리 기본정보 수정", description = "동아리의 기본 정보를 변경합니다.") - public ResponseEntity updateClub( - @AuthenticationPrincipal CustomOAuth2Member customOAuth2Member, - @PathVariable Long clubId, - @Parameter(description = "동아리 수정 요청 정보", schema = @Schema(implementation = ClubUpdateRequest.class)) - @RequestPart("clubUpdateRequest") String clubUpdateRequestString, - @RequestPart(value = "logoImage", required = false) MultipartFile logoImage) { - - // JSON String을 객체로 변환 - ObjectMapper objectMapper = new ObjectMapper(); - ClubUpdateRequest clubUpdateRequest; - try { - clubUpdateRequest = objectMapper.readValue(clubUpdateRequestString, ClubUpdateRequest.class); - } catch (JsonProcessingException e) { - throw new RuntimeException("Invalid JSON format", e); - } - ClubUpdateResponse clubUpdateResponse = clubService.updateClub(customOAuth2Member, clubId, clubUpdateRequest, logoImage); - return ResponseEntity.ok(clubUpdateResponse); - } - - - @GetMapping("/ranking/{sportsCategory}") - @Operation(summary = "랭킹 목록 조회", description = "랭킹 페이지로 들어가면 ALL TIME 기준의 랭킹 정보를 순위대로 얻을 수 있다.") - public ResponseEntity> getRanking(@PathVariable SportsCategory sportsCategory) { - List ranking = clubService.getRanking(sportsCategory); - return ResponseEntity.ok(ranking); - } - + private final ClubService clubService; + private final ClubMemberService clubMemberService; + + @PostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE) + @Operation(summary = "동아리 생성", description = "동아리에 대한 정보를 바탕으로 동아리를 생성합니다") + public ResponseEntity createClub( + @AuthenticationPrincipal CustomOAuth2Member customOAuth2Member, + @Parameter(description = "동아리 생성 요청 정보", schema = @Schema(implementation = ClubCreateRequest.class)) + @RequestPart("clubCreateRequest") String clubCreateRequestString, + @RequestPart(value = "logoImage", required = false) MultipartFile logoImage) { + + // JSON String을 객체로 변환 + ObjectMapper objectMapper = new ObjectMapper(); + ClubCreateRequest clubCreateRequest; + try { + clubCreateRequest = objectMapper.readValue(clubCreateRequestString, ClubCreateRequest.class); + } catch (JsonProcessingException e) { + throw new RuntimeException("Invalid JSON format", e); + } + ClubCreateResponse clubCreateResponse = clubService.createClub(customOAuth2Member, clubCreateRequest, + logoImage); + return ResponseEntity.ok(clubCreateResponse); + } + + @GetMapping("/{clubId}") + @Operation(summary = "동아리 기본 정보 조회", description = "clubId를 바탕으로 동아리에 대한 정보를 반환합니다.") + public ResponseEntity findClubInfo(@PathVariable Long clubId) { + ClubInfoResponse clubInfoResponse = clubService.findClubInfo(clubId); + return ResponseEntity.ok(clubInfoResponse); + } + + @GetMapping("/{clubId}/members") + @Operation(summary = "동아리원 전체 조회", description = "clubId를 바탕으로 동아리원을 조회합니다.") + public ResponseEntity findAllClubMemberInfo(@PathVariable Long clubId) { + ClubMemberInfoResponseList clubMemberInfoResponseList = clubMemberService.findAllClubMemberInfo(clubId); + return ResponseEntity.ok(clubMemberInfoResponseList); + } + + @PostMapping("/{clubId}") + @Operation(summary = "동아리 가입 신청", description = "clubId와 동아리 가입에 대한 정보를 바탕으로 동아리 가입을 신청합니다") + public ResponseEntity joinClub(@AuthenticationPrincipal CustomOAuth2Member customOAuth2Member, + @PathVariable Long clubId, @RequestBody ClubApplyRequest clubApplyRequest) { + ClubApplyResponse clubApplyResponse = clubService.joinClub(customOAuth2Member, clubId, clubApplyRequest); + return ResponseEntity.ok(clubApplyResponse); + } + + @PatchMapping(value = "/{clubId}", consumes = MediaType.MULTIPART_FORM_DATA_VALUE) + @Operation(summary = "동아리 기본정보 수정", description = "동아리의 기본 정보를 변경합니다.") + public ResponseEntity updateClub( + @AuthenticationPrincipal CustomOAuth2Member customOAuth2Member, + @PathVariable Long clubId, + @Parameter(description = "동아리 수정 요청 정보", schema = @Schema(implementation = ClubUpdateRequest.class)) + @RequestPart("clubUpdateRequest") String clubUpdateRequestString, + @RequestPart(value = "logoImage", required = false) MultipartFile logoImage) { + + // JSON String을 객체로 변환 + ObjectMapper objectMapper = new ObjectMapper(); + ClubUpdateRequest clubUpdateRequest; + try { + clubUpdateRequest = objectMapper.readValue(clubUpdateRequestString, ClubUpdateRequest.class); + } catch (JsonProcessingException e) { + throw new RuntimeException("Invalid JSON format", e); + } + ClubUpdateResponse clubUpdateResponse = clubService.updateClub(customOAuth2Member, clubId, clubUpdateRequest, + logoImage); + return ResponseEntity.ok(clubUpdateResponse); + } + + @GetMapping("/ranking/{sportsCategory}") + @Operation(summary = "랭킹 목록 조회", description = "랭킹 페이지로 들어가면 ALL TIME 기준의 랭킹 정보를 순위대로 얻을 수 있다.") + public ResponseEntity> getRanking(@PathVariable SportsCategory sportsCategory) { + List ranking = clubService.getRanking(sportsCategory); + return ResponseEntity.ok(ranking); + } } diff --git a/src/main/java/com/cotato/squadus/api/club/dto/ClubApplyRequest.java b/src/main/java/com/cotato/squadus/api/club/dto/ClubApplyRequest.java index 0ce1036..1eb732c 100644 --- a/src/main/java/com/cotato/squadus/api/club/dto/ClubApplyRequest.java +++ b/src/main/java/com/cotato/squadus/api/club/dto/ClubApplyRequest.java @@ -1,15 +1,15 @@ package com.cotato.squadus.api.club.dto; +import java.util.Map; + import lombok.Getter; import lombok.Setter; -import java.util.Map; - @Getter @Setter public class ClubApplyRequest { - private Long recruitingPostId; + private Long recruitingPostId; - private Map answers; + private Map answers; } diff --git a/src/main/java/com/cotato/squadus/api/club/dto/ClubCreateRequest.java b/src/main/java/com/cotato/squadus/api/club/dto/ClubCreateRequest.java index c1a90e8..b2ef66d 100644 --- a/src/main/java/com/cotato/squadus/api/club/dto/ClubCreateRequest.java +++ b/src/main/java/com/cotato/squadus/api/club/dto/ClubCreateRequest.java @@ -1,29 +1,30 @@ package com.cotato.squadus.api.club.dto; +import java.util.List; + import com.cotato.squadus.domain.club.common.enums.ClubCategory; import com.cotato.squadus.domain.club.common.enums.SportsCategory; + import lombok.Getter; import lombok.Setter; -import java.util.List; - @Getter @Setter public class ClubCreateRequest { - private String clubName; + private String clubName; - private ClubCategory clubCategory; + private ClubCategory clubCategory; - private SportsCategory sportsCategory; + private SportsCategory sportsCategory; - private Long maxMembers; + private Long maxMembers; - private String clubMessage; + private String clubMessage; - private List tags; + private List tags; - private String city; + private String city; - private String district; + private String district; } diff --git a/src/main/java/com/cotato/squadus/api/club/dto/ClubInfoResponse.java b/src/main/java/com/cotato/squadus/api/club/dto/ClubInfoResponse.java index b0a4ee6..88e85ae 100644 --- a/src/main/java/com/cotato/squadus/api/club/dto/ClubInfoResponse.java +++ b/src/main/java/com/cotato/squadus/api/club/dto/ClubInfoResponse.java @@ -1,41 +1,41 @@ package com.cotato.squadus.api.club.dto; -import com.cotato.squadus.domain.club.common.entity.Club; -import com.cotato.squadus.domain.club.common.enums.SportsCategory; - import java.time.LocalDateTime; import java.util.List; +import com.cotato.squadus.domain.club.common.entity.Club; +import com.cotato.squadus.domain.club.common.enums.SportsCategory; + public record ClubInfoResponse( - Long id, - String clubName, - String university, - String clubTier, - Integer clubRank, - SportsCategory sportsCategory, - String logo, - Integer numberOfMembers, - Long maxMembers, - LocalDateTime createdAt, - String clubMessage, - List tags, - Integer matchScore + Long id, + String clubName, + String university, + String clubTier, + Integer clubRank, + SportsCategory sportsCategory, + String logo, + Integer numberOfMembers, + Long maxMembers, + LocalDateTime createdAt, + String clubMessage, + List tags, + Integer matchScore ) { - public static ClubInfoResponse from(Club club) { - return new ClubInfoResponse( - club.getClubId(), - club.getClubName(), - club.getUniversity(), - club.getClubTier().name(), - club.getClubRank(), - club.getSportsCategory(), - club.getLogo(), - club.getClubMembers() != null ? club.getClubMembers().size() : 0, - club.getMaxMembers(), - club.getCreatedAt(), - club.getClubMessage(), - club.getTags(), - club.getMatchScore() - ); - } + public static ClubInfoResponse from(Club club) { + return new ClubInfoResponse( + club.getClubId(), + club.getClubName(), + club.getUniversity(), + club.getClubTier().name(), + club.getClubRank(), + club.getSportsCategory(), + club.getLogo(), + club.getClubMembers() != null ? club.getClubMembers().size() : 0, + club.getMaxMembers(), + club.getCreatedAt(), + club.getClubMessage(), + club.getTags(), + club.getMatchScore() + ); + } } diff --git a/src/main/java/com/cotato/squadus/api/club/dto/ClubMemberInfoResponse.java b/src/main/java/com/cotato/squadus/api/club/dto/ClubMemberInfoResponse.java index 40bae93..e32c607 100644 --- a/src/main/java/com/cotato/squadus/api/club/dto/ClubMemberInfoResponse.java +++ b/src/main/java/com/cotato/squadus/api/club/dto/ClubMemberInfoResponse.java @@ -3,16 +3,16 @@ import com.cotato.squadus.domain.club.common.entity.ClubMember; public record ClubMemberInfoResponse( - Long id, - String name, - String profileImg + Long id, + String name, + String profileImg ) { - public static ClubMemberInfoResponse from(ClubMember clubMember) { - return new ClubMemberInfoResponse( - clubMember.getClubMemberIdx(), - clubMember.getMember().getUsername(), - clubMember.getMember().getProfileImage() - ); - } + public static ClubMemberInfoResponse from(ClubMember clubMember) { + return new ClubMemberInfoResponse( + clubMember.getClubMemberIdx(), + clubMember.getMember().getUsername(), + clubMember.getMember().getProfileImage() + ); + } } diff --git a/src/main/java/com/cotato/squadus/api/club/dto/ClubMemberInfoResponseList.java b/src/main/java/com/cotato/squadus/api/club/dto/ClubMemberInfoResponseList.java index c86a328..8876895 100644 --- a/src/main/java/com/cotato/squadus/api/club/dto/ClubMemberInfoResponseList.java +++ b/src/main/java/com/cotato/squadus/api/club/dto/ClubMemberInfoResponseList.java @@ -3,9 +3,9 @@ import java.util.List; public record ClubMemberInfoResponseList( - List clubMemberInfoResponseList + List clubMemberInfoResponseList ) { - public static ClubMemberInfoResponseList from(List clubMemberInfoResponseList) { - return new ClubMemberInfoResponseList(clubMemberInfoResponseList); - } + public static ClubMemberInfoResponseList from(List clubMemberInfoResponseList) { + return new ClubMemberInfoResponseList(clubMemberInfoResponseList); + } } diff --git a/src/main/java/com/cotato/squadus/api/club/dto/ClubRankResponse.java b/src/main/java/com/cotato/squadus/api/club/dto/ClubRankResponse.java index 962fad0..1a83a6a 100644 --- a/src/main/java/com/cotato/squadus/api/club/dto/ClubRankResponse.java +++ b/src/main/java/com/cotato/squadus/api/club/dto/ClubRankResponse.java @@ -1,10 +1,10 @@ package com.cotato.squadus.api.club.dto; public record ClubRankResponse( - String logoUrl, // 동아리 로고 URL - String clubName, // 동아리 이름 - int matchScore, // 동아리 점수 - int currentRank, // 현재 순위 - int rankChange // 순위 변동 (이전 순위 - 현재 순위) + String logoUrl, // 동아리 로고 URL + String clubName, // 동아리 이름 + int matchScore, // 동아리 점수 + int currentRank, // 현재 순위 + int rankChange // 순위 변동 (이전 순위 - 현재 순위) ) { } \ No newline at end of file diff --git a/src/main/java/com/cotato/squadus/api/club/dto/ClubTierInfoResponse.java b/src/main/java/com/cotato/squadus/api/club/dto/ClubTierInfoResponse.java index 80aee01..c6aaa4c 100644 --- a/src/main/java/com/cotato/squadus/api/club/dto/ClubTierInfoResponse.java +++ b/src/main/java/com/cotato/squadus/api/club/dto/ClubTierInfoResponse.java @@ -1,10 +1,10 @@ package com.cotato.squadus.api.club.dto; public record ClubTierInfoResponse( - String clubTier, - int teamCount, //같은 종목을 가진 club의 갯수 - int currentRank, - int ranksToNextTier + String clubTier, + int teamCount, //같은 종목을 가진 club의 갯수 + int currentRank, + int ranksToNextTier ) { - + } diff --git a/src/main/java/com/cotato/squadus/api/club/dto/ClubUpdateRequest.java b/src/main/java/com/cotato/squadus/api/club/dto/ClubUpdateRequest.java index 2836758..2153d09 100644 --- a/src/main/java/com/cotato/squadus/api/club/dto/ClubUpdateRequest.java +++ b/src/main/java/com/cotato/squadus/api/club/dto/ClubUpdateRequest.java @@ -3,11 +3,11 @@ import java.util.List; public record ClubUpdateRequest( - String clubMessage, - String city, - String district, - Long maxMembers, - List tags + String clubMessage, + String city, + String district, + Long maxMembers, + List tags ) { } diff --git a/src/main/java/com/cotato/squadus/api/club/dto/ClubUpdateResponse.java b/src/main/java/com/cotato/squadus/api/club/dto/ClubUpdateResponse.java index 08ce58d..3203cba 100644 --- a/src/main/java/com/cotato/squadus/api/club/dto/ClubUpdateResponse.java +++ b/src/main/java/com/cotato/squadus/api/club/dto/ClubUpdateResponse.java @@ -1,6 +1,6 @@ package com.cotato.squadus.api.club.dto; public record ClubUpdateResponse( - Long clubId + Long clubId ) { } diff --git a/src/main/java/com/cotato/squadus/api/fee/controller/ClubFeeController.java b/src/main/java/com/cotato/squadus/api/fee/controller/ClubFeeController.java index 7a447a7..6f87381 100644 --- a/src/main/java/com/cotato/squadus/api/fee/controller/ClubFeeController.java +++ b/src/main/java/com/cotato/squadus/api/fee/controller/ClubFeeController.java @@ -1,15 +1,31 @@ package com.cotato.squadus.api.fee.controller; -import com.cotato.squadus.api.fee.dto.*; +import org.springframework.http.ResponseEntity; +import org.springframework.security.core.annotation.AuthenticationPrincipal; +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 org.springframework.web.bind.annotation.RestController; + +import com.cotato.squadus.api.fee.dto.ClubFeeCreateRequest; +import com.cotato.squadus.api.fee.dto.ClubFeeCreateResponse; +import com.cotato.squadus.api.fee.dto.ClubFeePaymentInfoResponseList; +import com.cotato.squadus.api.fee.dto.ClubFeePaymentUpdateRequest; +import com.cotato.squadus.api.fee.dto.ClubFeePaymentUpdateResponse; +import com.cotato.squadus.api.fee.dto.ClubFeeSummaryResponseList; +import com.cotato.squadus.api.fee.dto.ClubFeeUsageCreateResponse; +import com.cotato.squadus.api.fee.dto.ClubFeeUsageRequest; +import com.cotato.squadus.api.fee.dto.ClubFeeUsageResponseList; import com.cotato.squadus.common.config.auth.CustomOAuth2Member; import com.cotato.squadus.domain.club.fee.service.ClubFeeService; + import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.springframework.http.ResponseEntity; -import org.springframework.security.core.annotation.AuthenticationPrincipal; -import org.springframework.web.bind.annotation.*; @Tag(name = "동아리 회비", description = "동아리 회비 관련 API") @Slf4j @@ -18,71 +34,78 @@ @RequiredArgsConstructor public class ClubFeeController { - private final ClubFeeService clubFeeService; - - - @GetMapping("") - @Operation(summary = "동아리 회비 종류 전체 요약 조회", description = "동아리 회비의 종류 전체를 요약해서 조회합니다.(정기회비, 이벤트회비 등)") - public ResponseEntity findAllClubFeesSummary(@AuthenticationPrincipal CustomOAuth2Member customOAuth2Member, @PathVariable("clubId") Long clubId) { - ClubFeeSummaryResponseList clubFeeSummaryResponseList = clubFeeService.findAllClubFeeTypesSummary(customOAuth2Member, clubId); - return ResponseEntity.ok(clubFeeSummaryResponseList); - } - - @PostMapping("") - @Operation(summary = "동아리 회비 등록", description = "동아리 회비를 등록합니다.") - public ResponseEntity createClubFee(@AuthenticationPrincipal CustomOAuth2Member customOAuth2Member, @PathVariable("clubId") Long clubId, ClubFeeCreateRequest clubFeeCreateRequest) { - ClubFeeCreateResponse createdClubFee = clubFeeService.createFee(customOAuth2Member, clubId, clubFeeCreateRequest); - return ResponseEntity.ok(createdClubFee); - } - - @GetMapping("/usages") - @Operation(summary = "동아리 회비 전체에 대한 사용내역 조회", description = "clubId를 지정하여 해당 동아리의 회비 사용내역 전체를 조회합니다.") - public ResponseEntity findAllClubFeeUsage(@AuthenticationPrincipal CustomOAuth2Member customOAuth2Member, @PathVariable("clubId") Long clubId) { - ClubFeeUsageResponseList clubFeeUsageResponseList = clubFeeService.findAllClubFeeUsage(customOAuth2Member, clubId); - return ResponseEntity.ok(clubFeeUsageResponseList); - } - - @GetMapping("/{feeTypeId}/usage") - @Operation(summary = "동아리 회비 하나에 대한 사용내역 조회", description = "회비의 id를 지정하여 해당하는 동아리 회비의 사용내역을 조회합니다.") - public ResponseEntity findAllClubFeeUsageByFeeTypeId(@AuthenticationPrincipal CustomOAuth2Member customOAuth2Member, @PathVariable("clubId") Long clubId, @PathVariable("feeTypeId") Long feeTypeId) { - ClubFeeUsageResponseList clubFeeUsageResponseList = clubFeeService.findAllClubFeeUsageByFeeTypeId(customOAuth2Member, clubId, feeTypeId); - return ResponseEntity.ok(clubFeeUsageResponseList); - } - - @PostMapping("/{feeTypeId}/usage") - @Operation(summary = "동아리 회비 사용", description = "회비의 id를 지정하여 동아리 회비를 사용합니다.") - public ResponseEntity createClubFeeUsage(@AuthenticationPrincipal CustomOAuth2Member customOAuth2Member, @PathVariable("clubId") Long clubId, @PathVariable("feeTypeId") Long feeTypeId, ClubFeeUsageRequest clubFeeUsageRequest) { - ClubFeeUsageCreateResponse clubFeeUsage = clubFeeService.createClubFeeUsage(customOAuth2Member, clubId, feeTypeId, clubFeeUsageRequest); - return ResponseEntity.ok(clubFeeUsage); - } - - @GetMapping("/{feeTypeId}/payment") - @Operation(summary = "동아리 회비 입금 현황 조회", description = "회비의 id를 지정하여 동아리의 입금 현황을 조회합니다.") - public ResponseEntity findClubFeePaymentInfo( - @AuthenticationPrincipal CustomOAuth2Member customOAuth2Member, - @PathVariable("clubId") Long clubId, - @PathVariable("feeTypeId") Long feeTypeId) { - ClubFeePaymentInfoResponseList clubFeePaymentInfo = clubFeeService.findClubFeePaymentInfo(customOAuth2Member, clubId, feeTypeId); - return ResponseEntity.ok(clubFeePaymentInfo); - } - - @PatchMapping("/{feeTypeId}/payment") - @Operation(summary = "동아리 회비 입금 여부 수정", description = "동아리원의 회비 입금 여부를 수정합니다.") - public ResponseEntity updateClubFeePaymentInfo( - @AuthenticationPrincipal CustomOAuth2Member customOAuth2Member, - @PathVariable("clubId") Long clubId, - @PathVariable("feeTypeId") Long feeTypeId, - @RequestBody ClubFeePaymentUpdateRequest clubFeePaymentUpdateRequest) { - - ClubFeePaymentUpdateResponse clubFeePaymentUpdateResponse = clubFeeService.updateClubFeePaymentInfo(customOAuth2Member, clubId, feeTypeId, clubFeePaymentUpdateRequest); - return ResponseEntity.ok(clubFeePaymentUpdateResponse); - } - - - - - - - + private final ClubFeeService clubFeeService; + + @GetMapping("") + @Operation(summary = "동아리 회비 종류 전체 요약 조회", description = "동아리 회비의 종류 전체를 요약해서 조회합니다.(정기회비, 이벤트회비 등)") + public ResponseEntity findAllClubFeesSummary( + @AuthenticationPrincipal CustomOAuth2Member customOAuth2Member, @PathVariable("clubId") Long clubId) { + ClubFeeSummaryResponseList clubFeeSummaryResponseList = clubFeeService.findAllClubFeeTypesSummary( + customOAuth2Member, clubId); + return ResponseEntity.ok(clubFeeSummaryResponseList); + } + + @PostMapping("") + @Operation(summary = "동아리 회비 등록", description = "동아리 회비를 등록합니다.") + public ResponseEntity createClubFee( + @AuthenticationPrincipal CustomOAuth2Member customOAuth2Member, @PathVariable("clubId") Long clubId, + ClubFeeCreateRequest clubFeeCreateRequest) { + ClubFeeCreateResponse createdClubFee = clubFeeService.createFee(customOAuth2Member, clubId, + clubFeeCreateRequest); + return ResponseEntity.ok(createdClubFee); + } + + @GetMapping("/usages") + @Operation(summary = "동아리 회비 전체에 대한 사용내역 조회", description = "clubId를 지정하여 해당 동아리의 회비 사용내역 전체를 조회합니다.") + public ResponseEntity findAllClubFeeUsage( + @AuthenticationPrincipal CustomOAuth2Member customOAuth2Member, @PathVariable("clubId") Long clubId) { + ClubFeeUsageResponseList clubFeeUsageResponseList = clubFeeService.findAllClubFeeUsage(customOAuth2Member, + clubId); + return ResponseEntity.ok(clubFeeUsageResponseList); + } + + @GetMapping("/{feeTypeId}/usage") + @Operation(summary = "동아리 회비 하나에 대한 사용내역 조회", description = "회비의 id를 지정하여 해당하는 동아리 회비의 사용내역을 조회합니다.") + public ResponseEntity findAllClubFeeUsageByFeeTypeId( + @AuthenticationPrincipal CustomOAuth2Member customOAuth2Member, @PathVariable("clubId") Long clubId, + @PathVariable("feeTypeId") Long feeTypeId) { + ClubFeeUsageResponseList clubFeeUsageResponseList = clubFeeService.findAllClubFeeUsageByFeeTypeId( + customOAuth2Member, clubId, feeTypeId); + return ResponseEntity.ok(clubFeeUsageResponseList); + } + + @PostMapping("/{feeTypeId}/usage") + @Operation(summary = "동아리 회비 사용", description = "회비의 id를 지정하여 동아리 회비를 사용합니다.") + public ResponseEntity createClubFeeUsage( + @AuthenticationPrincipal CustomOAuth2Member customOAuth2Member, @PathVariable("clubId") Long clubId, + @PathVariable("feeTypeId") Long feeTypeId, ClubFeeUsageRequest clubFeeUsageRequest) { + ClubFeeUsageCreateResponse clubFeeUsage = clubFeeService.createClubFeeUsage(customOAuth2Member, clubId, + feeTypeId, clubFeeUsageRequest); + return ResponseEntity.ok(clubFeeUsage); + } + + @GetMapping("/{feeTypeId}/payment") + @Operation(summary = "동아리 회비 입금 현황 조회", description = "회비의 id를 지정하여 동아리의 입금 현황을 조회합니다.") + public ResponseEntity findClubFeePaymentInfo( + @AuthenticationPrincipal CustomOAuth2Member customOAuth2Member, + @PathVariable("clubId") Long clubId, + @PathVariable("feeTypeId") Long feeTypeId) { + ClubFeePaymentInfoResponseList clubFeePaymentInfo = clubFeeService.findClubFeePaymentInfo(customOAuth2Member, + clubId, feeTypeId); + return ResponseEntity.ok(clubFeePaymentInfo); + } + + @PatchMapping("/{feeTypeId}/payment") + @Operation(summary = "동아리 회비 입금 여부 수정", description = "동아리원의 회비 입금 여부를 수정합니다.") + public ResponseEntity updateClubFeePaymentInfo( + @AuthenticationPrincipal CustomOAuth2Member customOAuth2Member, + @PathVariable("clubId") Long clubId, + @PathVariable("feeTypeId") Long feeTypeId, + @RequestBody ClubFeePaymentUpdateRequest clubFeePaymentUpdateRequest) { + + ClubFeePaymentUpdateResponse clubFeePaymentUpdateResponse = clubFeeService.updateClubFeePaymentInfo( + customOAuth2Member, clubId, feeTypeId, clubFeePaymentUpdateRequest); + return ResponseEntity.ok(clubFeePaymentUpdateResponse); + } } diff --git a/src/main/java/com/cotato/squadus/api/fee/dto/ClubFeeCreateRequest.java b/src/main/java/com/cotato/squadus/api/fee/dto/ClubFeeCreateRequest.java index dcce663..e145f9d 100644 --- a/src/main/java/com/cotato/squadus/api/fee/dto/ClubFeeCreateRequest.java +++ b/src/main/java/com/cotato/squadus/api/fee/dto/ClubFeeCreateRequest.java @@ -1,18 +1,17 @@ package com.cotato.squadus.api.fee.dto; -import com.cotato.squadus.domain.club.common.entity.ClubMember; -import com.cotato.squadus.domain.club.fee.enums.FeeCategory; - import java.time.LocalDate; import java.util.List; +import com.cotato.squadus.domain.club.fee.enums.FeeCategory; + public record ClubFeeCreateRequest( - String feeTypeName, - Long price, - FeeCategory feeCategory, - LocalDate startDate, - LocalDate endDate, - List clubMemberIds, - String memo + String feeTypeName, + Long price, + FeeCategory feeCategory, + LocalDate startDate, + LocalDate endDate, + List clubMemberIds, + String memo ) { } diff --git a/src/main/java/com/cotato/squadus/api/fee/dto/ClubFeeCreateResponse.java b/src/main/java/com/cotato/squadus/api/fee/dto/ClubFeeCreateResponse.java index 92195e4..5bad7fe 100644 --- a/src/main/java/com/cotato/squadus/api/fee/dto/ClubFeeCreateResponse.java +++ b/src/main/java/com/cotato/squadus/api/fee/dto/ClubFeeCreateResponse.java @@ -1,6 +1,6 @@ package com.cotato.squadus.api.fee.dto; public record ClubFeeCreateResponse( - Long feeTypeId + Long feeTypeId ) { } diff --git a/src/main/java/com/cotato/squadus/api/fee/dto/ClubFeePaymentInfoResponse.java b/src/main/java/com/cotato/squadus/api/fee/dto/ClubFeePaymentInfoResponse.java index 7bf1bff..3d90495 100644 --- a/src/main/java/com/cotato/squadus/api/fee/dto/ClubFeePaymentInfoResponse.java +++ b/src/main/java/com/cotato/squadus/api/fee/dto/ClubFeePaymentInfoResponse.java @@ -3,19 +3,19 @@ import com.cotato.squadus.domain.club.fee.entity.FeePayment; public record ClubFeePaymentInfoResponse( - Long clubMemberIdx, - String name, - String profileImage, - Boolean isPaid, - Boolean isUser + Long clubMemberIdx, + String name, + String profileImage, + Boolean isPaid, + Boolean isUser ) { - public static ClubFeePaymentInfoResponse from(FeePayment feePayment, Boolean isUser) { - return new ClubFeePaymentInfoResponse( - feePayment.getClubMember().getClubMemberIdx(), - feePayment.getClubMember().getMember().getUsername(), - feePayment.getClubMember().getMember().getProfileImage(), - feePayment.getIsPaid(), - isUser - ); - } + public static ClubFeePaymentInfoResponse from(FeePayment feePayment, Boolean isUser) { + return new ClubFeePaymentInfoResponse( + feePayment.getClubMember().getClubMemberIdx(), + feePayment.getClubMember().getMember().getUsername(), + feePayment.getClubMember().getMember().getProfileImage(), + feePayment.getIsPaid(), + isUser + ); + } } diff --git a/src/main/java/com/cotato/squadus/api/fee/dto/ClubFeePaymentInfoResponseList.java b/src/main/java/com/cotato/squadus/api/fee/dto/ClubFeePaymentInfoResponseList.java index 44c8384..b4166e0 100644 --- a/src/main/java/com/cotato/squadus/api/fee/dto/ClubFeePaymentInfoResponseList.java +++ b/src/main/java/com/cotato/squadus/api/fee/dto/ClubFeePaymentInfoResponseList.java @@ -3,9 +3,9 @@ import java.util.List; public record ClubFeePaymentInfoResponseList( - List clubFeePaymentInfoResponseList + List clubFeePaymentInfoResponseList ) { - public static ClubFeePaymentInfoResponseList from(List clubFeePaymentInfoResponseList) { - return new ClubFeePaymentInfoResponseList(clubFeePaymentInfoResponseList); - } + public static ClubFeePaymentInfoResponseList from(List clubFeePaymentInfoResponseList) { + return new ClubFeePaymentInfoResponseList(clubFeePaymentInfoResponseList); + } } diff --git a/src/main/java/com/cotato/squadus/api/fee/dto/ClubFeePaymentUpdateRequest.java b/src/main/java/com/cotato/squadus/api/fee/dto/ClubFeePaymentUpdateRequest.java index c165762..39ccfbe 100644 --- a/src/main/java/com/cotato/squadus/api/fee/dto/ClubFeePaymentUpdateRequest.java +++ b/src/main/java/com/cotato/squadus/api/fee/dto/ClubFeePaymentUpdateRequest.java @@ -1,7 +1,8 @@ package com.cotato.squadus.api.fee.dto; + import java.util.Map; public record ClubFeePaymentUpdateRequest( - Map paymentsInfo + Map paymentsInfo ) { } diff --git a/src/main/java/com/cotato/squadus/api/fee/dto/ClubFeePaymentUpdateResponse.java b/src/main/java/com/cotato/squadus/api/fee/dto/ClubFeePaymentUpdateResponse.java index 642f779..ba716e4 100644 --- a/src/main/java/com/cotato/squadus/api/fee/dto/ClubFeePaymentUpdateResponse.java +++ b/src/main/java/com/cotato/squadus/api/fee/dto/ClubFeePaymentUpdateResponse.java @@ -1,6 +1,6 @@ package com.cotato.squadus.api.fee.dto; public record ClubFeePaymentUpdateResponse( - Long feeTypeId + Long feeTypeId ) { } diff --git a/src/main/java/com/cotato/squadus/api/fee/dto/ClubFeeSummaryResponse.java b/src/main/java/com/cotato/squadus/api/fee/dto/ClubFeeSummaryResponse.java index 09c8e6c..68cef9d 100644 --- a/src/main/java/com/cotato/squadus/api/fee/dto/ClubFeeSummaryResponse.java +++ b/src/main/java/com/cotato/squadus/api/fee/dto/ClubFeeSummaryResponse.java @@ -1,27 +1,27 @@ package com.cotato.squadus.api.fee.dto; +import java.time.LocalDate; + import com.cotato.squadus.domain.club.fee.entity.FeeType; import com.cotato.squadus.domain.club.fee.enums.FeeCategory; -import java.time.LocalDate; - public record ClubFeeSummaryResponse( - Long feeTypeId, - String feeTypeName, - FeeCategory feeCategory, - Long price, - Long balance, - LocalDate endDate + Long feeTypeId, + String feeTypeName, + FeeCategory feeCategory, + Long price, + Long balance, + LocalDate endDate ) { - public static ClubFeeSummaryResponse from(FeeType feeType) { - return new ClubFeeSummaryResponse( - feeType.getFeeTypeId(), - feeType.getFeeTypeName(), - feeType.getFeeCategory(), - feeType.getPrice(), - feeType.getBalance(), - feeType.getEndDate() - ); - } + public static ClubFeeSummaryResponse from(FeeType feeType) { + return new ClubFeeSummaryResponse( + feeType.getFeeTypeId(), + feeType.getFeeTypeName(), + feeType.getFeeCategory(), + feeType.getPrice(), + feeType.getBalance(), + feeType.getEndDate() + ); + } } diff --git a/src/main/java/com/cotato/squadus/api/fee/dto/ClubFeeSummaryResponseList.java b/src/main/java/com/cotato/squadus/api/fee/dto/ClubFeeSummaryResponseList.java index 8fee7d5..0917c1b 100644 --- a/src/main/java/com/cotato/squadus/api/fee/dto/ClubFeeSummaryResponseList.java +++ b/src/main/java/com/cotato/squadus/api/fee/dto/ClubFeeSummaryResponseList.java @@ -3,11 +3,12 @@ import java.util.List; public record ClubFeeSummaryResponseList( - Long totalBalance, - List clubFeeSummaryResponseList + Long totalBalance, + List clubFeeSummaryResponseList ) { - public static ClubFeeSummaryResponseList from(Long totalBalance, List clubFeeSummaryResponseList) { - return new ClubFeeSummaryResponseList(totalBalance, clubFeeSummaryResponseList); - } + public static ClubFeeSummaryResponseList from(Long totalBalance, + List clubFeeSummaryResponseList) { + return new ClubFeeSummaryResponseList(totalBalance, clubFeeSummaryResponseList); + } } diff --git a/src/main/java/com/cotato/squadus/api/fee/dto/ClubFeeUsageCreateResponse.java b/src/main/java/com/cotato/squadus/api/fee/dto/ClubFeeUsageCreateResponse.java index 400db32..c2a9ab3 100644 --- a/src/main/java/com/cotato/squadus/api/fee/dto/ClubFeeUsageCreateResponse.java +++ b/src/main/java/com/cotato/squadus/api/fee/dto/ClubFeeUsageCreateResponse.java @@ -1,6 +1,6 @@ package com.cotato.squadus.api.fee.dto; public record ClubFeeUsageCreateResponse( - Long feeUsageId + Long feeUsageId ) { } diff --git a/src/main/java/com/cotato/squadus/api/fee/dto/ClubFeeUsageRequest.java b/src/main/java/com/cotato/squadus/api/fee/dto/ClubFeeUsageRequest.java index 7fc94e3..2f1d802 100644 --- a/src/main/java/com/cotato/squadus/api/fee/dto/ClubFeeUsageRequest.java +++ b/src/main/java/com/cotato/squadus/api/fee/dto/ClubFeeUsageRequest.java @@ -3,8 +3,8 @@ import java.time.LocalDate; public record ClubFeeUsageRequest( - String description, - LocalDate usedAt, - Long price + String description, + LocalDate usedAt, + Long price ) { } diff --git a/src/main/java/com/cotato/squadus/api/fee/dto/ClubFeeUsageResponse.java b/src/main/java/com/cotato/squadus/api/fee/dto/ClubFeeUsageResponse.java index 13bcadd..d275f06 100644 --- a/src/main/java/com/cotato/squadus/api/fee/dto/ClubFeeUsageResponse.java +++ b/src/main/java/com/cotato/squadus/api/fee/dto/ClubFeeUsageResponse.java @@ -1,24 +1,24 @@ package com.cotato.squadus.api.fee.dto; -import com.cotato.squadus.domain.club.fee.entity.FeeUsage; - import java.time.LocalDate; +import com.cotato.squadus.domain.club.fee.entity.FeeUsage; + public record ClubFeeUsageResponse( - Long feeTypeId, - Long feeUsageId, - LocalDate usedAt, - String description, - Long price + Long feeTypeId, + Long feeUsageId, + LocalDate usedAt, + String description, + Long price ) { - public static ClubFeeUsageResponse from(FeeUsage feeUsage) { - return new ClubFeeUsageResponse( - feeUsage.getFeeType().getFeeTypeId(), - feeUsage.getFeeUsageId(), - feeUsage.getUsedAt(), - feeUsage.getDescription(), - feeUsage.getPrice() - ); - } + public static ClubFeeUsageResponse from(FeeUsage feeUsage) { + return new ClubFeeUsageResponse( + feeUsage.getFeeType().getFeeTypeId(), + feeUsage.getFeeUsageId(), + feeUsage.getUsedAt(), + feeUsage.getDescription(), + feeUsage.getPrice() + ); + } } diff --git a/src/main/java/com/cotato/squadus/api/fee/dto/ClubFeeUsageResponseList.java b/src/main/java/com/cotato/squadus/api/fee/dto/ClubFeeUsageResponseList.java index f84681a..f9c80fc 100644 --- a/src/main/java/com/cotato/squadus/api/fee/dto/ClubFeeUsageResponseList.java +++ b/src/main/java/com/cotato/squadus/api/fee/dto/ClubFeeUsageResponseList.java @@ -3,9 +3,10 @@ import java.util.List; public record ClubFeeUsageResponseList( - List dateGroupedClubFeeUsageResponseList + List dateGroupedClubFeeUsageResponseList ) { - public static ClubFeeUsageResponseList from(List dateGroupedClubFeeUsageResponseList) { - return new ClubFeeUsageResponseList(dateGroupedClubFeeUsageResponseList); - } + public static ClubFeeUsageResponseList from( + List dateGroupedClubFeeUsageResponseList) { + return new ClubFeeUsageResponseList(dateGroupedClubFeeUsageResponseList); + } } diff --git a/src/main/java/com/cotato/squadus/api/fee/dto/DateGroupedClubFeeUsageResponse.java b/src/main/java/com/cotato/squadus/api/fee/dto/DateGroupedClubFeeUsageResponse.java index cc6b5cd..5481274 100644 --- a/src/main/java/com/cotato/squadus/api/fee/dto/DateGroupedClubFeeUsageResponse.java +++ b/src/main/java/com/cotato/squadus/api/fee/dto/DateGroupedClubFeeUsageResponse.java @@ -4,7 +4,7 @@ import java.util.List; public record DateGroupedClubFeeUsageResponse( - LocalDate date, - List usages + LocalDate date, + List usages ) { } diff --git a/src/main/java/com/cotato/squadus/api/match/controller/MatchController.java b/src/main/java/com/cotato/squadus/api/match/controller/MatchController.java index 5d8faca..a1f4426 100644 --- a/src/main/java/com/cotato/squadus/api/match/controller/MatchController.java +++ b/src/main/java/com/cotato/squadus/api/match/controller/MatchController.java @@ -1,20 +1,30 @@ package com.cotato.squadus.api.match.controller; -import com.cotato.squadus.api.match.dto.matchPost.request.*; +import java.util.List; + +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Pageable; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import com.cotato.squadus.api.match.dto.matchPost.request.FilterRequest; +import com.cotato.squadus.api.match.dto.matchPost.request.MatchCreateRequest; +import com.cotato.squadus.api.match.dto.matchPost.request.MatchRequestRequest; +import com.cotato.squadus.api.match.dto.matchPost.request.SearchRequest; import com.cotato.squadus.api.match.dto.matchPost.response.MatchCreateResponse; import com.cotato.squadus.api.match.dto.matchPost.response.MatchCreateResponseWrapper; import com.cotato.squadus.api.match.dto.matchPost.response.MatchRequestResponse; import com.cotato.squadus.domain.club.match.service.match.MatchService; + import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; import lombok.RequiredArgsConstructor; -import org.springframework.data.domain.Page; -import org.springframework.data.domain.PageRequest; -import org.springframework.data.domain.Pageable; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.*; - -import java.util.List; @Tag(name = "매치", description = "매칭 관련 API") @RestController @@ -22,55 +32,55 @@ @RequiredArgsConstructor public class MatchController { - private final MatchService matchService; + private final MatchService matchService; - @PostMapping - @Operation(summary = "매칭 생성", description = "매칭 게시글을 생성합니다.") - public ResponseEntity createMatch(@RequestBody MatchCreateRequest matchCreateRequest) { - MatchCreateResponse response = matchService.createMatch(matchCreateRequest); - return ResponseEntity.ok(response); - } + @PostMapping + @Operation(summary = "매칭 생성", description = "매칭 게시글을 생성합니다.") + public ResponseEntity createMatch(@RequestBody MatchCreateRequest matchCreateRequest) { + MatchCreateResponse response = matchService.createMatch(matchCreateRequest); + return ResponseEntity.ok(response); + } - @GetMapping - @Operation(summary = "모든 매칭 조회", description = "모든 매칭 게시글을 조회합니다.") - public ResponseEntity getAllMatches() { - List responses = matchService.findAllMatches(); - return ResponseEntity.ok(MatchCreateResponseWrapper.from(responses)); - } + @GetMapping + @Operation(summary = "모든 매칭 조회", description = "모든 매칭 게시글을 조회합니다.") + public ResponseEntity getAllMatches() { + List responses = matchService.findAllMatches(); + return ResponseEntity.ok(MatchCreateResponseWrapper.from(responses)); + } - @GetMapping("/paged") - @Operation(summary = "모든 매칭 조회 (페이징)", description = "모든 매칭 게시글을 페이징 처리하여 조회합니다.") - public ResponseEntity getAllMatchesPaged( - @RequestParam(defaultValue = "0") int page, - @RequestParam(defaultValue = "10") int size) { - Pageable pageable = PageRequest.of(page, size); - Page responses = matchService.findAllMatches(pageable); - return ResponseEntity.ok(MatchCreateResponseWrapper.from(responses)); - } + @GetMapping("/paged") + @Operation(summary = "모든 매칭 조회 (페이징)", description = "모든 매칭 게시글을 페이징 처리하여 조회합니다.") + public ResponseEntity getAllMatchesPaged( + @RequestParam(defaultValue = "0") int page, + @RequestParam(defaultValue = "10") int size) { + Pageable pageable = PageRequest.of(page, size); + Page responses = matchService.findAllMatches(pageable); + return ResponseEntity.ok(MatchCreateResponseWrapper.from(responses)); + } - //필터 4개를 한 번에 조회 가능. 필터를 하지 않는 부분은 null로 reqeust해주면 자동으로 필터링 해줌 - @PostMapping("/filter") - @Operation(summary = "필터링된 매칭 조회", description = "필터를 적용하여 용병 매칭 게시글을 조회합니다. 필터 4개를 한번에 조회할 수 있습니다. 필터를 하지 않는 부분은 null로 reqeust해주면 자동으로 필터링을 진행한다.") - public ResponseEntity getMatchesByFilter( - @RequestBody FilterRequest filterRequest, - @RequestParam Long clubMemberId) { - List responses = matchService.getFilteredMatches(filterRequest, clubMemberId); - return ResponseEntity.ok(MatchCreateResponseWrapper.from(responses)); - } + //필터 4개를 한 번에 조회 가능. 필터를 하지 않는 부분은 null로 reqeust해주면 자동으로 필터링 해줌 + @PostMapping("/filter") + @Operation(summary = "필터링된 매칭 조회", description = "필터를 적용하여 용병 매칭 게시글을 조회합니다. 필터 4개를 한번에 조회할 수 있습니다. 필터를 하지 않는 부분은 null로 reqeust해주면 자동으로 필터링을 진행한다.") + public ResponseEntity getMatchesByFilter( + @RequestBody FilterRequest filterRequest, + @RequestParam Long clubMemberId) { + List responses = matchService.getFilteredMatches(filterRequest, clubMemberId); + return ResponseEntity.ok(MatchCreateResponseWrapper.from(responses)); + } - @PostMapping("/search") - @Operation(summary = "매칭 검색", description = "검색어를 바탕으로 매칭 게시글을 조회합니다.") - public ResponseEntity searchMatches( - @RequestBody SearchRequest searchRequest, - @RequestParam Long clubMemberId) { - List responses = matchService.searchMatches(searchRequest, clubMemberId); - return ResponseEntity.ok(MatchCreateResponseWrapper.from(responses)); - } + @PostMapping("/search") + @Operation(summary = "매칭 검색", description = "검색어를 바탕으로 매칭 게시글을 조회합니다.") + public ResponseEntity searchMatches( + @RequestBody SearchRequest searchRequest, + @RequestParam Long clubMemberId) { + List responses = matchService.searchMatches(searchRequest, clubMemberId); + return ResponseEntity.ok(MatchCreateResponseWrapper.from(responses)); + } - @PostMapping("/request") - @Operation(summary = "매칭 요청", description = "특정 매칭 게시글에 대해 매칭 요청을 보냅니다.") - public ResponseEntity sendMatchRequest(@RequestBody MatchRequestRequest matchRequestRequest) { - MatchRequestResponse response = matchService.sendMatchRequest(matchRequestRequest); - return ResponseEntity.ok(response); - } + @PostMapping("/request") + @Operation(summary = "매칭 요청", description = "특정 매칭 게시글에 대해 매칭 요청을 보냅니다.") + public ResponseEntity sendMatchRequest(@RequestBody MatchRequestRequest matchRequestRequest) { + MatchRequestResponse response = matchService.sendMatchRequest(matchRequestRequest); + return ResponseEntity.ok(response); + } } diff --git a/src/main/java/com/cotato/squadus/api/match/controller/MatchRequestController.java b/src/main/java/com/cotato/squadus/api/match/controller/MatchRequestController.java index cba777b..3a4fae0 100644 --- a/src/main/java/com/cotato/squadus/api/match/controller/MatchRequestController.java +++ b/src/main/java/com/cotato/squadus/api/match/controller/MatchRequestController.java @@ -1,20 +1,34 @@ package com.cotato.squadus.api.match.controller; +import java.util.List; + +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Pageable; +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.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + import com.cotato.squadus.api.match.dto.matchPost.request.MatchCreateRequest; -import com.cotato.squadus.api.match.dto.matchPost.response.*; +import com.cotato.squadus.api.match.dto.matchPost.response.MatchCreateResponse; +import com.cotato.squadus.api.match.dto.matchPost.response.MatchRequestAndMatchPostResponse; +import com.cotato.squadus.api.match.dto.matchPost.response.MatchRequestAndMatchPostResponseWrapper; +import com.cotato.squadus.api.match.dto.matchPost.response.MatchRequestResponse; +import com.cotato.squadus.api.match.dto.matchPost.response.MatchRequestResponseWrapper; import com.cotato.squadus.domain.club.match.service.match.MatchRequestService; import com.cotato.squadus.domain.club.match.service.match.MatchService; + import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.springframework.data.domain.Page; -import org.springframework.data.domain.PageRequest; -import org.springframework.data.domain.Pageable; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.*; - -import java.util.List; @RestController @RequestMapping("/v1/api/match-requests") @@ -23,81 +37,83 @@ @Tag(name = "매칭 요청", description = "매칭 요청 관련 API") public class MatchRequestController { - private final MatchRequestService matchRequestService; - private final MatchService matchService; - - //신청한 내역 기능 - 동아리 단위의 신청 - @GetMapping("/paged") - @Operation(summary = "내 동아리에서 신청한 매치 목록 조회 (페이징)", description = "내 동아리에서 신청한 매칭 글 목록을 페이징 처리하여 조회합니다.") - public ResponseEntity getMyClubMatchRequests( - @RequestParam Long clubId, - @RequestParam(defaultValue = "0") int page, - @RequestParam(defaultValue = "10") int size) { - Pageable pageable = PageRequest.of(page, size); - Page responses = matchRequestService.getMyClubMatchRequests(clubId, pageable); - return ResponseEntity.ok(MatchRequestResponseWrapper.from(responses)); - } - - @GetMapping - @Operation(summary = "내 동아리에서 신청한 매치 목록 조회 (전체)", description = "내 동아리에서 신청한 매칭 글 목록을 페이징 없이 전체 조회합니다.") - public ResponseEntity getAllMyClubMatchRequests(@RequestParam Long clubId) { - List responses = matchRequestService.getAllMyClubMatchRequests(clubId); - return ResponseEntity.ok(MatchRequestResponseWrapper.from(responses)); - } + private final MatchRequestService matchRequestService; + private final MatchService matchService; - @DeleteMapping("/{requestId}") - @Operation(summary = "매칭 요청 취소", description = "특정 동아리의 임원이 요청한 매칭 요청을 취소합니다.") - public ResponseEntity cancelMatchRequest(@PathVariable Long requestId, @RequestParam Long clubMemberId) { - matchRequestService.cancelMatchRequest(requestId, clubMemberId); - return ResponseEntity.noContent().build(); - } + //신청한 내역 기능 - 동아리 단위의 신청 + @GetMapping("/paged") + @Operation(summary = "내 동아리에서 신청한 매치 목록 조회 (페이징)", description = "내 동아리에서 신청한 매칭 글 목록을 페이징 처리하여 조회합니다.") + public ResponseEntity getMyClubMatchRequests( + @RequestParam Long clubId, + @RequestParam(defaultValue = "0") int page, + @RequestParam(defaultValue = "10") int size) { + Pageable pageable = PageRequest.of(page, size); + Page responses = matchRequestService.getMyClubMatchRequests(clubId, pageable); + return ResponseEntity.ok(MatchRequestResponseWrapper.from(responses)); + } + @GetMapping + @Operation(summary = "내 동아리에서 신청한 매치 목록 조회 (전체)", description = "내 동아리에서 신청한 매칭 글 목록을 페이징 없이 전체 조회합니다.") + public ResponseEntity getAllMyClubMatchRequests(@RequestParam Long clubId) { + List responses = matchRequestService.getAllMyClubMatchRequests(clubId); + return ResponseEntity.ok(MatchRequestResponseWrapper.from(responses)); + } - //신청 받은 내역 기능 - @GetMapping("/received/paged") - @Operation(summary = "내 동아리가 받은 매칭 요청 목록 조회 (페이징)", description = "내 동아리가 받은 매칭 요청 목록을 페이징 처리하여 조회합니다.") - public ResponseEntity getReceivedMatchRequests( - @RequestParam Long clubId, - @RequestParam(defaultValue = "0") int page, - @RequestParam(defaultValue = "10") int size) { - Pageable pageable = PageRequest.of(page, size); - Page responses = matchRequestService.getReceivedMatchRequests(clubId, pageable); - MatchRequestAndMatchPostResponseWrapper wrapper = MatchRequestAndMatchPostResponseWrapper.from(responses.getContent()); - return ResponseEntity.ok(wrapper); - } + @DeleteMapping("/{requestId}") + @Operation(summary = "매칭 요청 취소", description = "특정 동아리의 임원이 요청한 매칭 요청을 취소합니다.") + public ResponseEntity cancelMatchRequest(@PathVariable Long requestId, @RequestParam Long clubMemberId) { + matchRequestService.cancelMatchRequest(requestId, clubMemberId); + return ResponseEntity.noContent().build(); + } - @GetMapping("/received") - @Operation(summary = "내 동아리가 받은 매칭 요청 목록 조회 (전체)", description = "내 동아리가 받은 매칭 요청 목록을 페이징 없이 전체 조회합니다.") - public ResponseEntity getAllReceivedMatchRequests(@RequestParam Long clubId) { - List responses = matchRequestService.getAllReceivedMatchRequests(clubId); - MatchRequestAndMatchPostResponseWrapper wrapper = MatchRequestAndMatchPostResponseWrapper.from(responses); - return ResponseEntity.ok(wrapper); - } + //신청 받은 내역 기능 + @GetMapping("/received/paged") + @Operation(summary = "내 동아리가 받은 매칭 요청 목록 조회 (페이징)", description = "내 동아리가 받은 매칭 요청 목록을 페이징 처리하여 조회합니다.") + public ResponseEntity getReceivedMatchRequests( + @RequestParam Long clubId, + @RequestParam(defaultValue = "0") int page, + @RequestParam(defaultValue = "10") int size) { + Pageable pageable = PageRequest.of(page, size); + Page responses = matchRequestService.getReceivedMatchRequests(clubId, + pageable); + MatchRequestAndMatchPostResponseWrapper wrapper = MatchRequestAndMatchPostResponseWrapper.from( + responses.getContent()); + return ResponseEntity.ok(wrapper); + } + @GetMapping("/received") + @Operation(summary = "내 동아리가 받은 매칭 요청 목록 조회 (전체)", description = "내 동아리가 받은 매칭 요청 목록을 페이징 없이 전체 조회합니다.") + public ResponseEntity getAllReceivedMatchRequests( + @RequestParam Long clubId) { + List responses = matchRequestService.getAllReceivedMatchRequests(clubId); + MatchRequestAndMatchPostResponseWrapper wrapper = MatchRequestAndMatchPostResponseWrapper.from(responses); + return ResponseEntity.ok(wrapper); + } - @PostMapping("/{requestId}/decision") - @Operation(summary = "매칭 요청 승낙/거절", description = "특정 동아리의 임원이 받은 매칭 요청에 대해 승낙 또는 거절을 합니다.") - public ResponseEntity decideMatchRequest(@PathVariable Long requestId, @RequestParam String decision, @RequestParam Long clubMemberId) { - matchRequestService.decideMatchRequest(requestId, decision, clubMemberId); - return ResponseEntity.noContent().build(); - } + @PostMapping("/{requestId}/decision") + @Operation(summary = "매칭 요청 승낙/거절", description = "특정 동아리의 임원이 받은 매칭 요청에 대해 승낙 또는 거절을 합니다.") + public ResponseEntity decideMatchRequest(@PathVariable Long requestId, @RequestParam String decision, + @RequestParam Long clubMemberId) { + matchRequestService.decideMatchRequest(requestId, decision, clubMemberId); + return ResponseEntity.noContent().build(); + } - @PutMapping("/{matchIdx}") - @Operation(summary = "매칭 게시글 수정", description = "특정 매칭 게시글을 수정합니다.") - public ResponseEntity updateMatchPost( - @PathVariable Long matchIdx, - @RequestBody MatchCreateRequest matchCreateRequest) { - MatchCreateResponse response = matchService.updateMatchPost(matchIdx, matchCreateRequest); - return ResponseEntity.ok(response); - } + @PutMapping("/{matchIdx}") + @Operation(summary = "매칭 게시글 수정", description = "특정 매칭 게시글을 수정합니다.") + public ResponseEntity updateMatchPost( + @PathVariable Long matchIdx, + @RequestBody MatchCreateRequest matchCreateRequest) { + MatchCreateResponse response = matchService.updateMatchPost(matchIdx, matchCreateRequest); + return ResponseEntity.ok(response); + } - @DeleteMapping("/{matchIdx}/delete") - @Operation(summary = "매칭 게시글 삭제", description = "특정 매칭 게시글을 삭제합니다.") - public ResponseEntity deleteMatchPost( - @PathVariable Long matchIdx, - @RequestParam Long clubMemberId) { - matchService.deleteMatchPost(matchIdx, clubMemberId); - return ResponseEntity.noContent().build(); - } + @DeleteMapping("/{matchIdx}/delete") + @Operation(summary = "매칭 게시글 삭제", description = "특정 매칭 게시글을 삭제합니다.") + public ResponseEntity deleteMatchPost( + @PathVariable Long matchIdx, + @RequestParam Long clubMemberId) { + matchService.deleteMatchPost(matchIdx, clubMemberId); + return ResponseEntity.noContent().build(); + } } diff --git a/src/main/java/com/cotato/squadus/api/match/controller/MatchResultController.java b/src/main/java/com/cotato/squadus/api/match/controller/MatchResultController.java index d1eee59..c4c6003 100644 --- a/src/main/java/com/cotato/squadus/api/match/controller/MatchResultController.java +++ b/src/main/java/com/cotato/squadus/api/match/controller/MatchResultController.java @@ -1,16 +1,25 @@ package com.cotato.squadus.api.match.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 org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + import com.cotato.squadus.api.match.dto.matchResult.request.MatchResultAddRequest; import com.cotato.squadus.api.match.dto.matchResult.response.MatchDetailResponse; import com.cotato.squadus.api.match.dto.matchResult.response.MatchDetailWithWinResponse; import com.cotato.squadus.api.match.dto.matchResult.response.MatchFinalResultResponse; import com.cotato.squadus.api.match.dto.matchResult.response.MatchResultResponse; import com.cotato.squadus.domain.club.match.service.match.MatchResultService; + import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; import lombok.RequiredArgsConstructor; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.*; @Tag(name = "매치 결과", description = "매칭 결과 관련 API") @RestController @@ -18,78 +27,77 @@ @RequiredArgsConstructor public class MatchResultController { - private final MatchResultService matchResultService; - - @GetMapping("/{matchPostId}/details") - @Operation(summary = "매칭 상세보기", description = "매칭이 승낙된 두 동아리의 상세 정보를 조회합니다.(매칭 확정 상세 페이지") - public ResponseEntity getMatchDetail(@PathVariable Long matchPostId) { - MatchDetailResponse response = matchResultService.getMatchDetail(matchPostId); - return ResponseEntity.ok(response); - } - - @GetMapping("/{matchPostId}/details-with-win") - @Operation(summary = "매칭 상세보기 및 승리 정보", description = "매칭이 승낙된 두 동아리의 상세 정보와 승리 횟수를 조회합니다.") - public ResponseEntity getMatchDetailWithWin(@PathVariable Long matchPostId) { - MatchDetailResponse matchDetailResponse = matchResultService.getMatchDetail(matchPostId); - MatchFinalResultResponse matchFinalResultResponse = matchResultService.getWinningMatchResult(matchPostId); - - MatchDetailWithWinResponse response = new MatchDetailWithWinResponse(matchDetailResponse, matchFinalResultResponse); - return ResponseEntity.ok(response); - } - - - @PostMapping("/{matchPostId}/add-result") - @Operation(summary = "매치 결과 추가", description = "경기 결과를 추가합니다. MatchPost를 작성한 Club의 임원만 추가 가능합니다.") - public ResponseEntity addMatchResult(@PathVariable Long matchPostId, @RequestBody MatchResultAddRequest matchResultAddRequest) { - MatchResultResponse matchResult = matchResultService.addMatchResult(matchPostId, matchResultAddRequest); - return ResponseEntity.ok(matchResult); - } - - @PutMapping("/{matchResultId}/update-result") - @Operation(summary = "매치 결과 수정", description = "경기 결과를 수정합니다. MatchPost 작성 Club의 임원만 수정 가능합니다.") - public ResponseEntity updateMatchResult( - @PathVariable Long matchResultId, - @RequestBody MatchResultAddRequest matchResultAddRequest) { - MatchResultResponse matchResult = matchResultService.updateMatchResult(matchResultId, matchResultAddRequest); - return ResponseEntity.ok(matchResult); - } - - - @GetMapping("/{matchPostId}/final-result") - @Operation(summary = "매치 승리 결과", description = "매치의 최종 승리 결과를 가져옵니다. MatchPost를 작성한 Club의 임원만 추가 가능합니다. '모든 경기 입력 완료' 버튼") - public ResponseEntity getFinalMatchResult(@PathVariable Long matchPostId, @RequestParam Long clubMemberId) { - MatchFinalResultResponse response = matchResultService.getFinalMatchResult(matchPostId, clubMemberId); - return ResponseEntity.ok(response); - } - - - @PostMapping("/{matchPostId}/finalize-home") - @Operation(summary = "홈팀 경기 결과 확정", description = "홈팀이 경기 결과를 확정하고 점수를 반영합니다. MatchPost 작성 Club의 임원만 추가 가능합니다. ") - public ResponseEntity finalizeHomeMatch( - @PathVariable Long matchPostId, - @RequestParam Long clubMemberId) { - matchResultService.finalizeHomeResult(matchPostId, clubMemberId); - return ResponseEntity.noContent().build(); - } - - - @PostMapping("/{matchPostId}/finalize-away") - @Operation(summary = "어웨이팀 경기 결과 확정", description = "어웨이팀이 경기 결과를 확정하고 점수를 반영합니다. Away Club의 임원만 추가 가능합니다.") - public ResponseEntity finalizeAwayMatch( - @PathVariable Long matchPostId, - @RequestParam Long clubMemberId) { - matchResultService.finalizeAwayResult(matchPostId, clubMemberId); - return ResponseEntity.noContent().build(); - } - - @PostMapping("/{matchPostId}/reject") - @Operation(summary = "경기 결과 거절", description = "경기 결과를 거절하고 수정 가능하게 만듭니다. Away Club의 임원만 추가 가능합니다.") - public ResponseEntity rejectFinalResult( - @PathVariable Long matchPostId, - @RequestParam Long clubMemberId) { - matchResultService.rejectFinalResult(matchPostId, clubMemberId); - return ResponseEntity.noContent().build(); - } + private final MatchResultService matchResultService; + + @GetMapping("/{matchPostId}/details") + @Operation(summary = "매칭 상세보기", description = "매칭이 승낙된 두 동아리의 상세 정보를 조회합니다.(매칭 확정 상세 페이지") + public ResponseEntity getMatchDetail(@PathVariable Long matchPostId) { + MatchDetailResponse response = matchResultService.getMatchDetail(matchPostId); + return ResponseEntity.ok(response); + } + + @GetMapping("/{matchPostId}/details-with-win") + @Operation(summary = "매칭 상세보기 및 승리 정보", description = "매칭이 승낙된 두 동아리의 상세 정보와 승리 횟수를 조회합니다.") + public ResponseEntity getMatchDetailWithWin(@PathVariable Long matchPostId) { + MatchDetailResponse matchDetailResponse = matchResultService.getMatchDetail(matchPostId); + MatchFinalResultResponse matchFinalResultResponse = matchResultService.getWinningMatchResult(matchPostId); + + MatchDetailWithWinResponse response = new MatchDetailWithWinResponse(matchDetailResponse, + matchFinalResultResponse); + return ResponseEntity.ok(response); + } + + @PostMapping("/{matchPostId}/add-result") + @Operation(summary = "매치 결과 추가", description = "경기 결과를 추가합니다. MatchPost를 작성한 Club의 임원만 추가 가능합니다.") + public ResponseEntity addMatchResult(@PathVariable Long matchPostId, + @RequestBody MatchResultAddRequest matchResultAddRequest) { + MatchResultResponse matchResult = matchResultService.addMatchResult(matchPostId, matchResultAddRequest); + return ResponseEntity.ok(matchResult); + } + + @PutMapping("/{matchResultId}/update-result") + @Operation(summary = "매치 결과 수정", description = "경기 결과를 수정합니다. MatchPost 작성 Club의 임원만 수정 가능합니다.") + public ResponseEntity updateMatchResult( + @PathVariable Long matchResultId, + @RequestBody MatchResultAddRequest matchResultAddRequest) { + MatchResultResponse matchResult = matchResultService.updateMatchResult(matchResultId, matchResultAddRequest); + return ResponseEntity.ok(matchResult); + } + + @GetMapping("/{matchPostId}/final-result") + @Operation(summary = "매치 승리 결과", description = "매치의 최종 승리 결과를 가져옵니다. MatchPost를 작성한 Club의 임원만 추가 가능합니다. '모든 경기 입력 완료' 버튼") + public ResponseEntity getFinalMatchResult(@PathVariable Long matchPostId, + @RequestParam Long clubMemberId) { + MatchFinalResultResponse response = matchResultService.getFinalMatchResult(matchPostId, clubMemberId); + return ResponseEntity.ok(response); + } + + @PostMapping("/{matchPostId}/finalize-home") + @Operation(summary = "홈팀 경기 결과 확정", description = "홈팀이 경기 결과를 확정하고 점수를 반영합니다. MatchPost 작성 Club의 임원만 추가 가능합니다. ") + public ResponseEntity finalizeHomeMatch( + @PathVariable Long matchPostId, + @RequestParam Long clubMemberId) { + matchResultService.finalizeHomeResult(matchPostId, clubMemberId); + return ResponseEntity.noContent().build(); + } + + @PostMapping("/{matchPostId}/finalize-away") + @Operation(summary = "어웨이팀 경기 결과 확정", description = "어웨이팀이 경기 결과를 확정하고 점수를 반영합니다. Away Club의 임원만 추가 가능합니다.") + public ResponseEntity finalizeAwayMatch( + @PathVariable Long matchPostId, + @RequestParam Long clubMemberId) { + matchResultService.finalizeAwayResult(matchPostId, clubMemberId); + return ResponseEntity.noContent().build(); + } + + @PostMapping("/{matchPostId}/reject") + @Operation(summary = "경기 결과 거절", description = "경기 결과를 거절하고 수정 가능하게 만듭니다. Away Club의 임원만 추가 가능합니다.") + public ResponseEntity rejectFinalResult( + @PathVariable Long matchPostId, + @RequestParam Long clubMemberId) { + matchResultService.rejectFinalResult(matchPostId, clubMemberId); + return ResponseEntity.noContent().build(); + } } diff --git a/src/main/java/com/cotato/squadus/api/match/dto/matchPost/request/FilterRequest.java b/src/main/java/com/cotato/squadus/api/match/dto/matchPost/request/FilterRequest.java index eb40512..659bd27 100644 --- a/src/main/java/com/cotato/squadus/api/match/dto/matchPost/request/FilterRequest.java +++ b/src/main/java/com/cotato/squadus/api/match/dto/matchPost/request/FilterRequest.java @@ -1,7 +1,5 @@ package com.cotato.squadus.api.match.dto.matchPost.request; -import com.cotato.squadus.domain.club.common.entity.Tier; -import com.cotato.squadus.domain.club.common.enums.SportsCategory; import lombok.Getter; import lombok.Setter; @@ -9,9 +7,9 @@ @Setter public class FilterRequest { - private String sportsCategory; - private String city; - private String district; - private String tier; - private Boolean placeProvided; + private String sportsCategory; + private String city; + private String district; + private String tier; + private Boolean placeProvided; } diff --git a/src/main/java/com/cotato/squadus/api/match/dto/matchPost/request/MatchCreateRequest.java b/src/main/java/com/cotato/squadus/api/match/dto/matchPost/request/MatchCreateRequest.java index 39d3edb..75c6945 100644 --- a/src/main/java/com/cotato/squadus/api/match/dto/matchPost/request/MatchCreateRequest.java +++ b/src/main/java/com/cotato/squadus/api/match/dto/matchPost/request/MatchCreateRequest.java @@ -1,34 +1,35 @@ package com.cotato.squadus.api.match.dto.matchPost.request; +import java.time.LocalDate; +import java.time.LocalTime; + import com.fasterxml.jackson.annotation.JsonFormat; + import io.swagger.v3.oas.annotations.media.Schema; import lombok.Getter; import lombok.Setter; -import java.time.LocalDate; -import java.time.LocalTime; - @Getter @Setter public class MatchCreateRequest { - private Long homeClubId; - private Long clubMemberId; - private String title; - private String content; - private String tier; - private MatchPlaceRequest matchPlace; - private Boolean placeProvided; - private LocalDate matchStartDate; + private Long homeClubId; + private Long clubMemberId; + private String title; + private String content; + private String tier; + private MatchPlaceRequest matchPlace; + private Boolean placeProvided; + private LocalDate matchStartDate; - @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "HH:mm") - @Schema(description = "Match start time in format HH:mm", example = "10:00") - private LocalTime matchStartTime; - private Integer maxParticipants; + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "HH:mm") + @Schema(description = "Match start time in format HH:mm", example = "10:00") + private LocalTime matchStartTime; + private Integer maxParticipants; - @Getter - @Setter - public static class MatchPlaceRequest { - private String city; - private String district; - } + @Getter + @Setter + public static class MatchPlaceRequest { + private String city; + private String district; + } } \ No newline at end of file diff --git a/src/main/java/com/cotato/squadus/api/match/dto/matchPost/request/MatchFinalizeRequest.java b/src/main/java/com/cotato/squadus/api/match/dto/matchPost/request/MatchFinalizeRequest.java index cb51079..d6fcd93 100644 --- a/src/main/java/com/cotato/squadus/api/match/dto/matchPost/request/MatchFinalizeRequest.java +++ b/src/main/java/com/cotato/squadus/api/match/dto/matchPost/request/MatchFinalizeRequest.java @@ -6,5 +6,5 @@ @Getter @Setter public class MatchFinalizeRequest { - private Long matchPostId; + private Long matchPostId; } diff --git a/src/main/java/com/cotato/squadus/api/match/dto/matchPost/request/MatchRequestRequest.java b/src/main/java/com/cotato/squadus/api/match/dto/matchPost/request/MatchRequestRequest.java index f6c1d73..3160d09 100644 --- a/src/main/java/com/cotato/squadus/api/match/dto/matchPost/request/MatchRequestRequest.java +++ b/src/main/java/com/cotato/squadus/api/match/dto/matchPost/request/MatchRequestRequest.java @@ -6,6 +6,6 @@ @Getter @Setter public class MatchRequestRequest { - private Long clubMemberId; - private Long matchPostId; + private Long clubMemberId; + private Long matchPostId; } \ No newline at end of file diff --git a/src/main/java/com/cotato/squadus/api/match/dto/matchPost/request/MatchResultRequest.java b/src/main/java/com/cotato/squadus/api/match/dto/matchPost/request/MatchResultRequest.java index 9e3f577..cb6f979 100644 --- a/src/main/java/com/cotato/squadus/api/match/dto/matchPost/request/MatchResultRequest.java +++ b/src/main/java/com/cotato/squadus/api/match/dto/matchPost/request/MatchResultRequest.java @@ -6,7 +6,7 @@ @Getter @Setter public class MatchResultRequest { - private Long matchPostId; - private Integer homeScore; - private Integer awayScore; + private Long matchPostId; + private Integer homeScore; + private Integer awayScore; } diff --git a/src/main/java/com/cotato/squadus/api/match/dto/matchPost/request/SearchRequest.java b/src/main/java/com/cotato/squadus/api/match/dto/matchPost/request/SearchRequest.java index 172c228..4ec22a6 100644 --- a/src/main/java/com/cotato/squadus/api/match/dto/matchPost/request/SearchRequest.java +++ b/src/main/java/com/cotato/squadus/api/match/dto/matchPost/request/SearchRequest.java @@ -6,5 +6,5 @@ @Getter @Setter public class SearchRequest { - private String keyword; + private String keyword; } diff --git a/src/main/java/com/cotato/squadus/api/match/dto/matchPost/response/MatchCreateResponse.java b/src/main/java/com/cotato/squadus/api/match/dto/matchPost/response/MatchCreateResponse.java index 7c77ea8..830e04f 100644 --- a/src/main/java/com/cotato/squadus/api/match/dto/matchPost/response/MatchCreateResponse.java +++ b/src/main/java/com/cotato/squadus/api/match/dto/matchPost/response/MatchCreateResponse.java @@ -1,40 +1,40 @@ package com.cotato.squadus.api.match.dto.matchPost.response; -import com.cotato.squadus.domain.club.match.entity.match.MatchPost; - import java.time.LocalDate; import java.time.LocalTime; +import com.cotato.squadus.domain.club.match.entity.match.MatchPost; + public record MatchCreateResponse( - Long matchIdx, - String title, - String content, - String tier, - MatchPlaceResponse matchPlace, - Boolean placeProvided, - LocalDate matchStartDate, - LocalTime matchStartTime, - Integer maxParticipants, - Long clubIdx, - String sportsCategory, - String clubName, - String clubLogo + Long matchIdx, + String title, + String content, + String tier, + MatchPlaceResponse matchPlace, + Boolean placeProvided, + LocalDate matchStartDate, + LocalTime matchStartTime, + Integer maxParticipants, + Long clubIdx, + String sportsCategory, + String clubName, + String clubLogo ) { - public static MatchCreateResponse from(MatchPost matchPost) { - return new MatchCreateResponse( - matchPost.getMatchIdx(), - matchPost.getTitle(), - matchPost.getContent(), - matchPost.getTier().name(), - MatchPlaceResponse.from(matchPost.getMatchPlace()), - matchPost.getPlaceProvided(), - matchPost.getMatchStartDate(), - matchPost.getMatchStartTime(), - matchPost.getMaxParticipants(), - matchPost.getHomeClub().getClubId(), - matchPost.getHomeClub().getSportsCategory().name(), - matchPost.getHomeClub().getClubName(), - matchPost.getHomeClub().getLogo() - ); - } + public static MatchCreateResponse from(MatchPost matchPost) { + return new MatchCreateResponse( + matchPost.getMatchIdx(), + matchPost.getTitle(), + matchPost.getContent(), + matchPost.getTier().name(), + MatchPlaceResponse.from(matchPost.getMatchPlace()), + matchPost.getPlaceProvided(), + matchPost.getMatchStartDate(), + matchPost.getMatchStartTime(), + matchPost.getMaxParticipants(), + matchPost.getHomeClub().getClubId(), + matchPost.getHomeClub().getSportsCategory().name(), + matchPost.getHomeClub().getClubName(), + matchPost.getHomeClub().getLogo() + ); + } } diff --git a/src/main/java/com/cotato/squadus/api/match/dto/matchPost/response/MatchCreateResponseWrapper.java b/src/main/java/com/cotato/squadus/api/match/dto/matchPost/response/MatchCreateResponseWrapper.java index 553b2ac..80dbed7 100644 --- a/src/main/java/com/cotato/squadus/api/match/dto/matchPost/response/MatchCreateResponseWrapper.java +++ b/src/main/java/com/cotato/squadus/api/match/dto/matchPost/response/MatchCreateResponseWrapper.java @@ -1,17 +1,17 @@ package com.cotato.squadus.api.match.dto.matchPost.response; -import org.springframework.data.domain.Page; - import java.util.List; +import org.springframework.data.domain.Page; + public record MatchCreateResponseWrapper( - List matches + List matches ) { - public static MatchCreateResponseWrapper from(List responses) { - return new MatchCreateResponseWrapper(responses); - } + public static MatchCreateResponseWrapper from(List responses) { + return new MatchCreateResponseWrapper(responses); + } - public static MatchCreateResponseWrapper from(Page responses) { - return new MatchCreateResponseWrapper(responses.getContent()); - } + public static MatchCreateResponseWrapper from(Page responses) { + return new MatchCreateResponseWrapper(responses.getContent()); + } } diff --git a/src/main/java/com/cotato/squadus/api/match/dto/matchPost/response/MatchPlaceResponse.java b/src/main/java/com/cotato/squadus/api/match/dto/matchPost/response/MatchPlaceResponse.java index e2ed7cd..f127430 100644 --- a/src/main/java/com/cotato/squadus/api/match/dto/matchPost/response/MatchPlaceResponse.java +++ b/src/main/java/com/cotato/squadus/api/match/dto/matchPost/response/MatchPlaceResponse.java @@ -3,13 +3,13 @@ import com.cotato.squadus.domain.club.match.entity.MatchPlace; public record MatchPlaceResponse( - String city, - String district + String city, + String district ) { - public static MatchPlaceResponse from(MatchPlace matchPlace) { - return new MatchPlaceResponse( - matchPlace.getCity(), - matchPlace.getDistrict() - ); - } + public static MatchPlaceResponse from(MatchPlace matchPlace) { + return new MatchPlaceResponse( + matchPlace.getCity(), + matchPlace.getDistrict() + ); + } } diff --git a/src/main/java/com/cotato/squadus/api/match/dto/matchPost/response/MatchRequestAndMatchPostResponse.java b/src/main/java/com/cotato/squadus/api/match/dto/matchPost/response/MatchRequestAndMatchPostResponse.java index 1232dad..1c8e6d5 100644 --- a/src/main/java/com/cotato/squadus/api/match/dto/matchPost/response/MatchRequestAndMatchPostResponse.java +++ b/src/main/java/com/cotato/squadus/api/match/dto/matchPost/response/MatchRequestAndMatchPostResponse.java @@ -1,20 +1,19 @@ package com.cotato.squadus.api.match.dto.matchPost.response; -import com.cotato.squadus.domain.club.match.entity.match.MatchPost; -import com.cotato.squadus.domain.club.match.entity.match.MatchRequest; -import com.cotato.squadus.domain.club.match.enums.MatchingStatus; - import java.util.List; +import com.cotato.squadus.domain.club.match.entity.match.MatchPost; + public record MatchRequestAndMatchPostResponse( - MatchCreateResponse matchCreateResponse, - List receivedRequests + MatchCreateResponse matchCreateResponse, + List receivedRequests ) { - public static MatchRequestAndMatchPostResponse from(MatchPost matchPost, List receivedRequests) { - return new MatchRequestAndMatchPostResponse( - MatchCreateResponse.from(matchPost), - receivedRequests - ); - } + public static MatchRequestAndMatchPostResponse from(MatchPost matchPost, + List receivedRequests) { + return new MatchRequestAndMatchPostResponse( + MatchCreateResponse.from(matchPost), + receivedRequests + ); + } } diff --git a/src/main/java/com/cotato/squadus/api/match/dto/matchPost/response/MatchRequestAndMatchPostResponseWrapper.java b/src/main/java/com/cotato/squadus/api/match/dto/matchPost/response/MatchRequestAndMatchPostResponseWrapper.java index 9c9faf8..f543121 100644 --- a/src/main/java/com/cotato/squadus/api/match/dto/matchPost/response/MatchRequestAndMatchPostResponseWrapper.java +++ b/src/main/java/com/cotato/squadus/api/match/dto/matchPost/response/MatchRequestAndMatchPostResponseWrapper.java @@ -3,9 +3,9 @@ import java.util.List; public record MatchRequestAndMatchPostResponseWrapper( - List matchRequestAndMatchPostResponses + List matchRequestAndMatchPostResponses ) { - public static MatchRequestAndMatchPostResponseWrapper from(List responses) { - return new MatchRequestAndMatchPostResponseWrapper(responses); - } + public static MatchRequestAndMatchPostResponseWrapper from(List responses) { + return new MatchRequestAndMatchPostResponseWrapper(responses); + } } diff --git a/src/main/java/com/cotato/squadus/api/match/dto/matchPost/response/MatchRequestResponse.java b/src/main/java/com/cotato/squadus/api/match/dto/matchPost/response/MatchRequestResponse.java index e109b97..78c8d16 100644 --- a/src/main/java/com/cotato/squadus/api/match/dto/matchPost/response/MatchRequestResponse.java +++ b/src/main/java/com/cotato/squadus/api/match/dto/matchPost/response/MatchRequestResponse.java @@ -4,17 +4,17 @@ import com.cotato.squadus.domain.club.match.enums.MatchingStatus; public record MatchRequestResponse( - Long matchRequestIdx, - String clubName, - MatchingStatus status, - MatchCreateResponse matchCreateResponse + Long matchRequestIdx, + String clubName, + MatchingStatus status, + MatchCreateResponse matchCreateResponse ) { - public static MatchRequestResponse from(MatchRequest matchRequest) { - return new MatchRequestResponse( - matchRequest.getMatchRequestIdx(), - matchRequest.getClub().getClubName(), //쿼리 1개 발생 - matchRequest.getStatus(), - MatchCreateResponse.from(matchRequest.getMatchPost()) - ); - } + public static MatchRequestResponse from(MatchRequest matchRequest) { + return new MatchRequestResponse( + matchRequest.getMatchRequestIdx(), + matchRequest.getClub().getClubName(), //쿼리 1개 발생 + matchRequest.getStatus(), + MatchCreateResponse.from(matchRequest.getMatchPost()) + ); + } } diff --git a/src/main/java/com/cotato/squadus/api/match/dto/matchPost/response/MatchRequestResponseWrapper.java b/src/main/java/com/cotato/squadus/api/match/dto/matchPost/response/MatchRequestResponseWrapper.java index adee3ec..851deaa 100644 --- a/src/main/java/com/cotato/squadus/api/match/dto/matchPost/response/MatchRequestResponseWrapper.java +++ b/src/main/java/com/cotato/squadus/api/match/dto/matchPost/response/MatchRequestResponseWrapper.java @@ -1,17 +1,17 @@ package com.cotato.squadus.api.match.dto.matchPost.response; -import org.springframework.data.domain.Page; - import java.util.List; +import org.springframework.data.domain.Page; + public record MatchRequestResponseWrapper( - List matches + List matches ) { - public static MatchRequestResponseWrapper from(List responses) { - return new MatchRequestResponseWrapper(responses); - } + public static MatchRequestResponseWrapper from(List responses) { + return new MatchRequestResponseWrapper(responses); + } - public static MatchRequestResponseWrapper from(Page responses) { - return new MatchRequestResponseWrapper(responses.getContent()); - } + public static MatchRequestResponseWrapper from(Page responses) { + return new MatchRequestResponseWrapper(responses.getContent()); + } } diff --git a/src/main/java/com/cotato/squadus/api/match/dto/matchPost/response/MatchRequestStatusResponse.java b/src/main/java/com/cotato/squadus/api/match/dto/matchPost/response/MatchRequestStatusResponse.java index b42c967..f9e742d 100644 --- a/src/main/java/com/cotato/squadus/api/match/dto/matchPost/response/MatchRequestStatusResponse.java +++ b/src/main/java/com/cotato/squadus/api/match/dto/matchPost/response/MatchRequestStatusResponse.java @@ -4,17 +4,17 @@ import com.cotato.squadus.domain.club.match.enums.MatchingStatus; public record MatchRequestStatusResponse( - Long matchRequestId, - String clubName, - String university, - MatchingStatus status + Long matchRequestId, + String clubName, + String university, + MatchingStatus status ) { - public static MatchRequestStatusResponse from(MatchRequest matchRequest) { - return new MatchRequestStatusResponse( - matchRequest.getMatchRequestIdx(), - matchRequest.getClub().getClubName(), //쿼리 발생 - matchRequest.getClub().getUniversity(), //쿼리 발생 - matchRequest.getStatus() - ); - } + public static MatchRequestStatusResponse from(MatchRequest matchRequest) { + return new MatchRequestStatusResponse( + matchRequest.getMatchRequestIdx(), + matchRequest.getClub().getClubName(), //쿼리 발생 + matchRequest.getClub().getUniversity(), //쿼리 발생 + matchRequest.getStatus() + ); + } } \ No newline at end of file diff --git a/src/main/java/com/cotato/squadus/api/match/dto/matchPost/response/ReceivedMatchRequestResponse.java b/src/main/java/com/cotato/squadus/api/match/dto/matchPost/response/ReceivedMatchRequestResponse.java index 6a92cd7..d89b482 100644 --- a/src/main/java/com/cotato/squadus/api/match/dto/matchPost/response/ReceivedMatchRequestResponse.java +++ b/src/main/java/com/cotato/squadus/api/match/dto/matchPost/response/ReceivedMatchRequestResponse.java @@ -1,23 +1,21 @@ package com.cotato.squadus.api.match.dto.matchPost.response; -import com.cotato.squadus.domain.club.common.enums.ClubTier; import com.cotato.squadus.domain.club.match.entity.match.MatchRequest; -import com.cotato.squadus.domain.club.match.enums.MatchingStatus; public record ReceivedMatchRequestResponse( - String matchingStatus, - Long requestId, - String requesterClubName, - String requesterUniversity, - String requesterTier + String matchingStatus, + Long requestId, + String requesterClubName, + String requesterUniversity, + String requesterTier ) { - public static ReceivedMatchRequestResponse from(MatchRequest matchRequest) { - return new ReceivedMatchRequestResponse( - matchRequest.getStatus().name(), - matchRequest.getMatchRequestIdx(), - matchRequest.getClub().getClubName(), - matchRequest.getClub().getUniversity(), - matchRequest.getClub().getClubTier().name() - ); - } + public static ReceivedMatchRequestResponse from(MatchRequest matchRequest) { + return new ReceivedMatchRequestResponse( + matchRequest.getStatus().name(), + matchRequest.getMatchRequestIdx(), + matchRequest.getClub().getClubName(), + matchRequest.getClub().getUniversity(), + matchRequest.getClub().getClubTier().name() + ); + } } \ No newline at end of file diff --git a/src/main/java/com/cotato/squadus/api/match/dto/matchResult/request/MatchResultAddRequest.java b/src/main/java/com/cotato/squadus/api/match/dto/matchResult/request/MatchResultAddRequest.java index 9d9aace..e6f3646 100644 --- a/src/main/java/com/cotato/squadus/api/match/dto/matchResult/request/MatchResultAddRequest.java +++ b/src/main/java/com/cotato/squadus/api/match/dto/matchResult/request/MatchResultAddRequest.java @@ -7,7 +7,7 @@ @Setter public class MatchResultAddRequest { - private Long clubMemberId; - private Integer homeScore; - private Integer awayScore; + private Long clubMemberId; + private Integer homeScore; + private Integer awayScore; } diff --git a/src/main/java/com/cotato/squadus/api/match/dto/matchResult/response/MatchDetailResponse.java b/src/main/java/com/cotato/squadus/api/match/dto/matchResult/response/MatchDetailResponse.java index 61d764b..0a98a9e 100644 --- a/src/main/java/com/cotato/squadus/api/match/dto/matchResult/response/MatchDetailResponse.java +++ b/src/main/java/com/cotato/squadus/api/match/dto/matchResult/response/MatchDetailResponse.java @@ -1,33 +1,33 @@ package com.cotato.squadus.api.match.dto.matchResult.response; +import java.util.List; + import com.cotato.squadus.domain.club.common.entity.Club; import com.cotato.squadus.domain.club.match.entity.match.MatchPost; -import java.util.List; - public record MatchDetailResponse( - String homeClubName, - String homeClubLogoUrl, - String homeClubTier, - String awayClubName, - String awayClubLogoUrl, - String awayClubTier, - String matchTitle, - String matchContent, - List matchResults + String homeClubName, + String homeClubLogoUrl, + String homeClubTier, + String awayClubName, + String awayClubLogoUrl, + String awayClubTier, + String matchTitle, + String matchContent, + List matchResults ) { - public static MatchDetailResponse from(MatchPost matchPost, Club awayClub, List matchResults) { - return new MatchDetailResponse( - matchPost.getHomeClub().getClubName(), - matchPost.getHomeClub().getLogo(), - matchPost.getHomeClub().getClubTier().name(), - awayClub.getClubName(), - awayClub.getLogo(), - awayClub.getClubTier().name(), - matchPost.getTitle(), - matchPost.getContent(), - matchResults - ); - } + public static MatchDetailResponse from(MatchPost matchPost, Club awayClub, List matchResults) { + return new MatchDetailResponse( + matchPost.getHomeClub().getClubName(), + matchPost.getHomeClub().getLogo(), + matchPost.getHomeClub().getClubTier().name(), + awayClub.getClubName(), + awayClub.getLogo(), + awayClub.getClubTier().name(), + matchPost.getTitle(), + matchPost.getContent(), + matchResults + ); + } } diff --git a/src/main/java/com/cotato/squadus/api/match/dto/matchResult/response/MatchDetailWithWinResponse.java b/src/main/java/com/cotato/squadus/api/match/dto/matchResult/response/MatchDetailWithWinResponse.java index bd8b761..b5df836 100644 --- a/src/main/java/com/cotato/squadus/api/match/dto/matchResult/response/MatchDetailWithWinResponse.java +++ b/src/main/java/com/cotato/squadus/api/match/dto/matchResult/response/MatchDetailWithWinResponse.java @@ -1,6 +1,7 @@ package com.cotato.squadus.api.match.dto.matchResult.response; public record MatchDetailWithWinResponse( - MatchDetailResponse matchDetail, - MatchFinalResultResponse matchFinalResult -) {} + MatchDetailResponse matchDetail, + MatchFinalResultResponse matchFinalResult +) { +} diff --git a/src/main/java/com/cotato/squadus/api/match/dto/matchResult/response/MatchFinalResultResponse.java b/src/main/java/com/cotato/squadus/api/match/dto/matchResult/response/MatchFinalResultResponse.java index e3ce787..3664b65 100644 --- a/src/main/java/com/cotato/squadus/api/match/dto/matchResult/response/MatchFinalResultResponse.java +++ b/src/main/java/com/cotato/squadus/api/match/dto/matchResult/response/MatchFinalResultResponse.java @@ -1,6 +1,7 @@ package com.cotato.squadus.api.match.dto.matchResult.response; public record MatchFinalResultResponse( - int homeWins, - int awayWins -) {} \ No newline at end of file + int homeWins, + int awayWins +) { +} \ No newline at end of file diff --git a/src/main/java/com/cotato/squadus/api/match/dto/matchResult/response/MatchResultResponse.java b/src/main/java/com/cotato/squadus/api/match/dto/matchResult/response/MatchResultResponse.java index 3172454..7ae45ab 100644 --- a/src/main/java/com/cotato/squadus/api/match/dto/matchResult/response/MatchResultResponse.java +++ b/src/main/java/com/cotato/squadus/api/match/dto/matchResult/response/MatchResultResponse.java @@ -3,17 +3,17 @@ import com.cotato.squadus.domain.club.match.entity.match.MatchResult; public record MatchResultResponse( - Long matchResultIdx, - Long matchPostId, - Integer homeScore, - Integer awayScore + Long matchResultIdx, + Long matchPostId, + Integer homeScore, + Integer awayScore ) { - public static MatchResultResponse from(MatchResult matchResult) { - return new MatchResultResponse( - matchResult.getMatchResultIdx(), - matchResult.getMatchPost().getMatchIdx(), //option으로 넣음 - matchResult.getHomeScore(), - matchResult.getAwayScore() - ); - } + public static MatchResultResponse from(MatchResult matchResult) { + return new MatchResultResponse( + matchResult.getMatchResultIdx(), + matchResult.getMatchPost().getMatchIdx(), //option으로 넣음 + matchResult.getHomeScore(), + matchResult.getAwayScore() + ); + } } diff --git a/src/main/java/com/cotato/squadus/api/member/controller/MemberController.java b/src/main/java/com/cotato/squadus/api/member/controller/MemberController.java index 9fc7e2d..73823c3 100644 --- a/src/main/java/com/cotato/squadus/api/member/controller/MemberController.java +++ b/src/main/java/com/cotato/squadus/api/member/controller/MemberController.java @@ -1,21 +1,27 @@ package com.cotato.squadus.api.member.controller; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.security.core.annotation.AuthenticationPrincipal; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestPart; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.multipart.MultipartFile; + import com.cotato.squadus.api.member.dto.MemberClubApplicationListResponse; import com.cotato.squadus.api.member.dto.MemberClubListResponse; import com.cotato.squadus.api.member.dto.MemberInfoResponse; import com.cotato.squadus.common.config.auth.CustomOAuth2Member; import com.cotato.squadus.domain.auth.service.MemberService; + import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.tags.Tag; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.springframework.http.MediaType; -import org.springframework.http.ResponseEntity; -import org.springframework.security.core.annotation.AuthenticationPrincipal; -import org.springframework.web.bind.annotation.*; -import org.springframework.web.multipart.MultipartFile; - @Tag(name = "유저", description = "유저 관련 API") @Slf4j @@ -24,45 +30,48 @@ @RequiredArgsConstructor public class MemberController { - private final MemberService memberService; + private final MemberService memberService; - @GetMapping("/info") - @Operation(summary = "유저 정보 조회", description = "Access Token을 통해 유저에 대한 정보를 조회합니다") - public MemberInfoResponse findMemberInfo( - @AuthenticationPrincipal CustomOAuth2Member customOAuth2Member) { - MemberInfoResponse memberInfo = memberService.findMemberInfo(customOAuth2Member); - return memberInfo; - } + @GetMapping("/info") + @Operation(summary = "유저 정보 조회", description = "Access Token을 통해 유저에 대한 정보를 조회합니다") + public MemberInfoResponse findMemberInfo( + @AuthenticationPrincipal CustomOAuth2Member customOAuth2Member) { + MemberInfoResponse memberInfo = memberService.findMemberInfo(customOAuth2Member); + return memberInfo; + } - @GetMapping("/clubs") - @Operation(summary = "유저가 가입된 동아리 조회", description = "가입된 동아리에 대한 정보를 리스트로 조회") - public ResponseEntity findJoinedClubs(@AuthenticationPrincipal CustomOAuth2Member customOAuth2Member) { - MemberClubListResponse memberClubListResponse = memberService.findJoinedClubs(customOAuth2Member); - return ResponseEntity.ok(memberClubListResponse); - } + @GetMapping("/clubs") + @Operation(summary = "유저가 가입된 동아리 조회", description = "가입된 동아리에 대한 정보를 리스트로 조회") + public ResponseEntity findJoinedClubs( + @AuthenticationPrincipal CustomOAuth2Member customOAuth2Member) { + MemberClubListResponse memberClubListResponse = memberService.findJoinedClubs(customOAuth2Member); + return ResponseEntity.ok(memberClubListResponse); + } - @GetMapping("/applications") - @Operation(summary = "유저가 가입 신청한 동아리 조회", description = "동아리 가입 신청에 대한 정보를 리스트로 조회") - public ResponseEntity findAppliedClubs(@AuthenticationPrincipal CustomOAuth2Member customOAuth2Member) { - MemberClubApplicationListResponse appliedClubs = memberService.findAppliedClubs(customOAuth2Member); - return ResponseEntity.ok(appliedClubs); - } + @GetMapping("/applications") + @Operation(summary = "유저가 가입 신청한 동아리 조회", description = "동아리 가입 신청에 대한 정보를 리스트로 조회") + public ResponseEntity findAppliedClubs( + @AuthenticationPrincipal CustomOAuth2Member customOAuth2Member) { + MemberClubApplicationListResponse appliedClubs = memberService.findAppliedClubs(customOAuth2Member); + return ResponseEntity.ok(appliedClubs); + } - @PostMapping(value = "/profile-image", - consumes = MediaType.MULTIPART_FORM_DATA_VALUE, produces = MediaType.APPLICATION_JSON_VALUE) - @Operation(summary = "유저 프로필 이미지 변경", description = "유저의 프로필 이미지를 변경합니다.") - public ResponseEntity updateMemberProfileImage( - @AuthenticationPrincipal CustomOAuth2Member customOAuth2Member, - @Parameter(description = "multipart/form-data 형식의 이미지를 input으로 받습니다. 이때 key 값은 profileImage입니다.") - @RequestPart(value = "profileImage", required = true) MultipartFile profileImageFile) { - MemberInfoResponse memberInfoResponse = memberService.updateProfileImage(customOAuth2Member, profileImageFile); - return ResponseEntity.ok(memberInfoResponse); - } + @PostMapping(value = "/profile-image", + consumes = MediaType.MULTIPART_FORM_DATA_VALUE, produces = MediaType.APPLICATION_JSON_VALUE) + @Operation(summary = "유저 프로필 이미지 변경", description = "유저의 프로필 이미지를 변경합니다.") + public ResponseEntity updateMemberProfileImage( + @AuthenticationPrincipal CustomOAuth2Member customOAuth2Member, + @Parameter(description = "multipart/form-data 형식의 이미지를 input으로 받습니다. 이때 key 값은 profileImage입니다.") + @RequestPart(value = "profileImage", required = true) MultipartFile profileImageFile) { + MemberInfoResponse memberInfoResponse = memberService.updateProfileImage(customOAuth2Member, profileImageFile); + return ResponseEntity.ok(memberInfoResponse); + } - @DeleteMapping(value = "/profile-image") - @Operation(summary = "유저 프로필 이미지 삭제", description = "유저의 프로필 이미지를 삭제하고 기본 이미지로 설정합니다.") - public ResponseEntity deleteMemberProfileImage(@AuthenticationPrincipal CustomOAuth2Member customOAuth2Member) { - MemberInfoResponse memberInfoResponse = memberService.deleteProfileImage(customOAuth2Member); - return ResponseEntity.ok(memberInfoResponse); - } + @DeleteMapping(value = "/profile-image") + @Operation(summary = "유저 프로필 이미지 삭제", description = "유저의 프로필 이미지를 삭제하고 기본 이미지로 설정합니다.") + public ResponseEntity deleteMemberProfileImage( + @AuthenticationPrincipal CustomOAuth2Member customOAuth2Member) { + MemberInfoResponse memberInfoResponse = memberService.deleteProfileImage(customOAuth2Member); + return ResponseEntity.ok(memberInfoResponse); + } } diff --git a/src/main/java/com/cotato/squadus/api/member/dto/MemberClubApplicationInfoResponse.java b/src/main/java/com/cotato/squadus/api/member/dto/MemberClubApplicationInfoResponse.java index e214f17..2ab925e 100644 --- a/src/main/java/com/cotato/squadus/api/member/dto/MemberClubApplicationInfoResponse.java +++ b/src/main/java/com/cotato/squadus/api/member/dto/MemberClubApplicationInfoResponse.java @@ -1,41 +1,39 @@ package com.cotato.squadus.api.member.dto; -import com.cotato.squadus.api.admin.dto.MemberClubApplicationInfo; +import java.time.LocalDate; +import java.util.List; + import com.cotato.squadus.domain.auth.enums.ApplicationStatus; import com.cotato.squadus.domain.club.common.entity.ClubApplication; import com.cotato.squadus.domain.club.common.entity.Region; import com.cotato.squadus.domain.club.common.enums.ClubTier; import com.cotato.squadus.domain.club.common.enums.SportsCategory; -import java.time.LocalDate; -import java.util.List; - public record MemberClubApplicationInfoResponse( - Long applicationId, - Long recruitingPostId, - LocalDate startDate, - LocalDate endDate, - String title, - Region region, - SportsCategory sportsCategory, - ClubTier clubTier, - List tags, - ApplicationStatus applicationStatus + Long applicationId, + Long recruitingPostId, + LocalDate startDate, + LocalDate endDate, + String title, + Region region, + SportsCategory sportsCategory, + ClubTier clubTier, + List tags, + ApplicationStatus applicationStatus ) { - public static MemberClubApplicationInfoResponse from(ClubApplication clubApplication) { - return new MemberClubApplicationInfoResponse( - clubApplication.getApplicationIdx(), - clubApplication.getRecruitingPost().getPostId(), - clubApplication.getRecruitingPost().getStartDate(), - clubApplication.getRecruitingPost().getEndDate(), - clubApplication.getRecruitingPost().getTitle(), - clubApplication.getClub().getRegion(), - clubApplication.getClub().getSportsCategory(), - clubApplication.getClub().getClubTier(), - clubApplication.getClub().getTags(), - clubApplication.getApplicationStatus() - ); - } - + public static MemberClubApplicationInfoResponse from(ClubApplication clubApplication) { + return new MemberClubApplicationInfoResponse( + clubApplication.getApplicationIdx(), + clubApplication.getRecruitingPost().getPostId(), + clubApplication.getRecruitingPost().getStartDate(), + clubApplication.getRecruitingPost().getEndDate(), + clubApplication.getRecruitingPost().getTitle(), + clubApplication.getClub().getRegion(), + clubApplication.getClub().getSportsCategory(), + clubApplication.getClub().getClubTier(), + clubApplication.getClub().getTags(), + clubApplication.getApplicationStatus() + ); + } } diff --git a/src/main/java/com/cotato/squadus/api/member/dto/MemberClubApplicationListResponse.java b/src/main/java/com/cotato/squadus/api/member/dto/MemberClubApplicationListResponse.java index 6aa6160..1e9341a 100644 --- a/src/main/java/com/cotato/squadus/api/member/dto/MemberClubApplicationListResponse.java +++ b/src/main/java/com/cotato/squadus/api/member/dto/MemberClubApplicationListResponse.java @@ -3,13 +3,14 @@ import java.util.List; public record MemberClubApplicationListResponse( - Integer totalApplicationCount, - List memberClubApplicationInfoResponseList + Integer totalApplicationCount, + List memberClubApplicationInfoResponseList ) { - public static MemberClubApplicationListResponse from(List memberClubApplicationInfoResponseList) { - return new MemberClubApplicationListResponse( - memberClubApplicationInfoResponseList.size(), - memberClubApplicationInfoResponseList - ); - } + public static MemberClubApplicationListResponse from( + List memberClubApplicationInfoResponseList) { + return new MemberClubApplicationListResponse( + memberClubApplicationInfoResponseList.size(), + memberClubApplicationInfoResponseList + ); + } } diff --git a/src/main/java/com/cotato/squadus/api/member/dto/MemberClubListResponse.java b/src/main/java/com/cotato/squadus/api/member/dto/MemberClubListResponse.java index 7ef6781..26a5806 100644 --- a/src/main/java/com/cotato/squadus/api/member/dto/MemberClubListResponse.java +++ b/src/main/java/com/cotato/squadus/api/member/dto/MemberClubListResponse.java @@ -3,9 +3,9 @@ import java.util.List; public record MemberClubListResponse( - List memberClubResponseList + List memberClubResponseList ) { - public static MemberClubListResponse from(List memberClubResponseList) { - return new MemberClubListResponse(memberClubResponseList); - } + public static MemberClubListResponse from(List memberClubResponseList) { + return new MemberClubListResponse(memberClubResponseList); + } } diff --git a/src/main/java/com/cotato/squadus/api/member/dto/MemberClubResponse.java b/src/main/java/com/cotato/squadus/api/member/dto/MemberClubResponse.java index bd95ccc..712455a 100644 --- a/src/main/java/com/cotato/squadus/api/member/dto/MemberClubResponse.java +++ b/src/main/java/com/cotato/squadus/api/member/dto/MemberClubResponse.java @@ -5,25 +5,25 @@ import com.cotato.squadus.domain.club.common.entity.ClubMember; public record MemberClubResponse( - Long clubId, - Long clubMemberIdx, - String clubName, - Boolean isAdmin + Long clubId, + Long clubMemberIdx, + String clubName, + Boolean isAdmin ) { - public static MemberClubResponse from(ClubMember clubMember) { - boolean isAdmin = false; + public static MemberClubResponse from(ClubMember clubMember) { + boolean isAdmin = false; - if (clubMember instanceof ClubAdminMember) { - ClubAdminMember adminMember = (ClubAdminMember) clubMember; - isAdmin = adminMember.getAdminStatus() == AdminStatus.CURRENT; - } + if (clubMember instanceof ClubAdminMember) { + ClubAdminMember adminMember = (ClubAdminMember)clubMember; + isAdmin = adminMember.getAdminStatus() == AdminStatus.CURRENT; + } - return new MemberClubResponse( - clubMember.getClub().getClubId(), - clubMember.getClubMemberIdx(), - clubMember.getClub().getClubName(), - isAdmin - ); - } + return new MemberClubResponse( + clubMember.getClub().getClubId(), + clubMember.getClubMemberIdx(), + clubMember.getClub().getClubName(), + isAdmin + ); + } } \ No newline at end of file diff --git a/src/main/java/com/cotato/squadus/api/member/dto/MemberInfoResponse.java b/src/main/java/com/cotato/squadus/api/member/dto/MemberInfoResponse.java index e984981..5922807 100644 --- a/src/main/java/com/cotato/squadus/api/member/dto/MemberInfoResponse.java +++ b/src/main/java/com/cotato/squadus/api/member/dto/MemberInfoResponse.java @@ -4,21 +4,21 @@ import com.cotato.squadus.domain.auth.enums.MemberRole; public record MemberInfoResponse( - Long memberId, - String memberName, - String email, - MemberRole memberRole, - String university, - String profileImage + Long memberId, + String memberName, + String email, + MemberRole memberRole, + String university, + String profileImage ) { - public static MemberInfoResponse from(Member member) { - return new MemberInfoResponse( - member.getMemberIdx(), - member.getUsername(), - member.getEmail(), - member.getMemberRole(), - member.getUniversity(), - member.getProfileImage() - ); - } + public static MemberInfoResponse from(Member member) { + return new MemberInfoResponse( + member.getMemberIdx(), + member.getUsername(), + member.getEmail(), + member.getMemberRole(), + member.getUniversity(), + member.getProfileImage() + ); + } } \ No newline at end of file diff --git a/src/main/java/com/cotato/squadus/api/mercenary/controller/MercenaryController.java b/src/main/java/com/cotato/squadus/api/mercenary/controller/MercenaryController.java index 3440978..4c4064e 100644 --- a/src/main/java/com/cotato/squadus/api/mercenary/controller/MercenaryController.java +++ b/src/main/java/com/cotato/squadus/api/mercenary/controller/MercenaryController.java @@ -1,5 +1,19 @@ package com.cotato.squadus.api.mercenary.controller; +import java.util.List; + +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Pageable; +import org.springframework.http.ResponseEntity; +import org.springframework.security.core.annotation.AuthenticationPrincipal; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + import com.cotato.squadus.api.match.dto.matchPost.request.FilterRequest; import com.cotato.squadus.api.match.dto.matchPost.request.SearchRequest; import com.cotato.squadus.api.mercenary.dto.request.MercenaryCreateRequest; @@ -9,17 +23,10 @@ import com.cotato.squadus.api.mercenary.dto.response.MercenaryRequestResponse; import com.cotato.squadus.common.config.auth.CustomOAuth2Member; import com.cotato.squadus.domain.club.match.service.mercenary.MercenaryService; + import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; import lombok.RequiredArgsConstructor; -import org.springframework.data.domain.Page; -import org.springframework.data.domain.PageRequest; -import org.springframework.data.domain.Pageable; -import org.springframework.http.ResponseEntity; -import org.springframework.security.core.annotation.AuthenticationPrincipal; -import org.springframework.web.bind.annotation.*; - -import java.util.List; @Tag(name = "용병 매치", description = "용병 매칭 관련 API") @RestController @@ -27,55 +34,57 @@ @RequiredArgsConstructor public class MercenaryController { - private final MercenaryService mercenaryService; + private final MercenaryService mercenaryService; - @PostMapping - @Operation(summary = "용병 매칭 생성", description = "용병 매칭 게시글을 생성합니다.") - public ResponseEntity createMatch(@RequestBody MercenaryCreateRequest mercenaryCreateRequest) { - MercenaryCreateResponse response = mercenaryService.createMatch(mercenaryCreateRequest); - return ResponseEntity.ok(response); - } + @PostMapping + @Operation(summary = "용병 매칭 생성", description = "용병 매칭 게시글을 생성합니다.") + public ResponseEntity createMatch( + @RequestBody MercenaryCreateRequest mercenaryCreateRequest) { + MercenaryCreateResponse response = mercenaryService.createMatch(mercenaryCreateRequest); + return ResponseEntity.ok(response); + } - @GetMapping - @Operation(summary = "모든 용병 매칭 조회", description = "모든 용병 매칭 게시글을 조회합니다") - public ResponseEntity getAllMatches() { - List responses = mercenaryService.findAllMatches(); - return ResponseEntity.ok(MercenaryCreateResponseWrapper.from(responses)); - } + @GetMapping + @Operation(summary = "모든 용병 매칭 조회", description = "모든 용병 매칭 게시글을 조회합니다") + public ResponseEntity getAllMatches() { + List responses = mercenaryService.findAllMatches(); + return ResponseEntity.ok(MercenaryCreateResponseWrapper.from(responses)); + } - @GetMapping("/paged") - @Operation(summary = "모든 용병 매칭 조회 (페이징)", description = "모든 용병 매칭 게시글을 페이징(10개) 처리하여 조회합니다.") - public ResponseEntity getAllMatchesPaged( - @RequestParam(defaultValue = "0") int page, - @RequestParam(defaultValue = "10") int size) { - Pageable pageable = PageRequest.of(page, size); - Page responses = mercenaryService.findAllMatches(pageable); - return ResponseEntity.ok(MercenaryCreateResponseWrapper.from(responses)); - } + @GetMapping("/paged") + @Operation(summary = "모든 용병 매칭 조회 (페이징)", description = "모든 용병 매칭 게시글을 페이징(10개) 처리하여 조회합니다.") + public ResponseEntity getAllMatchesPaged( + @RequestParam(defaultValue = "0") int page, + @RequestParam(defaultValue = "10") int size) { + Pageable pageable = PageRequest.of(page, size); + Page responses = mercenaryService.findAllMatches(pageable); + return ResponseEntity.ok(MercenaryCreateResponseWrapper.from(responses)); + } - //필터 4개를 한 번에 조회 가능. 필터를 하지 않는 부분은 null로 reqeust해주면 자동으로 필터링 해줌 - @PostMapping("/filter") - @Operation(summary = "필터링된 용병 매칭 조회", description = "필터를 적용하여 용병 매칭 게시글을 조회합니다. 필터 4개를 한번에 조회할 수 있습니다. 필터를 하지 않는 부분은 null로 reqeust해주면 자동으로 필터링을 진행한다.") - public ResponseEntity getMatchesByFilter( - @RequestBody FilterRequest filterRequest) { - List responses = mercenaryService.getFilteredMatches(filterRequest); - return ResponseEntity.ok(MercenaryCreateResponseWrapper.from(responses)); - } + //필터 4개를 한 번에 조회 가능. 필터를 하지 않는 부분은 null로 reqeust해주면 자동으로 필터링 해줌 + @PostMapping("/filter") + @Operation(summary = "필터링된 용병 매칭 조회", description = "필터를 적용하여 용병 매칭 게시글을 조회합니다. 필터 4개를 한번에 조회할 수 있습니다. 필터를 하지 않는 부분은 null로 reqeust해주면 자동으로 필터링을 진행한다.") + public ResponseEntity getMatchesByFilter( + @RequestBody FilterRequest filterRequest) { + List responses = mercenaryService.getFilteredMatches(filterRequest); + return ResponseEntity.ok(MercenaryCreateResponseWrapper.from(responses)); + } - @PostMapping("/search") - @Operation(summary = "용병 매칭 검색", description = "검색어를 바탕으로 용병 매칭 게시글을 조회합니다.") - public ResponseEntity searchMatches( - @RequestBody SearchRequest searchRequest) { - List responses = mercenaryService.searchMatches(searchRequest); - return ResponseEntity.ok(MercenaryCreateResponseWrapper.from(responses)); - } + @PostMapping("/search") + @Operation(summary = "용병 매칭 검색", description = "검색어를 바탕으로 용병 매칭 게시글을 조회합니다.") + public ResponseEntity searchMatches( + @RequestBody SearchRequest searchRequest) { + List responses = mercenaryService.searchMatches(searchRequest); + return ResponseEntity.ok(MercenaryCreateResponseWrapper.from(responses)); + } - @PostMapping("/request") - @Operation(summary = "용병 매칭 요청", description = "특정 용병 매칭 게시글에 대해 매칭 요청을 보냅니다.") - public ResponseEntity sendMatchRequest( - @RequestBody MercenaryRequestRequest mercenaryRequestRequest, - @AuthenticationPrincipal CustomOAuth2Member customOAuth2Member) { - MercenaryRequestResponse response = mercenaryService.sendMatchRequest(mercenaryRequestRequest, customOAuth2Member); - return ResponseEntity.ok(response); - } + @PostMapping("/request") + @Operation(summary = "용병 매칭 요청", description = "특정 용병 매칭 게시글에 대해 매칭 요청을 보냅니다.") + public ResponseEntity sendMatchRequest( + @RequestBody MercenaryRequestRequest mercenaryRequestRequest, + @AuthenticationPrincipal CustomOAuth2Member customOAuth2Member) { + MercenaryRequestResponse response = mercenaryService.sendMatchRequest(mercenaryRequestRequest, + customOAuth2Member); + return ResponseEntity.ok(response); + } } diff --git a/src/main/java/com/cotato/squadus/api/mercenary/controller/MercenaryRequestController.java b/src/main/java/com/cotato/squadus/api/mercenary/controller/MercenaryRequestController.java index bc4c9d6..05c6819 100644 --- a/src/main/java/com/cotato/squadus/api/mercenary/controller/MercenaryRequestController.java +++ b/src/main/java/com/cotato/squadus/api/mercenary/controller/MercenaryRequestController.java @@ -1,21 +1,35 @@ package com.cotato.squadus.api.mercenary.controller; +import java.util.List; + +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Pageable; +import org.springframework.http.ResponseEntity; +import org.springframework.security.core.annotation.AuthenticationPrincipal; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + import com.cotato.squadus.api.mercenary.dto.request.MercenaryCreateRequest; -import com.cotato.squadus.api.mercenary.dto.response.*; +import com.cotato.squadus.api.mercenary.dto.response.MercenaryCreateResponse; +import com.cotato.squadus.api.mercenary.dto.response.MercenaryRequestAndMercenaryPostResponse; +import com.cotato.squadus.api.mercenary.dto.response.MercenaryRequestAndMercenaryPostResponseWrapper; +import com.cotato.squadus.api.mercenary.dto.response.MercenaryRequestResponse; +import com.cotato.squadus.api.mercenary.dto.response.MercenaryRequestResponseWrapper; import com.cotato.squadus.common.config.auth.CustomOAuth2Member; import com.cotato.squadus.domain.club.match.service.mercenary.MercenaryRequestService; import com.cotato.squadus.domain.club.match.service.mercenary.MercenaryService; + import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; import lombok.RequiredArgsConstructor; -import org.springframework.data.domain.Page; -import org.springframework.data.domain.PageRequest; -import org.springframework.data.domain.Pageable; -import org.springframework.http.ResponseEntity; -import org.springframework.security.core.annotation.AuthenticationPrincipal; -import org.springframework.web.bind.annotation.*; - -import java.util.List; @RestController @RequestMapping("/v1/api/mercenary-requests") @@ -23,80 +37,86 @@ @Tag(name = "용병 매칭 요청", description = "용병 매칭 요청 관련 API") public class MercenaryRequestController { - private final MercenaryRequestService mercenaryRequestService; - private final MercenaryService mercenaryService; - - //신청한 내역 기능 - 개인 단위의 신청 - @GetMapping("/paged") - @Operation(summary = "개인이 신청한 용병 매치 목록 조회 (페이징)", description = "개인이 신청한 용병 매칭 글 목록을 페이징 처리하여 조회합니다.") - public ResponseEntity getMyRequests( - @AuthenticationPrincipal CustomOAuth2Member customOAuth2Member, - @RequestParam(defaultValue = "0") int page, - @RequestParam(defaultValue = "10") int size) { - Pageable pageable = PageRequest.of(page, size); - Page responses = mercenaryRequestService.getMyRequests(customOAuth2Member, pageable); - return ResponseEntity.ok(MercenaryRequestResponseWrapper.from(responses)); - } - - @GetMapping - @Operation(summary = "개인이 신청한 용병 매치 목록 조회 (전체)", description = "개인이 신청한 용병 매칭 글 목록을 페이징 없이 전체 조회합니다.") - public ResponseEntity getAllMyRequests(@AuthenticationPrincipal CustomOAuth2Member customOAuth2Member) { - List responses = mercenaryRequestService.getAllMyRequests(customOAuth2Member); - return ResponseEntity.ok(MercenaryRequestResponseWrapper.from(responses)); - } + private final MercenaryRequestService mercenaryRequestService; + private final MercenaryService mercenaryService; - @DeleteMapping("/{requestId}") - @Operation(summary = "용병 매칭 요청 취소", description = "개인이 요청한 용병 매칭 요청을 취소합니다.") - public ResponseEntity cancelMercenaryRequest(@PathVariable Long requestId, @AuthenticationPrincipal CustomOAuth2Member customOAuth2Member) { - mercenaryRequestService.cancelMatchRequest(requestId, customOAuth2Member); - return ResponseEntity.noContent().build(); - } + //신청한 내역 기능 - 개인 단위의 신청 + @GetMapping("/paged") + @Operation(summary = "개인이 신청한 용병 매치 목록 조회 (페이징)", description = "개인이 신청한 용병 매칭 글 목록을 페이징 처리하여 조회합니다.") + public ResponseEntity getMyRequests( + @AuthenticationPrincipal CustomOAuth2Member customOAuth2Member, + @RequestParam(defaultValue = "0") int page, + @RequestParam(defaultValue = "10") int size) { + Pageable pageable = PageRequest.of(page, size); + Page responses = mercenaryRequestService.getMyRequests(customOAuth2Member, pageable); + return ResponseEntity.ok(MercenaryRequestResponseWrapper.from(responses)); + } + @GetMapping + @Operation(summary = "개인이 신청한 용병 매치 목록 조회 (전체)", description = "개인이 신청한 용병 매칭 글 목록을 페이징 없이 전체 조회합니다.") + public ResponseEntity getAllMyRequests( + @AuthenticationPrincipal CustomOAuth2Member customOAuth2Member) { + List responses = mercenaryRequestService.getAllMyRequests(customOAuth2Member); + return ResponseEntity.ok(MercenaryRequestResponseWrapper.from(responses)); + } - //신청 받은 내역 기능 - @GetMapping("/received/paged") - @Operation(summary = "내 동아리가 받은 용병 매칭 요청 목록 조회 (페이징)", description = "내 동아리가 받은 용병 매칭 요청 목록을 페이징 처리하여 조회합니다.") - public ResponseEntity getReceivedMatchRequests( - @RequestParam Long clubId, - @RequestParam(defaultValue = "0") int page, - @RequestParam(defaultValue = "10") int size) { - Pageable pageable = PageRequest.of(page, size); - Page responses = mercenaryRequestService.getReceivedMatchRequests(clubId, pageable); - MercenaryRequestAndMercenaryPostResponseWrapper wrapper = MercenaryRequestAndMercenaryPostResponseWrapper.from(responses.getContent()); - return ResponseEntity.ok(wrapper); - } + @DeleteMapping("/{requestId}") + @Operation(summary = "용병 매칭 요청 취소", description = "개인이 요청한 용병 매칭 요청을 취소합니다.") + public ResponseEntity cancelMercenaryRequest(@PathVariable Long requestId, + @AuthenticationPrincipal CustomOAuth2Member customOAuth2Member) { + mercenaryRequestService.cancelMatchRequest(requestId, customOAuth2Member); + return ResponseEntity.noContent().build(); + } - @GetMapping("/received") - @Operation(summary = "내 동아리가 받은 용병 매칭 요청 목록 조회 (전체)", description = "내 동아리가 받은 용병 매칭 요청 목록을 페이징 없이 전체 조회합니다.") - public ResponseEntity getAllReceivedMatchRequests(@RequestParam Long clubId) { - List responses = mercenaryRequestService.getAllReceivedMatchRequests(clubId); - MercenaryRequestAndMercenaryPostResponseWrapper wrapper = MercenaryRequestAndMercenaryPostResponseWrapper.from(responses); - return ResponseEntity.ok(wrapper); - } + //신청 받은 내역 기능 + @GetMapping("/received/paged") + @Operation(summary = "내 동아리가 받은 용병 매칭 요청 목록 조회 (페이징)", description = "내 동아리가 받은 용병 매칭 요청 목록을 페이징 처리하여 조회합니다.") + public ResponseEntity getReceivedMatchRequests( + @RequestParam Long clubId, + @RequestParam(defaultValue = "0") int page, + @RequestParam(defaultValue = "10") int size) { + Pageable pageable = PageRequest.of(page, size); + Page responses = mercenaryRequestService.getReceivedMatchRequests( + clubId, pageable); + MercenaryRequestAndMercenaryPostResponseWrapper wrapper = MercenaryRequestAndMercenaryPostResponseWrapper.from( + responses.getContent()); + return ResponseEntity.ok(wrapper); + } + @GetMapping("/received") + @Operation(summary = "내 동아리가 받은 용병 매칭 요청 목록 조회 (전체)", description = "내 동아리가 받은 용병 매칭 요청 목록을 페이징 없이 전체 조회합니다.") + public ResponseEntity getAllReceivedMatchRequests( + @RequestParam Long clubId) { + List responses = mercenaryRequestService.getAllReceivedMatchRequests( + clubId); + MercenaryRequestAndMercenaryPostResponseWrapper wrapper = MercenaryRequestAndMercenaryPostResponseWrapper.from( + responses); + return ResponseEntity.ok(wrapper); + } - @PostMapping("/{requestId}/decision") - @Operation(summary = "매칭 요청 승낙/거절", description = "특정 동아리의 임원(clubMemberId)이 받은 매칭 요청에 대해 승낙 또는 거절을 합니다.") - public ResponseEntity decideMatchRequest(@PathVariable Long requestId, @RequestParam String decision, @RequestParam Long clubMemberId) { - mercenaryRequestService.decideMatchRequest(requestId, decision, clubMemberId); - return ResponseEntity.noContent().build(); - } + @PostMapping("/{requestId}/decision") + @Operation(summary = "매칭 요청 승낙/거절", description = "특정 동아리의 임원(clubMemberId)이 받은 매칭 요청에 대해 승낙 또는 거절을 합니다.") + public ResponseEntity decideMatchRequest(@PathVariable Long requestId, @RequestParam String decision, + @RequestParam Long clubMemberId) { + mercenaryRequestService.decideMatchRequest(requestId, decision, clubMemberId); + return ResponseEntity.noContent().build(); + } - @PutMapping("/{mercenaryIdx}") - @Operation(summary = "용병 매칭 게시글 수정", description = "특정 동아리의 임원(clubMemberId)이 특정 용병 매칭 게시글을 수정합니다.") - public ResponseEntity updateMercenaryPost( - @PathVariable Long mercenaryIdx, - @RequestBody MercenaryCreateRequest mercenaryCreateRequest) { - MercenaryCreateResponse response = mercenaryService.updateMercenaryPost(mercenaryIdx, mercenaryCreateRequest); - return ResponseEntity.ok(response); - } + @PutMapping("/{mercenaryIdx}") + @Operation(summary = "용병 매칭 게시글 수정", description = "특정 동아리의 임원(clubMemberId)이 특정 용병 매칭 게시글을 수정합니다.") + public ResponseEntity updateMercenaryPost( + @PathVariable Long mercenaryIdx, + @RequestBody MercenaryCreateRequest mercenaryCreateRequest) { + MercenaryCreateResponse response = mercenaryService.updateMercenaryPost(mercenaryIdx, mercenaryCreateRequest); + return ResponseEntity.ok(response); + } - @DeleteMapping("/{mercenaryIdx}/delete") - @Operation(summary = "용병 매칭 게시글 삭제", description = "특정 동아리의 임원(clubMemberId)이 특정 용병 매칭 게시글을 삭제합니다.") - public ResponseEntity deleteMercenaryPost( - @PathVariable Long mercenaryIdx, - @RequestParam Long clubMemberId) { - mercenaryService.deleteMercenaryPost(mercenaryIdx, clubMemberId); - return ResponseEntity.noContent().build(); - } + @DeleteMapping("/{mercenaryIdx}/delete") + @Operation(summary = "용병 매칭 게시글 삭제", description = "특정 동아리의 임원(clubMemberId)이 특정 용병 매칭 게시글을 삭제합니다.") + public ResponseEntity deleteMercenaryPost( + @PathVariable Long mercenaryIdx, + @RequestParam Long clubMemberId) { + mercenaryService.deleteMercenaryPost(mercenaryIdx, clubMemberId); + return ResponseEntity.noContent().build(); + } } diff --git a/src/main/java/com/cotato/squadus/api/mercenary/dto/request/MercenaryCreateRequest.java b/src/main/java/com/cotato/squadus/api/mercenary/dto/request/MercenaryCreateRequest.java index 827ac5e..87e030c 100644 --- a/src/main/java/com/cotato/squadus/api/mercenary/dto/request/MercenaryCreateRequest.java +++ b/src/main/java/com/cotato/squadus/api/mercenary/dto/request/MercenaryCreateRequest.java @@ -1,36 +1,34 @@ package com.cotato.squadus.api.mercenary.dto.request; -import com.cotato.squadus.api.match.dto.matchPost.request.MatchCreateRequest; -import com.cotato.squadus.domain.club.common.entity.Tier; -import com.cotato.squadus.domain.club.common.enums.SportsCategory; +import java.time.LocalDate; +import java.time.LocalTime; + import com.fasterxml.jackson.annotation.JsonFormat; + import io.swagger.v3.oas.annotations.media.Schema; import lombok.Getter; import lombok.Setter; -import java.time.LocalDate; -import java.time.LocalTime; - @Getter @Setter public class MercenaryCreateRequest { - private Long homeClubId; - private Long clubMemberId; - private String title; - private String content; - private MatchPlaceRequest matchPlace; - private Boolean placeProvided; - private LocalDate matchStartDate; + private Long homeClubId; + private Long clubMemberId; + private String title; + private String content; + private MatchPlaceRequest matchPlace; + private Boolean placeProvided; + private LocalDate matchStartDate; - @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "HH:mm") - @Schema(description = "Match start time in format HH:mm", example = "10:00") - private LocalTime matchStartTime; - private Integer maxParticipants; + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "HH:mm") + @Schema(description = "Match start time in format HH:mm", example = "10:00") + private LocalTime matchStartTime; + private Integer maxParticipants; - @Getter - @Setter - public static class MatchPlaceRequest { - private String city; - private String district; - } + @Getter + @Setter + public static class MatchPlaceRequest { + private String city; + private String district; + } } diff --git a/src/main/java/com/cotato/squadus/api/mercenary/dto/request/MercenaryRequestRequest.java b/src/main/java/com/cotato/squadus/api/mercenary/dto/request/MercenaryRequestRequest.java index e51ae84..b99689b 100644 --- a/src/main/java/com/cotato/squadus/api/mercenary/dto/request/MercenaryRequestRequest.java +++ b/src/main/java/com/cotato/squadus/api/mercenary/dto/request/MercenaryRequestRequest.java @@ -6,5 +6,5 @@ @Getter @Setter public class MercenaryRequestRequest { - private Long mercenaryPostId; + private Long mercenaryPostId; } diff --git a/src/main/java/com/cotato/squadus/api/mercenary/dto/response/MercenaryCreateResponse.java b/src/main/java/com/cotato/squadus/api/mercenary/dto/response/MercenaryCreateResponse.java index 057d9ac..ab4770e 100644 --- a/src/main/java/com/cotato/squadus/api/mercenary/dto/response/MercenaryCreateResponse.java +++ b/src/main/java/com/cotato/squadus/api/mercenary/dto/response/MercenaryCreateResponse.java @@ -1,41 +1,41 @@ package com.cotato.squadus.api.mercenary.dto.response; -import com.cotato.squadus.api.match.dto.matchPost.response.MatchPlaceResponse; -import com.cotato.squadus.domain.club.match.entity.mercenary.MercenaryPost; - import java.time.LocalDate; import java.time.LocalTime; +import com.cotato.squadus.api.match.dto.matchPost.response.MatchPlaceResponse; +import com.cotato.squadus.domain.club.match.entity.mercenary.MercenaryPost; + public record MercenaryCreateResponse( - Long mercenaryIdx, - String title, - String content, - MatchPlaceResponse matchPlace, - Boolean placeProvided, - LocalDate matchStartDate, - LocalTime matchStartTime, - Integer maxParticipants, - Integer currentParticipants, - Long clubIdx, - String sportsCategory, - String clubName, - String clubLogo + Long mercenaryIdx, + String title, + String content, + MatchPlaceResponse matchPlace, + Boolean placeProvided, + LocalDate matchStartDate, + LocalTime matchStartTime, + Integer maxParticipants, + Integer currentParticipants, + Long clubIdx, + String sportsCategory, + String clubName, + String clubLogo ) { - public static MercenaryCreateResponse from(MercenaryPost mercenaryPost) { - return new MercenaryCreateResponse( - mercenaryPost.getMercenaryIdx(), - mercenaryPost.getTitle(), - mercenaryPost.getContent(), - MatchPlaceResponse.from(mercenaryPost.getMatchPlace()), - mercenaryPost.getPlaceProvided(), - mercenaryPost.getMatchStartDate(), - mercenaryPost.getMatchStartTime(), - mercenaryPost.getMaxParticipants(), - mercenaryPost.getCurrentParticipants(), - mercenaryPost.getHomeClub().getClubId(), - mercenaryPost.getHomeClub().getSportsCategory().name(), - mercenaryPost.getHomeClub().getClubName(), - mercenaryPost.getHomeClub().getLogo() - ); - } + public static MercenaryCreateResponse from(MercenaryPost mercenaryPost) { + return new MercenaryCreateResponse( + mercenaryPost.getMercenaryIdx(), + mercenaryPost.getTitle(), + mercenaryPost.getContent(), + MatchPlaceResponse.from(mercenaryPost.getMatchPlace()), + mercenaryPost.getPlaceProvided(), + mercenaryPost.getMatchStartDate(), + mercenaryPost.getMatchStartTime(), + mercenaryPost.getMaxParticipants(), + mercenaryPost.getCurrentParticipants(), + mercenaryPost.getHomeClub().getClubId(), + mercenaryPost.getHomeClub().getSportsCategory().name(), + mercenaryPost.getHomeClub().getClubName(), + mercenaryPost.getHomeClub().getLogo() + ); + } } diff --git a/src/main/java/com/cotato/squadus/api/mercenary/dto/response/MercenaryCreateResponseWrapper.java b/src/main/java/com/cotato/squadus/api/mercenary/dto/response/MercenaryCreateResponseWrapper.java index cbb8a5b..14d9ef6 100644 --- a/src/main/java/com/cotato/squadus/api/mercenary/dto/response/MercenaryCreateResponseWrapper.java +++ b/src/main/java/com/cotato/squadus/api/mercenary/dto/response/MercenaryCreateResponseWrapper.java @@ -1,19 +1,17 @@ package com.cotato.squadus.api.mercenary.dto.response; -import com.cotato.squadus.api.match.dto.matchPost.response.MatchCreateResponse; -import com.cotato.squadus.api.match.dto.matchPost.response.MatchCreateResponseWrapper; -import org.springframework.data.domain.Page; - import java.util.List; +import org.springframework.data.domain.Page; + public record MercenaryCreateResponseWrapper( - List matches + List matches ) { - public static MercenaryCreateResponseWrapper from(List responses) { - return new MercenaryCreateResponseWrapper(responses); - } + public static MercenaryCreateResponseWrapper from(List responses) { + return new MercenaryCreateResponseWrapper(responses); + } - public static MercenaryCreateResponseWrapper from(Page responses) { - return new MercenaryCreateResponseWrapper(responses.getContent()); - } + public static MercenaryCreateResponseWrapper from(Page responses) { + return new MercenaryCreateResponseWrapper(responses.getContent()); + } } diff --git a/src/main/java/com/cotato/squadus/api/mercenary/dto/response/MercenaryRequestAndMercenaryPostResponse.java b/src/main/java/com/cotato/squadus/api/mercenary/dto/response/MercenaryRequestAndMercenaryPostResponse.java index c9543df..091c5e3 100644 --- a/src/main/java/com/cotato/squadus/api/mercenary/dto/response/MercenaryRequestAndMercenaryPostResponse.java +++ b/src/main/java/com/cotato/squadus/api/mercenary/dto/response/MercenaryRequestAndMercenaryPostResponse.java @@ -1,18 +1,19 @@ package com.cotato.squadus.api.mercenary.dto.response; -import com.cotato.squadus.domain.club.match.entity.mercenary.MercenaryPost; - import java.util.List; +import com.cotato.squadus.domain.club.match.entity.mercenary.MercenaryPost; + public record MercenaryRequestAndMercenaryPostResponse( - MercenaryCreateResponse mercenaryCreateResponse, - List receivedRequests + MercenaryCreateResponse mercenaryCreateResponse, + List receivedRequests ) { - public static MercenaryRequestAndMercenaryPostResponse from(MercenaryPost mercenaryPost, List receivedRequests) { - return new MercenaryRequestAndMercenaryPostResponse( - MercenaryCreateResponse.from(mercenaryPost), - receivedRequests - ); - } + public static MercenaryRequestAndMercenaryPostResponse from(MercenaryPost mercenaryPost, + List receivedRequests) { + return new MercenaryRequestAndMercenaryPostResponse( + MercenaryCreateResponse.from(mercenaryPost), + receivedRequests + ); + } } diff --git a/src/main/java/com/cotato/squadus/api/mercenary/dto/response/MercenaryRequestAndMercenaryPostResponseWrapper.java b/src/main/java/com/cotato/squadus/api/mercenary/dto/response/MercenaryRequestAndMercenaryPostResponseWrapper.java index c23c63f..4840159 100644 --- a/src/main/java/com/cotato/squadus/api/mercenary/dto/response/MercenaryRequestAndMercenaryPostResponseWrapper.java +++ b/src/main/java/com/cotato/squadus/api/mercenary/dto/response/MercenaryRequestAndMercenaryPostResponseWrapper.java @@ -3,9 +3,10 @@ import java.util.List; public record MercenaryRequestAndMercenaryPostResponseWrapper( - List responses + List responses ) { - public static MercenaryRequestAndMercenaryPostResponseWrapper from(List responses) { - return new MercenaryRequestAndMercenaryPostResponseWrapper(responses); - } + public static MercenaryRequestAndMercenaryPostResponseWrapper from( + List responses) { + return new MercenaryRequestAndMercenaryPostResponseWrapper(responses); + } } diff --git a/src/main/java/com/cotato/squadus/api/mercenary/dto/response/MercenaryRequestResponse.java b/src/main/java/com/cotato/squadus/api/mercenary/dto/response/MercenaryRequestResponse.java index 57b7654..859eb67 100644 --- a/src/main/java/com/cotato/squadus/api/mercenary/dto/response/MercenaryRequestResponse.java +++ b/src/main/java/com/cotato/squadus/api/mercenary/dto/response/MercenaryRequestResponse.java @@ -4,15 +4,15 @@ import com.cotato.squadus.domain.club.match.enums.MatchingStatus; public record MercenaryRequestResponse( - Long mercenaryRequestIdx, - MatchingStatus status, - MercenaryCreateResponse mercenaryCreateResponse + Long mercenaryRequestIdx, + MatchingStatus status, + MercenaryCreateResponse mercenaryCreateResponse ) { - public static MercenaryRequestResponse from(MercenaryRequest mercenaryRequest) { - return new MercenaryRequestResponse( - mercenaryRequest.getMercenaryRequestIdx(),//쿼리 1개 발생 - mercenaryRequest.getStatus(), - MercenaryCreateResponse.from(mercenaryRequest.getMercenaryPost()) - ); - } + public static MercenaryRequestResponse from(MercenaryRequest mercenaryRequest) { + return new MercenaryRequestResponse( + mercenaryRequest.getMercenaryRequestIdx(),//쿼리 1개 발생 + mercenaryRequest.getStatus(), + MercenaryCreateResponse.from(mercenaryRequest.getMercenaryPost()) + ); + } } diff --git a/src/main/java/com/cotato/squadus/api/mercenary/dto/response/MercenaryRequestResponseWrapper.java b/src/main/java/com/cotato/squadus/api/mercenary/dto/response/MercenaryRequestResponseWrapper.java index 496ca5f..7fcfd21 100644 --- a/src/main/java/com/cotato/squadus/api/mercenary/dto/response/MercenaryRequestResponseWrapper.java +++ b/src/main/java/com/cotato/squadus/api/mercenary/dto/response/MercenaryRequestResponseWrapper.java @@ -1,19 +1,17 @@ package com.cotato.squadus.api.mercenary.dto.response; -import com.cotato.squadus.api.match.dto.matchPost.response.MatchRequestResponse; -import com.cotato.squadus.api.match.dto.matchPost.response.MatchRequestResponseWrapper; -import org.springframework.data.domain.Page; - import java.util.List; +import org.springframework.data.domain.Page; + public record MercenaryRequestResponseWrapper( - List matches + List matches ) { - public static MercenaryRequestResponseWrapper from(List responses) { - return new MercenaryRequestResponseWrapper(responses); - } + public static MercenaryRequestResponseWrapper from(List responses) { + return new MercenaryRequestResponseWrapper(responses); + } - public static MercenaryRequestResponseWrapper from(Page responses) { - return new MercenaryRequestResponseWrapper(responses.getContent()); - } + public static MercenaryRequestResponseWrapper from(Page responses) { + return new MercenaryRequestResponseWrapper(responses.getContent()); + } } diff --git a/src/main/java/com/cotato/squadus/api/mercenary/dto/response/MercenaryRequestStatusResponse.java b/src/main/java/com/cotato/squadus/api/mercenary/dto/response/MercenaryRequestStatusResponse.java index e0b97a3..d00a186 100644 --- a/src/main/java/com/cotato/squadus/api/mercenary/dto/response/MercenaryRequestStatusResponse.java +++ b/src/main/java/com/cotato/squadus/api/mercenary/dto/response/MercenaryRequestStatusResponse.java @@ -4,17 +4,17 @@ import com.cotato.squadus.domain.club.match.enums.MatchingStatus; public record MercenaryRequestStatusResponse( - Long mercenaryRequestId, -// String clubName, - String university, - MatchingStatus status + Long mercenaryRequestId, + // String clubName, + String university, + MatchingStatus status ) { - public static MercenaryRequestStatusResponse from(MercenaryRequest mercenaryRequest) { - return new MercenaryRequestStatusResponse( - mercenaryRequest.getMercenaryRequestIdx(), -// mercenaryRequest.getClubMember().getClub().getClubName(), //쿼리 발생 - mercenaryRequest.getMember().getUniversity(), //쿼리 발생 - mercenaryRequest.getStatus() - ); - } + public static MercenaryRequestStatusResponse from(MercenaryRequest mercenaryRequest) { + return new MercenaryRequestStatusResponse( + mercenaryRequest.getMercenaryRequestIdx(), + // mercenaryRequest.getClubMember().getClub().getClubName(), //쿼리 발생 + mercenaryRequest.getMember().getUniversity(), //쿼리 발생 + mercenaryRequest.getStatus() + ); + } } \ No newline at end of file diff --git a/src/main/java/com/cotato/squadus/api/mercenary/dto/response/ReceivedMercenaryRequestResponse.java b/src/main/java/com/cotato/squadus/api/mercenary/dto/response/ReceivedMercenaryRequestResponse.java index c5d773d..cbdff63 100644 --- a/src/main/java/com/cotato/squadus/api/mercenary/dto/response/ReceivedMercenaryRequestResponse.java +++ b/src/main/java/com/cotato/squadus/api/mercenary/dto/response/ReceivedMercenaryRequestResponse.java @@ -1,22 +1,21 @@ package com.cotato.squadus.api.mercenary.dto.response; import com.cotato.squadus.domain.club.match.entity.mercenary.MercenaryRequest; -import com.cotato.squadus.domain.club.match.enums.MatchingStatus; public record ReceivedMercenaryRequestResponse( - String matchingStatus, - Long requestId, - Long memberId, - String requestName, - String requesterUniversity + String matchingStatus, + Long requestId, + Long memberId, + String requestName, + String requesterUniversity ) { - public static ReceivedMercenaryRequestResponse from(MercenaryRequest mercenaryRequest) { - return new ReceivedMercenaryRequestResponse( - mercenaryRequest.getStatus().name(), - mercenaryRequest.getMercenaryRequestIdx(), - mercenaryRequest.getMember().getMemberIdx(), - mercenaryRequest.getMember().getUsername(), // 요청자 이름 - mercenaryRequest.getMember().getUniversity() // 요청자 소속 대학 - ); - } + public static ReceivedMercenaryRequestResponse from(MercenaryRequest mercenaryRequest) { + return new ReceivedMercenaryRequestResponse( + mercenaryRequest.getStatus().name(), + mercenaryRequest.getMercenaryRequestIdx(), + mercenaryRequest.getMember().getMemberIdx(), + mercenaryRequest.getMember().getUsername(), // 요청자 이름 + mercenaryRequest.getMember().getUniversity() // 요청자 소속 대학 + ); + } } \ No newline at end of file diff --git a/src/main/java/com/cotato/squadus/api/post/controller/ClubPostCommentController.java b/src/main/java/com/cotato/squadus/api/post/controller/ClubPostCommentController.java index 79768ba..c91a3ac 100644 --- a/src/main/java/com/cotato/squadus/api/post/controller/ClubPostCommentController.java +++ b/src/main/java/com/cotato/squadus/api/post/controller/ClubPostCommentController.java @@ -1,16 +1,28 @@ package com.cotato.squadus.api.post.controller; -import com.cotato.squadus.api.post.dto.*; +import java.util.List; + +import org.springframework.http.ResponseEntity; +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 org.springframework.web.bind.annotation.RestController; + +import com.cotato.squadus.api.post.dto.ClubPostCommentCreateRequest; +import com.cotato.squadus.api.post.dto.ClubPostCommentCreateResponse; +import com.cotato.squadus.api.post.dto.ClubPostCommentLikeResponse; +import com.cotato.squadus.api.post.dto.ClubPostCommentListResponse; +import com.cotato.squadus.api.post.dto.ClubPostCommentResponse; import com.cotato.squadus.domain.auth.service.ClubMemberService; import com.cotato.squadus.domain.club.post.service.ClubPostCommentService; + import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.*; - -import java.util.List; @Tag(name = "동아리 공지 댓글", description = "동아리 공지 댓글 관련 API") @Slf4j @@ -19,34 +31,38 @@ @RequiredArgsConstructor public class ClubPostCommentController { - private final ClubPostCommentService clubPostCommentService; - private final ClubMemberService clubMemberService; - - @GetMapping() - @Operation(summary = "동아리 공지 댓글 전체 조회", description = "clubId와 postId를 바탕으로 동아리 공지 댓글 전체를 조회합니다") - public ResponseEntity getAllClubPostComments(@PathVariable Long clubId, @PathVariable Long postId) { -// clubMemberService.validateClubMember(clubId); - List allClubPostComments = clubPostCommentService.findAllClubPostComments(postId); - log.info("공지에 대한 전체 댓글 조회 : {}", allClubPostComments); - return ResponseEntity.ok(ClubPostCommentListResponse.from(allClubPostComments)); - } - - @PostMapping() - @Operation(summary = "동아리 공지 댓글 생성", description = "clubId와 postId를 바탕으로 동아리 공지 댓글을 하나 생성합니다") - public ResponseEntity createClubPostComment( - @PathVariable Long clubId, - @PathVariable Long postId, - @RequestBody ClubPostCommentCreateRequest clubPostCommentCreateRequest) { -// clubMemberService.validateClubMember(clubId); - ClubPostCommentCreateResponse clubPostCommentCreateResponse = clubPostCommentService.createClubPostComment(clubId, postId, clubPostCommentCreateRequest); - return ResponseEntity.ok(clubPostCommentCreateResponse); - } - - @PatchMapping("/{commentId}/like") - @Operation(summary = "동아리 공지 댓글 좋아요", description = "clubId, postId, commentId를 바탕으로 동아리 공지 댓글에 대한 좋아요를 1 증가시킵니다") - public ResponseEntity increaseClubPostCommentLike(@PathVariable Long clubId, @PathVariable Long postId, @PathVariable Long commentId) { -// clubMemberService.validateClubMember(clubId); - ClubPostCommentLikeResponse clubPostCommentLikeResponse = clubPostCommentService.increaseClubPostCommentLike(clubId, commentId); - return ResponseEntity.ok(clubPostCommentLikeResponse); - } + private final ClubPostCommentService clubPostCommentService; + private final ClubMemberService clubMemberService; + + @GetMapping() + @Operation(summary = "동아리 공지 댓글 전체 조회", description = "clubId와 postId를 바탕으로 동아리 공지 댓글 전체를 조회합니다") + public ResponseEntity getAllClubPostComments(@PathVariable Long clubId, + @PathVariable Long postId) { + // clubMemberService.validateClubMember(clubId); + List allClubPostComments = clubPostCommentService.findAllClubPostComments(postId); + log.info("공지에 대한 전체 댓글 조회 : {}", allClubPostComments); + return ResponseEntity.ok(ClubPostCommentListResponse.from(allClubPostComments)); + } + + @PostMapping() + @Operation(summary = "동아리 공지 댓글 생성", description = "clubId와 postId를 바탕으로 동아리 공지 댓글을 하나 생성합니다") + public ResponseEntity createClubPostComment( + @PathVariable Long clubId, + @PathVariable Long postId, + @RequestBody ClubPostCommentCreateRequest clubPostCommentCreateRequest) { + // clubMemberService.validateClubMember(clubId); + ClubPostCommentCreateResponse clubPostCommentCreateResponse = clubPostCommentService.createClubPostComment( + clubId, postId, clubPostCommentCreateRequest); + return ResponseEntity.ok(clubPostCommentCreateResponse); + } + + @PatchMapping("/{commentId}/like") + @Operation(summary = "동아리 공지 댓글 좋아요", description = "clubId, postId, commentId를 바탕으로 동아리 공지 댓글에 대한 좋아요를 1 증가시킵니다") + public ResponseEntity increaseClubPostCommentLike(@PathVariable Long clubId, + @PathVariable Long postId, @PathVariable Long commentId) { + // clubMemberService.validateClubMember(clubId); + ClubPostCommentLikeResponse clubPostCommentLikeResponse = clubPostCommentService.increaseClubPostCommentLike( + clubId, commentId); + return ResponseEntity.ok(clubPostCommentLikeResponse); + } } diff --git a/src/main/java/com/cotato/squadus/api/post/controller/ClubPostController.java b/src/main/java/com/cotato/squadus/api/post/controller/ClubPostController.java index 833f06b..f6c56c1 100644 --- a/src/main/java/com/cotato/squadus/api/post/controller/ClubPostController.java +++ b/src/main/java/com/cotato/squadus/api/post/controller/ClubPostController.java @@ -1,19 +1,32 @@ package com.cotato.squadus.api.post.controller; -import com.cotato.squadus.api.post.dto.*; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +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.RequestMapping; +import org.springframework.web.bind.annotation.RequestPart; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.multipart.MultipartFile; + +import com.cotato.squadus.api.post.dto.ClubPostCreateRequest; +import com.cotato.squadus.api.post.dto.ClubPostCreateResponse; +import com.cotato.squadus.api.post.dto.ClubPostLikesResponse; +import com.cotato.squadus.api.post.dto.ClubPostListResponse; +import com.cotato.squadus.api.post.dto.ClubPostResponse; +import com.cotato.squadus.api.post.dto.ClubPostSummaryListResponse; import com.cotato.squadus.domain.club.post.service.ClubPostService; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; + import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.tags.Tag; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.springframework.http.MediaType; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.*; -import org.springframework.web.multipart.MultipartFile; @Tag(name = "동아리 공지", description = "동아리 공지 관련 API") @Slf4j @@ -22,64 +35,65 @@ @RequiredArgsConstructor public class ClubPostController { - private final ClubPostService clubPostService; - - @GetMapping("") - @Operation(summary = "동아리 공지 전체 조회", description = "clubId를 바탕으로 동아리 공지 전체를 조회합니다") - public ResponseEntity getAllClubPostsByClubId(@PathVariable Long clubId) { -// clubMemberService.validateClubMember(clubId); - ClubPostListResponse allClubPostsByClubId = clubPostService.findAllClubPostsByClubId(clubId); - log.info("ClubId로 동아리 공지 전체 조회 : {} ", allClubPostsByClubId); - return ResponseEntity.ok(allClubPostsByClubId); - } + private final ClubPostService clubPostService; - @GetMapping("/summary") - @Operation(summary = "동아리 공지 요약 전체 조회", description = "clubId를 바탕으로 동아리 공지에 대한 요약 전체를 조회합니다") - public ResponseEntity getAllClubPostsSummaryByClubId(@PathVariable Long clubId) { -// clubMemberService.validateClubMember(clubId); - ClubPostSummaryListResponse allClubPostsSummaryByClubId = clubPostService.findAllClubPostsSummaryByClubId(clubId); - log.info("ClubId로 동아리 공지 전체 조회(제목, 날짜) : {} ", allClubPostsSummaryByClubId); - return ResponseEntity.ok(allClubPostsSummaryByClubId); - } + @GetMapping("") + @Operation(summary = "동아리 공지 전체 조회", description = "clubId를 바탕으로 동아리 공지 전체를 조회합니다") + public ResponseEntity getAllClubPostsByClubId(@PathVariable Long clubId) { + // clubMemberService.validateClubMember(clubId); + ClubPostListResponse allClubPostsByClubId = clubPostService.findAllClubPostsByClubId(clubId); + return ResponseEntity.ok(allClubPostsByClubId); + } - @GetMapping("{postId}") - @Operation(summary = "동아리 공지 단건 조회", description = "postId를 바탕으로 동아리 공지 하나에 대한 정보를 조회합니다") - public ResponseEntity getPostByPostId(@PathVariable Long clubId, @PathVariable Long postId) { -// clubMemberService.validateClubMember(clubId); - ClubPostResponse clubPostByPostId = clubPostService.findClubPostByPostId(postId); - log.info("PostId로 동아리 공지 조회 : {} ", clubPostByPostId); - return ResponseEntity.ok(clubPostByPostId); - } + @GetMapping("/summary") + @Operation(summary = "동아리 공지 요약 전체 조회", description = "clubId를 바탕으로 동아리 공지에 대한 요약 전체를 조회합니다") + public ResponseEntity getAllClubPostsSummaryByClubId(@PathVariable Long clubId) { + // clubMemberService.validateClubMember(clubId); + ClubPostSummaryListResponse allClubPostsSummaryByClubId = clubPostService.findAllClubPostsSummaryByClubId( + clubId); + log.info("ClubId로 동아리 공지 전체 조회(제목, 날짜) : {} ", allClubPostsSummaryByClubId); + return ResponseEntity.ok(allClubPostsSummaryByClubId); + } - @PostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE) - @Operation(summary = "동아리 공지 생성", description = "동아리 공지를 하나 생성합니다") - public ResponseEntity createClubPost( - @PathVariable Long clubId, - @Parameter(description = "공지 사항 생성 요청 정보", schema = @Schema(implementation = ClubPostCreateRequest.class)) - @RequestPart("clubPostCreateRequest") String clubPostCreateRequestString, - @RequestPart(value = "image", required = false) MultipartFile imageFile) { + @GetMapping("{postId}") + @Operation(summary = "동아리 공지 단건 조회", description = "postId를 바탕으로 동아리 공지 하나에 대한 정보를 조회합니다") + public ResponseEntity getPostByPostId(@PathVariable Long clubId, @PathVariable Long postId) { + // clubMemberService.validateClubMember(clubId); + ClubPostResponse clubPostByPostId = clubPostService.findClubPostByPostId(postId); + log.info("PostId로 동아리 공지 조회 : {} ", clubPostByPostId); + return ResponseEntity.ok(clubPostByPostId); + } - // JSON String을 객체로 변환 - ObjectMapper objectMapper = new ObjectMapper(); - ClubPostCreateRequest clubPostCreateRequest; - try { - clubPostCreateRequest = objectMapper.readValue(clubPostCreateRequestString, ClubPostCreateRequest.class); - } catch (JsonProcessingException e) { - throw new RuntimeException("Invalid JSON format", e); - } + @PostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE) + @Operation(summary = "동아리 공지 생성", description = "동아리 공지를 하나 생성합니다") + public ResponseEntity createClubPost( + @PathVariable Long clubId, + @Parameter(description = "공지 사항 생성 요청 정보", schema = @Schema(implementation = ClubPostCreateRequest.class)) + @RequestPart("clubPostCreateRequest") String clubPostCreateRequestString, + @RequestPart(value = "image", required = false) MultipartFile imageFile) { - ClubPostCreateResponse clubPostCreateResponse = clubPostService.createClubPost(clubId, clubPostCreateRequest, imageFile); - log.info("동아리 공지 작성, postId: {} ", clubPostCreateResponse); - return ResponseEntity.ok(clubPostCreateResponse); - } + // JSON String을 객체로 변환 + ObjectMapper objectMapper = new ObjectMapper(); + ClubPostCreateRequest clubPostCreateRequest; + try { + clubPostCreateRequest = objectMapper.readValue(clubPostCreateRequestString, ClubPostCreateRequest.class); + } catch (JsonProcessingException e) { + throw new RuntimeException("Invalid JSON format", e); + } + ClubPostCreateResponse clubPostCreateResponse = clubPostService.createClubPost(clubId, clubPostCreateRequest, + imageFile); + log.info("동아리 공지 작성, postId: {} ", clubPostCreateResponse); + return ResponseEntity.ok(clubPostCreateResponse); + } - @PatchMapping("{postId}/like") - @Operation(summary = "동아리 공지 좋아요 증가", description = "postId를 바탕으로 동아리 공지의 좋아요를 1 증가시킵니다") - public ResponseEntity increaseClubPostLikes(@PathVariable Long clubId, @PathVariable Long postId) { -// clubMemberService.validateClubMember(clubId); - ClubPostLikesResponse clubPostLikesResponse = clubPostService.increaseClubPostLikes(clubId, postId); - log.info("동아리 공지 좋아요, likes: {} ", clubPostLikesResponse); - return ResponseEntity.ok(clubPostLikesResponse); - } + @PatchMapping("{postId}/like") + @Operation(summary = "동아리 공지 좋아요 증가", description = "postId를 바탕으로 동아리 공지의 좋아요를 1 증가시킵니다") + public ResponseEntity increaseClubPostLikes(@PathVariable Long clubId, + @PathVariable Long postId) { + // clubMemberService.validateClubMember(clubId); + ClubPostLikesResponse clubPostLikesResponse = clubPostService.increaseClubPostLikes(clubId, postId); + log.info("동아리 공지 좋아요, likes: {} ", clubPostLikesResponse); + return ResponseEntity.ok(clubPostLikesResponse); + } } diff --git a/src/main/java/com/cotato/squadus/api/post/dto/ClubPostCommentCreateRequest.java b/src/main/java/com/cotato/squadus/api/post/dto/ClubPostCommentCreateRequest.java index 33547cf..84a3d2f 100644 --- a/src/main/java/com/cotato/squadus/api/post/dto/ClubPostCommentCreateRequest.java +++ b/src/main/java/com/cotato/squadus/api/post/dto/ClubPostCommentCreateRequest.java @@ -1,6 +1,6 @@ package com.cotato.squadus.api.post.dto; public record ClubPostCommentCreateRequest( - String content + String content ) { } diff --git a/src/main/java/com/cotato/squadus/api/post/dto/ClubPostCommentCreateResponse.java b/src/main/java/com/cotato/squadus/api/post/dto/ClubPostCommentCreateResponse.java index 4687f6d..99d1fa5 100644 --- a/src/main/java/com/cotato/squadus/api/post/dto/ClubPostCommentCreateResponse.java +++ b/src/main/java/com/cotato/squadus/api/post/dto/ClubPostCommentCreateResponse.java @@ -1,6 +1,6 @@ package com.cotato.squadus.api.post.dto; public record ClubPostCommentCreateResponse( - Long commentId + Long commentId ) { } diff --git a/src/main/java/com/cotato/squadus/api/post/dto/ClubPostCommentLikeResponse.java b/src/main/java/com/cotato/squadus/api/post/dto/ClubPostCommentLikeResponse.java index b4863df..6cf2d2f 100644 --- a/src/main/java/com/cotato/squadus/api/post/dto/ClubPostCommentLikeResponse.java +++ b/src/main/java/com/cotato/squadus/api/post/dto/ClubPostCommentLikeResponse.java @@ -1,6 +1,6 @@ package com.cotato.squadus.api.post.dto; public record ClubPostCommentLikeResponse( - Long likes + Long likes ) { } diff --git a/src/main/java/com/cotato/squadus/api/post/dto/ClubPostCommentListResponse.java b/src/main/java/com/cotato/squadus/api/post/dto/ClubPostCommentListResponse.java index 0137e80..192602f 100644 --- a/src/main/java/com/cotato/squadus/api/post/dto/ClubPostCommentListResponse.java +++ b/src/main/java/com/cotato/squadus/api/post/dto/ClubPostCommentListResponse.java @@ -3,10 +3,10 @@ import java.util.List; public record ClubPostCommentListResponse( - List clubPostCommentResponseList + List clubPostCommentResponseList ) { - public static ClubPostCommentListResponse from(List clubPostCommentResponseList) { - return new ClubPostCommentListResponse(clubPostCommentResponseList); - } + public static ClubPostCommentListResponse from(List clubPostCommentResponseList) { + return new ClubPostCommentListResponse(clubPostCommentResponseList); + } } diff --git a/src/main/java/com/cotato/squadus/api/post/dto/ClubPostCommentResponse.java b/src/main/java/com/cotato/squadus/api/post/dto/ClubPostCommentResponse.java index 063329b..417c70b 100644 --- a/src/main/java/com/cotato/squadus/api/post/dto/ClubPostCommentResponse.java +++ b/src/main/java/com/cotato/squadus/api/post/dto/ClubPostCommentResponse.java @@ -1,26 +1,27 @@ package com.cotato.squadus.api.post.dto; -import com.cotato.squadus.domain.club.post.entity.ClubPostComment; import java.time.LocalDateTime; +import com.cotato.squadus.domain.club.post.entity.ClubPostComment; + public record ClubPostCommentResponse( - Long id, - String clubMemberName, - String content, - LocalDateTime createdDate, - String profileImgUrl, - Long likes + Long id, + String clubMemberName, + String content, + LocalDateTime createdDate, + String profileImgUrl, + Long likes ) { - public static ClubPostCommentResponse from(ClubPostComment clubPostComment) { - return new ClubPostCommentResponse( - clubPostComment.getId(), - clubPostComment.getClubMember().getMember().getUsername(), - clubPostComment.getContent(), - clubPostComment.getCreatedAt(), - clubPostComment.getClubMember().getMember().getProfileImage(), - clubPostComment.getLikes() - ); - } + public static ClubPostCommentResponse from(ClubPostComment clubPostComment) { + return new ClubPostCommentResponse( + clubPostComment.getId(), + clubPostComment.getClubMember().getMember().getUsername(), + clubPostComment.getContent(), + clubPostComment.getCreatedAt(), + clubPostComment.getClubMember().getMember().getProfileImage(), + clubPostComment.getLikes() + ); + } } diff --git a/src/main/java/com/cotato/squadus/api/post/dto/ClubPostCreateRequest.java b/src/main/java/com/cotato/squadus/api/post/dto/ClubPostCreateRequest.java index b8789c5..fd1e474 100644 --- a/src/main/java/com/cotato/squadus/api/post/dto/ClubPostCreateRequest.java +++ b/src/main/java/com/cotato/squadus/api/post/dto/ClubPostCreateRequest.java @@ -1,9 +1,9 @@ package com.cotato.squadus.api.post.dto; public record ClubPostCreateRequest( - String title, - String content, - Boolean hasVote, - Boolean isImportant + String title, + String content, + Boolean hasVote, + Boolean isImportant ) { } diff --git a/src/main/java/com/cotato/squadus/api/post/dto/ClubPostCreateResponse.java b/src/main/java/com/cotato/squadus/api/post/dto/ClubPostCreateResponse.java index 8a14699..39cd2aa 100644 --- a/src/main/java/com/cotato/squadus/api/post/dto/ClubPostCreateResponse.java +++ b/src/main/java/com/cotato/squadus/api/post/dto/ClubPostCreateResponse.java @@ -1,6 +1,6 @@ package com.cotato.squadus.api.post.dto; public record ClubPostCreateResponse( - Long id + Long id ) { } diff --git a/src/main/java/com/cotato/squadus/api/post/dto/ClubPostLikesResponse.java b/src/main/java/com/cotato/squadus/api/post/dto/ClubPostLikesResponse.java index 04920b2..3702010 100644 --- a/src/main/java/com/cotato/squadus/api/post/dto/ClubPostLikesResponse.java +++ b/src/main/java/com/cotato/squadus/api/post/dto/ClubPostLikesResponse.java @@ -1,6 +1,6 @@ package com.cotato.squadus.api.post.dto; public record ClubPostLikesResponse( - Long likes + Long likes ) { } diff --git a/src/main/java/com/cotato/squadus/api/post/dto/ClubPostListResponse.java b/src/main/java/com/cotato/squadus/api/post/dto/ClubPostListResponse.java index 30a1880..3a771e6 100644 --- a/src/main/java/com/cotato/squadus/api/post/dto/ClubPostListResponse.java +++ b/src/main/java/com/cotato/squadus/api/post/dto/ClubPostListResponse.java @@ -1,12 +1,12 @@ package com.cotato.squadus.api.post.dto; + import java.util.List; public record ClubPostListResponse( - List clubPosts + List clubPosts ) { - - public static ClubPostListResponse from(List clubPosts) { - return new ClubPostListResponse(clubPosts); - } + public static ClubPostListResponse from(List clubPosts) { + return new ClubPostListResponse(clubPosts); + } } diff --git a/src/main/java/com/cotato/squadus/api/post/dto/ClubPostResponse.java b/src/main/java/com/cotato/squadus/api/post/dto/ClubPostResponse.java index 84dfedb..c32d220 100644 --- a/src/main/java/com/cotato/squadus/api/post/dto/ClubPostResponse.java +++ b/src/main/java/com/cotato/squadus/api/post/dto/ClubPostResponse.java @@ -1,28 +1,28 @@ package com.cotato.squadus.api.post.dto; -import com.cotato.squadus.domain.club.post.entity.ClubPost; - import java.time.LocalDateTime; +import com.cotato.squadus.domain.club.post.entity.ClubPost; + public record ClubPostResponse( - Long postId, - String title, - String content, - String image, - LocalDateTime createdAt, - Long view, - Long likes + Long postId, + String title, + String content, + String image, + LocalDateTime createdAt, + Long view, + Long likes ) { - public static ClubPostResponse from(ClubPost clubPost) { - return new ClubPostResponse( - clubPost.getPostId(), - clubPost.getTitle(), - clubPost.getContent(), - clubPost.getImage(), - clubPost.getCreatedAt(), - clubPost.getViews(), - clubPost.getLikes() - ); - } + public static ClubPostResponse from(ClubPost clubPost) { + return new ClubPostResponse( + clubPost.getPostId(), + clubPost.getTitle(), + clubPost.getContent(), + clubPost.getImage(), + clubPost.getCreatedAt(), + clubPost.getViews(), + clubPost.getLikes() + ); + } } \ No newline at end of file diff --git a/src/main/java/com/cotato/squadus/api/post/dto/ClubPostSummaryListResponse.java b/src/main/java/com/cotato/squadus/api/post/dto/ClubPostSummaryListResponse.java index 52af452..80e1ef0 100644 --- a/src/main/java/com/cotato/squadus/api/post/dto/ClubPostSummaryListResponse.java +++ b/src/main/java/com/cotato/squadus/api/post/dto/ClubPostSummaryListResponse.java @@ -3,9 +3,9 @@ import java.util.List; public record ClubPostSummaryListResponse( - List clubPostSummaryResponses + List clubPostSummaryResponses ) { - public static ClubPostSummaryListResponse from(List clubPostSummaryList) { - return new ClubPostSummaryListResponse(clubPostSummaryList); - } + public static ClubPostSummaryListResponse from(List clubPostSummaryList) { + return new ClubPostSummaryListResponse(clubPostSummaryList); + } } diff --git a/src/main/java/com/cotato/squadus/api/post/dto/ClubPostSummaryResponse.java b/src/main/java/com/cotato/squadus/api/post/dto/ClubPostSummaryResponse.java index 756ecc7..455e8e5 100644 --- a/src/main/java/com/cotato/squadus/api/post/dto/ClubPostSummaryResponse.java +++ b/src/main/java/com/cotato/squadus/api/post/dto/ClubPostSummaryResponse.java @@ -1,20 +1,20 @@ package com.cotato.squadus.api.post.dto; -import com.cotato.squadus.domain.club.post.entity.ClubPost; - import java.time.LocalDateTime; +import com.cotato.squadus.domain.club.post.entity.ClubPost; + public record ClubPostSummaryResponse( - Long postId, - String title, - LocalDateTime createdAt + Long postId, + String title, + LocalDateTime createdAt ) { - public static ClubPostSummaryResponse from(ClubPost clubPost) { - return new ClubPostSummaryResponse( - clubPost.getPostId(), - clubPost.getTitle(), - clubPost.getCreatedAt() - ); - } + public static ClubPostSummaryResponse from(ClubPost clubPost) { + return new ClubPostSummaryResponse( + clubPost.getPostId(), + clubPost.getTitle(), + clubPost.getCreatedAt() + ); + } } \ No newline at end of file diff --git a/src/main/java/com/cotato/squadus/api/recruit/controller/RecruitingPostController.java b/src/main/java/com/cotato/squadus/api/recruit/controller/RecruitingPostController.java index e204bff..0b53bee 100644 --- a/src/main/java/com/cotato/squadus/api/recruit/controller/RecruitingPostController.java +++ b/src/main/java/com/cotato/squadus/api/recruit/controller/RecruitingPostController.java @@ -1,5 +1,16 @@ package com.cotato.squadus.api.recruit.controller; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.web.PageableDefault; +import org.springframework.http.ResponseEntity; +import org.springframework.security.core.annotation.AuthenticationPrincipal; +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.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; import com.cotato.squadus.api.recruit.dto.RecruitingPostCreateRequest; import com.cotato.squadus.api.recruit.dto.RecruitingPostCreateResponse; @@ -7,16 +18,11 @@ import com.cotato.squadus.api.recruit.dto.RecruitingPostResponse; import com.cotato.squadus.common.config.auth.CustomOAuth2Member; import com.cotato.squadus.domain.club.recruit.service.RecruitingPostService; + import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.springframework.data.domain.Page; -import org.springframework.data.domain.Pageable; -import org.springframework.data.web.PageableDefault; -import org.springframework.http.ResponseEntity; -import org.springframework.security.core.annotation.AuthenticationPrincipal; -import org.springframework.web.bind.annotation.*; @Tag(name = "동아리 홍보 글", description = "동아리 홍보글 관련 API") @Slf4j @@ -25,29 +31,34 @@ @RequiredArgsConstructor public class RecruitingPostController { - private final RecruitingPostService recruitingPostService; - - @GetMapping() - @Operation(summary = "동아리 홍보글 전체 조회(페이징 단위: 10)", description = "동아리 홍보글 전체를 10개씩 페이징하여 조회합니다.") - public ResponseEntity> findAllRecruitingPosts(@AuthenticationPrincipal CustomOAuth2Member customOAuth2Member, @PageableDefault(size = 10) Pageable pageable) { - Page allRecruitingPosts = recruitingPostService.findAllRecruitingPosts(customOAuth2Member, pageable); - return ResponseEntity.ok(allRecruitingPosts); - } - - @GetMapping("/{recruitingPostId}") - @Operation(summary = "동아리 홍보글 단건 조회", description = "홍보글의 id를 통해 동아리 홍보글 하나에 대한 정보를 조회합니다.") - public ResponseEntity findRecruitingPostByPostId(@AuthenticationPrincipal CustomOAuth2Member customOAuth2Member, @PathVariable Long recruitingPostId) { - RecruitingPostInfoResponse recruitingPostByPostId = recruitingPostService.findRecruitingPostByPostId(customOAuth2Member, recruitingPostId); - return ResponseEntity.ok(recruitingPostByPostId); - } + private final RecruitingPostService recruitingPostService; - @PostMapping - @Operation(summary = "동아리 홍보글 생성", description = "동아리 홍보글을 생성합니다") - public ResponseEntity createRecruitingPost(@AuthenticationPrincipal CustomOAuth2Member customOAuth2Member, @RequestBody RecruitingPostCreateRequest recruitingPostCreateRequest) { - RecruitingPostCreateResponse recruitingPost = recruitingPostService.createRecruitingPost(customOAuth2Member, recruitingPostCreateRequest); - return ResponseEntity.ok(recruitingPost); - } + @GetMapping() + @Operation(summary = "동아리 홍보글 전체 조회(페이징 단위: 10)", description = "동아리 홍보글 전체를 10개씩 페이징하여 조회합니다.") + public ResponseEntity> findAllRecruitingPosts( + @AuthenticationPrincipal CustomOAuth2Member customOAuth2Member, @PageableDefault(size = 10) Pageable pageable) { + Page allRecruitingPosts = recruitingPostService.findAllRecruitingPosts( + customOAuth2Member, pageable); + return ResponseEntity.ok(allRecruitingPosts); + } + @GetMapping("/{recruitingPostId}") + @Operation(summary = "동아리 홍보글 단건 조회", description = "홍보글의 id를 통해 동아리 홍보글 하나에 대한 정보를 조회합니다.") + public ResponseEntity findRecruitingPostByPostId( + @AuthenticationPrincipal CustomOAuth2Member customOAuth2Member, @PathVariable Long recruitingPostId) { + RecruitingPostInfoResponse recruitingPostByPostId = recruitingPostService.findRecruitingPostByPostId( + customOAuth2Member, recruitingPostId); + return ResponseEntity.ok(recruitingPostByPostId); + } + @PostMapping + @Operation(summary = "동아리 홍보글 생성", description = "동아리 홍보글을 생성합니다") + public ResponseEntity createRecruitingPost( + @AuthenticationPrincipal CustomOAuth2Member customOAuth2Member, + @RequestBody RecruitingPostCreateRequest recruitingPostCreateRequest) { + RecruitingPostCreateResponse recruitingPost = recruitingPostService.createRecruitingPost(customOAuth2Member, + recruitingPostCreateRequest); + return ResponseEntity.ok(recruitingPost); + } } diff --git a/src/main/java/com/cotato/squadus/api/recruit/dto/RecruitingPostCreateRequest.java b/src/main/java/com/cotato/squadus/api/recruit/dto/RecruitingPostCreateRequest.java index 639810f..6ee0967 100644 --- a/src/main/java/com/cotato/squadus/api/recruit/dto/RecruitingPostCreateRequest.java +++ b/src/main/java/com/cotato/squadus/api/recruit/dto/RecruitingPostCreateRequest.java @@ -4,10 +4,10 @@ import java.util.Map; public record RecruitingPostCreateRequest( - Long clubId, - String title, - LocalDate startDate, - LocalDate endDate, - Map questions + Long clubId, + String title, + LocalDate startDate, + LocalDate endDate, + Map questions ) { } diff --git a/src/main/java/com/cotato/squadus/api/recruit/dto/RecruitingPostCreateResponse.java b/src/main/java/com/cotato/squadus/api/recruit/dto/RecruitingPostCreateResponse.java index 1833267..840aefb 100644 --- a/src/main/java/com/cotato/squadus/api/recruit/dto/RecruitingPostCreateResponse.java +++ b/src/main/java/com/cotato/squadus/api/recruit/dto/RecruitingPostCreateResponse.java @@ -1,6 +1,6 @@ package com.cotato.squadus.api.recruit.dto; public record RecruitingPostCreateResponse( - Long postId + Long postId ) { } diff --git a/src/main/java/com/cotato/squadus/api/recruit/dto/RecruitingPostInfoResponse.java b/src/main/java/com/cotato/squadus/api/recruit/dto/RecruitingPostInfoResponse.java index 5f054b2..ede409f 100644 --- a/src/main/java/com/cotato/squadus/api/recruit/dto/RecruitingPostInfoResponse.java +++ b/src/main/java/com/cotato/squadus/api/recruit/dto/RecruitingPostInfoResponse.java @@ -1,22 +1,22 @@ package com.cotato.squadus.api.recruit.dto; +import java.util.Map; + import com.cotato.squadus.domain.club.common.enums.SportsCategory; import com.cotato.squadus.domain.club.recruit.entity.RecruitingPost; -import java.util.Map; - public record RecruitingPostInfoResponse( - Long recruitingPostId, - SportsCategory sportsCategory, - Map questions + Long recruitingPostId, + SportsCategory sportsCategory, + Map questions ) { - public static RecruitingPostInfoResponse from(RecruitingPost recruitingPost) { - return new RecruitingPostInfoResponse( - recruitingPost.getPostId(), - recruitingPost.getClub().getSportsCategory(), - recruitingPost.getQuestions() - ); - } + public static RecruitingPostInfoResponse from(RecruitingPost recruitingPost) { + return new RecruitingPostInfoResponse( + recruitingPost.getPostId(), + recruitingPost.getClub().getSportsCategory(), + recruitingPost.getQuestions() + ); + } } diff --git a/src/main/java/com/cotato/squadus/api/recruit/dto/RecruitingPostResponse.java b/src/main/java/com/cotato/squadus/api/recruit/dto/RecruitingPostResponse.java index d0e1992..0608d53 100644 --- a/src/main/java/com/cotato/squadus/api/recruit/dto/RecruitingPostResponse.java +++ b/src/main/java/com/cotato/squadus/api/recruit/dto/RecruitingPostResponse.java @@ -1,43 +1,43 @@ package com.cotato.squadus.api.recruit.dto; +import java.time.LocalDate; +import java.util.List; + import com.cotato.squadus.domain.club.common.entity.Region; import com.cotato.squadus.domain.club.common.enums.ClubCategory; import com.cotato.squadus.domain.club.common.enums.ClubTier; import com.cotato.squadus.domain.club.common.enums.SportsCategory; import com.cotato.squadus.domain.club.recruit.entity.RecruitingPost; -import java.time.LocalDate; -import java.util.List; - public record RecruitingPostResponse( - Long recruitingPostId, - Long clubId, - String clubName, - Boolean isActive, - String title, - LocalDate startDate, - LocalDate endDate, - SportsCategory sportsCategory, - ClubCategory clubCategory, - Region region, - ClubTier clubTier, - List tags + Long recruitingPostId, + Long clubId, + String clubName, + Boolean isActive, + String title, + LocalDate startDate, + LocalDate endDate, + SportsCategory sportsCategory, + ClubCategory clubCategory, + Region region, + ClubTier clubTier, + List tags ) { - public static RecruitingPostResponse from(RecruitingPost recruitingPost) { - return new RecruitingPostResponse( - recruitingPost.getPostId(), - recruitingPost.getClub().getClubId(), - recruitingPost.getClub().getClubName(), - recruitingPost.getIsActive(), - recruitingPost.getTitle(), - recruitingPost.getStartDate(), - recruitingPost.getEndDate(), - recruitingPost.getClub().getSportsCategory(), - recruitingPost.getClub().getClubCategory(), - recruitingPost.getClub().getRegion(), - recruitingPost.getClub().getClubTier(), - recruitingPost.getClub().getTags() - ); - } + public static RecruitingPostResponse from(RecruitingPost recruitingPost) { + return new RecruitingPostResponse( + recruitingPost.getPostId(), + recruitingPost.getClub().getClubId(), + recruitingPost.getClub().getClubName(), + recruitingPost.getIsActive(), + recruitingPost.getTitle(), + recruitingPost.getStartDate(), + recruitingPost.getEndDate(), + recruitingPost.getClub().getSportsCategory(), + recruitingPost.getClub().getClubCategory(), + recruitingPost.getClub().getRegion(), + recruitingPost.getClub().getClubTier(), + recruitingPost.getClub().getTags() + ); + } } diff --git a/src/main/java/com/cotato/squadus/api/recruit/dto/RecruitingPostResponseList.java b/src/main/java/com/cotato/squadus/api/recruit/dto/RecruitingPostResponseList.java index c273136..72ba52d 100644 --- a/src/main/java/com/cotato/squadus/api/recruit/dto/RecruitingPostResponseList.java +++ b/src/main/java/com/cotato/squadus/api/recruit/dto/RecruitingPostResponseList.java @@ -3,9 +3,9 @@ import java.util.List; public record RecruitingPostResponseList( - List recruitingPostResponseList + List recruitingPostResponseList ) { - public static RecruitingPostResponseList from(List recruitingPostResponseList) { - return new RecruitingPostResponseList(recruitingPostResponseList); - } + public static RecruitingPostResponseList from(List recruitingPostResponseList) { + return new RecruitingPostResponseList(recruitingPostResponseList); + } } diff --git a/src/main/java/com/cotato/squadus/api/schedule/controller/ClubScheduleController.java b/src/main/java/com/cotato/squadus/api/schedule/controller/ClubScheduleController.java index 182022e..9db41b1 100644 --- a/src/main/java/com/cotato/squadus/api/schedule/controller/ClubScheduleController.java +++ b/src/main/java/com/cotato/squadus/api/schedule/controller/ClubScheduleController.java @@ -1,20 +1,29 @@ package com.cotato.squadus.api.schedule.controller; +import java.time.LocalDate; +import java.util.List; + +import org.springframework.format.annotation.DateTimeFormat; +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.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + import com.cotato.squadus.api.schedule.dto.ClubScheduleListResponse; import com.cotato.squadus.api.schedule.dto.ClubScheduleRequest; import com.cotato.squadus.api.schedule.dto.ClubScheduleResponse; import com.cotato.squadus.domain.club.schedule.service.ClubScheduleService; + import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.springframework.format.annotation.DateTimeFormat; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.*; - -import java.time.LocalDate; -import java.time.YearMonth; -import java.util.List; @Tag(name = "동아리 일정", description = "동아리 일정 관련 API") @Slf4j @@ -23,57 +32,61 @@ @RequiredArgsConstructor public class ClubScheduleController { - private final ClubScheduleService clubScheduleService; + private final ClubScheduleService clubScheduleService; - @GetMapping - @Operation(summary = "동아리 일정 전체 조회", description = "clubId를 바탕으로 동아리 공지 댓글 전체를 조회합니다") - public ResponseEntity getAllSchedules(@PathVariable Long clubId) { - List schedules = clubScheduleService.findAllSchedules(clubId); - return ResponseEntity.ok(ClubScheduleListResponse.from(schedules)); - } + @GetMapping + @Operation(summary = "동아리 일정 전체 조회", description = "clubId를 바탕으로 동아리 공지 댓글 전체를 조회합니다") + public ResponseEntity getAllSchedules(@PathVariable Long clubId) { + List schedules = clubScheduleService.findAllSchedules(clubId); + return ResponseEntity.ok(ClubScheduleListResponse.from(schedules)); + } - @GetMapping("/date") - @Operation(summary = "동아리 일정 날짜로 조회", description = "clubId와 설정한 날짜를 바탕으로 동아리 일정을 조회합니다") - public ResponseEntity getSchedulesByDate(@PathVariable Long clubId, - @RequestParam @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate date) { - List schedules = clubScheduleService.findSchedulesByDate(clubId, date); - return ResponseEntity.ok(ClubScheduleListResponse.from(schedules)); - } + @GetMapping("/date") + @Operation(summary = "동아리 일정 날짜로 조회", description = "clubId와 설정한 날짜를 바탕으로 동아리 일정을 조회합니다") + public ResponseEntity getSchedulesByDate(@PathVariable Long clubId, + @RequestParam @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate date) { + List schedules = clubScheduleService.findSchedulesByDate(clubId, date); + return ResponseEntity.ok(ClubScheduleListResponse.from(schedules)); + } - @GetMapping("/month") - public ResponseEntity getSchedulesByMonth(@PathVariable Long clubId, - @RequestParam int year, - @RequestParam int month) { - List schedules = clubScheduleService.findSchedulesByYearMonth(clubId, year, month); - return ResponseEntity.ok(ClubScheduleListResponse.from(schedules)); - } + @GetMapping("/month") + public ResponseEntity getSchedulesByMonth(@PathVariable Long clubId, + @RequestParam int year, + @RequestParam int month) { + List schedules = clubScheduleService.findSchedulesByYearMonth(clubId, year, month); + return ResponseEntity.ok(ClubScheduleListResponse.from(schedules)); + } - @PostMapping - @Operation(summary = "동아리 일정 단건 생성", description = "clubId와 일정에 대한 정보를 바탕으로 동아리 일정을 생성합니다") - public ResponseEntity createSchedule(@PathVariable Long clubId, @RequestBody ClubScheduleRequest scheduleRequest) { - ClubScheduleResponse schedule = clubScheduleService.createSchedule(clubId, scheduleRequest); - return ResponseEntity.ok(schedule); - } + @PostMapping + @Operation(summary = "동아리 일정 단건 생성", description = "clubId와 일정에 대한 정보를 바탕으로 동아리 일정을 생성합니다") + public ResponseEntity createSchedule(@PathVariable Long clubId, + @RequestBody ClubScheduleRequest scheduleRequest) { + ClubScheduleResponse schedule = clubScheduleService.createSchedule(clubId, scheduleRequest); + return ResponseEntity.ok(schedule); + } - @DeleteMapping("/{scheduleId}") - @Operation(summary = "동아리 일정 단건 삭제", description = "clubId와 scheduleId를 바탕으로 동아리 일정을 삭제합니다") - public ResponseEntity deleteSchedule(@PathVariable Long clubId, @PathVariable Long scheduleId, @RequestParam Long adminId) { - clubScheduleService.deleteSchedule(clubId, scheduleId, adminId); - return ResponseEntity.noContent().build(); - } + @DeleteMapping("/{scheduleId}") + @Operation(summary = "동아리 일정 단건 삭제", description = "clubId와 scheduleId를 바탕으로 동아리 일정을 삭제합니다") + public ResponseEntity deleteSchedule(@PathVariable Long clubId, @PathVariable Long scheduleId, + @RequestParam Long adminId) { + clubScheduleService.deleteSchedule(clubId, scheduleId, adminId); + return ResponseEntity.noContent().build(); + } - @PutMapping("/{scheduleId}") - @Operation(summary = "동아리 일정 수정", description = "clubId와 scheduleId와 일정에 대한 바뀐 정보를 바탕으로 동아리 일정을 수정합니다") - public ResponseEntity updateSchedule(@PathVariable Long clubId, @PathVariable Long scheduleId, @RequestBody ClubScheduleRequest scheduleRequest) { - ClubScheduleResponse schedule = clubScheduleService.updateSchedule(clubId, scheduleId, scheduleRequest); - return ResponseEntity.ok(schedule); - } + @PutMapping("/{scheduleId}") + @Operation(summary = "동아리 일정 수정", description = "clubId와 scheduleId와 일정에 대한 바뀐 정보를 바탕으로 동아리 일정을 수정합니다") + public ResponseEntity updateSchedule(@PathVariable Long clubId, @PathVariable Long scheduleId, + @RequestBody ClubScheduleRequest scheduleRequest) { + ClubScheduleResponse schedule = clubScheduleService.updateSchedule(clubId, scheduleId, scheduleRequest); + return ResponseEntity.ok(schedule); + } - @GetMapping("/upcoming") - @Operation(summary = "임박한 일정 조회", description = "clubId를 바탕으로 임박한 일정 3개(변경 가능)를 조회합니다") - public ResponseEntity getUpcomingSchedules(@PathVariable Long clubId, @RequestParam(defaultValue = "3") int limit) { - List schedules = clubScheduleService.findTopUpcomingSchedules(clubId, limit); - return ResponseEntity.ok(ClubScheduleListResponse.from(schedules)); - } + @GetMapping("/upcoming") + @Operation(summary = "임박한 일정 조회", description = "clubId를 바탕으로 임박한 일정 3개(변경 가능)를 조회합니다") + public ResponseEntity getUpcomingSchedules(@PathVariable Long clubId, + @RequestParam(defaultValue = "3") int limit) { + List schedules = clubScheduleService.findTopUpcomingSchedules(clubId, limit); + return ResponseEntity.ok(ClubScheduleListResponse.from(schedules)); + } } \ No newline at end of file diff --git a/src/main/java/com/cotato/squadus/api/schedule/controller/ScheduleCommentController.java b/src/main/java/com/cotato/squadus/api/schedule/controller/ScheduleCommentController.java index 1792117..1cf0843 100644 --- a/src/main/java/com/cotato/squadus/api/schedule/controller/ScheduleCommentController.java +++ b/src/main/java/com/cotato/squadus/api/schedule/controller/ScheduleCommentController.java @@ -1,16 +1,26 @@ package com.cotato.squadus.api.schedule.controller; +import java.util.List; + +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.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + import com.cotato.squadus.api.schedule.dto.LikeResponse; import com.cotato.squadus.api.schedule.dto.ScheduleCommentListResponse; import com.cotato.squadus.api.schedule.dto.ScheduleCommentRequest; import com.cotato.squadus.api.schedule.dto.ScheduleCommentResponse; import com.cotato.squadus.domain.club.schedule.service.ScheduleCommentService; + import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.*; - -import java.util.List; @Slf4j @RestController @@ -18,36 +28,40 @@ @RequiredArgsConstructor public class ScheduleCommentController { - private final ScheduleCommentService commentService; - - @PostMapping - public ResponseEntity addComment(@PathVariable Long scheduleId, @RequestBody ScheduleCommentRequest commentRequest) { - ScheduleCommentResponse commentResponse = commentService.addComment(scheduleId, commentRequest); - return ResponseEntity.ok(commentResponse); - } - - @PutMapping("/{commentId}") - public ResponseEntity updateComment(@PathVariable Long scheduleId, @PathVariable Long commentId, @RequestBody ScheduleCommentRequest commentUpdateRequest) { - ScheduleCommentResponse commentResponse = commentService.updateComment(scheduleId, commentId, commentUpdateRequest); - return ResponseEntity.ok(commentResponse); - } - - @DeleteMapping("/{commentId}") - public ResponseEntity deleteComment(@PathVariable Long scheduleId, @PathVariable Long commentId, @RequestParam Long memberId) { - commentService.deleteComment(scheduleId, commentId, memberId); - return ResponseEntity.noContent().build(); - } - - @GetMapping - public ResponseEntity getAllComments(@PathVariable Long scheduleId) { - List comments = commentService.getAllComments(scheduleId); - - return ResponseEntity.ok(ScheduleCommentListResponse.from(comments)); - } - - @PostMapping("/{commentId}/like") - public ResponseEntity likeComment(@PathVariable Long scheduleId, @PathVariable Long commentId) { - LikeResponse likeResponse = commentService.likeComment(scheduleId, commentId); - return ResponseEntity.ok(likeResponse); - } + private final ScheduleCommentService commentService; + + @PostMapping + public ResponseEntity addComment(@PathVariable Long scheduleId, + @RequestBody ScheduleCommentRequest commentRequest) { + ScheduleCommentResponse commentResponse = commentService.addComment(scheduleId, commentRequest); + return ResponseEntity.ok(commentResponse); + } + + @PutMapping("/{commentId}") + public ResponseEntity updateComment(@PathVariable Long scheduleId, + @PathVariable Long commentId, @RequestBody ScheduleCommentRequest commentUpdateRequest) { + ScheduleCommentResponse commentResponse = commentService.updateComment(scheduleId, commentId, + commentUpdateRequest); + return ResponseEntity.ok(commentResponse); + } + + @DeleteMapping("/{commentId}") + public ResponseEntity deleteComment(@PathVariable Long scheduleId, @PathVariable Long commentId, + @RequestParam Long memberId) { + commentService.deleteComment(scheduleId, commentId, memberId); + return ResponseEntity.noContent().build(); + } + + @GetMapping + public ResponseEntity getAllComments(@PathVariable Long scheduleId) { + List comments = commentService.getAllComments(scheduleId); + + return ResponseEntity.ok(ScheduleCommentListResponse.from(comments)); + } + + @PostMapping("/{commentId}/like") + public ResponseEntity likeComment(@PathVariable Long scheduleId, @PathVariable Long commentId) { + LikeResponse likeResponse = commentService.likeComment(scheduleId, commentId); + return ResponseEntity.ok(likeResponse); + } } diff --git a/src/main/java/com/cotato/squadus/api/schedule/dto/ClubScheduleCommentResponse.java b/src/main/java/com/cotato/squadus/api/schedule/dto/ClubScheduleCommentResponse.java index 718325c..6bcc8bb 100644 --- a/src/main/java/com/cotato/squadus/api/schedule/dto/ClubScheduleCommentResponse.java +++ b/src/main/java/com/cotato/squadus/api/schedule/dto/ClubScheduleCommentResponse.java @@ -5,17 +5,17 @@ import java.time.LocalDateTime; public record ClubScheduleCommentResponse( - Long commentId, - String content, - Long likes, - LocalDateTime createdAt + Long commentId, + String content, + Long likes, + LocalDateTime createdAt ) { - public static ClubScheduleCommentResponse from(ScheduleComment comment) { - return new ClubScheduleCommentResponse( - comment.getId(), - comment.getContent(), - comment.getLikes(), - comment.getCreatedAt() - ); - } + public static ClubScheduleCommentResponse from(ScheduleComment comment) { + return new ClubScheduleCommentResponse( + comment.getId(), + comment.getContent(), + comment.getLikes(), + comment.getCreatedAt() + ); + } } \ No newline at end of file diff --git a/src/main/java/com/cotato/squadus/api/schedule/dto/ClubScheduleListResponse.java b/src/main/java/com/cotato/squadus/api/schedule/dto/ClubScheduleListResponse.java index 3b2d2af..86242d4 100644 --- a/src/main/java/com/cotato/squadus/api/schedule/dto/ClubScheduleListResponse.java +++ b/src/main/java/com/cotato/squadus/api/schedule/dto/ClubScheduleListResponse.java @@ -3,7 +3,7 @@ import java.util.List; public record ClubScheduleListResponse(List schedules) { - public static ClubScheduleListResponse from(List schedules) { - return new ClubScheduleListResponse(schedules); - } + public static ClubScheduleListResponse from(List schedules) { + return new ClubScheduleListResponse(schedules); + } } diff --git a/src/main/java/com/cotato/squadus/api/schedule/dto/ClubScheduleRequest.java b/src/main/java/com/cotato/squadus/api/schedule/dto/ClubScheduleRequest.java index 14ae85f..5a0d02a 100644 --- a/src/main/java/com/cotato/squadus/api/schedule/dto/ClubScheduleRequest.java +++ b/src/main/java/com/cotato/squadus/api/schedule/dto/ClubScheduleRequest.java @@ -1,21 +1,21 @@ package com.cotato.squadus.api.schedule.dto; -import lombok.Getter; -import lombok.Setter; - import java.time.LocalDate; import java.time.LocalTime; +import lombok.Getter; +import lombok.Setter; + @Getter @Setter public class ClubScheduleRequest { - private String title; - private String scheduleCategory; - private String content; - private Long authorId; - private String location; - private String equipment; - private LocalDate date; - private LocalTime startTime; - private LocalTime endTime; + private String title; + private String scheduleCategory; + private String content; + private Long authorId; + private String location; + private String equipment; + private LocalDate date; + private LocalTime startTime; + private LocalTime endTime; } \ No newline at end of file diff --git a/src/main/java/com/cotato/squadus/api/schedule/dto/ClubScheduleResponse.java b/src/main/java/com/cotato/squadus/api/schedule/dto/ClubScheduleResponse.java index 57ca426..d3b5a54 100644 --- a/src/main/java/com/cotato/squadus/api/schedule/dto/ClubScheduleResponse.java +++ b/src/main/java/com/cotato/squadus/api/schedule/dto/ClubScheduleResponse.java @@ -1,39 +1,39 @@ package com.cotato.squadus.api.schedule.dto; -import com.cotato.squadus.domain.club.schedule.entity.ClubSchedule; -import com.fasterxml.jackson.annotation.JsonFormat; - import java.time.LocalDate; import java.time.LocalTime; +import com.cotato.squadus.domain.club.schedule.entity.ClubSchedule; +import com.fasterxml.jackson.annotation.JsonFormat; + public record ClubScheduleResponse( - Long scheduleIdx, - String title, - String scheduleCategory, - String content, - Long authorId, - String location, - String equipment, - LocalDate date, + Long scheduleIdx, + String title, + String scheduleCategory, + String content, + Long authorId, + String location, + String equipment, + LocalDate date, - @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "HH:mm") - LocalTime startTime, + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "HH:mm") + LocalTime startTime, - @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "HH:mm") - LocalTime endTime + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "HH:mm") + LocalTime endTime ) { - public static ClubScheduleResponse from(ClubSchedule schedule) { - return new ClubScheduleResponse( - schedule.getScheduleIdx(), - schedule.getTitle(), - schedule.getScheduleCategory().name(), - schedule.getContent(), - schedule.getAuthor().getClubMemberIdx(), - schedule.getLocation(), - schedule.getEquipment(), - schedule.getDate(), - schedule.getStartTime(), - schedule.getEndTime() - ); - } + public static ClubScheduleResponse from(ClubSchedule schedule) { + return new ClubScheduleResponse( + schedule.getScheduleIdx(), + schedule.getTitle(), + schedule.getScheduleCategory().name(), + schedule.getContent(), + schedule.getAuthor().getClubMemberIdx(), + schedule.getLocation(), + schedule.getEquipment(), + schedule.getDate(), + schedule.getStartTime(), + schedule.getEndTime() + ); + } } diff --git a/src/main/java/com/cotato/squadus/api/schedule/dto/LikeResponse.java b/src/main/java/com/cotato/squadus/api/schedule/dto/LikeResponse.java index 9615685..0643a43 100644 --- a/src/main/java/com/cotato/squadus/api/schedule/dto/LikeResponse.java +++ b/src/main/java/com/cotato/squadus/api/schedule/dto/LikeResponse.java @@ -1,7 +1,7 @@ package com.cotato.squadus.api.schedule.dto; public record LikeResponse(Long commentId, Long likes) { - public static LikeResponse from(Long commentId, Long likes) { - return new LikeResponse(commentId, likes); - } + public static LikeResponse from(Long commentId, Long likes) { + return new LikeResponse(commentId, likes); + } } diff --git a/src/main/java/com/cotato/squadus/api/schedule/dto/ScheduleCommentListResponse.java b/src/main/java/com/cotato/squadus/api/schedule/dto/ScheduleCommentListResponse.java index 8c085cf..bcc4a53 100644 --- a/src/main/java/com/cotato/squadus/api/schedule/dto/ScheduleCommentListResponse.java +++ b/src/main/java/com/cotato/squadus/api/schedule/dto/ScheduleCommentListResponse.java @@ -3,7 +3,7 @@ import java.util.List; public record ScheduleCommentListResponse(List scheduleCommentResponses) { - public static ScheduleCommentListResponse from(List scheduleCommentResponses) { - return new ScheduleCommentListResponse(scheduleCommentResponses); - } + public static ScheduleCommentListResponse from(List scheduleCommentResponses) { + return new ScheduleCommentListResponse(scheduleCommentResponses); + } } \ No newline at end of file diff --git a/src/main/java/com/cotato/squadus/api/schedule/dto/ScheduleCommentRequest.java b/src/main/java/com/cotato/squadus/api/schedule/dto/ScheduleCommentRequest.java index c4cc058..3ca0ffb 100644 --- a/src/main/java/com/cotato/squadus/api/schedule/dto/ScheduleCommentRequest.java +++ b/src/main/java/com/cotato/squadus/api/schedule/dto/ScheduleCommentRequest.java @@ -6,6 +6,6 @@ @Getter @Setter public class ScheduleCommentRequest { - private Long memberId; - private String content; + private Long memberId; + private String content; } diff --git a/src/main/java/com/cotato/squadus/api/schedule/dto/ScheduleCommentResponse.java b/src/main/java/com/cotato/squadus/api/schedule/dto/ScheduleCommentResponse.java index 821fadb1f..712df7c 100644 --- a/src/main/java/com/cotato/squadus/api/schedule/dto/ScheduleCommentResponse.java +++ b/src/main/java/com/cotato/squadus/api/schedule/dto/ScheduleCommentResponse.java @@ -2,20 +2,18 @@ import com.cotato.squadus.domain.club.schedule.entity.ScheduleComment; -import java.time.LocalDateTime; - public record ScheduleCommentResponse( - Long commentId, - Long memberId, - String content, - Long likes + Long commentId, + Long memberId, + String content, + Long likes ) { - public static ScheduleCommentResponse from(ScheduleComment comment) { - return new ScheduleCommentResponse( - comment.getId(), - comment.getClubMember().getClubMemberIdx(), - comment.getContent(), - comment.getLikes() - ); - } + public static ScheduleCommentResponse from(ScheduleComment comment) { + return new ScheduleCommentResponse( + comment.getId(), + comment.getClubMember().getClubMemberIdx(), + comment.getContent(), + comment.getLikes() + ); + } } diff --git a/src/main/java/com/cotato/squadus/common/config/CorsConfig.java b/src/main/java/com/cotato/squadus/common/config/CorsConfig.java index eb7d494..4d3f2ba 100644 --- a/src/main/java/com/cotato/squadus/common/config/CorsConfig.java +++ b/src/main/java/com/cotato/squadus/common/config/CorsConfig.java @@ -1,6 +1,7 @@ package com.cotato.squadus.common.config; import java.util.List; + import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.cors.CorsConfiguration; @@ -10,24 +11,24 @@ @Configuration public class CorsConfig { - @Bean - public CorsFilter corsFilter() { - CorsConfiguration config = new CorsConfiguration(); + @Bean + public CorsFilter corsFilter() { + CorsConfiguration config = new CorsConfiguration(); - config.setAllowCredentials(true); - config.setAllowedOrigins(List.of( - "http://localhost:3000", - "http://15.165.165.240", - "https://squadus.kro.kr" // 이 줄을 추가하여 해당 도메인도 허용 - )); - config.addAllowedHeader("*"); - config.addAllowedMethod("*"); - config.setExposedHeaders(List.of("access", "refresh")); - config.setMaxAge(3600L); + config.setAllowCredentials(true); + config.setAllowedOrigins(List.of( + "http://localhost:3000", + "http://15.165.165.240", + "https://squadus.kro.kr" + )); + config.addAllowedHeader("*"); + config.addAllowedMethod("*"); + config.setExposedHeaders(List.of("access", "refresh")); + config.setMaxAge(3600L); - UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); - source.registerCorsConfiguration("/**", config); + UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); + source.registerCorsConfiguration("/**", config); - return new CorsFilter(source); - } + return new CorsFilter(source); + } } diff --git a/src/main/java/com/cotato/squadus/common/config/EmailConfig.java b/src/main/java/com/cotato/squadus/common/config/EmailConfig.java index 90b81c8..6d71868 100644 --- a/src/main/java/com/cotato/squadus/common/config/EmailConfig.java +++ b/src/main/java/com/cotato/squadus/common/config/EmailConfig.java @@ -1,39 +1,41 @@ package com.cotato.squadus.common.config; +import java.util.Properties; + import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.mail.javamail.JavaMailSender; import org.springframework.mail.javamail.JavaMailSenderImpl; -import java.util.Properties; - @Configuration public class EmailConfig { - @Value("${spring.mail.username}") private String username; - @Value("${spring.mail.password}") private String password; - - @Bean - public JavaMailSender mailSender() { - - JavaMailSenderImpl mailSender = new JavaMailSenderImpl(); - mailSender.setHost("smtp.gmail.com"); - mailSender.setPort(587); // TLS port - mailSender.setUsername(username); - mailSender.setPassword(password); - - Properties javaMailProperties = new Properties(); - javaMailProperties.put("mail.transport.protocol", "smtp"); - javaMailProperties.put("mail.smtp.auth", "true"); - javaMailProperties.put("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory"); - javaMailProperties.put("mail.smtp.starttls.enable", "true"); - javaMailProperties.put("mail.debug", "true"); - javaMailProperties.put("mail.smtp.ssl.trust", "smtp.gmail.com"); - javaMailProperties.put("mail.smtp.ssl.protocols", "TLSv1.3"); // TLS v1.3을 사용 - - mailSender.setJavaMailProperties(javaMailProperties); - - return mailSender; - } + @Value("${spring.mail.username}") + private String username; + @Value("${spring.mail.password}") + private String password; + + @Bean + public JavaMailSender mailSender() { + + JavaMailSenderImpl mailSender = new JavaMailSenderImpl(); + mailSender.setHost("smtp.gmail.com"); + mailSender.setPort(587); // TLS port + mailSender.setUsername(username); + mailSender.setPassword(password); + + Properties javaMailProperties = new Properties(); + javaMailProperties.put("mail.transport.protocol", "smtp"); + javaMailProperties.put("mail.smtp.auth", "true"); + javaMailProperties.put("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory"); + javaMailProperties.put("mail.smtp.starttls.enable", "true"); + javaMailProperties.put("mail.debug", "true"); + javaMailProperties.put("mail.smtp.ssl.trust", "smtp.gmail.com"); + javaMailProperties.put("mail.smtp.ssl.protocols", "TLSv1.3"); // TLS v1.3을 사용 + + mailSender.setJavaMailProperties(javaMailProperties); + + return mailSender; + } } diff --git a/src/main/java/com/cotato/squadus/common/config/QueryDslConfig.java b/src/main/java/com/cotato/squadus/common/config/QueryDslConfig.java index 3a21625..7842188 100644 --- a/src/main/java/com/cotato/squadus/common/config/QueryDslConfig.java +++ b/src/main/java/com/cotato/squadus/common/config/QueryDslConfig.java @@ -1,20 +1,21 @@ package com.cotato.squadus.common.config; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + import com.querydsl.jpa.impl.JPAQueryFactory; + import jakarta.persistence.EntityManager; -import jakarta.persistence.PersistenceContext; import lombok.RequiredArgsConstructor; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; @Configuration @RequiredArgsConstructor public class QueryDslConfig { - private final EntityManager entityManager; + private final EntityManager entityManager; - @Bean - public JPAQueryFactory jpaQueryFactory() { - return new JPAQueryFactory(entityManager); - } + @Bean + public JPAQueryFactory jpaQueryFactory() { + return new JPAQueryFactory(entityManager); + } } diff --git a/src/main/java/com/cotato/squadus/common/config/RedisConfig.java b/src/main/java/com/cotato/squadus/common/config/RedisConfig.java index 1c15d6c..50aedca 100644 --- a/src/main/java/com/cotato/squadus/common/config/RedisConfig.java +++ b/src/main/java/com/cotato/squadus/common/config/RedisConfig.java @@ -1,39 +1,42 @@ package com.cotato.squadus.common.config; -import lombok.RequiredArgsConstructor; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Primary; import org.springframework.data.redis.connection.RedisConnectionFactory; import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.repository.configuration.EnableRedisRepositories; import org.springframework.data.redis.serializer.StringRedisSerializer; +import lombok.RequiredArgsConstructor; + @EnableRedisRepositories @RequiredArgsConstructor @Configuration public class RedisConfig { - @Value("${spring.data.redis.host}") - private String host; + @Value("${spring.data.redis.host}") + private String host; - @Value("${spring.data.redis.port}") - private Integer port; + @Value("${spring.data.redis.port}") + private Integer port; - // IoC container를 통해 lettuce connector 설정 - // PersistenceExceptionTranslator 역할을 수행 - @Bean - public RedisConnectionFactory redisConnectionFactory() { - return new LettuceConnectionFactory(host, port); - } + // IoC container를 통해 lettuce connector 설정 + // PersistenceExceptionTranslator 역할을 수행 + @Bean + public RedisConnectionFactory redisConnectionFactory() { + return new LettuceConnectionFactory(host, port); + } - @Bean - public RedisTemplate redisTemplate() { - RedisTemplate redisTemplate = new RedisTemplate<>(); - redisTemplate.setKeySerializer(new StringRedisSerializer()); - redisTemplate.setValueSerializer(new StringRedisSerializer()); - redisTemplate.setConnectionFactory(redisConnectionFactory()); - return redisTemplate; - } + @Bean + @Primary + public RedisTemplate redisTemplate() { + RedisTemplate redisTemplate = new RedisTemplate<>(); + redisTemplate.setKeySerializer(new StringRedisSerializer()); + redisTemplate.setValueSerializer(new StringRedisSerializer()); + redisTemplate.setConnectionFactory(redisConnectionFactory()); + return redisTemplate; + } } diff --git a/src/main/java/com/cotato/squadus/common/config/S3Config.java b/src/main/java/com/cotato/squadus/common/config/S3Config.java index 61c7fe7..b8f32e7 100644 --- a/src/main/java/com/cotato/squadus/common/config/S3Config.java +++ b/src/main/java/com/cotato/squadus/common/config/S3Config.java @@ -1,34 +1,35 @@ package com.cotato.squadus.common.config; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + import com.amazonaws.auth.AWSCredentials; import com.amazonaws.auth.AWSStaticCredentialsProvider; import com.amazonaws.auth.BasicAWSCredentials; import com.amazonaws.services.s3.AmazonS3; import com.amazonaws.services.s3.AmazonS3ClientBuilder; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; @Configuration public class S3Config { - @Value("${cloud.aws.credentials.accessKey}") - private String accessKey; + @Value("${cloud.aws.credentials.accessKey}") + private String accessKey; - @Value("${cloud.aws.credentials.secretKey}") - private String secretKey; + @Value("${cloud.aws.credentials.secretKey}") + private String secretKey; - @Value("${cloud.aws.region.static}") - private String region; + @Value("${cloud.aws.region.static}") + private String region; - @Bean - public AmazonS3 amazonS3() { - AWSCredentials credentials = new BasicAWSCredentials(accessKey, secretKey); + @Bean + public AmazonS3 amazonS3() { + AWSCredentials credentials = new BasicAWSCredentials(accessKey, secretKey); - return AmazonS3ClientBuilder - .standard() - .withCredentials(new AWSStaticCredentialsProvider(credentials)) - .withRegion(region) - .build(); - } + return AmazonS3ClientBuilder + .standard() + .withCredentials(new AWSStaticCredentialsProvider(credentials)) + .withRegion(region) + .build(); + } } \ No newline at end of file diff --git a/src/main/java/com/cotato/squadus/common/config/SecurityConfig.java b/src/main/java/com/cotato/squadus/common/config/SecurityConfig.java index bde58c4..d735495 100644 --- a/src/main/java/com/cotato/squadus/common/config/SecurityConfig.java +++ b/src/main/java/com/cotato/squadus/common/config/SecurityConfig.java @@ -1,13 +1,5 @@ package com.cotato.squadus.common.config; -import com.cotato.squadus.common.config.auth.CustomOAuth2MemberService; -import com.cotato.squadus.common.config.auth.CustomSuccessHandler; -import com.cotato.squadus.common.config.filter.CustomLogoutFilter; -import com.cotato.squadus.common.config.filter.JWTFilter; -import com.cotato.squadus.common.config.jwt.JWTUtil; -import com.cotato.squadus.domain.auth.enums.AdminStatus; -import com.cotato.squadus.common.config.jwt.RefreshRepository; -import lombok.RequiredArgsConstructor; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.web.builders.HttpSecurity; @@ -18,82 +10,91 @@ import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; import org.springframework.security.web.authentication.logout.LogoutFilter; +import com.cotato.squadus.common.config.auth.CustomOAuth2MemberService; +import com.cotato.squadus.common.config.auth.CustomSuccessHandler; +import com.cotato.squadus.common.config.filter.CustomLogoutFilter; +import com.cotato.squadus.common.config.filter.JWTFilter; +import com.cotato.squadus.common.config.jwt.JWTUtil; +import com.cotato.squadus.common.config.jwt.RefreshRepository; +import com.cotato.squadus.domain.auth.enums.AdminStatus; + +import lombok.RequiredArgsConstructor; + @Configuration @RequiredArgsConstructor @EnableWebSecurity public class SecurityConfig { - private static final String[] WHITE_LIST = { - "/v1/api/auth/**", - "/v1/api/member/**", - "/v1/api/clubs/**", - "/v1/api/articles/**", - "/v1/api/email/**", - "/v1/api/image/**", - "/swagger-ui/**", - "/v3/api-docs/**", - "/login", - "oauth2/**", - "/v1/api/matches/**", - "/v1/api/mercenary/**", - "/v1/api/mercenary-requests/**", - "/v1/api/match-requests/**", - "/v1/api/match-results/**" - }; - - private final CustomOAuth2MemberService customOAuth2MemberService; - private final CustomSuccessHandler customSuccessHandler; - private final JWTUtil jwtUtil; - private final RefreshRepository refreshRepository; - - - @Bean - public BCryptPasswordEncoder bCryptPasswordEncoder() { - - return new BCryptPasswordEncoder(); - } - - @Bean - public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { - - //csrf disable - http - .csrf((auth) -> auth.disable()); - - //From 로그인 방식 disable - http - .formLogin((auth) -> auth.disable()); - - //http basic 인증 방식 disable - http - .httpBasic((auth) -> auth.disable()); - - http - .addFilterBefore(new JWTFilter(jwtUtil), UsernamePasswordAuthenticationFilter.class); - - http - .oauth2Login((oauth2) -> oauth2 - .userInfoEndpoint((userInfoEndpointConfig) -> userInfoEndpointConfig - .userService(customOAuth2MemberService)) - .successHandler(customSuccessHandler) - ); - - //경로별 인가 작업 - http - .authorizeHttpRequests((auth) -> auth - .requestMatchers("/v1/api/email/**").permitAll() - .requestMatchers(WHITE_LIST).permitAll() - .requestMatchers("/admin").hasRole(AdminStatus.CURRENT.name()) - .requestMatchers("/reissue").permitAll() - .anyRequest().authenticated()); - - http - .addFilterBefore(new CustomLogoutFilter(jwtUtil, refreshRepository), LogoutFilter.class); - - http - .sessionManagement((session) -> session - .sessionCreationPolicy(SessionCreationPolicy.STATELESS)); - - return http.build(); - } + private static final String[] WHITE_LIST = { + "/v1/api/auth/**", + "/v1/api/member/**", + "/v1/api/clubs/**", + "/v1/api/articles/**", + "/v1/api/email/**", + "/v1/api/image/**", + "/swagger-ui/**", + "/v3/api-docs/**", + "/login", + "oauth2/**", + "/v1/api/matches/**", + "/v1/api/mercenary/**", + "/v1/api/mercenary-requests/**", + "/v1/api/match-requests/**", + "/v1/api/match-results/**" + }; + + private final CustomOAuth2MemberService customOAuth2MemberService; + private final CustomSuccessHandler customSuccessHandler; + private final JWTUtil jwtUtil; + private final RefreshRepository refreshRepository; + + @Bean + public BCryptPasswordEncoder bCryptPasswordEncoder() { + + return new BCryptPasswordEncoder(); + } + + @Bean + public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { + + //csrf disable + http + .csrf((auth) -> auth.disable()); + + //From 로그인 방식 disable + http + .formLogin((auth) -> auth.disable()); + + //http basic 인증 방식 disable + http + .httpBasic((auth) -> auth.disable()); + + http + .addFilterBefore(new JWTFilter(jwtUtil), UsernamePasswordAuthenticationFilter.class); + + http + .oauth2Login((oauth2) -> oauth2 + .userInfoEndpoint((userInfoEndpointConfig) -> userInfoEndpointConfig + .userService(customOAuth2MemberService)) + .successHandler(customSuccessHandler) + ); + + //경로별 인가 작업 + http + .authorizeHttpRequests((auth) -> auth + .requestMatchers("/v1/api/email/**").permitAll() + .requestMatchers(WHITE_LIST).permitAll() + .requestMatchers("/admin").hasRole(AdminStatus.CURRENT.name()) + .requestMatchers("/reissue").permitAll() + .anyRequest().authenticated()); + + http + .addFilterBefore(new CustomLogoutFilter(jwtUtil, refreshRepository), LogoutFilter.class); + + http + .sessionManagement((session) -> session + .sessionCreationPolicy(SessionCreationPolicy.STATELESS)); + + return http.build(); + } } \ No newline at end of file diff --git a/src/main/java/com/cotato/squadus/common/config/SwaggerConfig.java b/src/main/java/com/cotato/squadus/common/config/SwaggerConfig.java index 294fb1e..478e00c 100644 --- a/src/main/java/com/cotato/squadus/common/config/SwaggerConfig.java +++ b/src/main/java/com/cotato/squadus/common/config/SwaggerConfig.java @@ -1,5 +1,8 @@ package com.cotato.squadus.common.config; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + import io.swagger.v3.oas.annotations.OpenAPIDefinition; import io.swagger.v3.oas.annotations.info.Info; import io.swagger.v3.oas.models.Components; @@ -7,45 +10,43 @@ import io.swagger.v3.oas.models.security.SecurityRequirement; import io.swagger.v3.oas.models.security.SecurityScheme; import io.swagger.v3.oas.models.servers.Server; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; @OpenAPIDefinition( - info = @Info(title = "Squadus 프로젝트 API 명세서", - description = "Squadus API 명세서", - version = "v1") + info = @Info(title = "Squadus 프로젝트 API 명세서", + description = "Squadus API 명세서", + version = "v1") ) @Configuration public class SwaggerConfig { - @Bean - public OpenAPI customOpenAPI() { - - String accessHeaderName = "access"; - String refreshHeaderName = "refresh"; - - // Define the SecurityRequirement to be included in the request - SecurityRequirement securityRequirement = new SecurityRequirement() - .addList(accessHeaderName) - .addList(refreshHeaderName); - - Components components = new Components() - .addSecuritySchemes(accessHeaderName, new SecurityScheme() - .name(accessHeaderName) - .type(SecurityScheme.Type.APIKEY) - .in(SecurityScheme.In.HEADER) - .name(accessHeaderName)) - .addSecuritySchemes(refreshHeaderName, new SecurityScheme() - .name(refreshHeaderName) - .type(SecurityScheme.Type.APIKEY) - .in(SecurityScheme.In.HEADER) - .name(refreshHeaderName)); - - return new OpenAPI() - .addServersItem(new Server().url("https://squadus.kro.kr").description("운영 서버")) - .addServersItem(new Server().url("http://localhost:8080").description("Local Server")) - .addServersItem(new Server().url("http://15.165.165.240:8080").description("AWS Server")) - .addSecurityItem(securityRequirement) - .components(components); - } + @Bean + public OpenAPI customOpenAPI() { + + String accessHeaderName = "access"; + String refreshHeaderName = "refresh"; + + // Define the SecurityRequirement to be included in the request + SecurityRequirement securityRequirement = new SecurityRequirement() + .addList(accessHeaderName) + .addList(refreshHeaderName); + + Components components = new Components() + .addSecuritySchemes(accessHeaderName, new SecurityScheme() + .name(accessHeaderName) + .type(SecurityScheme.Type.APIKEY) + .in(SecurityScheme.In.HEADER) + .name(accessHeaderName)) + .addSecuritySchemes(refreshHeaderName, new SecurityScheme() + .name(refreshHeaderName) + .type(SecurityScheme.Type.APIKEY) + .in(SecurityScheme.In.HEADER) + .name(refreshHeaderName)); + + return new OpenAPI() + .addServersItem(new Server().url("https://squadus.kro.kr").description("운영 서버")) + .addServersItem(new Server().url("http://localhost:8080").description("Local Server")) + .addServersItem(new Server().url("http://15.165.165.240:8080").description("AWS Server")) + .addSecurityItem(securityRequirement) + .components(components); + } } diff --git a/src/main/java/com/cotato/squadus/common/config/auth/CustomOAuth2Member.java b/src/main/java/com/cotato/squadus/common/config/auth/CustomOAuth2Member.java index f492995..979ac5f 100644 --- a/src/main/java/com/cotato/squadus/common/config/auth/CustomOAuth2Member.java +++ b/src/main/java/com/cotato/squadus/common/config/auth/CustomOAuth2Member.java @@ -1,46 +1,47 @@ package com.cotato.squadus.common.config.auth; -import com.cotato.squadus.api.auth.dto.LoginRequest; -import com.cotato.squadus.domain.auth.enums.MemberRole; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.springframework.security.core.GrantedAuthority; -import org.springframework.security.oauth2.core.user.OAuth2User; - import java.util.ArrayList; import java.util.Collection; import java.util.Map; +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.oauth2.core.user.OAuth2User; + +import com.cotato.squadus.api.auth.dto.LoginRequest; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; + @RequiredArgsConstructor @Slf4j public class CustomOAuth2Member implements OAuth2User { - private final LoginRequest loginRequest; - - @Override - public Collection getAuthorities() { - Collection collection = new ArrayList<>(); - - collection.add(new GrantedAuthority() { - @Override - public String getAuthority() { - return loginRequest.getMemberRole().name(); - } - }); - return collection; - } - - @Override - public Map getAttributes() { - return null; - } - - public String getUniqueId(){ - return loginRequest.getUniqueId(); - } - - @Override - public String getName() { - return loginRequest.getUsername(); - } + private final LoginRequest loginRequest; + + @Override + public Collection getAuthorities() { + Collection collection = new ArrayList<>(); + + collection.add(new GrantedAuthority() { + @Override + public String getAuthority() { + return loginRequest.getMemberRole().name(); + } + }); + return collection; + } + + @Override + public Map getAttributes() { + return null; + } + + public String getUniqueId() { + return loginRequest.getUniqueId(); + } + + @Override + public String getName() { + return loginRequest.getUsername(); + } } diff --git a/src/main/java/com/cotato/squadus/common/config/auth/CustomOAuth2MemberService.java b/src/main/java/com/cotato/squadus/common/config/auth/CustomOAuth2MemberService.java index a078a0a..afa8b20 100644 --- a/src/main/java/com/cotato/squadus/common/config/auth/CustomOAuth2MemberService.java +++ b/src/main/java/com/cotato/squadus/common/config/auth/CustomOAuth2MemberService.java @@ -1,43 +1,45 @@ package com.cotato.squadus.common.config.auth; -import com.cotato.squadus.api.auth.dto.LoginRequest; -import com.cotato.squadus.api.auth.dto.OAuth2Attribute; -import com.cotato.squadus.domain.auth.entity.Member; -import com.cotato.squadus.domain.auth.repository.MemberRepository; -import lombok.RequiredArgsConstructor; import org.springframework.security.oauth2.client.userinfo.DefaultOAuth2UserService; import org.springframework.security.oauth2.client.userinfo.OAuth2UserRequest; import org.springframework.security.oauth2.core.OAuth2AuthenticationException; import org.springframework.security.oauth2.core.user.OAuth2User; import org.springframework.stereotype.Service; +import com.cotato.squadus.api.auth.dto.LoginRequest; +import com.cotato.squadus.api.auth.dto.OAuth2Attribute; +import com.cotato.squadus.domain.auth.entity.Member; +import com.cotato.squadus.domain.auth.repository.MemberRepository; + +import lombok.RequiredArgsConstructor; + @RequiredArgsConstructor @Service public class CustomOAuth2MemberService extends DefaultOAuth2UserService { - private final MemberRepository memberRepository; + private final MemberRepository memberRepository; - @Override - public OAuth2User loadUser(OAuth2UserRequest userRequest) throws OAuth2AuthenticationException { + @Override + public OAuth2User loadUser(OAuth2UserRequest userRequest) throws OAuth2AuthenticationException { - OAuth2User oAuth2User = super.loadUser(userRequest); + OAuth2User oAuth2User = super.loadUser(userRequest); - String registrationId = userRequest.getClientRegistration().getRegistrationId(); //naver, google - OAuth2Attribute attribute = OAuth2Attribute.of(registrationId, oAuth2User.getAttributes()); + String registrationId = userRequest.getClientRegistration().getRegistrationId(); //naver, google + OAuth2Attribute attribute = OAuth2Attribute.of(registrationId, oAuth2User.getAttributes()); - String uniqueId = registrationId+" "+attribute.getProviderId(); + String uniqueId = registrationId + " " + attribute.getProviderId(); - Member member = saveOrUpdate(attribute, uniqueId); - LoginRequest loginRequest = new LoginRequest(member); + Member member = saveOrUpdate(attribute, uniqueId); + LoginRequest loginRequest = new LoginRequest(member); - return new CustomOAuth2Member(loginRequest); - } + return new CustomOAuth2Member(loginRequest); + } - private Member saveOrUpdate(OAuth2Attribute attribute, String uniqueId){ - Member user = memberRepository.findByUniqueId(uniqueId) - .map(entity -> entity.update(attribute.getEmail(), attribute.getUsername())) - .orElse(attribute.toEntity(uniqueId)); - return memberRepository.save(user); - } + private Member saveOrUpdate(OAuth2Attribute attribute, String uniqueId) { + Member user = memberRepository.findByUniqueId(uniqueId) + .map(entity -> entity.update(attribute.getEmail(), attribute.getUsername())) + .orElse(attribute.toEntity(uniqueId)); + return memberRepository.save(user); + } } diff --git a/src/main/java/com/cotato/squadus/common/config/auth/CustomSuccessHandler.java b/src/main/java/com/cotato/squadus/common/config/auth/CustomSuccessHandler.java index 48c5ae6..7f35e61 100644 --- a/src/main/java/com/cotato/squadus/common/config/auth/CustomSuccessHandler.java +++ b/src/main/java/com/cotato/squadus/common/config/auth/CustomSuccessHandler.java @@ -1,60 +1,59 @@ package com.cotato.squadus.common.config.auth; +import java.io.IOException; +import java.util.Collection; +import java.util.Iterator; + +import org.springframework.security.core.Authentication; +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.web.authentication.SimpleUrlAuthenticationSuccessHandler; +import org.springframework.stereotype.Component; + import com.cotato.squadus.common.config.jwt.JWTUtil; -import com.cotato.squadus.common.config.jwt.RefreshEntity; import com.cotato.squadus.common.config.jwt.RefreshRepository; -import com.cotato.squadus.domain.auth.enums.MemberRole; import com.cotato.squadus.domain.auth.service.RefreshService; + import jakarta.servlet.ServletException; -import jakarta.servlet.http.Cookie; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.springframework.security.core.Authentication; -import org.springframework.security.core.GrantedAuthority; -import org.springframework.security.web.authentication.SimpleUrlAuthenticationSuccessHandler; -import org.springframework.stereotype.Component; - -import java.io.IOException; -import java.util.Collection; -import java.util.Date; -import java.util.Iterator; @Component @RequiredArgsConstructor @Slf4j public class CustomSuccessHandler extends SimpleUrlAuthenticationSuccessHandler { - private final JWTUtil jwtUtil; - private final RefreshRepository refreshRepository; - private final RefreshService refreshService; - + private final JWTUtil jwtUtil; + private final RefreshRepository refreshRepository; + private final RefreshService refreshService; - @Override - public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException { + @Override + public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, + Authentication authentication) throws IOException, ServletException { - //OAuth2User - CustomOAuth2Member customOAuth2Member = (CustomOAuth2Member) authentication.getPrincipal(); + //OAuth2User + CustomOAuth2Member customOAuth2Member = (CustomOAuth2Member)authentication.getPrincipal(); - String uniqueId = customOAuth2Member.getUniqueId(); - String username = customOAuth2Member.getName(); - Collection authorities = authentication.getAuthorities(); - Iterator iterator = authorities.iterator(); - GrantedAuthority auth = iterator.next(); - String role = auth.getAuthority(); + String uniqueId = customOAuth2Member.getUniqueId(); + String username = customOAuth2Member.getName(); + Collection authorities = authentication.getAuthorities(); + Iterator iterator = authorities.iterator(); + GrantedAuthority auth = iterator.next(); + String role = auth.getAuthority(); - String access = jwtUtil.createJwt("access", uniqueId, username, role, 600000L); //10분 - String refresh = jwtUtil.createJwt("refresh", uniqueId, username, role, 86400000L); //24시간 + String access = jwtUtil.createJwt("access", uniqueId, username, role, 600000L); //10분 + String refresh = jwtUtil.createJwt("refresh", uniqueId, username, role, 86400000L); //24시간 - refreshService.addRefreshEntity(uniqueId, username, refresh, 86400000L); + refreshService.addRefreshEntity(uniqueId, username, refresh, 86400000L); - log.info("access: {} refresh: {}", access, refresh); + log.info("access: {} refresh: {}", access, refresh); -// response.setHeader("access", access); -// response.addCookie(refreshService.createCookie("refresh", refresh)); - String redirectUrl = String.format("http://localhost:3000/callback?access_token=%s&refresh_token=%s", access, refresh); - response.sendRedirect(redirectUrl); - } + // response.setHeader("access", access); + // response.addCookie(refreshService.createCookie("refresh", refresh)); + String redirectUrl = String.format("http://localhost:3000/callback?access_token=%s&refresh_token=%s", access, + refresh); + response.sendRedirect(redirectUrl); + } } \ No newline at end of file diff --git a/src/main/java/com/cotato/squadus/common/config/filter/CustomLogoutFilter.java b/src/main/java/com/cotato/squadus/common/config/filter/CustomLogoutFilter.java index ebf790c..71d3cf1 100644 --- a/src/main/java/com/cotato/squadus/common/config/filter/CustomLogoutFilter.java +++ b/src/main/java/com/cotato/squadus/common/config/filter/CustomLogoutFilter.java @@ -1,7 +1,12 @@ package com.cotato.squadus.common.config.filter; +import java.io.IOException; + +import org.springframework.web.filter.GenericFilterBean; + import com.cotato.squadus.common.config.jwt.JWTUtil; import com.cotato.squadus.common.config.jwt.RefreshRepository; + import io.jsonwebtoken.ExpiredJwtException; import jakarta.servlet.FilterChain; import jakarta.servlet.ServletException; @@ -10,87 +15,88 @@ import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import lombok.extern.slf4j.Slf4j; -import org.springframework.web.filter.GenericFilterBean; - -import java.io.IOException; @Slf4j public class CustomLogoutFilter extends GenericFilterBean { - private final JWTUtil jwtUtil; - private final RefreshRepository refreshRepository; - - public CustomLogoutFilter(JWTUtil jwtUtil, RefreshRepository refreshRepository) { - - this.jwtUtil = jwtUtil; - this.refreshRepository = refreshRepository; - } - - @Override - public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { - - doFilter((HttpServletRequest) request, (HttpServletResponse) response, chain); - } - - private void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws IOException, ServletException { - - //path and method verify - String requestUri = request.getRequestURI(); - if (!requestUri.matches("^\\/logout$")) { - - filterChain.doFilter(request, response); - return; - } - String requestMethod = request.getMethod(); - if (!requestMethod.equals("POST")) { - - filterChain.doFilter(request, response); - return; - } - - //get refresh token - String refresh = null; - refresh = request.getHeader("refresh"); - - //refresh null check - if (refresh == null) { - - response.setStatus(HttpServletResponse.SC_BAD_REQUEST); - return; - } - - //expired check - try { - jwtUtil.isExpired(refresh); - } catch (ExpiredJwtException e) { - - //response status code - response.setStatus(HttpServletResponse.SC_BAD_REQUEST); - return; - } - - // 토큰이 refresh인지 확인 (발급시 페이로드에 명시) - String category = jwtUtil.getCategory(refresh); - if (!category.equals("refresh")) { - - //response status code - response.setStatus(HttpServletResponse.SC_BAD_REQUEST); - return; - } - - //DB에 저장되어 있는지 확인 - Boolean isExist = refreshRepository.existsByRefresh(refresh); - if (!isExist) { - - //response status code - response.setStatus(HttpServletResponse.SC_BAD_REQUEST); - return; - } - - //로그아웃 진행 - //Refresh 토큰 DB에서 제거 - refreshRepository.deleteByRefresh(refresh); - log.info("로그아웃 성공, {}", refresh); - response.setStatus(HttpServletResponse.SC_OK); - } + private final JWTUtil jwtUtil; + private final RefreshRepository refreshRepository; + + public CustomLogoutFilter(JWTUtil jwtUtil, RefreshRepository refreshRepository) { + + this.jwtUtil = jwtUtil; + this.refreshRepository = refreshRepository; + } + + @Override + public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws + IOException, + ServletException { + + doFilter((HttpServletRequest)request, (HttpServletResponse)response, chain); + } + + private void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws + IOException, + ServletException { + + //path and method verify + String requestUri = request.getRequestURI(); + if (!requestUri.matches("^\\/logout$")) { + + filterChain.doFilter(request, response); + return; + } + String requestMethod = request.getMethod(); + if (!requestMethod.equals("POST")) { + + filterChain.doFilter(request, response); + return; + } + + //get refresh token + String refresh = null; + refresh = request.getHeader("refresh"); + + //refresh null check + if (refresh == null) { + + response.setStatus(HttpServletResponse.SC_BAD_REQUEST); + return; + } + + //expired check + try { + jwtUtil.isExpired(refresh); + } catch (ExpiredJwtException e) { + + //response status code + response.setStatus(HttpServletResponse.SC_BAD_REQUEST); + return; + } + + // 토큰이 refresh인지 확인 (발급시 페이로드에 명시) + String category = jwtUtil.getCategory(refresh); + if (!category.equals("refresh")) { + + //response status code + response.setStatus(HttpServletResponse.SC_BAD_REQUEST); + return; + } + + //DB에 저장되어 있는지 확인 + Boolean isExist = refreshRepository.existsByRefresh(refresh); + if (!isExist) { + + //response status code + response.setStatus(HttpServletResponse.SC_BAD_REQUEST); + return; + } + + //로그아웃 진행 + //Refresh 토큰 DB에서 제거 + refreshRepository.deleteByRefresh(refresh); + log.info("로그아웃 성공, {}", refresh); + response.setStatus(HttpServletResponse.SC_OK); + } } \ No newline at end of file diff --git a/src/main/java/com/cotato/squadus/common/config/filter/JWTFilter.java b/src/main/java/com/cotato/squadus/common/config/filter/JWTFilter.java index df6d2b7..87c1c85 100644 --- a/src/main/java/com/cotato/squadus/common/config/filter/JWTFilter.java +++ b/src/main/java/com/cotato/squadus/common/config/filter/JWTFilter.java @@ -1,9 +1,18 @@ package com.cotato.squadus.common.config.filter; +import java.io.IOException; +import java.io.PrintWriter; + +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.web.filter.OncePerRequestFilter; + import com.cotato.squadus.api.auth.dto.LoginRequest; import com.cotato.squadus.common.config.auth.CustomOAuth2Member; import com.cotato.squadus.common.config.jwt.JWTUtil; import com.cotato.squadus.domain.auth.enums.MemberRole; + import io.jsonwebtoken.ExpiredJwtException; import jakarta.servlet.FilterChain; import jakarta.servlet.ServletException; @@ -11,84 +20,78 @@ import jakarta.servlet.http.HttpServletResponse; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; -import org.springframework.security.core.Authentication; -import org.springframework.security.core.context.SecurityContextHolder; -import org.springframework.web.filter.OncePerRequestFilter; - -import java.io.IOException; -import java.io.PrintWriter; @RequiredArgsConstructor @Slf4j public class JWTFilter extends OncePerRequestFilter { - private final JWTUtil jwtUtil; - - @Override - protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { - - - String requestUri = request.getRequestURI(); - if (requestUri.matches("^\\/login(?:\\/.*)?$")) { - filterChain.doFilter(request, response); - return; - } - if (requestUri.matches("^\\/oauth2(?:\\/.*)?$")) { - filterChain.doFilter(request, response); - return; - } - - // 헤더에서 access키에 담긴 토큰을 꺼냄 - String accessToken = request.getHeader("access"); - - // 토큰이 없다면 다음 필터로 넘김 - if (accessToken == null) { - log.info("not access token in authorization"); - filterChain.doFilter(request, response); - return; - } - - // 토큰 만료 여부 확인, 만료시 다음 필터로 넘기지 않음 - try { - jwtUtil.isExpired(accessToken); - } catch (ExpiredJwtException e) { - - //response body - PrintWriter writer = response.getWriter(); - writer.print("access token expired"); - - //response status code - response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); - return; - } - - // 토큰이 access인지 확인 (발급시 페이로드에 명시) - String category = jwtUtil.getCategory(accessToken); - - if (!category.equals("access")) { - - //response body - PrintWriter writer = response.getWriter(); - writer.print("invalid access token"); - - //response status code - response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); - return; - } - - LoginRequest loginRequest = LoginRequest.builder() - .uniqueId(jwtUtil.getUniqueId(accessToken)) - .username(jwtUtil.getUsername(accessToken)) - .memberRole(MemberRole.valueOf(jwtUtil.getRole(accessToken))) - .build(); - CustomOAuth2Member customOAuth2Member = new CustomOAuth2Member(loginRequest); - - Authentication authToken = new UsernamePasswordAuthenticationToken(customOAuth2Member, null, customOAuth2Member.getAuthorities()); - - // 일시적인 세션 생성 - SecurityContextHolder.getContext().setAuthentication(authToken); - - filterChain.doFilter(request, response); - } + private final JWTUtil jwtUtil; + + @Override + protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, + FilterChain filterChain) throws ServletException, IOException { + + String requestUri = request.getRequestURI(); + if (requestUri.matches("^\\/login(?:\\/.*)?$")) { + filterChain.doFilter(request, response); + return; + } + if (requestUri.matches("^\\/oauth2(?:\\/.*)?$")) { + filterChain.doFilter(request, response); + return; + } + + // 헤더에서 access키에 담긴 토큰을 꺼냄 + String accessToken = request.getHeader("access"); + + // 토큰이 없다면 다음 필터로 넘김 + if (accessToken == null) { + log.info("not access token in authorization"); + filterChain.doFilter(request, response); + return; + } + + // 토큰 만료 여부 확인, 만료시 다음 필터로 넘기지 않음 + try { + jwtUtil.isExpired(accessToken); + } catch (ExpiredJwtException e) { + + //response body + PrintWriter writer = response.getWriter(); + writer.print("access token expired"); + + //response status code + response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); + return; + } + + // 토큰이 access인지 확인 (발급시 페이로드에 명시) + String category = jwtUtil.getCategory(accessToken); + + if (!category.equals("access")) { + + //response body + PrintWriter writer = response.getWriter(); + writer.print("invalid access token"); + + //response status code + response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); + return; + } + + LoginRequest loginRequest = LoginRequest.builder() + .uniqueId(jwtUtil.getUniqueId(accessToken)) + .username(jwtUtil.getUsername(accessToken)) + .memberRole(MemberRole.valueOf(jwtUtil.getRole(accessToken))) + .build(); + CustomOAuth2Member customOAuth2Member = new CustomOAuth2Member(loginRequest); + + Authentication authToken = new UsernamePasswordAuthenticationToken(customOAuth2Member, null, + customOAuth2Member.getAuthorities()); + + // 일시적인 세션 생성 + SecurityContextHolder.getContext().setAuthentication(authToken); + + filterChain.doFilter(request, response); + } } \ No newline at end of file diff --git a/src/main/java/com/cotato/squadus/common/config/jwt/JWTUtil.java b/src/main/java/com/cotato/squadus/common/config/jwt/JWTUtil.java index 323c9ea..e6fd87c 100644 --- a/src/main/java/com/cotato/squadus/common/config/jwt/JWTUtil.java +++ b/src/main/java/com/cotato/squadus/common/config/jwt/JWTUtil.java @@ -1,59 +1,87 @@ package com.cotato.squadus.common.config.jwt; -import com.cotato.squadus.domain.auth.enums.MemberRole; -import io.jsonwebtoken.Jwts; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.stereotype.Component; - -import javax.crypto.SecretKey; -import javax.crypto.spec.SecretKeySpec; import java.nio.charset.StandardCharsets; import java.util.Date; -@Component -public class JWTUtil { - - private SecretKey secretKey; - - public JWTUtil(@Value("${spring.jwt.secret}")String secret) { - secretKey = new SecretKeySpec(secret.getBytes(StandardCharsets.UTF_8), Jwts.SIG.HS256.key().build().getAlgorithm()); - } - - public String getUniqueId(String token) { - - return Jwts.parser().verifyWith(secretKey).build().parseSignedClaims(token).getPayload().get("uniqueId", String.class); - } - - public String getUsername(String token) { - - return Jwts.parser().verifyWith(secretKey).build().parseSignedClaims(token).getPayload().get("username", String.class); - } - - public String getRole(String token) { - - return Jwts.parser().verifyWith(secretKey).build().parseSignedClaims(token).getPayload().get("role", String.class); - } - - public String getCategory(String token) { - - return Jwts.parser().verifyWith(secretKey).build().parseSignedClaims(token).getPayload().get("category", String.class); - } +import javax.crypto.SecretKey; +import javax.crypto.spec.SecretKeySpec; - public Boolean isExpired(String token) { +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; - return Jwts.parser().verifyWith(secretKey).build().parseSignedClaims(token).getPayload().getExpiration().before(new Date()); - } +import io.jsonwebtoken.Jwts; - public String createJwt(String category, String uniqueId, String username, String role, Long expiredMs) { +@Component +public class JWTUtil { - return Jwts.builder() - .claim("category", category) - .claim("uniqueId", uniqueId) - .claim("username", username) - .claim("role", role) - .issuedAt(new Date(System.currentTimeMillis())) - .expiration(new Date(System.currentTimeMillis() + expiredMs)) - .signWith(secretKey) - .compact(); - } + private SecretKey secretKey; + + public JWTUtil(@Value("${spring.jwt.secret}") String secret) { + secretKey = new SecretKeySpec(secret.getBytes(StandardCharsets.UTF_8), + Jwts.SIG.HS256.key().build().getAlgorithm()); + } + + public String getUniqueId(String token) { + + return Jwts.parser() + .verifyWith(secretKey) + .build() + .parseSignedClaims(token) + .getPayload() + .get("uniqueId", String.class); + } + + public String getUsername(String token) { + + return Jwts.parser() + .verifyWith(secretKey) + .build() + .parseSignedClaims(token) + .getPayload() + .get("username", String.class); + } + + public String getRole(String token) { + + return Jwts.parser() + .verifyWith(secretKey) + .build() + .parseSignedClaims(token) + .getPayload() + .get("role", String.class); + } + + public String getCategory(String token) { + + return Jwts.parser() + .verifyWith(secretKey) + .build() + .parseSignedClaims(token) + .getPayload() + .get("category", String.class); + } + + public Boolean isExpired(String token) { + + return Jwts.parser() + .verifyWith(secretKey) + .build() + .parseSignedClaims(token) + .getPayload() + .getExpiration() + .before(new Date()); + } + + public String createJwt(String category, String uniqueId, String username, String role, Long expiredMs) { + + return Jwts.builder() + .claim("category", category) + .claim("uniqueId", uniqueId) + .claim("username", username) + .claim("role", role) + .issuedAt(new Date(System.currentTimeMillis())) + .expiration(new Date(System.currentTimeMillis() + expiredMs)) + .signWith(secretKey) + .compact(); + } } diff --git a/src/main/java/com/cotato/squadus/common/config/jwt/RefreshEntity.java b/src/main/java/com/cotato/squadus/common/config/jwt/RefreshEntity.java index 79e0307..f711a66 100644 --- a/src/main/java/com/cotato/squadus/common/config/jwt/RefreshEntity.java +++ b/src/main/java/com/cotato/squadus/common/config/jwt/RefreshEntity.java @@ -1,6 +1,10 @@ package com.cotato.squadus.common.config.jwt; -import jakarta.persistence.*; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; import lombok.Getter; import lombok.Setter; @@ -9,14 +13,14 @@ @Setter public class RefreshEntity { - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - private Long id; + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; - private String uniqueId; - private String username; + private String uniqueId; + private String username; - @Column(nullable = false, length = 2048) - private String refresh; - private String expiration; + @Column(nullable = false, length = 2048) + private String refresh; + private String expiration; } diff --git a/src/main/java/com/cotato/squadus/common/config/jwt/RefreshRepository.java b/src/main/java/com/cotato/squadus/common/config/jwt/RefreshRepository.java index 7ae9aa3..84b88e0 100644 --- a/src/main/java/com/cotato/squadus/common/config/jwt/RefreshRepository.java +++ b/src/main/java/com/cotato/squadus/common/config/jwt/RefreshRepository.java @@ -1,12 +1,13 @@ package com.cotato.squadus.common.config.jwt; -import jakarta.transaction.Transactional; import org.springframework.data.jpa.repository.JpaRepository; +import jakarta.transaction.Transactional; + public interface RefreshRepository extends JpaRepository { - Boolean existsByRefresh(String refresh); + Boolean existsByRefresh(String refresh); - @Transactional - void deleteByRefresh(String refresh); + @Transactional + void deleteByRefresh(String refresh); } \ No newline at end of file diff --git a/src/main/java/com/cotato/squadus/common/entity/BaseTimeEntity.java b/src/main/java/com/cotato/squadus/common/entity/BaseTimeEntity.java index b803b2f..be518e6 100644 --- a/src/main/java/com/cotato/squadus/common/entity/BaseTimeEntity.java +++ b/src/main/java/com/cotato/squadus/common/entity/BaseTimeEntity.java @@ -1,24 +1,25 @@ package com.cotato.squadus.common.entity; -import jakarta.persistence.Column; -import jakarta.persistence.EntityListeners; -import jakarta.persistence.MappedSuperclass; -import lombok.Getter; +import java.time.LocalDateTime; + import org.springframework.data.annotation.CreatedDate; import org.springframework.data.annotation.LastModifiedDate; import org.springframework.data.jpa.domain.support.AuditingEntityListener; -import java.time.LocalDateTime; +import jakarta.persistence.Column; +import jakarta.persistence.EntityListeners; +import jakarta.persistence.MappedSuperclass; +import lombok.Getter; @Getter @MappedSuperclass @EntityListeners(AuditingEntityListener.class) public abstract class BaseTimeEntity { - @CreatedDate - @Column(updatable = false) - private LocalDateTime createdAt; + @CreatedDate + @Column(updatable = false) + private LocalDateTime createdAt; - @LastModifiedDate - private LocalDateTime modifiedAt; + @LastModifiedDate + private LocalDateTime modifiedAt; } diff --git a/src/main/java/com/cotato/squadus/common/error/ErrorCode.java b/src/main/java/com/cotato/squadus/common/error/ErrorCode.java index a444054..44c3c0b 100644 --- a/src/main/java/com/cotato/squadus/common/error/ErrorCode.java +++ b/src/main/java/com/cotato/squadus/common/error/ErrorCode.java @@ -1,100 +1,101 @@ package com.cotato.squadus.common.error; +import org.springframework.http.HttpStatus; + import lombok.AllArgsConstructor; import lombok.Getter; -import org.springframework.http.HttpStatus; @AllArgsConstructor @Getter public enum ErrorCode { - - //S3 에러 - EMPTY_FILE_EXCEPTION(HttpStatus.BAD_REQUEST, "S3-001", "파일이 비어 있습니다."), - IO_EXCEPTION_ON_IMAGE_UPLOAD(HttpStatus.INTERNAL_SERVER_ERROR, "S3-002", "이미지 업로드 중 IO 예외 발생"), - NO_FILE_EXTENTION(HttpStatus.BAD_REQUEST, "S3-003", "파일 확장자가 없습니다."), - INVALID_FILE_EXTENTION(HttpStatus.BAD_REQUEST, "S3-004", "유효하지 않은 파일 확장자입니다."), - PUT_OBJECT_EXCEPTION(HttpStatus.INTERNAL_SERVER_ERROR, "S3-005", "S3에 객체를 업로드하는 동안 예외 발생"), - IO_EXCEPTION_ON_IMAGE_DELETE(HttpStatus.INTERNAL_SERVER_ERROR, "S3-006", "이미지 삭제 중 IO 예외 발생"), - - // Auth 일반적인 인증 문제 Auth JWT 토큰 관련 에러 - TOKEN_EXPIRED(HttpStatus.UNAUTHORIZED, "T-001", "이미 만료된 토큰입니다."), - FILTER_EXCEPTION(HttpStatus.UNAUTHORIZED, "T-002", "필터 내부에러 발생"), - JWT_FORM_ERROR(HttpStatus.UNAUTHORIZED, "T-003", "jwt 형식 에러 발생"), - REFRESH_TOKEN_NOT_EXIST(HttpStatus.UNAUTHORIZED, "T-004", "해당 리프레시 토큰이 DB에 존재하지 않습니다."), - REISSUE_FAIL(HttpStatus.UNAUTHORIZED, "T-005", "액세스 토큰 재발급 요청 실패"), - LOGIN_FAIL(HttpStatus.UNAUTHORIZED, "T-006", "로그인에 실패했습니다."), - - // DTO 에서 발생하는 에러 - INVALID_INPUT(HttpStatus.BAD_REQUEST, "I-001", "입력 값이 잘못되었습니다."), - // 404 오류 -> 객체를 찾을 수 없는 문제 - ENTITY_NOT_FOUND(HttpStatus.NOT_FOUND, "I-201", "해당 Entity를 찾을 수 없습니다."), - - // 회원 가입 - EMAIL_TYPE_ERROR(HttpStatus.BAD_REQUEST, "A-001", "구글, 네이버 형식으로 입력해주세요"), - INVALID_PASSWORD(HttpStatus.BAD_REQUEST, "A-002", "유효하지 않은 패스워드입니다."), - INVALID_PHONE_NUMBER(HttpStatus.BAD_REQUEST, "A-003", "유효하지 않은 전화번호 입니다."), - CODE_NOT_MATCH(HttpStatus.BAD_REQUEST, "A-101", "요청하신 코드가 일치하지 않습니다."), - EMAIL_NOT_FOUND(HttpStatus.NOT_FOUND, "A-201", "해당 이메일이 존재하지 않습니다."), // 이게 소켓에 왜 필요한지, find 그 부분에서 발생해야할 예외일듯 - EMAIL_DUPLICATED(HttpStatus.CONFLICT, "A-301", "존재하는 이메일 입니다."), - PHONE_NUMBER_DUPLICATED(HttpStatus.CONFLICT, "A-302", "존재하는 전화번호입니다."), - - //회원 관련 - ROLE_IS_NOT_MATCH(HttpStatus.BAD_REQUEST, "M-101", "해당 ROLE은 변경할 수 없습니다."), - ROLE_IS_NOT_OLD_MEMBER(HttpStatus.BAD_REQUEST, "M-103", "해당 회원의 ROLE은 OLD_MEMBER가 아닙니다."), - SAME_PASSWORD(HttpStatus.CONFLICT, "M-301", "이전과 같은 비밀번호로 변경할 수 없습니다."), - MEMBER_TYPE_IS_NOT_ADMIN(HttpStatus.BAD_REQUEST, "M-102", "해당 회원은 ADMIN 회원이 아닙니다."), - - // 동아리 관련 - CLUB_ACCESS_DENIED(HttpStatus.FORBIDDEN, "C-001", "해당 동아리에 접근할 수 있는 권한이 없습니다."), - CLUB_POST_COMMENT_ACCESS_DENIED(HttpStatus.FORBIDDEN, "C-002", "해당 동아리 공지에 접근할 수 있는 권한이 없습니다."), - CLUB_POST_AUTHOR(HttpStatus.BAD_REQUEST, "C-003", "자신의 글은 좋아요할 수 없습니다."), - CLUB_POST_COMMENT_AUTHOR(HttpStatus.BAD_REQUEST, "C-004", "자신의 댓글은 좋아요할 수 없습니다."), - - //매칭 관련 - DUPLICATE_REQUEST(HttpStatus.CONFLICT, "M-302", "이미 해당 용병 게시글에 신청하셨습니다."), - CLUB_MATCH_FINALIZE(HttpStatus.CONFLICT, "M-303", "이미 매칭이 확정된 요청을 처리할 수 없습니다."), - - // 기수 운영 (세션 -> 출석) - INVALID_DATE(HttpStatus.BAD_REQUEST, "G-101", "시작날짜가 끝 날짜보다 뒤입니다"), - GENERATION_NUMBER_DUPLICATED(HttpStatus.CONFLICT, "G-201", "같은 숫자의 기수가 있습니다"), - - // 교육 도메인 - REGRADE_FAIL(HttpStatus.BAD_REQUEST, "E-201", "재채점 할 기록이 없습니다."), - EDUCATION_DUPLICATED(HttpStatus.CONFLICT, "E-301", "이미 교육이 존재합니다"), - EDUCATION_CLOSED(HttpStatus.BAD_REQUEST, "E-401", "CS 퀴즈가 닫혀 있습니다 먼저 교육 시작 버튼을 눌러주세요"), - EDUCATION_STATUS_NOT_BEFORE(HttpStatus.BAD_REQUEST, "E-402", "이미 시작한 적이 있는 교육입니다."), - MEMBER_CANT_ACCESS(HttpStatus.BAD_REQUEST, "E-403", "해당 멤버의 ROLE로 접근할 수 없습니다"), - - INVALID_ANSWER(HttpStatus.BAD_REQUEST, "Q-101", "객관식 문제는 숫자 형식의 값만 정답으로 추가할 수 있습니다."), - CONTENT_IS_NOT_ANSWER(HttpStatus.BAD_REQUEST, "Q-201", "추가되지 않은 정답을 추가할 수 없습니다."), - QUIZ_NUMBER_DUPLICATED(HttpStatus.CONFLICT, "Q-301", "퀴즈 번호는 중복될 수 없습니다."), - CHOICE_NUMBER_DUPLICATED(HttpStatus.CONFLICT, "Q-302", "선지 번호는 중복될 수 없습니다"), - CONTENT_IS_ALREADY_ANSWER(HttpStatus.BAD_REQUEST, "Q-303", "이미 정답인 답을 추가했습니다"), - QUIZ_ACCESS_DENIED(HttpStatus.BAD_REQUEST, "Q-401", "해당 퀴즈는 아직 접근할 수 없습니다."), - QUIZ_TYPE_NOT_MATCH(HttpStatus.BAD_REQUEST, "Q-402", "주관식 정답만 추가 가능합니다."), - - KING_MEMBER_EXIST(HttpStatus.CONFLICT, "K-301", "이미 킹킹 멤버가 존재합니다"), - - SUBJECT_INVALID(HttpStatus.BAD_REQUEST, "E-000", "교육 주제는 NULL이거나 비어있을 수 없습니다."), - - PROCESSING(HttpStatus.CONFLICT, "D-999", "해당 키의 요청은 아직 처리 중 입니다."), - - ALREADY_REPLY_CORRECT(HttpStatus.BAD_REQUEST, "R-301", "해당 사용자는 이미 정답 처리되었습니다."), - - LAST_QUIZ_SCORER_NOT_EXIST(HttpStatus.CONFLICT, "W-201", "아직 마지막 문제 득점자가 없습니다"), - WINNER_EXIST(HttpStatus.CONFLICT, "W-301", "이미 우승자가 존재합니다"), - // 500 오류 -> 서버측에서 처리가 실패한 부분들 - WEBSOCKET_SEND_EXCEPTION(HttpStatus.INTERNAL_SERVER_ERROR, "S-001", "소캣 메세지 전송 실패"), - IMAGE_PROCESSING_FAIL(HttpStatus.INTERNAL_SERVER_ERROR, "S-002", "이미지 처리에 실패했습니다."), - IMAGE_DELETE_FAIL(HttpStatus.INTERNAL_SERVER_ERROR, "S-003", "s3 이미지 삭제처리를 실패했습니다"), - INTERNAL_SQL_ERROR(HttpStatus.INTERNAL_SERVER_ERROR, "S-004", "SQL 관련 에러 발생"), - ENUM_NOT_RESOLVED(HttpStatus.BAD_REQUEST, "S-005", "입력한 Enum이 존재하지 않습니다."), - - NO_BALANCE_ERROR(HttpStatus.BAD_REQUEST, "F-001", "회비의 잔액보다 사용내역의 금액이 더 큽니다."), - PAYMENT_CHANGE_DENIED(HttpStatus.BAD_REQUEST, "F-002", "이미 사용중인 회비의 입금현황을 변경할 수 없습니다."), - ; - - private final HttpStatus httpStatus; - private final String code; - private final String message; + + //S3 에러 + EMPTY_FILE_EXCEPTION(HttpStatus.BAD_REQUEST, "S3-001", "파일이 비어 있습니다."), + IO_EXCEPTION_ON_IMAGE_UPLOAD(HttpStatus.INTERNAL_SERVER_ERROR, "S3-002", "이미지 업로드 중 IO 예외 발생"), + NO_FILE_EXTENTION(HttpStatus.BAD_REQUEST, "S3-003", "파일 확장자가 없습니다."), + INVALID_FILE_EXTENTION(HttpStatus.BAD_REQUEST, "S3-004", "유효하지 않은 파일 확장자입니다."), + PUT_OBJECT_EXCEPTION(HttpStatus.INTERNAL_SERVER_ERROR, "S3-005", "S3에 객체를 업로드하는 동안 예외 발생"), + IO_EXCEPTION_ON_IMAGE_DELETE(HttpStatus.INTERNAL_SERVER_ERROR, "S3-006", "이미지 삭제 중 IO 예외 발생"), + + // Auth 일반적인 인증 문제 Auth JWT 토큰 관련 에러 + TOKEN_EXPIRED(HttpStatus.UNAUTHORIZED, "T-001", "이미 만료된 토큰입니다."), + FILTER_EXCEPTION(HttpStatus.UNAUTHORIZED, "T-002", "필터 내부에러 발생"), + JWT_FORM_ERROR(HttpStatus.UNAUTHORIZED, "T-003", "jwt 형식 에러 발생"), + REFRESH_TOKEN_NOT_EXIST(HttpStatus.UNAUTHORIZED, "T-004", "해당 리프레시 토큰이 DB에 존재하지 않습니다."), + REISSUE_FAIL(HttpStatus.UNAUTHORIZED, "T-005", "액세스 토큰 재발급 요청 실패"), + LOGIN_FAIL(HttpStatus.UNAUTHORIZED, "T-006", "로그인에 실패했습니다."), + + // DTO 에서 발생하는 에러 + INVALID_INPUT(HttpStatus.BAD_REQUEST, "I-001", "입력 값이 잘못되었습니다."), + // 404 오류 -> 객체를 찾을 수 없는 문제 + ENTITY_NOT_FOUND(HttpStatus.NOT_FOUND, "I-201", "해당 Entity를 찾을 수 없습니다."), + + // 회원 가입 + EMAIL_TYPE_ERROR(HttpStatus.BAD_REQUEST, "A-001", "구글, 네이버 형식으로 입력해주세요"), + INVALID_PASSWORD(HttpStatus.BAD_REQUEST, "A-002", "유효하지 않은 패스워드입니다."), + INVALID_PHONE_NUMBER(HttpStatus.BAD_REQUEST, "A-003", "유효하지 않은 전화번호 입니다."), + CODE_NOT_MATCH(HttpStatus.BAD_REQUEST, "A-101", "요청하신 코드가 일치하지 않습니다."), + EMAIL_NOT_FOUND(HttpStatus.NOT_FOUND, "A-201", "해당 이메일이 존재하지 않습니다."), // 이게 소켓에 왜 필요한지, find 그 부분에서 발생해야할 예외일듯 + EMAIL_DUPLICATED(HttpStatus.CONFLICT, "A-301", "존재하는 이메일 입니다."), + PHONE_NUMBER_DUPLICATED(HttpStatus.CONFLICT, "A-302", "존재하는 전화번호입니다."), + + //회원 관련 + ROLE_IS_NOT_MATCH(HttpStatus.BAD_REQUEST, "M-101", "해당 ROLE은 변경할 수 없습니다."), + ROLE_IS_NOT_OLD_MEMBER(HttpStatus.BAD_REQUEST, "M-103", "해당 회원의 ROLE은 OLD_MEMBER가 아닙니다."), + SAME_PASSWORD(HttpStatus.CONFLICT, "M-301", "이전과 같은 비밀번호로 변경할 수 없습니다."), + MEMBER_TYPE_IS_NOT_ADMIN(HttpStatus.BAD_REQUEST, "M-102", "해당 회원은 ADMIN 회원이 아닙니다."), + + // 동아리 관련 + CLUB_ACCESS_DENIED(HttpStatus.FORBIDDEN, "C-001", "해당 동아리에 접근할 수 있는 권한이 없습니다."), + CLUB_POST_COMMENT_ACCESS_DENIED(HttpStatus.FORBIDDEN, "C-002", "해당 동아리 공지에 접근할 수 있는 권한이 없습니다."), + CLUB_POST_AUTHOR(HttpStatus.BAD_REQUEST, "C-003", "자신의 글은 좋아요할 수 없습니다."), + CLUB_POST_COMMENT_AUTHOR(HttpStatus.BAD_REQUEST, "C-004", "자신의 댓글은 좋아요할 수 없습니다."), + + //매칭 관련 + DUPLICATE_REQUEST(HttpStatus.CONFLICT, "M-302", "이미 해당 용병 게시글에 신청하셨습니다."), + CLUB_MATCH_FINALIZE(HttpStatus.CONFLICT, "M-303", "이미 매칭이 확정된 요청을 처리할 수 없습니다."), + + // 기수 운영 (세션 -> 출석) + INVALID_DATE(HttpStatus.BAD_REQUEST, "G-101", "시작날짜가 끝 날짜보다 뒤입니다"), + GENERATION_NUMBER_DUPLICATED(HttpStatus.CONFLICT, "G-201", "같은 숫자의 기수가 있습니다"), + + // 교육 도메인 + REGRADE_FAIL(HttpStatus.BAD_REQUEST, "E-201", "재채점 할 기록이 없습니다."), + EDUCATION_DUPLICATED(HttpStatus.CONFLICT, "E-301", "이미 교육이 존재합니다"), + EDUCATION_CLOSED(HttpStatus.BAD_REQUEST, "E-401", "CS 퀴즈가 닫혀 있습니다 먼저 교육 시작 버튼을 눌러주세요"), + EDUCATION_STATUS_NOT_BEFORE(HttpStatus.BAD_REQUEST, "E-402", "이미 시작한 적이 있는 교육입니다."), + MEMBER_CANT_ACCESS(HttpStatus.BAD_REQUEST, "E-403", "해당 멤버의 ROLE로 접근할 수 없습니다"), + + INVALID_ANSWER(HttpStatus.BAD_REQUEST, "Q-101", "객관식 문제는 숫자 형식의 값만 정답으로 추가할 수 있습니다."), + CONTENT_IS_NOT_ANSWER(HttpStatus.BAD_REQUEST, "Q-201", "추가되지 않은 정답을 추가할 수 없습니다."), + QUIZ_NUMBER_DUPLICATED(HttpStatus.CONFLICT, "Q-301", "퀴즈 번호는 중복될 수 없습니다."), + CHOICE_NUMBER_DUPLICATED(HttpStatus.CONFLICT, "Q-302", "선지 번호는 중복될 수 없습니다"), + CONTENT_IS_ALREADY_ANSWER(HttpStatus.BAD_REQUEST, "Q-303", "이미 정답인 답을 추가했습니다"), + QUIZ_ACCESS_DENIED(HttpStatus.BAD_REQUEST, "Q-401", "해당 퀴즈는 아직 접근할 수 없습니다."), + QUIZ_TYPE_NOT_MATCH(HttpStatus.BAD_REQUEST, "Q-402", "주관식 정답만 추가 가능합니다."), + + KING_MEMBER_EXIST(HttpStatus.CONFLICT, "K-301", "이미 킹킹 멤버가 존재합니다"), + + SUBJECT_INVALID(HttpStatus.BAD_REQUEST, "E-000", "교육 주제는 NULL이거나 비어있을 수 없습니다."), + + PROCESSING(HttpStatus.CONFLICT, "D-999", "해당 키의 요청은 아직 처리 중 입니다."), + + ALREADY_REPLY_CORRECT(HttpStatus.BAD_REQUEST, "R-301", "해당 사용자는 이미 정답 처리되었습니다."), + + LAST_QUIZ_SCORER_NOT_EXIST(HttpStatus.CONFLICT, "W-201", "아직 마지막 문제 득점자가 없습니다"), + WINNER_EXIST(HttpStatus.CONFLICT, "W-301", "이미 우승자가 존재합니다"), + // 500 오류 -> 서버측에서 처리가 실패한 부분들 + WEBSOCKET_SEND_EXCEPTION(HttpStatus.INTERNAL_SERVER_ERROR, "S-001", "소캣 메세지 전송 실패"), + IMAGE_PROCESSING_FAIL(HttpStatus.INTERNAL_SERVER_ERROR, "S-002", "이미지 처리에 실패했습니다."), + IMAGE_DELETE_FAIL(HttpStatus.INTERNAL_SERVER_ERROR, "S-003", "s3 이미지 삭제처리를 실패했습니다"), + INTERNAL_SQL_ERROR(HttpStatus.INTERNAL_SERVER_ERROR, "S-004", "SQL 관련 에러 발생"), + ENUM_NOT_RESOLVED(HttpStatus.BAD_REQUEST, "S-005", "입력한 Enum이 존재하지 않습니다."), + + NO_BALANCE_ERROR(HttpStatus.BAD_REQUEST, "F-001", "회비의 잔액보다 사용내역의 금액이 더 큽니다."), + PAYMENT_CHANGE_DENIED(HttpStatus.BAD_REQUEST, "F-002", "이미 사용중인 회비의 입금현황을 변경할 수 없습니다."), + ; + + private final HttpStatus httpStatus; + private final String code; + private final String message; } diff --git a/src/main/java/com/cotato/squadus/common/error/exception/AppException.java b/src/main/java/com/cotato/squadus/common/error/exception/AppException.java index b698578..6a05fd3 100644 --- a/src/main/java/com/cotato/squadus/common/error/exception/AppException.java +++ b/src/main/java/com/cotato/squadus/common/error/exception/AppException.java @@ -1,6 +1,7 @@ package com.cotato.squadus.common.error.exception; import com.cotato.squadus.common.error.ErrorCode; + import lombok.AllArgsConstructor; import lombok.Getter; @@ -8,5 +9,5 @@ @Getter public class AppException extends RuntimeException { - private ErrorCode errorCode; + private ErrorCode errorCode; } diff --git a/src/main/java/com/cotato/squadus/common/error/exception/S3Exception.java b/src/main/java/com/cotato/squadus/common/error/exception/S3Exception.java index 3bdefa4..ee2c600 100644 --- a/src/main/java/com/cotato/squadus/common/error/exception/S3Exception.java +++ b/src/main/java/com/cotato/squadus/common/error/exception/S3Exception.java @@ -1,14 +1,15 @@ package com.cotato.squadus.common.error.exception; import com.cotato.squadus.common.error.ErrorCode; + import lombok.Getter; @Getter public class S3Exception extends RuntimeException { - private final ErrorCode errorCode; + private final ErrorCode errorCode; - public S3Exception(ErrorCode errorCode) { - super(errorCode.getMessage()); - this.errorCode = errorCode; - } + public S3Exception(ErrorCode errorCode) { + super(errorCode.getMessage()); + this.errorCode = errorCode; + } } diff --git a/src/main/java/com/cotato/squadus/common/error/handler/GlobalExceptionHandler.java b/src/main/java/com/cotato/squadus/common/error/handler/GlobalExceptionHandler.java index 2068f9c..0ce1149 100644 --- a/src/main/java/com/cotato/squadus/common/error/handler/GlobalExceptionHandler.java +++ b/src/main/java/com/cotato/squadus/common/error/handler/GlobalExceptionHandler.java @@ -1,15 +1,8 @@ package com.cotato.squadus.common.error.handler; +import java.sql.SQLException; +import java.util.List; -import com.cotato.squadus.common.error.ErrorCode; -import com.cotato.squadus.common.error.exception.AppException; -import com.cotato.squadus.common.error.exception.S3Exception; -import com.cotato.squadus.common.error.response.ErrorResponse; -import com.cotato.squadus.common.error.response.MethodArgumentErrorResponse; -import com.cotato.squadus.common.error.response.MethodArgumentErrorResponse.FieldErrorResponse; -import jakarta.persistence.EntityNotFoundException; -import jakarta.servlet.http.HttpServletRequest; -import lombok.extern.slf4j.Slf4j; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatusCode; @@ -21,78 +14,86 @@ import org.springframework.web.context.request.WebRequest; import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler; -import java.sql.SQLException; -import java.util.List; +import com.cotato.squadus.common.error.ErrorCode; +import com.cotato.squadus.common.error.exception.AppException; +import com.cotato.squadus.common.error.exception.S3Exception; +import com.cotato.squadus.common.error.response.ErrorResponse; +import com.cotato.squadus.common.error.response.MethodArgumentErrorResponse; +import com.cotato.squadus.common.error.response.MethodArgumentErrorResponse.FieldErrorResponse; + +import jakarta.persistence.EntityNotFoundException; +import jakarta.servlet.http.HttpServletRequest; +import lombok.extern.slf4j.Slf4j; @Slf4j @RestControllerAdvice public class GlobalExceptionHandler extends ResponseEntityExceptionHandler { - @ExceptionHandler(AppException.class) - public ResponseEntity handleAppCustomException(AppException e, HttpServletRequest request) { - log.error("AppException 발생: {}", e.getErrorCode().getMessage()); - log.error("에러가 발생한 지점 {}, {}", request.getMethod(), request.getRequestURI()); - ErrorResponse errorResponse = ErrorResponse.of(e.getErrorCode(), request); - return ResponseEntity.status(e.getErrorCode().getHttpStatus()) - .body(errorResponse); - } -// -// @ExceptionHandler(ImageException.class) -// public ResponseEntity handleImageException(ImageException e, HttpServletRequest request) { -// log.error("이미지 처리 실패 예외 발생: {}", e.getErrorCode().getMessage()); -// log.error("에러가 발생한 지점 {}, {}", request.getMethod(), request.getRequestURI()); -// ErrorResponse errorResponse = ErrorResponse.of(ErrorCode.IMAGE_PROCESSING_FAIL, request); -// return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(errorResponse); -// } + @ExceptionHandler(AppException.class) + public ResponseEntity handleAppCustomException(AppException e, HttpServletRequest request) { + log.error("AppException 발생: {}", e.getErrorCode().getMessage()); + log.error("에러가 발생한 지점 {}, {}", request.getMethod(), request.getRequestURI()); + ErrorResponse errorResponse = ErrorResponse.of(e.getErrorCode(), request); + return ResponseEntity.status(e.getErrorCode().getHttpStatus()) + .body(errorResponse); + } + // + // @ExceptionHandler(ImageException.class) + // public ResponseEntity handleImageException(ImageException e, HttpServletRequest request) { + // log.error("이미지 처리 실패 예외 발생: {}", e.getErrorCode().getMessage()); + // log.error("에러가 발생한 지점 {}, {}", request.getMethod(), request.getRequestURI()); + // ErrorResponse errorResponse = ErrorResponse.of(ErrorCode.IMAGE_PROCESSING_FAIL, request); + // return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(errorResponse); + // } - @Override - protected ResponseEntity handleMethodArgumentNotValid(MethodArgumentNotValidException ex, - HttpHeaders headers, HttpStatusCode status, - WebRequest request) { - ServletWebRequest servletWebRequest = (ServletWebRequest) request; - HttpServletRequest httpServletRequest = servletWebRequest.getRequest(); - String requestURI = httpServletRequest.getRequestURI(); + @Override + protected ResponseEntity handleMethodArgumentNotValid(MethodArgumentNotValidException ex, + HttpHeaders headers, HttpStatusCode status, + WebRequest request) { + ServletWebRequest servletWebRequest = (ServletWebRequest)request; + HttpServletRequest httpServletRequest = servletWebRequest.getRequest(); + String requestURI = httpServletRequest.getRequestURI(); - List fieldErrorResponses = ex.getBindingResult().getFieldErrors().stream() - .map(FieldErrorResponse::of) - .toList(); + List fieldErrorResponses = ex.getBindingResult().getFieldErrors().stream() + .map(FieldErrorResponse::of) + .toList(); - List errorFields = fieldErrorResponses.stream() - .map(FieldErrorResponse::getField) - .toList(); + List errorFields = fieldErrorResponses.stream() + .map(FieldErrorResponse::getField) + .toList(); - log.error("[Method Argument Not Valid Execption 발생]: {}", errorFields); - log.error("에러가 발생한 지점 {}, {}", httpServletRequest.getMethod(), requestURI); + log.error("[Method Argument Not Valid Execption 발생]: {}", errorFields); + log.error("에러가 발생한 지점 {}, {}", httpServletRequest.getMethod(), requestURI); - MethodArgumentErrorResponse errorResponse = MethodArgumentErrorResponse.of( - ErrorCode.INVALID_INPUT, httpServletRequest, fieldErrorResponses); - return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(errorResponse); - } + MethodArgumentErrorResponse errorResponse = MethodArgumentErrorResponse.of( + ErrorCode.INVALID_INPUT, httpServletRequest, fieldErrorResponses); + return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(errorResponse); + } - @ExceptionHandler(EntityNotFoundException.class) - public ResponseEntity handleEntityNotFoundException(EntityNotFoundException e, - HttpServletRequest request) { - log.error("Entity Not Found Exception 발생: {}", e.getMessage()); - log.error("에러가 발생한 지점 {}, {}", request.getMethod(), request.getRequestURI()); - ErrorResponse errorResponse = ErrorResponse.of(ErrorCode.ENTITY_NOT_FOUND, request); - return ResponseEntity.status(HttpStatus.NOT_FOUND).body(errorResponse); - } + @ExceptionHandler(EntityNotFoundException.class) + public ResponseEntity handleEntityNotFoundException(EntityNotFoundException e, + HttpServletRequest request) { + log.error("Entity Not Found Exception 발생: {}", e.getMessage()); + log.error("에러가 발생한 지점 {}, {}", request.getMethod(), request.getRequestURI()); + ErrorResponse errorResponse = ErrorResponse.of(ErrorCode.ENTITY_NOT_FOUND, request); + return ResponseEntity.status(HttpStatus.NOT_FOUND).body(errorResponse); + } - @ExceptionHandler(SQLException.class) - public ResponseEntity handleSQLException(SQLException e, HttpServletRequest request) { - log.error("발생한 에러: {}", e.getErrorCode()); - log.error("에러가 발생한 지점 {}, {}", request.getMethod(), request.getRequestURI()); - ErrorResponse errorResponse = ErrorResponse.of(ErrorCode.INTERNAL_SQL_ERROR, request); - return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(errorResponse); - } + @ExceptionHandler(SQLException.class) + public ResponseEntity handleSQLException(SQLException e, HttpServletRequest request) { + log.error("발생한 에러: {}", e.getErrorCode()); + log.error("에러가 발생한 지점 {}, {}", request.getMethod(), request.getRequestURI()); + ErrorResponse errorResponse = ErrorResponse.of(ErrorCode.INTERNAL_SQL_ERROR, request); + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(errorResponse); + } - @ExceptionHandler(S3Exception.class) - public ResponseEntity handleS3Exception(S3Exception e, HttpServletRequest request) { - log.error("S3Exception 발생: {}", e.getErrorCode().getMessage()); - log.error("Exception detail: ", e); // 예외의 상세 내용을 로그에 출력 - log.error("에러가 발생한 지점 {}, {}", request.getMethod(), request.getRequestURI()); - ErrorResponse errorResponse = ErrorResponse.of(e.getErrorCode(), request); - return ResponseEntity.status(e.getErrorCode().getHttpStatus()) - .body(errorResponse); - } + @ExceptionHandler(S3Exception.class) + public ResponseEntity handleS3Exception(S3Exception e, HttpServletRequest request) { + log.error("S3Exception 발생: {}", e.getErrorCode().getMessage()); + log.error("Exception detail: ", e); // 예외의 상세 내용을 로그에 출력 + log.error("에러가 발생한 지점 {}, {}", request.getMethod(), request.getRequestURI()); + ErrorResponse errorResponse = ErrorResponse.of(e.getErrorCode(), request); + return ResponseEntity.status(e.getErrorCode().getHttpStatus()) + .body(errorResponse); + } } \ No newline at end of file diff --git a/src/main/java/com/cotato/squadus/common/error/response/ErrorResponse.java b/src/main/java/com/cotato/squadus/common/error/response/ErrorResponse.java index bfc0fa8..a3440b7 100644 --- a/src/main/java/com/cotato/squadus/common/error/response/ErrorResponse.java +++ b/src/main/java/com/cotato/squadus/common/error/response/ErrorResponse.java @@ -1,30 +1,31 @@ package com.cotato.squadus.common.error.response; import com.cotato.squadus.common.error.ErrorCode; + import jakarta.servlet.http.HttpServletRequest; public record ErrorResponse( - String code, - String message, - String method, - String requestURI + String code, + String message, + String method, + String requestURI ) { - public static ErrorResponse of(ErrorCode errorCode, HttpServletRequest request) { - return new ErrorResponse( - errorCode.getCode(), - errorCode.getMessage(), - request.getMethod(), - request.getRequestURI() - ); - } + public static ErrorResponse of(ErrorCode errorCode, HttpServletRequest request) { + return new ErrorResponse( + errorCode.getCode(), + errorCode.getMessage(), + request.getMethod(), + request.getRequestURI() + ); + } - public static ErrorResponse of(HttpServletRequest request, ErrorCode errorCode, final String errorMessage) { - return new ErrorResponse( - errorCode.getCode(), - errorMessage, - request.getMethod(), - request.getRequestURI() - ); - } + public static ErrorResponse of(HttpServletRequest request, ErrorCode errorCode, final String errorMessage) { + return new ErrorResponse( + errorCode.getCode(), + errorMessage, + request.getMethod(), + request.getRequestURI() + ); + } } diff --git a/src/main/java/com/cotato/squadus/common/error/response/MethodArgumentErrorResponse.java b/src/main/java/com/cotato/squadus/common/error/response/MethodArgumentErrorResponse.java index 038dbe4..b8244d1 100644 --- a/src/main/java/com/cotato/squadus/common/error/response/MethodArgumentErrorResponse.java +++ b/src/main/java/com/cotato/squadus/common/error/response/MethodArgumentErrorResponse.java @@ -1,46 +1,48 @@ package com.cotato.squadus.common.error.response; +import java.util.List; + +import org.springframework.validation.FieldError; + import com.cotato.squadus.common.error.ErrorCode; + import jakarta.servlet.http.HttpServletRequest; import lombok.AccessLevel; import lombok.AllArgsConstructor; import lombok.Getter; import lombok.NoArgsConstructor; -import org.springframework.validation.FieldError; - -import java.util.List; public record MethodArgumentErrorResponse( - String code, - String message, - String method, - String requestURI, - List errors + String code, + String message, + String method, + String requestURI, + List errors ) { - public static MethodArgumentErrorResponse of(ErrorCode errorCode, HttpServletRequest request, - List errors) { - return new MethodArgumentErrorResponse( - errorCode.getCode(), - errorCode.getMessage(), - request.getMethod(), - request.getRequestURI(), - errors - ); - } - - @Getter - @NoArgsConstructor(access = AccessLevel.PROTECTED) - @AllArgsConstructor(access = AccessLevel.PRIVATE) - public static class FieldErrorResponse { - private String field; - private String reason; - - public static FieldErrorResponse of(FieldError fieldError) { - return new FieldErrorResponse( - fieldError.getField(), - fieldError.getDefaultMessage() - ); - } - } + public static MethodArgumentErrorResponse of(ErrorCode errorCode, HttpServletRequest request, + List errors) { + return new MethodArgumentErrorResponse( + errorCode.getCode(), + errorCode.getMessage(), + request.getMethod(), + request.getRequestURI(), + errors + ); + } + + @Getter + @NoArgsConstructor(access = AccessLevel.PROTECTED) + @AllArgsConstructor(access = AccessLevel.PRIVATE) + public static class FieldErrorResponse { + private String field; + private String reason; + + public static FieldErrorResponse of(FieldError fieldError) { + return new FieldErrorResponse( + fieldError.getField(), + fieldError.getDefaultMessage() + ); + } + } } diff --git a/src/main/java/com/cotato/squadus/common/s3/S3Controller.java b/src/main/java/com/cotato/squadus/common/s3/S3Controller.java index deec999..85cfc93 100644 --- a/src/main/java/com/cotato/squadus/common/s3/S3Controller.java +++ b/src/main/java/com/cotato/squadus/common/s3/S3Controller.java @@ -1,30 +1,36 @@ package com.cotato.squadus.common.s3; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.*; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RequestPart; +import org.springframework.web.bind.annotation.RestController; import org.springframework.web.multipart.MultipartFile; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; + @Slf4j @RestController @RequestMapping("/v1/api/image") @RequiredArgsConstructor public class S3Controller { - private final S3ImageService s3ImageService; + private final S3ImageService s3ImageService; - @PostMapping("/s3/upload") - public ResponseEntity s3Upload(@RequestPart(value = "image", required = false) MultipartFile image){ - String profileImage = s3ImageService.upload(image); - log.info("Profile image: {}", profileImage); - return ResponseEntity.ok(profileImage); - } + @PostMapping("/s3/upload") + public ResponseEntity s3Upload(@RequestPart(value = "image", required = false) MultipartFile image) { + String profileImage = s3ImageService.upload(image); + log.info("Profile image: {}", profileImage); + return ResponseEntity.ok(profileImage); + } - @GetMapping("/s3/delete") - public ResponseEntity s3delete(@RequestParam String addr){ - s3ImageService.deleteImageFromS3(addr); - return ResponseEntity.ok(null); - } + @GetMapping("/s3/delete") + public ResponseEntity s3delete(@RequestParam String addr) { + s3ImageService.deleteImageFromS3(addr); + return ResponseEntity.ok(null); + } } diff --git a/src/main/java/com/cotato/squadus/common/s3/S3ImageService.java b/src/main/java/com/cotato/squadus/common/s3/S3ImageService.java index 4a0a22e..16ecc78 100644 --- a/src/main/java/com/cotato/squadus/common/s3/S3ImageService.java +++ b/src/main/java/com/cotato/squadus/common/s3/S3ImageService.java @@ -1,19 +1,5 @@ package com.cotato.squadus.common.s3; -import com.amazonaws.services.s3.AmazonS3; -import com.amazonaws.services.s3.model.CannedAccessControlList; -import com.amazonaws.services.s3.model.DeleteObjectRequest; -import com.amazonaws.services.s3.model.ObjectMetadata; -import com.amazonaws.services.s3.model.PutObjectRequest; -import com.amazonaws.util.IOUtils; -import com.cotato.squadus.common.error.ErrorCode; -import com.cotato.squadus.common.error.exception.S3Exception; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.stereotype.Component; -import org.springframework.web.multipart.MultipartFile; - import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; @@ -26,100 +12,116 @@ import java.util.Objects; import java.util.UUID; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; +import org.springframework.web.multipart.MultipartFile; + +import com.amazonaws.services.s3.AmazonS3; +import com.amazonaws.services.s3.model.CannedAccessControlList; +import com.amazonaws.services.s3.model.DeleteObjectRequest; +import com.amazonaws.services.s3.model.ObjectMetadata; +import com.amazonaws.services.s3.model.PutObjectRequest; +import com.amazonaws.util.IOUtils; +import com.cotato.squadus.common.error.ErrorCode; +import com.cotato.squadus.common.error.exception.S3Exception; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; + @Slf4j @RequiredArgsConstructor @Component public class S3ImageService { - private final AmazonS3 amazonS3; - - @Value("${cloud.aws.s3.bucketName}") - private String bucketName; - - public String upload(MultipartFile image) { - if(image.isEmpty() || Objects.isNull(image.getOriginalFilename())){ - throw new S3Exception(ErrorCode.EMPTY_FILE_EXCEPTION); - } - log.info("Uploading image " + image.getOriginalFilename()); - return this.uploadImage(image); - } - - private String uploadImage(MultipartFile image) { - this.validateImageFileExtention(image.getOriginalFilename()); - log.info("Uploading image2 " + image.getOriginalFilename()); - try { - return this.uploadImageToS3(image); - } catch (IOException e) { - throw new S3Exception(ErrorCode.IO_EXCEPTION_ON_IMAGE_UPLOAD); - } - } - - private void validateImageFileExtention(String filename) { - int lastDotIndex = filename.lastIndexOf("."); - if (lastDotIndex == -1) { - throw new S3Exception(ErrorCode.NO_FILE_EXTENTION); - } - - String extention = filename.substring(lastDotIndex + 1).toLowerCase(); - List allowedExtentionList = Arrays.asList("jpg", "jpeg", "png", "gif"); - - if (!allowedExtentionList.contains(extention)) { - throw new S3Exception(ErrorCode.INVALID_FILE_EXTENTION); - } - log.info("Validating image file " + filename); - } - - private String uploadImageToS3(MultipartFile image) throws IOException { - String originalFilename = image.getOriginalFilename(); //원본 파일 명 - String extention = originalFilename.substring(originalFilename.lastIndexOf(".")); //확장자 명 - - String s3FileName = UUID.randomUUID().toString().substring(0, 10) + originalFilename; //변경된 파일 명 - - InputStream is = image.getInputStream(); - byte[] bytes = IOUtils.toByteArray(is); - - ObjectMetadata metadata = new ObjectMetadata(); - metadata.setContentType("image/" + extention); - metadata.setContentLength(bytes.length); - ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes); - - log.info("hello image " + image.getOriginalFilename()); - - try{ - PutObjectRequest putObjectRequest = - new PutObjectRequest(bucketName, s3FileName, byteArrayInputStream, metadata) - .withCannedAcl(CannedAccessControlList.PublicRead); - log.info("first image " + image.getOriginalFilename()); - amazonS3.putObject(putObjectRequest); // put image to S3 - log.info("second image " + image.getOriginalFilename()); - - }catch (Exception e){ - throw new S3Exception(ErrorCode.PUT_OBJECT_EXCEPTION); - }finally { - byteArrayInputStream.close(); - is.close(); - } - - log.info("upload image " + originalFilename + " successfully uploaded"); - return amazonS3.getUrl(bucketName, s3FileName).toString(); - } - - public void deleteImageFromS3(String imageAddress){ - String key = getKeyFromImageAddress(imageAddress); - try{ - amazonS3.deleteObject(new DeleteObjectRequest(bucketName, key)); - }catch (Exception e){ - throw new S3Exception(ErrorCode.IO_EXCEPTION_ON_IMAGE_DELETE); - } - } - - private String getKeyFromImageAddress(String imageAddress){ - try{ - URL url = new URL(imageAddress); - String decodingKey = URLDecoder.decode(url.getPath(), "UTF-8"); - return decodingKey.substring(1); // 맨 앞의 '/' 제거 - }catch (MalformedURLException | UnsupportedEncodingException e){ - throw new S3Exception(ErrorCode.IO_EXCEPTION_ON_IMAGE_DELETE); - } - } + private final AmazonS3 amazonS3; + + @Value("${cloud.aws.s3.bucketName}") + private String bucketName; + + public String upload(MultipartFile image) { + if (image.isEmpty() || Objects.isNull(image.getOriginalFilename())) { + throw new S3Exception(ErrorCode.EMPTY_FILE_EXCEPTION); + } + log.info("Uploading image " + image.getOriginalFilename()); + return this.uploadImage(image); + } + + private String uploadImage(MultipartFile image) { + this.validateImageFileExtention(image.getOriginalFilename()); + log.info("Uploading image2 " + image.getOriginalFilename()); + try { + return this.uploadImageToS3(image); + } catch (IOException e) { + throw new S3Exception(ErrorCode.IO_EXCEPTION_ON_IMAGE_UPLOAD); + } + } + + private void validateImageFileExtention(String filename) { + int lastDotIndex = filename.lastIndexOf("."); + if (lastDotIndex == -1) { + throw new S3Exception(ErrorCode.NO_FILE_EXTENTION); + } + + String extention = filename.substring(lastDotIndex + 1).toLowerCase(); + List allowedExtentionList = Arrays.asList("jpg", "jpeg", "png", "gif"); + + if (!allowedExtentionList.contains(extention)) { + throw new S3Exception(ErrorCode.INVALID_FILE_EXTENTION); + } + log.info("Validating image file " + filename); + } + + private String uploadImageToS3(MultipartFile image) throws IOException { + String originalFilename = image.getOriginalFilename(); //원본 파일 명 + String extention = originalFilename.substring(originalFilename.lastIndexOf(".")); //확장자 명 + + String s3FileName = UUID.randomUUID().toString().substring(0, 10) + originalFilename; //변경된 파일 명 + + InputStream is = image.getInputStream(); + byte[] bytes = IOUtils.toByteArray(is); + + ObjectMetadata metadata = new ObjectMetadata(); + metadata.setContentType("image/" + extention); + metadata.setContentLength(bytes.length); + ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes); + + log.info("hello image " + image.getOriginalFilename()); + + try { + PutObjectRequest putObjectRequest = + new PutObjectRequest(bucketName, s3FileName, byteArrayInputStream, metadata) + .withCannedAcl(CannedAccessControlList.PublicRead); + log.info("first image " + image.getOriginalFilename()); + amazonS3.putObject(putObjectRequest); // put image to S3 + log.info("second image " + image.getOriginalFilename()); + + } catch (Exception e) { + throw new S3Exception(ErrorCode.PUT_OBJECT_EXCEPTION); + } finally { + byteArrayInputStream.close(); + is.close(); + } + + log.info("upload image " + originalFilename + " successfully uploaded"); + return amazonS3.getUrl(bucketName, s3FileName).toString(); + } + + public void deleteImageFromS3(String imageAddress) { + String key = getKeyFromImageAddress(imageAddress); + try { + amazonS3.deleteObject(new DeleteObjectRequest(bucketName, key)); + } catch (Exception e) { + throw new S3Exception(ErrorCode.IO_EXCEPTION_ON_IMAGE_DELETE); + } + } + + private String getKeyFromImageAddress(String imageAddress) { + try { + URL url = new URL(imageAddress); + String decodingKey = URLDecoder.decode(url.getPath(), "UTF-8"); + return decodingKey.substring(1); // 맨 앞의 '/' 제거 + } catch (MalformedURLException | UnsupportedEncodingException e) { + throw new S3Exception(ErrorCode.IO_EXCEPTION_ON_IMAGE_DELETE); + } + } } diff --git a/src/main/java/com/cotato/squadus/domain/auth/entity/Member.java b/src/main/java/com/cotato/squadus/domain/auth/entity/Member.java index e95d73c..2bea0ff 100644 --- a/src/main/java/com/cotato/squadus/domain/auth/entity/Member.java +++ b/src/main/java/com/cotato/squadus/domain/auth/entity/Member.java @@ -1,84 +1,94 @@ package com.cotato.squadus.domain.auth.entity; -import com.cotato.squadus.domain.club.common.entity.ClubMember; +import static jakarta.persistence.CascadeType.*; + +import java.util.List; + import com.cotato.squadus.domain.auth.enums.MemberRole; -import jakarta.persistence.*; +import com.cotato.squadus.domain.club.common.entity.ClubMember; + +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.EnumType; +import jakarta.persistence.Enumerated; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.Id; +import jakarta.persistence.OneToMany; +import jakarta.persistence.Table; import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; -import java.util.List; - -import static jakarta.persistence.CascadeType.*; - @Entity @Getter @Table(name = "member") @NoArgsConstructor public class Member { - @Id - @GeneratedValue - private Long memberIdx; - - private String uniqueId; + @Id + @GeneratedValue + private Long memberIdx; - private String username; // 임시로 생성 + private String uniqueId; - private String email; + private String username; // 임시로 생성 - private String profileImage; + private String email; - private String university; + private String profileImage; - @Enumerated(EnumType.STRING) - private MemberRole memberRole; + private String university; - // jwt refresh token - @Column(length = 1000) - private String refreshToken; + @Enumerated(EnumType.STRING) + private MemberRole memberRole; - public void updateRefreshToken(String refreshToken) { - this.refreshToken = refreshToken; - } + // jwt refresh token + @Column(length = 1000) + private String refreshToken; - public void destroyRefreshToken() { - this.refreshToken = null; - } + public void updateRefreshToken(String refreshToken) { + this.refreshToken = refreshToken; + } - @OneToMany(mappedBy = "member", cascade = ALL) - private List clubMemberships; // 가입된 동아리 리스트 확인 + public void destroyRefreshToken() { + this.refreshToken = null; + } + @OneToMany(mappedBy = "member", cascade = ALL) + private List clubMemberships; // 가입된 동아리 리스트 확인 - @Builder - public Member(String uniqueId, String username, String email, String memberRole, String profileImage, String university) { - this.uniqueId = uniqueId; - this.username = username; - this.email = email; - this.profileImage = profileImage; - this.university = university; - if (memberRole.equals("MEMBER")) this.memberRole = MemberRole.MEMBER; - else if(memberRole.equals("CERTIFIED_MEMBER")) this.memberRole = MemberRole.CERTIFIED_MEMBER; - } + @Builder + public Member(String uniqueId, String username, String email, String memberRole, String profileImage, + String university) { + this.uniqueId = uniqueId; + this.username = username; + this.email = email; + this.profileImage = profileImage; + this.university = university; + if (memberRole.equals("MEMBER")) + this.memberRole = MemberRole.MEMBER; + else if (memberRole.equals("CERTIFIED_MEMBER")) + this.memberRole = MemberRole.CERTIFIED_MEMBER; + } - public Member update(String email, String username) { - this.email = email; - this.username = username; - return this; - } + public Member update(String email, String username) { + this.email = email; + this.username = username; + return this; + } - public Member updateUniversity(String university) { - this.university = university; - return this; - } + public Member updateUniversity(String university) { + this.university = university; + return this; + } - public Member updateProfileImage(String profileImage) { - this.profileImage = profileImage; - return this; - } + public Member updateProfileImage(String profileImage) { + this.profileImage = profileImage; + return this; + } - public Member updateMemberRole(MemberRole memberRole) { - this.memberRole = memberRole; - return this; - } + public Member updateMemberRole(MemberRole memberRole) { + this.memberRole = memberRole; + return this; + } } diff --git a/src/main/java/com/cotato/squadus/domain/auth/enums/AdminStatus.java b/src/main/java/com/cotato/squadus/domain/auth/enums/AdminStatus.java index 3a0ae61..f8d3dca 100644 --- a/src/main/java/com/cotato/squadus/domain/auth/enums/AdminStatus.java +++ b/src/main/java/com/cotato/squadus/domain/auth/enums/AdminStatus.java @@ -1,6 +1,6 @@ package com.cotato.squadus.domain.auth.enums; public enum AdminStatus { - CURRENT, - FORMER + CURRENT, + FORMER } diff --git a/src/main/java/com/cotato/squadus/domain/auth/enums/ApplicationStatus.java b/src/main/java/com/cotato/squadus/domain/auth/enums/ApplicationStatus.java index aa6baf3..2fbc847 100644 --- a/src/main/java/com/cotato/squadus/domain/auth/enums/ApplicationStatus.java +++ b/src/main/java/com/cotato/squadus/domain/auth/enums/ApplicationStatus.java @@ -1,7 +1,7 @@ package com.cotato.squadus.domain.auth.enums; public enum ApplicationStatus { - PENDING, - APPROVED, - REJECTED + PENDING, + APPROVED, + REJECTED } diff --git a/src/main/java/com/cotato/squadus/domain/auth/enums/MemberRole.java b/src/main/java/com/cotato/squadus/domain/auth/enums/MemberRole.java index c65f3d7..4afced0 100644 --- a/src/main/java/com/cotato/squadus/domain/auth/enums/MemberRole.java +++ b/src/main/java/com/cotato/squadus/domain/auth/enums/MemberRole.java @@ -1,6 +1,6 @@ package com.cotato.squadus.domain.auth.enums; public enum MemberRole { - MEMBER, - CERTIFIED_MEMBER + MEMBER, + CERTIFIED_MEMBER } diff --git a/src/main/java/com/cotato/squadus/domain/auth/enums/Membership.java b/src/main/java/com/cotato/squadus/domain/auth/enums/Membership.java index 6ddd861..76f8fc3 100644 --- a/src/main/java/com/cotato/squadus/domain/auth/enums/Membership.java +++ b/src/main/java/com/cotato/squadus/domain/auth/enums/Membership.java @@ -1,7 +1,7 @@ package com.cotato.squadus.domain.auth.enums; public enum Membership { - APPLIED, - JOINED, - QUIT + APPLIED, + JOINED, + QUIT } diff --git a/src/main/java/com/cotato/squadus/domain/auth/enums/SchoolDomain.java b/src/main/java/com/cotato/squadus/domain/auth/enums/SchoolDomain.java index a13b8cf..aadc4e5 100644 --- a/src/main/java/com/cotato/squadus/domain/auth/enums/SchoolDomain.java +++ b/src/main/java/com/cotato/squadus/domain/auth/enums/SchoolDomain.java @@ -1,231 +1,231 @@ package com.cotato.squadus.domain.auth.enums; public enum SchoolDomain { - GACHON_UNIVERSITY("gachon.ac.kr", "가천대학교"), - CATHOLIC_SANGJI_COLLEGE("csj.ac.kr", "가톨릭상지대학교"), - GANGDONG_COLLEGE("gangdong.ac.kr", "강동대학교"), - GANGNEUNG_YEONGDONG_COLLEGE("gyc.ac.kr", "강릉영동대학교"), - KANGWON_TOURISM_COLLEGE("kt.ac.kr", "강원관광대학"), - KANGWON_DO_COLLEGE("gw.ac.kr", "강원도립대학"), - KOJE_COLLEGE("koje.ac.kr", "거제대학교"), - KYUNGGI_COLLEGE_OF_SCIENCE_AND_TECHNOLOGY("gtec.ac.kr", "경기과학기술대학교"), - GYEONGNAM_PROVINCIAL_GEOCHEON_COLLEGE("gc.ac.kr", "경남도립거창대학"), - GYEONGNAM_PROVINCIAL_NAMHAE_COLLEGE("namhae.ac.kr", "경남도립남해대학"), - GYEONGNAM_INFORMATION_UNIVERSITY("kit.ac.kr", "경남정보대학교"), - KYUNGMIN_UNIVERSITY("kyungmin.ac.kr", "경민대학교"), - KYUNGBOK_UNIVERSITY("kbu.ac.kr", "경복대학교"), - GYEONGBUK_COLLEGE_OF_SCIENCE("kbsc.ac.kr", "경북과학대학교"), - GYEONGBUK_PROVINCIAL_UNIVERSITY("gpc.ac.kr", "경북도립대학교"), - GYEONGBUK_COLLEGE("kbc.ac.kr", "경북전문대학교"), - GYEONGSAN_1_COLLEGE("gs.ac.kr", "경산1대학교"), - KYUNGWON_COLLEGE("kwc.ac.kr", "경원전문대학"), - KYUNG_IN_WOMENS_UNIVERSITY("kic.ac.kr", "경인여자대학교"), - KEIMYUNG_COLLEGE_UNIVERSITY("kmcu.ac.kr", "계명문화대학교"), - KAYWON_COLLEGE_OF_ARTS("kaywon.ac.kr", "계원예술대학교"), - GOGURYEO_UNIVERSITY("kgrc.ac.kr", "고구려대학교"), - KOREA_UNIVERSITY("korea.ac.kr", "고려대학교"), - SKKU("skku.edu", "성균관대학교"), - KWANGYANG_HEALTH_COLLEGE("kwangyang.ac.kr", "광양보건대학교"), - GWANGJU_HEALTH_COLLEGE("ghu.ac.kr", "광주보건대학교"), - GUMI_COLLEGE("gumi.ac.kr", "구미대학교"), - SAOTC("saotc.ac.kr", "구세군사관학교"), - KOOKJE_UNIVERSITY("kookje.ac.kr", "국제대학교"), - KUNSAN_NURSING_COLLEGE("kcn.ac.kr", "군산간호대학교"), - KUNJANG_COLLEGE("kunjang.ac.kr", "군장대학교"), - CHRISTIAN_COLLEGE_OF_NURSING("ccn.ac.kr", "기독간호대학교"), - KIMCHEON_COLLEGE("kcs.ac.kr", "김천과학대학"), - GIMCHEON_COLLEGE("gimcheon.ac.kr", "김천대학"), - KIMPO_COLLEGE("kimpo.ac.kr", "김포대학교"), - GIMHAE_COLLEGE("gimhae.ac.kr", "김해대학교"), - NH_COLLEGE("nonghyup.ac.kr", "농협대학교"), - DAEKYUNG_COLLEGE("tk.ac.kr", "대경대학교"), - DAEGU_TECHNICAL_COLLEGE("ttc.ac.kr", "대구공업대학교"), - DAEGU_SCIENCE_COLLEGE("tsu.ac.kr", "대구과학대학교"), - DAEGU_FUTURE_COLLEGE("dfc.ac.kr", "대구미래대학교"), - DAEGU_HEALTH_COLLEGE("dhc.ac.kr", "대구보건대학교"), - DAEDEOK_COLLEGE("ddu.ac.kr", "대덕대학교"), - DAEDONG_COLLEGE("daedong.ac.kr", "대동대학교"), - DAELIM_UNIVERSITY("daelim.ac.kr", "대림대학교"), - DAEWON_UNIVERSITY("daewon.ac.kr", "대원대학교"), - DAEJEON_HEALTH_COLLEGE("hit.ac.kr", "대전보건대학교"), - DONGKANG_COLLEGE("dkc.ac.kr", "동강대학교"), - DONGNAM_HEALTH_UNIVERSITY("dongnam.ac.kr", "동남보건대학교"), - DONGMYUNG_COLLEGE("tu.ac.kr", "동명대학"), - DONGPUSAN_COLLEGE("dpc.ac.kr", "동부산대학교"), - DONGSEOUL_UNIVERSITY("dsc.ac.kr", "동서울대학교"), - DONGAH_MEDIA_AND_ARTS_COLLEGE("dima.ac.kr", "동아방송예술대학교"), - DONGAIN_UNIVERSITY("dongac.ac.kr", "동아인재대학교"), - DONGYANG_MIRAE_UNIVERSITY("dongyang.ac.kr", "동양미래대학교"), - DONGWOO_COLLEGE("duc.ac.kr", "동우대학"), - DONGWON_COLLEGE_OF_SCIENCE_AND_TECHNOLOGY("dist.ac.kr", "동원과학기술대학교"), - DONGWON_UNIVERSITY("tw.ac.kr", "동원대학교"), - DONGUI_COLLEGE("dit.ac.kr", "동의과학대학교"), - DONGJU_COLLEGE("dongju.ac.kr", "동주대학교"), - DOOWON_TECHNICAL_COLLEGE("doowon.ac.kr", "두원공과대학교"), - MASAN_UNIVERSITY("masan.ac.kr", "마산대학교"), - MYONGJI_COLLEGE("mjc.ac.kr", "명지전문대학"), - MOKPO_SCIENCE_COLLEGE("mokpo-c.ac.kr", "목포과학대학교"), - MOONKYUNG_COLLEGE("mkc.ac.kr", "문경대학교"), - BAEHWA_WOMENS_UNIVERSITY("baewha.ac.kr", "배화여자대학교"), - BAEKSEOK_CULTURAL_UNIVERSITY("bscu.ac.kr", "백석문화대학교"), - PAEKCHE_INSTITUTE_OF_THE_ARTS("paekche.ac.kr", "백제예술대학교"), - BYEOKSEONG_COLLEGE("bs.ac.kr", "벽성대학"), - BUSAN_KYUNGSANG_UNIVERSITY("bsks.ac.kr", "부산경상대학교"), - BUSAN_COLLEGE_OF_SCIENCE_AND_TECHNOLOGY("bist.ac.kr", "부산과학기술대학교"), - BUSAN_WOMENS_COLLEGE("bwc.ac.kr", "부산여자대학교"), - BUSAN_UNIVERSITY_OF_ARTS("busanarts.ac.kr", "부산예술대학교"), - BUCHEON_UNIVERSITY("bc.ac.kr", "부천대학교"), - SAMYOOK_HEALTH_UNIVERSITY("shu.ac.kr", "삼육보건대학"), - SAMYOOK_UNIVERSITY("syu.ac.kr", "삼육의명대학"), - SANGJI_YEONGSEO_COLLEGE("sy.ac.kr", "상지영서대학교"), - SEOUL_NATIONAL_UNIVERSITY("snu.ac.kr", "서울대학교"), - SEORABOL_COLLEGE("sorabol.ac.kr", "서라벌대학교"), - SEOYEONG_UNIVERSITY("seoyeong.ac.kr", "서영대학교"), - SEOUL_HEALTH_COLLEGE("shjc.ac.kr", "서울보건대학"), - SEOUL_WOMENS_COLLEGE_OF_NURSING("snjc.ac.kr", "서울여자간호대학교"), - SEOUL_INSTITUTE_OF_THE_ARTS("seoularts.ac.kr", "서울예술대학교"), - SEOIL_UNIVERSITY("seoil.ac.kr", "서일대학교"), - SEOJEONG_COLLEGE("seojeong.ac.kr", "서정대학교"), - SOHAE_COLLEGE("sohae.ac.kr", "서해대학"), - SUNLIN_COLLEGE("sunlin.ac.kr", "선린대학교"), - SUNGDUK_COLLEGE("sdc.ac.kr", "성덕대학교"), - SUNGSIM_FOREIGN_LANGUAGE_UNIVERSITY("sungsim.ac.kr", "성심외국어대학"), - SAEKYUNG_COLLEGE("saekyung.ac.kr", "세경대학교"), - SONGGOK_COLLEGE("songgok.ac.kr", "송곡대학교"), - SONGWON_COLLEGE("songwon.ac.kr", "송원대학"), - SONGHO_COLLEGE("songho.ac.kr", "송호대학교"), - SUSEONG_COLLEGE("sc.ac.kr", "수성대학교"), - SUWON_SCIENCE_COLLEGE("ssc.ac.kr", "수원과학대학교"), - SUWON_WOMENS_COLLEGE("swc.ac.kr", "수원여자대학교"), - SUNCHEON_FIRST_COLLEGE("suncheon.ac.kr", "순천제일대학"), - SUNG_UI_WOMENS_UNIVERSITY("sewc.ac.kr", "숭의여자대학교"), - SHINGU_COLLEGE("shingu.ac.kr", "신구대학교"), - SHINSUNG_UNIVERSITY("shinsung.ac.kr", "신성대학교"), - SHINANSAN_UNIVERSITY("sau.ac.kr", "신안산대학교"), - SHINHUNG_COLLEGE("shc.ac.kr", "신흥대학교"), - AJOU_MOTOR_COLLEGE("motor.ac.kr", "아주자동차대학"), - ANDONG_SCIENCE_COLLEGE("asc.ac.kr", "안동과학대학교"), - ANSAN_COLLEGE("ansan.ac.kr", "안산대학교"), - YEOJU_INSTITUTE_OF_TECHNOLOGY("yit.ac.kr", "여주대학교"), - YEONSUNG_UNIVERSITY("yeonsung.ac.kr", "연성대학교"), - YEONSEI_UNIVERSITY("yonsei.ac.kr", "연세대학교"), - YOUNAM_ENGINEERING_COLLEGE("yc.ac.kr", "연암공과대학교"), - YEONGNAM_FOREIGN_LANGUAGE_COLLEGE("yflc.ac.kr", "영남외국어대학"), - YEONGNAM_ENGINEERING_COLLEGE("ync.ac.kr", "영남이공대학교"), - YUDEOK_CYBER_UNIVERSITY("ycc.ac.kr", "영진사이버대학"), - YEONGJIN_COLLEGE("yjc.ac.kr", "영진전문대학"), - OSAN_UNIVERSITY("osan.ac.kr", "오산대학교"), - YONGINSUNGDAM_UNIVERSITY("ysc.ac.kr", "용인송담대학교"), - WOOSONG_COLLEGE("wst.ac.kr", "우송공업대학"), - WOOSONG_INFORMATION_COLLEGE("wsi.ac.kr", "우송정보대학"), - ULSAN_COLLEGE_OF_SCIENCE_AND_TECHNOLOGY("uc.ac.kr", "울산과학대학교"), - UNJISEMU_COLLEGE("wat.ac.kr", "웅지세무대학"), - WONKWANG_HEALTH_COLLEGE("wkhc.ac.kr", "원광보건대학교"), - WONJU_COLLEGE("wonju.ac.kr", "원주대학"), - YUHAN_UNIVERSITY("yuhan.ac.kr", "유한대학교"), - INDUK_UNIVERSITY("induk.ac.kr", "인덕대학교"), - INCHEON_JAEUNGEUNIVERSITY("jeiu.ac.kr", "인천재능대학교"), - INCHEON_TECHNICAL_COLLEGE("icc.ac.kr", "인천전문대학"), - INHA_TECHNICAL_COLLEGE("itc.ac.kr", "인하공업전문대학"), - JANGAN_UNIVERSITY("jangan.ac.kr", "장안대학교"), - REDCROSS_NURSING_COLLEGE("cau.ac.kr", "적십자간호대학"), - JEONNAM_SCIENCE_COLLEGE("chunnam-c.ac.kr", "전남과학대학교"), - JEONNAM_PROVINCIAL_COLLEGE("dorip.ac.kr", "전남도립대학교"), - JEONBUK_COLLEGE_OF_SCIENCE("jbsc.ac.kr", "전북과학대학교"), - JEONJU_GIZON_COLLEGE("jk.ac.kr", "전주기전대학"), - JEONJU_VISION_COLLEGE("jvision.ac.kr", "전주비전대학교"), - JEJU_COLLEGE_OF_TOURISM("ctc.ac.kr", "제주관광대학교"), - JEJU_COLLEGE_OF_INDUSTRIAL_INFORMATION("jeju.ac.kr", "제주산업정보대학"), - JEJU_HANLA_UNIVERSITY("chu.ac.kr", "제주한라대학교"), - CHOSUN_NURSING_COLLEGE("cnc.ac.kr", "조선간호대학교"), - CHOSUN_ENGINEERING_COLLEGE("cst.ac.kr", "조선이공대학교"), - JINJU_HEALTH_COLLEGE("jhc.ac.kr", "진주보건대학교"), - CHANGSHIN_UNIVERSITY("csc.ac.kr", "창신대학"), - CHANGWON_MOONSEONG_UNIVERSITY("cmu.ac.kr", "창원문성대학"), - CHEONAN_YEONAM_COLLEGE("yonam.ac.kr", "천안연암대학"), - CHUNGKANG_COLLEGE_OF_CULTURAL_INDUSTRIES("chungkang.academy", "청강문화산업대학교"), - CHEONGNAM_COLLEGE("scjc.ac.kr", "청암대학교"), - CHUNHAE_HEALTH_UNIVERSITY("ch.ac.kr", "춘해보건대학교"), - CHUNGCHEONGNAM_PROVINCIAL_CHEONGLYANG_UNIVERSITY("cyc.ac.kr", "충남도립청양대학"), - CHUNGBUK_PROVINCIAL_UNIVERSITY("cpu.ac.kr", "충북도립대학"), - CHUNGBUK_HEALTH_AND_SCIENCE_UNIVERSITY("chsu.ac.kr", "충북보건과학대학교"), - CHUNGCHUNG_COLLEGE("ok.ac.kr", "충청대학교"), - POHANG_UNIVERSITY("pohang.ac.kr", "포항대학교"), - KOREA_GOLF_COLLEGE("kg.ac.kr", "한국골프대학"), - KOREA_TOURISM_COLLEGE("ktc.ac.kr", "한국관광대학교"), - KOREA_NONGSUSAN_UNIVERSITY("af.ac.kr", "한국농수산대학"), - KOREA_WELFARE_UNIVERSITY("hanrw.ac.kr", "한국복지대학교"), - KOREA_CYBER_WELFARE_UNIVERSITY("corea.ac.kr", "한국복지사이버대학"), - KOREA_ELEVATOR_UNIVERSITY("klc.ac.kr", "한국승강기대학교"), - KOREA_VIDEO_UNIVERSITY("pro.ac.kr", "한국영상대학교"), - KOREA_INFORMATION_AND_COMMUNICATION_UNIVERSITY("icpc.ac.kr", "한국정보통신기능대학"), - KOREA_RAILROAD_COLLEGE("krc.ac.kr", "한국철도대학"), - KOREA_POLYTECHNIC_1_SEOUL_GANGSEO_CAMPUS("kopo.ac.kr", "한국폴리텍 I 대학 서울강서캠퍼스"), - KOREA_POLYTECHNIC_1_SEOUL_JEONGSU_CAMPUS("kopo.ac.kr", "한국폴리텍 I 대학 서울정수캠퍼스"), - KOREA_POLYTECHNIC_1_SEONGNAM_CAMPUS("kopo.ac.kr", "한국폴리텍 I 대학 성남캠퍼스"), - KOREA_POLYTECHNIC_2_NAMINCHEON_CAMPUS("kopo.ac.kr", "한국폴리텍 II 대학 남인천캠퍼스"), - KOREA_POLYTECHNIC_2_INCHEON_CAMPUS("kopo.ac.kr", "한국폴리텍 II 대학 인천캠퍼스"), - KOREA_POLYTECHNIC_3_GANGNEUNG_CAMPUS("kopo.ac.kr", "한국폴리텍 III 대학 강릉캠퍼스"), - KOREA_POLYTECHNIC_3_CHUNCHEON_CAMPUS("kopo.ac.kr", "한국폴리텍 III 대학 춘천캠퍼스"), - KOREA_POLYTECHNIC_4_DAEJEON_CAMPUS("kopo.ac.kr", "한국폴리텍 IV 대학 대전캠퍼스"), - KOREA_POLYTECHNIC_4_ASAN_CAMPUS("kopo.ac.kr", "한국폴리텍 IV 대학 아산캠퍼스"), - KOREA_POLYTECHNIC_4_CHEONGJU_CAMPUS("kopo.ac.kr", "한국폴리텍 IV 대학 청주캠퍼스"), - KOREA_POLYTECHNIC_4_HONGSEONG_CAMPUS("kopo.ac.kr", "한국폴리텍 IV 대학 홍성캠퍼스"), - KOREA_POLYTECHNIC_5_GOCHANG_CAMPUS("kopo.ac.kr", "한국폴리텍 V 대학 고창캠퍼스"), - KOREA_POLYTECHNIC_5_KIMJE_CAMPUS("kopo.ac.kr", "한국폴리텍 V 대학 김제캠퍼스"), - KOREA_POLYTECHNIC_5_MOKPO_CAMPUS("kopo.ac.kr", "한국폴리텍 V 대학 목포캠퍼스"), - KOREA_POLYTECHNIC_5_IKSAN_CAMPUS("kopo.ac.kr", "한국폴리텍 V 대학 익산캠퍼스"), - KOREA_POLYTECHNIC_6_DAEGU_CAMPUS("kopo.ac.kr", "한국폴리텍 VI 대학 대구캠퍼스"), - KOREA_POLYTECHNIC_7_BUSAN_CAMPUS("kopo.ac.kr", "한국폴리텍 VII 대학 부산캠퍼스"), - KOREA_POLYTECHNIC_7_ULSAN_CAMPUS("kopo.ac.kr", "한국폴리텍 VII 대학 울산캠퍼스"), - KOREA_POLYTECHNIC_7_CHANGWON_CAMPUS("kopo.ac.kr", "한국폴리텍 VII 대학 창원캠퍼스"), - KOREA_POLYTECHNIC_6_GUMI_CAMPUS("kopo.ac.kr", "한국폴리텍VI대학 구미캠퍼스"), - KOREA_POLYTECHNIC_5_GWANGJU_CAMPUS("kopo.ac.kr", "한국폴리텍V대학 광주캠퍼스"), - KOREA_POLYTECHNIC_BIO_CAMPUS("kopo.ac.kr", "한국폴리텍대학 바이오캠퍼스"), - KOREA_POLYTECHNIC_FASHION_CAMPUS("kopo.ac.kr", "한국폴리텍대학 섬유패션캠퍼스"), - KOREA_POLYTECHNIC_ANSEONG_WOMENS_CAMPUS("kopo.ac.kr", "한국폴리텍대학 안성여자캠퍼스"), - KOREA_POLYTECHNIC_AVIATION_CAMPUS("kopo.ac.kr", "한국폴리텍대학 항공캠퍼스"), - HALLIM_SUNGSHIM_COLLEGE("hsc.ac.kr", "한림성심대학교"), - HANYANG_WOMENS_UNIVERSITY("hywoman.ac.kr", "한양여자대학교"), - HANYOUNG_COLLEGE("hanyeong.ac.kr", "한영대학"), - HYEJEON_COLLEGE("hj.ac.kr", "혜전대학"), - HYECHON_COLLEGE("hu.ac.kr", "혜천대학교"), - KAYA_UNIVERSITY("kaya.ac.kr", "가야대학교"), - CATHOLIC_KWANDONG_UNIVERSITY("cku.ac.kr", "가톨릭관동대학교"), - KWANGSHIN_UNIVERSITY("kwangshin.ac.kr", "광신대학교"), - KWANGWOON_UNIVERSITY("kw.ac.kr", "광운대학교"), - GWANGJU_CATHOLIC_UNIVERSITY("kjcatholic.ac.kr", "광주가톨릭대학교"), - GIST("gist.ac.kr", "광주과학기술원"), - GWANGJU_NATIONAL_UNIVERSITY_OF_EDUCATION("gnue.ac.kr", "광주교육대학교"), - GWANGJU_UNIVERSITY("gwangju.ac.kr", "광주대학교"), - GWANGJU_WOMENS_UNIVERSITY("kwu.ac.kr", "광주여자대학교"), - HONGIK_UNIVERSITY("g.hongik.ac.kr", "홍익대학교"), - JOONANG_UNIVERSITY("cau.ac.kr", "중앙대학교"), - CHUNGBUK_UNIVERSITY("chungbuk.ac.kr", "중앙대학교"), - SEONGSHIN_WOMENS_UNIVERSITY("sungshin.ac.kr", "성신여자대학교"); + GACHON_UNIVERSITY("gachon.ac.kr", "가천대학교"), + CATHOLIC_SANGJI_COLLEGE("csj.ac.kr", "가톨릭상지대학교"), + GANGDONG_COLLEGE("gangdong.ac.kr", "강동대학교"), + GANGNEUNG_YEONGDONG_COLLEGE("gyc.ac.kr", "강릉영동대학교"), + KANGWON_TOURISM_COLLEGE("kt.ac.kr", "강원관광대학"), + KANGWON_DO_COLLEGE("gw.ac.kr", "강원도립대학"), + KOJE_COLLEGE("koje.ac.kr", "거제대학교"), + KYUNGGI_COLLEGE_OF_SCIENCE_AND_TECHNOLOGY("gtec.ac.kr", "경기과학기술대학교"), + GYEONGNAM_PROVINCIAL_GEOCHEON_COLLEGE("gc.ac.kr", "경남도립거창대학"), + GYEONGNAM_PROVINCIAL_NAMHAE_COLLEGE("namhae.ac.kr", "경남도립남해대학"), + GYEONGNAM_INFORMATION_UNIVERSITY("kit.ac.kr", "경남정보대학교"), + KYUNGMIN_UNIVERSITY("kyungmin.ac.kr", "경민대학교"), + KYUNGBOK_UNIVERSITY("kbu.ac.kr", "경복대학교"), + GYEONGBUK_COLLEGE_OF_SCIENCE("kbsc.ac.kr", "경북과학대학교"), + GYEONGBUK_PROVINCIAL_UNIVERSITY("gpc.ac.kr", "경북도립대학교"), + GYEONGBUK_COLLEGE("kbc.ac.kr", "경북전문대학교"), + GYEONGSAN_1_COLLEGE("gs.ac.kr", "경산1대학교"), + KYUNGWON_COLLEGE("kwc.ac.kr", "경원전문대학"), + KYUNG_IN_WOMENS_UNIVERSITY("kic.ac.kr", "경인여자대학교"), + KEIMYUNG_COLLEGE_UNIVERSITY("kmcu.ac.kr", "계명문화대학교"), + KAYWON_COLLEGE_OF_ARTS("kaywon.ac.kr", "계원예술대학교"), + GOGURYEO_UNIVERSITY("kgrc.ac.kr", "고구려대학교"), + KOREA_UNIVERSITY("korea.ac.kr", "고려대학교"), + SKKU("skku.edu", "성균관대학교"), + KWANGYANG_HEALTH_COLLEGE("kwangyang.ac.kr", "광양보건대학교"), + GWANGJU_HEALTH_COLLEGE("ghu.ac.kr", "광주보건대학교"), + GUMI_COLLEGE("gumi.ac.kr", "구미대학교"), + SAOTC("saotc.ac.kr", "구세군사관학교"), + KOOKJE_UNIVERSITY("kookje.ac.kr", "국제대학교"), + KUNSAN_NURSING_COLLEGE("kcn.ac.kr", "군산간호대학교"), + KUNJANG_COLLEGE("kunjang.ac.kr", "군장대학교"), + CHRISTIAN_COLLEGE_OF_NURSING("ccn.ac.kr", "기독간호대학교"), + KIMCHEON_COLLEGE("kcs.ac.kr", "김천과학대학"), + GIMCHEON_COLLEGE("gimcheon.ac.kr", "김천대학"), + KIMPO_COLLEGE("kimpo.ac.kr", "김포대학교"), + GIMHAE_COLLEGE("gimhae.ac.kr", "김해대학교"), + NH_COLLEGE("nonghyup.ac.kr", "농협대학교"), + DAEKYUNG_COLLEGE("tk.ac.kr", "대경대학교"), + DAEGU_TECHNICAL_COLLEGE("ttc.ac.kr", "대구공업대학교"), + DAEGU_SCIENCE_COLLEGE("tsu.ac.kr", "대구과학대학교"), + DAEGU_FUTURE_COLLEGE("dfc.ac.kr", "대구미래대학교"), + DAEGU_HEALTH_COLLEGE("dhc.ac.kr", "대구보건대학교"), + DAEDEOK_COLLEGE("ddu.ac.kr", "대덕대학교"), + DAEDONG_COLLEGE("daedong.ac.kr", "대동대학교"), + DAELIM_UNIVERSITY("daelim.ac.kr", "대림대학교"), + DAEWON_UNIVERSITY("daewon.ac.kr", "대원대학교"), + DAEJEON_HEALTH_COLLEGE("hit.ac.kr", "대전보건대학교"), + DONGKANG_COLLEGE("dkc.ac.kr", "동강대학교"), + DONGNAM_HEALTH_UNIVERSITY("dongnam.ac.kr", "동남보건대학교"), + DONGMYUNG_COLLEGE("tu.ac.kr", "동명대학"), + DONGPUSAN_COLLEGE("dpc.ac.kr", "동부산대학교"), + DONGSEOUL_UNIVERSITY("dsc.ac.kr", "동서울대학교"), + DONGAH_MEDIA_AND_ARTS_COLLEGE("dima.ac.kr", "동아방송예술대학교"), + DONGAIN_UNIVERSITY("dongac.ac.kr", "동아인재대학교"), + DONGYANG_MIRAE_UNIVERSITY("dongyang.ac.kr", "동양미래대학교"), + DONGWOO_COLLEGE("duc.ac.kr", "동우대학"), + DONGWON_COLLEGE_OF_SCIENCE_AND_TECHNOLOGY("dist.ac.kr", "동원과학기술대학교"), + DONGWON_UNIVERSITY("tw.ac.kr", "동원대학교"), + DONGUI_COLLEGE("dit.ac.kr", "동의과학대학교"), + DONGJU_COLLEGE("dongju.ac.kr", "동주대학교"), + DOOWON_TECHNICAL_COLLEGE("doowon.ac.kr", "두원공과대학교"), + MASAN_UNIVERSITY("masan.ac.kr", "마산대학교"), + MYONGJI_COLLEGE("mjc.ac.kr", "명지전문대학"), + MOKPO_SCIENCE_COLLEGE("mokpo-c.ac.kr", "목포과학대학교"), + MOONKYUNG_COLLEGE("mkc.ac.kr", "문경대학교"), + BAEHWA_WOMENS_UNIVERSITY("baewha.ac.kr", "배화여자대학교"), + BAEKSEOK_CULTURAL_UNIVERSITY("bscu.ac.kr", "백석문화대학교"), + PAEKCHE_INSTITUTE_OF_THE_ARTS("paekche.ac.kr", "백제예술대학교"), + BYEOKSEONG_COLLEGE("bs.ac.kr", "벽성대학"), + BUSAN_KYUNGSANG_UNIVERSITY("bsks.ac.kr", "부산경상대학교"), + BUSAN_COLLEGE_OF_SCIENCE_AND_TECHNOLOGY("bist.ac.kr", "부산과학기술대학교"), + BUSAN_WOMENS_COLLEGE("bwc.ac.kr", "부산여자대학교"), + BUSAN_UNIVERSITY_OF_ARTS("busanarts.ac.kr", "부산예술대학교"), + BUCHEON_UNIVERSITY("bc.ac.kr", "부천대학교"), + SAMYOOK_HEALTH_UNIVERSITY("shu.ac.kr", "삼육보건대학"), + SAMYOOK_UNIVERSITY("syu.ac.kr", "삼육의명대학"), + SANGJI_YEONGSEO_COLLEGE("sy.ac.kr", "상지영서대학교"), + SEOUL_NATIONAL_UNIVERSITY("snu.ac.kr", "서울대학교"), + SEORABOL_COLLEGE("sorabol.ac.kr", "서라벌대학교"), + SEOYEONG_UNIVERSITY("seoyeong.ac.kr", "서영대학교"), + SEOUL_HEALTH_COLLEGE("shjc.ac.kr", "서울보건대학"), + SEOUL_WOMENS_COLLEGE_OF_NURSING("snjc.ac.kr", "서울여자간호대학교"), + SEOUL_INSTITUTE_OF_THE_ARTS("seoularts.ac.kr", "서울예술대학교"), + SEOIL_UNIVERSITY("seoil.ac.kr", "서일대학교"), + SEOJEONG_COLLEGE("seojeong.ac.kr", "서정대학교"), + SOHAE_COLLEGE("sohae.ac.kr", "서해대학"), + SUNLIN_COLLEGE("sunlin.ac.kr", "선린대학교"), + SUNGDUK_COLLEGE("sdc.ac.kr", "성덕대학교"), + SUNGSIM_FOREIGN_LANGUAGE_UNIVERSITY("sungsim.ac.kr", "성심외국어대학"), + SAEKYUNG_COLLEGE("saekyung.ac.kr", "세경대학교"), + SONGGOK_COLLEGE("songgok.ac.kr", "송곡대학교"), + SONGWON_COLLEGE("songwon.ac.kr", "송원대학"), + SONGHO_COLLEGE("songho.ac.kr", "송호대학교"), + SUSEONG_COLLEGE("sc.ac.kr", "수성대학교"), + SUWON_SCIENCE_COLLEGE("ssc.ac.kr", "수원과학대학교"), + SUWON_WOMENS_COLLEGE("swc.ac.kr", "수원여자대학교"), + SUNCHEON_FIRST_COLLEGE("suncheon.ac.kr", "순천제일대학"), + SUNG_UI_WOMENS_UNIVERSITY("sewc.ac.kr", "숭의여자대학교"), + SHINGU_COLLEGE("shingu.ac.kr", "신구대학교"), + SHINSUNG_UNIVERSITY("shinsung.ac.kr", "신성대학교"), + SHINANSAN_UNIVERSITY("sau.ac.kr", "신안산대학교"), + SHINHUNG_COLLEGE("shc.ac.kr", "신흥대학교"), + AJOU_MOTOR_COLLEGE("motor.ac.kr", "아주자동차대학"), + ANDONG_SCIENCE_COLLEGE("asc.ac.kr", "안동과학대학교"), + ANSAN_COLLEGE("ansan.ac.kr", "안산대학교"), + YEOJU_INSTITUTE_OF_TECHNOLOGY("yit.ac.kr", "여주대학교"), + YEONSUNG_UNIVERSITY("yeonsung.ac.kr", "연성대학교"), + YEONSEI_UNIVERSITY("yonsei.ac.kr", "연세대학교"), + YOUNAM_ENGINEERING_COLLEGE("yc.ac.kr", "연암공과대학교"), + YEONGNAM_FOREIGN_LANGUAGE_COLLEGE("yflc.ac.kr", "영남외국어대학"), + YEONGNAM_ENGINEERING_COLLEGE("ync.ac.kr", "영남이공대학교"), + YUDEOK_CYBER_UNIVERSITY("ycc.ac.kr", "영진사이버대학"), + YEONGJIN_COLLEGE("yjc.ac.kr", "영진전문대학"), + OSAN_UNIVERSITY("osan.ac.kr", "오산대학교"), + YONGINSUNGDAM_UNIVERSITY("ysc.ac.kr", "용인송담대학교"), + WOOSONG_COLLEGE("wst.ac.kr", "우송공업대학"), + WOOSONG_INFORMATION_COLLEGE("wsi.ac.kr", "우송정보대학"), + ULSAN_COLLEGE_OF_SCIENCE_AND_TECHNOLOGY("uc.ac.kr", "울산과학대학교"), + UNJISEMU_COLLEGE("wat.ac.kr", "웅지세무대학"), + WONKWANG_HEALTH_COLLEGE("wkhc.ac.kr", "원광보건대학교"), + WONJU_COLLEGE("wonju.ac.kr", "원주대학"), + YUHAN_UNIVERSITY("yuhan.ac.kr", "유한대학교"), + INDUK_UNIVERSITY("induk.ac.kr", "인덕대학교"), + INCHEON_JAEUNGEUNIVERSITY("jeiu.ac.kr", "인천재능대학교"), + INCHEON_TECHNICAL_COLLEGE("icc.ac.kr", "인천전문대학"), + INHA_TECHNICAL_COLLEGE("itc.ac.kr", "인하공업전문대학"), + JANGAN_UNIVERSITY("jangan.ac.kr", "장안대학교"), + REDCROSS_NURSING_COLLEGE("cau.ac.kr", "적십자간호대학"), + JEONNAM_SCIENCE_COLLEGE("chunnam-c.ac.kr", "전남과학대학교"), + JEONNAM_PROVINCIAL_COLLEGE("dorip.ac.kr", "전남도립대학교"), + JEONBUK_COLLEGE_OF_SCIENCE("jbsc.ac.kr", "전북과학대학교"), + JEONJU_GIZON_COLLEGE("jk.ac.kr", "전주기전대학"), + JEONJU_VISION_COLLEGE("jvision.ac.kr", "전주비전대학교"), + JEJU_COLLEGE_OF_TOURISM("ctc.ac.kr", "제주관광대학교"), + JEJU_COLLEGE_OF_INDUSTRIAL_INFORMATION("jeju.ac.kr", "제주산업정보대학"), + JEJU_HANLA_UNIVERSITY("chu.ac.kr", "제주한라대학교"), + CHOSUN_NURSING_COLLEGE("cnc.ac.kr", "조선간호대학교"), + CHOSUN_ENGINEERING_COLLEGE("cst.ac.kr", "조선이공대학교"), + JINJU_HEALTH_COLLEGE("jhc.ac.kr", "진주보건대학교"), + CHANGSHIN_UNIVERSITY("csc.ac.kr", "창신대학"), + CHANGWON_MOONSEONG_UNIVERSITY("cmu.ac.kr", "창원문성대학"), + CHEONAN_YEONAM_COLLEGE("yonam.ac.kr", "천안연암대학"), + CHUNGKANG_COLLEGE_OF_CULTURAL_INDUSTRIES("chungkang.academy", "청강문화산업대학교"), + CHEONGNAM_COLLEGE("scjc.ac.kr", "청암대학교"), + CHUNHAE_HEALTH_UNIVERSITY("ch.ac.kr", "춘해보건대학교"), + CHUNGCHEONGNAM_PROVINCIAL_CHEONGLYANG_UNIVERSITY("cyc.ac.kr", "충남도립청양대학"), + CHUNGBUK_PROVINCIAL_UNIVERSITY("cpu.ac.kr", "충북도립대학"), + CHUNGBUK_HEALTH_AND_SCIENCE_UNIVERSITY("chsu.ac.kr", "충북보건과학대학교"), + CHUNGCHUNG_COLLEGE("ok.ac.kr", "충청대학교"), + POHANG_UNIVERSITY("pohang.ac.kr", "포항대학교"), + KOREA_GOLF_COLLEGE("kg.ac.kr", "한국골프대학"), + KOREA_TOURISM_COLLEGE("ktc.ac.kr", "한국관광대학교"), + KOREA_NONGSUSAN_UNIVERSITY("af.ac.kr", "한국농수산대학"), + KOREA_WELFARE_UNIVERSITY("hanrw.ac.kr", "한국복지대학교"), + KOREA_CYBER_WELFARE_UNIVERSITY("corea.ac.kr", "한국복지사이버대학"), + KOREA_ELEVATOR_UNIVERSITY("klc.ac.kr", "한국승강기대학교"), + KOREA_VIDEO_UNIVERSITY("pro.ac.kr", "한국영상대학교"), + KOREA_INFORMATION_AND_COMMUNICATION_UNIVERSITY("icpc.ac.kr", "한국정보통신기능대학"), + KOREA_RAILROAD_COLLEGE("krc.ac.kr", "한국철도대학"), + KOREA_POLYTECHNIC_1_SEOUL_GANGSEO_CAMPUS("kopo.ac.kr", "한국폴리텍 I 대학 서울강서캠퍼스"), + KOREA_POLYTECHNIC_1_SEOUL_JEONGSU_CAMPUS("kopo.ac.kr", "한국폴리텍 I 대학 서울정수캠퍼스"), + KOREA_POLYTECHNIC_1_SEONGNAM_CAMPUS("kopo.ac.kr", "한국폴리텍 I 대학 성남캠퍼스"), + KOREA_POLYTECHNIC_2_NAMINCHEON_CAMPUS("kopo.ac.kr", "한국폴리텍 II 대학 남인천캠퍼스"), + KOREA_POLYTECHNIC_2_INCHEON_CAMPUS("kopo.ac.kr", "한국폴리텍 II 대학 인천캠퍼스"), + KOREA_POLYTECHNIC_3_GANGNEUNG_CAMPUS("kopo.ac.kr", "한국폴리텍 III 대학 강릉캠퍼스"), + KOREA_POLYTECHNIC_3_CHUNCHEON_CAMPUS("kopo.ac.kr", "한국폴리텍 III 대학 춘천캠퍼스"), + KOREA_POLYTECHNIC_4_DAEJEON_CAMPUS("kopo.ac.kr", "한국폴리텍 IV 대학 대전캠퍼스"), + KOREA_POLYTECHNIC_4_ASAN_CAMPUS("kopo.ac.kr", "한국폴리텍 IV 대학 아산캠퍼스"), + KOREA_POLYTECHNIC_4_CHEONGJU_CAMPUS("kopo.ac.kr", "한국폴리텍 IV 대학 청주캠퍼스"), + KOREA_POLYTECHNIC_4_HONGSEONG_CAMPUS("kopo.ac.kr", "한국폴리텍 IV 대학 홍성캠퍼스"), + KOREA_POLYTECHNIC_5_GOCHANG_CAMPUS("kopo.ac.kr", "한국폴리텍 V 대학 고창캠퍼스"), + KOREA_POLYTECHNIC_5_KIMJE_CAMPUS("kopo.ac.kr", "한국폴리텍 V 대학 김제캠퍼스"), + KOREA_POLYTECHNIC_5_MOKPO_CAMPUS("kopo.ac.kr", "한국폴리텍 V 대학 목포캠퍼스"), + KOREA_POLYTECHNIC_5_IKSAN_CAMPUS("kopo.ac.kr", "한국폴리텍 V 대학 익산캠퍼스"), + KOREA_POLYTECHNIC_6_DAEGU_CAMPUS("kopo.ac.kr", "한국폴리텍 VI 대학 대구캠퍼스"), + KOREA_POLYTECHNIC_7_BUSAN_CAMPUS("kopo.ac.kr", "한국폴리텍 VII 대학 부산캠퍼스"), + KOREA_POLYTECHNIC_7_ULSAN_CAMPUS("kopo.ac.kr", "한국폴리텍 VII 대학 울산캠퍼스"), + KOREA_POLYTECHNIC_7_CHANGWON_CAMPUS("kopo.ac.kr", "한국폴리텍 VII 대학 창원캠퍼스"), + KOREA_POLYTECHNIC_6_GUMI_CAMPUS("kopo.ac.kr", "한국폴리텍VI대학 구미캠퍼스"), + KOREA_POLYTECHNIC_5_GWANGJU_CAMPUS("kopo.ac.kr", "한국폴리텍V대학 광주캠퍼스"), + KOREA_POLYTECHNIC_BIO_CAMPUS("kopo.ac.kr", "한국폴리텍대학 바이오캠퍼스"), + KOREA_POLYTECHNIC_FASHION_CAMPUS("kopo.ac.kr", "한국폴리텍대학 섬유패션캠퍼스"), + KOREA_POLYTECHNIC_ANSEONG_WOMENS_CAMPUS("kopo.ac.kr", "한국폴리텍대학 안성여자캠퍼스"), + KOREA_POLYTECHNIC_AVIATION_CAMPUS("kopo.ac.kr", "한국폴리텍대학 항공캠퍼스"), + HALLIM_SUNGSHIM_COLLEGE("hsc.ac.kr", "한림성심대학교"), + HANYANG_WOMENS_UNIVERSITY("hywoman.ac.kr", "한양여자대학교"), + HANYOUNG_COLLEGE("hanyeong.ac.kr", "한영대학"), + HYEJEON_COLLEGE("hj.ac.kr", "혜전대학"), + HYECHON_COLLEGE("hu.ac.kr", "혜천대학교"), + KAYA_UNIVERSITY("kaya.ac.kr", "가야대학교"), + CATHOLIC_KWANDONG_UNIVERSITY("cku.ac.kr", "가톨릭관동대학교"), + KWANGSHIN_UNIVERSITY("kwangshin.ac.kr", "광신대학교"), + KWANGWOON_UNIVERSITY("kw.ac.kr", "광운대학교"), + GWANGJU_CATHOLIC_UNIVERSITY("kjcatholic.ac.kr", "광주가톨릭대학교"), + GIST("gist.ac.kr", "광주과학기술원"), + GWANGJU_NATIONAL_UNIVERSITY_OF_EDUCATION("gnue.ac.kr", "광주교육대학교"), + GWANGJU_UNIVERSITY("gwangju.ac.kr", "광주대학교"), + GWANGJU_WOMENS_UNIVERSITY("kwu.ac.kr", "광주여자대학교"), + HONGIK_UNIVERSITY("g.hongik.ac.kr", "홍익대학교"), + JOONANG_UNIVERSITY("cau.ac.kr", "중앙대학교"), + CHUNGBUK_UNIVERSITY("chungbuk.ac.kr", "중앙대학교"), + SEONGSHIN_WOMENS_UNIVERSITY("sungshin.ac.kr", "성신여자대학교"); - private final String domain; - private final String universityName; + private final String domain; + private final String universityName; - SchoolDomain(String domain, String universityName) { - this.domain = domain; - this.universityName = universityName; - } + SchoolDomain(String domain, String universityName) { + this.domain = domain; + this.universityName = universityName; + } - public String getDomain() { - return domain; - } + public String getDomain() { + return domain; + } - public String getUniversityName() { - return universityName; - } + public String getUniversityName() { + return universityName; + } - public static String getUniversityByDomain(String domain) { - for (SchoolDomain school : values()) { - if (school.getDomain().equals(domain)) { - return school.getUniversityName(); - } - } - return null; // 도메인이 없을 경우 null 반환 - } + public static String getUniversityByDomain(String domain) { + for (SchoolDomain school : values()) { + if (school.getDomain().equals(domain)) { + return school.getUniversityName(); + } + } + return null; // 도메인이 없을 경우 null 반환 + } } diff --git a/src/main/java/com/cotato/squadus/domain/auth/repository/MemberRepository.java b/src/main/java/com/cotato/squadus/domain/auth/repository/MemberRepository.java index ab47801..3046cc9 100644 --- a/src/main/java/com/cotato/squadus/domain/auth/repository/MemberRepository.java +++ b/src/main/java/com/cotato/squadus/domain/auth/repository/MemberRepository.java @@ -1,17 +1,19 @@ package com.cotato.squadus.domain.auth.repository; -import com.cotato.squadus.domain.auth.entity.Member; -import org.springframework.data.jpa.repository.JpaRepository; import java.util.Optional; +import org.springframework.data.jpa.repository.JpaRepository; + +import com.cotato.squadus.domain.auth.entity.Member; + public interface MemberRepository extends JpaRepository { - Boolean existsByUsername(String username); + Boolean existsByUsername(String username); - Optional findByUsername(String username); + Optional findByUsername(String username); - Optional findByUniqueId(String uniqueId); + Optional findByUniqueId(String uniqueId); - Optional findByEmail(String email); + Optional findByEmail(String email); } diff --git a/src/main/java/com/cotato/squadus/domain/auth/service/ClubMemberService.java b/src/main/java/com/cotato/squadus/domain/auth/service/ClubMemberService.java index 108a3a7..d8fc32b 100644 --- a/src/main/java/com/cotato/squadus/domain/auth/service/ClubMemberService.java +++ b/src/main/java/com/cotato/squadus/domain/auth/service/ClubMemberService.java @@ -1,5 +1,11 @@ package com.cotato.squadus.domain.auth.service; +import java.util.List; + +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + import com.cotato.squadus.api.club.dto.ClubMemberInfoResponse; import com.cotato.squadus.api.club.dto.ClubMemberInfoResponseList; import com.cotato.squadus.common.config.auth.CustomOAuth2Member; @@ -8,14 +14,10 @@ import com.cotato.squadus.domain.auth.entity.Member; import com.cotato.squadus.domain.club.common.entity.ClubMember; import com.cotato.squadus.domain.club.common.repository.ClubMemberRepository; + import jakarta.persistence.EntityNotFoundException; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.springframework.security.core.context.SecurityContextHolder; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -import java.util.List; @Slf4j @Service @@ -23,48 +25,49 @@ @RequiredArgsConstructor public class ClubMemberService { - private final ClubMemberRepository clubMemberRepository; - private final MemberService memberService; - - - @Transactional - public ClubMember saveClubMember(ClubMember clubMember) { - ClubMember savedClubMember = clubMemberRepository.save(clubMember); - return savedClubMember; - } + private final ClubMemberRepository clubMemberRepository; + private final MemberService memberService; - public ClubMember findClubMemberById(Long id) { - ClubMember clubMember = clubMemberRepository.findById(id) - .orElseThrow(() -> new EntityNotFoundException("해당 고유번호를 가진 회원을 찾을 수 없습니다.")); - return clubMember; - } + @Transactional + public ClubMember saveClubMember(ClubMember clubMember) { + ClubMember savedClubMember = clubMemberRepository.save(clubMember); + return savedClubMember; + } + public ClubMember findClubMemberById(Long id) { + ClubMember clubMember = clubMemberRepository.findById(id) + .orElseThrow(() -> new EntityNotFoundException("해당 고유번호를 가진 회원을 찾을 수 없습니다.")); + return clubMember; + } - // 임시 세션 정보를 통해 회원이 속한 동아리인지 검증 - public void validateClubMember(Long clubId) { - ClubMember clubMember = findClubMemberBySecurityContextHolder(clubId); - log.info("현재 로그인 된 회원의 clubId: {} ", clubMember.getClub().getClubId()); - if(!clubMember.getClub().getClubId().equals(clubId)) { - throw new AppException(ErrorCode.CLUB_ACCESS_DENIED); - } - } + // 임시 세션 정보를 통해 회원이 속한 동아리인지 검증 + public void validateClubMember(Long clubId) { + ClubMember clubMember = findClubMemberBySecurityContextHolder(clubId); + log.info("현재 로그인 된 회원의 clubId: {} ", clubMember.getClub().getClubId()); + if (!clubMember.getClub().getClubId().equals(clubId)) { + throw new AppException(ErrorCode.CLUB_ACCESS_DENIED); + } + } - public ClubMember findClubMemberBySecurityContextHolder(Long clubId) { - CustomOAuth2Member oAuth2Member = (CustomOAuth2Member) SecurityContextHolder.getContext().getAuthentication().getPrincipal(); - Member member = memberService.findMemberByUniqueId(oAuth2Member.getUniqueId()); - ClubMember clubMember = clubMemberRepository.findClubMemberByMember_MemberIdxAndClub_ClubId(member.getMemberIdx(), clubId) - .orElseThrow(() -> new EntityNotFoundException("해당 회원 고유번호를 가진 동아리 회원을 찾을 수 없습니다.")); - return clubMember; - } + public ClubMember findClubMemberBySecurityContextHolder(Long clubId) { + CustomOAuth2Member oAuth2Member = (CustomOAuth2Member)SecurityContextHolder.getContext() + .getAuthentication() + .getPrincipal(); + Member member = memberService.findMemberByUniqueId(oAuth2Member.getUniqueId()); + ClubMember clubMember = clubMemberRepository.findClubMemberByMember_MemberIdxAndClub_ClubId( + member.getMemberIdx(), clubId) + .orElseThrow(() -> new EntityNotFoundException("해당 회원 고유번호를 가진 동아리 회원을 찾을 수 없습니다.")); + return clubMember; + } - public ClubMemberInfoResponseList findAllClubMemberInfo(Long clubId) { - List clubMemberInfoResponseList = clubMemberRepository.findAllByClub_ClubId(clubId) - .stream() - .map(ClubMemberInfoResponse::from) - .toList(); + public ClubMemberInfoResponseList findAllClubMemberInfo(Long clubId) { + List clubMemberInfoResponseList = clubMemberRepository.findAllByClub_ClubId(clubId) + .stream() + .map(ClubMemberInfoResponse::from) + .toList(); - return ClubMemberInfoResponseList.from(clubMemberInfoResponseList); + return ClubMemberInfoResponseList.from(clubMemberInfoResponseList); - } + } } diff --git a/src/main/java/com/cotato/squadus/domain/auth/service/EmailSendService.java b/src/main/java/com/cotato/squadus/domain/auth/service/EmailSendService.java index 5bd3712..7c73adf 100644 --- a/src/main/java/com/cotato/squadus/domain/auth/service/EmailSendService.java +++ b/src/main/java/com/cotato/squadus/domain/auth/service/EmailSendService.java @@ -1,13 +1,9 @@ package com.cotato.squadus.domain.auth.service; -import com.cotato.squadus.common.config.RedisConfig; -import com.cotato.squadus.common.config.auth.CustomOAuth2Member; -import com.cotato.squadus.domain.auth.entity.Member; -import com.cotato.squadus.domain.auth.enums.MemberRole; -import com.cotato.squadus.domain.auth.enums.SchoolDomain; -import jakarta.mail.MessagingException; -import jakarta.mail.internet.MimeMessage; -import lombok.extern.slf4j.Slf4j; +import java.util.Objects; +import java.util.Random; +import java.util.concurrent.TimeUnit; + import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.data.redis.core.ValueOperations; @@ -17,129 +13,140 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import java.util.Objects; -import java.util.Random; -import java.util.concurrent.TimeUnit; +import com.cotato.squadus.common.config.RedisConfig; +import com.cotato.squadus.common.config.auth.CustomOAuth2Member; +import com.cotato.squadus.domain.auth.entity.Member; +import com.cotato.squadus.domain.auth.enums.MemberRole; +import com.cotato.squadus.domain.auth.enums.SchoolDomain; + +import jakarta.mail.MessagingException; +import jakarta.mail.internet.MimeMessage; +import lombok.extern.slf4j.Slf4j; @Service @Slf4j public class EmailSendService { - @Autowired private JavaMailSender javaMailSender; - @Autowired private RedisConfig redisConfig; - private int authNumber; - - /* 이메일 인증에 필요한 정보 */ - @Value("${spring.mail.username}") - private String serviceName; - @Autowired - private MemberService memberService; - - /* 랜덤 인증번호 생성 */ - public void makeRandomNum() { - Random r = new Random(); - String randomNumber = ""; - for(int i = 0; i < 6; i++) { - randomNumber += Integer.toString(r.nextInt(10)); - } - - authNumber = Integer.parseInt(randomNumber); - } - - /* 이메일 전송 */ - public void mailSend(String setFrom, String toMail, String title, String content) { - MimeMessage message = javaMailSender.createMimeMessage(); - try { - MimeMessageHelper helper = new MimeMessageHelper(message,true,"utf-8"); - helper.setFrom(setFrom); // service name - helper.setTo(toMail); // customer email - helper.setSubject(title); // email title - helper.setText(content,true); // content, html: true - javaMailSender.send(message); - } catch (MessagingException e) { - e.printStackTrace(); // 에러 출력 - } - // redis에 3분 동안 이메일과 인증 코드 저장 - ValueOperations valOperations = redisConfig.redisTemplate().opsForValue(); - valOperations.set(toMail, Integer.toString(authNumber), 180, TimeUnit.SECONDS); - } - - /* 이메일 작성 */ - public String joinEmail(String email) { - makeRandomNum(); - String customerMail = email; - String title = "학교 인증을 위한 이메일입니다"; - String content = - "안녕하세요! \uD83D\uDC4B" + - "

" + - "이메일 인증을 완료하기 위해 아래 절차를 진행해 주세요:" + - "

" + - "1. 인증 번호 입력 \uD83D\uDCDD" + - "
" + - "인증 번호 : " + "" + authNumber + "" + - "

" + - "2. 학교 인증 칸에 해당 번호를 입력해 주세요. \uD83D\uDD11" + - "

" + - "인증 절차가 완료되면, 추가적인 안내를 드리겠습니다." + - "

" + - "감사합니다! \uD83D\uDE0A"; -// "이메일을 인증하기 위한 절차입니다." + -// "

" + -// "인증 번호는 " + authNumber + "입니다." + -// "
" + -// "학교 인증 칸에 해당 번호를 입력해주세요."; - mailSend(serviceName, customerMail, title, content); - return Integer.toString(authNumber); - } - - @Transactional - /* 인증번호 확인 및 이메일 도메인 검증 */ - public Boolean checkAuthNum(String email, String authNum, @AuthenticationPrincipal CustomOAuth2Member customOauth2Member) { - // 이메일 도메인이 유효한지 확인 - if (!isValidSchoolEmail(email)) { - throw new IllegalArgumentException("유효하지 않은 학교 이메일 도메인입니다."); - } - - // Redis에서 인증번호 확인 - ValueOperations valOperations = redisConfig.redisTemplate().opsForValue(); - String code = valOperations.get(email); - - boolean isAuthSuccessful = Objects.equals(code, authNum); - - if (isAuthSuccessful) { - String domain = email.substring(email.indexOf("@") + 1); - String universityName = SchoolDomain.getUniversityByDomain(domain); - - // 회원의 university 필드를 업데이트 - Member memberByUniqueId = memberService.findMemberByUniqueId(customOauth2Member.getUniqueId()); - memberByUniqueId.updateUniversity(universityName); - memberByUniqueId.updateMemberRole(MemberRole.CERTIFIED_MEMBER); - memberService.saveMember(memberByUniqueId); - log.info("사용자 {}의 university 필드가 {}로 업데이트 되었습니다.", memberByUniqueId.getUsername(), universityName); - log.info("사용자 {}의 memberRole 필드가 {}로 업데이트 되었습니다.", memberByUniqueId.getUsername(), MemberRole.CERTIFIED_MEMBER); - } - - return isAuthSuccessful; - } - private boolean isValidSchoolEmail(String email) { - if (email == null || !email.contains("@")) { - return false; - } - - // 이메일 주소에서 도메인 부분 추출 - String domain = email.substring(email.indexOf("@") + 1); - - // 도메인에 해당하는 학교 이름이 있는지 확인 - for (SchoolDomain schoolDomain : SchoolDomain.values()) { - if (domain.endsWith(schoolDomain.getDomain())) { - log.info("이메일 인증 학교 : {}", schoolDomain.getUniversityName()); - return true; - } - } - - log.info("이메일 인증 실패: 도메인이 일치하지 않습니다."); - return false; - } + @Autowired + private JavaMailSender javaMailSender; + @Autowired + private RedisConfig redisConfig; + private int authNumber; + + /* 이메일 인증에 필요한 정보 */ + @Value("${spring.mail.username}") + private String serviceName; + @Autowired + private MemberService memberService; + + /* 랜덤 인증번호 생성 */ + public void makeRandomNum() { + Random r = new Random(); + String randomNumber = ""; + for (int i = 0; i < 6; i++) { + randomNumber += Integer.toString(r.nextInt(10)); + } + + authNumber = Integer.parseInt(randomNumber); + } + + /* 이메일 전송 */ + public void mailSend(String setFrom, String toMail, String title, String content) { + MimeMessage message = javaMailSender.createMimeMessage(); + try { + MimeMessageHelper helper = new MimeMessageHelper(message, true, "utf-8"); + helper.setFrom(setFrom); // service name + helper.setTo(toMail); // customer email + helper.setSubject(title); // email title + helper.setText(content, true); // content, html: true + javaMailSender.send(message); + } catch (MessagingException e) { + e.printStackTrace(); // 에러 출력 + } + // redis에 3분 동안 이메일과 인증 코드 저장 + ValueOperations valOperations = redisConfig.redisTemplate().opsForValue(); + valOperations.set(toMail, Integer.toString(authNumber), 180, TimeUnit.SECONDS); + } + + /* 이메일 작성 */ + public String joinEmail(String email) { + makeRandomNum(); + String customerMail = email; + String title = "학교 인증을 위한 이메일입니다"; + String content = + "안녕하세요! \uD83D\uDC4B" + + "

" + + "이메일 인증을 완료하기 위해 아래 절차를 진행해 주세요:" + + "

" + + "1. 인증 번호 입력 \uD83D\uDCDD" + + "
" + + "인증 번호 : " + "" + authNumber + "" + + "

" + + "2. 학교 인증 칸에 해당 번호를 입력해 주세요. \uD83D\uDD11" + + "

" + + "인증 절차가 완료되면, 추가적인 안내를 드리겠습니다." + + "

" + + "감사합니다! \uD83D\uDE0A"; + // "이메일을 인증하기 위한 절차입니다." + + // "

" + + // "인증 번호는 " + authNumber + "입니다." + + // "
" + + // "학교 인증 칸에 해당 번호를 입력해주세요."; + mailSend(serviceName, customerMail, title, content); + return Integer.toString(authNumber); + } + + @Transactional + /* 인증번호 확인 및 이메일 도메인 검증 */ + public Boolean checkAuthNum(String email, String authNum, + @AuthenticationPrincipal CustomOAuth2Member customOauth2Member) { + // 이메일 도메인이 유효한지 확인 + if (!isValidSchoolEmail(email)) { + throw new IllegalArgumentException("유효하지 않은 학교 이메일 도메인입니다."); + } + + // Redis에서 인증번호 확인 + ValueOperations valOperations = redisConfig.redisTemplate().opsForValue(); + String code = valOperations.get(email); + + boolean isAuthSuccessful = Objects.equals(code, authNum); + + if (isAuthSuccessful) { + String domain = email.substring(email.indexOf("@") + 1); + String universityName = SchoolDomain.getUniversityByDomain(domain); + + // 회원의 university 필드를 업데이트 + Member memberByUniqueId = memberService.findMemberByUniqueId(customOauth2Member.getUniqueId()); + memberByUniqueId.updateUniversity(universityName); + memberByUniqueId.updateMemberRole(MemberRole.CERTIFIED_MEMBER); + memberService.saveMember(memberByUniqueId); + log.info("사용자 {}의 university 필드가 {}로 업데이트 되었습니다.", memberByUniqueId.getUsername(), universityName); + log.info("사용자 {}의 memberRole 필드가 {}로 업데이트 되었습니다.", memberByUniqueId.getUsername(), + MemberRole.CERTIFIED_MEMBER); + } + + return isAuthSuccessful; + } + + private boolean isValidSchoolEmail(String email) { + if (email == null || !email.contains("@")) { + return false; + } + + // 이메일 주소에서 도메인 부분 추출 + String domain = email.substring(email.indexOf("@") + 1); + + // 도메인에 해당하는 학교 이름이 있는지 확인 + for (SchoolDomain schoolDomain : SchoolDomain.values()) { + if (domain.endsWith(schoolDomain.getDomain())) { + log.info("이메일 인증 학교 : {}", schoolDomain.getUniversityName()); + return true; + } + } + + log.info("이메일 인증 실패: 도메인이 일치하지 않습니다."); + return false; + } } diff --git a/src/main/java/com/cotato/squadus/domain/auth/service/MemberService.java b/src/main/java/com/cotato/squadus/domain/auth/service/MemberService.java index 10b8e20..e01318b 100644 --- a/src/main/java/com/cotato/squadus/domain/auth/service/MemberService.java +++ b/src/main/java/com/cotato/squadus/domain/auth/service/MemberService.java @@ -1,6 +1,16 @@ package com.cotato.squadus.domain.auth.service; -import com.cotato.squadus.api.member.dto.*; +import java.util.List; + +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.multipart.MultipartFile; + +import com.cotato.squadus.api.member.dto.MemberClubApplicationInfoResponse; +import com.cotato.squadus.api.member.dto.MemberClubApplicationListResponse; +import com.cotato.squadus.api.member.dto.MemberClubListResponse; +import com.cotato.squadus.api.member.dto.MemberClubResponse; +import com.cotato.squadus.api.member.dto.MemberInfoResponse; import com.cotato.squadus.common.config.auth.CustomOAuth2Member; import com.cotato.squadus.common.config.jwt.JWTUtil; import com.cotato.squadus.common.s3.S3ImageService; @@ -9,14 +19,10 @@ import com.cotato.squadus.domain.club.common.entity.ClubApplication; import com.cotato.squadus.domain.club.common.entity.ClubMember; import com.cotato.squadus.domain.club.common.repository.ClubApplicationRepository; + import jakarta.persistence.EntityNotFoundException; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; -import org.springframework.web.multipart.MultipartFile; - -import java.util.List; @Slf4j @Service @@ -24,69 +30,71 @@ @RequiredArgsConstructor public class MemberService { - private final MemberRepository memberRepository; - private final JWTUtil jwtUtil; - private final S3ImageService s3ImageService; - private final ClubApplicationRepository clubApplicationRepository; - - @Transactional - public Long saveMember(Member member) { - Member save = memberRepository.save(member); - return save.getMemberIdx(); - } - - public MemberInfoResponse findMemberInfo(CustomOAuth2Member customOAuth2Member) { - Member findMember = memberRepository.findByUniqueId(customOAuth2Member.getUniqueId()) - .orElseThrow(() -> new EntityNotFoundException("해당 고유번호를 가진 회원을 찾을 수 없습니다.")); - return MemberInfoResponse.from(findMember); - } - - public Member findMemberByUniqueId(String uniqueId) { - Member member = memberRepository.findByUniqueId(uniqueId) - .orElseThrow(() -> new EntityNotFoundException("해당 uniqueId를 가진 회원이 존재하지 않습니다.")); - return member; - } - - public MemberClubListResponse findJoinedClubs(CustomOAuth2Member customOAuth2Member) { - Member member = memberRepository.findByUniqueId(customOAuth2Member.getUniqueId()) - .orElseThrow(() -> new EntityNotFoundException("해당 uniqueId를 가진 회원이 존재하지 않습니다.")); - List clubMemberships = member.getClubMemberships(); - List memberClubResponseList = clubMemberships.stream() - .map(MemberClubResponse::from) - .toList(); - - return MemberClubListResponse.from(memberClubResponseList); - } - - @Transactional - public MemberInfoResponse updateProfileImage(CustomOAuth2Member customOAuth2Member, MultipartFile profileImageFile) { - String profileImage = s3ImageService.upload(profileImageFile); - - Member member = memberRepository.findByUniqueId(customOAuth2Member.getUniqueId()) - .orElseThrow(() -> new EntityNotFoundException("해당 uniqueId를 가진 회원을 찾을 수 없습니다.")); - Member updatedMember = member.updateProfileImage(profileImage); - return MemberInfoResponse.from(updatedMember); - } - - @Transactional - public MemberInfoResponse deleteProfileImage(CustomOAuth2Member customOAuth2Member) { - Member member = findMemberByUniqueId(customOAuth2Member.getUniqueId()); - s3ImageService.deleteImageFromS3(member.getProfileImage()); - member.updateProfileImage("default profile img"); - memberRepository.save(member); - return MemberInfoResponse.from(member); - } - - public MemberClubApplicationListResponse findAppliedClubs(CustomOAuth2Member customOAuth2Member) { - Member member = memberRepository.findByUniqueId(customOAuth2Member.getUniqueId()) - .orElseThrow(() -> new EntityNotFoundException("해당 uniqueId를 가진 회원이 존재하지 않습니다.")); - - List clubApplications = clubApplicationRepository.findByMember_MemberIdx(member.getMemberIdx()); - - List memberClubApplicationInfoResponses = clubApplications.stream() - .map(MemberClubApplicationInfoResponse::from) - .toList(); - - return MemberClubApplicationListResponse.from(memberClubApplicationInfoResponses); - } + private final MemberRepository memberRepository; + private final JWTUtil jwtUtil; + private final S3ImageService s3ImageService; + private final ClubApplicationRepository clubApplicationRepository; + + @Transactional + public Long saveMember(Member member) { + Member save = memberRepository.save(member); + return save.getMemberIdx(); + } + + public MemberInfoResponse findMemberInfo(CustomOAuth2Member customOAuth2Member) { + Member findMember = memberRepository.findByUniqueId(customOAuth2Member.getUniqueId()) + .orElseThrow(() -> new EntityNotFoundException("해당 고유번호를 가진 회원을 찾을 수 없습니다.")); + return MemberInfoResponse.from(findMember); + } + + public Member findMemberByUniqueId(String uniqueId) { + Member member = memberRepository.findByUniqueId(uniqueId) + .orElseThrow(() -> new EntityNotFoundException("해당 uniqueId를 가진 회원이 존재하지 않습니다.")); + return member; + } + + public MemberClubListResponse findJoinedClubs(CustomOAuth2Member customOAuth2Member) { + Member member = memberRepository.findByUniqueId(customOAuth2Member.getUniqueId()) + .orElseThrow(() -> new EntityNotFoundException("해당 uniqueId를 가진 회원이 존재하지 않습니다.")); + List clubMemberships = member.getClubMemberships(); + List memberClubResponseList = clubMemberships.stream() + .map(MemberClubResponse::from) + .toList(); + + return MemberClubListResponse.from(memberClubResponseList); + } + + @Transactional + public MemberInfoResponse updateProfileImage(CustomOAuth2Member customOAuth2Member, + MultipartFile profileImageFile) { + String profileImage = s3ImageService.upload(profileImageFile); + + Member member = memberRepository.findByUniqueId(customOAuth2Member.getUniqueId()) + .orElseThrow(() -> new EntityNotFoundException("해당 uniqueId를 가진 회원을 찾을 수 없습니다.")); + Member updatedMember = member.updateProfileImage(profileImage); + return MemberInfoResponse.from(updatedMember); + } + + @Transactional + public MemberInfoResponse deleteProfileImage(CustomOAuth2Member customOAuth2Member) { + Member member = findMemberByUniqueId(customOAuth2Member.getUniqueId()); + s3ImageService.deleteImageFromS3(member.getProfileImage()); + member.updateProfileImage("default profile img"); + memberRepository.save(member); + return MemberInfoResponse.from(member); + } + + public MemberClubApplicationListResponse findAppliedClubs(CustomOAuth2Member customOAuth2Member) { + Member member = memberRepository.findByUniqueId(customOAuth2Member.getUniqueId()) + .orElseThrow(() -> new EntityNotFoundException("해당 uniqueId를 가진 회원이 존재하지 않습니다.")); + + List clubApplications = clubApplicationRepository.findByMember_MemberIdxFetchClubAndRecruitingPost( + member.getMemberIdx()); + + List memberClubApplicationInfoResponses = clubApplications.stream() + .map(MemberClubApplicationInfoResponse::from) + .toList(); + + return MemberClubApplicationListResponse.from(memberClubApplicationInfoResponses); + } } diff --git a/src/main/java/com/cotato/squadus/domain/auth/service/RefreshService.java b/src/main/java/com/cotato/squadus/domain/auth/service/RefreshService.java index 4d89b81..3a7724b 100644 --- a/src/main/java/com/cotato/squadus/domain/auth/service/RefreshService.java +++ b/src/main/java/com/cotato/squadus/domain/auth/service/RefreshService.java @@ -1,69 +1,71 @@ package com.cotato.squadus.domain.auth.service; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; + +import org.springframework.stereotype.Service; + import com.cotato.squadus.common.config.jwt.JWTUtil; import com.cotato.squadus.common.config.jwt.RefreshEntity; import com.cotato.squadus.common.config.jwt.RefreshRepository; + import jakarta.servlet.http.Cookie; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.springframework.stereotype.Service; - -import java.util.Date; -import java.util.HashMap; -import java.util.Map; @Service @RequiredArgsConstructor @Slf4j public class RefreshService { - private final RefreshRepository refreshRepository; - private final JWTUtil jwtUtil; + private final RefreshRepository refreshRepository; + private final JWTUtil jwtUtil; - public Map reissueRefreshToken(String refresh){ - Map map = new HashMap<>(); + public Map reissueRefreshToken(String refresh) { + Map map = new HashMap<>(); - String uniqueId = jwtUtil.getUniqueId(refresh); - String username = jwtUtil.getUsername(refresh); - String role = jwtUtil.getRole(refresh); + String uniqueId = jwtUtil.getUniqueId(refresh); + String username = jwtUtil.getUsername(refresh); + String role = jwtUtil.getRole(refresh); - //make new JWT - String newAccess = jwtUtil.createJwt("access", uniqueId, username, role, 600000L); - String newRefresh = jwtUtil.createJwt("refresh", uniqueId, username, role, 86400000L); - map.put("access", newAccess); - map.put("refresh", newRefresh); + //make new JWT + String newAccess = jwtUtil.createJwt("access", uniqueId, username, role, 600000L); + String newRefresh = jwtUtil.createJwt("refresh", uniqueId, username, role, 86400000L); + map.put("access", newAccess); + map.put("refresh", newRefresh); - log.info("New refresh: " + newRefresh + " access: " + newAccess); + log.info("New refresh: " + newRefresh + " access: " + newAccess); - //Refresh 토큰 저장 DB에 기존의 Refresh 토큰 삭제 후 새 Refresh 토큰 저장 - refreshRepository.deleteByRefresh(refresh); - addRefreshEntity(uniqueId, username, newRefresh, 86400000L); + //Refresh 토큰 저장 DB에 기존의 Refresh 토큰 삭제 후 새 Refresh 토큰 저장 + refreshRepository.deleteByRefresh(refresh); + addRefreshEntity(uniqueId, username, newRefresh, 86400000L); - return map; - } + return map; + } - public void addRefreshEntity(String uniqueId, String username, String refresh, Long expiredMs) { - //증복 저장x 구현해야함 - Date date = new Date(System.currentTimeMillis() + expiredMs); + public void addRefreshEntity(String uniqueId, String username, String refresh, Long expiredMs) { + //증복 저장x 구현해야함 + Date date = new Date(System.currentTimeMillis() + expiredMs); - RefreshEntity refreshEntity = new RefreshEntity(); - refreshEntity.setUniqueId(uniqueId); - refreshEntity.setUsername(username); - refreshEntity.setRefresh(refresh); - refreshEntity.setExpiration(date.toString()); + RefreshEntity refreshEntity = new RefreshEntity(); + refreshEntity.setUniqueId(uniqueId); + refreshEntity.setUsername(username); + refreshEntity.setRefresh(refresh); + refreshEntity.setExpiration(date.toString()); - refreshRepository.save(refreshEntity); - } + refreshRepository.save(refreshEntity); + } - public Cookie createCookie(String key, String value) { + public Cookie createCookie(String key, String value) { - Cookie cookie = new Cookie(key, value); - cookie.setMaxAge(24*60*60); - //cookie.setSecure(true); - cookie.setPath("/"); //모든 위치에서 쿠키를 볼 수 있음 - cookie.setHttpOnly(true); //자바스크립트가 쿠키를 가져가지 못하게 함 + Cookie cookie = new Cookie(key, value); + cookie.setMaxAge(24 * 60 * 60); + //cookie.setSecure(true); + cookie.setPath("/"); //모든 위치에서 쿠키를 볼 수 있음 + cookie.setHttpOnly(true); //자바스크립트가 쿠키를 가져가지 못하게 함 - return cookie; - } + return cookie; + } } diff --git a/src/main/java/com/cotato/squadus/domain/club/admin/service/ClubAdminService.java b/src/main/java/com/cotato/squadus/domain/club/admin/service/ClubAdminService.java index b2a16ab..55c2ad9 100644 --- a/src/main/java/com/cotato/squadus/domain/club/admin/service/ClubAdminService.java +++ b/src/main/java/com/cotato/squadus/domain/club/admin/service/ClubAdminService.java @@ -1,5 +1,10 @@ package com.cotato.squadus.domain.club.admin.service; +import java.util.List; + +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + import com.cotato.squadus.api.admin.dto.ClubApplicationInfoResponse; import com.cotato.squadus.api.admin.dto.ClubApplicationListResponse; import com.cotato.squadus.api.admin.dto.ClubJoinApprovalResponse; @@ -9,18 +14,19 @@ import com.cotato.squadus.domain.auth.enums.ApplicationStatus; import com.cotato.squadus.domain.auth.enums.Membership; import com.cotato.squadus.domain.auth.service.ClubMemberService; -import com.cotato.squadus.domain.club.common.entity.*; +import com.cotato.squadus.domain.club.common.entity.Club; +import com.cotato.squadus.domain.club.common.entity.ClubAdminMember; +import com.cotato.squadus.domain.club.common.entity.ClubApplication; +import com.cotato.squadus.domain.club.common.entity.ClubMember; +import com.cotato.squadus.domain.club.common.entity.RegularClubMember; import com.cotato.squadus.domain.club.common.enums.MemberType; import com.cotato.squadus.domain.club.common.repository.ClubApplicationRepository; import com.cotato.squadus.domain.club.common.repository.ClubMemberRepository; import com.cotato.squadus.domain.club.common.repository.ClubRepository; + import jakarta.persistence.EntityNotFoundException; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -import java.util.List; @Slf4j @Service @@ -28,75 +34,73 @@ @RequiredArgsConstructor public class ClubAdminService { - private final ClubApplicationRepository clubApplicationRepository; - private final ClubMemberService clubMemberService; - private final ClubMemberRepository clubMemberRepository; - private final ClubRepository clubRepository; - - @Transactional - public ClubJoinApprovalResponse approveApply(Long clubId, Long applicationId) { - validateAdminMember(clubId); - - ClubApplication clubApplication = clubApplicationRepository.findById(applicationId) - .orElseThrow(() -> new EntityNotFoundException("해당 고유번호를 가진 지원서를 찾을 수 없습니다.")); + private final ClubApplicationRepository clubApplicationRepository; + private final ClubMemberService clubMemberService; + private final ClubMemberRepository clubMemberRepository; + private final ClubRepository clubRepository; - ClubMember clubMember = RegularClubMember.builder() - .member(clubApplication.getMember()) - .club(clubApplication.getClub()) - .membership(Membership.JOINED) - .isPaid(false) - .build(); + @Transactional + public ClubJoinApprovalResponse approveApply(Long clubId, Long applicationId) { + validateAdminMember(clubId); - ClubMember savedMember = clubMemberRepository.save(clubMember); + ClubApplication clubApplication = clubApplicationRepository.findById(applicationId) + .orElseThrow(() -> new EntityNotFoundException("해당 고유번호를 가진 지원서를 찾을 수 없습니다.")); - updateClubInfo(clubId, savedMember); - clubApplication.updateApplicationState(ApplicationStatus.APPROVED); - clubApplicationRepository.save(clubApplication); - return new ClubJoinApprovalResponse(savedMember.getClubMemberIdx()); - } + ClubMember clubMember = RegularClubMember.builder() + .member(clubApplication.getMember()) + .club(clubApplication.getClub()) + .membership(Membership.JOINED) + .isPaid(false) + .build(); - @Transactional - public ClubJoinDenialResponse denyApply(Long clubId, Long applicationId) { - validateAdminMember(clubId); + ClubMember savedMember = clubMemberRepository.save(clubMember); - ClubApplication clubApplication = clubApplicationRepository.findById(applicationId) - .orElseThrow(() -> new EntityNotFoundException("해당 고유번호를 가진 지원서를 찾을 수 없습니다.")); + updateClubInfo(clubId, savedMember); + clubApplication.updateApplicationState(ApplicationStatus.APPROVED); + clubApplicationRepository.save(clubApplication); + return new ClubJoinApprovalResponse(savedMember.getClubMemberIdx()); + } - clubApplication.updateApplicationState(ApplicationStatus.REJECTED); - clubApplicationRepository.save(clubApplication); + @Transactional + public ClubJoinDenialResponse denyApply(Long clubId, Long applicationId) { + validateAdminMember(clubId); - return new ClubJoinDenialResponse(clubApplication.getApplicationIdx()); - } + ClubApplication clubApplication = clubApplicationRepository.findById(applicationId) + .orElseThrow(() -> new EntityNotFoundException("해당 고유번호를 가진 지원서를 찾을 수 없습니다.")); - // 신규 가입한 동아리원에 대한 정보 반영 - private void updateClubInfo(Long clubId, ClubMember clubMember) { - Club club = clubRepository.findById(clubId) - .orElseThrow(() -> new EntityNotFoundException("해당 고유번호를 가진 동아리를 찾을 수 없습니다.")); + clubApplication.updateApplicationState(ApplicationStatus.REJECTED); + clubApplicationRepository.save(clubApplication); - club.addClubMember(clubMember); - club.addNumberOfMembers(); - clubRepository.save(club); - } + return new ClubJoinDenialResponse(clubApplication.getApplicationIdx()); + } - public ClubAdminMember validateAdminMember(Long clubId) { - ClubMember clubMember = clubMemberService.findClubMemberBySecurityContextHolder(clubId); - if (!clubMember.getMemberType().equals(MemberType.ADMIN)) { - throw new AppException(ErrorCode.MEMBER_TYPE_IS_NOT_ADMIN); - } + // 신규 가입한 동아리원에 대한 정보 반영 + private void updateClubInfo(Long clubId, ClubMember clubMember) { + Club club = clubRepository.findById(clubId) + .orElseThrow(() -> new EntityNotFoundException("해당 고유번호를 가진 동아리를 찾을 수 없습니다.")); - return (ClubAdminMember) clubMember; - } + club.addClubMember(clubMember); + club.addNumberOfMembers(); + clubRepository.save(club); + } + public ClubAdminMember validateAdminMember(Long clubId) { + ClubMember clubMember = clubMemberService.findClubMemberBySecurityContextHolder(clubId); + if (!clubMember.getMemberType().equals(MemberType.ADMIN)) { + throw new AppException(ErrorCode.MEMBER_TYPE_IS_NOT_ADMIN); + } - public ClubApplicationListResponse findAllClubApplyByRecruitingPostId(Long clubId, Long recruitingPostId) { + return (ClubAdminMember)clubMember; + } - List list = clubApplicationRepository.findByRecruitingPost_PostId(recruitingPostId) - .stream() - .map(ClubApplicationInfoResponse::from) - .toList(); + public ClubApplicationListResponse findAllClubApplyByRecruitingPostId(Long clubId, Long recruitingPostId) { - return ClubApplicationListResponse.from(list); + List list = clubApplicationRepository.findByRecruitingPost_PostId(recruitingPostId) + .stream() + .map(ClubApplicationInfoResponse::from) + .toList(); + return ClubApplicationListResponse.from(list); - } + } } diff --git a/src/main/java/com/cotato/squadus/domain/club/article/entity/Article.java b/src/main/java/com/cotato/squadus/domain/club/article/entity/Article.java index dec8196..4fdeb1d 100644 --- a/src/main/java/com/cotato/squadus/domain/club/article/entity/Article.java +++ b/src/main/java/com/cotato/squadus/domain/club/article/entity/Article.java @@ -1,12 +1,17 @@ package com.cotato.squadus.domain.club.article.entity; +import org.springframework.data.jpa.domain.support.AuditingEntityListener; + import com.cotato.squadus.common.entity.BaseTimeEntity; -import jakarta.persistence.*; + +import jakarta.persistence.Entity; +import jakarta.persistence.EntityListeners; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.Table; import lombok.Builder; import lombok.Getter; -import org.springframework.data.jpa.domain.support.AuditingEntityListener; - -import java.time.LocalDateTime; @Entity @Getter @@ -14,44 +19,45 @@ @EntityListeners(AuditingEntityListener.class) public class Article extends BaseTimeEntity { - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - private Long articleIdx; + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long articleIdx; - private String title; + private String title; - private String subtitle; + private String subtitle; - private String type; + private String type; - private String tag; + private String tag; - private String content; + private String content; - private Long views; + private Long views; - private String imageUrl; + private String imageUrl; - @Builder - public Article(String title, String subtitle, String type, String tag, String content, Long views, String imageUrl) { - this.title = title; - this.subtitle = subtitle; - this.type = type; - this.tag = tag; - this.content = content; - this.views = views; - this.imageUrl = imageUrl; // 추가된 필드 - } + @Builder + public Article(String title, String subtitle, String type, String tag, String content, Long views, + String imageUrl) { + this.title = title; + this.subtitle = subtitle; + this.type = type; + this.tag = tag; + this.content = content; + this.views = views; + this.imageUrl = imageUrl; // 추가된 필드 + } - public Article() { - } + public Article() { + } - public void setViews(Long views) { - this.views = views; - } + public void setViews(Long views) { + this.views = views; + } - public void setImageUrl(String imageUrl) { - this.imageUrl = imageUrl; - } + public void setImageUrl(String imageUrl) { + this.imageUrl = imageUrl; + } } diff --git a/src/main/java/com/cotato/squadus/domain/club/article/repository/ArticleRepository.java b/src/main/java/com/cotato/squadus/domain/club/article/repository/ArticleRepository.java index 5c6fb6a..c160f62 100644 --- a/src/main/java/com/cotato/squadus/domain/club/article/repository/ArticleRepository.java +++ b/src/main/java/com/cotato/squadus/domain/club/article/repository/ArticleRepository.java @@ -1,7 +1,8 @@ package com.cotato.squadus.domain.club.article.repository; -import com.cotato.squadus.domain.club.article.entity.Article; import org.springframework.data.jpa.repository.JpaRepository; +import com.cotato.squadus.domain.club.article.entity.Article; + public interface ArticleRepository extends JpaRepository { } diff --git a/src/main/java/com/cotato/squadus/domain/club/article/service/ArticleService.java b/src/main/java/com/cotato/squadus/domain/club/article/service/ArticleService.java index 399394a..1d0bcc1 100644 --- a/src/main/java/com/cotato/squadus/domain/club/article/service/ArticleService.java +++ b/src/main/java/com/cotato/squadus/domain/club/article/service/ArticleService.java @@ -1,75 +1,78 @@ package com.cotato.squadus.domain.club.article.service; +import java.util.List; +import java.util.stream.Collectors; + +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.stereotype.Service; +import org.springframework.web.multipart.MultipartFile; + import com.cotato.squadus.api.article.dto.ArticleRequest; import com.cotato.squadus.api.article.dto.ArticleResponse; import com.cotato.squadus.api.article.dto.ArticleSummaryResponse; import com.cotato.squadus.common.s3.S3ImageService; import com.cotato.squadus.domain.club.article.entity.Article; import com.cotato.squadus.domain.club.article.repository.ArticleRepository; + import jakarta.persistence.EntityNotFoundException; import jakarta.transaction.Transactional; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.springframework.data.domain.Page; -import org.springframework.data.domain.Pageable; -import org.springframework.stereotype.Service; -import org.springframework.web.multipart.MultipartFile; - -import java.util.List; -import java.util.stream.Collectors; @Slf4j @Service @RequiredArgsConstructor public class ArticleService { - private final ArticleRepository articleRepository; - private final S3ImageService s3ImageService; + private final ArticleRepository articleRepository; + private final S3ImageService s3ImageService; - public ArticleResponse findArticleById(Long articleId) { - Article article = articleRepository.findById(articleId) - .orElseThrow(() -> new EntityNotFoundException("해당 기사를 찾을 수 없습니다: " + articleId)); - article.setViews(article.getViews() + 1); // 조회수 증가 - articleRepository.save(article); // 변경된 조회수를 저장 - return ArticleResponse.from(article); - } + public ArticleResponse findArticleById(Long articleId) { + Article article = articleRepository.findById(articleId) + .orElseThrow(() -> new EntityNotFoundException("해당 기사를 찾을 수 없습니다: " + articleId)); + article.setViews(article.getViews() + 1); // 조회수 증가 + articleRepository.save(article); // 변경된 조회수를 저장 + return ArticleResponse.from(article); + } - @Transactional - public ArticleResponse createArticle(ArticleRequest articleRequest, MultipartFile multipartFile) { + @Transactional + public ArticleResponse createArticle(ArticleRequest articleRequest, MultipartFile multipartFile) { - String imageUrl; - if (multipartFile != null && !multipartFile.isEmpty()) { - imageUrl = s3ImageService.upload(multipartFile); - } else { - imageUrl = "no image"; - } + String imageUrl; + if (multipartFile != null && !multipartFile.isEmpty()) { + imageUrl = s3ImageService.upload(multipartFile); + } else { + imageUrl = "no image"; + } - Article article = Article.builder() - .title(articleRequest.getTitle()) - .subtitle(articleRequest.getSubtitle()) - .type(articleRequest.getType()) - .tag(articleRequest.getTag()) - .content(articleRequest.getContent()) - .views(articleRequest.getViews()) - .imageUrl(imageUrl) - .build(); - articleRepository.save(article); - return ArticleResponse.from(article); - } + Article article = Article.builder() + .title(articleRequest.getTitle()) + .subtitle(articleRequest.getSubtitle()) + .type(articleRequest.getType()) + .tag(articleRequest.getTag()) + .content(articleRequest.getContent()) + .views(articleRequest.getViews()) + .imageUrl(imageUrl) + .build(); + articleRepository.save(article); + return ArticleResponse.from(article); + } - public Page findAllArticleSummaries(Pageable pageable) { - return articleRepository.findAll(pageable).map(ArticleSummaryResponse::from); - } + public Page findAllArticleSummaries(Pageable pageable) { + return articleRepository.findAll(pageable).map(ArticleSummaryResponse::from); + } - public List getAllArticles() { - return articleRepository.findAll().stream() - .map(article -> new ArticleSummaryResponse(article.getArticleIdx(), article.getTitle(), article.getSubtitle())) - .collect(Collectors.toList()); - } + public List getAllArticles() { + return articleRepository.findAll().stream() + .map(article -> new ArticleSummaryResponse(article.getArticleIdx(), article.getTitle(), + article.getSubtitle())) + .collect(Collectors.toList()); + } - public List getAllArticlesWithAllData() { - return articleRepository.findAll().stream() - .map(ArticleResponse::from) - .collect(Collectors.toList()); - } + public List getAllArticlesWithAllData() { + return articleRepository.findAll().stream() + .map(ArticleResponse::from) + .collect(Collectors.toList()); + } } diff --git a/src/main/java/com/cotato/squadus/domain/club/banner/Banner.java b/src/main/java/com/cotato/squadus/domain/club/banner/Banner.java index 10e4a3e..61ed40b 100644 --- a/src/main/java/com/cotato/squadus/domain/club/banner/Banner.java +++ b/src/main/java/com/cotato/squadus/domain/club/banner/Banner.java @@ -1,29 +1,30 @@ package com.cotato.squadus.domain.club.banner; +import java.time.LocalDateTime; + import jakarta.persistence.Entity; import jakarta.persistence.GeneratedValue; import jakarta.persistence.Id; import jakarta.persistence.Table; import lombok.Getter; -import java.time.LocalDateTime; - @Entity @Getter @Table(name = "banner") public class Banner { - @Id @GeneratedValue - private Long bannerIdx; + @Id + @GeneratedValue + private Long bannerIdx; - private String title; + private String title; - private String type; + private String type; - private LocalDateTime createdAt; + private LocalDateTime createdAt; - private String content; + private String content; - private Long views; + private Long views; } diff --git a/src/main/java/com/cotato/squadus/domain/club/common/entity/Club.java b/src/main/java/com/cotato/squadus/domain/club/common/entity/Club.java index 5f471e2..6421c31 100644 --- a/src/main/java/com/cotato/squadus/domain/club/common/entity/Club.java +++ b/src/main/java/com/cotato/squadus/domain/club/common/entity/Club.java @@ -1,5 +1,13 @@ package com.cotato.squadus.domain.club.common.entity; +import static jakarta.persistence.CascadeType.*; +import static jakarta.persistence.FetchType.*; + +import java.util.ArrayList; +import java.util.List; + +import org.springframework.data.jpa.domain.support.AuditingEntityListener; + import com.cotato.squadus.common.entity.BaseTimeEntity; import com.cotato.squadus.domain.club.common.enums.ClubCategory; import com.cotato.squadus.domain.club.common.enums.ClubTier; @@ -9,16 +17,22 @@ import com.cotato.squadus.domain.club.match.entity.mercenary.MercenaryPost; import com.cotato.squadus.domain.club.post.entity.ClubPost; import com.cotato.squadus.domain.club.schedule.entity.ClubSchedule; -import jakarta.persistence.*; + +import jakarta.persistence.ElementCollection; +import jakarta.persistence.Embedded; +import jakarta.persistence.Entity; +import jakarta.persistence.EntityListeners; +import jakarta.persistence.EnumType; +import jakarta.persistence.Enumerated; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.Lob; +import jakarta.persistence.OneToMany; +import jakarta.persistence.Table; import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; -import org.springframework.data.jpa.domain.support.AuditingEntityListener; - -import java.util.ArrayList; -import java.util.List; -import static jakarta.persistence.CascadeType.*; -import static jakarta.persistence.FetchType.LAZY; @Entity @Getter @@ -27,116 +41,118 @@ @EntityListeners(AuditingEntityListener.class) public class Club extends BaseTimeEntity { - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - private Long clubId; - - private String clubName; + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long clubId; - private String university; + private String clubName; - @Enumerated(EnumType.STRING) - private ClubTier clubTier; + private String university; - private Integer clubRank; + @Enumerated(EnumType.STRING) + private ClubTier clubTier; - @Lob - private String clubMessage; + private Integer clubRank; - private Long maxMembers; + @Lob + private String clubMessage; - private Integer numberOfMembers; + private Long maxMembers; - //동아리 매칭 점수, 티어를 위해 사용함 - private Integer matchScore = 0; + private Integer numberOfMembers; - @ElementCollection - private List tags; // 별도의 테이블을 생성하여 컬렉션의 데이터를 저장 + //동아리 매칭 점수, 티어를 위해 사용함 + private Integer matchScore = 0; - @Enumerated(EnumType.STRING) - private ClubCategory clubCategory; + @ElementCollection + private List tags; // 별도의 테이블을 생성하여 컬렉션의 데이터를 저장 - @Enumerated(EnumType.STRING) - private SportsCategory sportsCategory; + @Enumerated(EnumType.STRING) + private ClubCategory clubCategory; - @Embedded - private Region region; // 활동 지역 + @Enumerated(EnumType.STRING) + private SportsCategory sportsCategory; - //s3로 이미지 저장 - private String logo; + @Embedded + private Region region; // 활동 지역 - @OneToMany(mappedBy = "club", cascade = ALL) - private List clubSchedules; + //s3로 이미지 저장 + private String logo; - @OneToMany(mappedBy = "club", cascade = ALL) - private List clubMembers = new ArrayList<>(); + @OneToMany(mappedBy = "club", cascade = ALL) + private List clubSchedules; - @OneToMany(mappedBy = "club", fetch = LAZY, cascade = ALL) - private List clubPosts = new ArrayList<>(); + @OneToMany(mappedBy = "club", cascade = ALL) + private List clubMembers = new ArrayList<>(); - @OneToMany(mappedBy = "homeClub", fetch = LAZY, cascade = ALL) - private List matchPosts = new ArrayList<>(); + @OneToMany(mappedBy = "club", fetch = LAZY, cascade = ALL) + private List clubPosts = new ArrayList<>(); - @OneToMany(mappedBy = "homeClub", fetch = LAZY, cascade = ALL) - private List mercenaryPosts = new ArrayList<>(); + @OneToMany(mappedBy = "homeClub", fetch = LAZY, cascade = ALL) + private List matchPosts = new ArrayList<>(); - @OneToMany(mappedBy = "club", fetch = LAZY, cascade = ALL) - private List feeTypes = new ArrayList<>(); + @OneToMany(mappedBy = "homeClub", fetch = LAZY, cascade = ALL) + private List mercenaryPosts = new ArrayList<>(); - @Builder - private Club(String clubName, String university, ClubCategory clubCategory, SportsCategory sportsCategory, String logo, ClubTier clubTier, Integer clubRank, String clubMessage, Long maxMembers, Region region, List tags) { - this.clubName = clubName; - this.university = university; - this.clubCategory = clubCategory; - this.sportsCategory = sportsCategory; - this.logo = logo; - this.clubTier = clubTier; - this.clubRank = clubRank; - this.clubMessage = clubMessage; - this.maxMembers = maxMembers; - this.numberOfMembers = 1; - this.region = region; - this.tags = tags; - } + @OneToMany(mappedBy = "club", fetch = LAZY, cascade = ALL) + private List feeTypes = new ArrayList<>(); - public void addClubMember(ClubMember clubMember) { - this.clubMembers.add(clubMember); - } + @Builder + private Club(String clubName, String university, ClubCategory clubCategory, SportsCategory sportsCategory, + String logo, ClubTier clubTier, Integer clubRank, String clubMessage, Long maxMembers, Region region, + List tags) { + this.clubName = clubName; + this.university = university; + this.clubCategory = clubCategory; + this.sportsCategory = sportsCategory; + this.logo = logo; + this.clubTier = clubTier; + this.clubRank = clubRank; + this.clubMessage = clubMessage; + this.maxMembers = maxMembers; + this.numberOfMembers = 1; + this.region = region; + this.tags = tags; + } - public void addMatchPost(MatchPost matchPost) { - this.matchPosts.add(matchPost); - matchPost.setHomeClub(this); - } + public void addClubMember(ClubMember clubMember) { + this.clubMembers.add(clubMember); + } - public void addMercenaryPost(MercenaryPost mercenaryPost) { - this.mercenaryPosts.add(mercenaryPost); - mercenaryPost.setHomeClub(this); - } + public void addMatchPost(MatchPost matchPost) { + this.matchPosts.add(matchPost); + matchPost.setHomeClub(this); + } - public void addNumberOfMembers() { - this.numberOfMembers++; - } + public void addMercenaryPost(MercenaryPost mercenaryPost) { + this.mercenaryPosts.add(mercenaryPost); + mercenaryPost.setHomeClub(this); + } - // 매칭 결과를 누적하여 점수 반영 - public void updateMatchScore(int points) { - this.matchScore = this.matchScore + points; - } + public void addNumberOfMembers() { + this.numberOfMembers++; + } - public Club updateClub(String logo, String clubMessage, Region region, Long maxMembers, List tags) { - this.logo = logo; - this.clubMessage = clubMessage; - this.region = region; - this.maxMembers = maxMembers; - this.tags = tags; - return this; - } + // 매칭 결과를 누적하여 점수 반영 + public void updateMatchScore(int points) { + this.matchScore = this.matchScore + points; + } - public void updateTier(ClubTier newTier) { - this.clubTier = newTier; - } + public Club updateClub(String logo, String clubMessage, Region region, Long maxMembers, List tags) { + this.logo = logo; + this.clubMessage = clubMessage; + this.region = region; + this.maxMembers = maxMembers; + this.tags = tags; + return this; + } - public void updateClubRank(Integer clubRank) { - this.clubRank = clubRank; - } + public void updateTier(ClubTier newTier) { + this.clubTier = newTier; + } + + public void updateClubRank(Integer clubRank) { + this.clubRank = clubRank; + } } diff --git a/src/main/java/com/cotato/squadus/domain/club/common/entity/ClubAdminMember.java b/src/main/java/com/cotato/squadus/domain/club/common/entity/ClubAdminMember.java index 021653e..3d441f0 100644 --- a/src/main/java/com/cotato/squadus/domain/club/common/entity/ClubAdminMember.java +++ b/src/main/java/com/cotato/squadus/domain/club/common/entity/ClubAdminMember.java @@ -4,6 +4,7 @@ import com.cotato.squadus.domain.auth.enums.AdminStatus; import com.cotato.squadus.domain.auth.enums.Membership; import com.cotato.squadus.domain.club.common.enums.MemberType; + import jakarta.persistence.DiscriminatorValue; import jakarta.persistence.Entity; import jakarta.persistence.EnumType; @@ -18,18 +19,19 @@ @NoArgsConstructor public class ClubAdminMember extends ClubMember { - @Enumerated(EnumType.STRING) - private AdminStatus adminStatus; + @Enumerated(EnumType.STRING) + private AdminStatus adminStatus; - @Builder - public ClubAdminMember(Member member, Club club, Membership membership, Boolean isPaid, String clubProfileImage, AdminStatus adminStatus) { - super(member, club, membership, isPaid, clubProfileImage); - this.adminStatus = adminStatus; - } + @Builder + public ClubAdminMember(Member member, Club club, Membership membership, Boolean isPaid, String clubProfileImage, + AdminStatus adminStatus) { + super(member, club, membership, isPaid, clubProfileImage); + this.adminStatus = adminStatus; + } - @Override - public MemberType getMemberType() { - return MemberType.ADMIN; - } + @Override + public MemberType getMemberType() { + return MemberType.ADMIN; + } } diff --git a/src/main/java/com/cotato/squadus/domain/club/common/entity/ClubApplication.java b/src/main/java/com/cotato/squadus/domain/club/common/entity/ClubApplication.java index c52b8cf..4582dc7 100644 --- a/src/main/java/com/cotato/squadus/domain/club/common/entity/ClubApplication.java +++ b/src/main/java/com/cotato/squadus/domain/club/common/entity/ClubApplication.java @@ -1,67 +1,82 @@ package com.cotato.squadus.domain.club.common.entity; -import com.cotato.squadus.domain.auth.enums.ApplicationStatus; +import java.time.LocalDateTime; +import java.util.HashMap; +import java.util.Map; + import com.cotato.squadus.domain.auth.entity.Member; +import com.cotato.squadus.domain.auth.enums.ApplicationStatus; import com.cotato.squadus.domain.club.recruit.entity.RecruitingPost; -import jakarta.persistence.*; + +import jakarta.persistence.CollectionTable; +import jakarta.persistence.Column; +import jakarta.persistence.ElementCollection; +import jakarta.persistence.Entity; +import jakarta.persistence.EnumType; +import jakarta.persistence.Enumerated; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.MapKeyColumn; +import jakarta.persistence.Table; import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; -import java.time.LocalDateTime; -import java.util.HashMap; -import java.util.Map; - @Entity @Getter @NoArgsConstructor @Table(name = "club_application") public class ClubApplication { - @Id @GeneratedValue - private Long applicationIdx; + @Id + @GeneratedValue + private Long applicationIdx; - @ManyToOne - @JoinColumn(name = "member_idx") - private Member member; + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "member_idx") + private Member member; - @ManyToOne - @JoinColumn(name = "club_idx") - private Club club; + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "club_idx") + private Club club; - @ManyToOne - @JoinColumn(name = "recruiting_post_id") - private RecruitingPost recruitingPost; + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "recruiting_post_id") + private RecruitingPost recruitingPost; - private LocalDateTime appliedAt; + private LocalDateTime appliedAt; - @Enumerated(EnumType.STRING) - private ApplicationStatus applicationStatus; + @Enumerated(EnumType.STRING) + private ApplicationStatus applicationStatus; - @ElementCollection(fetch = FetchType.LAZY) - @CollectionTable(name = "application_questions", joinColumns = @JoinColumn(name = "application_id")) - @MapKeyColumn(name = "question_index") - @Column(name = "questions") - private Map questions = new HashMap<>(); + @ElementCollection(fetch = FetchType.LAZY) + @CollectionTable(name = "application_questions", joinColumns = @JoinColumn(name = "application_id")) + @MapKeyColumn(name = "question_index") + @Column(name = "questions") + private Map questions = new HashMap<>(); - @ElementCollection(fetch = FetchType.LAZY) - @CollectionTable(name = "recruiting_post_answers", joinColumns = @JoinColumn(name = "application_id")) - @MapKeyColumn(name = "answer_index") - @Column(name = "answers") - private Map answers = new HashMap<>(); + @ElementCollection(fetch = FetchType.LAZY) + @CollectionTable(name = "recruiting_post_answers", joinColumns = @JoinColumn(name = "application_id")) + @MapKeyColumn(name = "answer_index") + @Column(name = "answers") + private Map answers = new HashMap<>(); - @Builder - public ClubApplication(Member member, Club club, LocalDateTime appliedAt, ApplicationStatus applicationStatus, Map questions, Map answers, RecruitingPost recruitingPost) { - this.member = member; - this.club = club; - this.appliedAt = appliedAt; - this.applicationStatus = applicationStatus; - this.questions = new HashMap<>(questions); - this.answers = answers; - this.recruitingPost = recruitingPost; - } + @Builder + public ClubApplication(Member member, Club club, LocalDateTime appliedAt, ApplicationStatus applicationStatus, + Map questions, Map answers, RecruitingPost recruitingPost) { + this.member = member; + this.club = club; + this.appliedAt = appliedAt; + this.applicationStatus = applicationStatus; + this.questions = new HashMap<>(questions); + this.answers = answers; + this.recruitingPost = recruitingPost; + } - public void updateApplicationState(ApplicationStatus status) { - this.applicationStatus = status; - } + public void updateApplicationState(ApplicationStatus status) { + this.applicationStatus = status; + } } diff --git a/src/main/java/com/cotato/squadus/domain/club/common/entity/ClubMember.java b/src/main/java/com/cotato/squadus/domain/club/common/entity/ClubMember.java index e361c65..ada42f4 100644 --- a/src/main/java/com/cotato/squadus/domain/club/common/entity/ClubMember.java +++ b/src/main/java/com/cotato/squadus/domain/club/common/entity/ClubMember.java @@ -1,17 +1,31 @@ package com.cotato.squadus.domain.club.common.entity; + +import static jakarta.persistence.CascadeType.*; + +import java.util.List; + import com.cotato.squadus.domain.auth.entity.Member; import com.cotato.squadus.domain.auth.enums.Membership; import com.cotato.squadus.domain.club.common.enums.MemberType; import com.cotato.squadus.domain.club.schedule.entity.ScheduleComment; -import jakarta.persistence.*; -import lombok.Builder; + +import jakarta.persistence.DiscriminatorColumn; +import jakarta.persistence.Entity; +import jakarta.persistence.EnumType; +import jakarta.persistence.Enumerated; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.Inheritance; +import jakarta.persistence.InheritanceType; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.OneToMany; +import jakarta.persistence.Table; import lombok.Getter; import lombok.NoArgsConstructor; -import java.util.List; - -import static jakarta.persistence.CascadeType.ALL; - @Entity @Getter @Inheritance(strategy = InheritanceType.SINGLE_TABLE) @@ -20,36 +34,36 @@ @Table(name = "club_member") public abstract class ClubMember { - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - private Long clubMemberIdx; + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long clubMemberIdx; - @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "member_idx") - private Member member; + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "member_idx") + private Member member; - @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "club_id") - private Club club; + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "club_id") + private Club club; - @Enumerated(EnumType.STRING) - private Membership membership; + @Enumerated(EnumType.STRING) + private Membership membership; - private Boolean isPaid; + private Boolean isPaid; - //s3로 이미지 url 저장 - private String clubProfileImage; + //s3로 이미지 url 저장 + private String clubProfileImage; - @OneToMany(mappedBy = "clubMember", cascade = ALL) - private List scheduleComments; + @OneToMany(mappedBy = "clubMember", cascade = ALL) + private List scheduleComments; - public abstract MemberType getMemberType(); + public abstract MemberType getMemberType(); - public ClubMember(Member member, Club club, Membership membership, Boolean isPaid, String clubProfileImage) { - this.member = member; - this.club = club; - this.membership = membership; - this.isPaid = isPaid; - this.clubProfileImage = clubProfileImage; - } + public ClubMember(Member member, Club club, Membership membership, Boolean isPaid, String clubProfileImage) { + this.member = member; + this.club = club; + this.membership = membership; + this.isPaid = isPaid; + this.clubProfileImage = clubProfileImage; + } } diff --git a/src/main/java/com/cotato/squadus/domain/club/common/entity/Region.java b/src/main/java/com/cotato/squadus/domain/club/common/entity/Region.java index 33f88f6..f79b772 100644 --- a/src/main/java/com/cotato/squadus/domain/club/common/entity/Region.java +++ b/src/main/java/com/cotato/squadus/domain/club/common/entity/Region.java @@ -11,13 +11,13 @@ @NoArgsConstructor(access = AccessLevel.PROTECTED) public class Region { - private String city; // 시/도 + private String city; // 시/도 - private String district; // 군/구 + private String district; // 군/구 - @Builder - public Region(String city, String district) { - this.city = city; - this.district = district; - } + @Builder + public Region(String city, String district) { + this.city = city; + this.district = district; + } } diff --git a/src/main/java/com/cotato/squadus/domain/club/common/entity/RegularClubMember.java b/src/main/java/com/cotato/squadus/domain/club/common/entity/RegularClubMember.java index bfc5066..7204c1e 100644 --- a/src/main/java/com/cotato/squadus/domain/club/common/entity/RegularClubMember.java +++ b/src/main/java/com/cotato/squadus/domain/club/common/entity/RegularClubMember.java @@ -3,6 +3,7 @@ import com.cotato.squadus.domain.auth.entity.Member; import com.cotato.squadus.domain.auth.enums.Membership; import com.cotato.squadus.domain.club.common.enums.MemberType; + import jakarta.persistence.DiscriminatorValue; import jakarta.persistence.Entity; import lombok.Builder; @@ -15,13 +16,13 @@ @DiscriminatorValue("MEMBER") public class RegularClubMember extends ClubMember { - @Builder - public RegularClubMember(Member member, Club club, Membership membership, Boolean isPaid, String clubProfileImage) { - super(member, club, membership, isPaid, clubProfileImage); - } + @Builder + public RegularClubMember(Member member, Club club, Membership membership, Boolean isPaid, String clubProfileImage) { + super(member, club, membership, isPaid, clubProfileImage); + } - @Override - public MemberType getMemberType() { - return MemberType.MEMBER; - } + @Override + public MemberType getMemberType() { + return MemberType.MEMBER; + } } \ No newline at end of file diff --git a/src/main/java/com/cotato/squadus/domain/club/common/entity/Tier.java b/src/main/java/com/cotato/squadus/domain/club/common/entity/Tier.java index 66cf188..52756e2 100644 --- a/src/main/java/com/cotato/squadus/domain/club/common/entity/Tier.java +++ b/src/main/java/com/cotato/squadus/domain/club/common/entity/Tier.java @@ -1,7 +1,7 @@ package com.cotato.squadus.domain.club.common.entity; public enum Tier { - GOLD, - SILVER, - BRONZE + GOLD, + SILVER, + BRONZE } diff --git a/src/main/java/com/cotato/squadus/domain/club/common/enums/ClubCategory.java b/src/main/java/com/cotato/squadus/domain/club/common/enums/ClubCategory.java index 551f054..2ab2a66 100644 --- a/src/main/java/com/cotato/squadus/domain/club/common/enums/ClubCategory.java +++ b/src/main/java/com/cotato/squadus/domain/club/common/enums/ClubCategory.java @@ -2,16 +2,16 @@ public enum ClubCategory { - SCHOOL("교내"), - UNION("연합"); + SCHOOL("교내"), + UNION("연합"); - private final String description; + private final String description; - ClubCategory(String description) { - this.description = description; - } + ClubCategory(String description) { + this.description = description; + } - public String getDescription() { - return description; - } + public String getDescription() { + return description; + } } diff --git a/src/main/java/com/cotato/squadus/domain/club/common/enums/ClubTier.java b/src/main/java/com/cotato/squadus/domain/club/common/enums/ClubTier.java index 6afd300..7f786c6 100644 --- a/src/main/java/com/cotato/squadus/domain/club/common/enums/ClubTier.java +++ b/src/main/java/com/cotato/squadus/domain/club/common/enums/ClubTier.java @@ -1,7 +1,7 @@ package com.cotato.squadus.domain.club.common.enums; public enum ClubTier { - BRONZE, - SILVER, - GOLD + BRONZE, + SILVER, + GOLD } diff --git a/src/main/java/com/cotato/squadus/domain/club/common/enums/MemberType.java b/src/main/java/com/cotato/squadus/domain/club/common/enums/MemberType.java index 6265cec..5e3da35 100644 --- a/src/main/java/com/cotato/squadus/domain/club/common/enums/MemberType.java +++ b/src/main/java/com/cotato/squadus/domain/club/common/enums/MemberType.java @@ -1,5 +1,5 @@ package com.cotato.squadus.domain.club.common.enums; public enum MemberType { - ADMIN, MEMBER + ADMIN, MEMBER } diff --git a/src/main/java/com/cotato/squadus/domain/club/common/enums/SportsCategory.java b/src/main/java/com/cotato/squadus/domain/club/common/enums/SportsCategory.java index d4c4fb4..5367d12 100644 --- a/src/main/java/com/cotato/squadus/domain/club/common/enums/SportsCategory.java +++ b/src/main/java/com/cotato/squadus/domain/club/common/enums/SportsCategory.java @@ -1,29 +1,29 @@ package com.cotato.squadus.domain.club.common.enums; public enum SportsCategory { - // 구기 종목 - SOCCER, // 축구 - BASKETBALL, // 농구 - VOLLEYBALL, // 배구 - BASEBALL, // 야구 + // 구기 종목 + SOCCER, // 축구 + BASKETBALL, // 농구 + VOLLEYBALL, // 배구 + BASEBALL, // 야구 - // 라켓 스포츠 - BADMINTON, // 배드민턴 - TENNIS, // 테니스 - TABLE_TENNIS, // 탁구 + // 라켓 스포츠 + BADMINTON, // 배드민턴 + TENNIS, // 테니스 + TABLE_TENNIS, // 탁구 - // 격투 스포츠 - TAEKWONDO, // 태권도 - JUDO, // 유도 - KENDO, // 검도 + // 격투 스포츠 + TAEKWONDO, // 태권도 + JUDO, // 유도 + KENDO, // 검도 - // 육상 종목 - RUNNING, // 러닝 - CROSSFIT, // 크로스핏 - CYCLING, // 사이클 + // 육상 종목 + RUNNING, // 러닝 + CROSSFIT, // 크로스핏 + CYCLING, // 사이클 - // 수상 스포츠 - SWIMMING, // 수영 - SURFING, // 서핑 - YACHTING // 요트 + // 수상 스포츠 + SWIMMING, // 수영 + SURFING, // 서핑 + YACHTING // 요트 } diff --git a/src/main/java/com/cotato/squadus/domain/club/common/repository/ClubAdminMemberRepository.java b/src/main/java/com/cotato/squadus/domain/club/common/repository/ClubAdminMemberRepository.java index a1f464e..d670bc8 100644 --- a/src/main/java/com/cotato/squadus/domain/club/common/repository/ClubAdminMemberRepository.java +++ b/src/main/java/com/cotato/squadus/domain/club/common/repository/ClubAdminMemberRepository.java @@ -1,17 +1,19 @@ package com.cotato.squadus.domain.club.common.repository; -import com.cotato.squadus.domain.auth.enums.AdminStatus; -import com.cotato.squadus.domain.club.common.entity.ClubAdminMember; +import java.util.Optional; + import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.query.Param; -import java.util.Optional; +import com.cotato.squadus.domain.auth.enums.AdminStatus; +import com.cotato.squadus.domain.club.common.entity.ClubAdminMember; public interface ClubAdminMemberRepository extends JpaRepository { - Optional findByClubMemberIdxAndAdminStatus(Long id, AdminStatus status); + Optional findByClubMemberIdxAndAdminStatus(Long id, AdminStatus status); - @Query("SELECT cam FROM ClubAdminMember cam WHERE cam.club.clubId = :clubId AND cam.clubMemberIdx = :memberId AND cam.adminStatus = 'CURRENT'") - Optional findActiveAdminByClubIdAndClubMemberId(@Param("clubId") Long clubId, @Param("memberId") Long memberId); + @Query("SELECT cam FROM ClubAdminMember cam WHERE cam.club.clubId = :clubId AND cam.clubMemberIdx = :memberId AND cam.adminStatus = 'CURRENT'") + Optional findActiveAdminByClubIdAndClubMemberId(@Param("clubId") Long clubId, + @Param("memberId") Long memberId); } diff --git a/src/main/java/com/cotato/squadus/domain/club/common/repository/ClubApplicationRepository.java b/src/main/java/com/cotato/squadus/domain/club/common/repository/ClubApplicationRepository.java index 0e1aa12..9c01282 100644 --- a/src/main/java/com/cotato/squadus/domain/club/common/repository/ClubApplicationRepository.java +++ b/src/main/java/com/cotato/squadus/domain/club/common/repository/ClubApplicationRepository.java @@ -1,13 +1,22 @@ package com.cotato.squadus.domain.club.common.repository; -import com.cotato.squadus.domain.club.common.entity.ClubApplication; +import java.util.List; + import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; -import java.util.List; +import com.cotato.squadus.domain.club.common.entity.ClubApplication; public interface ClubApplicationRepository extends JpaRepository { - List findByRecruitingPost_PostId(Long postId); + List findByRecruitingPost_PostId(Long postId); + + List findByMember_MemberIdx(Long memberIdx); - List findByMember_MemberIdx(Long memberIdx); + @Query("SELECT ca FROM ClubApplication ca " + + "JOIN FETCH ca.recruitingPost rp " + + "JOIN FETCH rp.club c " + + "WHERE ca.member.memberIdx = :memberIdx") + List findByMember_MemberIdxFetchClubAndRecruitingPost(@Param("memberIdx") Long memberIdx); } diff --git a/src/main/java/com/cotato/squadus/domain/club/common/repository/ClubMemberRepository.java b/src/main/java/com/cotato/squadus/domain/club/common/repository/ClubMemberRepository.java index 9f629d5..c82486f 100644 --- a/src/main/java/com/cotato/squadus/domain/club/common/repository/ClubMemberRepository.java +++ b/src/main/java/com/cotato/squadus/domain/club/common/repository/ClubMemberRepository.java @@ -1,16 +1,18 @@ package com.cotato.squadus.domain.club.common.repository; -import com.cotato.squadus.domain.club.common.entity.ClubMember; -import org.springframework.data.jpa.repository.JpaRepository; - import java.util.List; import java.util.Optional; +import org.springframework.data.jpa.repository.JpaRepository; + +import com.cotato.squadus.domain.club.common.entity.ClubMember; + public interface ClubMemberRepository extends JpaRepository { - Optional findClubMemberByClubMemberIdx(Long idx); - Optional findClubMemberByMember_MemberIdxAndClub_ClubId(Long memberIdx, Long clubId); + Optional findClubMemberByClubMemberIdx(Long idx); + + Optional findClubMemberByMember_MemberIdxAndClub_ClubId(Long memberIdx, Long clubId); - List findAllByClub_ClubId(Long clubId); + List findAllByClub_ClubId(Long clubId); } \ No newline at end of file diff --git a/src/main/java/com/cotato/squadus/domain/club/common/repository/ClubRepository.java b/src/main/java/com/cotato/squadus/domain/club/common/repository/ClubRepository.java index 7e7bb10..ee7e128 100644 --- a/src/main/java/com/cotato/squadus/domain/club/common/repository/ClubRepository.java +++ b/src/main/java/com/cotato/squadus/domain/club/common/repository/ClubRepository.java @@ -2,6 +2,7 @@ import com.cotato.squadus.domain.club.common.entity.Club; import com.cotato.squadus.domain.club.common.enums.SportsCategory; + import org.springframework.data.jpa.repository.JpaRepository; import java.time.LocalDate; @@ -9,9 +10,9 @@ public interface ClubRepository extends JpaRepository { - List findBySportsCategoryOrderByMatchScoreDesc(SportsCategory sportsCategory); + List findBySportsCategoryOrderByMatchScoreDesc(SportsCategory sportsCategory); - long countBySportsCategory(SportsCategory sportsCategory); -// List findBySportsCategoryAndMatchDateBetweenOrderByMatchScoreDesc(SportsCategory sportsCategory, LocalDate startDate, LocalDate endDate); + long countBySportsCategory(SportsCategory sportsCategory); + // List findBySportsCategoryAndMatchDateBetweenOrderByMatchScoreDesc(SportsCategory sportsCategory, LocalDate startDate, LocalDate endDate); } diff --git a/src/main/java/com/cotato/squadus/domain/club/common/service/ClubService.java b/src/main/java/com/cotato/squadus/domain/club/common/service/ClubService.java index 7702277..d70127f 100644 --- a/src/main/java/com/cotato/squadus/domain/club/common/service/ClubService.java +++ b/src/main/java/com/cotato/squadus/domain/club/common/service/ClubService.java @@ -1,38 +1,50 @@ package com.cotato.squadus.domain.club.common.service; -import com.cotato.squadus.api.club.dto.*; +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; +import java.util.Optional; +import java.util.Set; +import java.util.stream.Collectors; + +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.multipart.MultipartFile; + +import com.cotato.squadus.api.club.dto.ClubApplyRequest; +import com.cotato.squadus.api.club.dto.ClubApplyResponse; +import com.cotato.squadus.api.club.dto.ClubCreateRequest; +import com.cotato.squadus.api.club.dto.ClubCreateResponse; +import com.cotato.squadus.api.club.dto.ClubInfoResponse; +import com.cotato.squadus.api.club.dto.ClubRankResponse; +import com.cotato.squadus.api.club.dto.ClubUpdateRequest; +import com.cotato.squadus.api.club.dto.ClubUpdateResponse; import com.cotato.squadus.common.config.auth.CustomOAuth2Member; import com.cotato.squadus.common.s3.S3ImageService; +import com.cotato.squadus.domain.auth.entity.Member; import com.cotato.squadus.domain.auth.enums.AdminStatus; +import com.cotato.squadus.domain.auth.enums.ApplicationStatus; import com.cotato.squadus.domain.auth.enums.Membership; -import com.cotato.squadus.domain.auth.repository.MemberRepository; import com.cotato.squadus.domain.auth.service.ClubMemberService; import com.cotato.squadus.domain.auth.service.MemberService; import com.cotato.squadus.domain.club.admin.service.ClubAdminService; +import com.cotato.squadus.domain.club.common.entity.Club; import com.cotato.squadus.domain.club.common.entity.ClubAdminMember; +import com.cotato.squadus.domain.club.common.entity.ClubApplication; import com.cotato.squadus.domain.club.common.entity.Region; import com.cotato.squadus.domain.club.common.enums.ClubCategory; import com.cotato.squadus.domain.club.common.enums.ClubTier; import com.cotato.squadus.domain.club.common.enums.SportsCategory; import com.cotato.squadus.domain.club.common.repository.ClubApplicationRepository; import com.cotato.squadus.domain.club.common.repository.ClubRepository; -import com.cotato.squadus.domain.auth.enums.ApplicationStatus; -import com.cotato.squadus.domain.club.common.entity.Club; -import com.cotato.squadus.domain.club.common.entity.ClubApplication; -import com.cotato.squadus.domain.auth.entity.Member; import com.cotato.squadus.domain.club.recruit.entity.RecruitingPost; import com.cotato.squadus.domain.club.recruit.repository.RecruitingPostRepository; + import jakarta.persistence.EntityNotFoundException; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.springframework.data.redis.core.RedisTemplate; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; -import org.springframework.web.multipart.MultipartFile; - -import java.util.*; -import java.time.LocalDateTime; -import java.util.stream.Collectors; @Slf4j @Service @@ -40,284 +52,285 @@ @RequiredArgsConstructor public class ClubService { - private final ClubRepository clubRepository; - private final ClubApplicationRepository clubApplicationRepository; - private final RedisTemplate redisTemplate; - private final ClubMemberService clubMemberService; - private final ClubAdminService clubAdminService; - private final MemberService memberService; - private final S3ImageService s3ImageService; - private final RecruitingPostRepository recruitingPostRepository; - - @Transactional - public ClubCreateResponse createClub(CustomOAuth2Member customOAuth2Member, ClubCreateRequest clubCreateRequest, MultipartFile logoImage) { - - Member member = memberService.findMemberByUniqueId(customOAuth2Member.getUniqueId()); - - // logo 설정 - String logo = null; - if (logoImage != null && !logoImage.isEmpty()) { - logo = s3ImageService.upload(logoImage); - } else { - logo = "default_logo.jpg"; // 기본 로고 이미지 URL - } - - // ClubCategory에 따른 university 값 설정 - String university; - if (clubCreateRequest.getClubCategory() == ClubCategory.UNION) { - university = "no university"; - } else { - university = member.getUniversity(); - } - - Club club = Club.builder() - .clubName(clubCreateRequest.getClubName()) - .university(university) - .clubCategory(clubCreateRequest.getClubCategory()) - .sportsCategory(clubCreateRequest.getSportsCategory()) - .logo(logo) - .clubTier(ClubTier.BRONZE) - .clubMessage(clubCreateRequest.getClubMessage()) - .maxMembers(clubCreateRequest.getMaxMembers()) - .tags(clubCreateRequest.getTags()) - .region(Region.builder() - .city(clubCreateRequest.getCity()) - .district(clubCreateRequest.getDistrict()) - .build()) - .build(); - - ClubAdminMember clubAdminMember = ClubAdminMember.builder() - .member(member) - .club(club) - .membership(Membership.JOINED) - .clubProfileImage("default.jpg") - .adminStatus(AdminStatus.CURRENT) - .isPaid(false) - .build(); - - clubMemberService.saveClubMember(clubAdminMember); - - club.addClubMember(clubAdminMember); - Club savedClub = clubRepository.save(club); - - updateClubScore(club.getSportsCategory(), club.getClubId(), club.getMatchScore()); - - log.info("동아리 생성됨, clubId : {}", savedClub.getClubId()); - return new ClubCreateResponse(savedClub.getClubId()); - } - - @Transactional - public ClubApplyResponse joinClub(CustomOAuth2Member customOAuth2Member, Long clubId, ClubApplyRequest clubApplyRequest) { - Club club = clubRepository.findById(clubId) - .orElseThrow(() -> new EntityNotFoundException("해당 고유번호를 가진 동아리를 찾을 수 없습니다.")); - Member member = memberService.findMemberByUniqueId(customOAuth2Member.getUniqueId()); - - RecruitingPost recruitingPost = recruitingPostRepository.findById(clubApplyRequest.getRecruitingPostId()) - .orElseThrow(() -> new EntityNotFoundException("해당 고유번호를 가진 홍보 게시글을 찾을 수 없습니다.")); - - ClubApplication clubApplication = ClubApplication.builder() - .member(member) - .club(club) - .appliedAt(LocalDateTime.now()) - .applicationStatus(ApplicationStatus.PENDING) - .questions(recruitingPost.getQuestions()) - .answers(clubApplyRequest.getAnswers()) - .recruitingPost(recruitingPost) - .build(); - - ClubApplication savedApplication = clubApplicationRepository.save(clubApplication); - return new ClubApplyResponse(savedApplication.getApplicationIdx()); - } - - public Club findClubByClubId(Long clubId) { - - Club club = clubRepository.findById(clubId) - .orElseThrow(() -> new EntityNotFoundException("해당 고유번호를 가진 동아리를 찾을 수 없습니다.")); - - return club; - } - - public ClubInfoResponse findClubInfo(Long clubId) { - - Club club = clubRepository.findById(clubId) - .orElseThrow(() -> new EntityNotFoundException("해당 고유번호를 가진 동아리를 찾을 수 없습니다.")); - - ClubInfoResponse clubInfoResponse = ClubInfoResponse.from(club); - return clubInfoResponse; - } - - - @Transactional - public ClubUpdateResponse updateClub(CustomOAuth2Member customOAuth2Member, Long clubId, ClubUpdateRequest clubUpdateRequest, MultipartFile logoImage) { - clubAdminService.validateAdminMember(clubId); - - Club club = clubRepository.findById(clubId) - .orElseThrow(() -> new EntityNotFoundException("해당 clubId를 가진 동아리가 존재하지 않습니다.")); - - // logo 설정 - String logo = club.getLogo(); - if (logoImage != null && !logoImage.isEmpty()) { - logo = s3ImageService.upload(logoImage); - } - - Club updateClub = club.updateClub( - logo, - clubUpdateRequest.clubMessage(), - Region.builder() - .city(clubUpdateRequest.city()) - .district(clubUpdateRequest.district()) - .build(), - clubUpdateRequest.maxMembers(), - clubUpdateRequest.tags() - ); - - Club savedClub = clubRepository.save(updateClub); - - return new ClubUpdateResponse(savedClub.getClubId()); - } - - - public void updateClubScore(SportsCategory category, Long clubId, int matchScore) { - String key = "ranking:" + category.name(); - redisTemplate.opsForZSet().add(key, clubId.toString(), matchScore); - } - - @Transactional - public void updateClubMatchScore(Long clubId) { - Club club = clubRepository.findById(clubId) - .orElseThrow(() -> new EntityNotFoundException("동아리를 찾을 수 없습니다.")); - - // Redis에 업데이트 - updateClubScore(club.getSportsCategory(), club.getClubId(), club.getMatchScore()); - } - - - public List getRanking(SportsCategory category) { - String key = "ranking:" + category.name(); - Set clubIds = redisTemplate.opsForZSet().reverseRange(key, 0, -1); // 높은 점수 순으로 가져옴 - - // 클럽이 5개 미만이라면 티어 업데이트를 하지 않고 BRONZE로 유지 - if (clubIds.size() < 5) { - return clubIds.stream() - .map(clubId -> clubRepository.findById(Long.parseLong(clubId)) - .map(club -> new ClubRankResponse(club.getClubName(), club.getLogo(), club.getMatchScore(), club.getClubRank(), 0)) - .orElseThrow(() -> new EntityNotFoundException("동아리를 찾을 수 없습니다."))) - .collect(Collectors.toList()); - } - - List rankingResponses = new ArrayList<>(); - int rank = 1; - - List clubs = clubIds.stream() - .map(Long::parseLong) - .map(clubRepository::findById) - .map(Optional::get) - .sorted(Comparator.comparingInt(Club::getMatchScore).reversed() // 먼저 점수 기준으로 정렬 - .thenComparing(Club::getClubId)) // 점수가 같으면 clubId 기준으로 정렬 - .collect(Collectors.toList()); - - int totalClubs = clubs.size(); - int goldCutoff = (int) Math.ceil(totalClubs * 0.2); - int silverCutoff = (int) Math.ceil(totalClubs * 0.5); - - for (Club club : clubs) { - // 기존 랭킹 정보와 비교하여 순위 변동 계산 - int previousRank = club.getClubRank() != null ? club.getClubRank() : rank; - int rankChange = previousRank - rank; - - // ClubRankResponse로 변환 - ClubRankResponse response = new ClubRankResponse( - club.getClubName(), - club.getLogo(), - club.getMatchScore(), - rank, - rankChange - ); - - // 현재 랭킹을 Club 엔티티에 저장 - club.updateClubRank(rank); - - // 티어 갱신 - if (rank <= goldCutoff) { - club.updateTier(ClubTier.GOLD); - } else if (rank <= silverCutoff) { - club.updateTier(ClubTier.SILVER); - } else { - club.updateTier(ClubTier.BRONZE); - } - - rankingResponses.add(response); - rank++; - } - - clubRepository.saveAll(clubs); - - return rankingResponses; - } - - - //특정 동아리에서 matchScore가 업데이트 될 때, tier도 변경 - public List updateTier(SportsCategory category) { - String key = "ranking:" + category.name(); - Set clubIds = redisTemplate.opsForZSet().reverseRange(key, 0, -1); // 높은 점수 순으로 가져옴 - - // 클럽이 5개 미만이라면 티어 업데이트를 하지 않고 BRONZE로 유지 - if (clubIds.size() < 5) { - return clubIds.stream() - .map(clubId -> clubRepository.findById(Long.parseLong(clubId)) - .map(club -> new ClubRankResponse(club.getClubName(), club.getLogo(), club.getMatchScore(), club.getClubRank(), 0)) - .orElseThrow(() -> new EntityNotFoundException("동아리를 찾을 수 없습니다."))) - .collect(Collectors.toList()); - } - - List rankingResponses = new ArrayList<>(); - int rank = 1; - - List clubs = clubIds.stream() - .map(Long::parseLong) - .map(clubRepository::findById) - .map(Optional::get) - .sorted(Comparator.comparingInt(Club::getMatchScore).reversed() // 먼저 점수 기준으로 정렬 - .thenComparing(Club::getClubId)) // 점수가 같으면 clubId 기준으로 정렬 - .collect(Collectors.toList()); - - int totalClubs = clubs.size(); - int goldCutoff = (int) Math.ceil(totalClubs * 0.2); - int silverCutoff = (int) Math.ceil(totalClubs * 0.5); - - for (Club club : clubs) { - // 기존 랭킹 정보와 비교하여 순위 변동 계산 - int previousRank = club.getClubRank() != null ? club.getClubRank() : rank; - int rankChange = previousRank - rank; - - // ClubRankResponse로 변환 - ClubRankResponse response = new ClubRankResponse( - club.getClubName(), - club.getLogo(), - club.getMatchScore(), - rank, - rankChange - ); - - // 현재 랭킹을 Club 엔티티에 저장 - club.updateClubRank(rank); - - // 티어 갱신 - if (rank <= goldCutoff) { - club.updateTier(ClubTier.GOLD); - } else if (rank <= silverCutoff) { - club.updateTier(ClubTier.SILVER); - } else { - club.updateTier(ClubTier.BRONZE); - } - - rankingResponses.add(response); - rank++; - } - - clubRepository.saveAll(clubs); - - return rankingResponses; - } + private final ClubRepository clubRepository; + private final ClubApplicationRepository clubApplicationRepository; + private final RedisTemplate redisTemplate; + private final ClubMemberService clubMemberService; + private final ClubAdminService clubAdminService; + private final MemberService memberService; + private final S3ImageService s3ImageService; + private final RecruitingPostRepository recruitingPostRepository; + + @Transactional + public ClubCreateResponse createClub(CustomOAuth2Member customOAuth2Member, ClubCreateRequest clubCreateRequest, + MultipartFile logoImage) { + + Member member = memberService.findMemberByUniqueId(customOAuth2Member.getUniqueId()); + + // logo 설정 + String logo = null; + if (logoImage != null && !logoImage.isEmpty()) { + logo = s3ImageService.upload(logoImage); + } else { + logo = "default_logo.jpg"; // 기본 로고 이미지 URL + } + + // ClubCategory에 따른 university 값 설정 + String university; + if (clubCreateRequest.getClubCategory() == ClubCategory.UNION) { + university = "no university"; + } else { + university = member.getUniversity(); + } + + Club club = Club.builder() + .clubName(clubCreateRequest.getClubName()) + .university(university) + .clubCategory(clubCreateRequest.getClubCategory()) + .sportsCategory(clubCreateRequest.getSportsCategory()) + .logo(logo) + .clubTier(ClubTier.BRONZE) + .clubMessage(clubCreateRequest.getClubMessage()) + .maxMembers(clubCreateRequest.getMaxMembers()) + .tags(clubCreateRequest.getTags()) + .region(Region.builder() + .city(clubCreateRequest.getCity()) + .district(clubCreateRequest.getDistrict()) + .build()) + .build(); + + ClubAdminMember clubAdminMember = ClubAdminMember.builder() + .member(member) + .club(club) + .membership(Membership.JOINED) + .clubProfileImage("default.jpg") + .adminStatus(AdminStatus.CURRENT) + .isPaid(false) + .build(); + + clubMemberService.saveClubMember(clubAdminMember); + + club.addClubMember(clubAdminMember); + Club savedClub = clubRepository.save(club); + + updateClubScore(club.getSportsCategory(), club.getClubId(), club.getMatchScore()); + + log.info("동아리 생성됨, clubId : {}", savedClub.getClubId()); + return new ClubCreateResponse(savedClub.getClubId()); + } + + @Transactional + public ClubApplyResponse joinClub(CustomOAuth2Member customOAuth2Member, Long clubId, + ClubApplyRequest clubApplyRequest) { + Club club = clubRepository.findById(clubId) + .orElseThrow(() -> new EntityNotFoundException("해당 고유번호를 가진 동아리를 찾을 수 없습니다.")); + Member member = memberService.findMemberByUniqueId(customOAuth2Member.getUniqueId()); + + RecruitingPost recruitingPost = recruitingPostRepository.findById(clubApplyRequest.getRecruitingPostId()) + .orElseThrow(() -> new EntityNotFoundException("해당 고유번호를 가진 홍보 게시글을 찾을 수 없습니다.")); + + ClubApplication clubApplication = ClubApplication.builder() + .member(member) + .club(club) + .appliedAt(LocalDateTime.now()) + .applicationStatus(ApplicationStatus.PENDING) + .questions(recruitingPost.getQuestions()) + .answers(clubApplyRequest.getAnswers()) + .recruitingPost(recruitingPost) + .build(); + + ClubApplication savedApplication = clubApplicationRepository.save(clubApplication); + return new ClubApplyResponse(savedApplication.getApplicationIdx()); + } + + public Club findClubByClubId(Long clubId) { + + Club club = clubRepository.findById(clubId) + .orElseThrow(() -> new EntityNotFoundException("해당 고유번호를 가진 동아리를 찾을 수 없습니다.")); + + return club; + } + + public ClubInfoResponse findClubInfo(Long clubId) { + + Club club = clubRepository.findById(clubId) + .orElseThrow(() -> new EntityNotFoundException("해당 고유번호를 가진 동아리를 찾을 수 없습니다.")); + + ClubInfoResponse clubInfoResponse = ClubInfoResponse.from(club); + return clubInfoResponse; + } + + @Transactional + public ClubUpdateResponse updateClub(CustomOAuth2Member customOAuth2Member, Long clubId, + ClubUpdateRequest clubUpdateRequest, MultipartFile logoImage) { + clubAdminService.validateAdminMember(clubId); + + Club club = clubRepository.findById(clubId) + .orElseThrow(() -> new EntityNotFoundException("해당 clubId를 가진 동아리가 존재하지 않습니다.")); + + // logo 설정 + String logo = club.getLogo(); + if (logoImage != null && !logoImage.isEmpty()) { + logo = s3ImageService.upload(logoImage); + } + + Club updateClub = club.updateClub( + logo, + clubUpdateRequest.clubMessage(), + Region.builder() + .city(clubUpdateRequest.city()) + .district(clubUpdateRequest.district()) + .build(), + clubUpdateRequest.maxMembers(), + clubUpdateRequest.tags() + ); + + Club savedClub = clubRepository.save(updateClub); + + return new ClubUpdateResponse(savedClub.getClubId()); + } + + public void updateClubScore(SportsCategory category, Long clubId, int matchScore) { + String key = "ranking:" + category.name(); + redisTemplate.opsForZSet().add(key, clubId.toString(), matchScore); + } + + @Transactional + public void updateClubMatchScore(Long clubId) { + Club club = clubRepository.findById(clubId) + .orElseThrow(() -> new EntityNotFoundException("동아리를 찾을 수 없습니다.")); + + // Redis에 업데이트 + updateClubScore(club.getSportsCategory(), club.getClubId(), club.getMatchScore()); + } + + public List getRanking(SportsCategory category) { + String key = "ranking:" + category.name(); + Set clubIds = redisTemplate.opsForZSet().reverseRange(key, 0, -1); // 높은 점수 순으로 가져옴 + + // 클럽이 5개 미만이라면 티어 업데이트를 하지 않고 BRONZE로 유지 + if (clubIds.size() < 5) { + return clubIds.stream() + .map(clubId -> clubRepository.findById(Long.parseLong(clubId)) + .map(club -> new ClubRankResponse(club.getClubName(), club.getLogo(), club.getMatchScore(), + club.getClubRank(), 0)) + .orElseThrow(() -> new EntityNotFoundException("동아리를 찾을 수 없습니다."))) + .collect(Collectors.toList()); + } + + List rankingResponses = new ArrayList<>(); + int rank = 1; + + List clubs = clubIds.stream() + .map(Long::parseLong) + .map(clubRepository::findById) + .map(Optional::get) + .sorted(Comparator.comparingInt(Club::getMatchScore).reversed() // 먼저 점수 기준으로 정렬 + .thenComparing(Club::getClubId)) // 점수가 같으면 clubId 기준으로 정렬 + .collect(Collectors.toList()); + + int totalClubs = clubs.size(); + int goldCutoff = (int)Math.ceil(totalClubs * 0.2); + int silverCutoff = (int)Math.ceil(totalClubs * 0.5); + + for (Club club : clubs) { + // 기존 랭킹 정보와 비교하여 순위 변동 계산 + int previousRank = club.getClubRank() != null ? club.getClubRank() : rank; + int rankChange = previousRank - rank; + + // ClubRankResponse로 변환 + ClubRankResponse response = new ClubRankResponse( + club.getClubName(), + club.getLogo(), + club.getMatchScore(), + rank, + rankChange + ); + + // 현재 랭킹을 Club 엔티티에 저장 + club.updateClubRank(rank); + + // 티어 갱신 + if (rank <= goldCutoff) { + club.updateTier(ClubTier.GOLD); + } else if (rank <= silverCutoff) { + club.updateTier(ClubTier.SILVER); + } else { + club.updateTier(ClubTier.BRONZE); + } + + rankingResponses.add(response); + rank++; + } + + clubRepository.saveAll(clubs); + + return rankingResponses; + } + + //특정 동아리에서 matchScore가 업데이트 될 때, tier도 변경 + public List updateTier(SportsCategory category) { + String key = "ranking:" + category.name(); + Set clubIds = redisTemplate.opsForZSet().reverseRange(key, 0, -1); // 높은 점수 순으로 가져옴 + + // 클럽이 5개 미만이라면 티어 업데이트를 하지 않고 BRONZE로 유지 + if (clubIds.size() < 5) { + return clubIds.stream() + .map(clubId -> clubRepository.findById(Long.parseLong(clubId)) + .map(club -> new ClubRankResponse(club.getClubName(), club.getLogo(), club.getMatchScore(), + club.getClubRank(), 0)) + .orElseThrow(() -> new EntityNotFoundException("동아리를 찾을 수 없습니다."))) + .collect(Collectors.toList()); + } + + List rankingResponses = new ArrayList<>(); + int rank = 1; + + List clubs = clubIds.stream() + .map(Long::parseLong) + .map(clubRepository::findById) + .map(Optional::get) + .sorted(Comparator.comparingInt(Club::getMatchScore).reversed() // 먼저 점수 기준으로 정렬 + .thenComparing(Club::getClubId)) // 점수가 같으면 clubId 기준으로 정렬 + .collect(Collectors.toList()); + + int totalClubs = clubs.size(); + int goldCutoff = (int)Math.ceil(totalClubs * 0.2); + int silverCutoff = (int)Math.ceil(totalClubs * 0.5); + + for (Club club : clubs) { + // 기존 랭킹 정보와 비교하여 순위 변동 계산 + int previousRank = club.getClubRank() != null ? club.getClubRank() : rank; + int rankChange = previousRank - rank; + + // ClubRankResponse로 변환 + ClubRankResponse response = new ClubRankResponse( + club.getClubName(), + club.getLogo(), + club.getMatchScore(), + rank, + rankChange + ); + + // 현재 랭킹을 Club 엔티티에 저장 + club.updateClubRank(rank); + + // 티어 갱신 + if (rank <= goldCutoff) { + club.updateTier(ClubTier.GOLD); + } else if (rank <= silverCutoff) { + club.updateTier(ClubTier.SILVER); + } else { + club.updateTier(ClubTier.BRONZE); + } + + rankingResponses.add(response); + rank++; + } + + clubRepository.saveAll(clubs); + + return rankingResponses; + } } diff --git a/src/main/java/com/cotato/squadus/domain/club/fee/entity/FeePayment.java b/src/main/java/com/cotato/squadus/domain/club/fee/entity/FeePayment.java index 9dfc60e..a5d7406 100644 --- a/src/main/java/com/cotato/squadus/domain/club/fee/entity/FeePayment.java +++ b/src/main/java/com/cotato/squadus/domain/club/fee/entity/FeePayment.java @@ -1,8 +1,13 @@ package com.cotato.squadus.domain.club.fee.entity; - import com.cotato.squadus.domain.club.common.entity.ClubMember; -import jakarta.persistence.*; + +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.Table; import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; @@ -13,28 +18,28 @@ @Table(name = "fee_payment") public class FeePayment { - @Id - @GeneratedValue - private Long feePaymentId; + @Id + @GeneratedValue + private Long feePaymentId; - private Boolean isPaid; + private Boolean isPaid; - @ManyToOne - @JoinColumn(name = "fee_type_id") - private FeeType feeType; + @ManyToOne + @JoinColumn(name = "fee_type_id") + private FeeType feeType; - @ManyToOne - @JoinColumn(name = "club_member_idx") - private ClubMember clubMember; + @ManyToOne + @JoinColumn(name = "club_member_idx") + private ClubMember clubMember; - public void updateIsPaid(Boolean isPaid) { - this.isPaid = isPaid; - } + public void updateIsPaid(Boolean isPaid) { + this.isPaid = isPaid; + } - @Builder - public FeePayment(Boolean isPaid, FeeType feeType, ClubMember clubMember) { - this.isPaid = isPaid; - this.feeType = feeType; - this.clubMember = clubMember; - } + @Builder + public FeePayment(Boolean isPaid, FeeType feeType, ClubMember clubMember) { + this.isPaid = isPaid; + this.feeType = feeType; + this.clubMember = clubMember; + } } diff --git a/src/main/java/com/cotato/squadus/domain/club/fee/entity/FeeType.java b/src/main/java/com/cotato/squadus/domain/club/fee/entity/FeeType.java index c6fbbe0..8d19fa0 100644 --- a/src/main/java/com/cotato/squadus/domain/club/fee/entity/FeeType.java +++ b/src/main/java/com/cotato/squadus/domain/club/fee/entity/FeeType.java @@ -1,93 +1,110 @@ package com.cotato.squadus.domain.club.fee.entity; +import static jakarta.persistence.CascadeType.*; +import static jakarta.persistence.FetchType.*; + +import java.time.LocalDate; +import java.util.ArrayList; +import java.util.List; + import com.cotato.squadus.common.entity.BaseTimeEntity; import com.cotato.squadus.domain.club.common.entity.Club; import com.cotato.squadus.domain.club.common.entity.ClubMember; import com.cotato.squadus.domain.club.fee.enums.FeeCategory; -import jakarta.persistence.*; + +import jakarta.persistence.Entity; +import jakarta.persistence.EnumType; +import jakarta.persistence.Enumerated; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.OneToMany; +import jakarta.persistence.Table; import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; -import java.time.LocalDate; -import java.util.ArrayList; -import java.util.List; - -import static jakarta.persistence.CascadeType.ALL; -import static jakarta.persistence.FetchType.LAZY; - @Entity @Getter @NoArgsConstructor @Table(name = "fee_type") public class FeeType extends BaseTimeEntity { - @Id - @GeneratedValue - private Long feeTypeId; - - private String feeTypeName; - - private Long price; // 인당 내야할 금액 - - @Enumerated(EnumType.STRING) - private FeeCategory feeCategory; - - private LocalDate startDate; - - private LocalDate endDate; - - private String memo; - - private Long totalPrice; // 납부 총 금액 - private Long balance; // 잔액 - - @ManyToOne - @JoinColumn(name = "club_id") - private Club club; - - @OneToMany(mappedBy = "feeType", fetch = LAZY, cascade = ALL) - private List feePayments = new ArrayList<>(); - - @OneToMany(mappedBy = "feeType", fetch = LAZY, cascade = ALL) - private List feeUsages = new ArrayList<>(); - - public void updateFeePayments(FeePayment feePayment) { - this.feePayments.add(feePayment); - } - - public void updateFeeUsages(FeeUsage feeUsage) { - this.feeUsages.add(feeUsage); - } - - public void updateTotalPrice(Long totalPrice) { - this.totalPrice = totalPrice; - } - - @Builder - public FeeType(Club club, String feeTypeName, Long price, String memo, List clubMembers, FeeCategory feeCategory, LocalDate startDate, LocalDate endDate, Long totalPrice, Long balance) { - this.club = club; - this.feeTypeName = feeTypeName; - this.price = price; - this.memo = memo; - this.feeCategory = feeCategory; - this.startDate = startDate; - this.endDate = endDate; - this.totalPrice = totalPrice; - this.balance = balance; - } - - public void update(String feeTypeName, Long price, String memo, FeeCategory feeCategory, LocalDate startDate, LocalDate endDate) { - if (feeTypeName != null) this.feeTypeName = feeTypeName; - if (price != null) this.price = price; - if (memo != null) this.memo = memo; - if (feeCategory != null) this.feeCategory = feeCategory; - if (startDate != null) this.startDate = startDate; - if (endDate != null) this.endDate = endDate; - } - - - public void updateBalance(Long price) { - this.balance += price; - } + @Id + @GeneratedValue + private Long feeTypeId; + + private String feeTypeName; + + private Long price; // 인당 내야할 금액 + + @Enumerated(EnumType.STRING) + private FeeCategory feeCategory; + + private LocalDate startDate; + + private LocalDate endDate; + + private String memo; + + private Long totalPrice; // 납부 총 금액 + private Long balance; // 잔액 + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "club_id") + private Club club; + + @OneToMany(mappedBy = "feeType", fetch = LAZY, cascade = ALL) + private List feePayments = new ArrayList<>(); + + @OneToMany(mappedBy = "feeType", fetch = LAZY, cascade = ALL) + private List feeUsages = new ArrayList<>(); + + public void updateFeePayments(FeePayment feePayment) { + this.feePayments.add(feePayment); + } + + public void updateFeeUsages(FeeUsage feeUsage) { + this.feeUsages.add(feeUsage); + } + + public void updateTotalPrice(Long totalPrice) { + this.totalPrice = totalPrice; + } + + @Builder + public FeeType(Club club, String feeTypeName, Long price, String memo, List clubMembers, + FeeCategory feeCategory, LocalDate startDate, LocalDate endDate, Long totalPrice, Long balance) { + this.club = club; + this.feeTypeName = feeTypeName; + this.price = price; + this.memo = memo; + this.feeCategory = feeCategory; + this.startDate = startDate; + this.endDate = endDate; + this.totalPrice = totalPrice; + this.balance = balance; + } + + public void update(String feeTypeName, Long price, String memo, FeeCategory feeCategory, LocalDate startDate, + LocalDate endDate) { + if (feeTypeName != null) + this.feeTypeName = feeTypeName; + if (price != null) + this.price = price; + if (memo != null) + this.memo = memo; + if (feeCategory != null) + this.feeCategory = feeCategory; + if (startDate != null) + this.startDate = startDate; + if (endDate != null) + this.endDate = endDate; + } + + public void updateBalance(Long price) { + this.balance += price; + } } diff --git a/src/main/java/com/cotato/squadus/domain/club/fee/entity/FeeUsage.java b/src/main/java/com/cotato/squadus/domain/club/fee/entity/FeeUsage.java index 23b9b26..252320b 100644 --- a/src/main/java/com/cotato/squadus/domain/club/fee/entity/FeeUsage.java +++ b/src/main/java/com/cotato/squadus/domain/club/fee/entity/FeeUsage.java @@ -1,38 +1,42 @@ package com.cotato.squadus.domain.club.fee.entity; +import java.time.LocalDate; -import jakarta.persistence.*; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.Table; import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; -import java.time.LocalDate; - @Entity @Getter @NoArgsConstructor @Table(name = "fee_usage") public class FeeUsage { - @Id - @GeneratedValue - private Long feeUsageId; + @Id + @GeneratedValue + private Long feeUsageId; - private String description; // 사용 내역 + private String description; // 사용 내역 - private LocalDate usedAt; + private LocalDate usedAt; - private Long price; + private Long price; - @ManyToOne - @JoinColumn(name = "fee_type_id") - private FeeType feeType; + @ManyToOne + @JoinColumn(name = "fee_type_id") + private FeeType feeType; - @Builder - public FeeUsage(String description, LocalDate usedAt, Long price, FeeType feeType) { - this.feeType = feeType; - this.description = description; - this.usedAt = usedAt; - this.price = price; - } + @Builder + public FeeUsage(String description, LocalDate usedAt, Long price, FeeType feeType) { + this.feeType = feeType; + this.description = description; + this.usedAt = usedAt; + this.price = price; + } } diff --git a/src/main/java/com/cotato/squadus/domain/club/fee/enums/FeeCategory.java b/src/main/java/com/cotato/squadus/domain/club/fee/enums/FeeCategory.java index 01d1ef6..abc2856 100644 --- a/src/main/java/com/cotato/squadus/domain/club/fee/enums/FeeCategory.java +++ b/src/main/java/com/cotato/squadus/domain/club/fee/enums/FeeCategory.java @@ -2,5 +2,5 @@ public enum FeeCategory { - REGULAR, EVENT + REGULAR, EVENT } diff --git a/src/main/java/com/cotato/squadus/domain/club/fee/repository/FeePaymentRepository.java b/src/main/java/com/cotato/squadus/domain/club/fee/repository/FeePaymentRepository.java index 2bbb195..562d3b9 100644 --- a/src/main/java/com/cotato/squadus/domain/club/fee/repository/FeePaymentRepository.java +++ b/src/main/java/com/cotato/squadus/domain/club/fee/repository/FeePaymentRepository.java @@ -1,12 +1,13 @@ package com.cotato.squadus.domain.club.fee.repository; +import java.util.List; -import com.cotato.squadus.domain.club.fee.entity.FeePayment; import org.springframework.data.jpa.repository.JpaRepository; -import java.util.List; + +import com.cotato.squadus.domain.club.fee.entity.FeePayment; public interface FeePaymentRepository extends JpaRepository { - List findAllByFeeType_FeeTypeId(Long feeTypeId); + List findAllByFeeType_FeeTypeId(Long feeTypeId); } diff --git a/src/main/java/com/cotato/squadus/domain/club/fee/repository/FeeTypeRepository.java b/src/main/java/com/cotato/squadus/domain/club/fee/repository/FeeTypeRepository.java index 1101669..2677d2c 100644 --- a/src/main/java/com/cotato/squadus/domain/club/fee/repository/FeeTypeRepository.java +++ b/src/main/java/com/cotato/squadus/domain/club/fee/repository/FeeTypeRepository.java @@ -1,11 +1,12 @@ package com.cotato.squadus.domain.club.fee.repository; -import com.cotato.squadus.domain.club.fee.entity.FeeType; +import java.util.List; + import org.springframework.data.jpa.repository.JpaRepository; -import java.util.List; +import com.cotato.squadus.domain.club.fee.entity.FeeType; public interface FeeTypeRepository extends JpaRepository { - List findAllByClub_ClubId(Long clubId); + List findAllByClub_ClubId(Long clubId); } diff --git a/src/main/java/com/cotato/squadus/domain/club/fee/repository/FeeUsageRepository.java b/src/main/java/com/cotato/squadus/domain/club/fee/repository/FeeUsageRepository.java index 6286c70..8cdc6c4 100644 --- a/src/main/java/com/cotato/squadus/domain/club/fee/repository/FeeUsageRepository.java +++ b/src/main/java/com/cotato/squadus/domain/club/fee/repository/FeeUsageRepository.java @@ -1,14 +1,15 @@ package com.cotato.squadus.domain.club.fee.repository; -import com.cotato.squadus.domain.club.fee.entity.FeeType; -import com.cotato.squadus.domain.club.fee.entity.FeeUsage; +import java.util.List; + import org.springframework.data.jpa.repository.JpaRepository; -import java.util.List; +import com.cotato.squadus.domain.club.fee.entity.FeeType; +import com.cotato.squadus.domain.club.fee.entity.FeeUsage; public interface FeeUsageRepository extends JpaRepository { - List findAllByFeeType(FeeType feeType); + List findAllByFeeType(FeeType feeType); - List findAllByFeeType_Club_ClubId(Long clubId); + List findAllByFeeType_Club_ClubId(Long clubId); } diff --git a/src/main/java/com/cotato/squadus/domain/club/fee/service/ClubFeeService.java b/src/main/java/com/cotato/squadus/domain/club/fee/service/ClubFeeService.java index c744d7b..9e3c3c0 100644 --- a/src/main/java/com/cotato/squadus/domain/club/fee/service/ClubFeeService.java +++ b/src/main/java/com/cotato/squadus/domain/club/fee/service/ClubFeeService.java @@ -1,6 +1,28 @@ package com.cotato.squadus.domain.club.fee.service; -import com.cotato.squadus.api.fee.dto.*; +import java.time.LocalDate; +import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import com.cotato.squadus.api.fee.dto.ClubFeeCreateRequest; +import com.cotato.squadus.api.fee.dto.ClubFeeCreateResponse; +import com.cotato.squadus.api.fee.dto.ClubFeePaymentInfoResponse; +import com.cotato.squadus.api.fee.dto.ClubFeePaymentInfoResponseList; +import com.cotato.squadus.api.fee.dto.ClubFeePaymentUpdateRequest; +import com.cotato.squadus.api.fee.dto.ClubFeePaymentUpdateResponse; +import com.cotato.squadus.api.fee.dto.ClubFeeSummaryResponse; +import com.cotato.squadus.api.fee.dto.ClubFeeSummaryResponseList; +import com.cotato.squadus.api.fee.dto.ClubFeeUsageCreateResponse; +import com.cotato.squadus.api.fee.dto.ClubFeeUsageRequest; +import com.cotato.squadus.api.fee.dto.ClubFeeUsageResponse; +import com.cotato.squadus.api.fee.dto.ClubFeeUsageResponseList; +import com.cotato.squadus.api.fee.dto.DateGroupedClubFeeUsageResponse; import com.cotato.squadus.common.config.auth.CustomOAuth2Member; import com.cotato.squadus.common.error.ErrorCode; import com.cotato.squadus.common.error.exception.AppException; @@ -16,18 +38,10 @@ import com.cotato.squadus.domain.club.fee.repository.FeePaymentRepository; import com.cotato.squadus.domain.club.fee.repository.FeeTypeRepository; import com.cotato.squadus.domain.club.fee.repository.FeeUsageRepository; + import jakarta.persistence.EntityNotFoundException; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -import java.time.LocalDate; -import java.util.ArrayList; -import java.util.Comparator; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; @Slf4j @Service @@ -35,214 +49,219 @@ @RequiredArgsConstructor public class ClubFeeService { - private final FeeTypeRepository feeTypeRepository; - private final FeePaymentRepository feePaymentRepository; - private final ClubMemberService clubMemberService; - private final ClubService clubService; - private final FeeUsageRepository feeUsageRepository; - private final MemberService memberService; - - - public ClubFeeSummaryResponseList findAllClubFeeTypesSummary(CustomOAuth2Member customOAuth2Member, Long clubId) { - - List clubFeeSummaryResponseList = feeTypeRepository.findAllByClub_ClubId(clubId) - .stream(). - map(ClubFeeSummaryResponse::from) - .toList(); - - Long totalBalance = clubFeeSummaryResponseList.stream() - .mapToLong(ClubFeeSummaryResponse::balance) - .sum(); - - return ClubFeeSummaryResponseList.from(totalBalance, clubFeeSummaryResponseList); - } - - @Transactional - public ClubFeeCreateResponse createFee(CustomOAuth2Member customOAuth2Member, Long clubId, ClubFeeCreateRequest clubFeeCreateRequest) { - - Club club = clubService.findClubByClubId(clubId); - - FeeType feeType = FeeType.builder() - .club(club) - .feeTypeName(clubFeeCreateRequest.feeTypeName()) - .price(clubFeeCreateRequest.price()) - .memo(clubFeeCreateRequest.memo()) - .feeCategory(clubFeeCreateRequest.feeCategory()) - .startDate(clubFeeCreateRequest.startDate()) - .endDate(clubFeeCreateRequest.endDate()) - .balance(0L) - .totalPrice(0L) - .build(); - - List clubMemberIds = clubFeeCreateRequest.clubMemberIds(); - - for (Long memberId : clubMemberIds) { - ClubMember clubMember = clubMemberService.findClubMemberById(memberId); - - // FeePayment 생성 및 초기화 - FeePayment feePayment = FeePayment.builder() - .isPaid(false) // 초기화 시 납부 여부를 false로 설정 - .feeType(feeType) - .clubMember(clubMember) - .build(); - - feePaymentRepository.save(feePayment); - - // FeePayment를 리스트에 추가 - feeType.updateFeePayments(feePayment); - } - feeTypeRepository.save(feeType); - - return new ClubFeeCreateResponse(feeType.getFeeTypeId()); - } - -// -// @Transactional -// public ClubFeeUpdateResponse updateFee(CustomOAuth2Member customOAuth2Member, Long clubId, Long feeTypeId, ClubFeeCreateRequest clubFeeCreateRequest) { -// FeeType feeType = feeTypeRepository.findById(feeTypeId) -// .orElseThrow(() -> new EntityNotFoundException("해당 feeTypeId를 가진 동아리 회비를 찾을 수 없습니다.")); -// -// feeType.update( -// clubFeeCreateRequest.feeTypeName(), -// clubFeeCreateRequest.price(), -// clubFeeCreateRequest.memo(), -// clubFeeCreateRequest.feeCategory(), -// clubFeeCreateRequest.startDate(), -// clubFeeCreateRequest.endDate()); -// -// List feePayments = feeType.getFeePayments(); -// List clubMemberIds = clubFeeCreateRequest.clubMemberIds(); -// -// for (Long memberId : clubMemberIds) { -// ClubMember clubMember = clubMemberService.findClubMemberById(memberId); -// -// FeePayment feePayment = feePaymentRepository.findFeePaymentByClubMemberAndFeeType(clubMember, feeType) -// .orElseThrow(() -> new EntityNotFoundException("해당 동아리원이 납부할 회비를 찾을 수 없습니다.")); -// -// -// -// feePaymentRepository.save(feePayment); -// -// // FeePayment를 리스트에 추가 -// feeType.updateFeePayments(feePayment); -// } -// -// feeTypeRepository.save(feeType); -// return null; -// } - - @Transactional - public ClubFeeUsageCreateResponse createClubFeeUsage(CustomOAuth2Member customOAuth2Member, Long clubId, Long feeTypeId, ClubFeeUsageRequest clubFeeUsageRequest) { - - FeeType feeType = feeTypeRepository.findById(feeTypeId) - .orElseThrow(() -> new EntityNotFoundException("해당 id를 가진 회비를 찾을 수 없습니다.")); - - if (clubFeeUsageRequest.price() > feeType.getBalance()) { - throw new AppException(ErrorCode.NO_BALANCE_ERROR); - } - feeType.updateBalance(-clubFeeUsageRequest.price()); // price 만큼 사용 - - FeeUsage feeUsage = FeeUsage.builder() - .feeType(feeType) - .description(clubFeeUsageRequest.description()) - .price(clubFeeUsageRequest.price()) - .usedAt(clubFeeUsageRequest.usedAt()) - .build(); - - FeeUsage savedUsage = feeUsageRepository.save(feeUsage); - - feeType.updateFeeUsages(feeUsage); - - feeTypeRepository.save(feeType); - - return new ClubFeeUsageCreateResponse(savedUsage.getFeeUsageId()); - } - - public ClubFeePaymentInfoResponseList findClubFeePaymentInfo(CustomOAuth2Member customOAuth2Member, Long clubId, Long feeTypeId) { - Member member = memberService.findMemberByUniqueId(customOAuth2Member.getUniqueId()); - List feePayments = feePaymentRepository.findAllByFeeType_FeeTypeId(feeTypeId); - - List clubFeePaymentInfoResponseList = new ArrayList<>(); - for (FeePayment feePayment : feePayments) { - ClubFeePaymentInfoResponse clubFeePaymentInfoResponse; - if (feePayment.getClubMember().getMember().getMemberIdx().equals(member.getMemberIdx())) { - clubFeePaymentInfoResponse = ClubFeePaymentInfoResponse.from(feePayment, true); - } else { - clubFeePaymentInfoResponse = ClubFeePaymentInfoResponse.from(feePayment, false); - } - clubFeePaymentInfoResponseList.add(clubFeePaymentInfoResponse); - } - return ClubFeePaymentInfoResponseList.from(clubFeePaymentInfoResponseList); - - } - - public ClubFeeUsageResponseList findAllClubFeeUsage(CustomOAuth2Member customOAuth2Member, Long clubId) { - - // clubId에 해당하는 모든 FeeUsage를 조회 및 변환 - List allUsages = feeUsageRepository.findAllByFeeType_Club_ClubId(clubId) - .stream() - .map(ClubFeeUsageResponse::from) - .toList(); - - List dateGroupedResponses = getDateGroupedClubFeeUsageResponses(allUsages); - - return ClubFeeUsageResponseList.from(dateGroupedResponses); - - } - - public ClubFeeUsageResponseList findAllClubFeeUsageByFeeTypeId(CustomOAuth2Member customOAuth2Member, Long clubId, Long feeTypeId) { - - FeeType feeType = feeTypeRepository.findById(feeTypeId) - .orElseThrow(() -> new EntityNotFoundException("해당 id를 가진 회비를 찾을 수 없습니다.")); - List clubFeeUsageResponseList = feeUsageRepository.findAllByFeeType(feeType) - .stream() - .map(ClubFeeUsageResponse::from) - .toList(); - - List dateGroupedResponses = getDateGroupedClubFeeUsageResponses(clubFeeUsageResponseList); - - return ClubFeeUsageResponseList.from(dateGroupedResponses); - - } - - private List getDateGroupedClubFeeUsageResponses(List clubFeeUsageResponseList) { - // 사용 내역을 날짜별로 그룹화 - Map> groupedByDate = clubFeeUsageResponseList.stream() - .collect(Collectors.groupingBy(ClubFeeUsageResponse::usedAt)); - - // 날짜별로 그룹화된 데이터를 적절한 응답 형태로 변환 - List dateGroupedResponses = groupedByDate.entrySet().stream() - .map(entry -> new DateGroupedClubFeeUsageResponse(entry.getKey(), entry.getValue())) - .sorted(Comparator.comparing(DateGroupedClubFeeUsageResponse::date).reversed()) // 날짜별로 최신 순 정렬 - .toList(); - return dateGroupedResponses; - } - - @Transactional - public ClubFeePaymentUpdateResponse updateClubFeePaymentInfo(CustomOAuth2Member customOAuth2Member, Long clubId, Long feeTypeId, ClubFeePaymentUpdateRequest clubFeePaymentUpdateRequest) { - List feePayments = feePaymentRepository.findAllByFeeType_FeeTypeId(feeTypeId); - FeeType feeType = feeTypeRepository.findById(feeTypeId) - .orElseThrow(() -> new EntityNotFoundException("해당 아이디를 가진 feeType을 찾을 수 없습니다.")); - - Long totalPrice = 0L; - if(!feeType.getBalance().equals(0L)) { - throw new AppException(ErrorCode.PAYMENT_CHANGE_DENIED); - } - for (FeePayment feePayment : feePayments) { - Long clubMemberIdx = feePayment.getClubMember().getClubMemberIdx(); - if(clubFeePaymentUpdateRequest.paymentsInfo().get(clubMemberIdx)) { - feePayment.updateIsPaid(true); - totalPrice += feeType.getPrice(); - } else { - feePayment.updateIsPaid(false); - } - feePaymentRepository.save(feePayment); - } - feeType.updateTotalPrice(totalPrice); - feeType.updateBalance(totalPrice); - feeTypeRepository.save(feeType); - return new ClubFeePaymentUpdateResponse(feeTypeId); - } - + private final FeeTypeRepository feeTypeRepository; + private final FeePaymentRepository feePaymentRepository; + private final ClubMemberService clubMemberService; + private final ClubService clubService; + private final FeeUsageRepository feeUsageRepository; + private final MemberService memberService; + + public ClubFeeSummaryResponseList findAllClubFeeTypesSummary(CustomOAuth2Member customOAuth2Member, Long clubId) { + + List clubFeeSummaryResponseList = feeTypeRepository.findAllByClub_ClubId(clubId) + .stream(). + map(ClubFeeSummaryResponse::from) + .toList(); + + Long totalBalance = clubFeeSummaryResponseList.stream() + .mapToLong(ClubFeeSummaryResponse::balance) + .sum(); + + return ClubFeeSummaryResponseList.from(totalBalance, clubFeeSummaryResponseList); + } + + @Transactional + public ClubFeeCreateResponse createFee(CustomOAuth2Member customOAuth2Member, Long clubId, + ClubFeeCreateRequest clubFeeCreateRequest) { + + Club club = clubService.findClubByClubId(clubId); + + FeeType feeType = FeeType.builder() + .club(club) + .feeTypeName(clubFeeCreateRequest.feeTypeName()) + .price(clubFeeCreateRequest.price()) + .memo(clubFeeCreateRequest.memo()) + .feeCategory(clubFeeCreateRequest.feeCategory()) + .startDate(clubFeeCreateRequest.startDate()) + .endDate(clubFeeCreateRequest.endDate()) + .balance(0L) + .totalPrice(0L) + .build(); + + List clubMemberIds = clubFeeCreateRequest.clubMemberIds(); + + for (Long memberId : clubMemberIds) { + ClubMember clubMember = clubMemberService.findClubMemberById(memberId); + + // FeePayment 생성 및 초기화 + FeePayment feePayment = FeePayment.builder() + .isPaid(false) // 초기화 시 납부 여부를 false로 설정 + .feeType(feeType) + .clubMember(clubMember) + .build(); + + feePaymentRepository.save(feePayment); + + // FeePayment를 리스트에 추가 + feeType.updateFeePayments(feePayment); + } + feeTypeRepository.save(feeType); + + return new ClubFeeCreateResponse(feeType.getFeeTypeId()); + } + + // + // @Transactional + // public ClubFeeUpdateResponse updateFee(CustomOAuth2Member customOAuth2Member, Long clubId, Long feeTypeId, ClubFeeCreateRequest clubFeeCreateRequest) { + // FeeType feeType = feeTypeRepository.findById(feeTypeId) + // .orElseThrow(() -> new EntityNotFoundException("해당 feeTypeId를 가진 동아리 회비를 찾을 수 없습니다.")); + // + // feeType.update( + // clubFeeCreateRequest.feeTypeName(), + // clubFeeCreateRequest.price(), + // clubFeeCreateRequest.memo(), + // clubFeeCreateRequest.feeCategory(), + // clubFeeCreateRequest.startDate(), + // clubFeeCreateRequest.endDate()); + // + // List feePayments = feeType.getFeePayments(); + // List clubMemberIds = clubFeeCreateRequest.clubMemberIds(); + // + // for (Long memberId : clubMemberIds) { + // ClubMember clubMember = clubMemberService.findClubMemberById(memberId); + // + // FeePayment feePayment = feePaymentRepository.findFeePaymentByClubMemberAndFeeType(clubMember, feeType) + // .orElseThrow(() -> new EntityNotFoundException("해당 동아리원이 납부할 회비를 찾을 수 없습니다.")); + // + // + // + // feePaymentRepository.save(feePayment); + // + // // FeePayment를 리스트에 추가 + // feeType.updateFeePayments(feePayment); + // } + // + // feeTypeRepository.save(feeType); + // return null; + // } + + @Transactional + public ClubFeeUsageCreateResponse createClubFeeUsage(CustomOAuth2Member customOAuth2Member, Long clubId, + Long feeTypeId, ClubFeeUsageRequest clubFeeUsageRequest) { + + FeeType feeType = feeTypeRepository.findById(feeTypeId) + .orElseThrow(() -> new EntityNotFoundException("해당 id를 가진 회비를 찾을 수 없습니다.")); + + if (clubFeeUsageRequest.price() > feeType.getBalance()) { + throw new AppException(ErrorCode.NO_BALANCE_ERROR); + } + feeType.updateBalance(-clubFeeUsageRequest.price()); // price 만큼 사용 + + FeeUsage feeUsage = FeeUsage.builder() + .feeType(feeType) + .description(clubFeeUsageRequest.description()) + .price(clubFeeUsageRequest.price()) + .usedAt(clubFeeUsageRequest.usedAt()) + .build(); + + FeeUsage savedUsage = feeUsageRepository.save(feeUsage); + + feeType.updateFeeUsages(feeUsage); + + feeTypeRepository.save(feeType); + + return new ClubFeeUsageCreateResponse(savedUsage.getFeeUsageId()); + } + + public ClubFeePaymentInfoResponseList findClubFeePaymentInfo(CustomOAuth2Member customOAuth2Member, Long clubId, + Long feeTypeId) { + Member member = memberService.findMemberByUniqueId(customOAuth2Member.getUniqueId()); + List feePayments = feePaymentRepository.findAllByFeeType_FeeTypeId(feeTypeId); + + List clubFeePaymentInfoResponseList = new ArrayList<>(); + for (FeePayment feePayment : feePayments) { + ClubFeePaymentInfoResponse clubFeePaymentInfoResponse; + if (feePayment.getClubMember().getMember().getMemberIdx().equals(member.getMemberIdx())) { + clubFeePaymentInfoResponse = ClubFeePaymentInfoResponse.from(feePayment, true); + } else { + clubFeePaymentInfoResponse = ClubFeePaymentInfoResponse.from(feePayment, false); + } + clubFeePaymentInfoResponseList.add(clubFeePaymentInfoResponse); + } + return ClubFeePaymentInfoResponseList.from(clubFeePaymentInfoResponseList); + + } + + public ClubFeeUsageResponseList findAllClubFeeUsage(CustomOAuth2Member customOAuth2Member, Long clubId) { + + // clubId에 해당하는 모든 FeeUsage를 조회 및 변환 + List allUsages = feeUsageRepository.findAllByFeeType_Club_ClubId(clubId) + .stream() + .map(ClubFeeUsageResponse::from) + .toList(); + + List dateGroupedResponses = getDateGroupedClubFeeUsageResponses(allUsages); + + return ClubFeeUsageResponseList.from(dateGroupedResponses); + + } + + public ClubFeeUsageResponseList findAllClubFeeUsageByFeeTypeId(CustomOAuth2Member customOAuth2Member, Long clubId, + Long feeTypeId) { + + FeeType feeType = feeTypeRepository.findById(feeTypeId) + .orElseThrow(() -> new EntityNotFoundException("해당 id를 가진 회비를 찾을 수 없습니다.")); + List clubFeeUsageResponseList = feeUsageRepository.findAllByFeeType(feeType) + .stream() + .map(ClubFeeUsageResponse::from) + .toList(); + + List dateGroupedResponses = getDateGroupedClubFeeUsageResponses( + clubFeeUsageResponseList); + + return ClubFeeUsageResponseList.from(dateGroupedResponses); + + } + + private List getDateGroupedClubFeeUsageResponses( + List clubFeeUsageResponseList) { + // 사용 내역을 날짜별로 그룹화 + Map> groupedByDate = clubFeeUsageResponseList.stream() + .collect(Collectors.groupingBy(ClubFeeUsageResponse::usedAt)); + + // 날짜별로 그룹화된 데이터를 적절한 응답 형태로 변환 + List dateGroupedResponses = groupedByDate.entrySet().stream() + .map(entry -> new DateGroupedClubFeeUsageResponse(entry.getKey(), entry.getValue())) + .sorted(Comparator.comparing(DateGroupedClubFeeUsageResponse::date).reversed()) // 날짜별로 최신 순 정렬 + .toList(); + return dateGroupedResponses; + } + + @Transactional + public ClubFeePaymentUpdateResponse updateClubFeePaymentInfo(CustomOAuth2Member customOAuth2Member, Long clubId, + Long feeTypeId, ClubFeePaymentUpdateRequest clubFeePaymentUpdateRequest) { + List feePayments = feePaymentRepository.findAllByFeeType_FeeTypeId(feeTypeId); + FeeType feeType = feeTypeRepository.findById(feeTypeId) + .orElseThrow(() -> new EntityNotFoundException("해당 아이디를 가진 feeType을 찾을 수 없습니다.")); + + Long totalPrice = 0L; + if (!feeType.getBalance().equals(0L)) { + throw new AppException(ErrorCode.PAYMENT_CHANGE_DENIED); + } + for (FeePayment feePayment : feePayments) { + Long clubMemberIdx = feePayment.getClubMember().getClubMemberIdx(); + if (clubFeePaymentUpdateRequest.paymentsInfo().get(clubMemberIdx)) { + feePayment.updateIsPaid(true); + totalPrice += feeType.getPrice(); + } else { + feePayment.updateIsPaid(false); + } + feePaymentRepository.save(feePayment); + } + feeType.updateTotalPrice(totalPrice); + feeType.updateBalance(totalPrice); + feeTypeRepository.save(feeType); + return new ClubFeePaymentUpdateResponse(feeTypeId); + } } diff --git a/src/main/java/com/cotato/squadus/domain/club/match/entity/MatchPlace.java b/src/main/java/com/cotato/squadus/domain/club/match/entity/MatchPlace.java index 015af9b..35130b7 100644 --- a/src/main/java/com/cotato/squadus/domain/club/match/entity/MatchPlace.java +++ b/src/main/java/com/cotato/squadus/domain/club/match/entity/MatchPlace.java @@ -11,13 +11,13 @@ @NoArgsConstructor(access = AccessLevel.PROTECTED) public class MatchPlace { - private String city; // 시/도 + private String city; // 시/도 - private String district; // 군/구 + private String district; // 군/구 - @Builder - public MatchPlace(String city, String district) { - this.city = city; - this.district = district; - } + @Builder + public MatchPlace(String city, String district) { + this.city = city; + this.district = district; + } } \ No newline at end of file diff --git a/src/main/java/com/cotato/squadus/domain/club/match/entity/match/MatchPost.java b/src/main/java/com/cotato/squadus/domain/club/match/entity/match/MatchPost.java index 1dfe1b6..d5e0ed6 100644 --- a/src/main/java/com/cotato/squadus/domain/club/match/entity/match/MatchPost.java +++ b/src/main/java/com/cotato/squadus/domain/club/match/entity/match/MatchPost.java @@ -1,104 +1,119 @@ package com.cotato.squadus.domain.club.match.entity.match; +import java.time.LocalDate; +import java.time.LocalTime; +import java.util.ArrayList; +import java.util.List; + import com.cotato.squadus.common.entity.BaseTimeEntity; import com.cotato.squadus.domain.club.common.entity.Club; import com.cotato.squadus.domain.club.common.entity.Tier; import com.cotato.squadus.domain.club.match.entity.MatchPlace; -import jakarta.persistence.*; + +import jakarta.persistence.CascadeType; +import jakarta.persistence.Embedded; +import jakarta.persistence.Entity; +import jakarta.persistence.EnumType; +import jakarta.persistence.Enumerated; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.Lob; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.OneToMany; +import jakarta.persistence.Table; import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; -import java.time.LocalDate; -import java.time.LocalTime; -import java.util.ArrayList; -import java.util.List; - @Entity @Getter @NoArgsConstructor @Table(name = "match_post") public class MatchPost extends BaseTimeEntity { - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - private Long matchIdx; - - @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "home_club_id") - private Club homeClub; - - @OneToMany(mappedBy = "matchPost", cascade = CascadeType.ALL) - private List matchRequests = new ArrayList<>(); - - private String title; - - @Lob - private String content; - - @Enumerated(EnumType.STRING) - private Tier tier; - - @Embedded - private MatchPlace matchPlace; - - private Boolean placeProvided; - - //월, 일 정보 저장 - private LocalDate matchStartDate; - - //시간 정보 저장 - private LocalTime matchStartTime; - - private Integer maxParticipants; // 최대 참가 인원 - - private Boolean isFinalized = false; - - private Integer homeWins = 0; - private Integer awayWins = 0; - - - @Builder - public MatchPost(Club homeClub, String title, String content, - Tier tier, MatchPlace matchPlace, Boolean placeProvided, LocalDate matchStartDate, LocalTime matchStartTime, Integer maxParticipants) { - this.homeClub = homeClub; - this.title = title; - this.content = content; - this.tier = tier; - this.matchPlace = matchPlace; - this.placeProvided = placeProvided; - this.matchStartDate = matchStartDate; - this.matchStartTime = matchStartTime; - this.maxParticipants = maxParticipants; - } - - public void setHomeClub(Club homeClub) { - this.homeClub = homeClub; - } - - public void addMatchRequest(MatchRequest matchRequest) { - this.matchRequests.add(matchRequest); - matchRequest.setMatchPost(this); - } - - public void update(String title, String content, MatchPlace matchPlace, Boolean placeProvided, LocalDate matchStartDate, LocalTime matchStartTime, Integer maxParticipants) { - this.title = title; - this.content = content; - this.matchPlace = matchPlace; - this.placeProvided = placeProvided; - this.matchStartDate = matchStartDate; - this.matchStartTime = matchStartTime; - this.maxParticipants = maxParticipants; - } - - //매칭을 최종 확정하는 메서드 - public void finalizeMatch(){ - this.isFinalized = true; - } - - public void updateWinCounts(int homeWins, int awayWins) { - this.homeWins = homeWins; - this.awayWins = awayWins; - } + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long matchIdx; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "home_club_id") + private Club homeClub; + + @OneToMany(mappedBy = "matchPost", cascade = CascadeType.ALL) + private List matchRequests = new ArrayList<>(); + + private String title; + + @Lob + private String content; + + @Enumerated(EnumType.STRING) + private Tier tier; + + @Embedded + private MatchPlace matchPlace; + + private Boolean placeProvided; + + //월, 일 정보 저장 + private LocalDate matchStartDate; + + //시간 정보 저장 + private LocalTime matchStartTime; + + private Integer maxParticipants; // 최대 참가 인원 + + private Boolean isFinalized = false; + + private Integer homeWins = 0; + private Integer awayWins = 0; + + @Builder + public MatchPost(Club homeClub, String title, String content, + Tier tier, MatchPlace matchPlace, Boolean placeProvided, LocalDate matchStartDate, LocalTime matchStartTime, + Integer maxParticipants) { + this.homeClub = homeClub; + this.title = title; + this.content = content; + this.tier = tier; + this.matchPlace = matchPlace; + this.placeProvided = placeProvided; + this.matchStartDate = matchStartDate; + this.matchStartTime = matchStartTime; + this.maxParticipants = maxParticipants; + } + + public void setHomeClub(Club homeClub) { + this.homeClub = homeClub; + } + + public void addMatchRequest(MatchRequest matchRequest) { + this.matchRequests.add(matchRequest); + matchRequest.setMatchPost(this); + } + + public void update(String title, String content, MatchPlace matchPlace, Boolean placeProvided, + LocalDate matchStartDate, LocalTime matchStartTime, Integer maxParticipants) { + this.title = title; + this.content = content; + this.matchPlace = matchPlace; + this.placeProvided = placeProvided; + this.matchStartDate = matchStartDate; + this.matchStartTime = matchStartTime; + this.maxParticipants = maxParticipants; + } + + //매칭을 최종 확정하는 메서드 + public void finalizeMatch() { + this.isFinalized = true; + } + + public void updateWinCounts(int homeWins, int awayWins) { + this.homeWins = homeWins; + this.awayWins = awayWins; + } } diff --git a/src/main/java/com/cotato/squadus/domain/club/match/entity/match/MatchRequest.java b/src/main/java/com/cotato/squadus/domain/club/match/entity/match/MatchRequest.java index 550b99c..ed8da88 100644 --- a/src/main/java/com/cotato/squadus/domain/club/match/entity/match/MatchRequest.java +++ b/src/main/java/com/cotato/squadus/domain/club/match/entity/match/MatchRequest.java @@ -2,7 +2,17 @@ import com.cotato.squadus.domain.club.common.entity.Club; import com.cotato.squadus.domain.club.match.enums.MatchingStatus; -import jakarta.persistence.*; + +import jakarta.persistence.Entity; +import jakarta.persistence.EnumType; +import jakarta.persistence.Enumerated; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.Table; import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; @@ -13,50 +23,52 @@ @Table(name = "match_request") public class MatchRequest { - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - private Long matchRequestIdx; - - @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "match_post_id") - private MatchPost matchPost; // 신청 대상이 되는 매치 글 + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long matchRequestIdx; - @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "club_id") - private Club club; // 신청한 동아리 + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "match_post_id") + private MatchPost matchPost; // 신청 대상이 되는 매치 글 - @Enumerated(EnumType.STRING) - private MatchingStatus status; // 대기, 승낙, 거절 상태 관리 + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "club_id") + private Club club; // 신청한 동아리 - private Boolean isConfirmedByHomeTeam; // home 팀에서 결과 확정했는지 여부 - private Boolean isConfirmedByAwayTeam; // away 팀에서 결과 확정했는지 여부 + @Enumerated(EnumType.STRING) + private MatchingStatus status; // 대기, 승낙, 거절 상태 관리 - private Boolean isLocked = false; // 상태 변경 후 잠금 여부 + private Boolean isConfirmedByHomeTeam; // home 팀에서 결과 확정했는지 여부 + private Boolean isConfirmedByAwayTeam; // away 팀에서 결과 확정했는지 여부 - public void accept() { - if (isLocked) throw new IllegalStateException("이미 처리된 요청은 수정할 수 없습니다."); - this.status = MatchingStatus.ACCEPTED; - this.isLocked = true; - } + private Boolean isLocked = false; // 상태 변경 후 잠금 여부 - public void reject() { - if (isLocked) throw new IllegalStateException("이미 처리된 요청은 수정할 수 없습니다."); - this.status = MatchingStatus.REJECTED; - this.isLocked = true; - } + public void accept() { + if (isLocked) + throw new IllegalStateException("이미 처리된 요청은 수정할 수 없습니다."); + this.status = MatchingStatus.ACCEPTED; + this.isLocked = true; + } - @Builder - public MatchRequest(Club club, MatchPost matchPost, MatchingStatus status, Boolean isConfirmedByAwayTeam, Boolean isConfirmedByHomeTeam){ - this.club = club; - this.matchPost = matchPost; - this.status = status; - this.isConfirmedByHomeTeam = isConfirmedByHomeTeam; - this.isConfirmedByAwayTeam = isConfirmedByAwayTeam; - } + public void reject() { + if (isLocked) + throw new IllegalStateException("이미 처리된 요청은 수정할 수 없습니다."); + this.status = MatchingStatus.REJECTED; + this.isLocked = true; + } - public void setMatchPost(MatchPost matchPost) { - this.matchPost = matchPost; - } + @Builder + public MatchRequest(Club club, MatchPost matchPost, MatchingStatus status, Boolean isConfirmedByAwayTeam, + Boolean isConfirmedByHomeTeam) { + this.club = club; + this.matchPost = matchPost; + this.status = status; + this.isConfirmedByHomeTeam = isConfirmedByHomeTeam; + this.isConfirmedByAwayTeam = isConfirmedByAwayTeam; + } + public void setMatchPost(MatchPost matchPost) { + this.matchPost = matchPost; + } } \ No newline at end of file diff --git a/src/main/java/com/cotato/squadus/domain/club/match/entity/match/MatchResult.java b/src/main/java/com/cotato/squadus/domain/club/match/entity/match/MatchResult.java index f6a14f1..5c0c8a2 100644 --- a/src/main/java/com/cotato/squadus/domain/club/match/entity/match/MatchResult.java +++ b/src/main/java/com/cotato/squadus/domain/club/match/entity/match/MatchResult.java @@ -1,7 +1,15 @@ package com.cotato.squadus.domain.club.match.entity.match; import com.cotato.squadus.domain.club.common.entity.Club; -import jakarta.persistence.*; + +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.Table; import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; @@ -12,56 +20,57 @@ @Table(name = "match_result") public class MatchResult { - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - private Long matchResultIdx; + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long matchResultIdx; - @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "match_post_id") - private MatchPost matchPost; // 매칭 게시글 + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "match_post_id") + private MatchPost matchPost; // 매칭 게시글 - @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "home_club_id") - private Club homeClub; // 홈팀 + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "home_club_id") + private Club homeClub; // 홈팀 - @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "away_club_id") - private Club awayClub; // 어웨이팀 + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "away_club_id") + private Club awayClub; // 어웨이팀 - private Integer homeScore; // 홈팀 점수 - private Integer awayScore; // 어웨이팀 점수 + private Integer homeScore; // 홈팀 점수 + private Integer awayScore; // 어웨이팀 점수 - private Boolean isFinalizedHome = false; // Home팀 결과가 확정되었는지 여부 - private Boolean isfinalizedAway = false; // Away팀 결과가 확정되었는지 여부 + private Boolean isFinalizedHome = false; // Home팀 결과가 확정되었는지 여부 + private Boolean isfinalizedAway = false; // Away팀 결과가 확정되었는지 여부 - @Builder - public MatchResult(MatchPost matchPost, Club homeClub, Club awayClub, Integer homeScore, Integer awayScore) { - this.matchPost = matchPost; - this.homeClub = homeClub; - this.awayClub = awayClub; - this.homeScore = homeScore; - this.awayScore = awayScore; - } + @Builder + public MatchResult(MatchPost matchPost, Club homeClub, Club awayClub, Integer homeScore, Integer awayScore) { + this.matchPost = matchPost; + this.homeClub = homeClub; + this.awayClub = awayClub; + this.homeScore = homeScore; + this.awayScore = awayScore; + } - public void updateScores(Integer homeScore, Integer awayScore) { - if (isFinalizedHome || isfinalizedAway) throw new IllegalStateException("결과가 이미 확정되었습니다."); - this.homeScore = homeScore; - this.awayScore = awayScore; - } + public void updateScores(Integer homeScore, Integer awayScore) { + if (isFinalizedHome || isfinalizedAway) + throw new IllegalStateException("결과가 이미 확정되었습니다."); + this.homeScore = homeScore; + this.awayScore = awayScore; + } - public void finalizeHomeResult() { - this.isFinalizedHome = true; - } + public void finalizeHomeResult() { + this.isFinalizedHome = true; + } - public void finalizeAwayResult() { - this.isfinalizedAway = true; - } + public void finalizeAwayResult() { + this.isfinalizedAway = true; + } - public void setIsFinalizedHome(boolean isFinalizedHome) { - this.isFinalizedHome = isFinalizedHome; - } + public void setIsFinalizedHome(boolean isFinalizedHome) { + this.isFinalizedHome = isFinalizedHome; + } - public void setIsfinalizedAway(boolean isfinalizedAway) { - this.isfinalizedAway = isfinalizedAway; - } + public void setIsfinalizedAway(boolean isfinalizedAway) { + this.isfinalizedAway = isfinalizedAway; + } } diff --git a/src/main/java/com/cotato/squadus/domain/club/match/entity/mercenary/MercenaryPost.java b/src/main/java/com/cotato/squadus/domain/club/match/entity/mercenary/MercenaryPost.java index 43a2720..d2372f7 100644 --- a/src/main/java/com/cotato/squadus/domain/club/match/entity/mercenary/MercenaryPost.java +++ b/src/main/java/com/cotato/squadus/domain/club/match/entity/mercenary/MercenaryPost.java @@ -1,95 +1,107 @@ package com.cotato.squadus.domain.club.match.entity.mercenary; +import java.time.LocalDate; +import java.time.LocalTime; +import java.util.ArrayList; +import java.util.List; + import com.cotato.squadus.common.entity.BaseTimeEntity; import com.cotato.squadus.domain.club.common.entity.Club; import com.cotato.squadus.domain.club.match.entity.MatchPlace; -import jakarta.persistence.*; + +import jakarta.persistence.CascadeType; +import jakarta.persistence.Embedded; +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.Lob; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.OneToMany; +import jakarta.persistence.Table; import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; -import java.time.LocalDate; -import java.time.LocalTime; -import java.util.ArrayList; -import java.util.List; - @Entity @Getter @NoArgsConstructor @Table(name = "mercenary_post") -public class MercenaryPost extends BaseTimeEntity { - - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - private Long mercenaryIdx; - - @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "home_club_id") - private Club homeClub; - - @OneToMany(mappedBy = "mercenaryPost", cascade = CascadeType.ALL) - private List mercenaryRequests = new ArrayList<>(); - - private String title; - - @Lob - private String content; - - @Embedded - private MatchPlace matchPlace; - - private Boolean placeProvided; - - //월, 일 정보 저장 - private LocalDate matchStartDate; - - //시간 정보 저장 - private LocalTime matchStartTime; - - private Integer maxParticipants; // 최대 참가 인원 - - private Integer currentParticipants = 0; - - - @Builder - public MercenaryPost(Club homeClub, String title, String content, - MatchPlace matchPlace, Boolean placeProvided, LocalDate matchStartDate, LocalTime matchStartTime, - Integer maxParticipants) { - this.homeClub = homeClub; - this.title = title; - this.content = content; - this.matchPlace = matchPlace; - this.placeProvided = placeProvided; - this.matchStartDate = matchStartDate; - this.matchStartTime = matchStartTime; - this.maxParticipants = maxParticipants; - } - - public void setHomeClub(Club homeClub) { - this.homeClub = homeClub; - } - - public void addMercenaryRequest(MercenaryRequest mercenaryRequest) { - this.mercenaryRequests.add(mercenaryRequest); - mercenaryRequest.setMercenaryPost(this); - } - - public void incrementParticipants() { - if (this.currentParticipants < this.maxParticipants) { - this.currentParticipants++; - } else { - throw new IllegalStateException("더 이상 참가할 수 없습니다. 최대 인원을 초과했습니다."); - } - } - - public void update(String title, String content, MatchPlace matchPlace, Boolean placeProvided, LocalDate matchStartDate, LocalTime matchStartTime, Integer maxParticipants) { - this.title = title; - this.content = content; - this.matchPlace = matchPlace; - this.placeProvided = placeProvided; - this.matchStartDate = matchStartDate; - this.matchStartTime = matchStartTime; - this.maxParticipants = maxParticipants; - } +public class MercenaryPost extends BaseTimeEntity { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long mercenaryIdx; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "home_club_id") + private Club homeClub; + + @OneToMany(mappedBy = "mercenaryPost", cascade = CascadeType.ALL) + private List mercenaryRequests = new ArrayList<>(); + + private String title; + + @Lob + private String content; + + @Embedded + private MatchPlace matchPlace; + + private Boolean placeProvided; + + //월, 일 정보 저장 + private LocalDate matchStartDate; + + //시간 정보 저장 + private LocalTime matchStartTime; + + private Integer maxParticipants; // 최대 참가 인원 + + private Integer currentParticipants = 0; + + @Builder + public MercenaryPost(Club homeClub, String title, String content, + MatchPlace matchPlace, Boolean placeProvided, LocalDate matchStartDate, LocalTime matchStartTime, + Integer maxParticipants) { + this.homeClub = homeClub; + this.title = title; + this.content = content; + this.matchPlace = matchPlace; + this.placeProvided = placeProvided; + this.matchStartDate = matchStartDate; + this.matchStartTime = matchStartTime; + this.maxParticipants = maxParticipants; + } + + public void setHomeClub(Club homeClub) { + this.homeClub = homeClub; + } + + public void addMercenaryRequest(MercenaryRequest mercenaryRequest) { + this.mercenaryRequests.add(mercenaryRequest); + mercenaryRequest.setMercenaryPost(this); + } + + public void incrementParticipants() { + if (this.currentParticipants < this.maxParticipants) { + this.currentParticipants++; + } else { + throw new IllegalStateException("더 이상 참가할 수 없습니다. 최대 인원을 초과했습니다."); + } + } + + public void update(String title, String content, MatchPlace matchPlace, Boolean placeProvided, + LocalDate matchStartDate, LocalTime matchStartTime, Integer maxParticipants) { + this.title = title; + this.content = content; + this.matchPlace = matchPlace; + this.placeProvided = placeProvided; + this.matchStartDate = matchStartDate; + this.matchStartTime = matchStartTime; + this.maxParticipants = maxParticipants; + } } diff --git a/src/main/java/com/cotato/squadus/domain/club/match/entity/mercenary/MercenaryRequest.java b/src/main/java/com/cotato/squadus/domain/club/match/entity/mercenary/MercenaryRequest.java index e292931..a76c9ce 100644 --- a/src/main/java/com/cotato/squadus/domain/club/match/entity/mercenary/MercenaryRequest.java +++ b/src/main/java/com/cotato/squadus/domain/club/match/entity/mercenary/MercenaryRequest.java @@ -1,9 +1,18 @@ package com.cotato.squadus.domain.club.match.entity.mercenary; import com.cotato.squadus.domain.auth.entity.Member; -import com.cotato.squadus.domain.club.common.entity.ClubMember; import com.cotato.squadus.domain.club.match.enums.MatchingStatus; -import jakarta.persistence.*; + +import jakarta.persistence.Entity; +import jakarta.persistence.EnumType; +import jakarta.persistence.Enumerated; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.Table; import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; @@ -14,45 +23,46 @@ @Table(name = "mercenary_request") public class MercenaryRequest { - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - private Long mercenaryRequestIdx; - - @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "mercenary_post_id") - private MercenaryPost mercenaryPost; // 신청 대상이 되는 매치 글 + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long mercenaryRequestIdx; - @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "member_idx") - private Member member; // 신청한 개인 + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "mercenary_post_id") + private MercenaryPost mercenaryPost; // 신청 대상이 되는 매치 글 - @Enumerated(EnumType.STRING) - private MatchingStatus status; // 대기, 승낙, 거절 상태 관리 + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "member_idx") + private Member member; // 신청한 개인 - private Boolean isLocked = false; // 상태 변경 후 잠금 여부 + @Enumerated(EnumType.STRING) + private MatchingStatus status; // 대기, 승낙, 거절 상태 관리 - public void accept() { - if (isLocked) throw new IllegalStateException("이미 처리된 요청은 수정할 수 없습니다."); - this.status = MatchingStatus.ACCEPTED; - this.isLocked = true; - } + private Boolean isLocked = false; // 상태 변경 후 잠금 여부 - public void reject() { - if (isLocked) throw new IllegalStateException("이미 처리된 요청은 수정할 수 없습니다."); - this.status = MatchingStatus.REJECTED; - this.isLocked = true; - } + public void accept() { + if (isLocked) + throw new IllegalStateException("이미 처리된 요청은 수정할 수 없습니다."); + this.status = MatchingStatus.ACCEPTED; + this.isLocked = true; + } - @Builder - public MercenaryRequest(Member member, MercenaryPost mercenaryPost, MatchingStatus status){ - this.member = member; - this.mercenaryPost = mercenaryPost; - this.status = status; - } + public void reject() { + if (isLocked) + throw new IllegalStateException("이미 처리된 요청은 수정할 수 없습니다."); + this.status = MatchingStatus.REJECTED; + this.isLocked = true; + } - public void setMercenaryPost(MercenaryPost mercenaryPost) { - this.mercenaryPost = mercenaryPost; - } + @Builder + public MercenaryRequest(Member member, MercenaryPost mercenaryPost, MatchingStatus status) { + this.member = member; + this.mercenaryPost = mercenaryPost; + this.status = status; + } + public void setMercenaryPost(MercenaryPost mercenaryPost) { + this.mercenaryPost = mercenaryPost; + } } diff --git a/src/main/java/com/cotato/squadus/domain/club/match/enums/MatchingStatus.java b/src/main/java/com/cotato/squadus/domain/club/match/enums/MatchingStatus.java index a76b280..dbf4e26 100644 --- a/src/main/java/com/cotato/squadus/domain/club/match/enums/MatchingStatus.java +++ b/src/main/java/com/cotato/squadus/domain/club/match/enums/MatchingStatus.java @@ -1,7 +1,7 @@ package com.cotato.squadus.domain.club.match.enums; public enum MatchingStatus { - PENDING, // 대기 중 - ACCEPTED, // 수락됨 - REJECTED // 거절됨 + PENDING, // 대기 중 + ACCEPTED, // 수락됨 + REJECTED // 거절됨 } diff --git a/src/main/java/com/cotato/squadus/domain/club/match/repository/match/MatchPostRepository.java b/src/main/java/com/cotato/squadus/domain/club/match/repository/match/MatchPostRepository.java index a4b7359..e40f962 100644 --- a/src/main/java/com/cotato/squadus/domain/club/match/repository/match/MatchPostRepository.java +++ b/src/main/java/com/cotato/squadus/domain/club/match/repository/match/MatchPostRepository.java @@ -1,7 +1,9 @@ package com.cotato.squadus.domain.club.match.repository.match; -import com.cotato.squadus.domain.club.common.entity.Club; -import com.cotato.squadus.domain.club.match.entity.match.MatchPost; +import java.time.LocalDate; +import java.time.LocalTime; +import java.util.List; + import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.data.jpa.repository.JpaRepository; @@ -9,20 +11,18 @@ import org.springframework.data.repository.query.Param; import org.springframework.stereotype.Repository; -import java.time.LocalDate; -import java.time.LocalTime; -import java.util.List; +import com.cotato.squadus.domain.club.common.entity.Club; +import com.cotato.squadus.domain.club.match.entity.match.MatchPost; @Repository public interface MatchPostRepository extends JpaRepository, MatchPostRepositoryCustom { + @Query("SELECT m FROM MatchPost m WHERE m.matchStartDate > :date " + + "OR (m.matchStartDate = :date AND m.matchStartTime > :time)") + Page findAllByMatchStartDateAfterOrMatchStartDateEqualsAndMatchStartTimeAfter( + @Param("date") LocalDate date, + @Param("time") LocalTime time, + Pageable pageable); - @Query("SELECT m FROM MatchPost m WHERE m.matchStartDate > :date " + - "OR (m.matchStartDate = :date AND m.matchStartTime > :time)") - Page findAllByMatchStartDateAfterOrMatchStartDateEqualsAndMatchStartTimeAfter( - @Param("date") LocalDate date, - @Param("time") LocalTime time, - Pageable pageable); - - List findByHomeClub(Club club); + List findByHomeClub(Club club); } diff --git a/src/main/java/com/cotato/squadus/domain/club/match/repository/match/MatchPostRepositoryCustom.java b/src/main/java/com/cotato/squadus/domain/club/match/repository/match/MatchPostRepositoryCustom.java index 79d3957..6233215 100644 --- a/src/main/java/com/cotato/squadus/domain/club/match/repository/match/MatchPostRepositoryCustom.java +++ b/src/main/java/com/cotato/squadus/domain/club/match/repository/match/MatchPostRepositoryCustom.java @@ -1,15 +1,16 @@ package com.cotato.squadus.domain.club.match.repository.match; +import java.util.List; + import com.cotato.squadus.domain.club.common.enums.ClubTier; import com.cotato.squadus.domain.club.common.enums.SportsCategory; import com.cotato.squadus.domain.club.match.entity.match.MatchPost; -import java.util.List; - public interface MatchPostRepositoryCustom { - List customFindMatchesByFilter(SportsCategory sportsCategory, String city, String district, ClubTier tier, Boolean placeProvided); + List customFindMatchesByFilter(SportsCategory sportsCategory, String city, String district, + ClubTier tier, Boolean placeProvided); - List customFindByKeyword(String keyword); + List customFindByKeyword(String keyword); } diff --git a/src/main/java/com/cotato/squadus/domain/club/match/repository/match/MatchPostRepositoryImpl.java b/src/main/java/com/cotato/squadus/domain/club/match/repository/match/MatchPostRepositoryImpl.java index 59cb798..d5b2333 100644 --- a/src/main/java/com/cotato/squadus/domain/club/match/repository/match/MatchPostRepositoryImpl.java +++ b/src/main/java/com/cotato/squadus/domain/club/match/repository/match/MatchPostRepositoryImpl.java @@ -1,78 +1,82 @@ package com.cotato.squadus.domain.club.match.repository.match; +import static com.cotato.squadus.domain.club.match.entity.match.QMatchPost.*; +import static com.querydsl.core.types.dsl.Expressions.*; + +import java.util.List; + +import org.springframework.stereotype.Repository; + import com.cotato.squadus.domain.club.common.enums.ClubTier; import com.cotato.squadus.domain.club.common.enums.SportsCategory; import com.cotato.squadus.domain.club.match.entity.match.MatchPost; import com.cotato.squadus.domain.club.match.entity.match.QMatchPost; import com.querydsl.core.types.dsl.BooleanExpression; import com.querydsl.jpa.impl.JPAQueryFactory; -import lombok.extern.slf4j.Slf4j; -import org.springframework.stereotype.Repository; -import java.util.List; - -import static com.cotato.squadus.domain.club.match.entity.match.QMatchPost.matchPost; -import static com.querydsl.core.types.dsl.Expressions.stringTemplate; +import lombok.extern.slf4j.Slf4j; @Repository @Slf4j public class MatchPostRepositoryImpl implements MatchPostRepositoryCustom { - private final JPAQueryFactory jpaQueryFactory; + private final JPAQueryFactory jpaQueryFactory; - public MatchPostRepositoryImpl(JPAQueryFactory jpaQueryFactory){ - this.jpaQueryFactory = jpaQueryFactory; - } + public MatchPostRepositoryImpl(JPAQueryFactory jpaQueryFactory) { + this.jpaQueryFactory = jpaQueryFactory; + } - @Override - public List customFindMatchesByFilter(SportsCategory sportsCategory, String city, String district, ClubTier clubTier, Boolean placeProvided) { - QMatchPost matchPost = QMatchPost.matchPost; - return jpaQueryFactory - .selectFrom(matchPost) - .where( - sportsCategoryEq(sportsCategory), - cityEq(city), - districtEq(district), - tierEq(clubTier), - placeProvidedEq(placeProvided) - ) - .fetch(); - } + @Override + public List customFindMatchesByFilter(SportsCategory sportsCategory, String city, String district, + ClubTier clubTier, Boolean placeProvided) { + QMatchPost matchPost = QMatchPost.matchPost; + return jpaQueryFactory + .selectFrom(matchPost) + .where( + sportsCategoryEq(sportsCategory), + cityEq(city), + districtEq(district), + tierEq(clubTier), + placeProvidedEq(placeProvided) + ) + .fetch(); + } - @Override - public List customFindByKeyword(String keyword) { - QMatchPost matchPost = QMatchPost.matchPost; - String pattern = "%" + keyword + "%"; // 부분 일치 검색을 위해 패턴 설정 - return jpaQueryFactory - .selectFrom(matchPost) - .where( - stringTemplate("cast({0} as string)", matchPost.title) - .likeIgnoreCase(pattern) - .or( - stringTemplate("cast({0} as string)", matchPost.content) - .likeIgnoreCase(pattern) - ) - ) - .fetch(); - } + @Override + public List customFindByKeyword(String keyword) { + QMatchPost matchPost = QMatchPost.matchPost; + String pattern = "%" + keyword + "%"; // 부분 일치 검색을 위해 패턴 설정 + return jpaQueryFactory + .selectFrom(matchPost) + .where( + stringTemplate("cast({0} as string)", matchPost.title) + .likeIgnoreCase(pattern) + .or( + stringTemplate("cast({0} as string)", matchPost.content) + .likeIgnoreCase(pattern) + ) + ) + .fetch(); + } - private BooleanExpression sportsCategoryEq(SportsCategory sportsCategory) { - return sportsCategory != null ? matchPost.homeClub.sportsCategory.stringValue().eq(sportsCategory.name()) : null; - } + private BooleanExpression sportsCategoryEq(SportsCategory sportsCategory) { + return sportsCategory != null ? matchPost.homeClub.sportsCategory.stringValue().eq(sportsCategory.name()) : + null; + } - private BooleanExpression tierEq(ClubTier clubTier) { - return clubTier != null ? matchPost.homeClub.clubTier.stringValue().eq(clubTier.name()) : null; - } + private BooleanExpression tierEq(ClubTier clubTier) { + return clubTier != null ? matchPost.homeClub.clubTier.stringValue().eq(clubTier.name()) : null; + } - private BooleanExpression cityEq(String city) { - return city != null ? matchPost.matchPlace.city.eq(city) : null; - } + private BooleanExpression cityEq(String city) { + return city != null ? matchPost.matchPlace.city.eq(city) : null; + } - private BooleanExpression districtEq(String district) { - return district != null ? matchPost.matchPlace.district.eq(district) : null; - } + private BooleanExpression districtEq(String district) { + return district != null ? matchPost.matchPlace.district.eq(district) : null; + } - private BooleanExpression placeProvidedEq(Boolean placeProvided) { - return placeProvided != null ? matchPost.placeProvided.eq(placeProvided) : null; - } + private BooleanExpression placeProvidedEq(Boolean placeProvided) { + return placeProvided != null ? matchPost.placeProvided.eq(placeProvided) : null; + } } diff --git a/src/main/java/com/cotato/squadus/domain/club/match/repository/match/MatchRequestRepository.java b/src/main/java/com/cotato/squadus/domain/club/match/repository/match/MatchRequestRepository.java index ded32eb..83e0c47 100644 --- a/src/main/java/com/cotato/squadus/domain/club/match/repository/match/MatchRequestRepository.java +++ b/src/main/java/com/cotato/squadus/domain/club/match/repository/match/MatchRequestRepository.java @@ -1,22 +1,22 @@ package com.cotato.squadus.domain.club.match.repository.match; -import com.cotato.squadus.domain.club.common.entity.Club; -import com.cotato.squadus.domain.club.match.entity.match.MatchPost; -import com.cotato.squadus.domain.club.match.entity.match.MatchRequest; -import org.springframework.data.domain.Pageable; -import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.data.domain.Page; - import java.util.List; import java.util.Optional; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.jpa.repository.JpaRepository; + +import com.cotato.squadus.domain.club.common.entity.Club; +import com.cotato.squadus.domain.club.match.entity.match.MatchPost; +import com.cotato.squadus.domain.club.match.entity.match.MatchRequest; public interface MatchRequestRepository extends JpaRepository { - Page findAllByClub_ClubId(Long clubId, Pageable pageable); + Page findAllByClub_ClubId(Long clubId, Pageable pageable); - List findAllByClub_ClubId(Long clubId); + List findAllByClub_ClubId(Long clubId); - Optional findTop1ByClubAndMatchPost(Club club, MatchPost matchPost); + Optional findTop1ByClubAndMatchPost(Club club, MatchPost matchPost); } diff --git a/src/main/java/com/cotato/squadus/domain/club/match/repository/match/MatchResultRepository.java b/src/main/java/com/cotato/squadus/domain/club/match/repository/match/MatchResultRepository.java index 8a67d8e..6ff7920 100644 --- a/src/main/java/com/cotato/squadus/domain/club/match/repository/match/MatchResultRepository.java +++ b/src/main/java/com/cotato/squadus/domain/club/match/repository/match/MatchResultRepository.java @@ -1,13 +1,14 @@ package com.cotato.squadus.domain.club.match.repository.match; -import com.cotato.squadus.domain.club.match.entity.match.MatchPost; -import com.cotato.squadus.domain.club.match.entity.match.MatchResult; +import java.util.List; + import org.springframework.data.jpa.repository.JpaRepository; -import java.util.List; +import com.cotato.squadus.domain.club.match.entity.match.MatchPost; +import com.cotato.squadus.domain.club.match.entity.match.MatchResult; public interface MatchResultRepository extends JpaRepository { - List findByMatchPost(MatchPost matchPost); + List findByMatchPost(MatchPost matchPost); } diff --git a/src/main/java/com/cotato/squadus/domain/club/match/repository/mercenary/MercenaryPostRepository.java b/src/main/java/com/cotato/squadus/domain/club/match/repository/mercenary/MercenaryPostRepository.java index 173b951..26ae619 100644 --- a/src/main/java/com/cotato/squadus/domain/club/match/repository/mercenary/MercenaryPostRepository.java +++ b/src/main/java/com/cotato/squadus/domain/club/match/repository/mercenary/MercenaryPostRepository.java @@ -1,7 +1,9 @@ package com.cotato.squadus.domain.club.match.repository.mercenary; -import com.cotato.squadus.domain.club.common.entity.Club; -import com.cotato.squadus.domain.club.match.entity.mercenary.MercenaryPost; +import java.time.LocalDate; +import java.time.LocalTime; +import java.util.List; + import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.data.jpa.repository.JpaRepository; @@ -9,21 +11,19 @@ import org.springframework.data.repository.query.Param; import org.springframework.stereotype.Repository; -import java.time.LocalDate; -import java.time.LocalTime; -import java.util.List; +import com.cotato.squadus.domain.club.common.entity.Club; +import com.cotato.squadus.domain.club.match.entity.mercenary.MercenaryPost; @Repository public interface MercenaryPostRepository extends JpaRepository, MercenaryPostRepositoryCustom { - @Query("SELECT m FROM MercenaryPost m WHERE m.matchStartDate > :date " + - "OR (m.matchStartDate = :date AND m.matchStartTime > :time)") - Page findAllByMatchStartDateAfterOrMatchStartDateEqualsAndMatchStartTimeAfter( - @Param("date") LocalDate date, - @Param("time") LocalTime time, - Pageable pageable); - + @Query("SELECT m FROM MercenaryPost m WHERE m.matchStartDate > :date " + + "OR (m.matchStartDate = :date AND m.matchStartTime > :time)") + Page findAllByMatchStartDateAfterOrMatchStartDateEqualsAndMatchStartTimeAfter( + @Param("date") LocalDate date, + @Param("time") LocalTime time, + Pageable pageable); - List findByHomeClub(Club club); + List findByHomeClub(Club club); } diff --git a/src/main/java/com/cotato/squadus/domain/club/match/repository/mercenary/MercenaryPostRepositoryCustom.java b/src/main/java/com/cotato/squadus/domain/club/match/repository/mercenary/MercenaryPostRepositoryCustom.java index 3c4219e..169f1f9 100644 --- a/src/main/java/com/cotato/squadus/domain/club/match/repository/mercenary/MercenaryPostRepositoryCustom.java +++ b/src/main/java/com/cotato/squadus/domain/club/match/repository/mercenary/MercenaryPostRepositoryCustom.java @@ -1,16 +1,16 @@ package com.cotato.squadus.domain.club.match.repository.mercenary; +import java.util.List; + import com.cotato.squadus.domain.club.common.enums.ClubTier; import com.cotato.squadus.domain.club.common.enums.SportsCategory; import com.cotato.squadus.domain.club.match.entity.mercenary.MercenaryPost; -import java.util.List; - public interface MercenaryPostRepositoryCustom { + List customFindMatchesByFilter(SportsCategory sportsCategory, String city, String district, + ClubTier tier, Boolean placeProvided); - List customFindMatchesByFilter(SportsCategory sportsCategory, String city, String district, ClubTier tier, Boolean placeProvided); - - List customFindByKeyword(String keyword); + List customFindByKeyword(String keyword); } diff --git a/src/main/java/com/cotato/squadus/domain/club/match/repository/mercenary/MercenaryPostRepositoryImpl.java b/src/main/java/com/cotato/squadus/domain/club/match/repository/mercenary/MercenaryPostRepositoryImpl.java index 5ada589..0d2d807 100644 --- a/src/main/java/com/cotato/squadus/domain/club/match/repository/mercenary/MercenaryPostRepositoryImpl.java +++ b/src/main/java/com/cotato/squadus/domain/club/match/repository/mercenary/MercenaryPostRepositoryImpl.java @@ -1,77 +1,80 @@ package com.cotato.squadus.domain.club.match.repository.mercenary; +import static com.cotato.squadus.domain.club.match.entity.mercenary.QMercenaryPost.*; +import static com.querydsl.core.types.dsl.Expressions.*; + +import java.util.List; + +import org.springframework.stereotype.Repository; + import com.cotato.squadus.domain.club.common.enums.ClubTier; import com.cotato.squadus.domain.club.common.enums.SportsCategory; import com.cotato.squadus.domain.club.match.entity.mercenary.MercenaryPost; import com.cotato.squadus.domain.club.match.entity.mercenary.QMercenaryPost; import com.querydsl.core.types.dsl.BooleanExpression; import com.querydsl.jpa.impl.JPAQueryFactory; -import org.springframework.stereotype.Repository; - -import java.util.List; - -import static com.cotato.squadus.domain.club.match.entity.mercenary.QMercenaryPost.mercenaryPost; -import static com.querydsl.core.types.dsl.Expressions.stringTemplate; @Repository -public class MercenaryPostRepositoryImpl implements MercenaryPostRepositoryCustom{ +public class MercenaryPostRepositoryImpl implements MercenaryPostRepositoryCustom { - private final JPAQueryFactory jpaQueryFactory; + private final JPAQueryFactory jpaQueryFactory; - public MercenaryPostRepositoryImpl(JPAQueryFactory jpaQueryFactory){ - this.jpaQueryFactory = jpaQueryFactory; - } + public MercenaryPostRepositoryImpl(JPAQueryFactory jpaQueryFactory) { + this.jpaQueryFactory = jpaQueryFactory; + } - @Override - public List customFindMatchesByFilter(SportsCategory sportsCategory, String city, String district, ClubTier clubTier, Boolean placeProvided) { - QMercenaryPost mercenaryPost = QMercenaryPost.mercenaryPost; - return jpaQueryFactory - .selectFrom(mercenaryPost) - .where( - sportsCategoryEq(sportsCategory), - cityEq(city), - districtEq(district), - tierEq(clubTier), - placeProvidedEq(placeProvided) - ) - .fetch(); - } + @Override + public List customFindMatchesByFilter(SportsCategory sportsCategory, String city, String district, + ClubTier clubTier, Boolean placeProvided) { + QMercenaryPost mercenaryPost = QMercenaryPost.mercenaryPost; + return jpaQueryFactory + .selectFrom(mercenaryPost) + .where( + sportsCategoryEq(sportsCategory), + cityEq(city), + districtEq(district), + tierEq(clubTier), + placeProvidedEq(placeProvided) + ) + .fetch(); + } - @Override - public List customFindByKeyword(String keyword) { - QMercenaryPost mercenaryPost = QMercenaryPost.mercenaryPost; - String pattern = "%" + keyword + "%"; // 부분 일치 검색을 위해 패턴 설정 - return jpaQueryFactory - .selectFrom(mercenaryPost) - .where( - stringTemplate("cast({0} as string)", mercenaryPost.title) - .likeIgnoreCase(pattern) - .or( - stringTemplate("cast({0} as string)", mercenaryPost.content) - .likeIgnoreCase(pattern) - ) - ) - .fetch(); - } + @Override + public List customFindByKeyword(String keyword) { + QMercenaryPost mercenaryPost = QMercenaryPost.mercenaryPost; + String pattern = "%" + keyword + "%"; // 부분 일치 검색을 위해 패턴 설정 + return jpaQueryFactory + .selectFrom(mercenaryPost) + .where( + stringTemplate("cast({0} as string)", mercenaryPost.title) + .likeIgnoreCase(pattern) + .or( + stringTemplate("cast({0} as string)", mercenaryPost.content) + .likeIgnoreCase(pattern) + ) + ) + .fetch(); + } - private BooleanExpression sportsCategoryEq(SportsCategory sportsCategory) { - return sportsCategory != null ? mercenaryPost.homeClub.sportsCategory.stringValue().eq(sportsCategory.name()) : null; - } + private BooleanExpression sportsCategoryEq(SportsCategory sportsCategory) { + return sportsCategory != null ? mercenaryPost.homeClub.sportsCategory.stringValue().eq(sportsCategory.name()) : + null; + } - private BooleanExpression tierEq(ClubTier clubTier) { - return clubTier != null ? mercenaryPost.homeClub.clubTier.stringValue().eq(clubTier.name()) : null; - } + private BooleanExpression tierEq(ClubTier clubTier) { + return clubTier != null ? mercenaryPost.homeClub.clubTier.stringValue().eq(clubTier.name()) : null; + } - private BooleanExpression cityEq(String city) { - return city != null ? mercenaryPost.matchPlace.city.eq(city) : null; - } + private BooleanExpression cityEq(String city) { + return city != null ? mercenaryPost.matchPlace.city.eq(city) : null; + } - private BooleanExpression districtEq(String district) { - return district != null ? mercenaryPost.matchPlace.district.eq(district) : null; - } + private BooleanExpression districtEq(String district) { + return district != null ? mercenaryPost.matchPlace.district.eq(district) : null; + } - private BooleanExpression placeProvidedEq(Boolean placeProvided) { - return placeProvided != null ? mercenaryPost.placeProvided.eq(placeProvided) : null; - } + private BooleanExpression placeProvidedEq(Boolean placeProvided) { + return placeProvided != null ? mercenaryPost.placeProvided.eq(placeProvided) : null; + } } diff --git a/src/main/java/com/cotato/squadus/domain/club/match/repository/mercenary/MercenaryRequestRepository.java b/src/main/java/com/cotato/squadus/domain/club/match/repository/mercenary/MercenaryRequestRepository.java index 947d609..ee5e25d 100644 --- a/src/main/java/com/cotato/squadus/domain/club/match/repository/mercenary/MercenaryRequestRepository.java +++ b/src/main/java/com/cotato/squadus/domain/club/match/repository/mercenary/MercenaryRequestRepository.java @@ -1,24 +1,24 @@ package com.cotato.squadus.domain.club.match.repository.mercenary; -import com.cotato.squadus.domain.auth.entity.Member; -import com.cotato.squadus.domain.club.common.entity.ClubMember; -import com.cotato.squadus.domain.club.match.entity.mercenary.MercenaryPost; -import com.cotato.squadus.domain.club.match.entity.mercenary.MercenaryRequest; +import java.util.List; +import java.util.Optional; + import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.data.jpa.repository.JpaRepository; -import java.util.List; -import java.util.Optional; +import com.cotato.squadus.domain.auth.entity.Member; +import com.cotato.squadus.domain.club.match.entity.mercenary.MercenaryPost; +import com.cotato.squadus.domain.club.match.entity.mercenary.MercenaryRequest; public interface MercenaryRequestRepository extends JpaRepository { - Page findAllByMember_MemberIdx(Member member, Pageable pageable); + Page findAllByMember_MemberIdx(Member member, Pageable pageable); - List findAllByMember_MemberIdx(Member member); + List findAllByMember_MemberIdx(Member member); - Optional findTop1ByMemberAndMercenaryPost(Member member, MercenaryPost mercenaryPost); + Optional findTop1ByMemberAndMercenaryPost(Member member, MercenaryPost mercenaryPost); -// Optional findTop1ByClubMemberAndMercenaryPost(ClubMember clubMember, MercenaryPost mercenaryPost); + // Optional findTop1ByClubMemberAndMercenaryPost(ClubMember clubMember, MercenaryPost mercenaryPost); } diff --git a/src/main/java/com/cotato/squadus/domain/club/match/service/match/MatchRequestService.java b/src/main/java/com/cotato/squadus/domain/club/match/service/match/MatchRequestService.java index e9af958..dbd24d3 100644 --- a/src/main/java/com/cotato/squadus/domain/club/match/service/match/MatchRequestService.java +++ b/src/main/java/com/cotato/squadus/domain/club/match/service/match/MatchRequestService.java @@ -1,5 +1,14 @@ package com.cotato.squadus.domain.club.match.service.match; +import java.time.LocalDateTime; +import java.util.List; +import java.util.stream.Collectors; + +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageImpl; +import org.springframework.data.domain.Pageable; +import org.springframework.stereotype.Service; + import com.cotato.squadus.api.match.dto.matchPost.response.MatchRequestAndMatchPostResponse; import com.cotato.squadus.api.match.dto.matchPost.response.MatchRequestResponse; import com.cotato.squadus.api.match.dto.matchPost.response.ReceivedMatchRequestResponse; @@ -12,159 +21,145 @@ import com.cotato.squadus.domain.club.match.entity.match.MatchRequest; import com.cotato.squadus.domain.club.match.repository.match.MatchPostRepository; import com.cotato.squadus.domain.club.match.repository.match.MatchRequestRepository; + import jakarta.persistence.EntityNotFoundException; import jakarta.transaction.Transactional; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.springframework.data.domain.Page; -import org.springframework.data.domain.PageImpl; -import org.springframework.data.domain.Pageable; -import org.springframework.security.access.AccessDeniedException; -import org.springframework.stereotype.Service; - -import java.time.LocalDateTime; -import java.util.List; -import java.util.stream.Collectors; @Service @RequiredArgsConstructor @Slf4j public class MatchRequestService { - private final MatchRequestRepository matchRequestRepository; - private final ClubAdminMemberRepository clubAdminMemberRepository; - private final ClubRepository clubRepository; - private final MatchPostRepository matchPostRepository; - - public Page getMyClubMatchRequests(Long clubId, Pageable pageable) { - Page requestsPage = matchRequestRepository.findAllByClub_ClubId(clubId, pageable); - - // 유효한 MercenaryPost만 필터링하여 새로운 리스트로 변환 - List filteredResponses = requestsPage - .stream() - .filter(matchRequest -> isPostValid(matchRequest.getMatchPost())) - .map(MatchRequestResponse::from) - .collect(Collectors.toList()); - - // 필터링된 리스트를 Page 객체로 변환하여 반환 - return new PageImpl<>(filteredResponses, pageable, requestsPage.getTotalElements()); - } - - - public List getAllMyClubMatchRequests(Long clubId) { - return matchRequestRepository.findAllByClub_ClubId(clubId) - .stream() - .filter(mercenaryRequest -> isPostValid(mercenaryRequest.getMatchPost())) - .map(MatchRequestResponse::from) - .collect(Collectors.toList()); - } - - @Transactional - public void cancelMatchRequest(Long requestId, Long memberId) { - MatchRequest matchRequest = matchRequestRepository.findById(requestId) - .orElseThrow(() -> new EntityNotFoundException("매칭 요청을 찾을 수 없습니다.")); - - clubAdminMemberRepository.findActiveAdminByClubIdAndClubMemberId( - matchRequest.getClub().getClubId(), memberId) - .orElseThrow(() -> new AppException(ErrorCode.CLUB_ACCESS_DENIED)); - - matchRequestRepository.delete(matchRequest); - } - - - - - public Page getReceivedMatchRequests(Long clubId, Pageable pageable) { - - Club club = clubRepository.findById(clubId) - .orElseThrow(() -> new EntityNotFoundException("동아리를 찾을 수 없습니다.")); - - List matchPosts = matchPostRepository.findByHomeClub(club); - - LocalDateTime now = LocalDateTime.now(); - - List allResponses = matchPosts.stream() - .filter(matchPost -> LocalDateTime.of(matchPost.getMatchStartDate(),matchPost.getMatchStartTime()).isAfter(now)) - .map(matchPost -> { - List receivedRequests = matchPost.getMatchRequests() - .stream() - .map(ReceivedMatchRequestResponse::from) - .collect(Collectors.toList()); - - return MatchRequestAndMatchPostResponse.from( - matchPost, - receivedRequests - ); - }) - .collect(Collectors.toList()); - - // allResponses 리스트를 pageable에 맞게 자릅니다. - int start = (int) pageable.getOffset(); - int end = Math.min(start + pageable.getPageSize(), allResponses.size()); - - List paginatedList = allResponses.subList(start, end); - - return new PageImpl<>(paginatedList, pageable, allResponses.size()); - } - - - public List getAllReceivedMatchRequests(Long clubId) { - - Club club = clubRepository.findById(clubId) - .orElseThrow(() -> new EntityNotFoundException("동아리를 찾을 수 없습니다.")); - - List matchPosts = club.getMatchPosts(); - - LocalDateTime now = LocalDateTime.now(); - - return matchPosts.stream() - .filter(matchPost -> LocalDateTime.of(matchPost.getMatchStartDate(),matchPost.getMatchStartTime()).isAfter(now)) - .map(matchPost -> { - List receivedRequests = matchPost.getMatchRequests() - .stream() - .map(ReceivedMatchRequestResponse::from) - .collect(Collectors.toList()); - - return MatchRequestAndMatchPostResponse.from( - matchPost, - receivedRequests - ); - }) - .collect(Collectors.toList()); - } - - - - - @Transactional - public void decideMatchRequest(Long requestId, String decision, Long memberId) { - MatchRequest matchRequest = matchRequestRepository.findById(requestId) - .orElseThrow(() -> new EntityNotFoundException("매칭 요청을 찾을 수 없습니다.")); - - clubAdminMemberRepository.findActiveAdminByClubIdAndClubMemberId( - matchRequest.getMatchPost().getHomeClub().getClubId(), memberId) - .orElseThrow(() -> new AppException(ErrorCode.CLUB_ACCESS_DENIED)); - - // matchPost가 이미 최종 확정되었는지 확인 - if (matchRequest.getMatchPost().getIsFinalized()) { - throw new AppException(ErrorCode.CLUB_MATCH_FINALIZE); - } - - if ("ACCEPTED".equalsIgnoreCase(decision)) { - matchRequest.accept(); - matchRequest.getMatchPost().finalizeMatch(); - } else if ("REJECTED".equalsIgnoreCase(decision)) { - matchRequest.reject(); - } else { - throw new IllegalArgumentException("결정은 ACCEPTED 또는 REJECTED이어야 합니다."); - } - - matchRequestRepository.save(matchRequest); - } - - private boolean isPostValid(MatchPost matchPost) { - LocalDateTime postDateTime = LocalDateTime.of(matchPost.getMatchStartDate(), matchPost.getMatchStartTime()); - return postDateTime.isAfter(LocalDateTime.now()); - } + private final MatchRequestRepository matchRequestRepository; + private final ClubAdminMemberRepository clubAdminMemberRepository; + private final ClubRepository clubRepository; + private final MatchPostRepository matchPostRepository; + + public Page getMyClubMatchRequests(Long clubId, Pageable pageable) { + Page requestsPage = matchRequestRepository.findAllByClub_ClubId(clubId, pageable); + + // 유효한 MercenaryPost만 필터링하여 새로운 리스트로 변환 + List filteredResponses = requestsPage + .stream() + .filter(matchRequest -> isPostValid(matchRequest.getMatchPost())) + .map(MatchRequestResponse::from) + .collect(Collectors.toList()); + + // 필터링된 리스트를 Page 객체로 변환하여 반환 + return new PageImpl<>(filteredResponses, pageable, requestsPage.getTotalElements()); + } + + public List getAllMyClubMatchRequests(Long clubId) { + return matchRequestRepository.findAllByClub_ClubId(clubId) + .stream() + .filter(mercenaryRequest -> isPostValid(mercenaryRequest.getMatchPost())) + .map(MatchRequestResponse::from) + .collect(Collectors.toList()); + } + + @Transactional + public void cancelMatchRequest(Long requestId, Long memberId) { + MatchRequest matchRequest = matchRequestRepository.findById(requestId) + .orElseThrow(() -> new EntityNotFoundException("매칭 요청을 찾을 수 없습니다.")); + + clubAdminMemberRepository.findActiveAdminByClubIdAndClubMemberId( + matchRequest.getClub().getClubId(), memberId) + .orElseThrow(() -> new AppException(ErrorCode.CLUB_ACCESS_DENIED)); + + matchRequestRepository.delete(matchRequest); + } + + public Page getReceivedMatchRequests(Long clubId, Pageable pageable) { + + Club club = clubRepository.findById(clubId) + .orElseThrow(() -> new EntityNotFoundException("동아리를 찾을 수 없습니다.")); + + List matchPosts = matchPostRepository.findByHomeClub(club); + + LocalDateTime now = LocalDateTime.now(); + + List allResponses = matchPosts.stream() + .filter(matchPost -> LocalDateTime.of(matchPost.getMatchStartDate(), matchPost.getMatchStartTime()) + .isAfter(now)) + .map(matchPost -> { + List receivedRequests = matchPost.getMatchRequests() + .stream() + .map(ReceivedMatchRequestResponse::from) + .collect(Collectors.toList()); + + return MatchRequestAndMatchPostResponse.from( + matchPost, + receivedRequests + ); + }) + .collect(Collectors.toList()); + + // allResponses 리스트를 pageable에 맞게 자릅니다. + int start = (int)pageable.getOffset(); + int end = Math.min(start + pageable.getPageSize(), allResponses.size()); + + List paginatedList = allResponses.subList(start, end); + + return new PageImpl<>(paginatedList, pageable, allResponses.size()); + } + + public List getAllReceivedMatchRequests(Long clubId) { + + Club club = clubRepository.findById(clubId) + .orElseThrow(() -> new EntityNotFoundException("동아리를 찾을 수 없습니다.")); + + List matchPosts = club.getMatchPosts(); + + LocalDateTime now = LocalDateTime.now(); + + return matchPosts.stream() + .filter(matchPost -> LocalDateTime.of(matchPost.getMatchStartDate(), matchPost.getMatchStartTime()) + .isAfter(now)) + .map(matchPost -> { + List receivedRequests = matchPost.getMatchRequests() + .stream() + .map(ReceivedMatchRequestResponse::from) + .collect(Collectors.toList()); + + return MatchRequestAndMatchPostResponse.from( + matchPost, + receivedRequests + ); + }) + .collect(Collectors.toList()); + } + + @Transactional + public void decideMatchRequest(Long requestId, String decision, Long memberId) { + MatchRequest matchRequest = matchRequestRepository.findById(requestId) + .orElseThrow(() -> new EntityNotFoundException("매칭 요청을 찾을 수 없습니다.")); + + clubAdminMemberRepository.findActiveAdminByClubIdAndClubMemberId( + matchRequest.getMatchPost().getHomeClub().getClubId(), memberId) + .orElseThrow(() -> new AppException(ErrorCode.CLUB_ACCESS_DENIED)); + + // matchPost가 이미 최종 확정되었는지 확인 + if (matchRequest.getMatchPost().getIsFinalized()) { + throw new AppException(ErrorCode.CLUB_MATCH_FINALIZE); + } + + if ("ACCEPTED".equalsIgnoreCase(decision)) { + matchRequest.accept(); + matchRequest.getMatchPost().finalizeMatch(); + } else if ("REJECTED".equalsIgnoreCase(decision)) { + matchRequest.reject(); + } else { + throw new IllegalArgumentException("결정은 ACCEPTED 또는 REJECTED이어야 합니다."); + } + + matchRequestRepository.save(matchRequest); + } + + private boolean isPostValid(MatchPost matchPost) { + LocalDateTime postDateTime = LocalDateTime.of(matchPost.getMatchStartDate(), matchPost.getMatchStartTime()); + return postDateTime.isAfter(LocalDateTime.now()); + } } diff --git a/src/main/java/com/cotato/squadus/domain/club/match/service/match/MatchResultService.java b/src/main/java/com/cotato/squadus/domain/club/match/service/match/MatchResultService.java index 0f76088..c61b5af 100644 --- a/src/main/java/com/cotato/squadus/domain/club/match/service/match/MatchResultService.java +++ b/src/main/java/com/cotato/squadus/domain/club/match/service/match/MatchResultService.java @@ -1,5 +1,11 @@ package com.cotato.squadus.domain.club.match.service.match; +import java.util.List; +import java.util.stream.Collectors; + +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + import com.cotato.squadus.api.match.dto.matchResult.request.MatchResultAddRequest; import com.cotato.squadus.api.match.dto.matchResult.response.MatchDetailResponse; import com.cotato.squadus.api.match.dto.matchResult.response.MatchFinalResultResponse; @@ -15,205 +21,196 @@ import com.cotato.squadus.domain.club.match.enums.MatchingStatus; import com.cotato.squadus.domain.club.match.repository.match.MatchPostRepository; import com.cotato.squadus.domain.club.match.repository.match.MatchResultRepository; + import jakarta.persistence.EntityNotFoundException; import lombok.RequiredArgsConstructor; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -import java.util.List; -import java.util.stream.Collectors; @Service @RequiredArgsConstructor @Transactional(readOnly = true) public class MatchResultService { - private final MatchResultRepository matchResultRepository; - private final MatchPostRepository matchPostRepository; - private final ClubAdminMemberRepository clubAdminMemberRepository; - private final ClubService clubService; - - public MatchDetailResponse getMatchDetail(Long matchPostId) { - MatchPost matchPost = matchPostRepository.findById(matchPostId) - .orElseThrow(() -> new EntityNotFoundException("매칭 게시글을 찾을 수 없습니다.")); - - MatchRequest acceptedRequest = matchPost.getMatchRequests().stream() - .filter(request -> request.getStatus() == MatchingStatus.ACCEPTED) - .findFirst() - .orElseThrow(() -> new IllegalStateException("승인된 매칭 요청이 없습니다.")); - - //요청을 신청한 club - Club awayClub = acceptedRequest.getClub(); - - //매치 결과도 함께 반환 - List matchResults = matchResultRepository.findByMatchPost(matchPost).stream() - .map(MatchResultResponse::from) - .collect(Collectors.toList()); - - return MatchDetailResponse.from(matchPost, awayClub, matchResults); - } - - public MatchFinalResultResponse getWinningMatchResult(Long matchPostId) { - MatchPost matchPost = matchPostRepository.findById(matchPostId) - .orElseThrow(() -> new EntityNotFoundException("매칭 게시글을 찾을 수 없습니다.")); - return new MatchFinalResultResponse(matchPost.getHomeWins(), matchPost.getAwayWins()); - } - - - @Transactional - public MatchResultResponse addMatchResult(Long matchPostId, MatchResultAddRequest matchResultAddRequest) { - MatchPost matchPost = matchPostRepository.findById(matchPostId) - .orElseThrow(() -> new EntityNotFoundException("매칭 게시글을 찾을 수 없습니다.")); - - // Home 팀의 Admin인지 확인 - clubAdminMemberRepository.findActiveAdminByClubIdAndClubMemberId(matchPost.getHomeClub().getClubId(), matchResultAddRequest.getClubMemberId()) - .orElseThrow(() -> new AppException(ErrorCode.CLUB_ACCESS_DENIED)); - - MatchRequest acceptedRequest = matchPost.getMatchRequests().stream() - .filter(request -> request.getStatus() == MatchingStatus.ACCEPTED) - .findFirst() - .orElseThrow(() -> new IllegalStateException("승인된 매칭 요청이 없습니다.")); - - MatchResult matchResult = MatchResult.builder() - .matchPost(matchPost) - .homeClub(matchPost.getHomeClub()) - .awayClub(acceptedRequest.getClub()) - .homeScore(matchResultAddRequest.getHomeScore()) - .awayScore(matchResultAddRequest.getAwayScore()) - .build(); - - matchResultRepository.save(matchResult); - return MatchResultResponse.from(matchResult); - } - - @Transactional - public MatchResultResponse updateMatchResult(Long matchResultId, MatchResultAddRequest matchResultAddRequest) { - MatchResult matchResult = matchResultRepository.findById(matchResultId) - .orElseThrow(() -> new EntityNotFoundException("매칭 결과를 찾을 수 없습니다.")); - - MatchPost matchPost = matchResult.getMatchPost(); - - // Home 팀의 Admin인지 확인 - clubAdminMemberRepository.findActiveAdminByClubIdAndClubMemberId(matchPost.getHomeClub().getClubId(), matchResultAddRequest.getClubMemberId()) - .orElseThrow(() -> new AppException(ErrorCode.CLUB_ACCESS_DENIED)); - - // 기존 점수를 수정 - matchResult.updateScores(matchResultAddRequest.getHomeScore(), matchResultAddRequest.getAwayScore()); - - matchResultRepository.save(matchResult); - return MatchResultResponse.from(matchResult); - } - - - - @Transactional - public MatchFinalResultResponse getFinalMatchResult(Long matchPostId, Long memberId) { - MatchPost matchPost = matchPostRepository.findById(matchPostId) - .orElseThrow(() -> new EntityNotFoundException("매칭 게시글을 찾을 수 없습니다.")); - - clubAdminMemberRepository.findActiveAdminByClubIdAndClubMemberId(matchPost.getHomeClub().getClubId(), memberId) - .orElseThrow(() -> new AppException(ErrorCode.CLUB_ACCESS_DENIED)); - - int homeWins = 0; - int awayWins = 0; - List matchResults = matchResultRepository.findByMatchPost(matchPost); - for (MatchResult result : matchResults) { - if (result.getHomeScore() > result.getAwayScore()) { - homeWins++; - } else if (result.getHomeScore() < result.getAwayScore()) { - awayWins++; - } - } - - matchPost.updateWinCounts(homeWins, awayWins); - return new MatchFinalResultResponse(homeWins, awayWins); - } - - - @Transactional - public void finalizeHomeResult(Long matchPostId, Long memberId){ - - MatchPost matchPost = matchPostRepository.findById(matchPostId) - .orElseThrow(() -> new EntityNotFoundException("매칭 게시글을 찾을 수 없습니다.")); - - clubAdminMemberRepository.findActiveAdminByClubIdAndClubMemberId(matchPost.getHomeClub().getClubId(), memberId) - .orElseThrow(() -> new AppException(ErrorCode.CLUB_ACCESS_DENIED)); - - - List matchResults = matchResultRepository.findByMatchPost(matchPost); - matchResults.forEach(MatchResult::finalizeHomeResult); - - matchResultRepository.saveAll(matchResults); - } - - @Transactional - public void finalizeAwayResult(Long matchPostId, Long memberId) { - MatchPost matchPost = matchPostRepository.findById(matchPostId) - .orElseThrow(() -> new EntityNotFoundException("매칭 게시글을 찾을 수 없습니다.")); - - // Away 팀의 ClubId를 가져옴 - MatchRequest acceptedRequest = matchPost.getMatchRequests().stream() - .filter(request -> request.getStatus() == MatchingStatus.ACCEPTED) - .findFirst() - .orElseThrow(() -> new IllegalStateException("승인된 매칭 요청이 없습니다.")); - - Club awayClub = acceptedRequest.getClub(); - - // Away 팀의 Admin인지 확인 - clubAdminMemberRepository.findActiveAdminByClubIdAndClubMemberId(awayClub.getClubId(), memberId) - .orElseThrow(() -> new AppException(ErrorCode.CLUB_ACCESS_DENIED)); - - List matchResults = matchResultRepository.findByMatchPost(matchPost); - - // 결과 확정 - matchResults.forEach(MatchResult::finalizeAwayResult); - - int homeWins = matchPost.getHomeWins(); - int awayWins = matchPost.getAwayWins(); - - if (homeWins > awayWins) { - matchPost.getHomeClub().updateMatchScore(7); - awayClub.updateMatchScore(3); - } else if (homeWins < awayWins) { - matchPost.getHomeClub().updateMatchScore(3); - awayClub.updateMatchScore(7); - } else { // 비긴 경우 - matchPost.getHomeClub().updateMatchScore(5); - awayClub.updateMatchScore(5); - } - - clubService.updateClubMatchScore(matchPost.getHomeClub().getClubId()); - clubService.updateClubMatchScore(awayClub.getClubId()); - matchResultRepository.saveAll(matchResults); - } - - - - @Transactional - public void rejectFinalResult(Long matchPostId, Long memberId) { - MatchPost matchPost = matchPostRepository.findById(matchPostId) - .orElseThrow(() -> new EntityNotFoundException("매칭 게시글을 찾을 수 없습니다.")); - - // Away 팀의 ClubId를 가져옴 - MatchRequest acceptedRequest = matchPost.getMatchRequests().stream() - .filter(request -> request.getStatus() == MatchingStatus.ACCEPTED) - .findFirst() - .orElseThrow(() -> new IllegalStateException("승인된 매칭 요청이 없습니다.")); - - Club awayClub = acceptedRequest.getClub(); - - // Away 팀의 Admin인지 확인 - clubAdminMemberRepository.findActiveAdminByClubIdAndClubMemberId(awayClub.getClubId(), memberId) - .orElseThrow(() -> new AppException(ErrorCode.CLUB_ACCESS_DENIED)); - - List matchResults = matchResultRepository.findByMatchPost(matchPost); - matchResults.forEach(result -> { - result.setIsFinalizedHome(false); - result.setIsfinalizedAway(false); - }); - - matchResultRepository.saveAll(matchResults); - } + private final MatchResultRepository matchResultRepository; + private final MatchPostRepository matchPostRepository; + private final ClubAdminMemberRepository clubAdminMemberRepository; + private final ClubService clubService; + + public MatchDetailResponse getMatchDetail(Long matchPostId) { + MatchPost matchPost = matchPostRepository.findById(matchPostId) + .orElseThrow(() -> new EntityNotFoundException("매칭 게시글을 찾을 수 없습니다.")); + + MatchRequest acceptedRequest = matchPost.getMatchRequests().stream() + .filter(request -> request.getStatus() == MatchingStatus.ACCEPTED) + .findFirst() + .orElseThrow(() -> new IllegalStateException("승인된 매칭 요청이 없습니다.")); + + //요청을 신청한 club + Club awayClub = acceptedRequest.getClub(); + + //매치 결과도 함께 반환 + List matchResults = matchResultRepository.findByMatchPost(matchPost).stream() + .map(MatchResultResponse::from) + .collect(Collectors.toList()); + + return MatchDetailResponse.from(matchPost, awayClub, matchResults); + } + + public MatchFinalResultResponse getWinningMatchResult(Long matchPostId) { + MatchPost matchPost = matchPostRepository.findById(matchPostId) + .orElseThrow(() -> new EntityNotFoundException("매칭 게시글을 찾을 수 없습니다.")); + return new MatchFinalResultResponse(matchPost.getHomeWins(), matchPost.getAwayWins()); + } + + @Transactional + public MatchResultResponse addMatchResult(Long matchPostId, MatchResultAddRequest matchResultAddRequest) { + MatchPost matchPost = matchPostRepository.findById(matchPostId) + .orElseThrow(() -> new EntityNotFoundException("매칭 게시글을 찾을 수 없습니다.")); + + // Home 팀의 Admin인지 확인 + clubAdminMemberRepository.findActiveAdminByClubIdAndClubMemberId(matchPost.getHomeClub().getClubId(), + matchResultAddRequest.getClubMemberId()) + .orElseThrow(() -> new AppException(ErrorCode.CLUB_ACCESS_DENIED)); + + MatchRequest acceptedRequest = matchPost.getMatchRequests().stream() + .filter(request -> request.getStatus() == MatchingStatus.ACCEPTED) + .findFirst() + .orElseThrow(() -> new IllegalStateException("승인된 매칭 요청이 없습니다.")); + + MatchResult matchResult = MatchResult.builder() + .matchPost(matchPost) + .homeClub(matchPost.getHomeClub()) + .awayClub(acceptedRequest.getClub()) + .homeScore(matchResultAddRequest.getHomeScore()) + .awayScore(matchResultAddRequest.getAwayScore()) + .build(); + + matchResultRepository.save(matchResult); + return MatchResultResponse.from(matchResult); + } + + @Transactional + public MatchResultResponse updateMatchResult(Long matchResultId, MatchResultAddRequest matchResultAddRequest) { + MatchResult matchResult = matchResultRepository.findById(matchResultId) + .orElseThrow(() -> new EntityNotFoundException("매칭 결과를 찾을 수 없습니다.")); + + MatchPost matchPost = matchResult.getMatchPost(); + + // Home 팀의 Admin인지 확인 + clubAdminMemberRepository.findActiveAdminByClubIdAndClubMemberId(matchPost.getHomeClub().getClubId(), + matchResultAddRequest.getClubMemberId()) + .orElseThrow(() -> new AppException(ErrorCode.CLUB_ACCESS_DENIED)); + + // 기존 점수를 수정 + matchResult.updateScores(matchResultAddRequest.getHomeScore(), matchResultAddRequest.getAwayScore()); + + matchResultRepository.save(matchResult); + return MatchResultResponse.from(matchResult); + } + + @Transactional + public MatchFinalResultResponse getFinalMatchResult(Long matchPostId, Long memberId) { + MatchPost matchPost = matchPostRepository.findById(matchPostId) + .orElseThrow(() -> new EntityNotFoundException("매칭 게시글을 찾을 수 없습니다.")); + + clubAdminMemberRepository.findActiveAdminByClubIdAndClubMemberId(matchPost.getHomeClub().getClubId(), memberId) + .orElseThrow(() -> new AppException(ErrorCode.CLUB_ACCESS_DENIED)); + + int homeWins = 0; + int awayWins = 0; + List matchResults = matchResultRepository.findByMatchPost(matchPost); + for (MatchResult result : matchResults) { + if (result.getHomeScore() > result.getAwayScore()) { + homeWins++; + } else if (result.getHomeScore() < result.getAwayScore()) { + awayWins++; + } + } + + matchPost.updateWinCounts(homeWins, awayWins); + return new MatchFinalResultResponse(homeWins, awayWins); + } + + @Transactional + public void finalizeHomeResult(Long matchPostId, Long memberId) { + + MatchPost matchPost = matchPostRepository.findById(matchPostId) + .orElseThrow(() -> new EntityNotFoundException("매칭 게시글을 찾을 수 없습니다.")); + + clubAdminMemberRepository.findActiveAdminByClubIdAndClubMemberId(matchPost.getHomeClub().getClubId(), memberId) + .orElseThrow(() -> new AppException(ErrorCode.CLUB_ACCESS_DENIED)); + + List matchResults = matchResultRepository.findByMatchPost(matchPost); + matchResults.forEach(MatchResult::finalizeHomeResult); + + matchResultRepository.saveAll(matchResults); + } + + @Transactional + public void finalizeAwayResult(Long matchPostId, Long memberId) { + MatchPost matchPost = matchPostRepository.findById(matchPostId) + .orElseThrow(() -> new EntityNotFoundException("매칭 게시글을 찾을 수 없습니다.")); + + // Away 팀의 ClubId를 가져옴 + MatchRequest acceptedRequest = matchPost.getMatchRequests().stream() + .filter(request -> request.getStatus() == MatchingStatus.ACCEPTED) + .findFirst() + .orElseThrow(() -> new IllegalStateException("승인된 매칭 요청이 없습니다.")); + + Club awayClub = acceptedRequest.getClub(); + + // Away 팀의 Admin인지 확인 + clubAdminMemberRepository.findActiveAdminByClubIdAndClubMemberId(awayClub.getClubId(), memberId) + .orElseThrow(() -> new AppException(ErrorCode.CLUB_ACCESS_DENIED)); + + List matchResults = matchResultRepository.findByMatchPost(matchPost); + + // 결과 확정 + matchResults.forEach(MatchResult::finalizeAwayResult); + + int homeWins = matchPost.getHomeWins(); + int awayWins = matchPost.getAwayWins(); + + if (homeWins > awayWins) { + matchPost.getHomeClub().updateMatchScore(7); + awayClub.updateMatchScore(3); + } else if (homeWins < awayWins) { + matchPost.getHomeClub().updateMatchScore(3); + awayClub.updateMatchScore(7); + } else { // 비긴 경우 + matchPost.getHomeClub().updateMatchScore(5); + awayClub.updateMatchScore(5); + } + + clubService.updateClubMatchScore(matchPost.getHomeClub().getClubId()); + clubService.updateClubMatchScore(awayClub.getClubId()); + matchResultRepository.saveAll(matchResults); + } + + @Transactional + public void rejectFinalResult(Long matchPostId, Long memberId) { + MatchPost matchPost = matchPostRepository.findById(matchPostId) + .orElseThrow(() -> new EntityNotFoundException("매칭 게시글을 찾을 수 없습니다.")); + + // Away 팀의 ClubId를 가져옴 + MatchRequest acceptedRequest = matchPost.getMatchRequests().stream() + .filter(request -> request.getStatus() == MatchingStatus.ACCEPTED) + .findFirst() + .orElseThrow(() -> new IllegalStateException("승인된 매칭 요청이 없습니다.")); + + Club awayClub = acceptedRequest.getClub(); + + // Away 팀의 Admin인지 확인 + clubAdminMemberRepository.findActiveAdminByClubIdAndClubMemberId(awayClub.getClubId(), memberId) + .orElseThrow(() -> new AppException(ErrorCode.CLUB_ACCESS_DENIED)); + + List matchResults = matchResultRepository.findByMatchPost(matchPost); + matchResults.forEach(result -> { + result.setIsFinalizedHome(false); + result.setIsfinalizedAway(false); + }); + + matchResultRepository.saveAll(matchResults); + } } diff --git a/src/main/java/com/cotato/squadus/domain/club/match/service/match/MatchService.java b/src/main/java/com/cotato/squadus/domain/club/match/service/match/MatchService.java index 93ebcfd..2e5bc15 100644 --- a/src/main/java/com/cotato/squadus/domain/club/match/service/match/MatchService.java +++ b/src/main/java/com/cotato/squadus/domain/club/match/service/match/MatchService.java @@ -1,6 +1,21 @@ package com.cotato.squadus.domain.club.match.service.match; -import com.cotato.squadus.api.match.dto.matchPost.request.*; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.LocalTime; +import java.util.List; +import java.util.stream.Collectors; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.stereotype.Service; + +import com.cotato.squadus.api.match.dto.matchPost.request.FilterRequest; +import com.cotato.squadus.api.match.dto.matchPost.request.MatchCreateRequest; +import com.cotato.squadus.api.match.dto.matchPost.request.MatchRequestRequest; +import com.cotato.squadus.api.match.dto.matchPost.request.SearchRequest; import com.cotato.squadus.api.match.dto.matchPost.response.MatchCreateResponse; import com.cotato.squadus.api.match.dto.matchPost.response.MatchRequestResponse; import com.cotato.squadus.common.error.ErrorCode; @@ -13,244 +28,232 @@ import com.cotato.squadus.domain.club.common.repository.ClubAdminMemberRepository; import com.cotato.squadus.domain.club.common.repository.ClubMemberRepository; import com.cotato.squadus.domain.club.common.repository.ClubRepository; -import com.cotato.squadus.domain.club.match.entity.*; +import com.cotato.squadus.domain.club.match.entity.MatchPlace; import com.cotato.squadus.domain.club.match.entity.match.MatchPost; import com.cotato.squadus.domain.club.match.entity.match.MatchRequest; import com.cotato.squadus.domain.club.match.enums.MatchingStatus; import com.cotato.squadus.domain.club.match.repository.match.MatchPostRepository; import com.cotato.squadus.domain.club.match.repository.match.MatchRequestRepository; + import jakarta.persistence.EntityNotFoundException; import jakarta.transaction.Transactional; import lombok.RequiredArgsConstructor; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.data.domain.Page; -import org.springframework.data.domain.Pageable; -import org.springframework.stereotype.Service; - -import java.time.LocalDate; -import java.time.LocalDateTime; -import java.time.LocalTime; -import java.util.List; -import java.util.stream.Collectors; @Service @RequiredArgsConstructor public class MatchService { - private static final Logger log = LoggerFactory.getLogger(MatchService.class); - private final MatchPostRepository matchPostRepository; - private final MatchRequestRepository matchRequestRepository; - private final ClubRepository clubRepository; - private final ClubMemberRepository clubMemberRepository; - private final ClubAdminMemberRepository clubAdminMemberRepository; - - @Transactional - public MatchCreateResponse createMatch(MatchCreateRequest matchCreateRequest) { - Club homeClub = clubRepository.findById(matchCreateRequest.getHomeClubId()) - .orElseThrow(() -> new EntityNotFoundException("동아리를 찾을 수 없습니다.")); - - // 해당 club의 임원인지 확인 - if (!clubAdminMemberRepository.findActiveAdminByClubIdAndClubMemberId(homeClub.getClubId(), matchCreateRequest.getClubMemberId()).isPresent()) { - throw new AppException(ErrorCode.CLUB_ACCESS_DENIED); - } - - MatchPlace matchPlace = new MatchPlace(matchCreateRequest.getMatchPlace().getCity(), - matchCreateRequest.getMatchPlace().getDistrict()); - - MatchPost matchPost = MatchPost.builder() - .homeClub(homeClub) - .title(matchCreateRequest.getTitle()) - .content(matchCreateRequest.getContent()) - .tier(Tier.valueOf(matchCreateRequest.getTier())) - .matchPlace(matchPlace) - .placeProvided(matchCreateRequest.getPlaceProvided()) - .matchStartDate(matchCreateRequest.getMatchStartDate()) - .matchStartTime(matchCreateRequest.getMatchStartTime()) - .maxParticipants(matchCreateRequest.getMaxParticipants()) - .build(); - - homeClub.addMatchPost(matchPost); - - matchPostRepository.save(matchPost); - return MatchCreateResponse.from(matchPost); - } - - - public List findAllMatches() { - - LocalDateTime now = LocalDateTime.now(); - - return matchPostRepository.findAll().stream() - .filter(matchPost -> { - LocalDateTime matchDateTime = LocalDateTime.of(matchPost.getMatchStartDate(), matchPost.getMatchStartTime()); - return matchDateTime.isAfter(now); - }) - .map(MatchCreateResponse::from) - .collect(Collectors.toList()); - } - - - public Page findAllMatches(Pageable pageable) { - - LocalDate today = LocalDate.now(); - LocalTime nowTime = LocalTime.now(); - - // 데이터베이스에서 직접 필터링 및 페이징 처리하여 가져오기 - Page matchPostPage = matchPostRepository - .findAllByMatchStartDateAfterOrMatchStartDateEqualsAndMatchStartTimeAfter( - today, nowTime, pageable); - - // 페이지 내용을 DTO로 변환 - return matchPostPage.map(MatchCreateResponse::from); - } - - - public List getFilteredMatches(FilterRequest filterRequest, Long clubMemberId) { - - // 사용자의 ClubMember 정보를 가져옵니다. - ClubMember clubMember = clubMemberRepository.findClubMemberByClubMemberIdx(clubMemberId) - .orElseThrow(() -> new EntityNotFoundException("동아리 멤버를 찾을 수 없습니다.")); - - // 사용자의 동아리를 가져옵니다. - Club userClub = clubMember.getClub(); - - SportsCategory sportsCategory = null; - ClubTier tier = null; - LocalDateTime now = LocalDateTime.now(); - - if (filterRequest.getSportsCategory() != null) { - sportsCategory = SportsCategory.valueOf(filterRequest.getSportsCategory()); - } - - if (filterRequest.getTier() != null) { - tier = ClubTier.valueOf(filterRequest.getTier()); - } - - List matchPosts = matchPostRepository.customFindMatchesByFilter( - sportsCategory, - filterRequest.getCity(), - filterRequest.getDistrict(), - tier, - filterRequest.getPlaceProvided() - ); - - return matchPosts.stream() - .filter(matchPost -> { - LocalDateTime matchDateTime = LocalDateTime.of(matchPost.getMatchStartDate(), matchPost.getMatchStartTime()); - return !matchPost.getHomeClub().equals(userClub) && matchDateTime.isAfter(now); - }) - .map(MatchCreateResponse::from) - .collect(Collectors.toList()); - } - - - public List searchMatches(SearchRequest searchRequest, Long clubMemberId) { - // 사용자의 ClubMember 정보를 가져옵니다. - ClubMember clubMember = clubMemberRepository.findClubMemberByClubMemberIdx(clubMemberId) - .orElseThrow(() -> new EntityNotFoundException("동아리 멤버를 찾을 수 없습니다.")); - - // 사용자의 동아리를 가져옵니다. - Club userClub = clubMember.getClub(); - LocalDateTime now = LocalDateTime.now(); - - return matchPostRepository.customFindByKeyword(searchRequest.getKeyword()).stream() - .filter(matchPost -> { - LocalDateTime matchDateTime = LocalDateTime.of(matchPost.getMatchStartDate(), matchPost.getMatchStartTime()); - return !matchPost.getHomeClub().equals(userClub) && matchDateTime.isAfter(now); - }) // 사용자의 동아리에서 작성한 글 제외 - .map(MatchCreateResponse::from) - .collect(Collectors.toList()); - } - - - @Transactional - public MatchRequestResponse sendMatchRequest(MatchRequestRequest matchRequestRequest) { - //매칭을 요청한 ClubMember - ClubMember clubMember = clubMemberRepository.findById(matchRequestRequest.getClubMemberId()) - .orElseThrow(() -> new EntityNotFoundException("동아리 멤버를 찾을 수 없습니다.")); - - // 해당 club의 임원인지 확인 - if (!clubAdminMemberRepository.findActiveAdminByClubIdAndClubMemberId(clubMember.getClub().getClubId(), clubMember.getClubMemberIdx()).isPresent()) { - throw new AppException(ErrorCode.CLUB_ACCESS_DENIED); - } - - //다른 동아리에서 작성한 매칭 게시글 - MatchPost matchPost = matchPostRepository.findById(matchRequestRequest.getMatchPostId()) - .orElseThrow(() -> new EntityNotFoundException("매칭 게시글을 찾을 수 없습니다.")); - - // ClubMember가 속한 동아리가 MatchPost 작성 동아리인지 확인 - if (matchPost.getHomeClub().equals(clubMember.getClub())) { - throw new AppException(ErrorCode.CLUB_ACCESS_DENIED); - } - - // 이미 신청한 클럽 요청이 있는지 확인 - if (matchRequestRepository.findTop1ByClubAndMatchPost(clubMember.getClub(), matchPost).isPresent()) { - throw new AppException(ErrorCode.DUPLICATE_REQUEST); - } - - MatchRequest matchRequest = MatchRequest.builder() - .club(clubMember.getClub()) // 다시 보기 - .matchPost(matchPost) - .status(MatchingStatus.PENDING) - .build(); - - matchPost.addMatchRequest(matchRequest); - - matchRequestRepository.save(matchRequest); - return MatchRequestResponse.from(matchRequest); - } - - - - @Transactional - public MatchCreateResponse updateMatchPost(Long matchPostId, MatchCreateRequest matchCreateRequest) { - MatchPost matchPost= matchPostRepository.findById(matchPostId) - .orElseThrow(() -> new EntityNotFoundException("매칭 게시글을 찾을 수 없습니다.")); - - Club homeClub = clubRepository.findById(matchCreateRequest.getHomeClubId()) - .orElseThrow(() -> new EntityNotFoundException("동아리를 찾을 수 없습니다.")); - - if (!clubAdminMemberRepository.findActiveAdminByClubIdAndClubMemberId(homeClub.getClubId(), matchCreateRequest.getClubMemberId()).isPresent()) { - throw new AppException(ErrorCode.CLUB_ACCESS_DENIED); - } - - matchPost.update( - matchCreateRequest.getTitle(), - matchCreateRequest.getContent(), - new MatchPlace(matchCreateRequest.getMatchPlace().getCity(), matchCreateRequest.getMatchPlace().getDistrict()), - matchCreateRequest.getPlaceProvided(), - matchCreateRequest.getMatchStartDate(), - matchCreateRequest.getMatchStartTime(), - matchCreateRequest.getMaxParticipants() - ); - - matchPostRepository.save(matchPost); - return MatchCreateResponse.from(matchPost); - } - - - @Transactional - public MatchCreateResponse deleteMatchPost(Long matchIdx, Long clubMemberId) { - MatchPost matchPost = matchPostRepository.findById(matchIdx) - .orElseThrow(() -> new EntityNotFoundException("해당 용병 매칭 게시글을 찾을 수 없습니다.")); - - // 해당 게시글을 작성한 동아리를 찾습니다. - Club homeClub = matchPost.getHomeClub(); - - // 요청한 사용자가 해당 동아리의 관리자인지 확인합니다. - boolean isAdmin = clubAdminMemberRepository.findActiveAdminByClubIdAndClubMemberId(homeClub.getClubId(), clubMemberId) - .isPresent(); - - // 관리자가 아니라면 접근 권한이 없음을 예외 처리합니다. - if (!isAdmin) { - throw new AppException(ErrorCode.CLUB_ACCESS_DENIED); - } - - matchPostRepository.delete(matchPost); - return MatchCreateResponse.from(matchPost); - } - - + private static final Logger log = LoggerFactory.getLogger(MatchService.class); + private final MatchPostRepository matchPostRepository; + private final MatchRequestRepository matchRequestRepository; + private final ClubRepository clubRepository; + private final ClubMemberRepository clubMemberRepository; + private final ClubAdminMemberRepository clubAdminMemberRepository; + + @Transactional + public MatchCreateResponse createMatch(MatchCreateRequest matchCreateRequest) { + Club homeClub = clubRepository.findById(matchCreateRequest.getHomeClubId()) + .orElseThrow(() -> new EntityNotFoundException("동아리를 찾을 수 없습니다.")); + + // 해당 club의 임원인지 확인 + if (!clubAdminMemberRepository.findActiveAdminByClubIdAndClubMemberId(homeClub.getClubId(), + matchCreateRequest.getClubMemberId()).isPresent()) { + throw new AppException(ErrorCode.CLUB_ACCESS_DENIED); + } + + MatchPlace matchPlace = new MatchPlace(matchCreateRequest.getMatchPlace().getCity(), + matchCreateRequest.getMatchPlace().getDistrict()); + + MatchPost matchPost = MatchPost.builder() + .homeClub(homeClub) + .title(matchCreateRequest.getTitle()) + .content(matchCreateRequest.getContent()) + .tier(Tier.valueOf(matchCreateRequest.getTier())) + .matchPlace(matchPlace) + .placeProvided(matchCreateRequest.getPlaceProvided()) + .matchStartDate(matchCreateRequest.getMatchStartDate()) + .matchStartTime(matchCreateRequest.getMatchStartTime()) + .maxParticipants(matchCreateRequest.getMaxParticipants()) + .build(); + + homeClub.addMatchPost(matchPost); + + matchPostRepository.save(matchPost); + return MatchCreateResponse.from(matchPost); + } + + public List findAllMatches() { + + LocalDateTime now = LocalDateTime.now(); + + return matchPostRepository.findAll().stream() + .filter(matchPost -> { + LocalDateTime matchDateTime = LocalDateTime.of(matchPost.getMatchStartDate(), + matchPost.getMatchStartTime()); + return matchDateTime.isAfter(now); + }) + .map(MatchCreateResponse::from) + .collect(Collectors.toList()); + } + + public Page findAllMatches(Pageable pageable) { + + LocalDate today = LocalDate.now(); + LocalTime nowTime = LocalTime.now(); + + // 데이터베이스에서 직접 필터링 및 페이징 처리하여 가져오기 + Page matchPostPage = matchPostRepository + .findAllByMatchStartDateAfterOrMatchStartDateEqualsAndMatchStartTimeAfter( + today, nowTime, pageable); + + // 페이지 내용을 DTO로 변환 + return matchPostPage.map(MatchCreateResponse::from); + } + + public List getFilteredMatches(FilterRequest filterRequest, Long clubMemberId) { + + // 사용자의 ClubMember 정보를 가져옵니다. + ClubMember clubMember = clubMemberRepository.findClubMemberByClubMemberIdx(clubMemberId) + .orElseThrow(() -> new EntityNotFoundException("동아리 멤버를 찾을 수 없습니다.")); + + // 사용자의 동아리를 가져옵니다. + Club userClub = clubMember.getClub(); + + SportsCategory sportsCategory = null; + ClubTier tier = null; + LocalDateTime now = LocalDateTime.now(); + + if (filterRequest.getSportsCategory() != null) { + sportsCategory = SportsCategory.valueOf(filterRequest.getSportsCategory()); + } + + if (filterRequest.getTier() != null) { + tier = ClubTier.valueOf(filterRequest.getTier()); + } + + List matchPosts = matchPostRepository.customFindMatchesByFilter( + sportsCategory, + filterRequest.getCity(), + filterRequest.getDistrict(), + tier, + filterRequest.getPlaceProvided() + ); + + return matchPosts.stream() + .filter(matchPost -> { + LocalDateTime matchDateTime = LocalDateTime.of(matchPost.getMatchStartDate(), + matchPost.getMatchStartTime()); + return !matchPost.getHomeClub().equals(userClub) && matchDateTime.isAfter(now); + }) + .map(MatchCreateResponse::from) + .collect(Collectors.toList()); + } + + public List searchMatches(SearchRequest searchRequest, Long clubMemberId) { + // 사용자의 ClubMember 정보를 가져옵니다. + ClubMember clubMember = clubMemberRepository.findClubMemberByClubMemberIdx(clubMemberId) + .orElseThrow(() -> new EntityNotFoundException("동아리 멤버를 찾을 수 없습니다.")); + + // 사용자의 동아리를 가져옵니다. + Club userClub = clubMember.getClub(); + LocalDateTime now = LocalDateTime.now(); + + return matchPostRepository.customFindByKeyword(searchRequest.getKeyword()).stream() + .filter(matchPost -> { + LocalDateTime matchDateTime = LocalDateTime.of(matchPost.getMatchStartDate(), + matchPost.getMatchStartTime()); + return !matchPost.getHomeClub().equals(userClub) && matchDateTime.isAfter(now); + }) // 사용자의 동아리에서 작성한 글 제외 + .map(MatchCreateResponse::from) + .collect(Collectors.toList()); + } + + @Transactional + public MatchRequestResponse sendMatchRequest(MatchRequestRequest matchRequestRequest) { + //매칭을 요청한 ClubMember + ClubMember clubMember = clubMemberRepository.findById(matchRequestRequest.getClubMemberId()) + .orElseThrow(() -> new EntityNotFoundException("동아리 멤버를 찾을 수 없습니다.")); + + // 해당 club의 임원인지 확인 + if (!clubAdminMemberRepository.findActiveAdminByClubIdAndClubMemberId(clubMember.getClub().getClubId(), + clubMember.getClubMemberIdx()).isPresent()) { + throw new AppException(ErrorCode.CLUB_ACCESS_DENIED); + } + + //다른 동아리에서 작성한 매칭 게시글 + MatchPost matchPost = matchPostRepository.findById(matchRequestRequest.getMatchPostId()) + .orElseThrow(() -> new EntityNotFoundException("매칭 게시글을 찾을 수 없습니다.")); + + // ClubMember가 속한 동아리가 MatchPost 작성 동아리인지 확인 + if (matchPost.getHomeClub().equals(clubMember.getClub())) { + throw new AppException(ErrorCode.CLUB_ACCESS_DENIED); + } + + // 이미 신청한 클럽 요청이 있는지 확인 + if (matchRequestRepository.findTop1ByClubAndMatchPost(clubMember.getClub(), matchPost).isPresent()) { + throw new AppException(ErrorCode.DUPLICATE_REQUEST); + } + + MatchRequest matchRequest = MatchRequest.builder() + .club(clubMember.getClub()) // 다시 보기 + .matchPost(matchPost) + .status(MatchingStatus.PENDING) + .build(); + + matchPost.addMatchRequest(matchRequest); + + matchRequestRepository.save(matchRequest); + return MatchRequestResponse.from(matchRequest); + } + + @Transactional + public MatchCreateResponse updateMatchPost(Long matchPostId, MatchCreateRequest matchCreateRequest) { + MatchPost matchPost = matchPostRepository.findById(matchPostId) + .orElseThrow(() -> new EntityNotFoundException("매칭 게시글을 찾을 수 없습니다.")); + + Club homeClub = clubRepository.findById(matchCreateRequest.getHomeClubId()) + .orElseThrow(() -> new EntityNotFoundException("동아리를 찾을 수 없습니다.")); + + if (!clubAdminMemberRepository.findActiveAdminByClubIdAndClubMemberId(homeClub.getClubId(), + matchCreateRequest.getClubMemberId()).isPresent()) { + throw new AppException(ErrorCode.CLUB_ACCESS_DENIED); + } + + matchPost.update( + matchCreateRequest.getTitle(), + matchCreateRequest.getContent(), + new MatchPlace(matchCreateRequest.getMatchPlace().getCity(), + matchCreateRequest.getMatchPlace().getDistrict()), + matchCreateRequest.getPlaceProvided(), + matchCreateRequest.getMatchStartDate(), + matchCreateRequest.getMatchStartTime(), + matchCreateRequest.getMaxParticipants() + ); + + matchPostRepository.save(matchPost); + return MatchCreateResponse.from(matchPost); + } + + @Transactional + public MatchCreateResponse deleteMatchPost(Long matchIdx, Long clubMemberId) { + MatchPost matchPost = matchPostRepository.findById(matchIdx) + .orElseThrow(() -> new EntityNotFoundException("해당 용병 매칭 게시글을 찾을 수 없습니다.")); + + // 해당 게시글을 작성한 동아리를 찾습니다. + Club homeClub = matchPost.getHomeClub(); + + // 요청한 사용자가 해당 동아리의 관리자인지 확인합니다. + boolean isAdmin = clubAdminMemberRepository.findActiveAdminByClubIdAndClubMemberId(homeClub.getClubId(), + clubMemberId) + .isPresent(); + + // 관리자가 아니라면 접근 권한이 없음을 예외 처리합니다. + if (!isAdmin) { + throw new AppException(ErrorCode.CLUB_ACCESS_DENIED); + } + + matchPostRepository.delete(matchPost); + return MatchCreateResponse.from(matchPost); + } } diff --git a/src/main/java/com/cotato/squadus/domain/club/match/service/mercenary/MercenaryRequestService.java b/src/main/java/com/cotato/squadus/domain/club/match/service/mercenary/MercenaryRequestService.java index 7f22f61..4a3002b 100644 --- a/src/main/java/com/cotato/squadus/domain/club/match/service/mercenary/MercenaryRequestService.java +++ b/src/main/java/com/cotato/squadus/domain/club/match/service/mercenary/MercenaryRequestService.java @@ -1,5 +1,16 @@ package com.cotato.squadus.domain.club.match.service.mercenary; +import java.time.LocalDateTime; +import java.util.List; +import java.util.stream.Collectors; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageImpl; +import org.springframework.data.domain.Pageable; +import org.springframework.stereotype.Service; + import com.cotato.squadus.api.mercenary.dto.response.MercenaryRequestAndMercenaryPostResponse; import com.cotato.squadus.api.mercenary.dto.response.MercenaryRequestResponse; import com.cotato.squadus.api.mercenary.dto.response.ReceivedMercenaryRequestResponse; @@ -9,173 +20,158 @@ import com.cotato.squadus.domain.auth.entity.Member; import com.cotato.squadus.domain.auth.repository.MemberRepository; import com.cotato.squadus.domain.club.common.entity.Club; -import com.cotato.squadus.domain.club.common.entity.ClubMember; import com.cotato.squadus.domain.club.common.repository.ClubAdminMemberRepository; import com.cotato.squadus.domain.club.common.repository.ClubRepository; import com.cotato.squadus.domain.club.match.entity.mercenary.MercenaryPost; import com.cotato.squadus.domain.club.match.entity.mercenary.MercenaryRequest; import com.cotato.squadus.domain.club.match.repository.mercenary.MercenaryPostRepository; import com.cotato.squadus.domain.club.match.repository.mercenary.MercenaryRequestRepository; + import jakarta.persistence.EntityNotFoundException; import jakarta.transaction.Transactional; import lombok.RequiredArgsConstructor; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.data.domain.Page; -import org.springframework.data.domain.PageImpl; -import org.springframework.data.domain.Pageable; -import org.springframework.stereotype.Service; - -import java.time.LocalDateTime; -import java.util.List; -import java.util.stream.Collectors; @Service @RequiredArgsConstructor public class MercenaryRequestService { - private static final Logger log = LoggerFactory.getLogger(MercenaryRequestService.class); - private final MercenaryRequestRepository mercenaryRequestRepository; - private final ClubAdminMemberRepository clubAdminMemberRepository; - private final ClubRepository clubRepository; - private final MercenaryPostRepository mercenaryPostRepository; - private final MemberRepository memberRepository; - - public Page getMyRequests(CustomOAuth2Member customOAuth2Member, Pageable pageable) { - Member member = memberRepository.findByUniqueId(customOAuth2Member.getUniqueId()) - .orElseThrow(() -> new EntityNotFoundException("해당 uniqueId를 가진 회원이 존재하지 않습니다.")); - Page requestsPage = mercenaryRequestRepository.findAllByMember_MemberIdx(member, pageable); - - // 유효한 MercenaryPost만 필터링하여 새로운 리스트로 변환 - List filteredResponses = requestsPage - .stream() - .filter(mercenaryRequest -> isPostValid(mercenaryRequest.getMercenaryPost())) - .map(MercenaryRequestResponse::from) - .collect(Collectors.toList()); - - // 필터링된 리스트를 Page 객체로 변환하여 반환 - return new PageImpl<>(filteredResponses, pageable, requestsPage.getTotalElements()); - } - - - public List getAllMyRequests(CustomOAuth2Member customOAuth2Member) { - Member member = memberRepository.findByUniqueId(customOAuth2Member.getUniqueId()) - .orElseThrow(() -> new EntityNotFoundException("해당 uniqueId를 가진 회원이 존재하지 않습니다.")); - - return mercenaryRequestRepository.findAllByMember_MemberIdx(member) - .stream() - .filter(mercenaryRequest -> isPostValid(mercenaryRequest.getMercenaryPost())) - .map(MercenaryRequestResponse::from) - .collect(Collectors.toList()); - } - - - - @Transactional - public void cancelMatchRequest(Long requestId, CustomOAuth2Member customOAuth2Member) { - Member member = memberRepository.findByUniqueId(customOAuth2Member.getUniqueId()) - .orElseThrow(() -> new EntityNotFoundException("해당 uniqueId를 가진 회원이 존재하지 않습니다.")); - - MercenaryRequest mercenaryRequest = mercenaryRequestRepository.findById(requestId) - .orElseThrow(() -> new EntityNotFoundException("매칭 요청을 찾을 수 없습니다.")); - - // 요청을 취소하려는 사용자가 이 요청을 만든 사용자인지 확인 - if (!mercenaryRequest.getMember().getMemberIdx().equals(member.getMemberIdx())) { - throw new AppException(ErrorCode.CLUB_ACCESS_DENIED); - } - - mercenaryRequestRepository.delete(mercenaryRequest); - } - - - - public Page getReceivedMatchRequests(Long clubId, Pageable pageable) { - - Club club = clubRepository.findById(clubId) - .orElseThrow(() -> new EntityNotFoundException("동아리를 찾을 수 없습니다.")); - - List mercenaryPosts = mercenaryPostRepository.findByHomeClub(club); - - LocalDateTime now = LocalDateTime.now(); - - List allResponses = mercenaryPosts.stream() - .filter(mercenaryPost -> LocalDateTime.of(mercenaryPost.getMatchStartDate(), mercenaryPost.getMatchStartTime()).isAfter(now)) - .map(mercenaryPost -> { - List receivedRequests = mercenaryPost.getMercenaryRequests() - .stream() - .map(ReceivedMercenaryRequestResponse::from) - .collect(Collectors.toList()); - - return MercenaryRequestAndMercenaryPostResponse.from( - mercenaryPost, - receivedRequests - ); - }) - .collect(Collectors.toList()); - - // allResponses 리스트를 pageable에 맞게 자름 - int start = (int) pageable.getOffset(); - int end = Math.min(start + pageable.getPageSize(), allResponses.size()); - - List paginatedList = allResponses.subList(start, end); - - return new PageImpl<>(paginatedList, pageable, allResponses.size()); - } - - - public List getAllReceivedMatchRequests(Long clubId) { - - Club club = clubRepository.findById(clubId) - .orElseThrow(() -> new EntityNotFoundException("동아리를 찾을 수 없습니다.")); - - List mercenaryPosts = club.getMercenaryPosts(); - - LocalDateTime now = LocalDateTime.now(); - - return mercenaryPosts.stream() - .filter(mercenaryPost -> LocalDateTime.of(mercenaryPost.getMatchStartDate(), mercenaryPost.getMatchStartTime()).isAfter(now)) - .map(mercenaryPost -> { - List receivedRequests = mercenaryPost.getMercenaryRequests() - .stream() - .map(ReceivedMercenaryRequestResponse::from) - .collect(Collectors.toList()); - - return MercenaryRequestAndMercenaryPostResponse.from( - mercenaryPost, - receivedRequests - ); - }) - .collect(Collectors.toList()); - } - - - - - @Transactional - public void decideMatchRequest(Long requestId, String decision, Long memberId) { - MercenaryRequest mercenaryRequest = mercenaryRequestRepository.findById(requestId) - .orElseThrow(() -> new EntityNotFoundException("매칭 요청을 찾을 수 없습니다.")); - - // 해당 용병 요청이 속한 Club의 Admin 권한 확인 - clubAdminMemberRepository.findActiveAdminByClubIdAndClubMemberId( - mercenaryRequest.getMercenaryPost().getHomeClub().getClubId(), memberId) - .orElseThrow(() -> new AppException(ErrorCode.CLUB_ACCESS_DENIED)); - - - if ("ACCEPTED".equalsIgnoreCase(decision)) { - mercenaryRequest.accept(); - mercenaryRequest.getMercenaryPost().incrementParticipants(); // 현재 인원 증가 - } else if ("REJECTED".equalsIgnoreCase(decision)) { - mercenaryRequest.reject(); - } else { - throw new IllegalArgumentException("결정은 ACCEPTED 또는 REJECTED이어야 합니다."); - } - - mercenaryRequestRepository.save(mercenaryRequest); - } - - private boolean isPostValid(MercenaryPost mercenaryPost) { - LocalDateTime postDateTime = LocalDateTime.of(mercenaryPost.getMatchStartDate(), mercenaryPost.getMatchStartTime()); - return postDateTime.isAfter(LocalDateTime.now()); - } + private static final Logger log = LoggerFactory.getLogger(MercenaryRequestService.class); + private final MercenaryRequestRepository mercenaryRequestRepository; + private final ClubAdminMemberRepository clubAdminMemberRepository; + private final ClubRepository clubRepository; + private final MercenaryPostRepository mercenaryPostRepository; + private final MemberRepository memberRepository; + + public Page getMyRequests(CustomOAuth2Member customOAuth2Member, Pageable pageable) { + Member member = memberRepository.findByUniqueId(customOAuth2Member.getUniqueId()) + .orElseThrow(() -> new EntityNotFoundException("해당 uniqueId를 가진 회원이 존재하지 않습니다.")); + Page requestsPage = mercenaryRequestRepository.findAllByMember_MemberIdx(member, pageable); + + // 유효한 MercenaryPost만 필터링하여 새로운 리스트로 변환 + List filteredResponses = requestsPage + .stream() + .filter(mercenaryRequest -> isPostValid(mercenaryRequest.getMercenaryPost())) + .map(MercenaryRequestResponse::from) + .collect(Collectors.toList()); + + // 필터링된 리스트를 Page 객체로 변환하여 반환 + return new PageImpl<>(filteredResponses, pageable, requestsPage.getTotalElements()); + } + + public List getAllMyRequests(CustomOAuth2Member customOAuth2Member) { + Member member = memberRepository.findByUniqueId(customOAuth2Member.getUniqueId()) + .orElseThrow(() -> new EntityNotFoundException("해당 uniqueId를 가진 회원이 존재하지 않습니다.")); + + return mercenaryRequestRepository.findAllByMember_MemberIdx(member) + .stream() + .filter(mercenaryRequest -> isPostValid(mercenaryRequest.getMercenaryPost())) + .map(MercenaryRequestResponse::from) + .collect(Collectors.toList()); + } + + @Transactional + public void cancelMatchRequest(Long requestId, CustomOAuth2Member customOAuth2Member) { + Member member = memberRepository.findByUniqueId(customOAuth2Member.getUniqueId()) + .orElseThrow(() -> new EntityNotFoundException("해당 uniqueId를 가진 회원이 존재하지 않습니다.")); + + MercenaryRequest mercenaryRequest = mercenaryRequestRepository.findById(requestId) + .orElseThrow(() -> new EntityNotFoundException("매칭 요청을 찾을 수 없습니다.")); + + // 요청을 취소하려는 사용자가 이 요청을 만든 사용자인지 확인 + if (!mercenaryRequest.getMember().getMemberIdx().equals(member.getMemberIdx())) { + throw new AppException(ErrorCode.CLUB_ACCESS_DENIED); + } + + mercenaryRequestRepository.delete(mercenaryRequest); + } + + public Page getReceivedMatchRequests(Long clubId, Pageable pageable) { + + Club club = clubRepository.findById(clubId) + .orElseThrow(() -> new EntityNotFoundException("동아리를 찾을 수 없습니다.")); + + List mercenaryPosts = mercenaryPostRepository.findByHomeClub(club); + + LocalDateTime now = LocalDateTime.now(); + + List allResponses = mercenaryPosts.stream() + .filter( + mercenaryPost -> LocalDateTime.of(mercenaryPost.getMatchStartDate(), mercenaryPost.getMatchStartTime()) + .isAfter(now)) + .map(mercenaryPost -> { + List receivedRequests = mercenaryPost.getMercenaryRequests() + .stream() + .map(ReceivedMercenaryRequestResponse::from) + .collect(Collectors.toList()); + + return MercenaryRequestAndMercenaryPostResponse.from( + mercenaryPost, + receivedRequests + ); + }) + .collect(Collectors.toList()); + + // allResponses 리스트를 pageable에 맞게 자름 + int start = (int)pageable.getOffset(); + int end = Math.min(start + pageable.getPageSize(), allResponses.size()); + + List paginatedList = allResponses.subList(start, end); + + return new PageImpl<>(paginatedList, pageable, allResponses.size()); + } + + public List getAllReceivedMatchRequests(Long clubId) { + + Club club = clubRepository.findById(clubId) + .orElseThrow(() -> new EntityNotFoundException("동아리를 찾을 수 없습니다.")); + + List mercenaryPosts = club.getMercenaryPosts(); + + LocalDateTime now = LocalDateTime.now(); + + return mercenaryPosts.stream() + .filter( + mercenaryPost -> LocalDateTime.of(mercenaryPost.getMatchStartDate(), mercenaryPost.getMatchStartTime()) + .isAfter(now)) + .map(mercenaryPost -> { + List receivedRequests = mercenaryPost.getMercenaryRequests() + .stream() + .map(ReceivedMercenaryRequestResponse::from) + .collect(Collectors.toList()); + + return MercenaryRequestAndMercenaryPostResponse.from( + mercenaryPost, + receivedRequests + ); + }) + .collect(Collectors.toList()); + } + + @Transactional + public void decideMatchRequest(Long requestId, String decision, Long memberId) { + MercenaryRequest mercenaryRequest = mercenaryRequestRepository.findById(requestId) + .orElseThrow(() -> new EntityNotFoundException("매칭 요청을 찾을 수 없습니다.")); + + // 해당 용병 요청이 속한 Club의 Admin 권한 확인 + clubAdminMemberRepository.findActiveAdminByClubIdAndClubMemberId( + mercenaryRequest.getMercenaryPost().getHomeClub().getClubId(), memberId) + .orElseThrow(() -> new AppException(ErrorCode.CLUB_ACCESS_DENIED)); + + if ("ACCEPTED".equalsIgnoreCase(decision)) { + mercenaryRequest.accept(); + mercenaryRequest.getMercenaryPost().incrementParticipants(); // 현재 인원 증가 + } else if ("REJECTED".equalsIgnoreCase(decision)) { + mercenaryRequest.reject(); + } else { + throw new IllegalArgumentException("결정은 ACCEPTED 또는 REJECTED이어야 합니다."); + } + + mercenaryRequestRepository.save(mercenaryRequest); + } + + private boolean isPostValid(MercenaryPost mercenaryPost) { + LocalDateTime postDateTime = LocalDateTime.of(mercenaryPost.getMatchStartDate(), + mercenaryPost.getMatchStartTime()); + return postDateTime.isAfter(LocalDateTime.now()); + } } diff --git a/src/main/java/com/cotato/squadus/domain/club/match/service/mercenary/MercenaryService.java b/src/main/java/com/cotato/squadus/domain/club/match/service/mercenary/MercenaryService.java index ac6a44d..bfab91f 100644 --- a/src/main/java/com/cotato/squadus/domain/club/match/service/mercenary/MercenaryService.java +++ b/src/main/java/com/cotato/squadus/domain/club/match/service/mercenary/MercenaryService.java @@ -1,5 +1,15 @@ package com.cotato.squadus.domain.club.match.service.mercenary; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.LocalTime; +import java.util.List; +import java.util.stream.Collectors; + +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.stereotype.Service; + import com.cotato.squadus.api.match.dto.matchPost.request.FilterRequest; import com.cotato.squadus.api.match.dto.matchPost.request.SearchRequest; import com.cotato.squadus.api.mercenary.dto.request.MercenaryCreateRequest; @@ -12,225 +22,215 @@ import com.cotato.squadus.domain.auth.entity.Member; import com.cotato.squadus.domain.auth.repository.MemberRepository; import com.cotato.squadus.domain.club.common.entity.Club; -import com.cotato.squadus.domain.club.common.entity.ClubMember; import com.cotato.squadus.domain.club.common.enums.ClubTier; import com.cotato.squadus.domain.club.common.enums.SportsCategory; import com.cotato.squadus.domain.club.common.repository.ClubAdminMemberRepository; import com.cotato.squadus.domain.club.common.repository.ClubMemberRepository; import com.cotato.squadus.domain.club.common.repository.ClubRepository; -import com.cotato.squadus.domain.club.match.entity.*; +import com.cotato.squadus.domain.club.match.entity.MatchPlace; import com.cotato.squadus.domain.club.match.entity.mercenary.MercenaryPost; import com.cotato.squadus.domain.club.match.entity.mercenary.MercenaryRequest; import com.cotato.squadus.domain.club.match.enums.MatchingStatus; import com.cotato.squadus.domain.club.match.repository.mercenary.MercenaryPostRepository; import com.cotato.squadus.domain.club.match.repository.mercenary.MercenaryRequestRepository; + import jakarta.persistence.EntityNotFoundException; import jakarta.transaction.Transactional; import lombok.RequiredArgsConstructor; -import org.springframework.data.domain.Page; -import org.springframework.data.domain.Pageable; -import org.springframework.stereotype.Service; - -import java.time.LocalDate; -import java.time.LocalDateTime; -import java.time.LocalTime; -import java.util.List; -import java.util.stream.Collectors; @Service @RequiredArgsConstructor public class MercenaryService { - private final MercenaryPostRepository mercenaryPostRepository; - private final MercenaryRequestRepository mercenaryRequestRepository; - private final ClubRepository clubRepository; - private final ClubMemberRepository clubMemberRepository; - private final ClubAdminMemberRepository clubAdminMemberRepository; - private final MemberRepository memberRepository; - - @Transactional - public MercenaryCreateResponse createMatch(MercenaryCreateRequest mercenaryCreateRequest) { - Club homeClub = clubRepository.findById(mercenaryCreateRequest.getHomeClubId()) - .orElseThrow(() -> new EntityNotFoundException("동아리를 찾을 수 없습니다.")); - - // 해당 club의 임원인지 확인 - if (!clubAdminMemberRepository.findActiveAdminByClubIdAndClubMemberId(homeClub.getClubId(), mercenaryCreateRequest.getClubMemberId()).isPresent()) { - throw new AppException(ErrorCode.CLUB_ACCESS_DENIED); - } - - MatchPlace matchPlace = new MatchPlace(mercenaryCreateRequest.getMatchPlace().getCity(), - mercenaryCreateRequest.getMatchPlace().getDistrict()); - - MercenaryPost mercenaryPost = MercenaryPost.builder() - .homeClub(homeClub) - .title(mercenaryCreateRequest.getTitle()) - .content(mercenaryCreateRequest.getContent()) - .matchPlace(matchPlace) - .placeProvided(mercenaryCreateRequest.getPlaceProvided()) - .matchStartDate(mercenaryCreateRequest.getMatchStartDate()) - .matchStartTime(mercenaryCreateRequest.getMatchStartTime()) - .maxParticipants(mercenaryCreateRequest.getMaxParticipants()) - .build(); - - homeClub.addMercenaryPost(mercenaryPost); - - mercenaryPostRepository.save(mercenaryPost); - return MercenaryCreateResponse.from(mercenaryPost); - } - - - - public List findAllMatches() { - - LocalDateTime now = LocalDateTime.now(); - - return mercenaryPostRepository.findAll().stream() - .filter(mercenaryPost -> { - LocalDateTime matchDateTime = LocalDateTime.of(mercenaryPost.getMatchStartDate(), mercenaryPost.getMatchStartTime()); - return matchDateTime.isAfter(now); - }) - .map(MercenaryCreateResponse::from) - .collect(Collectors.toList()); - } - - - public Page findAllMatches(Pageable pageable) { - - LocalDate today = LocalDate.now(); - LocalTime nowTime = LocalTime.now(); - - // 데이터베이스에서 직접 페이징 처리하여 가져오기 - Page mercenaryPostsPage = mercenaryPostRepository - .findAllByMatchStartDateAfterOrMatchStartDateEqualsAndMatchStartTimeAfter( - today, nowTime, pageable); - - - // 페이지 내용을 DTO로 변환 - return mercenaryPostsPage.map(MercenaryCreateResponse::from); - } - - - public List getFilteredMatches(FilterRequest filterRequest) { - - SportsCategory sportsCategory = null; - ClubTier tier = null; - LocalDateTime now = LocalDateTime.now(); - - if (filterRequest.getSportsCategory() != null) { - sportsCategory = SportsCategory.valueOf(filterRequest.getSportsCategory()); - } - - if (filterRequest.getTier() != null) { - tier = ClubTier.valueOf(filterRequest.getTier()); - } - - List mercenaryPosts = mercenaryPostRepository.customFindMatchesByFilter( - sportsCategory, - filterRequest.getCity(), - filterRequest.getDistrict(), - tier, - filterRequest.getPlaceProvided() - ); - - return mercenaryPosts.stream() - .filter(mercenaryPost -> { - LocalDateTime matchDateTime = LocalDateTime.of(mercenaryPost.getMatchStartDate(), mercenaryPost.getMatchStartTime()); - return matchDateTime.isAfter(now); - }) - .map(MercenaryCreateResponse::from) - .collect(Collectors.toList()); - } - - - public List searchMatches(SearchRequest searchRequest) { - - LocalDateTime now = LocalDateTime.now(); - - return mercenaryPostRepository.customFindByKeyword(searchRequest.getKeyword()).stream() - .filter(mercenaryPost -> { - LocalDateTime matchDateTime = LocalDateTime.of(mercenaryPost.getMatchStartDate(), mercenaryPost.getMatchStartTime()); - return matchDateTime.isAfter(now); - }) // 사용자의 동아리에서 작성한 글 제외 - .map(MercenaryCreateResponse::from) - .collect(Collectors.toList()); - } - - - @Transactional - public MercenaryRequestResponse sendMatchRequest(MercenaryRequestRequest mercenaryRequestRequest, CustomOAuth2Member customOAuth2Member) { - - Member member = memberRepository.findByUniqueId(customOAuth2Member.getUniqueId()) - .orElseThrow(() -> new EntityNotFoundException("해당 uniqueId를 가진 회원이 존재하지 않습니다.")); - - //다른 동아리에서 작성한 매칭 게시글 - MercenaryPost mercenaryPost = mercenaryPostRepository.findById(mercenaryRequestRequest.getMercenaryPostId()) - .orElseThrow(() -> new EntityNotFoundException("매칭 게시글을 찾을 수 없습니다.")); - - // 이미 신청한 용병 요청이 있는지 확인 - if (mercenaryRequestRepository.findTop1ByMemberAndMercenaryPost(member, mercenaryPost).isPresent()) { - throw new AppException(ErrorCode.DUPLICATE_REQUEST); - } - - MercenaryRequest mercenaryRequest = MercenaryRequest.builder() - .member(member) - .mercenaryPost(mercenaryPost) - .status(MatchingStatus.PENDING) - .build(); - - mercenaryPost.addMercenaryRequest(mercenaryRequest); - - mercenaryRequestRepository.save(mercenaryRequest); - return MercenaryRequestResponse.from(mercenaryRequest); - } - - - @Transactional - public MercenaryCreateResponse updateMercenaryPost(Long mercenaryPostId, MercenaryCreateRequest mercenaryCreateRequest) { - MercenaryPost mercenaryPost = mercenaryPostRepository.findById(mercenaryPostId) - .orElseThrow(() -> new EntityNotFoundException("매칭 게시글을 찾을 수 없습니다.")); - - Club homeClub = clubRepository.findById(mercenaryCreateRequest.getHomeClubId()) - .orElseThrow(() -> new EntityNotFoundException("동아리를 찾을 수 없습니다.")); - - if (!clubAdminMemberRepository.findActiveAdminByClubIdAndClubMemberId(homeClub.getClubId(), mercenaryCreateRequest.getClubMemberId()).isPresent()) { - throw new AppException(ErrorCode.CLUB_ACCESS_DENIED); - } - - mercenaryPost.update( - mercenaryCreateRequest.getTitle(), - mercenaryCreateRequest.getContent(), - new MatchPlace(mercenaryCreateRequest.getMatchPlace().getCity(), mercenaryCreateRequest.getMatchPlace().getDistrict()), - mercenaryCreateRequest.getPlaceProvided(), - mercenaryCreateRequest.getMatchStartDate(), - mercenaryCreateRequest.getMatchStartTime(), - mercenaryCreateRequest.getMaxParticipants() - ); - - mercenaryPostRepository.save(mercenaryPost); - return MercenaryCreateResponse.from(mercenaryPost); - } - - - @Transactional - public MercenaryCreateResponse deleteMercenaryPost(Long mercenaryIdx, Long clubMemberId) { - MercenaryPost mercenaryPost = mercenaryPostRepository.findById(mercenaryIdx) - .orElseThrow(() -> new EntityNotFoundException("해당 용병 매칭 게시글을 찾을 수 없습니다.")); - - // 해당 게시글을 작성한 동아리를 찾습니다. - Club homeClub = mercenaryPost.getHomeClub(); - - // 요청한 사용자가 해당 동아리의 관리자인지 확인합니다. - boolean isAdmin = clubAdminMemberRepository.findActiveAdminByClubIdAndClubMemberId(homeClub.getClubId(), clubMemberId) - .isPresent(); - - // 관리자가 아니라면 접근 권한이 없음을 예외 처리합니다. - if (!isAdmin) { - throw new AppException(ErrorCode.CLUB_ACCESS_DENIED); - } - - mercenaryPostRepository.delete(mercenaryPost); - return MercenaryCreateResponse.from(mercenaryPost); - } - + private final MercenaryPostRepository mercenaryPostRepository; + private final MercenaryRequestRepository mercenaryRequestRepository; + private final ClubRepository clubRepository; + private final ClubMemberRepository clubMemberRepository; + private final ClubAdminMemberRepository clubAdminMemberRepository; + private final MemberRepository memberRepository; + + @Transactional + public MercenaryCreateResponse createMatch(MercenaryCreateRequest mercenaryCreateRequest) { + Club homeClub = clubRepository.findById(mercenaryCreateRequest.getHomeClubId()) + .orElseThrow(() -> new EntityNotFoundException("동아리를 찾을 수 없습니다.")); + + // 해당 club의 임원인지 확인 + if (!clubAdminMemberRepository.findActiveAdminByClubIdAndClubMemberId(homeClub.getClubId(), + mercenaryCreateRequest.getClubMemberId()).isPresent()) { + throw new AppException(ErrorCode.CLUB_ACCESS_DENIED); + } + + MatchPlace matchPlace = new MatchPlace(mercenaryCreateRequest.getMatchPlace().getCity(), + mercenaryCreateRequest.getMatchPlace().getDistrict()); + + MercenaryPost mercenaryPost = MercenaryPost.builder() + .homeClub(homeClub) + .title(mercenaryCreateRequest.getTitle()) + .content(mercenaryCreateRequest.getContent()) + .matchPlace(matchPlace) + .placeProvided(mercenaryCreateRequest.getPlaceProvided()) + .matchStartDate(mercenaryCreateRequest.getMatchStartDate()) + .matchStartTime(mercenaryCreateRequest.getMatchStartTime()) + .maxParticipants(mercenaryCreateRequest.getMaxParticipants()) + .build(); + + homeClub.addMercenaryPost(mercenaryPost); + + mercenaryPostRepository.save(mercenaryPost); + return MercenaryCreateResponse.from(mercenaryPost); + } + + public List findAllMatches() { + + LocalDateTime now = LocalDateTime.now(); + + return mercenaryPostRepository.findAll().stream() + .filter(mercenaryPost -> { + LocalDateTime matchDateTime = LocalDateTime.of(mercenaryPost.getMatchStartDate(), + mercenaryPost.getMatchStartTime()); + return matchDateTime.isAfter(now); + }) + .map(MercenaryCreateResponse::from) + .collect(Collectors.toList()); + } + + public Page findAllMatches(Pageable pageable) { + + LocalDate today = LocalDate.now(); + LocalTime nowTime = LocalTime.now(); + + // 데이터베이스에서 직접 페이징 처리하여 가져오기 + Page mercenaryPostsPage = mercenaryPostRepository + .findAllByMatchStartDateAfterOrMatchStartDateEqualsAndMatchStartTimeAfter( + today, nowTime, pageable); + + // 페이지 내용을 DTO로 변환 + return mercenaryPostsPage.map(MercenaryCreateResponse::from); + } + + public List getFilteredMatches(FilterRequest filterRequest) { + + SportsCategory sportsCategory = null; + ClubTier tier = null; + LocalDateTime now = LocalDateTime.now(); + + if (filterRequest.getSportsCategory() != null) { + sportsCategory = SportsCategory.valueOf(filterRequest.getSportsCategory()); + } + + if (filterRequest.getTier() != null) { + tier = ClubTier.valueOf(filterRequest.getTier()); + } + + List mercenaryPosts = mercenaryPostRepository.customFindMatchesByFilter( + sportsCategory, + filterRequest.getCity(), + filterRequest.getDistrict(), + tier, + filterRequest.getPlaceProvided() + ); + + return mercenaryPosts.stream() + .filter(mercenaryPost -> { + LocalDateTime matchDateTime = LocalDateTime.of(mercenaryPost.getMatchStartDate(), + mercenaryPost.getMatchStartTime()); + return matchDateTime.isAfter(now); + }) + .map(MercenaryCreateResponse::from) + .collect(Collectors.toList()); + } + + public List searchMatches(SearchRequest searchRequest) { + + LocalDateTime now = LocalDateTime.now(); + + return mercenaryPostRepository.customFindByKeyword(searchRequest.getKeyword()).stream() + .filter(mercenaryPost -> { + LocalDateTime matchDateTime = LocalDateTime.of(mercenaryPost.getMatchStartDate(), + mercenaryPost.getMatchStartTime()); + return matchDateTime.isAfter(now); + }) // 사용자의 동아리에서 작성한 글 제외 + .map(MercenaryCreateResponse::from) + .collect(Collectors.toList()); + } + + @Transactional + public MercenaryRequestResponse sendMatchRequest(MercenaryRequestRequest mercenaryRequestRequest, + CustomOAuth2Member customOAuth2Member) { + + Member member = memberRepository.findByUniqueId(customOAuth2Member.getUniqueId()) + .orElseThrow(() -> new EntityNotFoundException("해당 uniqueId를 가진 회원이 존재하지 않습니다.")); + + //다른 동아리에서 작성한 매칭 게시글 + MercenaryPost mercenaryPost = mercenaryPostRepository.findById(mercenaryRequestRequest.getMercenaryPostId()) + .orElseThrow(() -> new EntityNotFoundException("매칭 게시글을 찾을 수 없습니다.")); + + // 이미 신청한 용병 요청이 있는지 확인 + if (mercenaryRequestRepository.findTop1ByMemberAndMercenaryPost(member, mercenaryPost).isPresent()) { + throw new AppException(ErrorCode.DUPLICATE_REQUEST); + } + + MercenaryRequest mercenaryRequest = MercenaryRequest.builder() + .member(member) + .mercenaryPost(mercenaryPost) + .status(MatchingStatus.PENDING) + .build(); + + mercenaryPost.addMercenaryRequest(mercenaryRequest); + + mercenaryRequestRepository.save(mercenaryRequest); + return MercenaryRequestResponse.from(mercenaryRequest); + } + + @Transactional + public MercenaryCreateResponse updateMercenaryPost(Long mercenaryPostId, + MercenaryCreateRequest mercenaryCreateRequest) { + MercenaryPost mercenaryPost = mercenaryPostRepository.findById(mercenaryPostId) + .orElseThrow(() -> new EntityNotFoundException("매칭 게시글을 찾을 수 없습니다.")); + + Club homeClub = clubRepository.findById(mercenaryCreateRequest.getHomeClubId()) + .orElseThrow(() -> new EntityNotFoundException("동아리를 찾을 수 없습니다.")); + + if (!clubAdminMemberRepository.findActiveAdminByClubIdAndClubMemberId(homeClub.getClubId(), + mercenaryCreateRequest.getClubMemberId()).isPresent()) { + throw new AppException(ErrorCode.CLUB_ACCESS_DENIED); + } + + mercenaryPost.update( + mercenaryCreateRequest.getTitle(), + mercenaryCreateRequest.getContent(), + new MatchPlace(mercenaryCreateRequest.getMatchPlace().getCity(), + mercenaryCreateRequest.getMatchPlace().getDistrict()), + mercenaryCreateRequest.getPlaceProvided(), + mercenaryCreateRequest.getMatchStartDate(), + mercenaryCreateRequest.getMatchStartTime(), + mercenaryCreateRequest.getMaxParticipants() + ); + + mercenaryPostRepository.save(mercenaryPost); + return MercenaryCreateResponse.from(mercenaryPost); + } + + @Transactional + public MercenaryCreateResponse deleteMercenaryPost(Long mercenaryIdx, Long clubMemberId) { + MercenaryPost mercenaryPost = mercenaryPostRepository.findById(mercenaryIdx) + .orElseThrow(() -> new EntityNotFoundException("해당 용병 매칭 게시글을 찾을 수 없습니다.")); + + // 해당 게시글을 작성한 동아리를 찾습니다. + Club homeClub = mercenaryPost.getHomeClub(); + + // 요청한 사용자가 해당 동아리의 관리자인지 확인합니다. + boolean isAdmin = clubAdminMemberRepository.findActiveAdminByClubIdAndClubMemberId(homeClub.getClubId(), + clubMemberId) + .isPresent(); + + // 관리자가 아니라면 접근 권한이 없음을 예외 처리합니다. + if (!isAdmin) { + throw new AppException(ErrorCode.CLUB_ACCESS_DENIED); + } + + mercenaryPostRepository.delete(mercenaryPost); + return MercenaryCreateResponse.from(mercenaryPost); + } } diff --git a/src/main/java/com/cotato/squadus/domain/club/post/entity/ClubPost.java b/src/main/java/com/cotato/squadus/domain/club/post/entity/ClubPost.java index 3cf2232..56b4ab2 100644 --- a/src/main/java/com/cotato/squadus/domain/club/post/entity/ClubPost.java +++ b/src/main/java/com/cotato/squadus/domain/club/post/entity/ClubPost.java @@ -3,54 +3,64 @@ import com.cotato.squadus.common.entity.BaseTimeEntity; import com.cotato.squadus.domain.club.common.entity.Club; import com.cotato.squadus.domain.club.common.entity.ClubAdminMember; -import jakarta.persistence.*; + +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.Table; import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; + @Entity @Getter @NoArgsConstructor @Table(name = "club_post") public class ClubPost extends BaseTimeEntity { - @Id @GeneratedValue - private Long postId; + @Id + @GeneratedValue + private Long postId; - @ManyToOne - @JoinColumn(name = "club_member_idx") - private ClubAdminMember author; + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "club_member_idx") + private ClubAdminMember author; - @ManyToOne - @JoinColumn(name = "club_id") - private Club club; + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "club_id") + private Club club; - private String title; + private String title; - private String content; + private String content; - private String image; + private String image; - private Long views; + private Long views; - private Long likes; + private Long likes; - @Builder - public ClubPost(ClubAdminMember clubAdminMember, Club club, String title, String content, String image, Long views, Long likes) { - this.author = clubAdminMember; - this.club = club; - this.title = title; - this.content = content; - this.image = image; - this.views = views; - this.likes = likes; - } + @Builder + public ClubPost(ClubAdminMember clubAdminMember, Club club, String title, String content, String image, Long views, + Long likes) { + this.author = clubAdminMember; + this.club = club; + this.title = title; + this.content = content; + this.image = image; + this.views = views; + this.likes = likes; + } - public ClubPost increaseLikes() { - this.likes += 1L; - return this; - } + public ClubPost increaseLikes() { + this.likes += 1L; + return this; + } - public void increaseViews() { - this.views += 1L; - } + public void increaseViews() { + this.views += 1L; + } } diff --git a/src/main/java/com/cotato/squadus/domain/club/post/entity/ClubPostComment.java b/src/main/java/com/cotato/squadus/domain/club/post/entity/ClubPostComment.java index 9ef9d4d..ca3b9e9 100644 --- a/src/main/java/com/cotato/squadus/domain/club/post/entity/ClubPostComment.java +++ b/src/main/java/com/cotato/squadus/domain/club/post/entity/ClubPostComment.java @@ -1,12 +1,23 @@ package com.cotato.squadus.domain.club.post.entity; +import org.springframework.data.jpa.domain.support.AuditingEntityListener; + import com.cotato.squadus.common.entity.BaseTimeEntity; import com.cotato.squadus.domain.club.common.entity.ClubMember; -import jakarta.persistence.*; + +import jakarta.persistence.Entity; +import jakarta.persistence.EntityListeners; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.Lob; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.Table; import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; -import org.springframework.data.jpa.domain.support.AuditingEntityListener; @Entity @Getter @@ -15,32 +26,32 @@ @EntityListeners(AuditingEntityListener.class) public class ClubPostComment extends BaseTimeEntity { - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - private Long id; + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; - @Lob - private String content; + @Lob + private String content; - private Long likes; + private Long likes; - @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "club_member_idx") - private ClubMember clubMember; + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "club_member_idx") + private ClubMember clubMember; - @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "post_id") - private ClubPost clubPost; + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "post_id") + private ClubPost clubPost; - @Builder - public ClubPostComment(String content, ClubMember clubMember, ClubPost clubPost, Long likes) { - this.content = content; - this.clubMember = clubMember; - this.clubPost = clubPost; - this.likes = likes; - } + @Builder + public ClubPostComment(String content, ClubMember clubMember, ClubPost clubPost, Long likes) { + this.content = content; + this.clubMember = clubMember; + this.clubPost = clubPost; + this.likes = likes; + } - public void increaseLikes() { - this.likes += 1L; - } + public void increaseLikes() { + this.likes += 1L; + } } diff --git a/src/main/java/com/cotato/squadus/domain/club/post/repository/ClubPostCommentRepository.java b/src/main/java/com/cotato/squadus/domain/club/post/repository/ClubPostCommentRepository.java index dfb2918..a28c9f6 100644 --- a/src/main/java/com/cotato/squadus/domain/club/post/repository/ClubPostCommentRepository.java +++ b/src/main/java/com/cotato/squadus/domain/club/post/repository/ClubPostCommentRepository.java @@ -1,13 +1,14 @@ package com.cotato.squadus.domain.club.post.repository; -import com.cotato.squadus.domain.club.post.entity.ClubPostComment; +import java.util.List; + import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; -import java.util.List; +import com.cotato.squadus.domain.club.post.entity.ClubPostComment; @Repository public interface ClubPostCommentRepository extends JpaRepository { - ListfindAllByClubPost_PostId(Long postId); + List findAllByClubPost_PostId(Long postId); } diff --git a/src/main/java/com/cotato/squadus/domain/club/post/repository/ClubPostRepository.java b/src/main/java/com/cotato/squadus/domain/club/post/repository/ClubPostRepository.java index c4b029c..11f9647 100644 --- a/src/main/java/com/cotato/squadus/domain/club/post/repository/ClubPostRepository.java +++ b/src/main/java/com/cotato/squadus/domain/club/post/repository/ClubPostRepository.java @@ -1,15 +1,17 @@ package com.cotato.squadus.domain.club.post.repository; -import com.cotato.squadus.domain.club.post.entity.ClubPost; -import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.stereotype.Repository; import java.util.List; import java.util.Optional; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +import com.cotato.squadus.domain.club.post.entity.ClubPost; + @Repository public interface ClubPostRepository extends JpaRepository { - Optional findByPostId(Long clubId); + Optional findByPostId(Long clubId); - List findAllByClub_ClubId(Long clubId); + List findAllByClub_ClubId(Long clubId); } diff --git a/src/main/java/com/cotato/squadus/domain/club/post/service/ClubPostCommentService.java b/src/main/java/com/cotato/squadus/domain/club/post/service/ClubPostCommentService.java index b0842b6..c3de229 100644 --- a/src/main/java/com/cotato/squadus/domain/club/post/service/ClubPostCommentService.java +++ b/src/main/java/com/cotato/squadus/domain/club/post/service/ClubPostCommentService.java @@ -1,5 +1,10 @@ package com.cotato.squadus.domain.club.post.service; +import java.util.List; + +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + import com.cotato.squadus.api.post.dto.ClubPostCommentCreateRequest; import com.cotato.squadus.api.post.dto.ClubPostCommentCreateResponse; import com.cotato.squadus.api.post.dto.ClubPostCommentLikeResponse; @@ -8,18 +13,14 @@ import com.cotato.squadus.common.error.exception.AppException; import com.cotato.squadus.domain.auth.service.ClubMemberService; import com.cotato.squadus.domain.club.common.entity.ClubMember; -import com.cotato.squadus.domain.club.common.repository.ClubMemberRepository; import com.cotato.squadus.domain.club.post.entity.ClubPost; import com.cotato.squadus.domain.club.post.entity.ClubPostComment; import com.cotato.squadus.domain.club.post.repository.ClubPostCommentRepository; import com.cotato.squadus.domain.club.post.repository.ClubPostRepository; + import jakarta.persistence.EntityNotFoundException; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -import java.util.List; @Slf4j @Service @@ -27,58 +28,60 @@ @RequiredArgsConstructor public class ClubPostCommentService { - private final ClubPostRepository clubPostRepository; - private final ClubPostCommentRepository clubPostCommentRepository; - private final ClubMemberService clubMemberService; - - public List findAllClubPostComments(Long postId) { - List clubPostCommentResponseList = clubPostCommentRepository.findAllByClubPost_PostId(postId).stream() - .map(ClubPostCommentResponse::from).toList(); - return clubPostCommentResponseList; - - } - - @Transactional - public ClubPostCommentLikeResponse increaseClubPostCommentLike(Long clubId, Long commentId) { - if(isClubPostCommentAuthor(clubId, commentId)) { - throw new AppException(ErrorCode.CLUB_POST_COMMENT_AUTHOR); - } -// ClubMember clubMember = clubMemberService.findClubMemberBySecurityContextHolder(); - - ClubPostComment clubPostComment = clubPostCommentRepository.findById(commentId) - .orElseThrow(() -> new EntityNotFoundException("해당 아이디를 가진 댓글이 존재하지 않습니다.")); - clubPostComment.increaseLikes(); - clubPostCommentRepository.save(clubPostComment); - return new ClubPostCommentLikeResponse(clubPostComment.getLikes()); - } - - @Transactional - public ClubPostCommentCreateResponse createClubPostComment(Long clubId, Long postId, ClubPostCommentCreateRequest clubPostCommentCreateRequest) { - - ClubPost clubPost = clubPostRepository.findByPostId(postId) - .orElseThrow(() -> new EntityNotFoundException("해당 아이디를 가진 동아리 공지가 존재하지 않습니다")); - - ClubMember clubMember = clubMemberService.findClubMemberBySecurityContextHolder(clubId); - - ClubPostComment clubPostComment = ClubPostComment.builder() - .content(clubPostCommentCreateRequest.content()) - .clubMember(clubMember) - .clubPost(clubPost) - .likes(0L) - .build(); - - ClubPostComment save = clubPostCommentRepository.save(clubPostComment); - return new ClubPostCommentCreateResponse(save.getId()); - - } - - private Boolean isClubPostCommentAuthor(Long clubId, Long postId) { - Long clubMemberId = clubMemberService.findClubMemberBySecurityContextHolder(clubId).getClubMemberIdx(); - ClubPostComment clubPostComment = clubPostCommentRepository.findById(postId) - .orElseThrow(() -> new EntityNotFoundException("해당 아이디를 가진 동아리 공지 댓글이 존재하지 않습니다.")); - Long clubMemberIdFromComment = clubPostComment.getClubMember().getClubMemberIdx(); - - return clubMemberIdFromComment.equals(clubMemberId); - } + private final ClubPostRepository clubPostRepository; + private final ClubPostCommentRepository clubPostCommentRepository; + private final ClubMemberService clubMemberService; + + public List findAllClubPostComments(Long postId) { + List clubPostCommentResponseList = clubPostCommentRepository.findAllByClubPost_PostId( + postId).stream() + .map(ClubPostCommentResponse::from).toList(); + return clubPostCommentResponseList; + + } + + @Transactional + public ClubPostCommentLikeResponse increaseClubPostCommentLike(Long clubId, Long commentId) { + if (isClubPostCommentAuthor(clubId, commentId)) { + throw new AppException(ErrorCode.CLUB_POST_COMMENT_AUTHOR); + } + // ClubMember clubMember = clubMemberService.findClubMemberBySecurityContextHolder(); + + ClubPostComment clubPostComment = clubPostCommentRepository.findById(commentId) + .orElseThrow(() -> new EntityNotFoundException("해당 아이디를 가진 댓글이 존재하지 않습니다.")); + clubPostComment.increaseLikes(); + clubPostCommentRepository.save(clubPostComment); + return new ClubPostCommentLikeResponse(clubPostComment.getLikes()); + } + + @Transactional + public ClubPostCommentCreateResponse createClubPostComment(Long clubId, Long postId, + ClubPostCommentCreateRequest clubPostCommentCreateRequest) { + + ClubPost clubPost = clubPostRepository.findByPostId(postId) + .orElseThrow(() -> new EntityNotFoundException("해당 아이디를 가진 동아리 공지가 존재하지 않습니다")); + + ClubMember clubMember = clubMemberService.findClubMemberBySecurityContextHolder(clubId); + + ClubPostComment clubPostComment = ClubPostComment.builder() + .content(clubPostCommentCreateRequest.content()) + .clubMember(clubMember) + .clubPost(clubPost) + .likes(0L) + .build(); + + ClubPostComment save = clubPostCommentRepository.save(clubPostComment); + return new ClubPostCommentCreateResponse(save.getId()); + + } + + private Boolean isClubPostCommentAuthor(Long clubId, Long postId) { + Long clubMemberId = clubMemberService.findClubMemberBySecurityContextHolder(clubId).getClubMemberIdx(); + ClubPostComment clubPostComment = clubPostCommentRepository.findById(postId) + .orElseThrow(() -> new EntityNotFoundException("해당 아이디를 가진 동아리 공지 댓글이 존재하지 않습니다.")); + Long clubMemberIdFromComment = clubPostComment.getClubMember().getClubMemberIdx(); + + return clubMemberIdFromComment.equals(clubMemberId); + } } diff --git a/src/main/java/com/cotato/squadus/domain/club/post/service/ClubPostService.java b/src/main/java/com/cotato/squadus/domain/club/post/service/ClubPostService.java index a9208fe..ee83609 100644 --- a/src/main/java/com/cotato/squadus/domain/club/post/service/ClubPostService.java +++ b/src/main/java/com/cotato/squadus/domain/club/post/service/ClubPostService.java @@ -1,6 +1,18 @@ package com.cotato.squadus.domain.club.post.service; -import com.cotato.squadus.api.post.dto.*; +import java.util.List; + +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.multipart.MultipartFile; + +import com.cotato.squadus.api.post.dto.ClubPostCreateRequest; +import com.cotato.squadus.api.post.dto.ClubPostCreateResponse; +import com.cotato.squadus.api.post.dto.ClubPostLikesResponse; +import com.cotato.squadus.api.post.dto.ClubPostListResponse; +import com.cotato.squadus.api.post.dto.ClubPostResponse; +import com.cotato.squadus.api.post.dto.ClubPostSummaryListResponse; +import com.cotato.squadus.api.post.dto.ClubPostSummaryResponse; import com.cotato.squadus.common.error.ErrorCode; import com.cotato.squadus.common.error.exception.AppException; import com.cotato.squadus.common.s3.S3ImageService; @@ -11,14 +23,10 @@ import com.cotato.squadus.domain.club.common.repository.ClubRepository; import com.cotato.squadus.domain.club.post.entity.ClubPost; import com.cotato.squadus.domain.club.post.repository.ClubPostRepository; + import jakarta.persistence.EntityNotFoundException; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; -import org.springframework.web.multipart.MultipartFile; - -import java.util.List; @Slf4j @Service @@ -26,88 +34,88 @@ @RequiredArgsConstructor public class ClubPostService { - private final ClubPostRepository clubPostRepository; - private final ClubMemberService clubMemberService; - private final ClubRepository clubRepository; - private final S3ImageService s3ImageService; - private final ClubAdminService clubAdminService; - - // 공지 전체 내용 조회 - public ClubPostListResponse findAllClubPostsByClubId(Long clubId) { - List clubPostResponses = clubPostRepository.findAllByClub_ClubId(clubId) - .stream() - .map(ClubPostResponse::from) - .toList(); - - return ClubPostListResponse.from(clubPostResponses); - } - - // id, 제목, 날짜 - public ClubPostSummaryListResponse findAllClubPostsSummaryByClubId(Long clubId) { - List clubPostSummaryResponseList = clubPostRepository.findAllByClub_ClubId(clubId) - .stream() - .map(ClubPostSummaryResponse::from) - .toList(); - - return ClubPostSummaryListResponse.from(clubPostSummaryResponseList); - } - - @Transactional - public ClubPostResponse findClubPostByPostId(Long postId) { - ClubPost clubPost = clubPostRepository.findByPostId(postId) - .orElseThrow(() -> new EntityNotFoundException("해당 고유번호를 가진 동아리 공지를 찾을 수 없습니다.")); - clubPost.increaseViews(); - clubPostRepository.save(clubPost); - log.info("조회수 증가, 조회수 : {}", clubPost.getViews()); - ClubPostResponse clubPostResponse = ClubPostResponse.from(clubPost); - return clubPostResponse; - } - - @Transactional - public ClubPostCreateResponse createClubPost(Long clubId, ClubPostCreateRequest clubPostCreateRequest, MultipartFile image) { - Club club = clubRepository.findById(clubId) - .orElseThrow(() -> new EntityNotFoundException("해당 고유번호를 가진 동아리를 찾을 수 없습니다.")); - - ClubAdminMember clubAdminMember = clubAdminService.validateAdminMember(clubId); - - String imageUrl; - if (image != null && !image.isEmpty()) { - imageUrl = s3ImageService.upload(image); - } else { - imageUrl = "no image"; - } - - - ClubPost clubPost = ClubPost.builder() - .club(club) - .title(clubPostCreateRequest.title()) - .content(clubPostCreateRequest.content()) - .clubAdminMember(clubAdminMember) - .image(imageUrl) - .views(0L) - .likes(0L) - .build(); - ClubPost savedClubPost = clubPostRepository.save(clubPost); - return new ClubPostCreateResponse(savedClubPost.getPostId()); - } - - @Transactional - public ClubPostLikesResponse increaseClubPostLikes(Long clubId, Long postId) { - if(isClubPostAuthor(clubId, postId)) { - throw new AppException(ErrorCode.CLUB_POST_AUTHOR); - } - ClubPost clubPost = clubPostRepository.findByPostId(postId) - .orElseThrow(() -> new EntityNotFoundException("해당 고유번호를 가진 동아리 공지를 찾을 수 없습니다.")); - ClubPost likesIncreasedPost = clubPost.increaseLikes(); - ClubPost updated = clubPostRepository.save(likesIncreasedPost); - return new ClubPostLikesResponse(updated.getLikes()); - } - - private Boolean isClubPostAuthor(Long clubId, Long postId) { - Long clubMemberId = clubMemberService.findClubMemberBySecurityContextHolder(clubId).getClubMemberIdx(); - ClubPost clubPost = clubPostRepository.findById(postId) - .orElseThrow(() -> new EntityNotFoundException("해당 아이디를 가진 동아리 공지가 존재하지 않습니다.")); - Long clubMemberIdFromClubPost = clubPost.getAuthor().getClubMemberIdx(); - return clubMemberIdFromClubPost.equals(clubMemberId); - } + private final ClubPostRepository clubPostRepository; + private final ClubMemberService clubMemberService; + private final ClubRepository clubRepository; + private final S3ImageService s3ImageService; + private final ClubAdminService clubAdminService; + + // 공지 전체 내용 조회 + public ClubPostListResponse findAllClubPostsByClubId(Long clubId) { + List clubPostResponses = clubPostRepository.findAllByClub_ClubId(clubId) + .stream() + .map(ClubPostResponse::from) + .toList(); + + return ClubPostListResponse.from(clubPostResponses); + } + + // id, 제목, 날짜 + public ClubPostSummaryListResponse findAllClubPostsSummaryByClubId(Long clubId) { + List clubPostSummaryResponseList = clubPostRepository.findAllByClub_ClubId(clubId) + .stream() + .map(ClubPostSummaryResponse::from) + .toList(); + + return ClubPostSummaryListResponse.from(clubPostSummaryResponseList); + } + + @Transactional + public ClubPostResponse findClubPostByPostId(Long postId) { + ClubPost clubPost = clubPostRepository.findByPostId(postId) + .orElseThrow(() -> new EntityNotFoundException("해당 고유번호를 가진 동아리 공지를 찾을 수 없습니다.")); + clubPost.increaseViews(); + clubPostRepository.save(clubPost); + log.info("조회수 증가, 조회수 : {}", clubPost.getViews()); + ClubPostResponse clubPostResponse = ClubPostResponse.from(clubPost); + return clubPostResponse; + } + + @Transactional + public ClubPostCreateResponse createClubPost(Long clubId, ClubPostCreateRequest clubPostCreateRequest, + MultipartFile image) { + Club club = clubRepository.findById(clubId) + .orElseThrow(() -> new EntityNotFoundException("해당 고유번호를 가진 동아리를 찾을 수 없습니다.")); + + ClubAdminMember clubAdminMember = clubAdminService.validateAdminMember(clubId); + + String imageUrl; + if (image != null && !image.isEmpty()) { + imageUrl = s3ImageService.upload(image); + } else { + imageUrl = "no image"; + } + + ClubPost clubPost = ClubPost.builder() + .club(club) + .title(clubPostCreateRequest.title()) + .content(clubPostCreateRequest.content()) + .clubAdminMember(clubAdminMember) + .image(imageUrl) + .views(0L) + .likes(0L) + .build(); + ClubPost savedClubPost = clubPostRepository.save(clubPost); + return new ClubPostCreateResponse(savedClubPost.getPostId()); + } + + @Transactional + public ClubPostLikesResponse increaseClubPostLikes(Long clubId, Long postId) { + if (isClubPostAuthor(clubId, postId)) { + throw new AppException(ErrorCode.CLUB_POST_AUTHOR); + } + ClubPost clubPost = clubPostRepository.findByPostId(postId) + .orElseThrow(() -> new EntityNotFoundException("해당 고유번호를 가진 동아리 공지를 찾을 수 없습니다.")); + ClubPost likesIncreasedPost = clubPost.increaseLikes(); + ClubPost updated = clubPostRepository.save(likesIncreasedPost); + return new ClubPostLikesResponse(updated.getLikes()); + } + + private Boolean isClubPostAuthor(Long clubId, Long postId) { + Long clubMemberId = clubMemberService.findClubMemberBySecurityContextHolder(clubId).getClubMemberIdx(); + ClubPost clubPost = clubPostRepository.findById(postId) + .orElseThrow(() -> new EntityNotFoundException("해당 아이디를 가진 동아리 공지가 존재하지 않습니다.")); + Long clubMemberIdFromClubPost = clubPost.getAuthor().getClubMemberIdx(); + return clubMemberIdFromClubPost.equals(clubMemberId); + } } diff --git a/src/main/java/com/cotato/squadus/domain/club/recruit/entity/RecruitingPost.java b/src/main/java/com/cotato/squadus/domain/club/recruit/entity/RecruitingPost.java index 7cfd375..dcdc69e 100644 --- a/src/main/java/com/cotato/squadus/domain/club/recruit/entity/RecruitingPost.java +++ b/src/main/java/com/cotato/squadus/domain/club/recruit/entity/RecruitingPost.java @@ -1,65 +1,77 @@ package com.cotato.squadus.domain.club.recruit.entity; +import java.time.LocalDate; +import java.util.HashMap; +import java.util.Map; + import com.cotato.squadus.common.entity.BaseTimeEntity; import com.cotato.squadus.domain.club.common.entity.Club; import com.cotato.squadus.domain.club.common.entity.ClubAdminMember; -import jakarta.persistence.*; + +import jakarta.persistence.CollectionTable; +import jakarta.persistence.Column; +import jakarta.persistence.ElementCollection; +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.MapKeyColumn; +import jakarta.persistence.Table; import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; -import java.time.LocalDate; -import java.util.HashMap; -import java.util.Map; - @Entity @Getter @Table(name = "recruiting_post") @NoArgsConstructor public class RecruitingPost extends BaseTimeEntity { - @Id @GeneratedValue - private Long postId; - - private String title; + @Id + @GeneratedValue + private Long postId; - private Boolean isActive; + private String title; - private LocalDate startDate; - private LocalDate endDate; + private Boolean isActive; -// private String content; + private LocalDate startDate; + private LocalDate endDate; -// private String image; + // private String content; - @ManyToOne - @JoinColumn(name = "club_member_idx") - private ClubAdminMember author; + // private String image; - @ManyToOne - @JoinColumn(name = "club_id") - private Club club; + @ManyToOne + @JoinColumn(name = "club_member_idx") + private ClubAdminMember author; + @ManyToOne + @JoinColumn(name = "club_id") + private Club club; - @ElementCollection(fetch = FetchType.LAZY) - @CollectionTable(name = "recruiting_post_questions", joinColumns = @JoinColumn(name = "post_id")) - @MapKeyColumn(name = "question_index") - @Column(name = "question") - private Map questions = new HashMap<>(); + @ElementCollection(fetch = FetchType.LAZY) + @CollectionTable(name = "recruiting_post_questions", joinColumns = @JoinColumn(name = "post_id")) + @MapKeyColumn(name = "question_index") + @Column(name = "question") + private Map questions = new HashMap<>(); - @Builder - public RecruitingPost(String title, Boolean isActive, LocalDate startDate, LocalDate endDate, ClubAdminMember author, Club club, Map questions) { - this.title = title; - this.isActive = isActive; - this.startDate = startDate; - this.endDate = endDate; - this.author = author; - this.club = club; - this.questions = questions; - } + @Builder + public RecruitingPost(String title, Boolean isActive, LocalDate startDate, LocalDate endDate, + ClubAdminMember author, Club club, Map questions) { + this.title = title; + this.isActive = isActive; + this.startDate = startDate; + this.endDate = endDate; + this.author = author; + this.club = club; + this.questions = questions; + } -// private Long views; -// -// private Long likes; + // private Long views; + // + // private Long likes; } diff --git a/src/main/java/com/cotato/squadus/domain/club/recruit/repository/RecruitingPostRepository.java b/src/main/java/com/cotato/squadus/domain/club/recruit/repository/RecruitingPostRepository.java index 7571ffa..077dfd9 100644 --- a/src/main/java/com/cotato/squadus/domain/club/recruit/repository/RecruitingPostRepository.java +++ b/src/main/java/com/cotato/squadus/domain/club/recruit/repository/RecruitingPostRepository.java @@ -1,11 +1,18 @@ package com.cotato.squadus.domain.club.recruit.repository; -import com.cotato.squadus.domain.club.recruit.entity.RecruitingPost; +import java.util.List; + +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; -import java.util.List; +import com.cotato.squadus.domain.club.recruit.entity.RecruitingPost; public interface RecruitingPostRepository extends JpaRepository { - List findAllByClub_ClubId(Long clubId); + List findAllByClub_ClubId(Long clubId); + + @Query("SELECT rp FROM RecruitingPost rp JOIN FETCH rp.club") + Page findAllWithClub(Pageable pageable); } diff --git a/src/main/java/com/cotato/squadus/domain/club/recruit/service/RecruitingPostService.java b/src/main/java/com/cotato/squadus/domain/club/recruit/service/RecruitingPostService.java index 18f2dc7..0e7c502 100644 --- a/src/main/java/com/cotato/squadus/domain/club/recruit/service/RecruitingPostService.java +++ b/src/main/java/com/cotato/squadus/domain/club/recruit/service/RecruitingPostService.java @@ -1,5 +1,11 @@ package com.cotato.squadus.domain.club.recruit.service; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.bind.annotation.RequestBody; + import com.cotato.squadus.api.recruit.dto.RecruitingPostCreateRequest; import com.cotato.squadus.api.recruit.dto.RecruitingPostCreateResponse; import com.cotato.squadus.api.recruit.dto.RecruitingPostInfoResponse; @@ -9,14 +15,10 @@ import com.cotato.squadus.domain.club.common.service.ClubService; import com.cotato.squadus.domain.club.recruit.entity.RecruitingPost; import com.cotato.squadus.domain.club.recruit.repository.RecruitingPostRepository; + import jakarta.persistence.EntityNotFoundException; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.springframework.data.domain.Page; -import org.springframework.data.domain.Pageable; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; -import org.springframework.web.bind.annotation.RequestBody; @Slf4j @Service @@ -24,35 +26,36 @@ @RequiredArgsConstructor public class RecruitingPostService { - private final RecruitingPostRepository recruitingPostRepository; - private final ClubService clubService; - - - public Page findAllRecruitingPosts(CustomOAuth2Member customOAuth2Member, Pageable pageable) { - return recruitingPostRepository.findAll(pageable) - .map(RecruitingPostResponse::from); - } - - public RecruitingPostInfoResponse findRecruitingPostByPostId(CustomOAuth2Member customOAuth2Member, Long postId) { - RecruitingPost recruitingPost = recruitingPostRepository.findById(postId) - .orElseThrow(() -> new EntityNotFoundException("해당 id를 가진 홍보 게시글을 찾을 수 없습니다.")); - - return RecruitingPostInfoResponse.from(recruitingPost); - } - - @Transactional - public RecruitingPostCreateResponse createRecruitingPost(CustomOAuth2Member customOAuth2Member, @RequestBody RecruitingPostCreateRequest recruitingPostCreateRequest) { - - Club club = clubService.findClubByClubId(recruitingPostCreateRequest.clubId()); - RecruitingPost recruitingPost = RecruitingPost.builder() - .title(recruitingPostCreateRequest.title()) - .club(club) - .startDate(recruitingPostCreateRequest.startDate()) - .endDate(recruitingPostCreateRequest.endDate()) - .questions(recruitingPostCreateRequest.questions()) - .build(); - - RecruitingPost saved = recruitingPostRepository.save(recruitingPost); - return new RecruitingPostCreateResponse(saved.getPostId()); - } + private final RecruitingPostRepository recruitingPostRepository; + private final ClubService clubService; + + public Page findAllRecruitingPosts(CustomOAuth2Member customOAuth2Member, + Pageable pageable) { + return recruitingPostRepository.findAllWithClub(pageable) + .map(RecruitingPostResponse::from); + } + + public RecruitingPostInfoResponse findRecruitingPostByPostId(CustomOAuth2Member customOAuth2Member, Long postId) { + RecruitingPost recruitingPost = recruitingPostRepository.findById(postId) + .orElseThrow(() -> new EntityNotFoundException("해당 id를 가진 홍보 게시글을 찾을 수 없습니다.")); + + return RecruitingPostInfoResponse.from(recruitingPost); + } + + @Transactional + public RecruitingPostCreateResponse createRecruitingPost(CustomOAuth2Member customOAuth2Member, + @RequestBody RecruitingPostCreateRequest recruitingPostCreateRequest) { + + Club club = clubService.findClubByClubId(recruitingPostCreateRequest.clubId()); + RecruitingPost recruitingPost = RecruitingPost.builder() + .title(recruitingPostCreateRequest.title()) + .club(club) + .startDate(recruitingPostCreateRequest.startDate()) + .endDate(recruitingPostCreateRequest.endDate()) + .questions(recruitingPostCreateRequest.questions()) + .build(); + + RecruitingPost saved = recruitingPostRepository.save(recruitingPost); + return new RecruitingPostCreateResponse(saved.getPostId()); + } } diff --git a/src/main/java/com/cotato/squadus/domain/club/schedule/entity/ClubSchedule.java b/src/main/java/com/cotato/squadus/domain/club/schedule/entity/ClubSchedule.java index c364576..48be614 100644 --- a/src/main/java/com/cotato/squadus/domain/club/schedule/entity/ClubSchedule.java +++ b/src/main/java/com/cotato/squadus/domain/club/schedule/entity/ClubSchedule.java @@ -1,22 +1,35 @@ package com.cotato.squadus.domain.club.schedule.entity; +import static jakarta.persistence.CascadeType.*; + +import java.time.LocalDate; +import java.time.LocalTime; +import java.util.List; + +import org.springframework.data.jpa.domain.support.AuditingEntityListener; + import com.cotato.squadus.common.entity.BaseTimeEntity; import com.cotato.squadus.domain.club.common.entity.Club; import com.cotato.squadus.domain.club.common.entity.ClubAdminMember; import com.cotato.squadus.domain.club.schedule.enums.ScheduleCategory; -import jakarta.persistence.*; + +import jakarta.persistence.Entity; +import jakarta.persistence.EntityListeners; +import jakarta.persistence.EnumType; +import jakarta.persistence.Enumerated; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.OneToMany; +import jakarta.persistence.Table; +import jakarta.persistence.Temporal; +import jakarta.persistence.TemporalType; import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; -import org.springframework.data.jpa.domain.support.AuditingEntityListener; - -import java.time.LocalDate; -import java.time.LocalDateTime; -import java.time.LocalTime; -import java.util.List; - -import static jakarta.persistence.CascadeType.ALL; -import static jakarta.persistence.FetchType.LAZY; @Entity @Getter @@ -25,66 +38,69 @@ @EntityListeners(AuditingEntityListener.class) public class ClubSchedule extends BaseTimeEntity { - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - private Long scheduleIdx; - - @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "club_id") - private Club club; - - private String title; - - @Enumerated(EnumType.STRING) - private ScheduleCategory scheduleCategory; - - private String content; - - @OneToMany(mappedBy = "clubSchedule", cascade = ALL) - private List scheduleComments; - - @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "club_member_idx") - private ClubAdminMember author; - - private String location; // 추후에 Address 클래스로 바뀔 여지 있음 - - private String equipment; - - @Temporal(TemporalType.DATE) - private LocalDate date; - - @Temporal(TemporalType.TIME) - private LocalTime startTime; - - @Temporal(TemporalType.TIME) - private LocalTime endTime; - -// private List votes; -// private List participants; - - @Builder - public ClubSchedule(Club club, String title, ScheduleCategory scheduleCategory, String content, ClubAdminMember author, String location, String equipment, LocalDate date, LocalTime startTime, LocalTime endTime) { - this.club = club; - this.title = title; - this.scheduleCategory = scheduleCategory; - this.content = content; - this.author = author; - this.location = location; - this.equipment = equipment; - this.date = date; - this.startTime = startTime; - this.endTime = endTime; - } - - public void update(String title, ScheduleCategory scheduleCategory, String content, String location, String equipment, LocalDate date, LocalTime startTime, LocalTime endTime) { - this.title = title; - this.scheduleCategory = scheduleCategory; - this.content = content; - this.location = location; - this.equipment = equipment; - this.date = date; - this.startTime = startTime; - this.endTime = endTime; - } + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long scheduleIdx; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "club_id") + private Club club; + + private String title; + + @Enumerated(EnumType.STRING) + private ScheduleCategory scheduleCategory; + + private String content; + + @OneToMany(mappedBy = "clubSchedule", cascade = ALL) + private List scheduleComments; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "club_member_idx") + private ClubAdminMember author; + + private String location; // 추후에 Address 클래스로 바뀔 여지 있음 + + private String equipment; + + @Temporal(TemporalType.DATE) + private LocalDate date; + + @Temporal(TemporalType.TIME) + private LocalTime startTime; + + @Temporal(TemporalType.TIME) + private LocalTime endTime; + + // private List votes; + // private List participants; + + @Builder + public ClubSchedule(Club club, String title, ScheduleCategory scheduleCategory, String content, + ClubAdminMember author, String location, String equipment, LocalDate date, LocalTime startTime, + LocalTime endTime) { + this.club = club; + this.title = title; + this.scheduleCategory = scheduleCategory; + this.content = content; + this.author = author; + this.location = location; + this.equipment = equipment; + this.date = date; + this.startTime = startTime; + this.endTime = endTime; + } + + public void update(String title, ScheduleCategory scheduleCategory, String content, String location, + String equipment, LocalDate date, LocalTime startTime, LocalTime endTime) { + this.title = title; + this.scheduleCategory = scheduleCategory; + this.content = content; + this.location = location; + this.equipment = equipment; + this.date = date; + this.startTime = startTime; + this.endTime = endTime; + } } diff --git a/src/main/java/com/cotato/squadus/domain/club/schedule/entity/ScheduleComment.java b/src/main/java/com/cotato/squadus/domain/club/schedule/entity/ScheduleComment.java index 6157f02..11697fa 100644 --- a/src/main/java/com/cotato/squadus/domain/club/schedule/entity/ScheduleComment.java +++ b/src/main/java/com/cotato/squadus/domain/club/schedule/entity/ScheduleComment.java @@ -1,14 +1,23 @@ package com.cotato.squadus.domain.club.schedule.entity; +import org.springframework.data.jpa.domain.support.AuditingEntityListener; + import com.cotato.squadus.common.entity.BaseTimeEntity; import com.cotato.squadus.domain.club.common.entity.ClubMember; -import jakarta.persistence.*; + +import jakarta.persistence.Entity; +import jakarta.persistence.EntityListeners; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.Lob; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.Table; import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; -import org.springframework.data.jpa.domain.support.AuditingEntityListener; - -import java.time.LocalDateTime; @Entity @Getter @@ -17,36 +26,36 @@ @EntityListeners(AuditingEntityListener.class) public class ScheduleComment extends BaseTimeEntity { - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - private Long id; + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; - @Lob - private String content; + @Lob + private String content; - private Long likes; + private Long likes; - @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "club_member_idx") - private ClubMember clubMember; + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "club_member_idx") + private ClubMember clubMember; - @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "club_schedule") - private ClubSchedule clubSchedule; + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "club_schedule") + private ClubSchedule clubSchedule; - @Builder - public ScheduleComment(String content, Long likes, ClubMember clubMember, ClubSchedule clubSchedule) { - this.content = content; - this.likes = likes; - this.clubMember = clubMember; - this.clubSchedule = clubSchedule; - } + @Builder + public ScheduleComment(String content, Long likes, ClubMember clubMember, ClubSchedule clubSchedule) { + this.content = content; + this.likes = likes; + this.clubMember = clubMember; + this.clubSchedule = clubSchedule; + } - public void updateContent(String content) { - this.content = content; - } + public void updateContent(String content) { + this.content = content; + } - public void incrementLikes() { - this.likes += 1; - } + public void incrementLikes() { + this.likes += 1; + } } diff --git a/src/main/java/com/cotato/squadus/domain/club/schedule/enums/ScheduleCategory.java b/src/main/java/com/cotato/squadus/domain/club/schedule/enums/ScheduleCategory.java index ad62bdd..7adb658 100644 --- a/src/main/java/com/cotato/squadus/domain/club/schedule/enums/ScheduleCategory.java +++ b/src/main/java/com/cotato/squadus/domain/club/schedule/enums/ScheduleCategory.java @@ -1,9 +1,9 @@ package com.cotato.squadus.domain.club.schedule.enums; public enum ScheduleCategory { - MEETING, - PRACTICE, - COMPETITION, - SOCIAL, - OTHER + MEETING, + PRACTICE, + COMPETITION, + SOCIAL, + OTHER } diff --git a/src/main/java/com/cotato/squadus/domain/club/schedule/repository/ClubScheduleRepository.java b/src/main/java/com/cotato/squadus/domain/club/schedule/repository/ClubScheduleRepository.java index 0f41296..5b57d4e 100644 --- a/src/main/java/com/cotato/squadus/domain/club/schedule/repository/ClubScheduleRepository.java +++ b/src/main/java/com/cotato/squadus/domain/club/schedule/repository/ClubScheduleRepository.java @@ -1,24 +1,23 @@ package com.cotato.squadus.domain.club.schedule.repository; -import com.cotato.squadus.domain.club.schedule.entity.ClubSchedule; -import org.springframework.data.domain.Pageable; -import org.springframework.data.jpa.repository.JpaRepository; - import java.time.LocalDate; -import java.time.LocalDateTime; -import java.util.Collection; import java.util.List; import java.util.Optional; +import org.springframework.data.domain.Pageable; +import org.springframework.data.jpa.repository.JpaRepository; + +import com.cotato.squadus.domain.club.schedule.entity.ClubSchedule; + public interface ClubScheduleRepository extends JpaRepository { - List findByClubClubId(Long clubId); + List findByClubClubId(Long clubId); - List findByClubClubIdAndDate(Long clubId, LocalDate date); + List findByClubClubIdAndDate(Long clubId, LocalDate date); - List findByClubClubIdAndDateBetween(Long clubId, LocalDate startDate, LocalDate endDate); + List findByClubClubIdAndDateBetween(Long clubId, LocalDate startDate, LocalDate endDate); - Optional findByScheduleIdxAndClubClubId(Long scheduleId, Long clubId); + Optional findByScheduleIdxAndClubClubId(Long scheduleId, Long clubId); - List findByClubClubIdOrderByDateAscStartTimeAsc(Long clubId, Pageable pageable); + List findByClubClubIdOrderByDateAscStartTimeAsc(Long clubId, Pageable pageable); } \ No newline at end of file diff --git a/src/main/java/com/cotato/squadus/domain/club/schedule/repository/ScheduleCommentRepository.java b/src/main/java/com/cotato/squadus/domain/club/schedule/repository/ScheduleCommentRepository.java index 6dcbb54..aab0efb 100644 --- a/src/main/java/com/cotato/squadus/domain/club/schedule/repository/ScheduleCommentRepository.java +++ b/src/main/java/com/cotato/squadus/domain/club/schedule/repository/ScheduleCommentRepository.java @@ -1,12 +1,11 @@ package com.cotato.squadus.domain.club.schedule.repository; +import java.util.List; -import com.cotato.squadus.domain.club.schedule.entity.ScheduleComment; import org.springframework.data.jpa.repository.JpaRepository; -import java.time.LocalDate; -import java.util.List; +import com.cotato.squadus.domain.club.schedule.entity.ScheduleComment; public interface ScheduleCommentRepository extends JpaRepository { - List findByClubScheduleScheduleIdx(Long scheduleIdx); + List findByClubScheduleScheduleIdx(Long scheduleIdx); } diff --git a/src/main/java/com/cotato/squadus/domain/club/schedule/service/ClubScheduleService.java b/src/main/java/com/cotato/squadus/domain/club/schedule/service/ClubScheduleService.java index 1e6b65c..e41db5d 100644 --- a/src/main/java/com/cotato/squadus/domain/club/schedule/service/ClubScheduleService.java +++ b/src/main/java/com/cotato/squadus/domain/club/schedule/service/ClubScheduleService.java @@ -1,140 +1,145 @@ package com.cotato.squadus.domain.club.schedule.service; +import java.time.LocalDate; +import java.time.YearMonth; +import java.util.List; +import java.util.stream.Collectors; + +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Pageable; +import org.springframework.stereotype.Service; + import com.cotato.squadus.api.schedule.dto.ClubScheduleRequest; import com.cotato.squadus.api.schedule.dto.ClubScheduleResponse; -import com.cotato.squadus.common.error.ErrorCode; import com.cotato.squadus.domain.auth.enums.AdminStatus; import com.cotato.squadus.domain.club.common.entity.Club; import com.cotato.squadus.domain.club.common.entity.ClubAdminMember; import com.cotato.squadus.domain.club.common.repository.ClubAdminMemberRepository; -import com.cotato.squadus.domain.club.common.repository.ClubMemberRepository; import com.cotato.squadus.domain.club.common.repository.ClubRepository; import com.cotato.squadus.domain.club.schedule.entity.ClubSchedule; import com.cotato.squadus.domain.club.schedule.enums.ScheduleCategory; import com.cotato.squadus.domain.club.schedule.repository.ClubScheduleRepository; + import jakarta.persistence.EntityNotFoundException; import jakarta.transaction.Transactional; import lombok.RequiredArgsConstructor; -import org.springframework.data.domain.PageRequest; -import org.springframework.data.domain.Pageable; -import org.springframework.stereotype.Service; - -import java.time.LocalDate; -import java.time.YearMonth; -import java.util.List; -import java.util.stream.Collectors; @Service @RequiredArgsConstructor public class ClubScheduleService { - private final ClubScheduleRepository clubScheduleRepository; - private final ClubRepository clubRepository; - private final ClubAdminMemberRepository clubAdminMemberRepository; - - //club의 모든 schedule을 가져옴 - public List findAllSchedules(Long clubId) { - List schedules = clubScheduleRepository.findByClubClubId(clubId); - return schedules.stream() - .map(ClubScheduleResponse::from) - .collect(Collectors.toList()); - } - - //club의 특정한 날짜의 schedule들을 가져옴 - public List findSchedulesByDate(Long clubId, LocalDate date) { - List schedules = clubScheduleRepository.findByClubClubIdAndDate(clubId, date); - return schedules.stream() - .map(ClubScheduleResponse::from) - .collect(Collectors.toList()); - } - - // club의 특정 연도와 월의 schedule들을 가져옴 - public List findSchedulesByYearMonth(Long clubId, int year, int month) { - YearMonth yearMonth = YearMonth.of(year, month); - LocalDate startDate = yearMonth.atDay(1); - LocalDate endDate = yearMonth.atEndOfMonth(); - List schedules = clubScheduleRepository.findByClubClubIdAndDateBetween(clubId, startDate, endDate); - return schedules.stream() - .map(ClubScheduleResponse::from) - .collect(Collectors.toList()); - } - - - @Transactional - public ClubScheduleResponse createSchedule(Long clubId, ClubScheduleRequest scheduleRequest) { - Club club = clubRepository.findById(clubId) - .orElseThrow(() -> new EntityNotFoundException("Club not found with id: " + clubId)); - - ClubAdminMember adminMember = clubAdminMemberRepository.findByClubMemberIdxAndAdminStatus(scheduleRequest.getAuthorId(), AdminStatus.CURRENT) - .orElseThrow(() -> new EntityNotFoundException("Admin member not found with id: " + scheduleRequest.getAuthorId())); - - ClubSchedule schedule = ClubSchedule.builder() - .club(club) - .title(scheduleRequest.getTitle()) - .scheduleCategory(ScheduleCategory.valueOf(scheduleRequest.getScheduleCategory())) - .content(scheduleRequest.getContent()) - .author(adminMember) - .location(scheduleRequest.getLocation()) - .equipment(scheduleRequest.getEquipment()) - .date(scheduleRequest.getDate()) - .startTime(scheduleRequest.getStartTime()) - .endTime(scheduleRequest.getEndTime()) - .build(); - - clubScheduleRepository.save(schedule); - return ClubScheduleResponse.from(schedule); - } - - @Transactional - public void deleteSchedule(Long clubId, Long scheduleId, Long adminId) { - ClubSchedule schedule = clubScheduleRepository.findByScheduleIdxAndClubClubId(scheduleId, clubId) - .orElseThrow(() -> new EntityNotFoundException("Schedule not found with id: " + scheduleId)); - - ClubAdminMember adminMember = clubAdminMemberRepository.findByClubMemberIdxAndAdminStatus(adminId, AdminStatus.CURRENT) - .orElseThrow(() -> new EntityNotFoundException("Admin member not found or not CURRENT with id: " + adminId)); - - if (!schedule.getAuthor().getClubMemberIdx().equals(adminMember.getClubMemberIdx())) { - throw new IllegalArgumentException("You do not have permission to delete this schedule."); - } - - clubScheduleRepository.delete(schedule); - } - - - @Transactional - public ClubScheduleResponse updateSchedule(Long clubId, Long scheduleId, ClubScheduleRequest scheduleRequest) { - ClubSchedule schedule = clubScheduleRepository.findByScheduleIdxAndClubClubId(scheduleId, clubId) - .orElseThrow(() -> new EntityNotFoundException("Schedule not found with id: " + scheduleId)); - - ClubAdminMember adminMember = clubAdminMemberRepository.findByClubMemberIdxAndAdminStatus(scheduleRequest.getAuthorId(), AdminStatus.CURRENT) - .orElseThrow(() -> new EntityNotFoundException("Admin member not found or not CURRENT with id: " + scheduleRequest.getAuthorId())); - - if (!schedule.getAuthor().getClubMemberIdx().equals(adminMember.getClubMemberIdx())) { - throw new IllegalArgumentException("You do not have permission to update this schedule."); - } - - schedule.update( - scheduleRequest.getTitle(), - ScheduleCategory.valueOf(scheduleRequest.getScheduleCategory()), - scheduleRequest.getContent(), - scheduleRequest.getLocation(), - scheduleRequest.getEquipment(), - scheduleRequest.getDate(), - scheduleRequest.getStartTime(), - scheduleRequest.getEndTime() - ); - - clubScheduleRepository.save(schedule); - return ClubScheduleResponse.from(schedule); - } - - public List findTopUpcomingSchedules(Long clubId, int limit) { - - Pageable pageable = PageRequest.of(0, limit); - return clubScheduleRepository.findByClubClubIdOrderByDateAscStartTimeAsc(clubId, pageable) - .stream() - .map(ClubScheduleResponse::from) - .toList(); - } + private final ClubScheduleRepository clubScheduleRepository; + private final ClubRepository clubRepository; + private final ClubAdminMemberRepository clubAdminMemberRepository; + + //club의 모든 schedule을 가져옴 + public List findAllSchedules(Long clubId) { + List schedules = clubScheduleRepository.findByClubClubId(clubId); + return schedules.stream() + .map(ClubScheduleResponse::from) + .collect(Collectors.toList()); + } + + //club의 특정한 날짜의 schedule들을 가져옴 + public List findSchedulesByDate(Long clubId, LocalDate date) { + List schedules = clubScheduleRepository.findByClubClubIdAndDate(clubId, date); + return schedules.stream() + .map(ClubScheduleResponse::from) + .collect(Collectors.toList()); + } + + // club의 특정 연도와 월의 schedule들을 가져옴 + public List findSchedulesByYearMonth(Long clubId, int year, int month) { + YearMonth yearMonth = YearMonth.of(year, month); + LocalDate startDate = yearMonth.atDay(1); + LocalDate endDate = yearMonth.atEndOfMonth(); + List schedules = clubScheduleRepository.findByClubClubIdAndDateBetween(clubId, startDate, + endDate); + return schedules.stream() + .map(ClubScheduleResponse::from) + .collect(Collectors.toList()); + } + + @Transactional + public ClubScheduleResponse createSchedule(Long clubId, ClubScheduleRequest scheduleRequest) { + Club club = clubRepository.findById(clubId) + .orElseThrow(() -> new EntityNotFoundException("Club not found with id: " + clubId)); + + ClubAdminMember adminMember = clubAdminMemberRepository.findByClubMemberIdxAndAdminStatus( + scheduleRequest.getAuthorId(), AdminStatus.CURRENT) + .orElseThrow( + () -> new EntityNotFoundException("Admin member not found with id: " + scheduleRequest.getAuthorId())); + + ClubSchedule schedule = ClubSchedule.builder() + .club(club) + .title(scheduleRequest.getTitle()) + .scheduleCategory(ScheduleCategory.valueOf(scheduleRequest.getScheduleCategory())) + .content(scheduleRequest.getContent()) + .author(adminMember) + .location(scheduleRequest.getLocation()) + .equipment(scheduleRequest.getEquipment()) + .date(scheduleRequest.getDate()) + .startTime(scheduleRequest.getStartTime()) + .endTime(scheduleRequest.getEndTime()) + .build(); + + clubScheduleRepository.save(schedule); + return ClubScheduleResponse.from(schedule); + } + + @Transactional + public void deleteSchedule(Long clubId, Long scheduleId, Long adminId) { + ClubSchedule schedule = clubScheduleRepository.findByScheduleIdxAndClubClubId(scheduleId, clubId) + .orElseThrow(() -> new EntityNotFoundException("Schedule not found with id: " + scheduleId)); + + ClubAdminMember adminMember = clubAdminMemberRepository.findByClubMemberIdxAndAdminStatus(adminId, + AdminStatus.CURRENT) + .orElseThrow( + () -> new EntityNotFoundException("Admin member not found or not CURRENT with id: " + adminId)); + + if (!schedule.getAuthor().getClubMemberIdx().equals(adminMember.getClubMemberIdx())) { + throw new IllegalArgumentException("You do not have permission to delete this schedule."); + } + + clubScheduleRepository.delete(schedule); + } + + @Transactional + public ClubScheduleResponse updateSchedule(Long clubId, Long scheduleId, ClubScheduleRequest scheduleRequest) { + ClubSchedule schedule = clubScheduleRepository.findByScheduleIdxAndClubClubId(scheduleId, clubId) + .orElseThrow(() -> new EntityNotFoundException("Schedule not found with id: " + scheduleId)); + + ClubAdminMember adminMember = clubAdminMemberRepository.findByClubMemberIdxAndAdminStatus( + scheduleRequest.getAuthorId(), AdminStatus.CURRENT) + .orElseThrow(() -> new EntityNotFoundException( + "Admin member not found or not CURRENT with id: " + scheduleRequest.getAuthorId())); + + if (!schedule.getAuthor().getClubMemberIdx().equals(adminMember.getClubMemberIdx())) { + throw new IllegalArgumentException("You do not have permission to update this schedule."); + } + + schedule.update( + scheduleRequest.getTitle(), + ScheduleCategory.valueOf(scheduleRequest.getScheduleCategory()), + scheduleRequest.getContent(), + scheduleRequest.getLocation(), + scheduleRequest.getEquipment(), + scheduleRequest.getDate(), + scheduleRequest.getStartTime(), + scheduleRequest.getEndTime() + ); + + clubScheduleRepository.save(schedule); + return ClubScheduleResponse.from(schedule); + } + + public List findTopUpcomingSchedules(Long clubId, int limit) { + + Pageable pageable = PageRequest.of(0, limit); + return clubScheduleRepository.findByClubClubIdOrderByDateAscStartTimeAsc(clubId, pageable) + .stream() + .map(ClubScheduleResponse::from) + .toList(); + } } diff --git a/src/main/java/com/cotato/squadus/domain/club/schedule/service/ScheduleCommentService.java b/src/main/java/com/cotato/squadus/domain/club/schedule/service/ScheduleCommentService.java index 737b191..e3b019d 100644 --- a/src/main/java/com/cotato/squadus/domain/club/schedule/service/ScheduleCommentService.java +++ b/src/main/java/com/cotato/squadus/domain/club/schedule/service/ScheduleCommentService.java @@ -1,94 +1,95 @@ package com.cotato.squadus.domain.club.schedule.service; +import java.util.List; +import java.util.stream.Collectors; + +import org.springframework.stereotype.Service; + import com.cotato.squadus.api.schedule.dto.LikeResponse; import com.cotato.squadus.api.schedule.dto.ScheduleCommentRequest; import com.cotato.squadus.api.schedule.dto.ScheduleCommentResponse; -import com.cotato.squadus.common.error.ErrorCode; import com.cotato.squadus.domain.club.common.entity.ClubMember; import com.cotato.squadus.domain.club.common.repository.ClubMemberRepository; import com.cotato.squadus.domain.club.schedule.entity.ClubSchedule; import com.cotato.squadus.domain.club.schedule.entity.ScheduleComment; import com.cotato.squadus.domain.club.schedule.repository.ClubScheduleRepository; import com.cotato.squadus.domain.club.schedule.repository.ScheduleCommentRepository; + import jakarta.persistence.EntityNotFoundException; import jakarta.transaction.Transactional; import lombok.RequiredArgsConstructor; -import org.springframework.stereotype.Service; - -import java.time.LocalDateTime; -import java.util.List; -import java.util.stream.Collectors; @Service @RequiredArgsConstructor public class ScheduleCommentService { - private final ClubScheduleRepository clubScheduleRepository; - private final ScheduleCommentRepository scheduleCommentRepository; - private final ClubMemberRepository clubMemberRepository; - - @Transactional - public ScheduleCommentResponse addComment(Long scheduleId, ScheduleCommentRequest scheduleCommentRequest) { - ClubSchedule schedule = clubScheduleRepository.findById(scheduleId) - .orElseThrow(() -> new EntityNotFoundException("Schedule not found with id: " + scheduleId)); + private final ClubScheduleRepository clubScheduleRepository; + private final ScheduleCommentRepository scheduleCommentRepository; + private final ClubMemberRepository clubMemberRepository; - ClubMember member = clubMemberRepository.findById(scheduleCommentRequest.getMemberId()) - .orElseThrow(() -> new EntityNotFoundException("Member not found with id: " + scheduleCommentRequest.getMemberId())); + @Transactional + public ScheduleCommentResponse addComment(Long scheduleId, ScheduleCommentRequest scheduleCommentRequest) { + ClubSchedule schedule = clubScheduleRepository.findById(scheduleId) + .orElseThrow(() -> new EntityNotFoundException("Schedule not found with id: " + scheduleId)); - ScheduleComment comment = ScheduleComment.builder() - .content(scheduleCommentRequest.getContent()) - .likes(0L) - .clubMember(member) - .clubSchedule(schedule) - .build(); + ClubMember member = clubMemberRepository.findById(scheduleCommentRequest.getMemberId()) + .orElseThrow( + () -> new EntityNotFoundException("Member not found with id: " + scheduleCommentRequest.getMemberId())); - scheduleCommentRepository.save(comment); + ScheduleComment comment = ScheduleComment.builder() + .content(scheduleCommentRequest.getContent()) + .likes(0L) + .clubMember(member) + .clubSchedule(schedule) + .build(); - return ScheduleCommentResponse.from(comment); - } + scheduleCommentRepository.save(comment); - @Transactional - public ScheduleCommentResponse updateComment(Long scheduleId, Long commentId, ScheduleCommentRequest scheduleCommentRequest) { - ScheduleComment comment = scheduleCommentRepository.findById(commentId) - .orElseThrow(() -> new EntityNotFoundException("Comment not found with id: " + commentId)); + return ScheduleCommentResponse.from(comment); + } - if (!comment.getClubMember().getClubMemberIdx().equals(scheduleCommentRequest.getMemberId())) { - throw new EntityNotFoundException("엔티티를 찾을 수 없습니다."); - } + @Transactional + public ScheduleCommentResponse updateComment(Long scheduleId, Long commentId, + ScheduleCommentRequest scheduleCommentRequest) { + ScheduleComment comment = scheduleCommentRepository.findById(commentId) + .orElseThrow(() -> new EntityNotFoundException("Comment not found with id: " + commentId)); - comment.updateContent(scheduleCommentRequest.getContent()); - scheduleCommentRepository.save(comment); + if (!comment.getClubMember().getClubMemberIdx().equals(scheduleCommentRequest.getMemberId())) { + throw new EntityNotFoundException("엔티티를 찾을 수 없습니다."); + } - return ScheduleCommentResponse.from(comment); - } + comment.updateContent(scheduleCommentRequest.getContent()); + scheduleCommentRepository.save(comment); - @Transactional - public void deleteComment(Long scheduleId, Long commentId, Long memberId) { - ScheduleComment comment = scheduleCommentRepository.findById(commentId) - .orElseThrow(() -> new EntityNotFoundException("Comment not found with id: " + commentId)); + return ScheduleCommentResponse.from(comment); + } - if (!comment.getClubMember().getClubMemberIdx().equals(memberId)) { - throw new EntityNotFoundException("엔티티를 찾을 수 없습니다."); - } + @Transactional + public void deleteComment(Long scheduleId, Long commentId, Long memberId) { + ScheduleComment comment = scheduleCommentRepository.findById(commentId) + .orElseThrow(() -> new EntityNotFoundException("Comment not found with id: " + commentId)); - scheduleCommentRepository.delete(comment); - } + if (!comment.getClubMember().getClubMemberIdx().equals(memberId)) { + throw new EntityNotFoundException("엔티티를 찾을 수 없습니다."); + } + scheduleCommentRepository.delete(comment); + } - public List getAllComments(Long scheduleId) { - List comments = scheduleCommentRepository.findByClubScheduleScheduleIdx(scheduleId); - return comments.stream() - .map(ScheduleCommentResponse::from) - .collect(Collectors.toList()); - } + public List getAllComments(Long scheduleId) { + List comments = scheduleCommentRepository.findByClubScheduleScheduleIdx(scheduleId); + return comments.stream() + .map(ScheduleCommentResponse::from) + .collect(Collectors.toList()); + } - public LikeResponse likeComment(Long scheduleId, Long commentId) { - ScheduleComment comment = scheduleCommentRepository.findById(commentId) - .orElseThrow(() -> new EntityNotFoundException("Comment not found with id: " + commentId)); + public LikeResponse likeComment(Long scheduleId, Long commentId) { + ScheduleComment comment = scheduleCommentRepository.findById(commentId) + .orElseThrow(() -> new EntityNotFoundException("Comment not found with id: " + commentId)); - comment.incrementLikes(); - scheduleCommentRepository.save(comment); + comment.incrementLikes(); + scheduleCommentRepository.save(comment); - return LikeResponse.from(comment.getId(), comment.getLikes()); - } + return LikeResponse.from(comment.getId(), comment.getLikes()); + } } diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index ae884d5..0607576 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -1,14 +1,6 @@ spring: jwt: secret: ${JWT_SECRET} - -# access: -# expiration: 80 -# header: Authorization -# -# refresh: -# expiration: 90 -# header: Authorization-refresh mail: host: smtp.gmail.com username: ${MAIL_ADDRESS} @@ -23,12 +15,11 @@ spring: password: ${DB_PASSWORD} driver-class-name: com.mysql.cj.jdbc.Driver jpa: + open-in-view: false hibernate: ddl-auto: update properties: - hibernate: - dialect: org.hibernate.dialect.MySQL8Dialect - format_sql: true + format_sql: true security: oauth2: client: @@ -80,6 +71,9 @@ spring: enabled: true max-file-size: 10MB max-request-size: 10MB + thymeleaf: # thymeleaf 제거 + enabled: false + check-template: false cloud: aws: