diff --git a/src/main/java/ssu/eatssu/domain/partnership/entity/Partnership.java b/src/main/java/ssu/eatssu/domain/partnership/entity/Partnership.java index d784217d..43d94e2b 100644 --- a/src/main/java/ssu/eatssu/domain/partnership/entity/Partnership.java +++ b/src/main/java/ssu/eatssu/domain/partnership/entity/Partnership.java @@ -26,7 +26,7 @@ @NoArgsConstructor(access = AccessLevel.PROTECTED) @Builder @AllArgsConstructor -@Where(clause = "end_date >= CURRENT_DATE") +@Where(clause = "start_date <= CURRENT_DATE AND end_date >= CURRENT_DATE") public class Partnership { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) diff --git a/src/main/java/ssu/eatssu/domain/partnership/persistence/PartnershipRepository.java b/src/main/java/ssu/eatssu/domain/partnership/persistence/PartnershipRepository.java index 786059e9..2ab491ff 100644 --- a/src/main/java/ssu/eatssu/domain/partnership/persistence/PartnershipRepository.java +++ b/src/main/java/ssu/eatssu/domain/partnership/persistence/PartnershipRepository.java @@ -4,16 +4,29 @@ import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.query.Param; import ssu.eatssu.domain.partnership.entity.Partnership; +import ssu.eatssu.domain.partnership.entity.PartnershipRestaurant; import ssu.eatssu.domain.user.department.entity.College; import ssu.eatssu.domain.user.department.entity.Department; import java.util.List; public interface PartnershipRepository extends JpaRepository { - @Query("SELECT DISTINCT p FROM Partnership p " + - "LEFT JOIN p.partnershipCollege pc " + - "LEFT JOIN p.partnershipDepartment pd " + - "WHERE (pc = :college OR pd = :department OR (pc IS NOT NULL AND pc.name = '총학'))") - List findRelevantPartnerships(@Param("college") College college, - @Param("department") Department department); + @Query(""" + select distinct pr + from PartnershipRestaurant pr + join fetch pr.partnerships p + left join fetch p.partnershipCollege pc + left join fetch p.partnershipDepartment pd + where + (pc = :college + or pd = :department + or (pc is not null and pc.name = '총학')) + and p.startDate <= current_date + and (p.endDate is null or p.endDate >= current_date) + """) + List findRestaurantsWithMyPartnerships( + @Param("college") College college, + @Param("department") Department department + ); + } diff --git a/src/main/java/ssu/eatssu/domain/partnership/persistence/PartnershipRestaurantRepository.java b/src/main/java/ssu/eatssu/domain/partnership/persistence/PartnershipRestaurantRepository.java index 5fd32d87..f21e1956 100644 --- a/src/main/java/ssu/eatssu/domain/partnership/persistence/PartnershipRestaurantRepository.java +++ b/src/main/java/ssu/eatssu/domain/partnership/persistence/PartnershipRestaurantRepository.java @@ -7,9 +7,11 @@ import java.util.List; public interface PartnershipRestaurantRepository extends JpaRepository { - @Query("SELECT DISTINCT pr FROM PartnershipRestaurant pr " + - "LEFT JOIN FETCH pr.partnerships p " + - "LEFT JOIN FETCH p.partnershipCollege " + - "LEFT JOIN FETCH p.partnershipDepartment ") + @Query(""" + SELECT DISTINCT pr FROM PartnershipRestaurant pr + LEFT JOIN FETCH pr.partnerships p + LEFT JOIN FETCH p.partnershipCollege + LEFT JOIN FETCH p.partnershipDepartment + WHERE p.startDate <= CURRENT_DATE and (p.endDate is null or p.endDate >= CURRENT_DATE)""") List findAllWithDetails(); } diff --git a/src/main/java/ssu/eatssu/domain/partnership/service/PartnershipService.java b/src/main/java/ssu/eatssu/domain/partnership/service/PartnershipService.java index 6e1bd075..b82a94db 100644 --- a/src/main/java/ssu/eatssu/domain/partnership/service/PartnershipService.java +++ b/src/main/java/ssu/eatssu/domain/partnership/service/PartnershipService.java @@ -115,14 +115,10 @@ public List getUserDepartmentPartnerships(CustomUserDetails College college = department.getCollege(); return partnershipRepository - .findRelevantPartnerships(college, department) + .findRestaurantsWithMyPartnerships(college, department) .stream() - .map(partnership -> { - PartnershipRestaurant partnershipRestaurant = partnership.getPartnershipRestaurant(); - - return PartnershipResponse.fromEntity(partnershipRestaurant, - customUserDetails.getId()); - }) + .map(partnershipRestaurant -> PartnershipResponse.fromEntity(partnershipRestaurant, + customUserDetails.getId())) .collect(Collectors.toList()); } } diff --git a/src/main/java/ssu/eatssu/domain/user/department/persistence/DepartmentRepository.java b/src/main/java/ssu/eatssu/domain/user/department/persistence/DepartmentRepository.java index 942e4063..50e55f12 100644 --- a/src/main/java/ssu/eatssu/domain/user/department/persistence/DepartmentRepository.java +++ b/src/main/java/ssu/eatssu/domain/user/department/persistence/DepartmentRepository.java @@ -1,10 +1,14 @@ package ssu.eatssu.domain.user.department.persistence; import org.springframework.data.jpa.repository.JpaRepository; +import ssu.eatssu.domain.user.department.entity.College; import ssu.eatssu.domain.user.department.entity.Department; +import java.util.List; import java.util.Optional; public interface DepartmentRepository extends JpaRepository { Optional findByName(String name); + + List findByCollege(College college); } diff --git a/src/main/java/ssu/eatssu/domain/user/dto/DepartmentResponse.java b/src/main/java/ssu/eatssu/domain/user/dto/DepartmentResponse.java index 7df39fdb..105ad9e3 100644 --- a/src/main/java/ssu/eatssu/domain/user/dto/DepartmentResponse.java +++ b/src/main/java/ssu/eatssu/domain/user/dto/DepartmentResponse.java @@ -1,10 +1,24 @@ package ssu.eatssu.domain.user.dto; -import lombok.AllArgsConstructor; -import lombok.Getter; +import lombok.Builder; +import ssu.eatssu.domain.user.department.entity.College; +import ssu.eatssu.domain.user.department.entity.Department; -@Getter -@AllArgsConstructor -public class DepartmentResponse { - private String departmentName; +@Builder +public record DepartmentResponse( + Long departmentId, String departmentName, Long collegeId, String collegeName +) { + public static DepartmentResponse from(Department department) { + if (department == null) { + return new DepartmentResponse(null, null, null, null); + } + final College college = department.getCollege(); + return DepartmentResponse.builder() + .departmentId(department.getId()) + .departmentName(department.getName()) + .collegeId(college != null ? college.getId() : null) + .collegeName(college != null ? college.getName() : null) + .build(); + } } + diff --git a/src/main/java/ssu/eatssu/domain/user/dto/GetCollegeResponse.java b/src/main/java/ssu/eatssu/domain/user/dto/GetCollegeResponse.java new file mode 100644 index 00000000..79e625ba --- /dev/null +++ b/src/main/java/ssu/eatssu/domain/user/dto/GetCollegeResponse.java @@ -0,0 +1,10 @@ +package ssu.eatssu.domain.user.dto; + +import lombok.Builder; + +@Builder +public record GetCollegeResponse( + Long id, + String name +) { +} diff --git a/src/main/java/ssu/eatssu/domain/user/dto/GetDepartmentResponse.java b/src/main/java/ssu/eatssu/domain/user/dto/GetDepartmentResponse.java new file mode 100644 index 00000000..128b9d92 --- /dev/null +++ b/src/main/java/ssu/eatssu/domain/user/dto/GetDepartmentResponse.java @@ -0,0 +1,8 @@ +package ssu.eatssu.domain.user.dto; + +import lombok.Builder; + +@Builder +public record GetDepartmentResponse(Long id, + String name) { +} diff --git a/src/main/java/ssu/eatssu/domain/user/dto/MyPageResponse.java b/src/main/java/ssu/eatssu/domain/user/dto/MyPageResponse.java index d5d7d529..4a5ba2af 100644 --- a/src/main/java/ssu/eatssu/domain/user/dto/MyPageResponse.java +++ b/src/main/java/ssu/eatssu/domain/user/dto/MyPageResponse.java @@ -5,15 +5,49 @@ import lombok.Builder; import lombok.Getter; import ssu.eatssu.domain.auth.entity.OAuthProvider; +import ssu.eatssu.domain.user.department.entity.College; +import ssu.eatssu.domain.user.department.entity.Department; +import ssu.eatssu.domain.user.entity.User; @AllArgsConstructor @Builder @Schema(title = "마이페이지 정보") @Getter public class MyPageResponse { + @Schema(description = "닉네임", example = "피치푸치") private String nickname; - @Schema(description = "연결 계정 정보", example = "피치푸치") + @Schema(description = "연결 계정 정보", example = "GOOGLE") private OAuthProvider provider; + + @Schema(description = "학과 id", example = "1") + private Long departmentId; + + @Schema(description = "학과 이름", example = "컴퓨터학부") + private String departmentName; + + @Schema(description = "단과대 id", example = "1") + private Long collegeId; + + @Schema(description = "단과대 이름", example = "IT 대학") + private String collegeName; + + public static MyPageResponse from(User user) { + if (user == null) { + return MyPageResponse.builder().build(); + } + + Department department = user.getDepartment(); + College college = department != null ? department.getCollege() : null; + + return MyPageResponse.builder() + .nickname(user.getNickname()) + .provider(user.getProvider()) + .departmentId(department != null ? department.getId() : null) + .departmentName(department != null ? department.getName() : null) + .collegeId(college != null ? college.getId() : null) + .collegeName(college != null ? college.getName() : null) + .build(); + } } diff --git a/src/main/java/ssu/eatssu/domain/user/dto/UpdateDepartmentRequest.java b/src/main/java/ssu/eatssu/domain/user/dto/UpdateDepartmentRequest.java index c93bd8b1..fd4a606f 100644 --- a/src/main/java/ssu/eatssu/domain/user/dto/UpdateDepartmentRequest.java +++ b/src/main/java/ssu/eatssu/domain/user/dto/UpdateDepartmentRequest.java @@ -10,6 +10,6 @@ @AllArgsConstructor @NoArgsConstructor public class UpdateDepartmentRequest { - @Schema(description = "학과 이름", example = "소프트") - private String departmentName; + @Schema(description = "학과 id", example = "1") + private Long departmentId; } diff --git a/src/main/java/ssu/eatssu/domain/user/presentation/UserController.java b/src/main/java/ssu/eatssu/domain/user/presentation/UserController.java index 83f064a1..65338a03 100644 --- a/src/main/java/ssu/eatssu/domain/user/presentation/UserController.java +++ b/src/main/java/ssu/eatssu/domain/user/presentation/UserController.java @@ -27,9 +27,13 @@ import ssu.eatssu.domain.auth.security.CustomUserDetails; import ssu.eatssu.domain.partnership.dto.PartnershipResponse; import ssu.eatssu.domain.partnership.service.PartnershipService; +import ssu.eatssu.domain.review.service.ReviewServiceV2; import ssu.eatssu.domain.slice.dto.SliceResponse; import ssu.eatssu.domain.slice.service.SliceService; import ssu.eatssu.domain.user.dto.DepartmentResponse; +import ssu.eatssu.domain.user.dto.GetCollegeResponse; +import ssu.eatssu.domain.user.dto.GetDepartmentResponse; +import ssu.eatssu.domain.user.dto.MyMealReviewResponse; import ssu.eatssu.domain.user.dto.MyPageResponse; import ssu.eatssu.domain.user.dto.MyReviewDetail; import ssu.eatssu.domain.user.dto.NicknameUpdateRequest; @@ -48,6 +52,7 @@ public class UserController { private final UserService userService; private final SliceService sliceService; private final PartnershipService partnershipService; + private final ReviewServiceV2 reviewServiceV2; @Operation(summary = "이메일 중복 체크", description = """ 이메일 중복 체크 API 입니다.

@@ -180,4 +185,42 @@ public BaseResponse> getUserDepartmentPartnerships( public BaseResponse getDepartment(@AuthenticationPrincipal CustomUserDetails userDetails) { return BaseResponse.success(userService.getDepartment(userDetails)); } + + @Operation(summary = "내가 쓴 리뷰 리스트 조회", description = "내가 쓴 리뷰 리스트를 조회하는 API V2 입니다.") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "내가 쓴 리뷰 리스트 조회 성공"), + @ApiResponse(responseCode = "404", description = "존재하지 않는 유저", content = @Content(schema = @Schema(implementation = BaseResponse.class))) + }) + @GetMapping("/v2/reviews") + public BaseResponse> getMyReviews( + @Parameter(description = "마지막으로 조회된 reviewId값(첫 조회시 값 필요 없음)", in = ParameterIn.QUERY) @RequestParam(required = false) Long lastReviewId, + @ParameterObject @PageableDefault(size = 20, sort = "date", direction = Sort.Direction.DESC) Pageable pageable, + @AuthenticationPrincipal CustomUserDetails customUserDetails) { + SliceResponse myReviews = reviewServiceV2.findMyReviews(customUserDetails, + lastReviewId, + pageable); + return BaseResponse.success(myReviews); + } + + @Operation(summary = "단과대 조회", description = "숭실대학교 단과대학 들을 조회하는 API입니다.(토큰 불필요)") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "단과대 리스트 조회 성공"), + @ApiResponse(responseCode = "404", description = "존재하지 않는 단과대", content = @Content(schema = @Schema(implementation = BaseResponse.class))) + }) + @GetMapping("/lookup/colleges") + public BaseResponse> getColleges() { + List getCollegeResponses = userService.getCollegeList(); + return BaseResponse.success(getCollegeResponses); + } + + @Operation(summary = "단과대에 따른 학과 조회", description = "단과대학을 입력하면 단과대에 속한 숭실대학교 학과를 조회하는 API입니다.(토큰 불필요)") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "단과대 리스트 조회 성공"), + }) + @GetMapping("/lookup/departments") + public BaseResponse> getDepartments(@RequestParam Long collegeId) { + List getCollegeResponses = userService.getDepartmentList(collegeId); + return BaseResponse.success(getCollegeResponses); + } + } diff --git a/src/main/java/ssu/eatssu/domain/user/repository/UserRepository.java b/src/main/java/ssu/eatssu/domain/user/repository/UserRepository.java index ea4f9cf9..6170adc4 100644 --- a/src/main/java/ssu/eatssu/domain/user/repository/UserRepository.java +++ b/src/main/java/ssu/eatssu/domain/user/repository/UserRepository.java @@ -13,4 +13,6 @@ public interface UserRepository extends JpaRepository { Optional findByEmail(String email); Optional findByProviderId(String providerId); + + Optional findByNickname(String nickname); } diff --git a/src/main/java/ssu/eatssu/domain/user/service/UserService.java b/src/main/java/ssu/eatssu/domain/user/service/UserService.java index 8dd68dc8..9bd2f1e5 100644 --- a/src/main/java/ssu/eatssu/domain/user/service/UserService.java +++ b/src/main/java/ssu/eatssu/domain/user/service/UserService.java @@ -10,9 +10,13 @@ import ssu.eatssu.domain.auth.security.CustomUserDetails; import ssu.eatssu.domain.review.entity.Review; import ssu.eatssu.domain.user.config.UserProperties; +import ssu.eatssu.domain.user.department.entity.College; import ssu.eatssu.domain.user.department.entity.Department; +import ssu.eatssu.domain.user.department.persistence.CollegeRepository; import ssu.eatssu.domain.user.department.persistence.DepartmentRepository; import ssu.eatssu.domain.user.dto.DepartmentResponse; +import ssu.eatssu.domain.user.dto.GetCollegeResponse; +import ssu.eatssu.domain.user.dto.GetDepartmentResponse; import ssu.eatssu.domain.user.dto.MyPageResponse; import ssu.eatssu.domain.user.dto.NicknameUpdateRequest; import ssu.eatssu.domain.user.dto.UpdateDepartmentRequest; @@ -20,11 +24,13 @@ import ssu.eatssu.domain.user.repository.UserRepository; import ssu.eatssu.global.handler.response.BaseException; +import java.util.List; import java.util.UUID; import static ssu.eatssu.global.handler.response.BaseResponseStatus.DUPLICATE_NICKNAME; import static ssu.eatssu.global.handler.response.BaseResponseStatus.NOT_FOUND_DEPARTMENT; import static ssu.eatssu.global.handler.response.BaseResponseStatus.NOT_FOUND_USER; +import static ssu.eatssu.global.handler.response.BaseResponseStatus.VALIDATION_ERROR; @Slf4j @Service @@ -37,6 +43,7 @@ public class UserService { private final PasswordEncoder passwordEncoder; private final DepartmentRepository departmentRepository; private final UserProperties userProperties; + private final CollegeRepository collegeRepository; public User join(String email, OAuthProvider provider, String providerId) { String credentials = createCredentials(provider, providerId); @@ -59,7 +66,7 @@ public void updateNickname(CustomUserDetails userDetails, NicknameUpdateRequest public MyPageResponse findMyPage(CustomUserDetails userDetails) { User user = userRepository.findById(userDetails.getId()) .orElseThrow(() -> new BaseException(NOT_FOUND_USER)); - return new MyPageResponse(user.getNickname(), user.getProvider()); + return MyPageResponse.from(user); } public boolean withdraw(CustomUserDetails userDetails) { @@ -98,7 +105,7 @@ private String createCredentials(OAuthProvider provider, String providerId) { public void registerDepartment(UpdateDepartmentRequest request, CustomUserDetails userDetails) { User user = userRepository.findById(userDetails.getId()) .orElseThrow(() -> new BaseException(NOT_FOUND_USER)); - Department department = departmentRepository.findByName(request.getDepartmentName()) + Department department = departmentRepository.findById(request.getDepartmentId()) .orElseThrow(() -> new BaseException(NOT_FOUND_DEPARTMENT)); user.updateDepartment(department); @@ -107,8 +114,27 @@ public void registerDepartment(UpdateDepartmentRequest request, CustomUserDetail public DepartmentResponse getDepartment(CustomUserDetails userDetails) { User user = userRepository.findById(userDetails.getId()) .orElseThrow(() -> new BaseException(NOT_FOUND_USER)); - Department department = user.getDepartment(); - return new DepartmentResponse(department != null ? department.getName() : ""); + return DepartmentResponse.from(user.getDepartment()); + } + + public List getCollegeList() { + List colleges = collegeRepository.findAll(); + return colleges.stream().map(college -> GetCollegeResponse.builder() + .id(college.getId()) + .name(college.getName()) + .build()) + .toList(); + } + + public List getDepartmentList(Long collegeId) { + College college = collegeRepository.findById(collegeId) + .orElseThrow(() -> new BaseException(VALIDATION_ERROR)); + List departments = departmentRepository.findByCollege(college); + return departments.stream().map(department -> GetDepartmentResponse.builder() + .id(department.getId()) + .name(department.getName()) + .build()) + .toList(); } private boolean isForbiddenNickname(String nickname) { diff --git a/src/main/java/ssu/eatssu/global/handler/GlobalExceptionHandler.java b/src/main/java/ssu/eatssu/global/handler/GlobalExceptionHandler.java index 962fd1af..d05810e1 100644 --- a/src/main/java/ssu/eatssu/global/handler/GlobalExceptionHandler.java +++ b/src/main/java/ssu/eatssu/global/handler/GlobalExceptionHandler.java @@ -46,7 +46,9 @@ public class GlobalExceptionHandler extends ResponseEntityExceptionHandler { */ @ExceptionHandler(BaseException.class) public ResponseEntity> handleBaseException(BaseException e) { - slackErrorNotifier.notify(e); + if(BaseResponseStatus.sendSlackNotification(e.getStatus())){ + slackErrorNotifier.notify(e); + } return ResponseEntity.status(e.getStatus().getHttpStatus()).body(BaseResponse.fail(e.getStatus())); } diff --git a/src/main/java/ssu/eatssu/global/handler/response/BaseResponseStatus.java b/src/main/java/ssu/eatssu/global/handler/response/BaseResponseStatus.java index c17fc045..e7352315 100644 --- a/src/main/java/ssu/eatssu/global/handler/response/BaseResponseStatus.java +++ b/src/main/java/ssu/eatssu/global/handler/response/BaseResponseStatus.java @@ -59,6 +59,7 @@ public enum BaseResponseStatus { NOT_FOUND_DEPARTMENT(false, HttpStatus.NOT_FOUND, 40409, "해당 학과를 찾을 수 없습니다."), NOT_FOUND_PARTNERSHIP(false, HttpStatus.NOT_FOUND, 40410, "해당 제휴를 찾을 수 없습니다."), NOT_FOUND_PARTNERSHIP_RESTAURANT(false, HttpStatus.NOT_FOUND, 40411, "해당 제휴 식당을 찾을 수 없습니다."), + INVALID_NICKNAME(false,HttpStatus.NOT_FOUND,40412,"잘못된 닉네임입니다."), /** * 405 METHOD_NOT_ALLOWED 지원하지 않은 method 호출 @@ -105,4 +106,8 @@ public enum BaseResponseStatus { this.code = code; this.message = message; } + + public static boolean sendSlackNotification(BaseResponseStatus baseResponseStatus) { + return baseResponseStatus.httpStatus.is5xxServerError(); + } } diff --git a/src/main/resources/application-dev.yml b/src/main/resources/application-dev.yml index a5043661..20b92233 100644 --- a/src/main/resources/application-dev.yml +++ b/src/main/resources/application-dev.yml @@ -41,8 +41,8 @@ spring: jwt: secret: key: ${EATSSU_JWT_SECRET_DEV} - token-validity-in-seconds: 60 - refresh-token-validity-in-seconds: 180 + token-validity-in-seconds: 86400 + refresh-token-validity-in-seconds: 604800 #S3 cloud: diff --git a/src/main/resources/application-local.yml b/src/main/resources/application-local.yml index a85011b2..399b9d53 100644 --- a/src/main/resources/application-local.yml +++ b/src/main/resources/application-local.yml @@ -29,8 +29,8 @@ spring: jwt: secret: key: ${EATSSU_JWT_SECRET_LOCAL} - token-validity-in-seconds: 10 - refresh-token-validity-in-seconds: 30 + token-validity-in-seconds: 86400 + refresh-token-validity-in-seconds: 604800 cloud: aws: