Skip to content

Commit

Permalink
[feat] 점주 id를 UUID로 변경 (#53)
Browse files Browse the repository at this point in the history
* [style] ArgumentResolver 개행

네이버 컨벤션에 부합하게 개행 처리

* [fix] LoginVendor 및 LoginCustomer의 id 변경

* [feat] POST /vendor/login 로그인 앤드 포인트

SignINVendorRequest에서 검증 수행 후 Service 에 위임

* [fix] Vendor의 id를 UUID로 수정

* [fix] Vendor id 변경으로 인한 VendorRepositoryTest 변경

* [fix] Vendor id 변경으로 인한 SignUPVendorServiceTest 변경

* [fix] Vendor id 변경으로 인한 VendorApiControllerTest 변경

* [feat] Vendor의 비밀번호 일치 여부를 확인하는 도메인 메서드

`+` matches()

* [feat] VendorRepository에서 Email로 조회하는 메서드

`+` findByEmail()
`+` findByEmailOrThrow()

* [feat] Vendor가 로그인하기 위한 서비스 구현

입력된 비밀번호와 Vendor의 비밀번호의 일치 여부 확인

* [docs] SignInVendorService가 던지는 예외 명시

SignInVendorService는 PasswordMismatchException을 발생시킨다.

* [fix] matches 메서드 파라미터 순서 오류 수정

* [fix] TestVendor 생성자 수정

부모 클래스에 필드값을 넣어주어야 제대로 동작한다.

* [test] Vendor.matches() 테스트

* [test] SignInVendorServiceTest

* [feat] 판매자 로그인 endpoint

* [test] 로그인 컨트롤러 테스트 코드 작성

* [fix] LoginCustomer는 다른 이슈에서 처리될 예정

* [feat] Vendor 예외 처리

`+` PasswordMismatchException
`+` NotFoundVendorException

* [test] 점포 생성 테스트 코드 수정

Vendor의 id 타입의 변경으로 인한 수정

* [test] status 검증 수정

응답 상태 코드가 BadRequest인지 검증

* [fix] 로그인시 응답 메시지 생성

status 값을 담아주는 APIResponseAdvice 활용

* [fix] Id 전략 변경으로 인한 SignUpVendorService 수정

Service 내부에서 DataIntegrityViolationException을 받기 위해서는 flush가 수행되어야 한다.

* [test] SignUpVendorServiceTest에서 SaveAndFlush를 mocking하게  수정
  • Loading branch information
Dr-KoKo authored Aug 15, 2024
1 parent 2e95b15 commit 1c5edcb
Show file tree
Hide file tree
Showing 23 changed files with 433 additions and 59 deletions.
12 changes: 9 additions & 3 deletions src/main/java/camp/woowak/lab/vendor/domain/Vendor.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package camp.woowak.lab.vendor.domain;

import java.util.UUID;

import camp.woowak.lab.payaccount.domain.PayAccount;
import camp.woowak.lab.vendor.exception.InvalidVendorCreationException;
import camp.woowak.lab.web.authentication.PasswordEncoder;
Expand All @@ -16,8 +18,8 @@
@Getter
public class Vendor {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@GeneratedValue(strategy = GenerationType.UUID)
private UUID id;
@Column(nullable = false, length = 50)
private String name;
@Column(unique = true, nullable = false, length = 100)
Expand Down Expand Up @@ -45,7 +47,11 @@ public Vendor(String name, String email, String password, String phone, PayAccou
this.payAccount = payAccount;
}

public Long getId() {
public UUID getId() {
return id;
}

public boolean matches(String password, PasswordEncoder passwordEncoder) {
return passwordEncoder.matches(password, this.password);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package camp.woowak.lab.vendor.exception;

import camp.woowak.lab.common.exception.NotFoundException;

public class NotFoundVendorException extends NotFoundException {
public NotFoundVendorException() {
super(VendorErrorCode.NOT_FOUND_VENDOR);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package camp.woowak.lab.vendor.exception;

import camp.woowak.lab.common.exception.BadRequestException;

public class PasswordMismatchException extends BadRequestException {
public PasswordMismatchException() {
super(VendorErrorCode.WRONG_PASSWORD);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@ public enum VendorErrorCode implements ErrorCode {
INVALID_NAME_EMPTY(HttpStatus.BAD_REQUEST, "v1_7", "이름이 입력되지 않았습니다."),
INVALID_NAME_RANGE(HttpStatus.BAD_REQUEST, "v1_8", "이름은 50자를 넘을 수 없습니다."),
INVALID_PAY_ACCOUNT_EMPTY(HttpStatus.BAD_REQUEST, "v_1_9", "포인트 계좌가 입력되지 않았습니다."),
DUPLICATE_EMAIL(HttpStatus.BAD_REQUEST, "v_2", "이미 가입된 이메일입니다.");
DUPLICATE_EMAIL(HttpStatus.BAD_REQUEST, "v_2", "이미 가입된 이메일입니다."),
NOT_FOUND_VENDOR(HttpStatus.BAD_REQUEST, "v3", "존재하지 않는 점주입니다."),
WRONG_PASSWORD(HttpStatus.BAD_REQUEST, "v4_1", "잘못된 비밀번호입니다.");

private final int status;
private final String errorCode;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,17 @@
package camp.woowak.lab.vendor.repository;

import java.util.Optional;
import java.util.UUID;

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

import camp.woowak.lab.vendor.domain.Vendor;
import camp.woowak.lab.vendor.exception.NotFoundVendorException;

public interface VendorRepository extends JpaRepository<Vendor, UUID> {
Optional<Vendor> findByEmail(String email);

public interface VendorRepository extends JpaRepository<Vendor, Long> {
default Vendor findByEmailOrThrow(String email) {
return findByEmail(email).orElseThrow(NotFoundVendorException::new);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package camp.woowak.lab.vendor.service;

import java.util.UUID;

import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import camp.woowak.lab.vendor.domain.Vendor;
import camp.woowak.lab.vendor.exception.PasswordMismatchException;
import camp.woowak.lab.vendor.repository.VendorRepository;
import camp.woowak.lab.vendor.service.command.SignInVendorCommand;
import camp.woowak.lab.web.authentication.PasswordEncoder;

@Service
@Transactional(readOnly = true)
public class SignInVendorService {
private final VendorRepository repository;
private final PasswordEncoder passwordEncoder;

public SignInVendorService(VendorRepository repository, PasswordEncoder passwordEncoder) {
this.repository = repository;
this.passwordEncoder = passwordEncoder;
}

/**
* @throws PasswordMismatchException 비밀번호가 일치하지 않으면
*/
public UUID signIn(SignInVendorCommand cmd) {
Vendor findVendor = repository.findByEmailOrThrow(cmd.email());
if (!findVendor.matches(cmd.password(), passwordEncoder)) {
throw new PasswordMismatchException();
}
return findVendor.getId();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,16 +26,16 @@ public SignUpVendorService(
this.passwordEncoder = passwordEncoder;
}

public Long signUp(SignUpVendorCommand cmd) {
public String signUp(SignUpVendorCommand cmd) {
PayAccount newPayAccount = new PayAccount();
payAccountRepository.save(newPayAccount);
Vendor newVendor =
new Vendor(cmd.name(), cmd.email(), cmd.password(), cmd.phone(), newPayAccount, passwordEncoder);
Vendor savedVendor;
try {
vendorRepository.save(newVendor);
savedVendor = vendorRepository.saveAndFlush(
new Vendor(cmd.name(), cmd.email(), cmd.password(), cmd.phone(), newPayAccount, passwordEncoder));
} catch (DataIntegrityViolationException e) {
throw new DuplicateEmailException();
}
return newVendor.getId();
return savedVendor.getId().toString();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package camp.woowak.lab.vendor.service.command;

public record SignInVendorCommand(
String email,
String password
) {
}
Original file line number Diff line number Diff line change
@@ -1,23 +1,34 @@
package camp.woowak.lab.web.api.vendor;

import java.util.UUID;

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

import camp.woowak.lab.vendor.service.SignInVendorService;
import camp.woowak.lab.vendor.service.SignUpVendorService;
import camp.woowak.lab.vendor.service.command.SignInVendorCommand;
import camp.woowak.lab.vendor.service.command.SignUpVendorCommand;
import camp.woowak.lab.web.authentication.LoginVendor;
import camp.woowak.lab.web.dto.request.vendor.SignInVendorRequest;
import camp.woowak.lab.web.dto.request.vendor.SignUpVendorRequest;
import camp.woowak.lab.web.dto.response.vendor.SignInVendorResponse;
import camp.woowak.lab.web.dto.response.vendor.SignUpVendorResponse;
import camp.woowak.lab.web.resolver.session.SessionConst;
import jakarta.servlet.http.HttpSession;
import jakarta.validation.Valid;

@RestController
public class VendorApiController {
private final SignUpVendorService signUpVendorService;
private final SignInVendorService signInVendorService;

public VendorApiController(SignUpVendorService signUpVendorService) {
public VendorApiController(SignUpVendorService signUpVendorService, SignInVendorService signInVendorService) {
this.signUpVendorService = signUpVendorService;
this.signInVendorService = signInVendorService;
}

@PostMapping("/vendors")
Expand All @@ -26,7 +37,16 @@ public SignUpVendorResponse signUpVendor(@Valid @RequestBody SignUpVendorRequest

SignUpVendorCommand command =
new SignUpVendorCommand(request.name(), request.email(), request.password(), request.phone());
Long registeredId = signUpVendorService.signUp(command);
String registeredId = signUpVendorService.signUp(command);
return new SignUpVendorResponse(registeredId);
}

@PostMapping("/vendors/login")
@ResponseStatus(HttpStatus.NO_CONTENT)
public SignInVendorResponse login(@Valid @RequestBody SignInVendorRequest request, HttpSession session) {
SignInVendorCommand command = new SignInVendorCommand(request.email(), request.password());
UUID vendorId = signInVendorService.signIn(command);
session.setAttribute(SessionConst.SESSION_VENDOR_KEY, new LoginVendor(vendorId));
return new SignInVendorResponse("success");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,23 @@
import camp.woowak.lab.common.advice.DomainExceptionHandler;
import camp.woowak.lab.vendor.exception.DuplicateEmailException;
import camp.woowak.lab.vendor.exception.InvalidVendorCreationException;
import camp.woowak.lab.vendor.exception.NotFoundVendorException;
import camp.woowak.lab.vendor.exception.PasswordMismatchException;
import lombok.extern.slf4j.Slf4j;

@Slf4j
@DomainExceptionHandler(basePackageClasses = VendorApiController.class)
public class VendorApiControllerAdvice {
@ExceptionHandler(PasswordMismatchException.class)
public ResponseEntity<ProblemDetail> handlePasswordMismatchException(PasswordMismatchException ex) {
return ResponseEntity.of(ProblemDetail.forStatusAndDetail(HttpStatus.BAD_REQUEST, ex.getMessage())).build();
}

@ExceptionHandler(NotFoundVendorException.class)
public ResponseEntity<ProblemDetail> handleNotFoundVendorException(NotFoundVendorException ex) {
return ResponseEntity.of(ProblemDetail.forStatusAndDetail(HttpStatus.BAD_REQUEST, ex.getMessage())).build();
}

@ExceptionHandler(InvalidVendorCreationException.class)
public ResponseEntity<ProblemDetail> handleInvalidVendorCreationException(InvalidVendorCreationException ex) {
return ResponseEntity.of(ProblemDetail.forStatusAndDetail(HttpStatus.BAD_REQUEST, ex.getMessage())).build();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
package camp.woowak.lab.web.authentication;

public interface LoginMember {
Long getId();
Object getId();
}
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
package camp.woowak.lab.web.authentication;

import java.util.UUID;

public class LoginVendor implements LoginMember {
private final Long id;
private final UUID id;

public LoginVendor(Long id) {
public LoginVendor(UUID id) {
this.id = id;
}

@Override
public Long getId() {
public UUID getId() {
return id;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package camp.woowak.lab.web.dto.request.vendor;

import org.hibernate.validator.constraints.Length;

import jakarta.validation.constraints.Email;
import jakarta.validation.constraints.NotBlank;

public record SignInVendorRequest(
@NotBlank @Email
String email,
@NotBlank @Length(min = 8, max = 30)
String password
) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package camp.woowak.lab.web.dto.response.vendor;

public record SignInVendorResponse(
String message
) {
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package camp.woowak.lab.web.dto.response.vendor;

public record SignUpVendorResponse(
Long id
String id
) {
}
9 changes: 9 additions & 0 deletions src/test/java/camp/woowak/lab/fixture/VendorFixture.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
package camp.woowak.lab.fixture;

import java.util.UUID;

import camp.woowak.lab.payaccount.domain.PayAccount;
import camp.woowak.lab.vendor.TestVendor;
import camp.woowak.lab.vendor.domain.Vendor;
import camp.woowak.lab.web.authentication.PasswordEncoder;

Expand All @@ -9,6 +12,12 @@ default PayAccount createPayAccount() {
return new PayAccount();
}

default Vendor createSavedVendor(UUID id, PayAccount payAccount, PasswordEncoder passwordEncoder) {
return new TestVendor(
id, "vendorName", "[email protected]", "vendorPassword", "010-0000-0000", payAccount,
passwordEncoder);
}

default Vendor createVendor(PayAccount payAccount, PasswordEncoder passwordEncoder) {
return new Vendor("vendorName", "[email protected]", "vendorPassword", "010-0000-0000", payAccount,
passwordEncoder);
Expand Down
21 changes: 21 additions & 0 deletions src/test/java/camp/woowak/lab/vendor/TestVendor.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package camp.woowak.lab.vendor;

import java.util.UUID;

import camp.woowak.lab.payaccount.domain.PayAccount;
import camp.woowak.lab.vendor.domain.Vendor;
import camp.woowak.lab.web.authentication.PasswordEncoder;

public class TestVendor extends Vendor {
private UUID id;

public TestVendor(UUID id, String name, String email, String password, String phone, PayAccount payAccount,
PasswordEncoder passwordEncoder) {
super(name, email, password, phone, payAccount, passwordEncoder);
this.id = id;
}

public UUID getId() {
return id;
}
}
41 changes: 40 additions & 1 deletion src/test/java/camp/woowak/lab/vendor/domain/VendorTest.java
Original file line number Diff line number Diff line change
@@ -1,18 +1,21 @@
package camp.woowak.lab.vendor.domain;

import java.util.UUID;

import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;

import camp.woowak.lab.fixture.VendorFixture;
import camp.woowak.lab.payaccount.domain.PayAccount;
import camp.woowak.lab.payaccount.domain.TestPayAccount;
import camp.woowak.lab.vendor.exception.InvalidVendorCreationException;
import camp.woowak.lab.web.authentication.NoOpPasswordEncoder;
import camp.woowak.lab.web.authentication.PasswordEncoder;

class VendorTest {
class VendorTest implements VendorFixture {

private PayAccount payAccount;
private PasswordEncoder passwordEncoder;
Expand Down Expand Up @@ -209,4 +212,40 @@ void failWithNull() {
}
}
}

@Nested
@DisplayName("비밀번화 확인은")
class Matches {
@Test
@DisplayName("[성공] 비밀번호가 일치하면 true를 반환한다.")
void return_true() {
// given
Vendor savedVendor = createSavedVendor(UUID.randomUUID(), createPayAccount(), passwordEncoder);

// when
boolean matches = savedVendor.matches("vendorPassword", passwordEncoder);

// then
Assertions.assertTrue(matches);
}

@Test
@DisplayName("[예외] 비밀번호가 불일치하면 false를 반환한다.")
void return_false() {
// given
Vendor savedVendor = createSavedVendor(UUID.randomUUID(), createPayAccount(), passwordEncoder);

// when
boolean matches = savedVendor.matches("something_wrong", passwordEncoder);

// then
Assertions.assertFalse(matches);
}

@Test
void test() {
boolean matches = passwordEncoder.matches("vendorPassword", "vendorPassword");
Assertions.assertTrue(matches);
}
}
}
Loading

0 comments on commit 1c5edcb

Please sign in to comment.