Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<Partnership, Long> {
@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<Partnership> 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<PartnershipRestaurant> findRestaurantsWithMyPartnerships(
@Param("college") College college,
@Param("department") Department department
);

}
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,11 @@
import java.util.List;

public interface PartnershipRestaurantRepository extends JpaRepository<PartnershipRestaurant, Long> {
@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<PartnershipRestaurant> findAllWithDetails();
}
Original file line number Diff line number Diff line change
Expand Up @@ -115,14 +115,10 @@ public List<PartnershipResponse> 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());
}
}
Original file line number Diff line number Diff line change
@@ -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<Department, Long> {
Optional<Department> findByName(String name);

List<Department> findByCollege(College college);
}
26 changes: 20 additions & 6 deletions src/main/java/ssu/eatssu/domain/user/dto/DepartmentResponse.java
Original file line number Diff line number Diff line change
@@ -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();
}
}

10 changes: 10 additions & 0 deletions src/main/java/ssu/eatssu/domain/user/dto/GetCollegeResponse.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package ssu.eatssu.domain.user.dto;

import lombok.Builder;

@Builder
public record GetCollegeResponse(
Long id,
String name
) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package ssu.eatssu.domain.user.dto;

import lombok.Builder;

@Builder
public record GetDepartmentResponse(Long id,
String name) {
}
36 changes: 35 additions & 1 deletion src/main/java/ssu/eatssu/domain/user/dto/MyPageResponse.java
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,6 @@
@AllArgsConstructor
@NoArgsConstructor
public class UpdateDepartmentRequest {
@Schema(description = "학과 이름", example = "소프트")
private String departmentName;
@Schema(description = "학과 id", example = "1")
private Long departmentId;
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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 입니다.<br><br>
Expand Down Expand Up @@ -180,4 +185,42 @@ public BaseResponse<List<PartnershipResponse>> getUserDepartmentPartnerships(
public BaseResponse<DepartmentResponse> 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<SliceResponse<MyMealReviewResponse>> 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<MyMealReviewResponse> 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)))

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Swagger 문서의 getColleges API 응답 코드가 실제 구현과 다릅니다. userService.getCollegeList()collegeRepository.findAll()을 호출하며, 결과가 없으면 빈 리스트를 반환하고 예외를 던지지 않습니다. 따라서 404 응답은 발생하지 않습니다. 혼동을 피하기 위해 404 관련 @ApiResponse를 제거하는 것이 좋습니다.

})
@GetMapping("/lookup/colleges")
public BaseResponse<List<GetCollegeResponse>> getColleges() {
List<GetCollegeResponse> getCollegeResponses = userService.getCollegeList();
return BaseResponse.success(getCollegeResponses);
}

@Operation(summary = "단과대에 따른 학과 조회", description = "단과대학을 입력하면 단과대에 속한 숭실대학교 학과를 조회하는 API입니다.(토큰 불필요)")
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "단과대 리스트 조회 성공"),

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Swagger 문서의 getDepartments API 응답 명세가 충분하지 않습니다. userService.getDepartmentList(collegeId)는 존재하지 않는 collegeId에 대해 BaseException을 발생시킵니다. 이 경우 400 또는 404 오류가 발생할 수 있으므로, 해당 오류 응답을 @ApiResponses에 추가하여 API 사용자가 오류 상황을 명확히 인지할 수 있도록 해야 합니다.

            @ApiResponse(responseCode = "200", description = "단과대 리스트 조회 성공"),
            @ApiResponse(responseCode = "400", description = "존재하지 않는 단과대 ID", content = @Content(schema = @Schema(implementation = BaseResponse.class)))

})
@GetMapping("/lookup/departments")
public BaseResponse<List<GetDepartmentResponse>> getDepartments(@RequestParam Long collegeId) {
List<GetDepartmentResponse> getCollegeResponses = userService.getDepartmentList(collegeId);
return BaseResponse.success(getCollegeResponses);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,6 @@ public interface UserRepository extends JpaRepository<User, Long> {
Optional<User> findByEmail(String email);

Optional<User> findByProviderId(String providerId);

Optional<User> findByNickname(String nickname);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

새로 추가된 findByNickname 메소드가 코드베이스에서 사용되지 않고 있습니다. 사용되지 않는 코드는 혼란을 야기하고 유지보수성을 떨어뜨릴 수 있습니다. 이 메소드가 향후 사용될 계획이 없다면 제거하는 것을 고려해 보세요.

}
34 changes: 30 additions & 4 deletions src/main/java/ssu/eatssu/domain/user/service/UserService.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,21 +10,27 @@
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;
import ssu.eatssu.domain.user.entity.User;
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
Expand All @@ -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);
Expand All @@ -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) {
Expand Down Expand Up @@ -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);
Expand All @@ -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<GetCollegeResponse> getCollegeList() {
List<College> colleges = collegeRepository.findAll();
return colleges.stream().map(college -> GetCollegeResponse.builder()
.id(college.getId())
.name(college.getName())
.build())
.toList();
}

public List<GetDepartmentResponse> getDepartmentList(Long collegeId) {
College college = collegeRepository.findById(collegeId)
.orElseThrow(() -> new BaseException(VALIDATION_ERROR));

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

collegeId로 단과대를 찾지 못했을 때 VALIDATION_ERROR (400 Bad Request)를 반환하고 있습니다. 이는 클라이언트의 잘못된 '입력 값'보다는 '존재하지 않는 리소스'를 요청한 경우에 더 가깝습니다. 의미적으로 더 명확한 NOT_FOUND_COLLEGE (404 Not Found)를 사용하는 것이 RESTful API 설계 원칙에 더 부합합니다. (NOT_FOUND_COLLEGE static import가 필요할 수 있습니다.)

Suggested change
.orElseThrow(() -> new BaseException(VALIDATION_ERROR));
.orElseThrow(() -> new BaseException(NOT_FOUND_COLLEGE));

List<Department> departments = departmentRepository.findByCollege(college);
return departments.stream().map(department -> GetDepartmentResponse.builder()
.id(department.getId())
.name(department.getName())
.build())
.toList();
}

private boolean isForbiddenNickname(String nickname) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,9 @@ public class GlobalExceptionHandler extends ResponseEntityExceptionHandler {
*/
@ExceptionHandler(BaseException.class)
public ResponseEntity<BaseResponse<Void>> 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()));
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 호출
Expand Down Expand Up @@ -105,4 +106,8 @@ public enum BaseResponseStatus {
this.code = code;
this.message = message;
}

public static boolean sendSlackNotification(BaseResponseStatus baseResponseStatus) {
return baseResponseStatus.httpStatus.is5xxServerError();
}
}
4 changes: 2 additions & 2 deletions src/main/resources/application-dev.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
Loading