From c55ce0c320ccf41ac791730ffd4c358b0f9cacaf Mon Sep 17 00:00:00 2001 From: Jeongho Date: Fri, 10 May 2024 15:40:28 +0900 Subject: [PATCH 01/16] =?UTF-8?q?Docs:=20kakao=20controller=20swagger=20de?= =?UTF-8?q?scription=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../backend/domain/auth/oauth/controller/KakaoController.java | 3 +-- .../backend/domain/register/controller/RegisterController.java | 3 --- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/src/main/java/com/meetup/teame/backend/domain/auth/oauth/controller/KakaoController.java b/src/main/java/com/meetup/teame/backend/domain/auth/oauth/controller/KakaoController.java index d9315f5..e693e4b 100644 --- a/src/main/java/com/meetup/teame/backend/domain/auth/oauth/controller/KakaoController.java +++ b/src/main/java/com/meetup/teame/backend/domain/auth/oauth/controller/KakaoController.java @@ -13,7 +13,6 @@ import lombok.RequiredArgsConstructor; import org.springframework.http.*; import org.springframework.web.bind.annotation.*; -import java.util.Optional; @RequiredArgsConstructor @@ -31,7 +30,7 @@ public class KakaoController { 이미 등록된 사용자면 "login"이 출력되고 - 등록되지 않은 사용자면 "/api/sign-up"을 요청해서 거주지 정보를 추가로 받아줘야 합니다. + 등록되지 않은 사용자면 "/sign-up"을 요청해서 거주지 정보를 추가로 받아줘야 합니다. """) @GetMapping("/login/kakao") public ResponseEntity kakaoLogin(@RequestParam String code) throws JsonProcessingException { diff --git a/src/main/java/com/meetup/teame/backend/domain/register/controller/RegisterController.java b/src/main/java/com/meetup/teame/backend/domain/register/controller/RegisterController.java index 93f3a1a..aca39b4 100644 --- a/src/main/java/com/meetup/teame/backend/domain/register/controller/RegisterController.java +++ b/src/main/java/com/meetup/teame/backend/domain/register/controller/RegisterController.java @@ -13,7 +13,6 @@ import org.springframework.http.ResponseEntity; 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; @RequiredArgsConstructor @@ -46,9 +45,7 @@ public ResponseEntity sendEmail(@RequestBody EmailRequest request) { """) @PostMapping("/register") public ResponseEntity register(@RequestBody RegisterRequest request) { - System.out.println("메서드 시작"); Long userId = registerService.register(request); - System.out.println("저장 메서드까지는 함"); HttpHeaders headers = kakaoService.getLoginHeader(userService.findById(userId)); return ResponseEntity.ok().headers(headers).body("회원가입 성공"); } From b4257115fa524a336f0310a5709795a42cb5aeb9 Mon Sep 17 00:00:00 2001 From: Jeongho Date: Sun, 12 May 2024 01:21:17 +0900 Subject: [PATCH 02/16] =?UTF-8?q?Feat:=20=ED=99=9C=EB=8F=99=20=EC=83=81?= =?UTF-8?q?=EC=84=B8=EC=A0=95=EB=B3=B4=20=EC=A1=B0=ED=9A=8C,=20=EC=A0=84?= =?UTF-8?q?=EC=B2=B4=20=ED=99=9C=EB=8F=99=20=EB=B6=88=EB=9F=AC=EC=98=A4?= =?UTF-8?q?=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/ActivityController.java | 37 ++++++++++++++ .../dto/response/ActivityDetailsRes.java | 48 +++++++++++++++++++ .../dto/response/ActivitySummaryRes.java | 41 ++++++++++++++++ .../domain/activity/entity/Activity.java | 3 ++ .../activity/service/ActivityService.java | 48 +++++++++++++++++++ .../global/exception/ExceptionContent.java | 1 + 6 files changed, 178 insertions(+) create mode 100644 src/main/java/com/meetup/teame/backend/domain/activity/controller/ActivityController.java create mode 100644 src/main/java/com/meetup/teame/backend/domain/activity/dto/response/ActivityDetailsRes.java create mode 100644 src/main/java/com/meetup/teame/backend/domain/activity/dto/response/ActivitySummaryRes.java create mode 100644 src/main/java/com/meetup/teame/backend/domain/activity/service/ActivityService.java diff --git a/src/main/java/com/meetup/teame/backend/domain/activity/controller/ActivityController.java b/src/main/java/com/meetup/teame/backend/domain/activity/controller/ActivityController.java new file mode 100644 index 0000000..5ac5ffe --- /dev/null +++ b/src/main/java/com/meetup/teame/backend/domain/activity/controller/ActivityController.java @@ -0,0 +1,37 @@ +package com.meetup.teame.backend.domain.activity.controller; + +import com.meetup.teame.backend.domain.activity.dto.response.ActivityDetailsRes; +import com.meetup.teame.backend.domain.activity.dto.response.ActivitySummaryRes; +import com.meetup.teame.backend.domain.activity.service.ActivityService; +import lombok.RequiredArgsConstructor; +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.RestController; + +import java.util.List; + +@RequiredArgsConstructor +@RestController +public class ActivityController { + + private final ActivityService activityService; + + //activityId로 특정 활동 불러오기 + @GetMapping("/{activityId}/activity-details") + public ResponseEntity getActivityDetails(@PathVariable Long activityId) { + ActivityDetailsRes activityDetailsRes = activityService.getActivityDetails(activityId); + return ResponseEntity.ok().body(activityDetailsRes); + } + + /** + * 페이징 처리 해야함 + */ + //전체 활동 불러오기 + @GetMapping("/activity-summaries") + public ResponseEntity> getActivitySummaries() { + List activitySummaries = activityService.getActivitySummaries(); + return ResponseEntity.ok().body(activitySummaries); + } + +} diff --git a/src/main/java/com/meetup/teame/backend/domain/activity/dto/response/ActivityDetailsRes.java b/src/main/java/com/meetup/teame/backend/domain/activity/dto/response/ActivityDetailsRes.java new file mode 100644 index 0000000..9dbf9de --- /dev/null +++ b/src/main/java/com/meetup/teame/backend/domain/activity/dto/response/ActivityDetailsRes.java @@ -0,0 +1,48 @@ +package com.meetup.teame.backend.domain.activity.dto.response; + +import com.meetup.teame.backend.domain.activity.entity.Activity; +import com.meetup.teame.backend.domain.personality.Personality; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import org.hibernate.annotations.Comment; + +import java.time.LocalDateTime; +import java.util.List; + +@NoArgsConstructor +@AllArgsConstructor +@Getter +@Builder +public class ActivityDetailsRes { + + private Long id; + + private String title; + + private String agency; + + private String location; + + private LocalDateTime time; + + private Long currentParticipants; + + private Long maxParticipants; + + private List personalities; + + public static ActivityDetailsRes of(Activity activity) { + return ActivityDetailsRes.builder() + .id(activity.getId()) + .title(activity.getTitle()) + .agency(activity.getAgency()) + .location(activity.getLocation()) + .time(activity.getTime()) + .currentParticipants(activity.getCurrentParticipants()) + .maxParticipants(activity.getMaxParticipants()) + .personalities(activity.getPersonalities()) + .build(); + } +} diff --git a/src/main/java/com/meetup/teame/backend/domain/activity/dto/response/ActivitySummaryRes.java b/src/main/java/com/meetup/teame/backend/domain/activity/dto/response/ActivitySummaryRes.java new file mode 100644 index 0000000..204cde7 --- /dev/null +++ b/src/main/java/com/meetup/teame/backend/domain/activity/dto/response/ActivitySummaryRes.java @@ -0,0 +1,41 @@ +package com.meetup.teame.backend.domain.activity.dto.response; + +import com.meetup.teame.backend.domain.activity.entity.Activity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import org.hibernate.annotations.Comment; + +import java.time.LocalDateTime; + +@NoArgsConstructor +@AllArgsConstructor +@Getter +@Builder +public class ActivitySummaryRes { + + private Long id; + + private String title; + + private String agency; + + private String location; + + private LocalDateTime time; + + //나중에 어떤 유저가 좋아요를 눌렀는지 안눌렀는지 체크하는거 해야함 + private boolean isLiked; + + public static ActivitySummaryRes of(Activity activity) { + return ActivitySummaryRes.builder() + .id(activity.getId()) + .title(activity.getTitle()) + .agency(activity.getAgency()) + .time(activity.getTime()) + .build(); + } +} diff --git a/src/main/java/com/meetup/teame/backend/domain/activity/entity/Activity.java b/src/main/java/com/meetup/teame/backend/domain/activity/entity/Activity.java index d116bfc..7af7d92 100644 --- a/src/main/java/com/meetup/teame/backend/domain/activity/entity/Activity.java +++ b/src/main/java/com/meetup/teame/backend/domain/activity/entity/Activity.java @@ -23,6 +23,9 @@ public class Activity { @Comment("활동 제목") private String title; + @Comment("활동 제공 기관") + private String agency; + @Comment("활동 장소") private String location; diff --git a/src/main/java/com/meetup/teame/backend/domain/activity/service/ActivityService.java b/src/main/java/com/meetup/teame/backend/domain/activity/service/ActivityService.java new file mode 100644 index 0000000..9f04859 --- /dev/null +++ b/src/main/java/com/meetup/teame/backend/domain/activity/service/ActivityService.java @@ -0,0 +1,48 @@ +package com.meetup.teame.backend.domain.activity.service; + +import com.meetup.teame.backend.domain.activity.dto.response.ActivityDetailsRes; +import com.meetup.teame.backend.domain.activity.dto.response.ActivitySummaryRes; +import com.meetup.teame.backend.domain.activity.entity.Activity; +import com.meetup.teame.backend.domain.activity.repository.ActivityRepository; +import com.meetup.teame.backend.global.exception.CustomException; +import com.meetup.teame.backend.global.exception.ExceptionContent; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; + +import java.util.List; +import java.util.stream.Collectors; + +@RequiredArgsConstructor +@Service +public class ActivityService { + + private final ActivityRepository activityRepository; + + //활동 참여 신청하기 + + + //특정 활동 상제 정보 response dto화 + public ActivityDetailsRes getActivityDetails(Long activityId) { + Activity activity = findActivityById(activityId); + return ActivityDetailsRes.of(activity); + } + + //전체 활동 불러오기 dto화 + public List getActivitySummaries() { + List activities = findAllActivities(); + return activities.stream() + .map(ActivitySummaryRes::of) + .collect(Collectors.toList()); + } + + //activityId로 특정 활동 불러오기 + private Activity findActivityById(Long activityId) { + return activityRepository.findById(activityId) + .orElseThrow(() -> new CustomException(ExceptionContent.NOT_FOUND_ACTIVITY)); + } + + //전체 활동 불러오기 + private List findAllActivities() { + return activityRepository.findAll(); + } +} diff --git a/src/main/java/com/meetup/teame/backend/global/exception/ExceptionContent.java b/src/main/java/com/meetup/teame/backend/global/exception/ExceptionContent.java index 6dfd9ff..1e6eeca 100644 --- a/src/main/java/com/meetup/teame/backend/global/exception/ExceptionContent.java +++ b/src/main/java/com/meetup/teame/backend/global/exception/ExceptionContent.java @@ -21,6 +21,7 @@ public enum ExceptionContent { NOT_FOUND_USER(NOT_FOUND, "존재하지 않는 사용자입니다."), NOT_FOUND_PERSONALITY(NOT_FOUND, "존재하지 않는 성격입니다."), NOT_FOUND_EXPERIENCE_TYPE(NOT_FOUND, "존재하지 않는 경험 유형입니다."), + NOT_FOUND_ACTIVITY(NOT_FOUND, "존재하지 않는 활동입니다."), ; private final HttpStatus httpStatus; From 9811509cd49e85d00bf5c2e3a509ab7964f2c0f9 Mon Sep 17 00:00:00 2001 From: Jeongho Date: Sun, 12 May 2024 16:14:37 +0900 Subject: [PATCH 03/16] =?UTF-8?q?Feat:=20=EC=A0=84=EC=B2=B4=20=ED=99=9C?= =?UTF-8?q?=EB=8F=99=20=EC=A1=B0=ED=9A=8C=20=ED=8E=98=EC=9D=B4=EC=A7=80?= =?UTF-8?q?=EB=84=A4=EC=9D=B4=EC=85=98=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../activity/controller/ActivityController.java | 13 +++++++------ .../activity/dto/response/ActivityPageRes.java | 6 ++++++ .../domain/activity/service/ActivityService.java | 14 +++++++++++--- 3 files changed, 24 insertions(+), 9 deletions(-) create mode 100644 src/main/java/com/meetup/teame/backend/domain/activity/dto/response/ActivityPageRes.java diff --git a/src/main/java/com/meetup/teame/backend/domain/activity/controller/ActivityController.java b/src/main/java/com/meetup/teame/backend/domain/activity/controller/ActivityController.java index 5ac5ffe..1d5fdeb 100644 --- a/src/main/java/com/meetup/teame/backend/domain/activity/controller/ActivityController.java +++ b/src/main/java/com/meetup/teame/backend/domain/activity/controller/ActivityController.java @@ -1,12 +1,14 @@ package com.meetup.teame.backend.domain.activity.controller; import com.meetup.teame.backend.domain.activity.dto.response.ActivityDetailsRes; +import com.meetup.teame.backend.domain.activity.dto.response.ActivityPageRes; import com.meetup.teame.backend.domain.activity.dto.response.ActivitySummaryRes; import com.meetup.teame.backend.domain.activity.service.ActivityService; import lombok.RequiredArgsConstructor; 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.RequestParam; import org.springframework.web.bind.annotation.RestController; import java.util.List; @@ -24,14 +26,13 @@ public ResponseEntity getActivityDetails(@PathVariable Long return ResponseEntity.ok().body(activityDetailsRes); } - /** - * 페이징 처리 해야함 - */ //전체 활동 불러오기 @GetMapping("/activity-summaries") - public ResponseEntity> getActivitySummaries() { - List activitySummaries = activityService.getActivitySummaries(); - return ResponseEntity.ok().body(activitySummaries); + public ResponseEntity getActivitySummaries(@RequestParam(defaultValue = "0") int page, + @RequestParam(defaultValue = "12") int size) + { + ActivityPageRes activityPage = activityService.getActivitySummaries(page, size); + return ResponseEntity.ok().body(activityPage); } } diff --git a/src/main/java/com/meetup/teame/backend/domain/activity/dto/response/ActivityPageRes.java b/src/main/java/com/meetup/teame/backend/domain/activity/dto/response/ActivityPageRes.java new file mode 100644 index 0000000..4634bc6 --- /dev/null +++ b/src/main/java/com/meetup/teame/backend/domain/activity/dto/response/ActivityPageRes.java @@ -0,0 +1,6 @@ +package com.meetup.teame.backend.domain.activity.dto.response; + +import java.util.List; + +public record ActivityPageRes(List activities, int totalPages, long totalElements) { +} diff --git a/src/main/java/com/meetup/teame/backend/domain/activity/service/ActivityService.java b/src/main/java/com/meetup/teame/backend/domain/activity/service/ActivityService.java index 9f04859..1adaba3 100644 --- a/src/main/java/com/meetup/teame/backend/domain/activity/service/ActivityService.java +++ b/src/main/java/com/meetup/teame/backend/domain/activity/service/ActivityService.java @@ -1,18 +1,24 @@ package com.meetup.teame.backend.domain.activity.service; import com.meetup.teame.backend.domain.activity.dto.response.ActivityDetailsRes; +import com.meetup.teame.backend.domain.activity.dto.response.ActivityPageRes; import com.meetup.teame.backend.domain.activity.dto.response.ActivitySummaryRes; import com.meetup.teame.backend.domain.activity.entity.Activity; import com.meetup.teame.backend.domain.activity.repository.ActivityRepository; import com.meetup.teame.backend.global.exception.CustomException; import com.meetup.teame.backend.global.exception.ExceptionContent; import lombok.RequiredArgsConstructor; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Pageable; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; import java.util.List; import java.util.stream.Collectors; @RequiredArgsConstructor +@Transactional(readOnly = true) @Service public class ActivityService { @@ -28,11 +34,13 @@ public ActivityDetailsRes getActivityDetails(Long activityId) { } //전체 활동 불러오기 dto화 - public List getActivitySummaries() { - List activities = findAllActivities(); - return activities.stream() + public ActivityPageRes getActivitySummaries(int page, int size) { + Pageable pageable = PageRequest.of(page, size); + Page activityPage = activityRepository.findAll(pageable); + List activitySummaries = activityPage.getContent().stream() .map(ActivitySummaryRes::of) .collect(Collectors.toList()); + return new ActivityPageRes(activitySummaries, activityPage.getTotalPages(), activityPage.getTotalElements()); } //activityId로 특정 활동 불러오기 From 006fb640bd93a6a7e51a2e7ed865fe56e94acefe Mon Sep 17 00:00:00 2001 From: Jeongho Date: Sun, 12 May 2024 17:54:12 +0900 Subject: [PATCH 04/16] =?UTF-8?q?Fix:=20SecurityConfig=20=EC=88=98?= =?UTF-8?q?=EC=A0=95=20header=EC=97=90=EC=84=9C=20=ED=86=A0=ED=81=B0=20?= =?UTF-8?q?=EC=B6=94=EC=B6=9C=20=EA=B0=80=EB=8A=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../activity/controller/ActivityController.java | 17 ++++++++++++++--- .../domain/auth/config/SecurityConfig.java | 1 + 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/meetup/teame/backend/domain/activity/controller/ActivityController.java b/src/main/java/com/meetup/teame/backend/domain/activity/controller/ActivityController.java index 1d5fdeb..cc7ef32 100644 --- a/src/main/java/com/meetup/teame/backend/domain/activity/controller/ActivityController.java +++ b/src/main/java/com/meetup/teame/backend/domain/activity/controller/ActivityController.java @@ -2,8 +2,9 @@ import com.meetup.teame.backend.domain.activity.dto.response.ActivityDetailsRes; import com.meetup.teame.backend.domain.activity.dto.response.ActivityPageRes; -import com.meetup.teame.backend.domain.activity.dto.response.ActivitySummaryRes; import com.meetup.teame.backend.domain.activity.service.ActivityService; +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.GetMapping; @@ -11,14 +12,17 @@ import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; -import java.util.List; - @RequiredArgsConstructor @RestController +@Tag(name = "activity", description = "활동 관련 api") public class ActivityController { private final ActivityService activityService; + @Operation(summary = "활동 상세 정보 조회", description = """ + 활동 id로 활동의 상세 정보를 조회합니다. + + """) //activityId로 특정 활동 불러오기 @GetMapping("/{activityId}/activity-details") public ResponseEntity getActivityDetails(@PathVariable Long activityId) { @@ -26,6 +30,13 @@ public ResponseEntity getActivityDetails(@PathVariable Long return ResponseEntity.ok().body(activityDetailsRes); } + @Operation(summary = "전체 활동 불러오기", description = """ + 활동 참여하기에 들어가면 제일 처음 볼 수 있는 페이지를 위한 기능입니다. + + 전체 활동들을 페이지 단위로 불러옵니다. + + page = 0, size = 12 로 default 값이 설정되어있어 0번 페이지에 12개의 활동들을 불러옵니다. + """) //전체 활동 불러오기 @GetMapping("/activity-summaries") public ResponseEntity getActivitySummaries(@RequestParam(defaultValue = "0") int page, diff --git a/src/main/java/com/meetup/teame/backend/domain/auth/config/SecurityConfig.java b/src/main/java/com/meetup/teame/backend/domain/auth/config/SecurityConfig.java index d59ffe1..20730da 100644 --- a/src/main/java/com/meetup/teame/backend/domain/auth/config/SecurityConfig.java +++ b/src/main/java/com/meetup/teame/backend/domain/auth/config/SecurityConfig.java @@ -42,6 +42,7 @@ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { config.setAllowCredentials(true); config.setAllowedHeaders(List.of("*")); config.setMaxAge(3600L); + config.addExposedHeader("Authorization"); return config; })) .headers(c -> c.frameOptions(c2 -> c2.disable())); From a491467e036ced617a4896e5152f437deabc74da Mon Sep 17 00:00:00 2001 From: Jeongho Date: Sun, 12 May 2024 21:00:30 +0900 Subject: [PATCH 05/16] =?UTF-8?q?Feat:=20S3=20storage=20=EC=84=A4=EC=A0=95?= =?UTF-8?q?=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle | 3 ++ .../teame/backend/global/config/S3Config.java | 33 +++++++++++++++++++ src/main/resources/application.yml | 15 ++++++++- 3 files changed, 50 insertions(+), 1 deletion(-) create mode 100644 src/main/java/com/meetup/teame/backend/global/config/S3Config.java diff --git a/build.gradle b/build.gradle index 9386646..f7313fa 100644 --- a/build.gradle +++ b/build.gradle @@ -70,6 +70,9 @@ dependencies { //MongoDB implementation 'org.springframework.boot:spring-boot-starter-data-mongodb' + + //S3 + implementation 'org.springframework.cloud:spring-cloud-starter-aws:2.2.6.RELEASE' } tasks.named('test') { diff --git a/src/main/java/com/meetup/teame/backend/global/config/S3Config.java b/src/main/java/com/meetup/teame/backend/global/config/S3Config.java new file mode 100644 index 0000000..fa9b553 --- /dev/null +++ b/src/main/java/com/meetup/teame/backend/global/config/S3Config.java @@ -0,0 +1,33 @@ +package com.meetup.teame.backend.global.config; + +import com.amazonaws.auth.AWSStaticCredentialsProvider; +import com.amazonaws.auth.BasicAWSCredentials; +import com.amazonaws.services.s3.AmazonS3Client; +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.access-key}") + private String accessKey; + + @Value("${cloud.aws.credentials.secret-key}") + private String secretKey; + + @Value("${cloud.aws.region.static}") + private String region; + + @Bean + public AmazonS3Client amazonS3Client() { + BasicAWSCredentials credentials = new BasicAWSCredentials(accessKey, secretKey); + + return (AmazonS3Client) AmazonS3ClientBuilder + .standard() + .withRegion(region) + .withCredentials(new AWSStaticCredentialsProvider(credentials)) + .build(); + } +} diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index e4da260..5ce08f1 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -41,4 +41,17 @@ kakao: jwt: secret: ${JWT_SECRET} - access-token-expired-time: 3600000 \ No newline at end of file + access-token-expired-time: 3600000 + +cloud: + aws: + s3: + bucket: ddoba + credentials: + access-key: ${S3_ACCESS} + secret-key: ${S3_SECRET} + region: + static: ap-northeast-2 + auto: false + stack: + auto: false \ No newline at end of file From 9be0150baa0287d7252d51eed8217273e673cfe7 Mon Sep 17 00:00:00 2001 From: Jeongho Date: Mon, 13 May 2024 20:32:23 +0900 Subject: [PATCH 06/16] =?UTF-8?q?Fix:=20=ED=99=9C=EB=8F=99=20=EC=82=AC?= =?UTF-8?q?=EC=A7=84=20=EB=B3=B5=EC=88=98=20=EC=B2=A8=EB=B6=80=20=EA=B0=80?= =?UTF-8?q?=EB=8A=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/ActivityController.java | 7 +--- .../dto/response/ActivityDetailsRes.java | 5 ++- .../dto/response/ActivityPageRes.java | 7 +++- .../dto/response/ActivitySummaryRes.java | 11 +++++ .../domain/activity/entity/Activity.java | 4 ++ .../activity/service/ActivityService.java | 41 ++++++++++++++++++- .../teame/backend/global/config/S3Config.java | 9 ++-- 7 files changed, 72 insertions(+), 12 deletions(-) diff --git a/src/main/java/com/meetup/teame/backend/domain/activity/controller/ActivityController.java b/src/main/java/com/meetup/teame/backend/domain/activity/controller/ActivityController.java index cc7ef32..e8570fd 100644 --- a/src/main/java/com/meetup/teame/backend/domain/activity/controller/ActivityController.java +++ b/src/main/java/com/meetup/teame/backend/domain/activity/controller/ActivityController.java @@ -7,10 +7,7 @@ import io.swagger.v3.oas.annotations.tags.Tag; import lombok.RequiredArgsConstructor; 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.RequestParam; -import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.bind.annotation.*; @RequiredArgsConstructor @RestController @@ -38,7 +35,7 @@ public ResponseEntity getActivityDetails(@PathVariable Long page = 0, size = 12 로 default 값이 설정되어있어 0번 페이지에 12개의 활동들을 불러옵니다. """) //전체 활동 불러오기 - @GetMapping("/activity-summaries") + @GetMapping("/activities") public ResponseEntity getActivitySummaries(@RequestParam(defaultValue = "0") int page, @RequestParam(defaultValue = "12") int size) { diff --git a/src/main/java/com/meetup/teame/backend/domain/activity/dto/response/ActivityDetailsRes.java b/src/main/java/com/meetup/teame/backend/domain/activity/dto/response/ActivityDetailsRes.java index 9dbf9de..a356611 100644 --- a/src/main/java/com/meetup/teame/backend/domain/activity/dto/response/ActivityDetailsRes.java +++ b/src/main/java/com/meetup/teame/backend/domain/activity/dto/response/ActivityDetailsRes.java @@ -33,7 +33,9 @@ public class ActivityDetailsRes { private List personalities; - public static ActivityDetailsRes of(Activity activity) { + private List activityImgs; + + public static ActivityDetailsRes of(Activity activity, List activityImgs) { return ActivityDetailsRes.builder() .id(activity.getId()) .title(activity.getTitle()) @@ -43,6 +45,7 @@ public static ActivityDetailsRes of(Activity activity) { .currentParticipants(activity.getCurrentParticipants()) .maxParticipants(activity.getMaxParticipants()) .personalities(activity.getPersonalities()) + .activityImgs(activityImgs) .build(); } } diff --git a/src/main/java/com/meetup/teame/backend/domain/activity/dto/response/ActivityPageRes.java b/src/main/java/com/meetup/teame/backend/domain/activity/dto/response/ActivityPageRes.java index 4634bc6..acc533b 100644 --- a/src/main/java/com/meetup/teame/backend/domain/activity/dto/response/ActivityPageRes.java +++ b/src/main/java/com/meetup/teame/backend/domain/activity/dto/response/ActivityPageRes.java @@ -2,5 +2,10 @@ import java.util.List; -public record ActivityPageRes(List activities, int totalPages, long totalElements) { +public record ActivityPageRes( + List activities, + int totalPages, + long totalElements) +{ + } diff --git a/src/main/java/com/meetup/teame/backend/domain/activity/dto/response/ActivitySummaryRes.java b/src/main/java/com/meetup/teame/backend/domain/activity/dto/response/ActivitySummaryRes.java index 204cde7..87cdae0 100644 --- a/src/main/java/com/meetup/teame/backend/domain/activity/dto/response/ActivitySummaryRes.java +++ b/src/main/java/com/meetup/teame/backend/domain/activity/dto/response/ActivitySummaryRes.java @@ -10,6 +10,7 @@ import org.hibernate.annotations.Comment; import java.time.LocalDateTime; +import java.util.List; @NoArgsConstructor @AllArgsConstructor @@ -27,15 +28,25 @@ public class ActivitySummaryRes { private LocalDateTime time; + private String activityThumbnail; + //나중에 어떤 유저가 좋아요를 눌렀는지 안눌렀는지 체크하는거 해야함 private boolean isLiked; public static ActivitySummaryRes of(Activity activity) { + List activityImgs = activity.getActivityImgs(); + //String activityThumbnail = null; + String activityThumbnail = activityImgs.get(0); + /*if (!activityImgs.isEmpty()) { + activityThumbnail = activityImgs.get(0); + }*/ + return ActivitySummaryRes.builder() .id(activity.getId()) .title(activity.getTitle()) .agency(activity.getAgency()) .time(activity.getTime()) + .activityThumbnail(activityThumbnail) .build(); } } diff --git a/src/main/java/com/meetup/teame/backend/domain/activity/entity/Activity.java b/src/main/java/com/meetup/teame/backend/domain/activity/entity/Activity.java index 7af7d92..05010ff 100644 --- a/src/main/java/com/meetup/teame/backend/domain/activity/entity/Activity.java +++ b/src/main/java/com/meetup/teame/backend/domain/activity/entity/Activity.java @@ -38,6 +38,10 @@ public class Activity { @Comment("최대 참여 인원") private Long maxParticipants; + @ElementCollection + @Comment("활동 사진들") + private List activityImgs; + @ElementCollection @Enumerated(EnumType.STRING) private List personalities; diff --git a/src/main/java/com/meetup/teame/backend/domain/activity/service/ActivityService.java b/src/main/java/com/meetup/teame/backend/domain/activity/service/ActivityService.java index 1adaba3..1929bf1 100644 --- a/src/main/java/com/meetup/teame/backend/domain/activity/service/ActivityService.java +++ b/src/main/java/com/meetup/teame/backend/domain/activity/service/ActivityService.java @@ -1,5 +1,7 @@ package com.meetup.teame.backend.domain.activity.service; +import com.amazonaws.services.s3.AmazonS3; +import com.amazonaws.services.s3.model.GeneratePresignedUrlRequest; import com.meetup.teame.backend.domain.activity.dto.response.ActivityDetailsRes; import com.meetup.teame.backend.domain.activity.dto.response.ActivityPageRes; import com.meetup.teame.backend.domain.activity.dto.response.ActivitySummaryRes; @@ -8,12 +10,16 @@ import com.meetup.teame.backend.global.exception.CustomException; import com.meetup.teame.backend.global.exception.ExceptionContent; import lombok.RequiredArgsConstructor; +import org.springframework.beans.factory.annotation.Value; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Pageable; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import java.net.URL; +import java.util.ArrayList; +import java.util.Date; import java.util.List; import java.util.stream.Collectors; @@ -22,6 +28,9 @@ @Service public class ActivityService { + @Value("${cloud.aws.s3.bucket}") + private String bucket; + private final AmazonS3 amazonS3; private final ActivityRepository activityRepository; //활동 참여 신청하기 @@ -30,7 +39,8 @@ public class ActivityService { //특정 활동 상제 정보 response dto화 public ActivityDetailsRes getActivityDetails(Long activityId) { Activity activity = findActivityById(activityId); - return ActivityDetailsRes.of(activity); + List imgs = getImageUrls(activity); + return ActivityDetailsRes.of(activity, imgs); } //전체 활동 불러오기 dto화 @@ -53,4 +63,33 @@ private Activity findActivityById(Long activityId) { private List findAllActivities() { return activityRepository.findAll(); } + + //활동 생성하기 + + + /*private String getUrl(Activity activity) { + URL url = amazonS3.getUrl(bucket, activity.getActivityImgs()); + return "" + url; + }*/ + public List getImageUrls(Activity activity) { + List activityImgs = activity.getActivityImgs(); + List imageUrls = new ArrayList<>(); + + // 각 이미지에 대해 URL을 생성합니다. + for (String imgKey : activityImgs) { + // 이미지의 URL을 생성하기 위해 S3에 대한 요청을 생성합니다. + GeneratePresignedUrlRequest urlRequest = new GeneratePresignedUrlRequest(bucket, imgKey); + /*// 이미지가 다운로드되는 시간(5분)을 설정합니다. + urlRequest.setExpiration(new Date(System.currentTimeMillis() + 1000 * 60 * 5));*/ + + // 이미지 URL을 생성합니다. + URL url = amazonS3.generatePresignedUrl(urlRequest); + + // 생성된 이미지 URL을 리스트에 추가합니다. + imageUrls.add(url.toString()); + } + + // 생성된 이미지 URL 리스트를 반환합니다. + return imageUrls; + } } diff --git a/src/main/java/com/meetup/teame/backend/global/config/S3Config.java b/src/main/java/com/meetup/teame/backend/global/config/S3Config.java index fa9b553..47ffba1 100644 --- a/src/main/java/com/meetup/teame/backend/global/config/S3Config.java +++ b/src/main/java/com/meetup/teame/backend/global/config/S3Config.java @@ -1,8 +1,9 @@ package com.meetup.teame.backend.global.config; +import com.amazonaws.auth.AWSCredentials; import com.amazonaws.auth.AWSStaticCredentialsProvider; import com.amazonaws.auth.BasicAWSCredentials; -import com.amazonaws.services.s3.AmazonS3Client; +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; @@ -21,10 +22,10 @@ public class S3Config { private String region; @Bean - public AmazonS3Client amazonS3Client() { - BasicAWSCredentials credentials = new BasicAWSCredentials(accessKey, secretKey); + public AmazonS3 amazonS3() { + AWSCredentials credentials = new BasicAWSCredentials(accessKey, secretKey); - return (AmazonS3Client) AmazonS3ClientBuilder + return (AmazonS3) AmazonS3ClientBuilder .standard() .withRegion(region) .withCredentials(new AWSStaticCredentialsProvider(credentials)) From ef93185bfe9828bddbaa61c397841d72a4aece6a Mon Sep 17 00:00:00 2001 From: Jeongho Date: Tue, 14 May 2024 00:56:37 +0900 Subject: [PATCH 07/16] =?UTF-8?q?Feat:=20User=20=EC=A0=95=EB=B3=B4=20?= =?UTF-8?q?=EC=A1=B0=ED=9A=8C=20=EB=B0=8F=20=EC=88=98=EC=A0=95=20api?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dto/request/ReadActivitiesReq.java | 24 ++++++++++++++ .../dto/response/ReadActivitiesRes.java | 30 +++++++++++++++++ .../custom/ActivityRepositoryCustom.java | 3 ++ .../custom/ActivityRepositoryImpl.java | 11 +++++++ .../activity/service/ActivityService.java | 15 +++++---- .../user/controller/UserController.java | 20 +++++++++-- .../user/dto/request/UpdateUserReq.java | 21 ++++++++++++ .../domain/user/dto/response/UserInfoRes.java | 33 +++++++++++++++++++ .../backend/domain/user/entity/User.java | 9 +++++ .../domain/user/service/UserService.java | 18 ++++++++-- 10 files changed, 174 insertions(+), 10 deletions(-) create mode 100644 src/main/java/com/meetup/teame/backend/domain/activity/dto/request/ReadActivitiesReq.java create mode 100644 src/main/java/com/meetup/teame/backend/domain/activity/dto/response/ReadActivitiesRes.java create mode 100644 src/main/java/com/meetup/teame/backend/domain/user/dto/request/UpdateUserReq.java create mode 100644 src/main/java/com/meetup/teame/backend/domain/user/dto/response/UserInfoRes.java diff --git a/src/main/java/com/meetup/teame/backend/domain/activity/dto/request/ReadActivitiesReq.java b/src/main/java/com/meetup/teame/backend/domain/activity/dto/request/ReadActivitiesReq.java new file mode 100644 index 0000000..c7717d5 --- /dev/null +++ b/src/main/java/com/meetup/teame/backend/domain/activity/dto/request/ReadActivitiesReq.java @@ -0,0 +1,24 @@ +package com.meetup.teame.backend.domain.activity.dto.request; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.Min; +import jakarta.validation.constraints.NotBlank; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; + +import java.util.List; + +@NoArgsConstructor +@AllArgsConstructor +@Getter +public class ReadActivitiesReq { + + private Long page; + + private String agency; + + private List personalities; + + private String category; +} diff --git a/src/main/java/com/meetup/teame/backend/domain/activity/dto/response/ReadActivitiesRes.java b/src/main/java/com/meetup/teame/backend/domain/activity/dto/response/ReadActivitiesRes.java new file mode 100644 index 0000000..a3b4139 --- /dev/null +++ b/src/main/java/com/meetup/teame/backend/domain/activity/dto/response/ReadActivitiesRes.java @@ -0,0 +1,30 @@ +package com.meetup.teame.backend.domain.activity.dto.response; + +import com.meetup.teame.backend.domain.activity.entity.Activity; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; + +import java.util.List; +import java.util.stream.Collectors; + +@NoArgsConstructor +@AllArgsConstructor +@Getter +@Builder +public class ReadActivitiesRes { + private Long curPage; + private Long pageCount; + private List activitySummaries; + + public static ReadActivitiesRes of(Long curPage, Long pageCount, List activities) { + return ReadActivitiesRes.builder() + .curPage(curPage) + .pageCount(pageCount) + .activitySummaries(activities.stream() + .map(ActivitySummaryRes::of) + .toList()) + .build(); + } +} diff --git a/src/main/java/com/meetup/teame/backend/domain/activity/repository/custom/ActivityRepositoryCustom.java b/src/main/java/com/meetup/teame/backend/domain/activity/repository/custom/ActivityRepositoryCustom.java index cb3a292..dd62e79 100644 --- a/src/main/java/com/meetup/teame/backend/domain/activity/repository/custom/ActivityRepositoryCustom.java +++ b/src/main/java/com/meetup/teame/backend/domain/activity/repository/custom/ActivityRepositoryCustom.java @@ -1,10 +1,13 @@ package com.meetup.teame.backend.domain.activity.repository.custom; import com.meetup.teame.backend.domain.activity.entity.Activity; +import com.meetup.teame.backend.domain.personality.Personality; import com.meetup.teame.backend.domain.user.entity.User; import java.util.List; public interface ActivityRepositoryCustom { List findActivitiesForUser(User user); + + List findByAgencyAndPersonality(String agency, Personality personality); } diff --git a/src/main/java/com/meetup/teame/backend/domain/activity/repository/custom/ActivityRepositoryImpl.java b/src/main/java/com/meetup/teame/backend/domain/activity/repository/custom/ActivityRepositoryImpl.java index 9b0ff06..065bd42 100644 --- a/src/main/java/com/meetup/teame/backend/domain/activity/repository/custom/ActivityRepositoryImpl.java +++ b/src/main/java/com/meetup/teame/backend/domain/activity/repository/custom/ActivityRepositoryImpl.java @@ -2,6 +2,7 @@ import com.meetup.teame.backend.domain.activity.entity.Activity; import com.meetup.teame.backend.domain.activity.entity.QActivity; +import com.meetup.teame.backend.domain.personality.Personality; import com.meetup.teame.backend.domain.user.entity.User; import com.querydsl.jpa.impl.JPAQueryFactory; import lombok.RequiredArgsConstructor; @@ -22,4 +23,14 @@ public List findActivitiesForUser(User user) { .where(activity.personalities.any().in(user.getPersonalities())) .fetch(); } + + @Override + public List findByAgencyAndPersonality(String agency, Personality personality) { + QActivity activity = QActivity.activity; + return jpaQueryFactory + .selectFrom(activity) + .where(activity.agency.eq(agency) + .and(activity.personalities.contains(personality))) + .fetch(); + } } diff --git a/src/main/java/com/meetup/teame/backend/domain/activity/service/ActivityService.java b/src/main/java/com/meetup/teame/backend/domain/activity/service/ActivityService.java index 1929bf1..f517619 100644 --- a/src/main/java/com/meetup/teame/backend/domain/activity/service/ActivityService.java +++ b/src/main/java/com/meetup/teame/backend/domain/activity/service/ActivityService.java @@ -7,6 +7,7 @@ import com.meetup.teame.backend.domain.activity.dto.response.ActivitySummaryRes; import com.meetup.teame.backend.domain.activity.entity.Activity; import com.meetup.teame.backend.domain.activity.repository.ActivityRepository; +import com.meetup.teame.backend.domain.personality.Personality; import com.meetup.teame.backend.global.exception.CustomException; import com.meetup.teame.backend.global.exception.ExceptionContent; import lombok.RequiredArgsConstructor; @@ -33,6 +34,8 @@ public class ActivityService { private final AmazonS3 amazonS3; private final ActivityRepository activityRepository; + private static final int ACTIVITY_PAGE_SIZE = 12; + //활동 참여 신청하기 @@ -59,13 +62,16 @@ private Activity findActivityById(Long activityId) { .orElseThrow(() -> new CustomException(ExceptionContent.NOT_FOUND_ACTIVITY)); } + //활동 목록 필터링으로 조회 + private List findActivitiesByAgencyAndPersonality(String agency, Personality personality) { + return activityRepository.findByAgencyAndPersonality(agency, personality); + } + //전체 활동 불러오기 private List findAllActivities() { return activityRepository.findAll(); } - //활동 생성하기 - /*private String getUrl(Activity activity) { URL url = amazonS3.getUrl(bucket, activity.getActivityImgs()); @@ -75,17 +81,14 @@ public List getImageUrls(Activity activity) { List activityImgs = activity.getActivityImgs(); List imageUrls = new ArrayList<>(); - // 각 이미지에 대해 URL을 생성합니다. for (String imgKey : activityImgs) { - // 이미지의 URL을 생성하기 위해 S3에 대한 요청을 생성합니다. + // 이미지의 URL을 생성하기 위해 S3에 대한 요청을 생성 GeneratePresignedUrlRequest urlRequest = new GeneratePresignedUrlRequest(bucket, imgKey); /*// 이미지가 다운로드되는 시간(5분)을 설정합니다. urlRequest.setExpiration(new Date(System.currentTimeMillis() + 1000 * 60 * 5));*/ - // 이미지 URL을 생성합니다. URL url = amazonS3.generatePresignedUrl(urlRequest); - // 생성된 이미지 URL을 리스트에 추가합니다. imageUrls.add(url.toString()); } diff --git a/src/main/java/com/meetup/teame/backend/domain/user/controller/UserController.java b/src/main/java/com/meetup/teame/backend/domain/user/controller/UserController.java index 1456623..374cb84 100644 --- a/src/main/java/com/meetup/teame/backend/domain/user/controller/UserController.java +++ b/src/main/java/com/meetup/teame/backend/domain/user/controller/UserController.java @@ -1,7 +1,9 @@ package com.meetup.teame.backend.domain.user.controller; import com.meetup.teame.backend.domain.user.dto.request.OnboardingReq; +import com.meetup.teame.backend.domain.user.dto.request.UpdateUserReq; import com.meetup.teame.backend.domain.user.dto.response.ReadMainRes; +import com.meetup.teame.backend.domain.user.dto.response.UserInfoRes; import com.meetup.teame.backend.domain.user.service.UserService; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; @@ -36,15 +38,29 @@ public ResponseEntity readMainPage() { 아직 로그인이 없어서 임시로 고정된 더미 유저의 온보딩 정보를 등록하는 식으로 구현되어 있습니다. 추후 로그인 적용 시에는 jwt토큰도 같이 전달해서 요청해주셔야 합니다. - + 현재 온보딩 정보로 입력 가능한 성격 유형 ("잔잔한", "활발한", "평화로운", "자연친화적인", "창의적인", "학문적인", "예술적인", "배울 수 있는") 위 유형들 중 최소 1개 이상을 선택해서 Request Body에 담아 전송해주세요. """) @PatchMapping("/onboarding") - public ResponseEntity setUserPersonality(@RequestBody @Valid OnboardingReq onboardingReq){ + public ResponseEntity setUserPersonality(@RequestBody @Valid OnboardingReq onboardingReq) { userService.setUserPersonality(onboardingReq); return ResponseEntity .ok().build(); } + + //기본 정보 조회 + @GetMapping("/{userId}/info") + public ResponseEntity getUserInfo(@PathVariable long userId) { + UserInfoRes userInfo = userService.getUserInfo(userId); + return ResponseEntity.ok().body(userInfo); + } + + //기본 정보 수정 + @PutMapping("/{userId}/info") + public ResponseEntity updateUserInfo(@PathVariable long userId, @RequestBody UpdateUserReq request) { + UserInfoRes userInfo = userService.updateUserInfo(userId, request); + return ResponseEntity.ok().body(userInfo); + } } diff --git a/src/main/java/com/meetup/teame/backend/domain/user/dto/request/UpdateUserReq.java b/src/main/java/com/meetup/teame/backend/domain/user/dto/request/UpdateUserReq.java new file mode 100644 index 0000000..bf28336 --- /dev/null +++ b/src/main/java/com/meetup/teame/backend/domain/user/dto/request/UpdateUserReq.java @@ -0,0 +1,21 @@ +package com.meetup.teame.backend.domain.user.dto.request; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@NoArgsConstructor +@AllArgsConstructor +@Getter +public class UpdateUserReq { + + private String name; + + private String email; + + private String password; + + private String imageUrl; + + private String location; +} diff --git a/src/main/java/com/meetup/teame/backend/domain/user/dto/response/UserInfoRes.java b/src/main/java/com/meetup/teame/backend/domain/user/dto/response/UserInfoRes.java new file mode 100644 index 0000000..bdd6081 --- /dev/null +++ b/src/main/java/com/meetup/teame/backend/domain/user/dto/response/UserInfoRes.java @@ -0,0 +1,33 @@ +package com.meetup.teame.backend.domain.user.dto.response; + +import com.meetup.teame.backend.domain.user.entity.User; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@NoArgsConstructor +@AllArgsConstructor +@Getter +@Builder +public class UserInfoRes { + + private String name; + + private String email; + + private String password; + + private String imageUrl; + + private String location; + + public static UserInfoRes of(User user) { + return UserInfoRes.builder() + .name(user.getName()) + .email(user.getEmail()) + .imageUrl(user.getImageUrl()) + .location(user.getLocation()) + .build(); + } +} diff --git a/src/main/java/com/meetup/teame/backend/domain/user/entity/User.java b/src/main/java/com/meetup/teame/backend/domain/user/entity/User.java index e9d1d61..f706070 100644 --- a/src/main/java/com/meetup/teame/backend/domain/user/entity/User.java +++ b/src/main/java/com/meetup/teame/backend/domain/user/entity/User.java @@ -4,6 +4,7 @@ import com.meetup.teame.backend.domain.personality.Personality; import com.meetup.teame.backend.domain.experience.entity.Experience; import com.meetup.teame.backend.domain.like.entity.ActivityLike; +import com.meetup.teame.backend.domain.user.dto.request.UpdateUserReq; import jakarta.persistence.*; import lombok.*; import org.hibernate.annotations.Comment; @@ -63,4 +64,12 @@ public class User { public void setPersonalities(List personalities) { this.personalities = personalities; } + + public void update(UpdateUserReq request) { + this.name = request.getName(); + this.email = request.getEmail(); + this.password = request.getPassword(); + this.imageUrl = request.getImageUrl(); + this.location = request.getLocation(); + } } diff --git a/src/main/java/com/meetup/teame/backend/domain/user/service/UserService.java b/src/main/java/com/meetup/teame/backend/domain/user/service/UserService.java index 83279bf..b14d9ba 100644 --- a/src/main/java/com/meetup/teame/backend/domain/user/service/UserService.java +++ b/src/main/java/com/meetup/teame/backend/domain/user/service/UserService.java @@ -5,14 +5,15 @@ import com.meetup.teame.backend.domain.experience.repository.ExperienceRepository; import com.meetup.teame.backend.domain.personality.Personality; import com.meetup.teame.backend.domain.user.dto.request.OnboardingReq; +import com.meetup.teame.backend.domain.user.dto.request.UpdateUserReq; import com.meetup.teame.backend.domain.user.dto.response.ReadMainRes; +import com.meetup.teame.backend.domain.user.dto.response.UserInfoRes; import com.meetup.teame.backend.domain.user.entity.Gender; import com.meetup.teame.backend.domain.user.entity.User; import com.meetup.teame.backend.domain.user.repository.UserRepository; import com.meetup.teame.backend.global.exception.CustomException; import com.meetup.teame.backend.global.exception.ExceptionContent; import lombok.RequiredArgsConstructor; -import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -55,9 +56,15 @@ public User createUser(CreateUserRequest request) { .build(); } + //user info dto화 + public UserInfoRes getUserInfo(Long userId) { + User user = findById(userId); + return UserInfoRes.of(user); + } + public User findById(Long userId) { return userRepository.findById(userId) - .orElseThrow(() -> new IllegalArgumentException("Unexpected user")); + .orElseThrow(() -> new CustomException(ExceptionContent.NOT_FOUND_USER)); } @Transactional @@ -66,6 +73,13 @@ public Long save(User user) { return savedUser.getId(); } + @Transactional + public UserInfoRes updateUserInfo(Long userId, UpdateUserReq request) { + User updatedUser = findById(userId); + updatedUser.update(request); + return UserInfoRes.of(updatedUser); + } + @Transactional public void setUserPersonality(OnboardingReq onboardingReq) { //todo 현재는 더미 유저지만 추후에는 SecurityContextHolder 정보를 조회해서 유저 정보를 가져와야 함 From 621ecd9b71f0a835d2bcc0df17dfa6541b7524ab Mon Sep 17 00:00:00 2001 From: Jeongho Date: Tue, 14 May 2024 17:51:12 +0900 Subject: [PATCH 08/16] =?UTF-8?q?Feat:=20=ED=99=9C=EB=8F=99=20=EB=AA=A9?= =?UTF-8?q?=EB=A1=9D=20=ED=95=84=ED=84=B0=EB=A7=81=EC=9C=BC=EB=A1=9C=20?= =?UTF-8?q?=EC=A1=B0=ED=9A=8C=ED=95=98=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/ActivityController.java | 40 ++++++++-- .../dto/request/ReadActivitiesReq.java | 4 +- .../dto/response/ActivityDetailsRes.java | 3 + .../dto/response/ActivitySummaryRes.java | 11 ++- .../domain/activity/entity/Activity.java | 5 ++ .../domain/activity/entity/AgencyType.java | 30 +++++++ .../custom/ActivityRepositoryCustom.java | 7 +- .../custom/ActivityRepositoryImpl.java | 80 +++++++++++++++++-- .../activity/service/ActivityService.java | 48 +++++++++-- .../domain/personality/Personality.java | 13 +-- .../domain/user/service/UserService.java | 2 +- .../global/exception/ExceptionContent.java | 1 + 12 files changed, 212 insertions(+), 32 deletions(-) create mode 100644 src/main/java/com/meetup/teame/backend/domain/activity/entity/AgencyType.java diff --git a/src/main/java/com/meetup/teame/backend/domain/activity/controller/ActivityController.java b/src/main/java/com/meetup/teame/backend/domain/activity/controller/ActivityController.java index e8570fd..fc5db80 100644 --- a/src/main/java/com/meetup/teame/backend/domain/activity/controller/ActivityController.java +++ b/src/main/java/com/meetup/teame/backend/domain/activity/controller/ActivityController.java @@ -1,10 +1,12 @@ package com.meetup.teame.backend.domain.activity.controller; +import com.meetup.teame.backend.domain.activity.dto.request.ReadActivitiesReq; import com.meetup.teame.backend.domain.activity.dto.response.ActivityDetailsRes; -import com.meetup.teame.backend.domain.activity.dto.response.ActivityPageRes; +import com.meetup.teame.backend.domain.activity.dto.response.ReadActivitiesRes; import com.meetup.teame.backend.domain.activity.service.ActivityService; 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.http.ResponseEntity; import org.springframework.web.bind.annotation.*; @@ -17,6 +19,7 @@ public class ActivityController { private final ActivityService activityService; @Operation(summary = "활동 상세 정보 조회", description = """ + 활동 id로 활동의 상세 정보를 조회합니다. """) @@ -32,15 +35,38 @@ public ResponseEntity getActivityDetails(@PathVariable Long 전체 활동들을 페이지 단위로 불러옵니다. - page = 0, size = 12 로 default 값이 설정되어있어 0번 페이지에 12개의 활동들을 불러옵니다. + page : 조회할 페이지 (0페이지 부터 시작) + + agencyType : 활동 기관 유형 (우선 기관 하나만 입력하는 것으로 만들었습니다.) + + personalities : 활동 성격 유형 (복수 선택 가능합니다, String List로 보내주시면 됩니다.) """) //전체 활동 불러오기 @GetMapping("/activities") - public ResponseEntity getActivitySummaries(@RequestParam(defaultValue = "0") int page, - @RequestParam(defaultValue = "12") int size) - { - ActivityPageRes activityPage = activityService.getActivitySummaries(page, size); - return ResponseEntity.ok().body(activityPage); + public ResponseEntity getActivities(@ModelAttribute @Valid ReadActivitiesReq request) { + ReadActivitiesRes activities = activityService.findActivities(request); + return ResponseEntity.ok().body(activities); } + @Operation(summary = "관심 활동 목록 조회", description = """ + 관심 활동들을 조회하는 api입니다. + + userId를 api 주소에 넣어주세요. + + 관심 활동들을 페이지 단위로 불러옵니다. + + page : 조회할 페이지 (0페이지 부터 시작) + + agencyType : 활동 기관 유형 (우선 기관 하나만 입력하는 것으로 만들었습니다.) + + personalities : 활동 성격 유형 (복수 선택 가능합니다, String List로 보내주시면 됩니다.) + + """) + //관심 활동 불러오기 + @GetMapping("/activities/liked/{userId}") + public ResponseEntity getLikedActivities(@PathVariable long userId, + @ModelAttribute @Valid ReadActivitiesReq request) { + ReadActivitiesRes activities = activityService.findlikedActivities(userId, request); + return ResponseEntity.ok().body(activities); + } } diff --git a/src/main/java/com/meetup/teame/backend/domain/activity/dto/request/ReadActivitiesReq.java b/src/main/java/com/meetup/teame/backend/domain/activity/dto/request/ReadActivitiesReq.java index c7717d5..55c8e6b 100644 --- a/src/main/java/com/meetup/teame/backend/domain/activity/dto/request/ReadActivitiesReq.java +++ b/src/main/java/com/meetup/teame/backend/domain/activity/dto/request/ReadActivitiesReq.java @@ -16,9 +16,9 @@ public class ReadActivitiesReq { private Long page; - private String agency; + private String agencyType; private List personalities; - private String category; + private boolean isLiked; } diff --git a/src/main/java/com/meetup/teame/backend/domain/activity/dto/response/ActivityDetailsRes.java b/src/main/java/com/meetup/teame/backend/domain/activity/dto/response/ActivityDetailsRes.java index a356611..807f37c 100644 --- a/src/main/java/com/meetup/teame/backend/domain/activity/dto/response/ActivityDetailsRes.java +++ b/src/main/java/com/meetup/teame/backend/domain/activity/dto/response/ActivityDetailsRes.java @@ -23,6 +23,8 @@ public class ActivityDetailsRes { private String agency; + private String agencyType; + private String location; private LocalDateTime time; @@ -40,6 +42,7 @@ public static ActivityDetailsRes of(Activity activity, List activityImgs .id(activity.getId()) .title(activity.getTitle()) .agency(activity.getAgency()) + .agency(activity.getAgencyType().getDescription()) .location(activity.getLocation()) .time(activity.getTime()) .currentParticipants(activity.getCurrentParticipants()) diff --git a/src/main/java/com/meetup/teame/backend/domain/activity/dto/response/ActivitySummaryRes.java b/src/main/java/com/meetup/teame/backend/domain/activity/dto/response/ActivitySummaryRes.java index 87cdae0..6426d95 100644 --- a/src/main/java/com/meetup/teame/backend/domain/activity/dto/response/ActivitySummaryRes.java +++ b/src/main/java/com/meetup/teame/backend/domain/activity/dto/response/ActivitySummaryRes.java @@ -24,6 +24,8 @@ public class ActivitySummaryRes { private String agency; + private String agencyType; + private String location; private LocalDateTime time; @@ -35,16 +37,17 @@ public class ActivitySummaryRes { public static ActivitySummaryRes of(Activity activity) { List activityImgs = activity.getActivityImgs(); - //String activityThumbnail = null; - String activityThumbnail = activityImgs.get(0); - /*if (!activityImgs.isEmpty()) { + String activityThumbnail = null; + //String activityThumbnail = activityImgs.get(0); + if (!activityImgs.isEmpty()) { activityThumbnail = activityImgs.get(0); - }*/ + } return ActivitySummaryRes.builder() .id(activity.getId()) .title(activity.getTitle()) .agency(activity.getAgency()) + .agencyType(activity.getAgencyType().getDescription()) .time(activity.getTime()) .activityThumbnail(activityThumbnail) .build(); diff --git a/src/main/java/com/meetup/teame/backend/domain/activity/entity/Activity.java b/src/main/java/com/meetup/teame/backend/domain/activity/entity/Activity.java index 05010ff..af62c1c 100644 --- a/src/main/java/com/meetup/teame/backend/domain/activity/entity/Activity.java +++ b/src/main/java/com/meetup/teame/backend/domain/activity/entity/Activity.java @@ -1,5 +1,6 @@ package com.meetup.teame.backend.domain.activity.entity; +import com.meetup.teame.backend.domain.experience.entity.ExperienceType; import com.meetup.teame.backend.domain.like.entity.ActivityLike; import com.meetup.teame.backend.domain.personality.Personality; import jakarta.persistence.*; @@ -26,6 +27,10 @@ public class Activity { @Comment("활동 제공 기관") private String agency; + @Comment("기관 유형") + @Enumerated(EnumType.STRING) + private AgencyType agencyType; + @Comment("활동 장소") private String location; diff --git a/src/main/java/com/meetup/teame/backend/domain/activity/entity/AgencyType.java b/src/main/java/com/meetup/teame/backend/domain/activity/entity/AgencyType.java new file mode 100644 index 0000000..e493619 --- /dev/null +++ b/src/main/java/com/meetup/teame/backend/domain/activity/entity/AgencyType.java @@ -0,0 +1,30 @@ +package com.meetup.teame.backend.domain.activity.entity; + +import com.meetup.teame.backend.global.exception.CustomException; +import com.meetup.teame.backend.global.exception.ExceptionContent; +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +@RequiredArgsConstructor +@Getter +public enum AgencyType { + CULTURAL_CENTER("문화센터"), + WELFARE_CENTER("복지관"), + CLUB("동호회"), + VOLUNTEER_WORK("자원봉사"), + ONE_DAY_CLASS("원데이 클래스"), + ETC("기타") + ; + + private final String description; + + public static AgencyType of(String description) { + for (AgencyType agencyType : AgencyType.values()) { + if (agencyType.getDescription().equals(description)) { + return agencyType; + } + } + throw new CustomException(ExceptionContent.NOT_FOUND_AGENCY_TYPE); + } + +} diff --git a/src/main/java/com/meetup/teame/backend/domain/activity/repository/custom/ActivityRepositoryCustom.java b/src/main/java/com/meetup/teame/backend/domain/activity/repository/custom/ActivityRepositoryCustom.java index dd62e79..dcfad6f 100644 --- a/src/main/java/com/meetup/teame/backend/domain/activity/repository/custom/ActivityRepositoryCustom.java +++ b/src/main/java/com/meetup/teame/backend/domain/activity/repository/custom/ActivityRepositoryCustom.java @@ -1,6 +1,7 @@ package com.meetup.teame.backend.domain.activity.repository.custom; import com.meetup.teame.backend.domain.activity.entity.Activity; +import com.meetup.teame.backend.domain.activity.entity.AgencyType; import com.meetup.teame.backend.domain.personality.Personality; import com.meetup.teame.backend.domain.user.entity.User; @@ -9,5 +10,9 @@ public interface ActivityRepositoryCustom { List findActivitiesForUser(User user); - List findByAgencyAndPersonality(String agency, Personality personality); + List findByAgencyAndPersonalities(long offset, long limit, AgencyType agencyType, List personalities); + + List findByUserLikesAndAgencyAndPersonalities(Long userId, long offset, long limit, AgencyType agencyType, List personalities); + + Long countActivities(AgencyType agencyType, List personalities); } diff --git a/src/main/java/com/meetup/teame/backend/domain/activity/repository/custom/ActivityRepositoryImpl.java b/src/main/java/com/meetup/teame/backend/domain/activity/repository/custom/ActivityRepositoryImpl.java index 065bd42..d480a90 100644 --- a/src/main/java/com/meetup/teame/backend/domain/activity/repository/custom/ActivityRepositoryImpl.java +++ b/src/main/java/com/meetup/teame/backend/domain/activity/repository/custom/ActivityRepositoryImpl.java @@ -1,15 +1,17 @@ package com.meetup.teame.backend.domain.activity.repository.custom; import com.meetup.teame.backend.domain.activity.entity.Activity; -import com.meetup.teame.backend.domain.activity.entity.QActivity; +import com.meetup.teame.backend.domain.activity.entity.AgencyType; import com.meetup.teame.backend.domain.personality.Personality; import com.meetup.teame.backend.domain.user.entity.User; +import com.querydsl.core.BooleanBuilder; import com.querydsl.jpa.impl.JPAQueryFactory; import lombok.RequiredArgsConstructor; import java.util.List; import static com.meetup.teame.backend.domain.activity.entity.QActivity.activity; +import static com.meetup.teame.backend.domain.like.entity.QActivityLike.activityLike; @RequiredArgsConstructor public class ActivityRepositoryImpl implements ActivityRepositoryCustom { @@ -25,12 +27,80 @@ public List findActivitiesForUser(User user) { } @Override - public List findByAgencyAndPersonality(String agency, Personality personality) { - QActivity activity = QActivity.activity; + public List findByAgencyAndPersonalities(long offset, long limit, AgencyType agencyType, List personalities) { + BooleanBuilder builder = new BooleanBuilder(); + + // agencyType나 personalities가 입력된 경우 해당 값으로 필터링 + if (agencyType != null || (personalities != null && !personalities.isEmpty())) { + if (agencyType != null) { + builder.and(activity.agencyType.eq(agencyType)); + } + if (personalities != null && !personalities.isEmpty()) { + builder.and(activity.personalities.any().in(personalities)); + } + } + return jpaQueryFactory .selectFrom(activity) - .where(activity.agency.eq(agency) - .and(activity.personalities.contains(personality))) + .where(builder) + .orderBy(activity.id.desc()) + .offset(offset) + .limit(limit) .fetch(); } + + @Override + public List findByUserLikesAndAgencyAndPersonalities(Long userId, long offset, long limit, AgencyType agencyType, List personalities) { + BooleanBuilder builder = new BooleanBuilder(); + + // 사용자의 좋아하는 활동 ID 목록을 조회 + List likedActivityIds = jpaQueryFactory + .select(activityLike.activity.id) + .from(activityLike) + .where(activityLike.user.id.eq(userId)) + .fetch(); + + // 좋아하는 활동 ID가 있는 경우만 필터 조건에 추가 + if (!likedActivityIds.isEmpty()) { + builder.and(activity.id.in(likedActivityIds)); + } + + // agencyType나 personalities가 입력된 경우 해당 값으로 필터링 + if (agencyType != null) { + builder.and(activity.agencyType.eq(agencyType)); + } + if (personalities != null && !personalities.isEmpty()) { + builder.and(activity.personalities.any().in(personalities)); + } + + return jpaQueryFactory + .selectFrom(activity) + .where(builder) + .orderBy(activity.id.desc()) + .offset(offset) + .limit(limit) + .fetch(); + } + + + @Override + public Long countActivities(AgencyType agencyType, List personalities) { + BooleanBuilder builder = new BooleanBuilder(); + + // agencyType나 personalities가 입력된 경우 해당 값으로 필터링 + if (agencyType != null || (personalities != null && !personalities.isEmpty())) { + if (agencyType != null) { + builder.and(activity.agencyType.eq(agencyType)); + } + if (personalities != null && !personalities.isEmpty()) { + builder.and(activity.personalities.any().in(personalities)); + } + } + + return jpaQueryFactory + .select(activity.count()) + .from(activity) + .where(builder) + .fetchOne(); + } } diff --git a/src/main/java/com/meetup/teame/backend/domain/activity/service/ActivityService.java b/src/main/java/com/meetup/teame/backend/domain/activity/service/ActivityService.java index f517619..b4845d9 100644 --- a/src/main/java/com/meetup/teame/backend/domain/activity/service/ActivityService.java +++ b/src/main/java/com/meetup/teame/backend/domain/activity/service/ActivityService.java @@ -2,10 +2,13 @@ import com.amazonaws.services.s3.AmazonS3; import com.amazonaws.services.s3.model.GeneratePresignedUrlRequest; +import com.meetup.teame.backend.domain.activity.dto.request.ReadActivitiesReq; import com.meetup.teame.backend.domain.activity.dto.response.ActivityDetailsRes; import com.meetup.teame.backend.domain.activity.dto.response.ActivityPageRes; import com.meetup.teame.backend.domain.activity.dto.response.ActivitySummaryRes; +import com.meetup.teame.backend.domain.activity.dto.response.ReadActivitiesRes; import com.meetup.teame.backend.domain.activity.entity.Activity; +import com.meetup.teame.backend.domain.activity.entity.AgencyType; import com.meetup.teame.backend.domain.activity.repository.ActivityRepository; import com.meetup.teame.backend.domain.personality.Personality; import com.meetup.teame.backend.global.exception.CustomException; @@ -20,7 +23,6 @@ import java.net.URL; import java.util.ArrayList; -import java.util.Date; import java.util.List; import java.util.stream.Collectors; @@ -42,11 +44,11 @@ public class ActivityService { //특정 활동 상제 정보 response dto화 public ActivityDetailsRes getActivityDetails(Long activityId) { Activity activity = findActivityById(activityId); - List imgs = getImageUrls(activity); - return ActivityDetailsRes.of(activity, imgs); + List imageUrls = getImageUrls(activity); + return ActivityDetailsRes.of(activity, imageUrls); } - //전체 활동 불러오기 dto화 + //전체 활동 불러오기 dto화 => 삭제 예정 public ActivityPageRes getActivitySummaries(int page, int size) { Pageable pageable = PageRequest.of(page, size); Page activityPage = activityRepository.findAll(pageable); @@ -62,12 +64,44 @@ private Activity findActivityById(Long activityId) { .orElseThrow(() -> new CustomException(ExceptionContent.NOT_FOUND_ACTIVITY)); } + //관심활동 목록 필터링으로 조회 + public ReadActivitiesRes findlikedActivities(Long userId, ReadActivitiesReq activitiesReq) { + long page = activitiesReq.getPage(); + long offset = page * ACTIVITY_PAGE_SIZE; + long limit = ACTIVITY_PAGE_SIZE; + AgencyType agencyType = null; + if (activitiesReq.getAgencyType() != null) { + agencyType = AgencyType.of(activitiesReq.getAgencyType()); + } + List personalities = activitiesReq.getPersonalities().stream() + .map(Personality::of) + .collect(Collectors.toList()); + long totalCount = activityRepository.countActivities(agencyType, personalities); + long pageCount = (totalCount + ACTIVITY_PAGE_SIZE - 1) / ACTIVITY_PAGE_SIZE; // 전체 페이지 수 계산 + + return ReadActivitiesRes.of(page, pageCount, activityRepository.findByUserLikesAndAgencyAndPersonalities(userId, offset, limit, agencyType, personalities)); + } + //활동 목록 필터링으로 조회 - private List findActivitiesByAgencyAndPersonality(String agency, Personality personality) { - return activityRepository.findByAgencyAndPersonality(agency, personality); + public ReadActivitiesRes findActivities(ReadActivitiesReq activitiesReq) { + long page = activitiesReq.getPage(); + long offset = page * ACTIVITY_PAGE_SIZE; + long limit = ACTIVITY_PAGE_SIZE; + AgencyType agencyType = null; + if (activitiesReq.getAgencyType() != null) { + agencyType = AgencyType.of(activitiesReq.getAgencyType()); + } + List personalities = activitiesReq.getPersonalities().stream() + .map(Personality::of) + .collect(Collectors.toList()); + long totalCount = activityRepository.countActivities(agencyType, personalities); + long pageCount = (totalCount + ACTIVITY_PAGE_SIZE - 1) / ACTIVITY_PAGE_SIZE; // 전체 페이지 수 계산 + + // 조건에 맞는 활동 조회 + return ReadActivitiesRes.of(page, pageCount, activityRepository.findByAgencyAndPersonalities(offset, limit, agencyType, personalities)); } - //전체 활동 불러오기 + //전체 활동 불러오기 => 삭제 예정 private List findAllActivities() { return activityRepository.findAll(); } diff --git a/src/main/java/com/meetup/teame/backend/domain/personality/Personality.java b/src/main/java/com/meetup/teame/backend/domain/personality/Personality.java index 290f89a..1eea639 100644 --- a/src/main/java/com/meetup/teame/backend/domain/personality/Personality.java +++ b/src/main/java/com/meetup/teame/backend/domain/personality/Personality.java @@ -1,5 +1,6 @@ package com.meetup.teame.backend.domain.personality; +import com.meetup.teame.backend.domain.activity.entity.AgencyType; import com.meetup.teame.backend.global.exception.CustomException; import com.meetup.teame.backend.global.exception.ExceptionContent; import lombok.Getter; @@ -22,10 +23,12 @@ public enum Personality { private final String description; //todo ExperienceType 참고해서 of메서드로 수정 - public static Personality des2enum(String description) { - return Arrays.stream(Personality.values()) - .filter(personality -> personality.getDescription().equals(description)) - .findFirst() - .orElseThrow(() -> new CustomException(ExceptionContent.BAD_REQUEST_PERSONALITY)); + public static Personality of(String description) { + for (Personality personality : Personality.values()) { + if (personality.getDescription().equals(description)) { + return personality; + } + } + throw new CustomException(ExceptionContent.NOT_FOUND_PERSONALITY); } } diff --git a/src/main/java/com/meetup/teame/backend/domain/user/service/UserService.java b/src/main/java/com/meetup/teame/backend/domain/user/service/UserService.java index b14d9ba..6e450ee 100644 --- a/src/main/java/com/meetup/teame/backend/domain/user/service/UserService.java +++ b/src/main/java/com/meetup/teame/backend/domain/user/service/UserService.java @@ -86,7 +86,7 @@ public void setUserPersonality(OnboardingReq onboardingReq) { User user = userRepository.findById(5L) .orElseThrow(() -> new CustomException(ExceptionContent.NOT_FOUND_USER)); List personalities = onboardingReq.getPersonalities().stream() - .map(Personality::des2enum) + .map(Personality::of) .toList(); user.setPersonalities(personalities); } diff --git a/src/main/java/com/meetup/teame/backend/global/exception/ExceptionContent.java b/src/main/java/com/meetup/teame/backend/global/exception/ExceptionContent.java index 88ad4c0..87bb05e 100644 --- a/src/main/java/com/meetup/teame/backend/global/exception/ExceptionContent.java +++ b/src/main/java/com/meetup/teame/backend/global/exception/ExceptionContent.java @@ -25,6 +25,7 @@ public enum ExceptionContent { NOT_FOUND_PERSONALITY(NOT_FOUND, "존재하지 않는 성격입니다."), NOT_FOUND_EXPERIENCE_TYPE(NOT_FOUND, "존재하지 않는 경험 유형입니다."), NOT_FOUND_ACTIVITY(NOT_FOUND, "존재하지 않는 활동입니다."), + NOT_FOUND_AGENCY_TYPE(NOT_FOUND, "존재하지 않는 기관 유형입니다."), ; private final HttpStatus httpStatus; From 01f31c9ecc14fc5849b7353587395aad5d8c1c0c Mon Sep 17 00:00:00 2001 From: Jeongho Date: Tue, 14 May 2024 18:42:07 +0900 Subject: [PATCH 09/16] =?UTF-8?q?Docs:=20swagger=20description=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/user/controller/UserController.java | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/main/java/com/meetup/teame/backend/domain/user/controller/UserController.java b/src/main/java/com/meetup/teame/backend/domain/user/controller/UserController.java index 374cb84..a5994e2 100644 --- a/src/main/java/com/meetup/teame/backend/domain/user/controller/UserController.java +++ b/src/main/java/com/meetup/teame/backend/domain/user/controller/UserController.java @@ -50,6 +50,12 @@ public ResponseEntity setUserPersonality(@RequestBody @Valid OnboardingReq .ok().build(); } + @Operation(summary = "사용자 기본 정보 조회", description = """ + + 사용자의 기본 정보를 볼 수 있는 api입니다. + + 추후 로그인 적용 시에는 jwt토큰도 같이 전달해서 요청해주셔야 합니다. + """) //기본 정보 조회 @GetMapping("/{userId}/info") public ResponseEntity getUserInfo(@PathVariable long userId) { @@ -57,6 +63,11 @@ public ResponseEntity getUserInfo(@PathVariable long userId) { return ResponseEntity.ok().body(userInfo); } + @Operation(summary = "사용자 기본 정보 수정", description = """ + 사용자의 기본 정보를 수정하는 api입니다. + + 추후 로그인 적용 시에는 jwt토큰도 같이 전달해서 요청해주셔야 합니다. + """) //기본 정보 수정 @PutMapping("/{userId}/info") public ResponseEntity updateUserInfo(@PathVariable long userId, @RequestBody UpdateUserReq request) { From a0b4e0ebd4ddfcce6f4b2eb4f08dc7d9e95b064b Mon Sep 17 00:00:00 2001 From: Jeongho Date: Wed, 15 May 2024 12:05:38 +0900 Subject: [PATCH 10/16] =?UTF-8?q?Fix:=20=ED=99=9C=EB=8F=99=20=EB=AA=A9?= =?UTF-8?q?=EB=A1=9D=20=EC=A1=B0=ED=9A=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/ActivityController.java | 9 +-- .../dto/response/ActivitySummaryRes.java | 15 +++-- .../dto/response/ReadActivitiesRes.java | 6 +- .../custom/ActivityRepositoryCustom.java | 2 +- .../custom/ActivityRepositoryImpl.java | 2 +- .../activity/service/ActivityService.java | 63 ++++++++++--------- .../oauth/controller/KakaoController.java | 2 +- .../repository/ActivityLikeRepository.java | 16 +++++ 8 files changed, 66 insertions(+), 49 deletions(-) create mode 100644 src/main/java/com/meetup/teame/backend/domain/like/repository/ActivityLikeRepository.java diff --git a/src/main/java/com/meetup/teame/backend/domain/activity/controller/ActivityController.java b/src/main/java/com/meetup/teame/backend/domain/activity/controller/ActivityController.java index fc5db80..6143077 100644 --- a/src/main/java/com/meetup/teame/backend/domain/activity/controller/ActivityController.java +++ b/src/main/java/com/meetup/teame/backend/domain/activity/controller/ActivityController.java @@ -42,9 +42,10 @@ public ResponseEntity getActivityDetails(@PathVariable Long personalities : 활동 성격 유형 (복수 선택 가능합니다, String List로 보내주시면 됩니다.) """) //전체 활동 불러오기 - @GetMapping("/activities") - public ResponseEntity getActivities(@ModelAttribute @Valid ReadActivitiesReq request) { - ReadActivitiesRes activities = activityService.findActivities(request); + @GetMapping("/activities/{userId}") + public ResponseEntity getActivities(@PathVariable long userId, + @ModelAttribute @Valid ReadActivitiesReq request) { + ReadActivitiesRes activities = activityService.findActivities(userId, request); return ResponseEntity.ok().body(activities); } @@ -63,7 +64,7 @@ public ResponseEntity getActivities(@ModelAttribute @Valid Re """) //관심 활동 불러오기 - @GetMapping("/activities/liked/{userId}") + @GetMapping("/activities/{userId}/liked") public ResponseEntity getLikedActivities(@PathVariable long userId, @ModelAttribute @Valid ReadActivitiesReq request) { ReadActivitiesRes activities = activityService.findlikedActivities(userId, request); diff --git a/src/main/java/com/meetup/teame/backend/domain/activity/dto/response/ActivitySummaryRes.java b/src/main/java/com/meetup/teame/backend/domain/activity/dto/response/ActivitySummaryRes.java index 6426d95..3a61c85 100644 --- a/src/main/java/com/meetup/teame/backend/domain/activity/dto/response/ActivitySummaryRes.java +++ b/src/main/java/com/meetup/teame/backend/domain/activity/dto/response/ActivitySummaryRes.java @@ -1,18 +1,16 @@ package com.meetup.teame.backend.domain.activity.dto.response; import com.meetup.teame.backend.domain.activity.entity.Activity; +import com.meetup.teame.backend.domain.like.repository.ActivityLikeRepository; import jakarta.persistence.GeneratedValue; import jakarta.persistence.GenerationType; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Getter; -import lombok.NoArgsConstructor; +import lombok.*; import org.hibernate.annotations.Comment; import java.time.LocalDateTime; import java.util.List; -@NoArgsConstructor +@RequiredArgsConstructor @AllArgsConstructor @Getter @Builder @@ -32,10 +30,10 @@ public class ActivitySummaryRes { private String activityThumbnail; - //나중에 어떤 유저가 좋아요를 눌렀는지 안눌렀는지 체크하는거 해야함 - private boolean isLiked; + private boolean isLiked = false; + + public static ActivitySummaryRes of(Activity activity, boolean isLiked) { - public static ActivitySummaryRes of(Activity activity) { List activityImgs = activity.getActivityImgs(); String activityThumbnail = null; //String activityThumbnail = activityImgs.get(0); @@ -50,6 +48,7 @@ public static ActivitySummaryRes of(Activity activity) { .agencyType(activity.getAgencyType().getDescription()) .time(activity.getTime()) .activityThumbnail(activityThumbnail) + .isLiked(isLiked) .build(); } } diff --git a/src/main/java/com/meetup/teame/backend/domain/activity/dto/response/ReadActivitiesRes.java b/src/main/java/com/meetup/teame/backend/domain/activity/dto/response/ReadActivitiesRes.java index a3b4139..264ab7f 100644 --- a/src/main/java/com/meetup/teame/backend/domain/activity/dto/response/ReadActivitiesRes.java +++ b/src/main/java/com/meetup/teame/backend/domain/activity/dto/response/ReadActivitiesRes.java @@ -18,13 +18,11 @@ public class ReadActivitiesRes { private Long pageCount; private List activitySummaries; - public static ReadActivitiesRes of(Long curPage, Long pageCount, List activities) { + public static ReadActivitiesRes of(Long curPage, Long pageCount, List activitySummaries) { return ReadActivitiesRes.builder() .curPage(curPage) .pageCount(pageCount) - .activitySummaries(activities.stream() - .map(ActivitySummaryRes::of) - .toList()) + .activitySummaries(activitySummaries) .build(); } } diff --git a/src/main/java/com/meetup/teame/backend/domain/activity/repository/custom/ActivityRepositoryCustom.java b/src/main/java/com/meetup/teame/backend/domain/activity/repository/custom/ActivityRepositoryCustom.java index dcfad6f..28b0555 100644 --- a/src/main/java/com/meetup/teame/backend/domain/activity/repository/custom/ActivityRepositoryCustom.java +++ b/src/main/java/com/meetup/teame/backend/domain/activity/repository/custom/ActivityRepositoryCustom.java @@ -12,7 +12,7 @@ public interface ActivityRepositoryCustom { List findByAgencyAndPersonalities(long offset, long limit, AgencyType agencyType, List personalities); - List findByUserLikesAndAgencyAndPersonalities(Long userId, long offset, long limit, AgencyType agencyType, List personalities); + List findLikedActivities(Long userId, long offset, long limit, AgencyType agencyType, List personalities); Long countActivities(AgencyType agencyType, List personalities); } diff --git a/src/main/java/com/meetup/teame/backend/domain/activity/repository/custom/ActivityRepositoryImpl.java b/src/main/java/com/meetup/teame/backend/domain/activity/repository/custom/ActivityRepositoryImpl.java index d480a90..fae10a2 100644 --- a/src/main/java/com/meetup/teame/backend/domain/activity/repository/custom/ActivityRepositoryImpl.java +++ b/src/main/java/com/meetup/teame/backend/domain/activity/repository/custom/ActivityRepositoryImpl.java @@ -50,7 +50,7 @@ public List findByAgencyAndPersonalities(long offset, long limit, Agen } @Override - public List findByUserLikesAndAgencyAndPersonalities(Long userId, long offset, long limit, AgencyType agencyType, List personalities) { + public List findLikedActivities(Long userId, long offset, long limit, AgencyType agencyType, List personalities) { BooleanBuilder builder = new BooleanBuilder(); // 사용자의 좋아하는 활동 ID 목록을 조회 diff --git a/src/main/java/com/meetup/teame/backend/domain/activity/service/ActivityService.java b/src/main/java/com/meetup/teame/backend/domain/activity/service/ActivityService.java index b4845d9..76b9413 100644 --- a/src/main/java/com/meetup/teame/backend/domain/activity/service/ActivityService.java +++ b/src/main/java/com/meetup/teame/backend/domain/activity/service/ActivityService.java @@ -4,26 +4,25 @@ import com.amazonaws.services.s3.model.GeneratePresignedUrlRequest; import com.meetup.teame.backend.domain.activity.dto.request.ReadActivitiesReq; import com.meetup.teame.backend.domain.activity.dto.response.ActivityDetailsRes; -import com.meetup.teame.backend.domain.activity.dto.response.ActivityPageRes; import com.meetup.teame.backend.domain.activity.dto.response.ActivitySummaryRes; import com.meetup.teame.backend.domain.activity.dto.response.ReadActivitiesRes; import com.meetup.teame.backend.domain.activity.entity.Activity; import com.meetup.teame.backend.domain.activity.entity.AgencyType; import com.meetup.teame.backend.domain.activity.repository.ActivityRepository; +import com.meetup.teame.backend.domain.like.repository.ActivityLikeRepository; import com.meetup.teame.backend.domain.personality.Personality; import com.meetup.teame.backend.global.exception.CustomException; import com.meetup.teame.backend.global.exception.ExceptionContent; import lombok.RequiredArgsConstructor; import org.springframework.beans.factory.annotation.Value; -import org.springframework.data.domain.Page; -import org.springframework.data.domain.PageRequest; -import org.springframework.data.domain.Pageable; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.net.URL; import java.util.ArrayList; +import java.util.HashSet; import java.util.List; +import java.util.Set; import java.util.stream.Collectors; @RequiredArgsConstructor @@ -35,6 +34,7 @@ public class ActivityService { private String bucket; private final AmazonS3 amazonS3; private final ActivityRepository activityRepository; + private final ActivityLikeRepository activityLikeRepository; private static final int ACTIVITY_PAGE_SIZE = 12; @@ -48,24 +48,14 @@ public ActivityDetailsRes getActivityDetails(Long activityId) { return ActivityDetailsRes.of(activity, imageUrls); } - //전체 활동 불러오기 dto화 => 삭제 예정 - public ActivityPageRes getActivitySummaries(int page, int size) { - Pageable pageable = PageRequest.of(page, size); - Page activityPage = activityRepository.findAll(pageable); - List activitySummaries = activityPage.getContent().stream() - .map(ActivitySummaryRes::of) - .collect(Collectors.toList()); - return new ActivityPageRes(activitySummaries, activityPage.getTotalPages(), activityPage.getTotalElements()); - } - //activityId로 특정 활동 불러오기 private Activity findActivityById(Long activityId) { return activityRepository.findById(activityId) .orElseThrow(() -> new CustomException(ExceptionContent.NOT_FOUND_ACTIVITY)); } - //관심활동 목록 필터링으로 조회 - public ReadActivitiesRes findlikedActivities(Long userId, ReadActivitiesReq activitiesReq) { + //활동 목록 필터링으로 조회 + public ReadActivitiesRes findActivities(Long userId, ReadActivitiesReq activitiesReq) { long page = activitiesReq.getPage(); long offset = page * ACTIVITY_PAGE_SIZE; long limit = ACTIVITY_PAGE_SIZE; @@ -76,14 +66,26 @@ public ReadActivitiesRes findlikedActivities(Long userId, ReadActivitiesReq acti List personalities = activitiesReq.getPersonalities().stream() .map(Personality::of) .collect(Collectors.toList()); - long totalCount = activityRepository.countActivities(agencyType, personalities); - long pageCount = (totalCount + ACTIVITY_PAGE_SIZE - 1) / ACTIVITY_PAGE_SIZE; // 전체 페이지 수 계산 + //long totalCount = activityRepository.countActivities(agencyType, personalities); + //long pageCount = (totalCount + ACTIVITY_PAGE_SIZE - 1) / ACTIVITY_PAGE_SIZE; // 전체 페이지 수 계산 + long pageCount = activityRepository.countActivities(agencyType, personalities) / ACTIVITY_PAGE_SIZE + 1; // 전체 페이지 수 계산 + + + List likedActivityIds = activityLikeRepository.findLikedActivityIdsByUserId(userId); + Set likedActivityIdsSet = new HashSet<>(likedActivityIds); + + List activities = activityRepository.findByAgencyAndPersonalities(offset, limit, agencyType, personalities); + List activitySummaries = activities.stream() + .map(activity -> ActivitySummaryRes.of(activity, likedActivityIdsSet.contains(activity.getId()))) + .toList(); - return ReadActivitiesRes.of(page, pageCount, activityRepository.findByUserLikesAndAgencyAndPersonalities(userId, offset, limit, agencyType, personalities)); + + // 조건에 맞는 활동 조회 + return ReadActivitiesRes.of(page, pageCount, activitySummaries); } - //활동 목록 필터링으로 조회 - public ReadActivitiesRes findActivities(ReadActivitiesReq activitiesReq) { + //관심활동 목록 필터링으로 조회 + public ReadActivitiesRes findlikedActivities(Long userId, ReadActivitiesReq activitiesReq) { long page = activitiesReq.getPage(); long offset = page * ACTIVITY_PAGE_SIZE; long limit = ACTIVITY_PAGE_SIZE; @@ -94,18 +96,19 @@ public ReadActivitiesRes findActivities(ReadActivitiesReq activitiesReq) { List personalities = activitiesReq.getPersonalities().stream() .map(Personality::of) .collect(Collectors.toList()); - long totalCount = activityRepository.countActivities(agencyType, personalities); - long pageCount = (totalCount + ACTIVITY_PAGE_SIZE - 1) / ACTIVITY_PAGE_SIZE; // 전체 페이지 수 계산 + //long totalCount = activityRepository.countActivities(agencyType, personalities); + long pageCount = activityRepository.countActivities(agencyType, personalities) / ACTIVITY_PAGE_SIZE + 1; // 전체 페이지 수 계산 - // 조건에 맞는 활동 조회 - return ReadActivitiesRes.of(page, pageCount, activityRepository.findByAgencyAndPersonalities(offset, limit, agencyType, personalities)); - } + List likedActivityIds = activityLikeRepository.findLikedActivityIdsByUserId(userId); + Set likedActivityIdsSet = new HashSet<>(likedActivityIds); - //전체 활동 불러오기 => 삭제 예정 - private List findAllActivities() { - return activityRepository.findAll(); - } + List activities = activityRepository.findLikedActivities(userId, offset, limit, agencyType, personalities); + List activitySummaries = activities.stream() + .map(activity -> ActivitySummaryRes.of(activity, likedActivityIdsSet.contains(activity.getId()))) + .toList(); + return ReadActivitiesRes.of(page, pageCount, activitySummaries); + } /*private String getUrl(Activity activity) { URL url = amazonS3.getUrl(bucket, activity.getActivityImgs()); diff --git a/src/main/java/com/meetup/teame/backend/domain/auth/oauth/controller/KakaoController.java b/src/main/java/com/meetup/teame/backend/domain/auth/oauth/controller/KakaoController.java index e693e4b..a3ef57c 100644 --- a/src/main/java/com/meetup/teame/backend/domain/auth/oauth/controller/KakaoController.java +++ b/src/main/java/com/meetup/teame/backend/domain/auth/oauth/controller/KakaoController.java @@ -44,7 +44,7 @@ public ResponseEntity kakaoLogin(@RequestParam String code) throws JsonP return ResponseEntity.ok().headers(headers).body("login"); //로그인 처리하기 } else { //신규 회원 - return ResponseEntity.ok(request); + return ResponseEntity.ok().body(request); } } diff --git a/src/main/java/com/meetup/teame/backend/domain/like/repository/ActivityLikeRepository.java b/src/main/java/com/meetup/teame/backend/domain/like/repository/ActivityLikeRepository.java new file mode 100644 index 0000000..0fd2350 --- /dev/null +++ b/src/main/java/com/meetup/teame/backend/domain/like/repository/ActivityLikeRepository.java @@ -0,0 +1,16 @@ +package com.meetup.teame.backend.domain.like.repository; + +import com.meetup.teame.backend.domain.like.entity.ActivityLike; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; + +import java.util.List; + +public interface ActivityLikeRepository extends JpaRepository { + + boolean existsByUserIdAndActivityId(Long userId, Long activityId); + + @Query("SELECT al.activity.id FROM ActivityLike al WHERE al.user.id = :userId") + List findLikedActivityIdsByUserId(Long userId); + +} From 9591aef18f0933d3720ba106b33da94e05af4c78 Mon Sep 17 00:00:00 2001 From: Jeongho Date: Wed, 15 May 2024 12:09:12 +0900 Subject: [PATCH 11/16] =?UTF-8?q?Fix:=20ReadActivitiesReq=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../backend/domain/activity/dto/request/ReadActivitiesReq.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/main/java/com/meetup/teame/backend/domain/activity/dto/request/ReadActivitiesReq.java b/src/main/java/com/meetup/teame/backend/domain/activity/dto/request/ReadActivitiesReq.java index 55c8e6b..b8de444 100644 --- a/src/main/java/com/meetup/teame/backend/domain/activity/dto/request/ReadActivitiesReq.java +++ b/src/main/java/com/meetup/teame/backend/domain/activity/dto/request/ReadActivitiesReq.java @@ -19,6 +19,4 @@ public class ReadActivitiesReq { private String agencyType; private List personalities; - - private boolean isLiked; } From 6e1399a54f1b53ab1687d3397d606dc440252a1c Mon Sep 17 00:00:00 2001 From: Jeongho Date: Wed, 15 May 2024 15:29:52 +0900 Subject: [PATCH 12/16] =?UTF-8?q?Docs:=20=EB=A1=9C=EC=BB=AC=20=ED=9A=8C?= =?UTF-8?q?=EC=9B=90=EA=B0=80=EC=9E=85=20description=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../backend/domain/register/controller/RegisterController.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/meetup/teame/backend/domain/register/controller/RegisterController.java b/src/main/java/com/meetup/teame/backend/domain/register/controller/RegisterController.java index aca39b4..e62a941 100644 --- a/src/main/java/com/meetup/teame/backend/domain/register/controller/RegisterController.java +++ b/src/main/java/com/meetup/teame/backend/domain/register/controller/RegisterController.java @@ -41,7 +41,7 @@ public ResponseEntity sendEmail(@RequestBody EmailRequest request) { @Operation(summary = "사용자 정보 입력", description = """ 이메일 인증을 마치면 사용자 정보를 입력합니다. - 사용자 정보 입력을 마치고 회원가입에 성공하면 "회원가입 성공"이라는 메세지를 반환합니다. + 사용자 정보 입력을 마치고 회원가입에 성공하면 Jwt 토큰을 헤더에 넣고 "회원가입 성공"이라는 메세지를 반환합니다. """) @PostMapping("/register") public ResponseEntity register(@RequestBody RegisterRequest request) { From e51f840b819e450a79dc1d10f939a80e0060e3d1 Mon Sep 17 00:00:00 2001 From: Jeongho Date: Wed, 15 May 2024 16:38:01 +0900 Subject: [PATCH 13/16] =?UTF-8?q?Feat:=20=ED=9B=84=EA=B8=B0=20=EB=B3=B4?= =?UTF-8?q?=EB=82=B4=EA=B8=B0,=20=ED=9B=84=EA=B8=B0=20=EC=A1=B0=ED=9A=8C?= =?UTF-8?q?=ED=95=98=EA=B8=B0=20api=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../review/controller/ReviewController.java | 46 +++++++++++++++++++ .../domain/review/dto/request/ReviewReq.java | 17 +++++++ .../domain/review/dto/response/ReviewRes.java | 37 +++++++++++++++ .../backend/domain/review/entity/Review.java | 39 ++++++++++++++++ .../review/repository/ReviewRepository.java | 7 +++ .../domain/review/service/ReviewService.java | 45 ++++++++++++++++++ .../global/exception/ExceptionContent.java | 1 + 7 files changed, 192 insertions(+) create mode 100644 src/main/java/com/meetup/teame/backend/domain/review/controller/ReviewController.java create mode 100644 src/main/java/com/meetup/teame/backend/domain/review/dto/request/ReviewReq.java create mode 100644 src/main/java/com/meetup/teame/backend/domain/review/dto/response/ReviewRes.java create mode 100644 src/main/java/com/meetup/teame/backend/domain/review/entity/Review.java create mode 100644 src/main/java/com/meetup/teame/backend/domain/review/repository/ReviewRepository.java create mode 100644 src/main/java/com/meetup/teame/backend/domain/review/service/ReviewService.java diff --git a/src/main/java/com/meetup/teame/backend/domain/review/controller/ReviewController.java b/src/main/java/com/meetup/teame/backend/domain/review/controller/ReviewController.java new file mode 100644 index 0000000..9eb0e3c --- /dev/null +++ b/src/main/java/com/meetup/teame/backend/domain/review/controller/ReviewController.java @@ -0,0 +1,46 @@ +package com.meetup.teame.backend.domain.review.controller; + +import com.meetup.teame.backend.domain.review.dto.request.ReviewReq; +import com.meetup.teame.backend.domain.review.dto.response.ReviewRes; +import com.meetup.teame.backend.domain.review.service.ReviewService; +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.*; + +@RequiredArgsConstructor +@RestController +@Tag(name = "review", description = "후기 관련 api") +public class ReviewController { + + private final ReviewService reviewService; + + @Operation(summary = "후기 보내기", description = """ + 후기 보내기 api 입니다. + + 후기 내용, 멘토 id, 멘티 id를 입력하셔야합니다. + + 후기보내기가 정상적으로 요청되면 후기 id, 후기 내용, 멘토 id, 멘티 id을 반환해줍니다. + """) + //후기 보내기 + @PostMapping("/review") + public ResponseEntity sendReview(@RequestBody ReviewReq request) { + ReviewRes response = reviewService.createReview(request); + return ResponseEntity.ok().body(response); + } + + @Operation(summary = "후기 조회하기", description = """ + 후기 조회하기 api 입니다. + + 후기 id로 후기에 대한 내용을 볼 수 있습니다. + + 후기 id, 후기 내용, 멘토 id, 멘티 id을 반환해줍니다. + """) + //후기 조회하기 + @GetMapping("/review/{reviewId}") + public ResponseEntity getReview(@PathVariable long reviewId) { + ReviewRes response = reviewService.findReview(reviewId); + return ResponseEntity.ok().body(response); + } +} diff --git a/src/main/java/com/meetup/teame/backend/domain/review/dto/request/ReviewReq.java b/src/main/java/com/meetup/teame/backend/domain/review/dto/request/ReviewReq.java new file mode 100644 index 0000000..94416b2 --- /dev/null +++ b/src/main/java/com/meetup/teame/backend/domain/review/dto/request/ReviewReq.java @@ -0,0 +1,17 @@ +package com.meetup.teame.backend.domain.review.dto.request; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@NoArgsConstructor +@AllArgsConstructor +@Getter +public class ReviewReq { + + private String description; + + private Long mentorId; + + private Long menteeId; +} diff --git a/src/main/java/com/meetup/teame/backend/domain/review/dto/response/ReviewRes.java b/src/main/java/com/meetup/teame/backend/domain/review/dto/response/ReviewRes.java new file mode 100644 index 0000000..1c669f1 --- /dev/null +++ b/src/main/java/com/meetup/teame/backend/domain/review/dto/response/ReviewRes.java @@ -0,0 +1,37 @@ +package com.meetup.teame.backend.domain.review.dto.response; + +import com.meetup.teame.backend.domain.chatroom.entity.DirectChatRoom; +import com.meetup.teame.backend.domain.experience.entity.Experience; +import com.meetup.teame.backend.domain.review.entity.Review; +import jakarta.persistence.FetchType; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import org.hibernate.annotations.Comment; + +@NoArgsConstructor +@AllArgsConstructor +@Getter +@Builder +public class ReviewRes { + + private Long id; + + private String description; + + private Long mentorId; + + private Long menteeId; + + public static ReviewRes of(Review review) { + return ReviewRes.builder() + .id(review.getId()) + .description(review.getDescription()) + .mentorId(review.getMentor().getUser().getId()) + .menteeId(review.getMentee().getMentee().getId()) + .build(); + } +} diff --git a/src/main/java/com/meetup/teame/backend/domain/review/entity/Review.java b/src/main/java/com/meetup/teame/backend/domain/review/entity/Review.java new file mode 100644 index 0000000..eb287f2 --- /dev/null +++ b/src/main/java/com/meetup/teame/backend/domain/review/entity/Review.java @@ -0,0 +1,39 @@ +package com.meetup.teame.backend.domain.review.entity; + +import com.meetup.teame.backend.domain.chatroom.entity.DirectChatRoom; +import com.meetup.teame.backend.domain.experience.entity.Experience; +import jakarta.persistence.*; +import lombok.*; +import org.hibernate.annotations.Comment; + +@Entity +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@AllArgsConstructor(access = AccessLevel.PRIVATE) +@Builder +@Getter +@Comment("후기") +public class Review { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @Comment("내용") + private String description; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "mentor") + private Experience mentor; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "mentee") + private DirectChatRoom mentee; + + public static Review of(String description, Experience mentor, DirectChatRoom mentee) { + return Review.builder() + .description(description) + .mentor(mentor) + .mentee(mentee) + .build(); + } +} diff --git a/src/main/java/com/meetup/teame/backend/domain/review/repository/ReviewRepository.java b/src/main/java/com/meetup/teame/backend/domain/review/repository/ReviewRepository.java new file mode 100644 index 0000000..c7bf70f --- /dev/null +++ b/src/main/java/com/meetup/teame/backend/domain/review/repository/ReviewRepository.java @@ -0,0 +1,7 @@ +package com.meetup.teame.backend.domain.review.repository; + +import com.meetup.teame.backend.domain.review.entity.Review; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface ReviewRepository extends JpaRepository { +} diff --git a/src/main/java/com/meetup/teame/backend/domain/review/service/ReviewService.java b/src/main/java/com/meetup/teame/backend/domain/review/service/ReviewService.java new file mode 100644 index 0000000..989c82d --- /dev/null +++ b/src/main/java/com/meetup/teame/backend/domain/review/service/ReviewService.java @@ -0,0 +1,45 @@ +package com.meetup.teame.backend.domain.review.service; + +import com.meetup.teame.backend.domain.chatroom.entity.DirectChatRoom; +import com.meetup.teame.backend.domain.chatroom.repository.DirectChatRoomRepository; +import com.meetup.teame.backend.domain.experience.entity.Experience; +import com.meetup.teame.backend.domain.experience.repository.ExperienceRepository; +import com.meetup.teame.backend.domain.review.dto.request.ReviewReq; +import com.meetup.teame.backend.domain.review.dto.response.ReviewRes; +import com.meetup.teame.backend.domain.review.entity.Review; +import com.meetup.teame.backend.domain.review.repository.ReviewRepository; +import com.meetup.teame.backend.global.exception.CustomException; +import com.meetup.teame.backend.global.exception.ExceptionContent; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@RequiredArgsConstructor +@Transactional(readOnly = true) +@Service +public class ReviewService { + + private final ReviewRepository reviewRepository; + private final ExperienceRepository experienceRepository; + private final DirectChatRoomRepository directChatRoomRepository; + + //후기 작성하기 + public ReviewRes createReview(ReviewReq reviewReq) { + Experience mentor = experienceRepository.findById(reviewReq.getMentorId()) + .orElseThrow(() -> new CustomException(ExceptionContent.NOT_FOUND_EXPERIENCE)); + DirectChatRoom mentee = directChatRoomRepository.findById(reviewReq.getMenteeId()) + .orElseThrow(() -> new CustomException(ExceptionContent.NOT_FOUND_CHAT_ROOM)); + + Review review = reviewRepository.save(Review.of(reviewReq.getDescription(), mentor, mentee)); + + return ReviewRes.of(review); + } + + //후기 조회하기 + public ReviewRes findReview(Long reviewId) { + Review review = reviewRepository.findById(reviewId) + .orElseThrow(() -> new CustomException(ExceptionContent.NOT_FOUND_REVIEW)); + return ReviewRes.of(review); + } + +} diff --git a/src/main/java/com/meetup/teame/backend/global/exception/ExceptionContent.java b/src/main/java/com/meetup/teame/backend/global/exception/ExceptionContent.java index 2b7f234..839b461 100644 --- a/src/main/java/com/meetup/teame/backend/global/exception/ExceptionContent.java +++ b/src/main/java/com/meetup/teame/backend/global/exception/ExceptionContent.java @@ -29,6 +29,7 @@ public enum ExceptionContent { NOT_FOUND_AGENCY_TYPE(NOT_FOUND, "존재하지 않는 기관 유형입니다."), NOT_FOUND_EXPERIENCE(NOT_FOUND, "존재하지 않는 경험입니다."), NOT_FOUND_CHAT_ROOM(NOT_FOUND, "존재하지 않는 채팅방입니다."), + NOT_FOUND_REVIEW(NOT_FOUND, "존재하지 않는 후기입니다."), ; private final HttpStatus httpStatus; From 3e86f144a3843ad5369ae7c05289aee7624eff69 Mon Sep 17 00:00:00 2001 From: Jeongho Date: Thu, 16 May 2024 15:10:37 +0900 Subject: [PATCH 14/16] =?UTF-8?q?Feat:=20=ED=9B=84=EA=B8=B0=20=EB=B3=B4?= =?UTF-8?q?=EB=82=B4=EA=B8=B0,=20=ED=9B=84=EA=B8=B0=20=EC=A1=B0=ED=9A=8C?= =?UTF-8?q?=ED=95=98=EA=B8=B0=20api=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/ActivityController.java | 4 +-- .../dto/request/ReadActivitiesReq.java | 10 ++++-- .../domain/activity/entity/AgencyType.java | 2 +- .../custom/ActivityRepositoryImpl.java | 4 +++ .../activity/service/ActivityService.java | 5 +-- .../domain/auth/config/SecurityConfig.java | 2 +- .../review/controller/ReviewController.java | 4 +-- .../{ReviewReq.java => CreateReviewReq.java} | 2 +- .../domain/review/dto/response/ReviewRes.java | 2 ++ .../review/repository/ReviewRepository.java | 3 +- .../custom/ReviewRepositoryCustom.java | 9 +++++ .../custom/ReviewRepositoryImpl.java | 34 +++++++++++++++++++ .../domain/review/service/ReviewService.java | 10 +++--- .../user/controller/UserController.java | 16 +++++++++ .../backend/domain/user/entity/Gender.java | 10 ++++++ .../domain/user/service/UserService.java | 13 +++++++ .../global/exception/ExceptionContent.java | 2 ++ 17 files changed, 113 insertions(+), 19 deletions(-) rename src/main/java/com/meetup/teame/backend/domain/review/dto/request/{ReviewReq.java => CreateReviewReq.java} (90%) create mode 100644 src/main/java/com/meetup/teame/backend/domain/review/repository/custom/ReviewRepositoryCustom.java create mode 100644 src/main/java/com/meetup/teame/backend/domain/review/repository/custom/ReviewRepositoryImpl.java diff --git a/src/main/java/com/meetup/teame/backend/domain/activity/controller/ActivityController.java b/src/main/java/com/meetup/teame/backend/domain/activity/controller/ActivityController.java index 6143077..bcae0da 100644 --- a/src/main/java/com/meetup/teame/backend/domain/activity/controller/ActivityController.java +++ b/src/main/java/com/meetup/teame/backend/domain/activity/controller/ActivityController.java @@ -44,7 +44,7 @@ public ResponseEntity getActivityDetails(@PathVariable Long //전체 활동 불러오기 @GetMapping("/activities/{userId}") public ResponseEntity getActivities(@PathVariable long userId, - @ModelAttribute @Valid ReadActivitiesReq request) { + @ModelAttribute ReadActivitiesReq request) { ReadActivitiesRes activities = activityService.findActivities(userId, request); return ResponseEntity.ok().body(activities); } @@ -66,7 +66,7 @@ public ResponseEntity getActivities(@PathVariable long userId //관심 활동 불러오기 @GetMapping("/activities/{userId}/liked") public ResponseEntity getLikedActivities(@PathVariable long userId, - @ModelAttribute @Valid ReadActivitiesReq request) { + @ModelAttribute ReadActivitiesReq request) { ReadActivitiesRes activities = activityService.findlikedActivities(userId, request); return ResponseEntity.ok().body(activities); } diff --git a/src/main/java/com/meetup/teame/backend/domain/activity/dto/request/ReadActivitiesReq.java b/src/main/java/com/meetup/teame/backend/domain/activity/dto/request/ReadActivitiesReq.java index b8de444..2cb6654 100644 --- a/src/main/java/com/meetup/teame/backend/domain/activity/dto/request/ReadActivitiesReq.java +++ b/src/main/java/com/meetup/teame/backend/domain/activity/dto/request/ReadActivitiesReq.java @@ -6,17 +6,23 @@ import lombok.AllArgsConstructor; import lombok.Getter; import lombok.NoArgsConstructor; +import lombok.Setter; +import java.util.ArrayList; import java.util.List; @NoArgsConstructor @AllArgsConstructor @Getter +@Setter public class ReadActivitiesReq { - private Long page; + @NotBlank(message = "page is required") + @Min(value = 0, message = "page must be greater than or equal to 0") + @Schema(example = "0") + private long page; private String agencyType; - private List personalities; + private List personalities = new ArrayList<>(); } diff --git a/src/main/java/com/meetup/teame/backend/domain/activity/entity/AgencyType.java b/src/main/java/com/meetup/teame/backend/domain/activity/entity/AgencyType.java index e493619..fa6f10b 100644 --- a/src/main/java/com/meetup/teame/backend/domain/activity/entity/AgencyType.java +++ b/src/main/java/com/meetup/teame/backend/domain/activity/entity/AgencyType.java @@ -24,7 +24,7 @@ public static AgencyType of(String description) { return agencyType; } } - throw new CustomException(ExceptionContent.NOT_FOUND_AGENCY_TYPE); + throw new CustomException(ExceptionContent.BAD_REQUEST_AGENCY_TYPE); } } diff --git a/src/main/java/com/meetup/teame/backend/domain/activity/repository/custom/ActivityRepositoryImpl.java b/src/main/java/com/meetup/teame/backend/domain/activity/repository/custom/ActivityRepositoryImpl.java index fae10a2..66aa299 100644 --- a/src/main/java/com/meetup/teame/backend/domain/activity/repository/custom/ActivityRepositoryImpl.java +++ b/src/main/java/com/meetup/teame/backend/domain/activity/repository/custom/ActivityRepositoryImpl.java @@ -8,6 +8,7 @@ import com.querydsl.jpa.impl.JPAQueryFactory; import lombok.RequiredArgsConstructor; +import java.util.ArrayList; import java.util.List; import static com.meetup.teame.backend.domain.activity.entity.QActivity.activity; @@ -64,6 +65,9 @@ public List findLikedActivities(Long userId, long offset, long limit, if (!likedActivityIds.isEmpty()) { builder.and(activity.id.in(likedActivityIds)); } + else{ + return new ArrayList<>(); + } // agencyType나 personalities가 입력된 경우 해당 값으로 필터링 if (agencyType != null) { diff --git a/src/main/java/com/meetup/teame/backend/domain/activity/service/ActivityService.java b/src/main/java/com/meetup/teame/backend/domain/activity/service/ActivityService.java index 76b9413..1ec30b5 100644 --- a/src/main/java/com/meetup/teame/backend/domain/activity/service/ActivityService.java +++ b/src/main/java/com/meetup/teame/backend/domain/activity/service/ActivityService.java @@ -38,9 +38,6 @@ public class ActivityService { private static final int ACTIVITY_PAGE_SIZE = 12; - //활동 참여 신청하기 - - //특정 활동 상제 정보 response dto화 public ActivityDetailsRes getActivityDetails(Long activityId) { Activity activity = findActivityById(activityId); @@ -86,7 +83,7 @@ public ReadActivitiesRes findActivities(Long userId, ReadActivitiesReq activitie //관심활동 목록 필터링으로 조회 public ReadActivitiesRes findlikedActivities(Long userId, ReadActivitiesReq activitiesReq) { - long page = activitiesReq.getPage(); + Long page = activitiesReq.getPage(); long offset = page * ACTIVITY_PAGE_SIZE; long limit = ACTIVITY_PAGE_SIZE; AgencyType agencyType = null; diff --git a/src/main/java/com/meetup/teame/backend/domain/auth/config/SecurityConfig.java b/src/main/java/com/meetup/teame/backend/domain/auth/config/SecurityConfig.java index 20730da..4ca6c89 100644 --- a/src/main/java/com/meetup/teame/backend/domain/auth/config/SecurityConfig.java +++ b/src/main/java/com/meetup/teame/backend/domain/auth/config/SecurityConfig.java @@ -37,7 +37,7 @@ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { .addFilterBefore(jwtFilter, ExceptionTranslationFilter.class) .cors(c -> c.configurationSource(request -> { CorsConfiguration config = new CorsConfiguration(); - config.setAllowedOrigins(List.of("http://localhost:3000", "https://api.yeongjin.site", "https://ddoba.vercel.app")); + config.setAllowedOrigins(List.of("http://localhost:3000", "https://api.yeongjin.site", "https://ddoba.vercel.app", "https://www.ddoba.site")); config.setAllowedMethods(List.of("*")); config.setAllowCredentials(true); config.setAllowedHeaders(List.of("*")); diff --git a/src/main/java/com/meetup/teame/backend/domain/review/controller/ReviewController.java b/src/main/java/com/meetup/teame/backend/domain/review/controller/ReviewController.java index 9eb0e3c..f782372 100644 --- a/src/main/java/com/meetup/teame/backend/domain/review/controller/ReviewController.java +++ b/src/main/java/com/meetup/teame/backend/domain/review/controller/ReviewController.java @@ -1,6 +1,6 @@ package com.meetup.teame.backend.domain.review.controller; -import com.meetup.teame.backend.domain.review.dto.request.ReviewReq; +import com.meetup.teame.backend.domain.review.dto.request.CreateReviewReq; import com.meetup.teame.backend.domain.review.dto.response.ReviewRes; import com.meetup.teame.backend.domain.review.service.ReviewService; import io.swagger.v3.oas.annotations.Operation; @@ -25,7 +25,7 @@ public class ReviewController { """) //후기 보내기 @PostMapping("/review") - public ResponseEntity sendReview(@RequestBody ReviewReq request) { + public ResponseEntity sendReview(@RequestBody CreateReviewReq request) { ReviewRes response = reviewService.createReview(request); return ResponseEntity.ok().body(response); } diff --git a/src/main/java/com/meetup/teame/backend/domain/review/dto/request/ReviewReq.java b/src/main/java/com/meetup/teame/backend/domain/review/dto/request/CreateReviewReq.java similarity index 90% rename from src/main/java/com/meetup/teame/backend/domain/review/dto/request/ReviewReq.java rename to src/main/java/com/meetup/teame/backend/domain/review/dto/request/CreateReviewReq.java index 94416b2..30da5e8 100644 --- a/src/main/java/com/meetup/teame/backend/domain/review/dto/request/ReviewReq.java +++ b/src/main/java/com/meetup/teame/backend/domain/review/dto/request/CreateReviewReq.java @@ -7,7 +7,7 @@ @NoArgsConstructor @AllArgsConstructor @Getter -public class ReviewReq { +public class CreateReviewReq { private String description; diff --git a/src/main/java/com/meetup/teame/backend/domain/review/dto/response/ReviewRes.java b/src/main/java/com/meetup/teame/backend/domain/review/dto/response/ReviewRes.java index 1c669f1..2f23844 100644 --- a/src/main/java/com/meetup/teame/backend/domain/review/dto/response/ReviewRes.java +++ b/src/main/java/com/meetup/teame/backend/domain/review/dto/response/ReviewRes.java @@ -26,6 +26,8 @@ public class ReviewRes { private Long menteeId; + //멘토 이름, 나이, 성별, 거주지, 프로필 사진, 경험 유형, 경험 제목 + public static ReviewRes of(Review review) { return ReviewRes.builder() .id(review.getId()) diff --git a/src/main/java/com/meetup/teame/backend/domain/review/repository/ReviewRepository.java b/src/main/java/com/meetup/teame/backend/domain/review/repository/ReviewRepository.java index c7bf70f..b6c9795 100644 --- a/src/main/java/com/meetup/teame/backend/domain/review/repository/ReviewRepository.java +++ b/src/main/java/com/meetup/teame/backend/domain/review/repository/ReviewRepository.java @@ -1,7 +1,8 @@ package com.meetup.teame.backend.domain.review.repository; import com.meetup.teame.backend.domain.review.entity.Review; +import com.meetup.teame.backend.domain.review.repository.custom.ReviewRepositoryCustom; import org.springframework.data.jpa.repository.JpaRepository; -public interface ReviewRepository extends JpaRepository { +public interface ReviewRepository extends JpaRepository, ReviewRepositoryCustom { } diff --git a/src/main/java/com/meetup/teame/backend/domain/review/repository/custom/ReviewRepositoryCustom.java b/src/main/java/com/meetup/teame/backend/domain/review/repository/custom/ReviewRepositoryCustom.java new file mode 100644 index 0000000..890b526 --- /dev/null +++ b/src/main/java/com/meetup/teame/backend/domain/review/repository/custom/ReviewRepositoryCustom.java @@ -0,0 +1,9 @@ +package com.meetup.teame.backend.domain.review.repository.custom; + +import com.meetup.teame.backend.domain.review.entity.Review; + +import java.util.List; + +public interface ReviewRepositoryCustom { + List findReviewsByUserId(Long userId, String type); +} diff --git a/src/main/java/com/meetup/teame/backend/domain/review/repository/custom/ReviewRepositoryImpl.java b/src/main/java/com/meetup/teame/backend/domain/review/repository/custom/ReviewRepositoryImpl.java new file mode 100644 index 0000000..00a956e --- /dev/null +++ b/src/main/java/com/meetup/teame/backend/domain/review/repository/custom/ReviewRepositoryImpl.java @@ -0,0 +1,34 @@ +package com.meetup.teame.backend.domain.review.repository.custom; + +import com.meetup.teame.backend.domain.experience.entity.ExperienceType; +import com.meetup.teame.backend.domain.review.entity.Review; +import com.querydsl.core.BooleanBuilder; +import com.querydsl.jpa.impl.JPAQueryFactory; +import lombok.RequiredArgsConstructor; + +import java.util.List; + +import static com.meetup.teame.backend.domain.experience.entity.QExperience.experience; +import static com.meetup.teame.backend.domain.review.entity.QReview.review; + +@RequiredArgsConstructor +public class ReviewRepositoryImpl implements ReviewRepositoryCustom { + private final JPAQueryFactory jpaQueryFactory; + + @Override + public List findReviewsByUserId(Long userId, String type) { + BooleanBuilder builder = new BooleanBuilder(); + + if (type != null) { + builder.and(experience.type.eq(ExperienceType.of(type))); + } + + return jpaQueryFactory + .selectFrom(review) + .join(review.mentor, experience) + .fetchJoin() + .where(experience.user.id.eq(userId)) + .fetch(); + } + +} diff --git a/src/main/java/com/meetup/teame/backend/domain/review/service/ReviewService.java b/src/main/java/com/meetup/teame/backend/domain/review/service/ReviewService.java index 989c82d..ec0f873 100644 --- a/src/main/java/com/meetup/teame/backend/domain/review/service/ReviewService.java +++ b/src/main/java/com/meetup/teame/backend/domain/review/service/ReviewService.java @@ -4,7 +4,7 @@ import com.meetup.teame.backend.domain.chatroom.repository.DirectChatRoomRepository; import com.meetup.teame.backend.domain.experience.entity.Experience; import com.meetup.teame.backend.domain.experience.repository.ExperienceRepository; -import com.meetup.teame.backend.domain.review.dto.request.ReviewReq; +import com.meetup.teame.backend.domain.review.dto.request.CreateReviewReq; import com.meetup.teame.backend.domain.review.dto.response.ReviewRes; import com.meetup.teame.backend.domain.review.entity.Review; import com.meetup.teame.backend.domain.review.repository.ReviewRepository; @@ -24,13 +24,13 @@ public class ReviewService { private final DirectChatRoomRepository directChatRoomRepository; //후기 작성하기 - public ReviewRes createReview(ReviewReq reviewReq) { - Experience mentor = experienceRepository.findById(reviewReq.getMentorId()) + public ReviewRes createReview(CreateReviewReq createReviewReq) { + Experience mentor = experienceRepository.findById(createReviewReq.getMentorId()) .orElseThrow(() -> new CustomException(ExceptionContent.NOT_FOUND_EXPERIENCE)); - DirectChatRoom mentee = directChatRoomRepository.findById(reviewReq.getMenteeId()) + DirectChatRoom mentee = directChatRoomRepository.findById(createReviewReq.getMenteeId()) .orElseThrow(() -> new CustomException(ExceptionContent.NOT_FOUND_CHAT_ROOM)); - Review review = reviewRepository.save(Review.of(reviewReq.getDescription(), mentor, mentee)); + Review review = reviewRepository.save(Review.of(createReviewReq.getDescription(), mentor, mentee)); return ReviewRes.of(review); } diff --git a/src/main/java/com/meetup/teame/backend/domain/user/controller/UserController.java b/src/main/java/com/meetup/teame/backend/domain/user/controller/UserController.java index a5994e2..8cf75ec 100644 --- a/src/main/java/com/meetup/teame/backend/domain/user/controller/UserController.java +++ b/src/main/java/com/meetup/teame/backend/domain/user/controller/UserController.java @@ -1,5 +1,6 @@ package com.meetup.teame.backend.domain.user.controller; +import com.meetup.teame.backend.domain.review.dto.response.ReviewRes; import com.meetup.teame.backend.domain.user.dto.request.OnboardingReq; import com.meetup.teame.backend.domain.user.dto.request.UpdateUserReq; import com.meetup.teame.backend.domain.user.dto.response.ReadMainRes; @@ -12,6 +13,8 @@ import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; +import java.util.List; + @RestController @RequiredArgsConstructor @RequestMapping("/users") @@ -74,4 +77,17 @@ public ResponseEntity updateUserInfo(@PathVariable long userId, @Re UserInfoRes userInfo = userService.updateUserInfo(userId, request); return ResponseEntity.ok().body(userInfo); } + + @Operation(summary = "내 후기 목록 조회", description = """ + 내 후기 목록을 조회하는 api입니다. + + + """) + //내 후기 목록 조회 + @GetMapping("/{userId}/review") + public ResponseEntity> getMyReviews(@PathVariable long userId, + @RequestParam String type) { + List myReviews = userService.getMyReviews(userId, type); + return ResponseEntity.ok().body(myReviews); + } } diff --git a/src/main/java/com/meetup/teame/backend/domain/user/entity/Gender.java b/src/main/java/com/meetup/teame/backend/domain/user/entity/Gender.java index 886d0b0..f08287f 100644 --- a/src/main/java/com/meetup/teame/backend/domain/user/entity/Gender.java +++ b/src/main/java/com/meetup/teame/backend/domain/user/entity/Gender.java @@ -1,5 +1,7 @@ package com.meetup.teame.backend.domain.user.entity; +import com.meetup.teame.backend.global.exception.CustomException; +import com.meetup.teame.backend.global.exception.ExceptionContent; import lombok.Getter; import lombok.RequiredArgsConstructor; @@ -11,4 +13,12 @@ public enum Gender { private final String description; + public static Gender of(String description) { + for (Gender gender : Gender.values()) { + if (gender.getDescription().equals(description)) { + return gender; + } + } + throw new CustomException(ExceptionContent.BAD_REQUEST_GENDER); + } } diff --git a/src/main/java/com/meetup/teame/backend/domain/user/service/UserService.java b/src/main/java/com/meetup/teame/backend/domain/user/service/UserService.java index 6e450ee..9c5b751 100644 --- a/src/main/java/com/meetup/teame/backend/domain/user/service/UserService.java +++ b/src/main/java/com/meetup/teame/backend/domain/user/service/UserService.java @@ -4,6 +4,9 @@ import com.meetup.teame.backend.domain.auth.oauth.dto.CreateUserRequest; import com.meetup.teame.backend.domain.experience.repository.ExperienceRepository; import com.meetup.teame.backend.domain.personality.Personality; +import com.meetup.teame.backend.domain.review.dto.response.ReviewRes; +import com.meetup.teame.backend.domain.review.entity.Review; +import com.meetup.teame.backend.domain.review.repository.ReviewRepository; import com.meetup.teame.backend.domain.user.dto.request.OnboardingReq; import com.meetup.teame.backend.domain.user.dto.request.UpdateUserReq; import com.meetup.teame.backend.domain.user.dto.response.ReadMainRes; @@ -20,6 +23,7 @@ import java.time.LocalDate; import java.util.List; import java.util.Objects; +import java.util.stream.Collectors; @Service @RequiredArgsConstructor @@ -29,6 +33,7 @@ public class UserService { private final UserRepository userRepository; private final ActivityRepository activityRepository; private final ExperienceRepository experienceRepository; + private final ReviewRepository reviewRepository; public ReadMainRes readMainPage() { //todo 현재는 더미 유저지만 추후에는 SecurityContextHolder 정보를 조회해서 유저 정보를 가져와야 함 @@ -80,6 +85,14 @@ public UserInfoRes updateUserInfo(Long userId, UpdateUserReq request) { return UserInfoRes.of(updatedUser); } + public List getMyReviews(Long userId, String type) { + List myReviews = reviewRepository.findReviewsByUserId(userId, type); + List reviews = myReviews.stream() + .map(ReviewRes::of) + .toList(); + return reviews; + } + @Transactional public void setUserPersonality(OnboardingReq onboardingReq) { //todo 현재는 더미 유저지만 추후에는 SecurityContextHolder 정보를 조회해서 유저 정보를 가져와야 함 diff --git a/src/main/java/com/meetup/teame/backend/global/exception/ExceptionContent.java b/src/main/java/com/meetup/teame/backend/global/exception/ExceptionContent.java index 839b461..5c35c41 100644 --- a/src/main/java/com/meetup/teame/backend/global/exception/ExceptionContent.java +++ b/src/main/java/com/meetup/teame/backend/global/exception/ExceptionContent.java @@ -21,6 +21,8 @@ public enum ExceptionContent { BAD_REQUEST_EXPERIENCE_TYPE(BAD_REQUEST, "잘못된 요청입니다. 유효하지 않은 경험 유형입니다."), BAD_REQUEST_SORT_TYPE(BAD_REQUEST, "잘못된 요청입니다. 유효하지 않은 정렬 방식입니다."), BAD_REQUEST_ALREADY_JOIN_CHATROOM(BAD_REQUEST, "이미 참여한 채팅방입니다."), + BAD_REQUEST_AGENCY_TYPE(BAD_REQUEST, "잘못된 요청입니다. 유효하지 않은 기관 유형입니다."), + BAD_REQUEST_GENDER(BAD_REQUEST, "잘못된 요청입니다. 유효하지 않은 성별입니다."), NOT_FOUND_USER(NOT_FOUND, "존재하지 않는 사용자입니다."), NOT_FOUND_PERSONALITY(NOT_FOUND, "존재하지 않는 성격입니다."), From a454b6fb298b5316a9ba79d3ed8a98e77839c595 Mon Sep 17 00:00:00 2001 From: Jeongho Date: Thu, 16 May 2024 15:44:07 +0900 Subject: [PATCH 15/16] =?UTF-8?q?Fix:=20=ED=99=9C=EB=8F=99=20=EC=83=81?= =?UTF-8?q?=EC=84=B8=20=EC=A1=B0=ED=9A=8C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../activity/dto/response/ActivityDetailsRes.java | 4 ++-- .../domain/activity/service/ActivityService.java | 11 ++++------- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/src/main/java/com/meetup/teame/backend/domain/activity/dto/response/ActivityDetailsRes.java b/src/main/java/com/meetup/teame/backend/domain/activity/dto/response/ActivityDetailsRes.java index 807f37c..5fad62e 100644 --- a/src/main/java/com/meetup/teame/backend/domain/activity/dto/response/ActivityDetailsRes.java +++ b/src/main/java/com/meetup/teame/backend/domain/activity/dto/response/ActivityDetailsRes.java @@ -37,7 +37,7 @@ public class ActivityDetailsRes { private List activityImgs; - public static ActivityDetailsRes of(Activity activity, List activityImgs) { + public static ActivityDetailsRes of(Activity activity) { return ActivityDetailsRes.builder() .id(activity.getId()) .title(activity.getTitle()) @@ -48,7 +48,7 @@ public static ActivityDetailsRes of(Activity activity, List activityImgs .currentParticipants(activity.getCurrentParticipants()) .maxParticipants(activity.getMaxParticipants()) .personalities(activity.getPersonalities()) - .activityImgs(activityImgs) + .activityImgs(activity.getActivityImgs()) .build(); } } diff --git a/src/main/java/com/meetup/teame/backend/domain/activity/service/ActivityService.java b/src/main/java/com/meetup/teame/backend/domain/activity/service/ActivityService.java index 1ec30b5..55ffb84 100644 --- a/src/main/java/com/meetup/teame/backend/domain/activity/service/ActivityService.java +++ b/src/main/java/com/meetup/teame/backend/domain/activity/service/ActivityService.java @@ -41,8 +41,8 @@ public class ActivityService { //특정 활동 상제 정보 response dto화 public ActivityDetailsRes getActivityDetails(Long activityId) { Activity activity = findActivityById(activityId); - List imageUrls = getImageUrls(activity); - return ActivityDetailsRes.of(activity, imageUrls); + //List imageUrls = getImageUrls(activity); + return ActivityDetailsRes.of(activity); } //activityId로 특정 활동 불러오기 @@ -111,16 +111,13 @@ public ReadActivitiesRes findlikedActivities(Long userId, ReadActivitiesReq acti URL url = amazonS3.getUrl(bucket, activity.getActivityImgs()); return "" + url; }*/ - public List getImageUrls(Activity activity) { + /*public List getImageUrls(Activity activity) { List activityImgs = activity.getActivityImgs(); List imageUrls = new ArrayList<>(); for (String imgKey : activityImgs) { // 이미지의 URL을 생성하기 위해 S3에 대한 요청을 생성 GeneratePresignedUrlRequest urlRequest = new GeneratePresignedUrlRequest(bucket, imgKey); - /*// 이미지가 다운로드되는 시간(5분)을 설정합니다. - urlRequest.setExpiration(new Date(System.currentTimeMillis() + 1000 * 60 * 5));*/ - URL url = amazonS3.generatePresignedUrl(urlRequest); imageUrls.add(url.toString()); @@ -128,5 +125,5 @@ public List getImageUrls(Activity activity) { // 생성된 이미지 URL 리스트를 반환합니다. return imageUrls; - } + }*/ } From 87116fb736c306a2a56573fd49991495a457c507 Mon Sep 17 00:00:00 2001 From: Jeongho Date: Thu, 16 May 2024 19:17:45 +0900 Subject: [PATCH 16/16] =?UTF-8?q?Fix:=20=ED=86=A0=ED=81=B0=EC=97=90?= =?UTF-8?q?=EC=84=9C=20userId=20=EC=B6=94=EC=B6=9C=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/ActivityController.java | 16 +++-- .../activity/service/ActivityService.java | 7 ++- .../auth/jwt/SecurityContextProvider.java | 19 ++++++ .../auth/jwt/dto/CustomUserDetails.java | 59 ------------------- .../jwt/service/CustomUserDetailsService.java | 32 ---------- .../auth/oauth/service/KakaoService.java | 1 - .../domain/user/service/UserService.java | 1 + 7 files changed, 32 insertions(+), 103 deletions(-) create mode 100644 src/main/java/com/meetup/teame/backend/domain/auth/jwt/SecurityContextProvider.java delete mode 100644 src/main/java/com/meetup/teame/backend/domain/auth/jwt/dto/CustomUserDetails.java delete mode 100644 src/main/java/com/meetup/teame/backend/domain/auth/jwt/service/CustomUserDetailsService.java diff --git a/src/main/java/com/meetup/teame/backend/domain/activity/controller/ActivityController.java b/src/main/java/com/meetup/teame/backend/domain/activity/controller/ActivityController.java index bcae0da..174fa50 100644 --- a/src/main/java/com/meetup/teame/backend/domain/activity/controller/ActivityController.java +++ b/src/main/java/com/meetup/teame/backend/domain/activity/controller/ActivityController.java @@ -4,9 +4,9 @@ import com.meetup.teame.backend.domain.activity.dto.response.ActivityDetailsRes; import com.meetup.teame.backend.domain.activity.dto.response.ReadActivitiesRes; import com.meetup.teame.backend.domain.activity.service.ActivityService; +import com.meetup.teame.backend.domain.auth.jwt.SecurityContextProvider; 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.http.ResponseEntity; import org.springframework.web.bind.annotation.*; @@ -42,10 +42,9 @@ public ResponseEntity getActivityDetails(@PathVariable Long personalities : 활동 성격 유형 (복수 선택 가능합니다, String List로 보내주시면 됩니다.) """) //전체 활동 불러오기 - @GetMapping("/activities/{userId}") - public ResponseEntity getActivities(@PathVariable long userId, - @ModelAttribute ReadActivitiesReq request) { - ReadActivitiesRes activities = activityService.findActivities(userId, request); + @GetMapping("/activities") + public ResponseEntity getActivities(@ModelAttribute ReadActivitiesReq request) { + ReadActivitiesRes activities = activityService.findActivities(request); return ResponseEntity.ok().body(activities); } @@ -64,10 +63,9 @@ public ResponseEntity getActivities(@PathVariable long userId """) //관심 활동 불러오기 - @GetMapping("/activities/{userId}/liked") - public ResponseEntity getLikedActivities(@PathVariable long userId, - @ModelAttribute ReadActivitiesReq request) { - ReadActivitiesRes activities = activityService.findlikedActivities(userId, request); + @GetMapping("/activities/liked") + public ResponseEntity getLikedActivities(@ModelAttribute ReadActivitiesReq request) { + ReadActivitiesRes activities = activityService.findlikedActivities(request); return ResponseEntity.ok().body(activities); } } diff --git a/src/main/java/com/meetup/teame/backend/domain/activity/service/ActivityService.java b/src/main/java/com/meetup/teame/backend/domain/activity/service/ActivityService.java index 55ffb84..84a555e 100644 --- a/src/main/java/com/meetup/teame/backend/domain/activity/service/ActivityService.java +++ b/src/main/java/com/meetup/teame/backend/domain/activity/service/ActivityService.java @@ -9,6 +9,7 @@ import com.meetup.teame.backend.domain.activity.entity.Activity; import com.meetup.teame.backend.domain.activity.entity.AgencyType; import com.meetup.teame.backend.domain.activity.repository.ActivityRepository; +import com.meetup.teame.backend.domain.auth.jwt.SecurityContextProvider; import com.meetup.teame.backend.domain.like.repository.ActivityLikeRepository; import com.meetup.teame.backend.domain.personality.Personality; import com.meetup.teame.backend.global.exception.CustomException; @@ -52,7 +53,8 @@ private Activity findActivityById(Long activityId) { } //활동 목록 필터링으로 조회 - public ReadActivitiesRes findActivities(Long userId, ReadActivitiesReq activitiesReq) { + public ReadActivitiesRes findActivities(ReadActivitiesReq activitiesReq) { + Long userId = SecurityContextProvider.getAuthenticatedUserId(); long page = activitiesReq.getPage(); long offset = page * ACTIVITY_PAGE_SIZE; long limit = ACTIVITY_PAGE_SIZE; @@ -82,7 +84,8 @@ public ReadActivitiesRes findActivities(Long userId, ReadActivitiesReq activitie } //관심활동 목록 필터링으로 조회 - public ReadActivitiesRes findlikedActivities(Long userId, ReadActivitiesReq activitiesReq) { + public ReadActivitiesRes findlikedActivities(ReadActivitiesReq activitiesReq) { + Long userId = SecurityContextProvider.getAuthenticatedUserId(); Long page = activitiesReq.getPage(); long offset = page * ACTIVITY_PAGE_SIZE; long limit = ACTIVITY_PAGE_SIZE; diff --git a/src/main/java/com/meetup/teame/backend/domain/auth/jwt/SecurityContextProvider.java b/src/main/java/com/meetup/teame/backend/domain/auth/jwt/SecurityContextProvider.java new file mode 100644 index 0000000..ee5b3c6 --- /dev/null +++ b/src/main/java/com/meetup/teame/backend/domain/auth/jwt/SecurityContextProvider.java @@ -0,0 +1,19 @@ +package com.meetup.teame.backend.domain.auth.jwt; + +import com.meetup.teame.backend.global.exception.CustomException; +import com.meetup.teame.backend.global.exception.ExceptionContent; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContextHolder; + +import java.util.Objects; + +public class SecurityContextProvider { + public static Long getAuthenticatedUserId() { + Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); + Object principal = authentication.getPrincipal(); + if (Objects.isNull(principal)) { + throw new CustomException(ExceptionContent.NOT_AUTHENTICATION); + } + return (Long) principal; + } +} diff --git a/src/main/java/com/meetup/teame/backend/domain/auth/jwt/dto/CustomUserDetails.java b/src/main/java/com/meetup/teame/backend/domain/auth/jwt/dto/CustomUserDetails.java deleted file mode 100644 index 1e29eb7..0000000 --- a/src/main/java/com/meetup/teame/backend/domain/auth/jwt/dto/CustomUserDetails.java +++ /dev/null @@ -1,59 +0,0 @@ -package com.meetup.teame.backend.domain.auth.jwt.dto; - -import com.meetup.teame.backend.domain.user.entity.User; -import lombok.RequiredArgsConstructor; -import org.springframework.security.core.GrantedAuthority; -import org.springframework.security.core.userdetails.UserDetails; - -import java.util.ArrayList; -import java.util.Collection; - -@RequiredArgsConstructor -public class CustomUserDetails implements UserDetails { - - private final User user; - - @Override - public Collection getAuthorities() { - - Collection collection = new ArrayList<>(); - - collection.add(new GrantedAuthority() { - @Override - public String getAuthority() { - return user.getEmail(); - } - }); - return collection; - } - - @Override - public String getUsername() { - return user.getName(); - } - - @Override - public String getPassword() { - return null; - } - - @Override - public boolean isAccountNonExpired() { - return true; - } - - @Override - public boolean isAccountNonLocked() { - return true; - } - - @Override - public boolean isCredentialsNonExpired() { - return true; - } - - @Override - public boolean isEnabled() { - return true; - } -} diff --git a/src/main/java/com/meetup/teame/backend/domain/auth/jwt/service/CustomUserDetailsService.java b/src/main/java/com/meetup/teame/backend/domain/auth/jwt/service/CustomUserDetailsService.java deleted file mode 100644 index 33dc0d6..0000000 --- a/src/main/java/com/meetup/teame/backend/domain/auth/jwt/service/CustomUserDetailsService.java +++ /dev/null @@ -1,32 +0,0 @@ -package com.meetup.teame.backend.domain.auth.jwt.service; - -import com.meetup.teame.backend.domain.auth.jwt.dto.CustomUserDetails; -import com.meetup.teame.backend.domain.user.entity.User; -import com.meetup.teame.backend.domain.user.repository.UserRepository; -import lombok.RequiredArgsConstructor; -import org.springframework.security.core.userdetails.UserDetails; -import org.springframework.security.core.userdetails.UserDetailsService; -import org.springframework.security.core.userdetails.UsernameNotFoundException; -import org.springframework.stereotype.Service; - -@RequiredArgsConstructor -@Service -public class CustomUserDetailsService implements UserDetailsService { - - private final UserRepository userRepository; - - @Override - public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { - - //DB에서 조회 - User userData = userRepository.findByName(username); - - if (userData != null) { - - //UserDetails에 담아서 return하면 AutneticationManager가 검증 함 - return new CustomUserDetails(userData); - } - - return null; - } -} diff --git a/src/main/java/com/meetup/teame/backend/domain/auth/oauth/service/KakaoService.java b/src/main/java/com/meetup/teame/backend/domain/auth/oauth/service/KakaoService.java index bf70e96..3504757 100644 --- a/src/main/java/com/meetup/teame/backend/domain/auth/oauth/service/KakaoService.java +++ b/src/main/java/com/meetup/teame/backend/domain/auth/oauth/service/KakaoService.java @@ -39,7 +39,6 @@ public class KakaoService { private long ACCESS_TOKEN_EXPIRE_TIME; private final JwtProvider jwtProvider; - private final UserService userService; //카카오 엑세스 토큰으로 사용자 정보 받아오기 public CreateOauthUserRequest getKakaoInfo(String accessToken) throws JsonProcessingException { diff --git a/src/main/java/com/meetup/teame/backend/domain/user/service/UserService.java b/src/main/java/com/meetup/teame/backend/domain/user/service/UserService.java index 9c5b751..9a3bc5c 100644 --- a/src/main/java/com/meetup/teame/backend/domain/user/service/UserService.java +++ b/src/main/java/com/meetup/teame/backend/domain/user/service/UserService.java @@ -85,6 +85,7 @@ public UserInfoRes updateUserInfo(Long userId, UpdateUserReq request) { return UserInfoRes.of(updatedUser); } + //내 후기 조회 public List getMyReviews(Long userId, String type) { List myReviews = reviewRepository.findReviewsByUserId(userId, type); List reviews = myReviews.stream()