-
Notifications
You must be signed in to change notification settings - Fork 8
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[BE] feat: 학생 인증 메일 전송 잦은 재요청시 예외처리 (#466) #467
Changes from 12 commits
5df569c
10ec56e
d781540
e078907
1356bbc
af0550c
e7460e8
2087790
2df5dc3
b906f9b
0556b14
7d56a08
8a9bd43
71c574f
2986630
f896daf
5d463db
d022838
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,22 +1,33 @@ | ||
package com.festago.student.domain; | ||
|
||
import com.festago.common.domain.BaseTimeEntity; | ||
import static java.time.temporal.ChronoUnit.SECONDS; | ||
|
||
import com.festago.common.exception.ErrorCode; | ||
import com.festago.common.exception.InternalServerException; | ||
import com.festago.member.domain.Member; | ||
import com.festago.school.domain.School; | ||
import jakarta.persistence.Embedded; | ||
import jakarta.persistence.Entity; | ||
import jakarta.persistence.EntityListeners; | ||
import jakarta.persistence.FetchType; | ||
import jakarta.persistence.GeneratedValue; | ||
import jakarta.persistence.GenerationType; | ||
import jakarta.persistence.Id; | ||
import jakarta.persistence.JoinColumn; | ||
import jakarta.persistence.ManyToOne; | ||
import jakarta.persistence.OneToOne; | ||
import jakarta.validation.constraints.NotNull; | ||
import java.time.LocalDateTime; | ||
import org.springframework.data.annotation.LastModifiedDate; | ||
import org.springframework.data.jpa.domain.support.AuditingEntityListener; | ||
import org.springframework.util.StringUtils; | ||
|
||
|
||
@Entity | ||
public class StudentCode extends BaseTimeEntity { | ||
@EntityListeners(AuditingEntityListener.class) | ||
public class StudentCode { | ||
|
||
private static final int MIN_REQUEST_TERM_SECONDS = 30; | ||
|
||
@Id | ||
@GeneratedValue(strategy = GenerationType.IDENTITY) | ||
|
@@ -29,24 +40,31 @@ public class StudentCode extends BaseTimeEntity { | |
private School school; | ||
|
||
@OneToOne(fetch = FetchType.LAZY) | ||
@JoinColumn(unique = true) | ||
private Member member; | ||
|
||
private String username; | ||
|
||
@NotNull | ||
@LastModifiedDate | ||
private LocalDateTime issuedAt; | ||
|
||
protected StudentCode() { | ||
} | ||
|
||
public StudentCode(VerificationCode code, School school, Member member, String username) { | ||
this(null, code, school, member, username); | ||
this(null, code, school, member, username, null); | ||
} | ||
|
||
public StudentCode(Long id, VerificationCode code, School school, Member member, String username) { | ||
public StudentCode(Long id, VerificationCode code, School school, Member member, String username, | ||
LocalDateTime issuedAt) { | ||
validate(username); | ||
this.id = id; | ||
this.code = code; | ||
this.school = school; | ||
this.member = member; | ||
this.username = username; | ||
this.issuedAt = issuedAt; | ||
} | ||
|
||
private void validate(String username) { | ||
|
@@ -59,6 +77,16 @@ private void validate(String username) { | |
} | ||
} | ||
|
||
public boolean canReissue(LocalDateTime currentTime) { | ||
return SECONDS.between(issuedAt, currentTime) > MIN_REQUEST_TERM_SECONDS; | ||
} | ||
Comment on lines
+79
to
+81
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. createdAt으로 비교를 하려 했었는데, issuedAt은 createdAt과 동일한 값을 가지는데, 해당 필드가 비즈니스 로직에 사용되기도 하고, 이정도의 중복은 괜찮다고 생각해 issuedAt 칼럼을 추가했습니다! 이에 대한 의견 남겨주세요! There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. StudentCode가 상속하고 있는 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 2df5dc3 반영 완료! There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 이렇게 해결해도 되고 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. delete-and-insert 대신 update를 채택하면서 isseudAt 칼럼이 생성일 기준이 아닌 수정일 기준으로 바뀌었어요! (7d56a08) 저는 이번 경우에는 issuedAt을 활용하는 것이 더 좋아보여요. 이번과 별개로 BaseTimeEntity를 protected로 여는 것에 대한 사이드이펙트는 저도 생각나는게 없네요!! There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 그러네용 도메인적으로 쓸꺼면 따로 만드는게 좋다고 생각되네요 |
||
|
||
public void reissue(VerificationCode code, School school, String username) { | ||
this.code = code; | ||
this.school = school; | ||
this.username = username; | ||
} | ||
|
||
public Long getId() { | ||
return id; | ||
} | ||
|
@@ -78,4 +106,8 @@ public Member getMember() { | |
public String getUsername() { | ||
return username; | ||
} | ||
|
||
public LocalDateTime getIssuedAt() { | ||
return issuedAt; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
-- issued_at 칼럼 추가 (NOT NULL) | ||
alter table student_code | ||
add column issued_at datetime(6) not null | ||
default '1999-12-31 00:00:00'; | ||
|
||
alter table student_code | ||
alter column issued_at drop default; | ||
|
||
-- 기존 created_at updated_at 삭제 | ||
alter table student_code | ||
drop column created_at; | ||
|
||
alter table student_code | ||
drop column updated_at; | ||
|
||
-- StudentCode의 member_id UNIQUE 제약조건 추가 | ||
create index temp_member_index | ||
on student_code (member_id); | ||
|
||
drop index fk_student_code__member on student_code; | ||
|
||
create unique index fk_student_code__member | ||
on student_code (member_id); | ||
|
||
drop index temp_member_index on student_code; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 요거 실행 시켜보면 fk_student_code__member 가 없다고 뜨는 것 같아요!!
요거 하나만 적어줘도 외래키에 대한 보조 인덱스 생성하면서 유니크 제약 조건까지 걸 수 있을 것 같아요 !! There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 완전 HIP 한데요? 아래는 V1.sql 중 일부인데 alter table student_code
add constraint fk_student_code__member
foreign key (member_id)
references member (id); 요러코롬 StudentCode 테이블에 이번에 해당 인덱스를 UNIQUE를 추가하려했는데
이 순서로 진행했었습니다!! 그런데 푸우가 제안해주신 방식으로 하면 그럴 필요가 없어지겠네요! There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
이 부분은 제 로컬 DB에선 잘 실행되었고, 푸우 DB에선 실행되지 않은 걸 보니 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
HTTP 응답에는 다음과 같은 코드가 있어요!
https://developer.mozilla.org/ko/docs/Web/HTTP/Status/429
새로운 Exception을 만들어서 처리해도 좋을 것 같네요!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
오... 이런 상태코드가 있었군요 없는게없는...
그런데 이전에 409 Conflict 상태코드를 사용할 것이냐 말 것이냐 논의가 길게 이어졌던 것 같은데
결론은 그냥 400 BadRequest로 에러를 정형화하자. 로 결론이 났던 것 같아요!
그래서 저는 이번 케이스도 별도의 Exception으로 처리하지 않고 정형화된 Exception을 활용하는 것도 나쁘지 않아보여요!
별개의 Exception을 만들어 429 보내기 vs 기존 BadReqeustException 써서 400 보내기
어떤게 좋아보이시나요?
@seokjin8678 @BGuga @carsago
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
저는 409 conflict를 쓰냐 마냐 상황에서는, 400을 보내는것에 기울었던걸로 기억해요. 왜냐하면 409라는 스펙이 정의가 되어있음에도, 거의 사용되어 있지 않기에(저번에 이 부분이 궁금해서 토스 API 명세를 봤을때도 존재하지 않더군요. 물론 이걸 선호하는 서비스도 존재할 거에요) 오히려 bad Request와 메시지를 통하는게 클라이언트 입장에서 더 혼란을 줄이고 명확할 수 있다는 점이였습니다.
다만 저는 too many request는 은근 쓰이고, 그 네이밍 자체로 명확해서 괜찮다는 의견도 있으면서, 동시에 400과 메시지로 커버해줘도 안될 이유도 없다.. 솔직히 큰 차이 없다고 느껴서 다른 분들에게 더 명확한 근거가 있다면 그 쪽에 따르거나 다수결에 합류하는 방식으로 갈 것 같아요.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
저도 429 는 원인이 명확하다 생각해서 써도 괜찮을 것 같아요
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
429로 땅땅땅 👨🏻⚖️