Skip to content
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

구매자 회원가입 #16

Merged
merged 76 commits into from
Aug 13, 2024
Merged
Show file tree
Hide file tree
Changes from 29 commits
Commits
Show all changes
76 commits
Select commit Hold shift + click to select a range
17a4cc8
[chore] .gitkeep 삭제
kimhyun5u Aug 10, 2024
38c81a2
[feat] PasswordEncoder 추가
kimhyun5u Aug 10, 2024
deb1f8b
[feat] Vendor CustomException 추가
kimhyun5u Aug 10, 2024
030a8c0
[feat] PayAccountRepository 구현
kimhyun5u Aug 10, 2024
bffe230
[test] SignUpCustomerServiceTest
kimhyun5u Aug 10, 2024
0313777
[feat] Customer 회원가입 조건에 맞도록 수정
kimhyun5u Aug 10, 2024
d7482dc
[feat] CustomerRepository 구현
kimhyun5u Aug 10, 2024
8a94701
[feat] SignUpCustomerCommand 구현
kimhyun5u Aug 10, 2024
04f61a0
[feat] SignUpCustomerService 구현
kimhyun5u Aug 10, 2024
2900681
[feat] Vendor 회원가입 전송 계층 구현
Dr-KoKo Aug 10, 2024
4d6a20c
[feat] SignUpCustomerRequest 구현
kimhyun5u Aug 10, 2024
f93f83d
[feat] AuthController.signUpCustomer 구현
kimhyun5u Aug 10, 2024
c1bd5dc
[refactor] AuthController -> CustomerController
kimhyun5u Aug 11, 2024
07cd051
[test] Customer 테스트
kimhyun5u Aug 11, 2024
17fb832
[feat] Phone 검증 기능
Dr-KoKo Aug 10, 2024
bbafb20
[feat] jpa 설정
Dr-KoKo Aug 10, 2024
a9201d7
[test] CustomerController 테스트
kimhyun5u Aug 11, 2024
2d54d49
[feat] SignUpCustomerRequest 제약 조건 추가
kimhyun5u Aug 11, 2024
98f450b
[feat] CustomerController.signUp 파라미터 Valid 추가
kimhyun5u Aug 11, 2024
6d718e5
[refactor] SignUpCustomerServiceTest 수정
kimhyun5u Aug 11, 2024
5197be3
[feat] CustomerFixture 추가
kimhyun5u Aug 11, 2024
476489c
[chore] CustomerControllerTest 주석 추가
kimhyun5u Aug 11, 2024
4adf5de
[fix] CustomerControllerTest 로직 오류 수정
kimhyun5u Aug 11, 2024
5f51c1e
[test] SignUpCustomerServiceIntegrationTest 추가
kimhyun5u Aug 11, 2024
1ceeb0d
[feat] SignUpCustomerService.signUp 수정
kimhyun5u Aug 11, 2024
8dcc908
[feat] DuplicateException, InvalidCreationException 수정
kimhyun5u Aug 11, 2024
f0aa992
[fix] SignUpCustomerRequest
kimhyun5u Aug 11, 2024
a06d1c6
[feat] TestPayAccount 추가
kimhyun5u Aug 11, 2024
2750dbc
[chore] 오류 메세지 수정
kimhyun5u Aug 11, 2024
196b911
[build] 깃헙 템플릿 수정
Dr-KoKo Aug 10, 2024
9ae90e9
[build] 깃헙 템플릿 수정
Dr-KoKo Aug 10, 2024
56ec6f2
[build] 깃헙 액션 추가
Dr-KoKo Aug 10, 2024
8e86910
[feat] APIResponse 구현
Hyeon-Uk Aug 12, 2024
0797084
[feat] APIUtils 구현
Hyeon-Uk Aug 12, 2024
b9a7e0b
[test] APIUtils 테스트 코드 작성
Hyeon-Uk Aug 12, 2024
8c9a222
[docs] APIResponse에 사용시 주의사항 주석 추가
Hyeon-Uk Aug 12, 2024
e43860c
[feat] HttpStatusException 구현
kimhyun5u Aug 12, 2024
587c0d5
[feat] HttpStatusException 를 구현하는 Exception 구현
kimhyun5u Aug 12, 2024
3d2bc74
[feat] ErrorCode interface 구현
kimhyun5u Aug 12, 2024
11994fb
[feat] CustomRestControllerAdvice 구현
kimhyun5u Aug 12, 2024
99df6fd
[chore] 사용하지 않는 import 제거
kimhyun5u Aug 12, 2024
7d57737
[refactor] CustomRestControllerAdvice 이름 변경
kimhyun5u Aug 12, 2024
0677fb4
[fix] open-in-view 기본 설정으로 복구
kimhyun5u Aug 12, 2024
eb702f8
[chore] .gitkeep 제거
kimhyun5u Aug 12, 2024
b76a98f
[chore] .gitkeep 제거
kimhyun5u Aug 12, 2024
6ec34a9
[feat] CustomerErrorCode 생성
kimhyun5u Aug 12, 2024
ed6a9b8
[refactor] 도메인 Validation 주체 분리
kimhyun5u Aug 12, 2024
70f0f14
[refactor] CustomerException 수정
kimhyun5u Aug 12, 2024
a542d7c
[fix] 올바른 Exception 으로 변경
kimhyun5u Aug 12, 2024
956fb2b
[chore] 사용하지 않는 코드 삭제
kimhyun5u Aug 12, 2024
f3b8142
[chore] Exception 관련 Service 주석 추가
kimhyun5u Aug 12, 2024
ca68049
[feat] CustomerController 를 전담하는 DomainExceptionHandler 구현
kimhyun5u Aug 12, 2024
e81511d
[refactor] CustomerController 의 에러 처리 주체 변경
kimhyun5u Aug 13, 2024
140dbcc
[test] CustomerControllerTest 수정
kimhyun5u Aug 13, 2024
e2bd830
Merge remote-tracking branch 'refs/remotes/origin/main' into feature/…
kimhyun5u Aug 13, 2024
9f90cf1
[chore] .gitkeep 제거
kimhyun5u Aug 13, 2024
ca72425
[chore] 사용하지 않는 코드 제거
kimhyun5u Aug 13, 2024
c38cbdb
[chore] 사용하지 않는 코드 제거
kimhyun5u Aug 13, 2024
ba7ef95
[refactor] 패키지 구조 변경
kimhyun5u Aug 13, 2024
3b07854
[test] 에러 코드 정책 변경으로 인한 수정
kimhyun5u Aug 13, 2024
d3d1cfc
[chore] @Repository 제거
kimhyun5u Aug 13, 2024
6be87cd
[chore] CustomerController 이름 변경
kimhyun5u Aug 13, 2024
e6b0b0c
[refactor] SignUpCustomerRequest 패키지 구조 변경
kimhyun5u Aug 13, 2024
f6d3346
[feat] BadRequestException 생성자 추가
kimhyun5u Aug 13, 2024
16ff26c
[feat] 에러코드 정책 변경에 따른 수정
kimhyun5u Aug 13, 2024
f932cae
[feat] 에러코드 정책 변경에 따른 수정
kimhyun5u Aug 13, 2024
54840c1
[feat] InvalidCreationException 수정
kimhyun5u Aug 13, 2024
c8784cd
[feat] SignUpCustomerResponse 추가
kimhyun5u Aug 13, 2024
6f125c9
[feat] CustomerValidator private 생성자 추가
kimhyun5u Aug 13, 2024
0b1eb38
Merge remote-tracking branch 'origin/main' into feature/4_kimhyun5u_구…
kimhyun5u Aug 13, 2024
ae0385d
[style] 코드 스타일 수정 적용
kimhyun5u Aug 13, 2024
98d77d1
Merge remote-tracking branch 'origin/main' into feature/4_kimhyun5u_구…
kimhyun5u Aug 13, 2024
7a44fac
[feat] SignUpCustomerRequest annotation param 수정
kimhyun5u Aug 13, 2024
b28cc5d
[refactor] Validation 상수 값 추출
kimhyun5u Aug 13, 2024
7a1e3fb
[feat] SignUpCustomerRequest annotation param 수정
kimhyun5u Aug 13, 2024
b68368a
[chore] 불필요한 throws 제거
kimhyun5u Aug 13, 2024
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
Empty file.
91 changes: 85 additions & 6 deletions src/main/java/camp/woowak/lab/customer/domain/Customer.java
Original file line number Diff line number Diff line change
@@ -1,13 +1,92 @@
package camp.woowak.lab.customer.domain;

