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
2 changes: 1 addition & 1 deletion .github/PULL_REQUEST_TEMPLATE.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
## #️⃣ Issue Number

<!--- ex) #이슈번호, #이슈번호 -->

- resolved #
## 📝 요약(Summary)

<!--- 변경 사항 및 관련 이슈에 대해 간단하게 작성해주세요. 어떻게보다 무엇을 왜 수정했는지 설명해주세요. -->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import org.springframework.web.util.UriComponentsBuilder;
import ssu.eatssu.domain.auth.dto.AppleKeys;
import ssu.eatssu.domain.auth.dto.OAuthInfo;
import ssu.eatssu.domain.user.repository.UserRepository;
import ssu.eatssu.global.handler.response.BaseException;

import java.math.BigInteger;
Expand All @@ -32,6 +33,7 @@
public class SystemAppleAuthenticator implements AppleAuthenticator {

private final RestTemplate restTemplate;
private final UserRepository userRepository;

public OAuthInfo getOAuthInfoByIdentityToken(String identityToken) {
PublicKey publicKey = generatePublicKey(identityToken);
Expand All @@ -42,30 +44,34 @@ public OAuthInfo getOAuthInfoByIdentityToken(String identityToken) {
* 애플 로그인 - PublicKey 를 통해 유저 정보(providerId, email) 조회
*/
private OAuthInfo getOAuthInfoByPublicKey(String identityToken, PublicKey publicKey) {
// identityToken 에서 publicKey 서명을 통해 Claims 를 추출한다.
Claims claims = Jwts.parserBuilder()
.setSigningKey(publicKey)
.build()
.parseClaimsJws(identityToken)
.getBody();
Claims claims;
try {
claims = Jwts.parserBuilder()
.setSigningKey(publicKey)
.build()
.parseClaimsJws(identityToken)
.getBody();
} catch (ExpiredJwtException exception) {
throw new BaseException(INVALID_IDENTITY_TOKEN);
}
Comment on lines +48 to +56

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

[Reviewer, 2024-01-01] ExpiredJwtException뿐만 아니라 SignatureException, MalformedJwtException 등 다른 JWT 관련 예외도 처리할 수 있도록 JwtException 및 IllegalArgumentException을 캐치하는 것이 안전합니다.

Suggested change
try {
claims = Jwts.parserBuilder()
.setSigningKey(publicKey)
.build()
.parseClaimsJws(identityToken)
.getBody();
} catch (ExpiredJwtException exception) {
throw new BaseException(INVALID_IDENTITY_TOKEN);
}
try {
claims = Jwts.parserBuilder()
.setSigningKey(publicKey)
.build()
.parseClaimsJws(identityToken)
.getBody();
} catch (JwtException | IllegalArgumentException exception) {
throw new BaseException(INVALID_IDENTITY_TOKEN);
}


Object emailObj = claims.get("email");
Object providerIdObj = claims.get("sub");

if (providerIdObj == null) {
throw new BaseException(NOT_FOUND_PROVIDER_ID);
}

String providerId = providerIdObj.toString();

// email 없는 경우 → Apple 재로그인 케이스 (Apple 스펙상 최초 로그인 시에만 email 포함)
if (emailObj == null) {
throw new BaseException(NOT_FOUND_EMAIL);
return userRepository.findByProviderId(providerId)
.map(user -> new OAuthInfo(user.getEmail(), providerId))
.orElseThrow(() -> new BaseException(NOT_FOUND_APPLE_EMAIL_NEW_USER));
}

try {
String email = emailObj.toString();
String providerId = providerIdObj.toString();
return new OAuthInfo(email, providerId);
} catch (ExpiredJwtException exception) {
throw new BaseException(INVALID_IDENTITY_TOKEN);
}
return new OAuthInfo(emailObj.toString(), providerId);
}

private PublicKey generatePublicKey(String identityToken) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import lombok.Getter;
import ssu.eatssu.domain.partnership.entity.Partnership;
import ssu.eatssu.domain.partnership.entity.PartnershipRestaurant;
import ssu.eatssu.domain.partnership.entity.PeriodType;

import java.time.LocalDate;

Expand All @@ -18,6 +19,7 @@ public class PartnershipInfo {
private String description;
private LocalDate startDate;
private LocalDate endDate;
private PeriodType periodType;

public static PartnershipInfo fromEntity(Partnership partnership,
PartnershipRestaurant restaurant,
Expand All @@ -27,6 +29,7 @@ public static PartnershipInfo fromEntity(Partnership partnership,
.description(partnership.getDescription())
.startDate(partnership.getStartDate())
.endDate(partnership.getEndDate())
.periodType(partnership.getPeriodType())

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

high

[Reviewer, 2024-01-01] 단과대 및 학과명을 다국어로 지원하기 위해, fromEntity 메서드에 Language 파라미터를 추가하고 collegeName 설정 시 getNameByLanguage(language)를 호출하도록 수정해야 합니다.

.collegeName(partnership.getPartnershipCollege() == null && partnership.getPartnershipDepartment() == null
? "총학생회"
: (partnership.getPartnershipCollege() != null ? partnership.getPartnershipCollege()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import lombok.Getter;
import ssu.eatssu.domain.partnership.entity.PartnershipRestaurant;
import ssu.eatssu.domain.partnership.entity.RestaurantType;
import ssu.eatssu.domain.user.entity.Language;

import java.util.List;
import java.util.stream.Collectors;
Expand All @@ -19,7 +20,7 @@ public class PartnershipResponse {
private RestaurantType restaurantType;
private List<PartnershipInfo> partnershipInfos;

public static PartnershipResponse fromEntity(PartnershipRestaurant restaurant, Long userId) {
public static PartnershipResponse fromEntity(PartnershipRestaurant restaurant, Long userId, Language language) {
boolean isLiked = restaurant.getLikes().stream()
.anyMatch(like -> like.getUser().getId().equals(userId));

Expand All @@ -30,12 +31,11 @@ public static PartnershipResponse fromEntity(PartnershipRestaurant restaurant, L
.collect(Collectors.toList());

return PartnershipResponse.builder()
.storeName(restaurant.getStoreName())
.storeName(restaurant.getStoreNameByLanguage(language))
.longitude(restaurant.getLongitude())
.latitude(restaurant.getLatitude())
.restaurantType(restaurant.getRestaurantType())
.partnershipInfos(infos)
.build();
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.EnumType;
import jakarta.persistence.Enumerated;
import jakarta.persistence.FetchType;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
Expand Down Expand Up @@ -39,6 +41,12 @@ public class Partnership {

@Column(name = "end_date", nullable = false)
private LocalDate endDate;

@Builder.Default
@Enumerated(EnumType.STRING)
@Column(name = "period_type", nullable = false)
private PeriodType periodType = PeriodType.NORMAL;

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "partnership_college_id")
private College partnershipCollege;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,16 @@
import lombok.Getter;
import lombok.NoArgsConstructor;
import org.hibernate.annotations.BatchSize;
import ssu.eatssu.domain.user.entity.Language;
import ssu.eatssu.global.i18n.Localizable;

import java.util.ArrayList;
import java.util.List;

@Entity
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class PartnershipRestaurant {
public class PartnershipRestaurant implements Localizable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "partnershipRestaurant_id")
Expand All @@ -34,12 +36,26 @@ public class PartnershipRestaurant {

@Column(name = "latitude", nullable = false)
private Double latitude; // 위도 == y축
@Column(name = "store_name", nullable = false)
private String storeName;
@Column(name = "store_name_ko", nullable = false)
private String storeNameKo;
@Column(name = "store_name_en")
private String storeNameEn;
@Column(name = "store_name_ja")
private String storeNameJa;
@Column(name = "store_name_vi")
private String storeNameVi;

@OneToMany(mappedBy = "partnershipRestaurant")
@BatchSize(size = 20)
private List<PartnershipLike> likes = new ArrayList<>();
@OneToMany(mappedBy = "partnershipRestaurant", cascade = CascadeType.ALL, orphanRemoval = true)
private List<Partnership> partnerships = new ArrayList<>();

public String getStoreName() {
return storeNameKo;
}

public String getStoreNameByLanguage(Language language) {
return getLocalizedValue(language, storeNameKo, storeNameEn, storeNameJa, storeNameVi);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package ssu.eatssu.domain.partnership.entity;

public enum PeriodType {
NORMAL,
FESTIVAL
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
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.entity.Language;
import ssu.eatssu.domain.user.entity.User;
import ssu.eatssu.domain.user.repository.UserRepository;
import ssu.eatssu.global.handler.response.BaseException;
Expand Down Expand Up @@ -52,19 +53,22 @@ public void createPartnership(CreatePartnershipRequest request) {
NOT_FOUND_PARTNERSHIP_RESTAURANT));
Partnership partnership = request.toPartnershipEntity(partnershipRestaurant);

College college = collegeRepository.findByName(request.getCollege())
College college = collegeRepository.findByNameKo(request.getCollege())
.orElseThrow(() -> new BaseException(NOT_FOUND_COLLEGE));
partnership.setPartnershipCollege(college);
Department department = departmentRepository.findByName(request.getDepartment())
Department department = departmentRepository.findByNameKo(request.getDepartment())
.orElseThrow(() -> new BaseException(NOT_FOUND_DEPARTMENT));
partnership.setPartnershipDepartment(department);
partnershipRepository.save(partnership);
}

public List<PartnershipResponse> getAllPartnerships(CustomUserDetails customUserDetails) {
Language language = findUserByUserDetails(customUserDetails).getLanguage();

return partnerShipRestaurantRepository.findAllWithDetails().stream()
.map(restaurant -> PartnershipResponse.fromEntity(restaurant,
customUserDetails.getId()))
customUserDetails.getId(),
language))
.collect(Collectors.toList());
}

Expand Down Expand Up @@ -100,8 +104,7 @@ public void togglePartnershipLike(Long partnershipId, CustomUserDetails userDeta
}

public List<PartnershipResponse> getUserLikedPartnerships(CustomUserDetails customUserDetails) {
User user = userRepository.findById(customUserDetails.getId())
.orElseThrow(() -> new BaseException(NOT_FOUND_USER));
User user = findUserByUserDetails(customUserDetails);

List<PartnershipLike> likes = partnershipLikeRepository.findAllByUserWithDetails(user);

Expand All @@ -111,14 +114,14 @@ public List<PartnershipResponse> getUserLikedPartnerships(CustomUserDetails cust
return restaurant.getPartnerships()
.stream()
.map(partnership -> PartnershipResponse.fromEntity(restaurant,
customUserDetails.getId()));
customUserDetails.getId(),
user.getLanguage()));
}).collect(Collectors.toList());
}


public List<PartnershipResponse> getUserDepartmentPartnerships(CustomUserDetails customUserDetails) {
User user = userRepository.findById(customUserDetails.getId())
.orElseThrow(() -> new BaseException(NOT_FOUND_USER));
User user = findUserByUserDetails(customUserDetails);

Department department = user.getDepartment();
if (department == null) {
Expand All @@ -130,7 +133,13 @@ public List<PartnershipResponse> getUserDepartmentPartnerships(CustomUserDetails
.findRestaurantsWithMyPartnerships(college, department)
.stream()
.map(partnershipRestaurant -> PartnershipResponse.fromEntity(partnershipRestaurant,
customUserDetails.getId()))
customUserDetails.getId(),
user.getLanguage()))
.collect(Collectors.toList());
}

private User findUserByUserDetails(CustomUserDetails userDetails) {
return userRepository.findById(userDetails.getId())
.orElseThrow(() -> new BaseException(NOT_FOUND_USER));
}
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
package ssu.eatssu.domain.review.dto;

import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.Valid;
import jakarta.validation.constraints.Max;
import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.NotNull;
import lombok.AllArgsConstructor;
import lombok.Getter;
import ssu.eatssu.domain.menu.entity.Menu;
Expand All @@ -16,10 +18,13 @@
@AllArgsConstructor
public class CreateMenuReviewRequestV2 {
@Schema(description = "평점", example = "5")
@NotNull
@Min(1)
@Max(5)
private Integer rating;

@NotNull
@Valid
private MenuLikeRequest menuLike;

@Schema(description = "한줄평", example = "이 메뉴 진짜 맛있어요!")
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package ssu.eatssu.domain.review.dto;

import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotNull;
import lombok.AllArgsConstructor;
import lombok.Getter;

Expand All @@ -9,6 +10,7 @@
@AllArgsConstructor
public class MenuLikeRequest {
@Schema(description = "메뉴 식별자", example = "123")
@NotNull
private Long menuId;
@Schema(description = "좋아요 선택", example = "좋아요 : true (기본값은 false)")
private Boolean isLike;
Expand Down
Loading
Loading