Skip to content

Commit ade2b56

Browse files
authored
Merge pull request #311 from GTable/feature/#310-phoneNumber
Feature: phone number 및 마케팅 입력 기능 추가
2 parents d2044a5 + 279bba7 commit ade2b56

File tree

12 files changed

+211
-45
lines changed

12 files changed

+211
-45
lines changed

nowait-app-admin-api/src/main/java/com/nowait/applicationadmin/config/security/CorsConfig.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ public CorsConfigurationSource corsConfigurationSource() {
1515
CorsConfiguration config = new CorsConfiguration();
1616

1717
config.setAllowCredentials(true); // 쿠키나 인증헤더 자격증명 허용
18-
config.setAllowedOrigins(List.of("http://localhost:5173","http://localhost:63342", "https://no-wait-fe-nowait-admin-2y5y.vercel.app", "https://nowait-admin.co.kr")); // 허용할 출처 설정
18+
config.setAllowedOrigins(List.of("http://localhost:5173","http://localhost:63342", "https://no-wait-fe-nowait-admin-2y5y.vercel.app", "https://nowait-admin.co.kr", "https://www.nowait-admin.com")); // 허용할 출처 설정
1919
config.setAllowedMethods(List.of("GET", "POST", "PATCH", "PUT", "DELETE", "OPTIONS")); // 메서드 허용
2020
config.setAllowedHeaders(List.of("*")); //클라이언트가 보낼 수 있는 헤더
2121
config.setExposedHeaders(List.of("Authorization")); //클라이언트(브라우저)가 접근할 수 있는 헤더 지정

nowait-app-admin-api/src/main/java/com/nowait/applicationadmin/user/dto/ManagerSignupRequestDto.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
package com.nowait.applicationadmin.user.dto;
22

3+
import java.time.LocalDateTime;
4+
35
import com.nowait.common.enums.Role;
46
import com.nowait.common.enums.SocialType;
57
import com.nowait.domaincorerdb.user.entity.User;
68

79
import io.swagger.v3.oas.annotations.media.Schema;
810
import jakarta.validation.constraints.Email;
911
import jakarta.validation.constraints.NotBlank;
10-
import jakarta.validation.constraints.NotNull;
1112
import jakarta.validation.constraints.Pattern;
1213
import lombok.Getter;
1314
import lombok.NoArgsConstructor;
@@ -39,10 +40,13 @@ public class ManagerSignupRequestDto {
3940
public User toEntity() {
4041
return User.builder()
4142
.email(email)
43+
.phoneNumber("")
4244
.password(password)
4345
.nickname(nickname)
4446
.socialType(SocialType.LOCAL)
4547
.role(Role.MANAGER)
48+
.createdAt(LocalDateTime.now())
49+
.updatedAt(LocalDateTime.now())
4650
.build();
4751

4852
}

nowait-app-user-api/src/main/java/com/nowait/applicationuser/oauth/oauth2/CustomOAuth2UserService.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package com.nowait.applicationuser.oauth.oauth2;
22

3+
import java.time.LocalDateTime;
34
import java.util.Optional;
45

56
import org.springframework.security.oauth2.client.userinfo.DefaultOAuth2UserService;
@@ -50,11 +51,16 @@ public OAuth2User loadUser(OAuth2UserRequest userRequest) throws OAuth2Authentic
5051

5152
User user = User.builder()
5253
.email(oAuth2Response.getEmail())
54+
.phoneNumber("")
5355
.nickname(oAuth2Response.getNickName())
5456
.profileImage(oAuth2Response.getProfileImage())
5557
.socialType(SocialType.KAKAO)
5658
.role(Role.USER) // 일반 유저 설정
5759
.storeId(0L)
60+
.phoneEntered(false)
61+
.isMarketingAgree(false)
62+
.createdAt(LocalDateTime.now())
63+
.updatedAt(LocalDateTime.now())
5864
.build();
5965

6066
userRepository.save(user);

nowait-app-user-api/src/main/java/com/nowait/applicationuser/oauth/oauth2/OAuth2LoginSuccessHandler.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,13 +38,14 @@ public class OAuth2LoginSuccessHandler extends SimpleUrlAuthenticationSuccessHan
3838
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
3939
Authentication authentication) throws IOException {
4040

41-
CustomOAuth2User customUserDetails = (CustomOAuth2User) authentication.getPrincipal();
41+
CustomOAuth2User customUserDetails = (CustomOAuth2User)authentication.getPrincipal();
4242
User user = customUserDetails.getUser();
4343
Long userId = customUserDetails.getUserId();
4444
String role = authentication.getAuthorities().iterator().next().getAuthority();
4545

4646
// JWT 발급
47-
String accessToken = jwtUtil.createAccessToken("accessToken", userId, role, 30 * 60 * 1000L); // 30분
47+
String accessToken = jwtUtil.createAccessToken("accessToken", userId, role,
48+
Boolean.TRUE.equals(user.getPhoneEntered()), Boolean.TRUE.equals(user.getIsMarketingAgree()),60 * 60 * 1000L); // 1시간
4849
String refreshToken = jwtUtil.createRefreshToken("refreshToken", userId, 30L * 24 * 60 * 60 * 1000L); // 30일
4950

5051
// 1. refreshToken을 DB에 저장 or update

nowait-app-user-api/src/main/java/com/nowait/applicationuser/security/jwt/JwtUtil.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,14 @@ public JwtUtil(@Value("${jwt.secret}") String secret) {
2323
);
2424
}
2525

26-
public String createAccessToken(String tokenCategory, Long userId, String role, Long expiredMs) {
26+
public String createAccessToken(String tokenCategory, Long userId, String role, boolean phoneEntered,
27+
boolean marketingAgree, Long expiredMs) {
2728
return Jwts.builder()
2829
.claim("tokenCategory", tokenCategory) // accessToken
2930
.claim("userId", userId)
3031
.claim("role", role)
32+
.claim("phoneEntered", phoneEntered)
33+
.claim("marketingAgree", marketingAgree)
3134
.issuedAt(new Date(System.currentTimeMillis()))
3235
.expiration(new Date(System.currentTimeMillis() + expiredMs))
3336
.signWith(secretKey)

nowait-app-user-api/src/main/java/com/nowait/applicationuser/token/controller/TokenController.java

Lines changed: 56 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@
1111
import com.nowait.applicationuser.security.jwt.JwtUtil;
1212
import com.nowait.applicationuser.token.dto.AuthenticationResponse;
1313
import com.nowait.applicationuser.token.service.TokenService;
14+
import com.nowait.domaincorerdb.user.entity.User;
15+
import com.nowait.domaincorerdb.user.exception.UserNotFoundException;
16+
import com.nowait.domaincorerdb.user.repository.UserRepository;
1417

1518
import io.swagger.v3.oas.annotations.Operation;
1619
import io.swagger.v3.oas.annotations.responses.ApiResponse;
@@ -22,37 +25,57 @@
2225
@RequestMapping("/api/refresh-token")
2326
@Slf4j
2427
public class TokenController {
25-
private final JwtUtil jwtUtil;
26-
private final TokenService tokenService;
27-
@Value("${jwt.access-token-expiration-ms}")
28-
private long accessTokenExpiration;
29-
@Value("${jwt.refresh-token-expiration-ms}")
30-
private long refreshTokenExpiration;
31-
32-
@PostMapping
33-
@Operation(summary = "리프레시 토큰", description = "리프레시 토큰을 사용하여 새로운 액세스 토큰과 리프레시 토큰을 발급합니다.")
34-
@ApiResponse(responseCode = "200", description = "새로운 액세스 토큰과 리프레시 토큰 발급 성공")
35-
public ResponseEntity<?> refreshToken(
36-
@CookieValue(value = "refreshToken", required = false) String refreshToken) {
37-
38-
if (refreshToken == null) {
39-
return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("Refresh token not found in cookies");
40-
}
41-
42-
// 리프레시 토큰 검증
43-
Long userId = jwtUtil.getUserId(refreshToken);
44-
String role = jwtUtil.getRole(refreshToken);
45-
46-
if (tokenService.validateToken(refreshToken, userId)){
47-
String newAccessToken = jwtUtil.createAccessToken("accessToken", userId, role, accessTokenExpiration);
48-
String newRefreshToken = jwtUtil.createRefreshToken("refreshToken", userId, refreshTokenExpiration);
49-
50-
tokenService.updateRefreshToken(userId, refreshToken, newRefreshToken);
51-
52-
AuthenticationResponse authenticationResponse = new AuthenticationResponse(newAccessToken, newRefreshToken);
53-
return ResponseEntity.ok().body(authenticationResponse);
54-
}
55-
56-
return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("Invalid or expired refresh token");
57-
}
28+
private final JwtUtil jwtUtil;
29+
private final TokenService tokenService;
30+
private final UserRepository userRepository;
31+
@Value("${jwt.access-token-expiration-ms}")
32+
private long accessTokenExpiration;
33+
@Value("${jwt.refresh-token-expiration-ms}")
34+
private long refreshTokenExpiration;
35+
36+
@PostMapping
37+
@Operation(summary = "리프레시 토큰", description = "리프레시 토큰을 사용하여 새로운 액세스 토큰과 리프레시 토큰을 발급합니다.")
38+
@ApiResponse(responseCode = "200", description = "새로운 액세스 토큰과 리프레시 토큰 발급 성공")
39+
public ResponseEntity<?> refreshToken(
40+
@CookieValue(value = "refreshToken", required = false) String refreshToken) {
41+
42+
if (refreshToken == null) {
43+
return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("Refresh token not found in cookies");
44+
}
45+
46+
// 리프레시 토큰 검증
47+
Long userId;
48+
String role;
49+
try {
50+
userId = jwtUtil.getUserId(refreshToken);
51+
role = jwtUtil.getRole(refreshToken);
52+
} catch (RuntimeException e) {
53+
return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("Invalid or expired refresh token");
54+
}
55+
56+
User user = userRepository.findById(userId).orElseThrow(UserNotFoundException::new);
57+
58+
if (tokenService.validateToken(refreshToken, userId)) {
59+
String newAccessToken = jwtUtil.createAccessToken(
60+
"accessToken",
61+
userId,
62+
role,
63+
Boolean.TRUE.equals(user.getPhoneEntered()),
64+
Boolean.TRUE.equals(user.getIsMarketingAgree()),
65+
accessTokenExpiration
66+
);
67+
String newRefreshToken = jwtUtil.createRefreshToken(
68+
"refreshToken",
69+
userId,
70+
refreshTokenExpiration
71+
);
72+
73+
tokenService.updateRefreshToken(userId, refreshToken, newRefreshToken);
74+
75+
AuthenticationResponse authenticationResponse = new AuthenticationResponse(newAccessToken, newRefreshToken);
76+
return ResponseEntity.ok().body(authenticationResponse);
77+
}
78+
79+
return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("Invalid or expired refresh token");
80+
}
5881
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
package com.nowait.applicationuser.user.controller;
2+
3+
import org.springframework.http.HttpStatus;
4+
import org.springframework.http.ResponseEntity;
5+
import org.springframework.security.core.annotation.AuthenticationPrincipal;
6+
import org.springframework.web.bind.annotation.PutMapping;
7+
import org.springframework.web.bind.annotation.RequestBody;
8+
import org.springframework.web.bind.annotation.RequestMapping;
9+
import org.springframework.web.bind.annotation.RestController;
10+
11+
import com.nowait.applicationuser.user.dto.UserUpdateRequest;
12+
import com.nowait.applicationuser.user.service.UserService;
13+
import com.nowait.common.api.ApiUtils;
14+
import com.nowait.domainuserrdb.oauth.dto.CustomOAuth2User;
15+
16+
import jakarta.validation.Valid;
17+
import lombok.RequiredArgsConstructor;
18+
19+
@RestController
20+
@RequestMapping("/users")
21+
@RequiredArgsConstructor
22+
public class UserController {
23+
24+
private final UserService userService;
25+
26+
@PutMapping("/optional-info")
27+
public ResponseEntity<?> putOptional(
28+
@AuthenticationPrincipal CustomOAuth2User customOAuth2User,
29+
@Valid @RequestBody UserUpdateRequest req) {
30+
31+
String newAccessToken = userService.putOptional(customOAuth2User.getUserId(), req.phoneNumber(),
32+
Boolean.TRUE.equals(req.consent()));
33+
34+
return ResponseEntity
35+
.status(HttpStatus.OK)
36+
.body(
37+
ApiUtils.success(
38+
newAccessToken
39+
)
40+
);
41+
}
42+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package com.nowait.applicationuser.user.dto;
2+
3+
import jakarta.validation.constraints.NotBlank;
4+
import jakarta.validation.constraints.Pattern;
5+
6+
public record UserUpdateRequest(
7+
@NotBlank
8+
@Pattern(regexp = "^010-\\d{4}-\\d{4}$", message = "휴대폰 번호는 010-0000-0000 형식이어야 합니다.")
9+
String phoneNumber,
10+
boolean consent) { }
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
package com.nowait.applicationuser.user.service;
2+
3+
import java.time.LocalDateTime;
4+
5+
import org.springframework.stereotype.Service;
6+
import org.springframework.transaction.annotation.Transactional;
7+
8+
import com.nowait.applicationuser.security.jwt.JwtUtil;
9+
import com.nowait.domaincorerdb.user.entity.User;
10+
import com.nowait.domaincorerdb.user.exception.UserNotFoundException;
11+
import com.nowait.domaincorerdb.user.repository.UserRepository;
12+
13+
import lombok.RequiredArgsConstructor;
14+
15+
@Service
16+
@RequiredArgsConstructor
17+
public class UserService {
18+
19+
private final UserRepository userRepository;
20+
private final JwtUtil jwtUtil;
21+
22+
@Transactional
23+
public String putOptional(Long userId, String phoneNumber, boolean consent) {
24+
25+
User user = userRepository.findById(userId)
26+
.orElseThrow(UserNotFoundException::new);
27+
28+
if (userRepository.existsByPhoneNumberAndIdNot(phoneNumber, userId)) {
29+
throw new IllegalArgumentException("이미 사용 중인 휴대폰 번호입니다.");
30+
}
31+
32+
user.setPhoneNumberAndMarkEntered(phoneNumber, LocalDateTime.now());
33+
user.setIsMarketingAgree(consent, LocalDateTime.now());
34+
35+
String role = "ROLE_" + user.getRole().name();
36+
37+
return jwtUtil.createAccessToken("accessToken", user.getId(), role,
38+
Boolean.TRUE.equals(user.getPhoneEntered()),
39+
Boolean.TRUE.equals(user.getIsMarketingAgree()),
40+
60 * 60 * 1000L);
41+
}
42+
}

nowait-domain/domain-core-rdb/src/main/java/com/nowait/domaincorerdb/store/entity/Store.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,13 +40,13 @@ public class Store extends BaseTimeEntity {
4040
@Column(nullable = true, length = 200)
4141
private String location;
4242

43-
@Column(nullable = true, length = 200)
43+
@Column(nullable = true, length = 250)
4444
private String description;
4545

4646
@Column(nullable = true, length = 200)
4747
private String noticeTitle;
4848

49-
@Column(nullable = true, length = 200)
49+
@Column(nullable = true, length = 500)
5050
private String noticeContent;
5151

5252
@Column(nullable = true, length = 200)

0 commit comments

Comments
 (0)