import camp.woowak.lab.customer.exception.InvalidCreationException;
import camp.woowak.lab.payaccount.domain.PayAccount;
import jakarta.persistence.*;
import camp.woowak.lab.web.authentication.PasswordEncoder;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.FetchType;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.OneToOne;
import lombok.Getter;

@Entity
@Getter
public class Customer {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@OneToOne(fetch = FetchType.LAZY)
private PayAccount payAccount;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false, length = 50)
private String name;
@Column(unique = true, nullable = false, length = 100)
private String email;
@Column(nullable = false, length = 30)
private String password;
@Column(nullable = false, length = 30)
private String phone;
@OneToOne(fetch = FetchType.LAZY)
private PayAccount payAccount;

public Customer() {
}

public Customer(String name, String email, String password, String phone, PayAccount payAccount,
PasswordEncoder passwordEncoder) throws
InvalidCreationException {
checkName(name);
checkEmail(email);
checkPassword(password);
checkPhone(phone);
checkPayAccount(payAccount);
this.name = name;
this.email = email;
this.password = passwordEncoder.encode(password);
this.phone = phone;
this.payAccount = payAccount;
}

private void checkPayAccount(PayAccount payAccount) throws InvalidCreationException {
if (payAccount == null) {
throw new InvalidCreationException("Pay account cannot be null");
}
}

