Skip to content

Commit ca72d8a

Browse files
committed
feat: Member 엔티티에 email 추가
1 parent a220c5e commit ca72d8a

File tree

12 files changed

+111
-60
lines changed

12 files changed

+111
-60
lines changed

src/main/java/eatda/client/oauth/OauthMemberInformation.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
public record OauthMemberInformation(long socialId, String email, String nickname) {
1010

1111
public Member toMember() {
12-
return new Member(Long.toString(socialId), nickname);
12+
return new Member(Long.toString(socialId), email, nickname);
1313
}
1414
}
1515

src/main/java/eatda/domain/member/Member.java

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,18 @@
2020
@NoArgsConstructor(access = AccessLevel.PROTECTED)
2121
public class Member {
2222

23+
private static final String EMAIL_REGEX = "^[a-zA-Z0-9_+&*-]+(?:\\.[a-zA-Z0-9_+&*-]+)*@(?:[a-zA-Z0-9-]+\\.)+[a-zA-Z]{2,7}$";
24+
2325
@Id
2426
@GeneratedValue(strategy = GenerationType.IDENTITY)
2527
private Long id;
2628

2729
@Column(name = "social_id", unique = true, nullable = false)
2830
private String socialId;
2931

32+
@Column(name = "email", unique = true, nullable = false)
33+
private String email;
34+
3035
@Column(name = "nickname")
3136
private String nickname;
3237

@@ -36,19 +41,22 @@ public class Member {
3641
@Column(name = "opt_in_marketing")
3742
private Boolean optInMarketing;
3843

39-
public Member(String socialId, String nickname) {
44+
public Member(String socialId, String email, String nickname) {
4045
validateSocialId(socialId);
46+
validateEmail(email);
4147
this.socialId = socialId;
48+
this.email = email;
4249
this.nickname = nickname;
4350
}
4451

4552
public Member(
4653
String socialId,
54+
String email,
4755
String nickname,
4856
String mobilePhoneNumber,
4957
Boolean optInMarketing
5058
) {
51-
this(socialId, nickname);
59+
this(socialId, email, nickname);
5260
validateOptInMarketing(optInMarketing);
5361
this.mobilePhoneNumber = new MobilePhoneNumber(mobilePhoneNumber);
5462
this.optInMarketing = optInMarketing;
@@ -67,6 +75,12 @@ private void validateSocialId(String socialId) {
6775
}
6876
}
6977

78+
private void validateEmail(String email) {
79+
if (email == null || !email.matches(EMAIL_REGEX)) {
80+
throw new BusinessException(BusinessErrorCode.INVALID_EMAIL);
81+
}
82+
}
83+
7084
private void validateOptInMarketing(Boolean optInMarketing) {
7185
if (optInMarketing == null) {
7286
throw new BusinessException(BusinessErrorCode.INVALID_MARKETING_CONSENT);

src/main/java/eatda/exception/BusinessErrorCode.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ public enum BusinessErrorCode {
1414
INVALID_SOCIAL_ID("MEM005", "소셜 ID는 필수입니다."),
1515
DUPLICATE_NICKNAME("MEM006", "이미 사용 중인 닉네임입니다."),
1616
DUPLICATE_PHONE_NUMBER("MEM007", "이미 사용 중인 전화번호입니다."),
17+
INVALID_EMAIL("MEM008", "유효하지 않은 이메일 형식입니다."),
18+
1719

1820
// Store
1921
INVALID_STORE_CATEGORY("STO001", "유효하지 않은 매장 카테고리입니다."),
@@ -54,7 +56,8 @@ public enum BusinessErrorCode {
5456
INVALID_IMAGE_TYPE("CLIENT010", "지원하지 않는 이미지 형식입니다.", HttpStatus.BAD_REQUEST),
5557
FILE_UPLOAD_FAILED("SERVER002", "파일 업로드에 실패했습니다.", HttpStatus.INTERNAL_SERVER_ERROR),
5658
FILE_URL_GENERATION_FAILED("SERVER003", "파일 URL 생성에 실패했습니다.", HttpStatus.INTERNAL_SERVER_ERROR),
57-
PRESIGNED_URL_GENERATION_FAILED("SERVER004", "Presigned URL 생성에 실패했습니다.", HttpStatus.INTERNAL_SERVER_ERROR);
59+
PRESIGNED_URL_GENERATION_FAILED("SERVER004", "Presigned URL 생성에 실패했습니다.", HttpStatus.INTERNAL_SERVER_ERROR),
60+
;
5861

5962
private final String code;
6063
private final String message;

src/main/resources/db/migration/V1__init.sql

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ CREATE TABLE `store`
1818
CREATE TABLE `member`
1919
(
2020
`id` BIGINT NOT NULL AUTO_INCREMENT,
21+
`email` VARCHAR(255) NOT NULL,
2122
`social_id` VARCHAR(255) NOT NULL,
2223
`nickname` VARCHAR(255) NULL,
2324
`phone_number` VARCHAR(255) NULL COMMENT '(`-` 없이))',

src/main/resources/db/seed/dev/V2__dev_init_data.sql

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
1-
INSERT INTO member (id, social_id, nickname, phone_number, opt_in_marketing)
2-
VALUES (1, 123456789, '이승로', '01012345678', true),
3-
(2, 987654321, '이충안', '01087654321', false),
4-
(3, 456789123, '장수빈', '01045678912', true),
5-
(4, 789123456, '서준환', '01078912345', true),
6-
(5, 321251287, '신민선', '01034574568', false),
7-
(6, 324569987, '박희수', '01043609998', false),
8-
(7, 323487985, '하아얀', '01065083298', false);
1+
INSERT INTO member (id, social_id, email, nickname, phone_number, opt_in_marketing)
2+
VALUES (1, 123456789, '[email protected]', '이승로', '01012345678', true),
3+
(2, 987654321, '[email protected]', '이충안', '01087654321', false),
4+
(3, 456789123, '[email protected]', '장수빈', '01045678912', true),
5+
(4, 789123456, '[email protected]', '서준환', '01078912345', true),
6+
(5, 321251287, '[email protected]', '신민선', '01034574568', false),
7+
(6, 324569987, '[email protected]', '박희수', '01043609998', false),
8+
(7, 323487985, '[email protected]', '하아얀', '01065083298', false);
99

1010
INSERT INTO store (id, name, category, latitude, longitude,
1111
address, phone_number, image_url, open_time, close_time,

src/main/resources/db/seed/local/V2__local_init_data.sql

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
INSERT INTO member (id, social_id, nickname, phone_number, opt_in_marketing)
2-
VALUES (1, 123456789, '이승로', '01012345678', true),
3-
(3, 456789123, '장수빈', '01045678912', true),
4-
(4, 789123456, '서준환', '01078912345', true),
5-
(5, 321251287, '신민선', '01034574568', false),
6-
(6, 324569987, '박희수', '01043609998', false),
7-
(7, 323487985, '하아얀', '01065083298', false);
1+
INSERT INTO member (id, social_id, email, nickname, phone_number, opt_in_marketing)
2+
VALUES (1, 123456789, '[email protected]', '이승로', '01012345678', true),
3+
(3, 456789123, '[email protected]', '장수빈', '01045678912', true),
4+
(4, 789123456, '[email protected]', '서준환', '01078912345', true),
5+
(5, 321251287, '[email protected]', '신민선', '01034574568', false),
6+
(6, 324569987, '[email protected]', '박희수', '01043609998', false),
7+
(7, 323487985, '[email protected]', '하아얀', '01065083298', false);
88

99
INSERT INTO store (id, name, category, latitude, longitude,
1010
address, phone_number, image_url, open_time, close_time,

src/test/java/eatda/controller/BaseControllerTest.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -87,12 +87,14 @@ protected final RequestSpecification given() {
8787
}
8888

8989
protected final String accessToken() {
90-
Member member = memberGenerator.generate(Long.toString(DEFAULT_OAUTH_MEMBER_INFO.socialId()));
90+
Member member = memberGenerator.generateByEmail(Long.toString(DEFAULT_OAUTH_MEMBER_INFO.socialId()),
91+
9192
return jwtManager.issueAccessToken(member.getId());
9293
}
9394

9495
protected final String refreshToken() {
95-
Member member = memberGenerator.generate(Long.toString(DEFAULT_OAUTH_MEMBER_INFO.socialId()));
96+
Member member = memberGenerator.generateByEmail(Long.toString(DEFAULT_OAUTH_MEMBER_INFO.socialId()),
97+
9698
return jwtManager.issueRefreshToken(member.getId());
9799
}
98100

src/test/java/eatda/controller/member/MemberControllerTest.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ class CheckNickname {
2727
@Test
2828
void 중복된_닉네임을_확인할_수_있다() {
2929
String existingNickname = "existing-nickname";
30-
memberGenerator.generateRegisteredMember("123", existingNickname, "01012345678");
30+
memberGenerator.generateRegisteredMember(existingNickname, "[email protected]", "123", "01012345678");
3131

3232
given()
3333
.header(HttpHeaders.AUTHORIZATION, accessToken())
@@ -54,7 +54,7 @@ class CheckPhoneNumber {
5454
@Test
5555
void 중복된_전화번호를_확인할_수_있다() {
5656
String existingPhoneNumber = "01012345678";
57-
memberGenerator.generateRegisteredMember("123", "nickname", existingPhoneNumber);
57+
memberGenerator.generateRegisteredMember("nickname", "[email protected]", "123", existingPhoneNumber);
5858
given()
5959
.header(HttpHeaders.AUTHORIZATION, accessToken())
6060
.queryParam("phoneNumber", existingPhoneNumber)

src/test/java/eatda/domain/bookmark/BookmarkTest.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ class CreateBookmark {
2121

2222
@Test
2323
void 정상적인_멤버와_가게로_북마크를_생성한다() {
24-
Member member = new Member("socialId123", "nickname");
24+
Member member = new Member("socialId123", "[email protected]", "nickname");
2525
Store store = new Store(
2626
"가게명",
2727
"양식",
@@ -65,7 +65,7 @@ class CreateBookmark {
6565

6666
@Test
6767
void 가게가_null이면_예외를_던진다() {
68-
Member member = new Member("socialId123", "nickname");
68+
Member member = new Member("socialId123", "[email protected]", "nickname");
6969

7070
BusinessException exception = assertThrows(BusinessException.class, () -> new Bookmark(member, null));
7171

src/test/java/eatda/domain/member/MemberTest.java

Lines changed: 34 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,14 @@
44
import static org.junit.jupiter.api.Assertions.assertAll;
55
import static org.junit.jupiter.api.Assertions.assertThrows;
66

7-
import eatda.enums.InterestArea;
87
import eatda.exception.BusinessErrorCode;
98
import eatda.exception.BusinessException;
109
import org.junit.jupiter.api.DisplayName;
1110
import org.junit.jupiter.api.Nested;
1211
import org.junit.jupiter.api.Test;
12+
import org.junit.jupiter.params.ParameterizedTest;
13+
import org.junit.jupiter.params.provider.NullAndEmptySource;
14+
import org.junit.jupiter.params.provider.ValueSource;
1315

1416
class MemberTest {
1517

@@ -18,13 +20,15 @@ class MemberTest {
1820
class CreateOauthMember {
1921

2022
@Test
21-
void socialId와_nickname만으로_생성_시_나머지_필드는_null_상태이다() {
23+
void socialId_email_nickname만으로_생성_시_나머지_필드는_null_상태이다() {
2224
String socialId = "oauth-user-id";
25+
String email = "[email protected]";
2326

24-
Member member = new Member(socialId, "nickname");
27+
Member member = new Member(socialId, email, "nickname");
2528

2629
assertAll(
2730
() -> assertThat(member.getSocialId()).isEqualTo(socialId),
31+
() -> assertThat(member.getEmail()).isEqualTo(email),
2832
() -> assertThat(member.getNickname()).isNotNull(),
2933
() -> assertThat(member.getMobilePhoneNumber()).isNull(),
3034
() -> assertThat(member.getOptInMarketing()).isNull()
@@ -34,11 +38,25 @@ class CreateOauthMember {
3438
@Test
3539
void socialId가_null이면_예외가_발생한다() {
3640
String socialId = null;
41+
String email = "[email protected]";
3742

38-
BusinessException exception = assertThrows(BusinessException.class, () -> new Member(socialId, "nickname"));
43+
BusinessException exception = assertThrows(BusinessException.class,
44+
() -> new Member(socialId, email, "nickname"));
3945

4046
assertThat(exception.getErrorCode()).isEqualTo(BusinessErrorCode.INVALID_SOCIAL_ID);
4147
}
48+
49+
@ParameterizedTest
50+
@NullAndEmptySource
51+
@ValueSource(strings = {"abc.com", "invalid-email", "[email protected]", "@example.com"})
52+
void email이_null이거나_유효하지_않으면_예외가_발생한다(String invalidEmail) {
53+
String socialId = "oauth-user-id";
54+
55+
BusinessException exception = assertThrows(BusinessException.class,
56+
() -> new Member(socialId, invalidEmail, "nickname"));
57+
58+
assertThat(exception.getErrorCode()).isEqualTo(BusinessErrorCode.INVALID_EMAIL);
59+
}
4260
}
4361

4462
@Nested
@@ -48,14 +66,16 @@ class CreateMemberTest {
4866
@Test
4967
void 모든_정보가_정상적일_때_회원을_생성한다() {
5068
String socialId = "test-social-id-123";
69+
String email = "[email protected]";
5170
String nickname = "맛있는녀석들-32";
5271
String mobilePhoneNumber = "01012345678";
5372
Boolean optInMarketing = true;
5473

55-
Member member = new Member(socialId, nickname, mobilePhoneNumber, optInMarketing);
74+
Member member = new Member(socialId, email, nickname, mobilePhoneNumber, optInMarketing);
5675

5776
assertAll(
5877
() -> assertThat(member.getSocialId()).isEqualTo(socialId),
78+
() -> assertThat(member.getEmail()).isEqualTo(email),
5979
() -> assertThat(member.getNickname()).isEqualTo(nickname),
6080
() -> assertThat(member.getMobilePhoneNumber().getValue()).isEqualTo(mobilePhoneNumber),
6181
() -> assertThat(member.isOptInMarketing()).isTrue()
@@ -65,11 +85,12 @@ class CreateMemberTest {
6585
@Test
6686
void 선택적_필드가_null이어도_멤버를_생성한다() {
6787
String socialId = "test-social-id-123";
88+
String email = "[email protected]";
6889
String nickname = null;
6990
String mobilePhoneNumber = null;
7091
Boolean optInMarketing = false;
7192

72-
Member member = new Member(socialId, nickname, mobilePhoneNumber, optInMarketing);
93+
Member member = new Member(socialId, email, nickname, mobilePhoneNumber, optInMarketing);
7394

7495
assertAll(
7596
() -> assertThat(member.getNickname()).isNull(),
@@ -81,13 +102,13 @@ class CreateMemberTest {
81102
@Test
82103
void 가입_완료_시_마케팅_동의_여부가_null이면_예외를_던진다() {
83104
String socialId = "test-social-id-123";
105+
String email = "[email protected]";
84106
String nickname = "맛있는녀석들-32";
85107
String mobilePhoneNumber = "01012345678";
86-
String interestArea = "강남구";
87108
Boolean optInMarketing = null;
88109

89110
BusinessException exception = assertThrows(BusinessException.class,
90-
() -> new Member(socialId, nickname, mobilePhoneNumber, optInMarketing));
111+
() -> new Member(socialId, email, nickname, mobilePhoneNumber, optInMarketing));
91112

92113
assertThat(exception.getErrorCode()).isEqualTo(BusinessErrorCode.INVALID_MARKETING_CONSENT);
93114
}
@@ -98,7 +119,7 @@ class UpdateMember {
98119

99120
@Test
100121
void 회원_정보를_정상적으로_수정한다() {
101-
Member member = new Member("social-id", "nickname");
122+
Member member = new Member("social-id", "[email protected]", "nickname");
102123
Member updatedMember = new Member("new-nickname", "01012345678", true);
103124

104125
member.update(updatedMember);
@@ -116,7 +137,7 @@ class IsSameNicknameTest {
116137

117138
@Test
118139
void 동일한_닉네임을_비교하면_true를_반환한다() {
119-
Member member = new Member("social-id", "nickname");
140+
Member member = new Member("social-id", "[email protected]", "nickname");
120141

121142
boolean result = member.isSameNickname("nickname");
122143

@@ -125,7 +146,7 @@ class IsSameNicknameTest {
125146

126147
@Test
127148
void 다른_닉네임을_비교하면_false를_반환한다() {
128-
Member member = new Member("social-id", "nickname");
149+
Member member = new Member("social-id", "[email protected]", "nickname");
129150

130151
boolean result = member.isSameNickname("different-nickname");
131152

@@ -138,7 +159,7 @@ class IsSameMobilePhoneNumberTest {
138159

139160
@Test
140161
void 동일한_전화번호를_비교하면_true를_반환한다() {
141-
Member member = new Member("social-id", "nickname", "01012345678", true);
162+
Member member = new Member("social-id", "[email protected]", "nickname", "01012345678", true);
142163

143164
boolean result = member.isSameMobilePhoneNumber("01012345678");
144165

@@ -147,7 +168,7 @@ class IsSameMobilePhoneNumberTest {
147168

148169
@Test
149170
void 다른_전화번호를_비교하면_false를_반환한다() {
150-
Member member = new Member("social-id", "nickname", "01012345678", true);
171+
Member member = new Member("social-id", "[email protected]", "nickname", "01012345678", true);
151172

152173
boolean result = member.isSameMobilePhoneNumber("01087654321");
153174

0 commit comments

Comments
 (0)