private void checkPhone(String phone) throws InvalidCreationException {
if (phone == null || phone.isBlank()) {
throw new InvalidCreationException("Customer phone cannot be blank");
}
if (phone.trim().length() > 30) {
throw new InvalidCreationException("Customer phone cannot be longer than 30 characters");
}
}

private void checkPassword(String password) throws InvalidCreationException {
if (password == null || password.isBlank()) {
throw new InvalidCreationException("Customer password cannot be blank");
}
if (password.trim().length() > 30) {
throw new InvalidCreationException("Customer password cannot be longer than 30 characters");
}
}

private void checkEmail(String email) throws InvalidCreationException {
if (email == null || email.isBlank()) {
throw new InvalidCreationException("Customer email cannot be blank");
}
if (email.trim().length() > 100) {
throw new InvalidCreationException("Customer email cannot be longer than 100 characters");
}
}

private void checkName(String name) throws InvalidCreationException {
if (name == null || name.isBlank()) {
throw new InvalidCreationException("Customer name cannot be blank");
}
if (name.length() > 50) {
throw new InvalidCreationException("Customer name cannot exceed 50 characters");
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
package camp.woowak.lab.customer.exception;

public class DuplicateEmailException extends DuplicateException {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
package camp.woowak.lab.customer.exception;

public abstract class DuplicateException extends RuntimeException {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package camp.woowak.lab.customer.exception;

public class InvalidCreationException extends RuntimeException {
public InvalidCreationException(String message) {
super(message);
}
}
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package camp.woowak.lab.customer.repository;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

import camp.woowak.lab.customer.domain.Customer;

@Repository
public interface CustomerRepository extends JpaRepository<Customer, Long> {
}
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package camp.woowak.lab.customer.service;

import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.stereotype.Service;

import camp.woowak.lab.customer.domain.Customer;
import camp.woowak.lab.customer.exception.DuplicateEmailException;
import camp.woowak.lab.customer.exception.InvalidCreationException;
import camp.woowak.lab.customer.repository.CustomerRepository;
import camp.woowak.lab.customer.service.command.SignUpCustomerCommand;
import camp.woowak.lab.payaccount.domain.PayAccount;
import camp.woowak.lab.payaccount.repository.PayAccountRepository;
import camp.woowak.lab.web.authentication.PasswordEncoder;
import jakarta.transaction.Transactional;

@Service
public class SignUpCustomerService {
private final CustomerRepository customerRepository;
private final PayAccountRepository payAccountRepository;
private final PasswordEncoder passwordEncoder;

public SignUpCustomerService(CustomerRepository customerRepository, PayAccountRepository payAccountRepository,
PasswordEncoder passwordEncoder) {
this.customerRepository = customerRepository;
this.payAccountRepository = payAccountRepository;
this.passwordEncoder = passwordEncoder;
}

kimhyun5u marked this conversation as resolved.
Show resolved Hide resolved
@Transactional
public Long signUp(SignUpCustomerCommand cmd) throws InvalidCreationException, DuplicateEmailException {
PayAccount payAccount = new PayAccount();
payAccountRepository.save(payAccount);

Customer newCustomer = new Customer(cmd.name(), cmd.email(), cmd.password(), cmd.phone(), payAccount,
passwordEncoder);

try {
kimhyun5u marked this conversation as resolved.
Show resolved Hide resolved
customerRepository.save(newCustomer);
} catch (DataIntegrityViolationException e) {
throw new DuplicateEmailException();
}
return newCustomer.getId();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
package camp.woowak.lab.customer.service.command;

public record SignUpCustomerCommand(String name, String email, String password, String phone) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package camp.woowak.lab.payaccount.repository;

import org.springframework.data.jpa.repository.JpaRepository;

import camp.woowak.lab.payaccount.domain.PayAccount;

public interface PayAccountRepository extends JpaRepository<PayAccount, Long> {
}
39 changes: 39 additions & 0 deletions src/main/java/camp/woowak/lab/web/api/CustomerController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package camp.woowak.lab.web.api;

import java.net.URI;

import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

import camp.woowak.lab.customer.service.SignUpCustomerService;
import camp.woowak.lab.customer.service.command.SignUpCustomerCommand;
import camp.woowak.lab.web.dto.request.SignUpCustomerRequest;
import camp.woowak.lab.web.dto.response.ApiResponse;
import camp.woowak.lab.web.error.ErrorCode;
import jakarta.validation.Valid;

@RestController
public class CustomerController {
private final SignUpCustomerService signUpCustomerService;

public CustomerController(SignUpCustomerService signUpCustomerService) {
this.signUpCustomerService = signUpCustomerService;
}

@PostMapping("/customers")
public ResponseEntity<?> signUp(@Valid @RequestBody SignUpCustomerRequest request) {
SignUpCustomerCommand command =
new SignUpCustomerCommand(request.name(), request.email(), request.password(), request.phone());
Long registeredId;
try {
registeredId = signUpCustomerService.signUp(command);
} catch (camp.woowak.lab.customer.exception.InvalidCreationException e) {
return ResponseEntity.badRequest().body(ApiResponse.error(ErrorCode.SIGNUP_INVALID_REQUEST));
} catch (camp.woowak.lab.customer.exception.DuplicateEmailException e) {
return ResponseEntity.ok(ApiResponse.error(ErrorCode.AUTH_DUPLICATE_EMAIL));
}
return ResponseEntity.created(URI.create("/customers/" + registeredId)).build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package camp.woowak.lab.web.authentication;

import java.util.Objects;

public class NoOpPasswordEncoder implements PasswordEncoder {
@Override
public String encode(String password) {
return password;
}

@Override
public boolean matches(String password, String encodedPassword) {
return Objects.equals(password, encodedPassword);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package camp.woowak.lab.web.authentication;

public interface PasswordEncoder {
String encode(String password);

boolean matches(String password, String encodedPassword);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package camp.woowak.lab.web.authentication.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import camp.woowak.lab.web.authentication.NoOpPasswordEncoder;
import camp.woowak.lab.web.authentication.PasswordEncoder;

@Configuration
public class AuthenticationConfig {
@Bean
public PasswordEncoder passwordEncoder() {
return new NoOpPasswordEncoder();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package camp.woowak.lab.web.dto.request;

import org.hibernate.validator.constraints.Length;

import camp.woowak.lab.web.validation.annotation.Phone;
import jakarta.validation.constraints.Email;
import jakarta.validation.constraints.NotBlank;

public record SignUpCustomerRequest(
@Length(min = 1, max = 50)
String name,
@NotBlank
@Email
String email,
@Length(min = 8, max = 20)
String password,
@Phone
String phone
) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package camp.woowak.lab.web.dto.request;

import org.hibernate.validator.constraints.Length;

import camp.woowak.lab.web.validation.annotation.Phone;
import jakarta.validation.constraints.Email;

public record SignUpVendorRequest(
@Length(min = 1, max = 50)
kimhyun5u marked this conversation as resolved.
Show resolved Hide resolved
String name,
@Email
String email,
@Length(min = 1, max = 30)
String password,
@Phone
String phone
) {
}
40 changes: 40 additions & 0 deletions src/main/java/camp/woowak/lab/web/dto/response/ApiResponse.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package camp.woowak.lab.web.dto.response;

import camp.woowak.lab.web.error.ErrorCode;

public class ApiResponse<T> {
private String code;
private String message;
private T data;

private ApiResponse(String code, String message) {
this.code = code;
this.message = message;
}

private ApiResponse(String code, String message, T data) {
this.code = code;
this.message = message;
this.data = data;
}

public static <T> ApiResponse<T> ok(T data) {
return new ApiResponse<>("OK", "success", data);
}

public static <T> ApiResponse<T> error(ErrorCode errorCode) {
return new ApiResponse<>(errorCode.getCode(), errorCode.getMessage());
}

public String getCode() {
return code;
}

public String getMessage() {
return message;
}

public T getData() {
return data;
}
}
22 changes: 22 additions & 0 deletions src/main/java/camp/woowak/lab/web/error/ErrorCode.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package camp.woowak.lab.web.error;

public enum ErrorCode {
AUTH_DUPLICATE_EMAIL("a1", "이미 가입된 이메일 입니다."),
SIGNUP_INVALID_REQUEST("s1", "잘못된 요청입니다.");

private final String code;
private final String message;

ErrorCode(String code, String message) {
this.code = code;
this.message = message;
}

public String getCode() {
return code;
}

public String getMessage() {
return message;
}
}
21 changes: 21 additions & 0 deletions src/main/java/camp/woowak/lab/web/validation/annotation/Phone.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package camp.woowak.lab.web.validation.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

import camp.woowak.lab.web.validation.validator.PhoneNumberValidator;
import jakarta.validation.Constraint;
import jakarta.validation.Payload;

@Target({ElementType.FIELD, ElementType.PARAMETER})
kimhyun5u marked this conversation as resolved.
Show resolved Hide resolved
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = PhoneNumberValidator.class)
public @interface Phone {
String message() default "Invalid phone number";

Class<?>[] groups() default {};

Class<? extends Payload>[] payload() default {};
}
Loading