Compare commits
35 Commits
feature/is
...
feature/de
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c03cdfc23b | ||
|
|
340626cb87 | ||
|
|
5bfb351c4c | ||
|
|
85dae8535a | ||
|
|
50001486ed | ||
|
|
b197e551da | ||
|
|
cd168f8168 | ||
|
|
55c74e84a4 | ||
|
|
ac479b56b1 | ||
|
|
8167b9e45a | ||
|
|
a5ec8bcc44 | ||
|
|
ba06c3a9b7 | ||
|
|
a1e304ebd4 | ||
|
|
6f10d85d65 | ||
|
|
af33948577 | ||
|
|
324e8b6086 | ||
|
|
f575528e39 | ||
|
|
205297bc10 | ||
|
|
fc0ee8c973 | ||
|
|
4d5c167123 | ||
|
|
ba79691b4b | ||
|
|
e4fddc359c | ||
|
|
83e8dcc9d6 | ||
|
|
bc8180307b | ||
|
|
ab7a7788ed | ||
|
|
bdb1374a0b | ||
|
|
940c6b327c | ||
|
|
1767d71baf | ||
|
|
9f70ee0ed9 | ||
|
|
38365de76c | ||
|
|
b36a58f965 | ||
|
|
2028f3e508 | ||
|
|
4133bcca42 | ||
|
|
c290e54dd3 | ||
|
|
47511c5823 |
81
README.md
81
README.md
@@ -14,4 +14,85 @@
|
|||||||
## 🎯 프로젝트 목표
|
## 🎯 프로젝트 목표
|
||||||
|
|
||||||
|
|
||||||
|
<br/><br/>
|
||||||
|
|
||||||
|
## 🧩 ERD
|
||||||
|
|
||||||
|
``` mermaid
|
||||||
|
erDiagram
|
||||||
|
MOVIE ||--o{ MOVIE_TIMES : ""
|
||||||
|
MOVIE {
|
||||||
|
bigint id PK "영화 ID"
|
||||||
|
varchar title "영화제목"
|
||||||
|
int running_time "러닝타임"
|
||||||
|
datetime created_at "등록일시"
|
||||||
|
datetime updated_at "수정일시"
|
||||||
|
}
|
||||||
|
THEATER ||--o{ MOVIE_TIMES : ""
|
||||||
|
THEATER ||--|{ SEAT : ""
|
||||||
|
THEATER {
|
||||||
|
bigint id PK "상영관 ID"
|
||||||
|
int theater_number "상영관 번호"
|
||||||
|
int seat_count "좌석수"
|
||||||
|
datetime created_at "등록일시"
|
||||||
|
datetime updated_at "수정일시"
|
||||||
|
}
|
||||||
|
SEAT ||--o{ TICKET : ""
|
||||||
|
SEAT {
|
||||||
|
bigint id PK "좌석 ID"
|
||||||
|
bigint theater_id FK "상영관 ID"
|
||||||
|
int column "열"
|
||||||
|
int row "행"
|
||||||
|
datetime created_at "등록일시"
|
||||||
|
datetime updated_at "수정일시"
|
||||||
|
}
|
||||||
|
MOVIE_TIMES ||--o{ TICKET : ""
|
||||||
|
MOVIE_TIMES {
|
||||||
|
bigint id PK "상영시간표 ID"
|
||||||
|
bigint movie_id FK "영화 ID"
|
||||||
|
bigint theater_id FK "상영관 ID"
|
||||||
|
date running_date "상영 날짜"
|
||||||
|
int round "회차"
|
||||||
|
time start_at "시작 시간"
|
||||||
|
time end_at "종료 시간"
|
||||||
|
datetime created_at "등록일시"
|
||||||
|
datetime updated_at "수정일시"
|
||||||
|
}
|
||||||
|
TICKET {
|
||||||
|
bigint id PK "티켓 ID"
|
||||||
|
bigint seat_id FK "좌석 ID"
|
||||||
|
bigint movie_times_id FK "상영시간표 ID"
|
||||||
|
bigint payment_id FK "결제 ID"
|
||||||
|
varchar status "상태 - 구매가능/예약진행중/판매완료"
|
||||||
|
int ticket_price "가격"
|
||||||
|
datetime created_at "등록일시"
|
||||||
|
datetime updated_at "수정일시"
|
||||||
|
}
|
||||||
|
TICKET }|--|| PAYMENT : ""
|
||||||
|
PAYMENT {
|
||||||
|
bigint id PK "결제 ID"
|
||||||
|
bigint user_id FK "유저ID"
|
||||||
|
varchar type "결제 타입 - 예) 네이버페이, 카카오페이"
|
||||||
|
varchar status "상태 - 완료/환불/실패"
|
||||||
|
varchar failed_message "실패사유 - 컬럼명을 알아보기 쉬운가?"
|
||||||
|
varchar payment_number "예매번호"
|
||||||
|
int total_price "결제 금액"
|
||||||
|
datetime created_at "결제일시"
|
||||||
|
datetime updated_at "수정일시"
|
||||||
|
}
|
||||||
|
USER ||--o{ PAYMENT : ""
|
||||||
|
USER {
|
||||||
|
bigint id "회원"
|
||||||
|
varchar name "이름"
|
||||||
|
varchar email "이메일"
|
||||||
|
varchar password "비밀번호"
|
||||||
|
varchar grade "등급 - 고객/임직원"
|
||||||
|
varchar phone "휴대폰 번호"
|
||||||
|
boolean is_deleted "탈퇴여부"
|
||||||
|
datetime deleted_at "탈퇴일시"
|
||||||
|
datetime created_at "가입일시"
|
||||||
|
datetime updated_at "수정일시"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
<br/><br/>
|
<br/><br/>
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
## 작업 내용
|
## 작업 분류
|
||||||
- [ ] 기능 추가
|
- [ ] 기능 추가
|
||||||
- [ ] 코드 수정
|
- [ ] 코드 수정
|
||||||
- [ ] 환경 설정
|
- [ ] 환경 설정
|
||||||
@@ -30,4 +30,3 @@
|
|||||||
- [ ] 구현 사항에 대한 테스트를 완료했습니다.
|
- [ ] 구현 사항에 대한 테스트를 완료했습니다.
|
||||||
- [ ] 의도한 내용 이외에 다른 코드에는 변경 사항이 없는지 확인했습니다.
|
- [ ] 의도한 내용 이외에 다른 코드에는 변경 사항이 없는지 확인했습니다.
|
||||||
- [ ] 코드 스타일을 적용하여 팀 코딩 컨벤션에 맞게 작성했습니다.
|
- [ ] 코드 스타일을 적용하여 팀 코딩 컨벤션에 맞게 작성했습니다.
|
||||||
- [ ] 팀원 모두 구현 내용 및 코드에 대해 이해하고 있습니다.
|
|
||||||
7
server/.gitignore
vendored
7
server/.gitignore
vendored
@@ -86,7 +86,9 @@ fabric.properties
|
|||||||
# Ignore everything but code style settings and run configurations
|
# Ignore everything but code style settings and run configurations
|
||||||
# that are supposed to be shared within teams.
|
# that are supposed to be shared within teams.
|
||||||
|
|
||||||
.idea/*
|
.idea/
|
||||||
|
.idea/*.iml
|
||||||
|
.idea/*.xml
|
||||||
|
|
||||||
!.idea/codeStyles
|
!.idea/codeStyles
|
||||||
!.idea/runConfigurations
|
!.idea/runConfigurations
|
||||||
@@ -198,4 +200,7 @@ gradle-app.setting
|
|||||||
# JDT-specific (Eclipse Java Development Tools)
|
# JDT-specific (Eclipse Java Development Tools)
|
||||||
.classpath
|
.classpath
|
||||||
|
|
||||||
|
# log
|
||||||
|
/logs
|
||||||
|
|
||||||
# End of https://www.toptal.com/developers/gitignore/api/macos,windows,intellij+all,gradle,visualstudiocode
|
# End of https://www.toptal.com/developers/gitignore/api/macos,windows,intellij+all,gradle,visualstudiocode
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
plugins {
|
plugins {
|
||||||
java
|
java
|
||||||
id ("org.springframework.boot") version "2.6.7"
|
id("org.springframework.boot") version "2.6.7"
|
||||||
id ("io.spring.dependency-management") version "1.0.11.RELEASE"
|
id("io.spring.dependency-management") version "1.0.11.RELEASE"
|
||||||
}
|
}
|
||||||
|
|
||||||
group = "com.ticketing"
|
group = "com.ticketing"
|
||||||
@@ -23,18 +23,30 @@ repositories {
|
|||||||
mavenCentral()
|
mavenCentral()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation ("org.springframework.boot:spring-boot-starter-data-jpa")
|
implementation("org.springframework.boot:spring-boot-starter-data-jpa")
|
||||||
implementation ("org.springframework.boot:spring-boot-starter-security")
|
implementation("org.springframework.boot:spring-boot-starter-security")
|
||||||
implementation ("org.springframework.boot:spring-boot-starter-validation")
|
implementation("org.springframework.boot:spring-boot-starter-validation")
|
||||||
implementation ("org.springframework.boot:spring-boot-starter-web")
|
implementation("org.springframework.boot:spring-boot-starter-web")
|
||||||
|
implementation("org.springframework.boot:spring-boot-starter-actuator")
|
||||||
|
implementation("com.github.ulisesbocchio:jasypt-spring-boot-starter:3.0.4")
|
||||||
|
implementation("org.springframework.boot:spring-boot-starter-log4j2")
|
||||||
|
implementation("com.lmax:disruptor:3.4.2")
|
||||||
|
|
||||||
compileOnly ("org.projectlombok:lombok")
|
modules {
|
||||||
runtimeOnly ("mysql:mysql-connector-java")
|
module("org.springframework.boot:spring-boot-starter-logging") {
|
||||||
annotationProcessor ("org.projectlombok:lombok")
|
replacedBy("org.springframework.boot:spring-boot-starter-log4j2", "Use Log4j2 instead of Logback")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
testImplementation ("org.springframework.boot:spring-boot-starter-test")
|
compileOnly("org.projectlombok:lombok")
|
||||||
testImplementation ("org.springframework.security:spring-security-test")
|
runtimeOnly("mysql:mysql-connector-java")
|
||||||
|
annotationProcessor("org.projectlombok:lombok")
|
||||||
|
|
||||||
|
testImplementation("org.springframework.boot:spring-boot-starter-test")
|
||||||
|
testImplementation("org.springframework.security:spring-security-test")
|
||||||
}
|
}
|
||||||
|
|
||||||
tasks.withType<Test> {
|
tasks.withType<Test> {
|
||||||
|
|||||||
@@ -2,7 +2,9 @@ package com.ticketing.server;
|
|||||||
|
|
||||||
import org.springframework.boot.SpringApplication;
|
import org.springframework.boot.SpringApplication;
|
||||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
|
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
|
||||||
|
|
||||||
|
@EnableJpaAuditing
|
||||||
@SpringBootApplication
|
@SpringBootApplication
|
||||||
public class ServerApplication {
|
public class ServerApplication {
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,26 @@
|
|||||||
|
package com.ticketing.server.global.config;
|
||||||
|
|
||||||
|
import org.jasypt.encryption.StringEncryptor;
|
||||||
|
import org.jasypt.encryption.pbe.PooledPBEStringEncryptor;
|
||||||
|
import org.jasypt.encryption.pbe.config.SimpleStringPBEConfig;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
public class JasyptConfig {
|
||||||
|
|
||||||
|
@Bean("jasyptStringEncryptor")
|
||||||
|
public StringEncryptor stringEncryptor() {
|
||||||
|
PooledPBEStringEncryptor encryptor = new PooledPBEStringEncryptor();
|
||||||
|
SimpleStringPBEConfig config = new SimpleStringPBEConfig();
|
||||||
|
config.setPassword("ticketing");
|
||||||
|
config.setAlgorithm("PBEWithMD5AndDES");
|
||||||
|
config.setKeyObtentionIterations("1000");
|
||||||
|
config.setPoolSize("1");
|
||||||
|
config.setProviderName("SunJCE");
|
||||||
|
config.setSaltGeneratorClassName("org.jasypt.salt.RandomSaltGenerator");
|
||||||
|
config.setStringOutputType("base64");
|
||||||
|
encryptor.setConfig(config);
|
||||||
|
return encryptor;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
package com.ticketing.server.global.config;
|
||||||
|
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.context.support.ResourceBundleMessageSource;
|
||||||
|
import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
public class MessagesConfig {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public ResourceBundleMessageSource messageSource() {
|
||||||
|
ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
|
||||||
|
messageSource.setBasename("i18n/messages");
|
||||||
|
messageSource.setDefaultEncoding("UTF-8");
|
||||||
|
|
||||||
|
return messageSource;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public LocalValidatorFactoryBean getValidator() {
|
||||||
|
LocalValidatorFactoryBean factoryBean = new LocalValidatorFactoryBean();
|
||||||
|
factoryBean.setValidationMessageSource(messageSource());
|
||||||
|
|
||||||
|
return factoryBean;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
package com.ticketing.server.global.config;
|
||||||
|
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||||
|
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||||
|
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
||||||
|
import org.springframework.security.crypto.factory.PasswordEncoderFactories;
|
||||||
|
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@EnableWebSecurity
|
||||||
|
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public PasswordEncoder passwordEncoder() {
|
||||||
|
return PasswordEncoderFactories.createDelegatingPasswordEncoder();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void configure(HttpSecurity http) throws Exception {
|
||||||
|
http
|
||||||
|
.cors().disable()
|
||||||
|
.csrf().disable()
|
||||||
|
.formLogin().disable()
|
||||||
|
.headers().frameOptions().disable();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
package com.ticketing.server.global.dto.repository;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import javax.persistence.Column;
|
||||||
|
import javax.persistence.EntityListeners;
|
||||||
|
import javax.persistence.GeneratedValue;
|
||||||
|
import javax.persistence.GenerationType;
|
||||||
|
import javax.persistence.Id;
|
||||||
|
import javax.persistence.MappedSuperclass;
|
||||||
|
import lombok.Getter;
|
||||||
|
import org.springframework.data.annotation.CreatedDate;
|
||||||
|
import org.springframework.data.annotation.LastModifiedDate;
|
||||||
|
import org.springframework.data.jpa.domain.support.AuditingEntityListener;
|
||||||
|
|
||||||
|
@MappedSuperclass
|
||||||
|
@EntityListeners(AuditingEntityListener.class)
|
||||||
|
@Getter
|
||||||
|
public abstract class AbstractEntity {
|
||||||
|
|
||||||
|
@Id
|
||||||
|
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
@Column(nullable = false, updatable = false)
|
||||||
|
@CreatedDate
|
||||||
|
private LocalDateTime createdAt;
|
||||||
|
|
||||||
|
@LastModifiedDate
|
||||||
|
private LocalDateTime updatedAt;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
package com.ticketing.server.global.exception;
|
||||||
|
|
||||||
|
public class AlreadyDeletedException extends RuntimeException {
|
||||||
|
|
||||||
|
public AlreadyDeletedException(String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
package com.ticketing.server.global.exception;
|
||||||
|
|
||||||
|
public class NotFoundEmailException extends IllegalArgumentException {
|
||||||
|
|
||||||
|
private static final String MESSAGE = "존재하지 않는 이메일 입니다.";
|
||||||
|
|
||||||
|
public NotFoundEmailException() {
|
||||||
|
super(MESSAGE);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
package com.ticketing.server.global.exception;
|
||||||
|
|
||||||
|
public class PasswordMismatchException extends RuntimeException {
|
||||||
|
|
||||||
|
private static final String MESSAGE = "패스워드가 일치하지 않습니다";
|
||||||
|
|
||||||
|
public PasswordMismatchException() {
|
||||||
|
super(MESSAGE);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
package com.ticketing.server.global.health;
|
||||||
|
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.springframework.boot.actuate.health.Health;
|
||||||
|
import org.springframework.boot.actuate.health.Status;
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.ResponseStatus;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/l7check")
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class L7checkController {
|
||||||
|
|
||||||
|
private final MutableHealthIndicator indicator;
|
||||||
|
|
||||||
|
@GetMapping
|
||||||
|
public ResponseEntity<Object> health() {
|
||||||
|
Health health = indicator.health();
|
||||||
|
boolean isUp = health.getStatus().equals(Status.UP);
|
||||||
|
return ResponseEntity
|
||||||
|
.status(isUp ? HttpStatus.OK : HttpStatus.SERVICE_UNAVAILABLE)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@DeleteMapping
|
||||||
|
@ResponseStatus(HttpStatus.NO_CONTENT)
|
||||||
|
public void down() {
|
||||||
|
indicator.setHealth(Health.down().build());
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping
|
||||||
|
@ResponseStatus(HttpStatus.CREATED)
|
||||||
|
public void up() {
|
||||||
|
indicator.setHealth(Health.up().build());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
package com.ticketing.server.global.health;
|
||||||
|
|
||||||
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
|
import org.springframework.boot.actuate.health.Health;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
public class ManualHealthIndicator implements MutableHealthIndicator {
|
||||||
|
|
||||||
|
private final AtomicReference<Health> healthRef = new AtomicReference<>(Health.up().build());
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setHealth(Health health) {
|
||||||
|
healthRef.set(health);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Health health() {
|
||||||
|
return healthRef.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
package com.ticketing.server.global.health;
|
||||||
|
|
||||||
|
import org.springframework.boot.actuate.health.Health;
|
||||||
|
import org.springframework.boot.actuate.health.HealthIndicator;
|
||||||
|
|
||||||
|
public interface MutableHealthIndicator extends HealthIndicator {
|
||||||
|
|
||||||
|
void setHealth(Health health);
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
package com.ticketing.server.global.validator.constraints;
|
||||||
|
|
||||||
|
import com.ticketing.server.global.validator.constraintvalidators.PhoneValidator;
|
||||||
|
import java.lang.annotation.Documented;
|
||||||
|
import java.lang.annotation.ElementType;
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
import java.lang.annotation.Target;
|
||||||
|
import javax.validation.Constraint;
|
||||||
|
import javax.validation.Payload;
|
||||||
|
|
||||||
|
@Target(ElementType.FIELD)
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
@Constraint(validatedBy = {PhoneValidator.class})
|
||||||
|
@Documented
|
||||||
|
public @interface Phone {
|
||||||
|
|
||||||
|
String message() default "{validation.phone}";
|
||||||
|
|
||||||
|
Class<?>[] groups() default {};
|
||||||
|
|
||||||
|
Class<? extends Payload>[] payload() default {};
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
package com.ticketing.server.global.validator.constraintvalidators;
|
||||||
|
|
||||||
|
import com.ticketing.server.global.validator.constraints.Phone;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
import javax.validation.ConstraintValidator;
|
||||||
|
import javax.validation.ConstraintValidatorContext;
|
||||||
|
|
||||||
|
public class PhoneValidator implements ConstraintValidator<Phone, String> {
|
||||||
|
|
||||||
|
private static final String PATTERN = "\\d{3}-\\d{4}-\\d{4}";
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isValid(String value, ConstraintValidatorContext context) {
|
||||||
|
if (value == null || value.isEmpty()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Pattern.matches(PATTERN, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
package com.ticketing.server.movie.application;
|
||||||
|
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
public class MovieController {
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
package com.ticketing.server.movie.application;
|
||||||
|
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
public class MovieTimesController {
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
package com.ticketing.server.movie.application;
|
||||||
|
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
public class SeatController {
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
package com.ticketing.server.movie.application;
|
||||||
|
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
public class TheaterController {
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
package com.ticketing.server.movie.application;
|
||||||
|
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
public class TicketController {
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
package com.ticketing.server.movie.domain;
|
||||||
|
|
||||||
|
import com.ticketing.server.global.dto.repository.AbstractEntity;
|
||||||
|
import javax.persistence.Entity;
|
||||||
|
import javax.validation.constraints.NotNull;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@Getter
|
||||||
|
public class Movie extends AbstractEntity {
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
private String title;
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
private Integer runningTime;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
package com.ticketing.server.movie.domain;
|
||||||
|
|
||||||
|
import com.ticketing.server.global.dto.repository.AbstractEntity;
|
||||||
|
import java.time.LocalDate;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import javax.persistence.Entity;
|
||||||
|
import javax.persistence.JoinColumn;
|
||||||
|
import javax.persistence.ManyToOne;
|
||||||
|
import javax.validation.constraints.NotNull;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@Getter
|
||||||
|
public class MovieTimes extends AbstractEntity {
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
@ManyToOne
|
||||||
|
@JoinColumn(name = "movie_id", referencedColumnName = "id", updatable = false)
|
||||||
|
private Movie movie;
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
@ManyToOne
|
||||||
|
@JoinColumn(name = "theater_id", referencedColumnName = "id", updatable = false)
|
||||||
|
private Theater theater;
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
private LocalDate runningDate;
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
private Integer round;
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
private LocalDateTime startAt;
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
private LocalDateTime endAt;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
package com.ticketing.server.movie.domain;
|
||||||
|
|
||||||
|
import com.ticketing.server.global.dto.repository.AbstractEntity;
|
||||||
|
import javax.persistence.Entity;
|
||||||
|
import javax.persistence.JoinColumn;
|
||||||
|
import javax.persistence.ManyToOne;
|
||||||
|
import javax.validation.constraints.NotNull;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@Getter
|
||||||
|
public class Seat extends AbstractEntity {
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
@ManyToOne
|
||||||
|
@JoinColumn(name = "theater_id", referencedColumnName = "id", updatable = false)
|
||||||
|
private Theater theater;
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
private Integer seatColumn;
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
private Integer seatRow;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
package com.ticketing.server.movie.domain;
|
||||||
|
|
||||||
|
import com.ticketing.server.global.dto.repository.AbstractEntity;
|
||||||
|
import javax.persistence.Entity;
|
||||||
|
import javax.validation.constraints.NotNull;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@Getter
|
||||||
|
public class Theater extends AbstractEntity {
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
private Integer theaterNumber;
|
||||||
|
|
||||||
|
private Integer seatCount;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
package com.ticketing.server.movie.domain;
|
||||||
|
|
||||||
|
import com.ticketing.server.global.dto.repository.AbstractEntity;
|
||||||
|
import com.ticketing.server.payment.domain.Payment;
|
||||||
|
import javax.persistence.Entity;
|
||||||
|
import javax.persistence.JoinColumn;
|
||||||
|
import javax.persistence.ManyToOne;
|
||||||
|
import javax.validation.constraints.NotNull;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@Getter
|
||||||
|
public class Ticket extends AbstractEntity {
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
@ManyToOne
|
||||||
|
@JoinColumn(name = "seat_id", referencedColumnName = "id", updatable = false)
|
||||||
|
private Seat seat;
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
@ManyToOne
|
||||||
|
@JoinColumn(name = "movie_times_id", referencedColumnName = "id", updatable = false)
|
||||||
|
private MovieTimes movieTimes;
|
||||||
|
|
||||||
|
@ManyToOne
|
||||||
|
@JoinColumn(name = "payment_id", referencedColumnName = "id", updatable = false)
|
||||||
|
private Payment payment;
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
private TicketStatus status;
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
private Integer ticketPrice;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
package com.ticketing.server.movie.domain;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@AllArgsConstructor
|
||||||
|
public enum TicketStatus {
|
||||||
|
SALE("판매가능"),
|
||||||
|
SCHEDULED("환불"),
|
||||||
|
SOLD("판매완료");
|
||||||
|
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
package com.ticketing.server.movie.domain.repository;
|
||||||
|
|
||||||
|
import com.ticketing.server.movie.domain.Movie;
|
||||||
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
import org.springframework.stereotype.Repository;
|
||||||
|
|
||||||
|
@Repository
|
||||||
|
public interface MovieRepository extends JpaRepository<Movie, Long> {
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
package com.ticketing.server.movie.domain.repository;
|
||||||
|
|
||||||
|
import com.ticketing.server.movie.domain.MovieTimes;
|
||||||
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
import org.springframework.stereotype.Repository;
|
||||||
|
|
||||||
|
@Repository
|
||||||
|
public interface MovieTimesRepository extends JpaRepository<MovieTimes, Long> {
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
package com.ticketing.server.movie.domain.repository;
|
||||||
|
|
||||||
|
import com.ticketing.server.movie.domain.Seat;
|
||||||
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
import org.springframework.stereotype.Repository;
|
||||||
|
|
||||||
|
@Repository
|
||||||
|
public interface SeatRepository extends JpaRepository<Seat, Long> {
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
package com.ticketing.server.movie.domain.repository;
|
||||||
|
|
||||||
|
import com.ticketing.server.movie.domain.Theater;
|
||||||
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
import org.springframework.stereotype.Repository;
|
||||||
|
|
||||||
|
@Repository
|
||||||
|
public interface TheaterRepository extends JpaRepository<Theater, Long> {
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
package com.ticketing.server.movie.domain.repository;
|
||||||
|
|
||||||
|
import com.ticketing.server.movie.domain.Ticket;
|
||||||
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
import org.springframework.stereotype.Repository;
|
||||||
|
|
||||||
|
@Repository
|
||||||
|
public interface TicketRepository extends JpaRepository<Ticket, Long> {
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
package com.ticketing.server.movie.service;
|
||||||
|
|
||||||
|
import com.ticketing.server.movie.service.interfaces.MovieService;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class MovieServiceImpl implements MovieService {
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
package com.ticketing.server.movie.service;
|
||||||
|
|
||||||
|
import com.ticketing.server.movie.service.interfaces.MovieTimesService;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class MovieTimesServiceImpl implements MovieTimesService {
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
package com.ticketing.server.movie.service;
|
||||||
|
|
||||||
|
import com.ticketing.server.movie.service.interfaces.SeatService;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class SeatServiceImpl implements SeatService {
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
package com.ticketing.server.movie.service;
|
||||||
|
|
||||||
|
import com.ticketing.server.movie.service.interfaces.TheaterService;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class TheaterServiceImpl implements TheaterService {
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
package com.ticketing.server.movie.service;
|
||||||
|
|
||||||
|
import com.ticketing.server.movie.service.interfaces.TicketService;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class TicketServiceImpl implements TicketService {
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
package com.ticketing.server.movie.service.interfaces;
|
||||||
|
|
||||||
|
public interface MovieService {
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
package com.ticketing.server.movie.service.interfaces;
|
||||||
|
|
||||||
|
public interface MovieTimesService {
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
package com.ticketing.server.movie.service.interfaces;
|
||||||
|
|
||||||
|
public interface SeatService {
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
package com.ticketing.server.movie.service.interfaces;
|
||||||
|
|
||||||
|
public interface TheaterService {
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
package com.ticketing.server.movie.service.interfaces;
|
||||||
|
|
||||||
|
public interface TicketService {
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
package com.ticketing.server.payment.application;
|
||||||
|
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
public class PaymentController {
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
package com.ticketing.server.payment.domain;
|
||||||
|
|
||||||
|
import com.ticketing.server.global.dto.repository.AbstractEntity;
|
||||||
|
import com.ticketing.server.user.domain.User;
|
||||||
|
import javax.persistence.Entity;
|
||||||
|
import javax.persistence.EnumType;
|
||||||
|
import javax.persistence.Enumerated;
|
||||||
|
import javax.persistence.JoinColumn;
|
||||||
|
import javax.persistence.ManyToOne;
|
||||||
|
import javax.validation.constraints.NotNull;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@Getter
|
||||||
|
public class Payment extends AbstractEntity {
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
@ManyToOne
|
||||||
|
@JoinColumn(name = "user_id", referencedColumnName = "id", updatable = false)
|
||||||
|
private User user;
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
@Enumerated(value = EnumType.STRING)
|
||||||
|
private PaymentType type;
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
@Enumerated(value = EnumType.STRING)
|
||||||
|
private PaymentStatus status;
|
||||||
|
|
||||||
|
private String failedMessage;
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
private String paymentNumber;
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
private Integer totalPrice;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
package com.ticketing.server.payment.domain;
|
||||||
|
|
||||||
|
public enum PaymentStatus {
|
||||||
|
COMPLETED, REFUNDED, FAILED
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
package com.ticketing.server.payment.domain;
|
||||||
|
|
||||||
|
public enum PaymentType {
|
||||||
|
KAKAO_PAY
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
package com.ticketing.server.payment.domain.repository;
|
||||||
|
|
||||||
|
import com.ticketing.server.payment.domain.Payment;
|
||||||
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
import org.springframework.stereotype.Repository;
|
||||||
|
|
||||||
|
@Repository
|
||||||
|
public interface PaymentRepository extends JpaRepository<Payment, Long> {
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
package com.ticketing.server.payment.service;
|
||||||
|
|
||||||
|
import com.ticketing.server.payment.service.interfaces.PaymentService;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class PaymentServiceImpl implements PaymentService {
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
package com.ticketing.server.payment.service.interfaces;
|
||||||
|
|
||||||
|
public interface PaymentService {
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
package com.ticketing.server.user.application;
|
||||||
|
|
||||||
|
import com.ticketing.server.user.application.request.SignUpRequest;
|
||||||
|
import com.ticketing.server.user.application.request.UserDeleteRequest;
|
||||||
|
import com.ticketing.server.user.application.request.UserModifyPasswordRequest;
|
||||||
|
import com.ticketing.server.user.application.response.SignUpResponse;
|
||||||
|
import com.ticketing.server.user.application.response.UserDeleteResponse;
|
||||||
|
import com.ticketing.server.user.application.response.UserChangePasswordResponse;
|
||||||
|
import com.ticketing.server.user.domain.User;
|
||||||
|
import com.ticketing.server.user.service.UserServiceImpl;
|
||||||
|
import javax.validation.Valid;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||||
|
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||||
|
import org.springframework.web.bind.annotation.PatchMapping;
|
||||||
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestBody;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
@RequestMapping("/user")
|
||||||
|
@Slf4j
|
||||||
|
public class UserController {
|
||||||
|
|
||||||
|
private final UserServiceImpl userService;
|
||||||
|
private final PasswordEncoder passwordEncoder;
|
||||||
|
|
||||||
|
@PostMapping
|
||||||
|
public ResponseEntity<Object> register(@RequestBody @Valid SignUpRequest request) {
|
||||||
|
User user = userService.register(request.toSignUpDto(passwordEncoder));
|
||||||
|
return ResponseEntity.status(HttpStatus.CREATED).body(SignUpResponse.of(user));
|
||||||
|
}
|
||||||
|
|
||||||
|
@DeleteMapping
|
||||||
|
public ResponseEntity<Object> deleteUser(@RequestBody @Valid UserDeleteRequest request) {
|
||||||
|
User user = userService.delete(request.toDeleteUserDto(passwordEncoder));
|
||||||
|
return ResponseEntity.status(HttpStatus.OK).body(UserDeleteResponse.of(user));
|
||||||
|
}
|
||||||
|
|
||||||
|
@PatchMapping("/password")
|
||||||
|
public ResponseEntity<Object> changePassword(@RequestBody @Valid UserModifyPasswordRequest request) {
|
||||||
|
if (request.oldEqualNew()) {
|
||||||
|
log.error("기존 패스워드와 동일한 패스워드로 변경할 수 없습니다.");
|
||||||
|
return ResponseEntity.status(HttpStatus.BAD_REQUEST).build();
|
||||||
|
}
|
||||||
|
|
||||||
|
User user = userService.changePassword(request.toChangePasswordDto(passwordEncoder));
|
||||||
|
return ResponseEntity.status(HttpStatus.OK).body(UserChangePasswordResponse.of(user));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
package com.ticketing.server.user.application.request;
|
||||||
|
|
||||||
|
import com.ticketing.server.global.validator.constraints.Phone;
|
||||||
|
import com.ticketing.server.user.service.dto.SignUpDTO;
|
||||||
|
import javax.validation.constraints.Email;
|
||||||
|
import javax.validation.constraints.NotEmpty;
|
||||||
|
import lombok.Getter;
|
||||||
|
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
public class SignUpRequest {
|
||||||
|
|
||||||
|
@NotEmpty(message = "{validation.not.empty.name}")
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
@NotEmpty(message = "{validation.not.empty.email}")
|
||||||
|
@Email(message = "{validation.email}")
|
||||||
|
private String email;
|
||||||
|
|
||||||
|
@NotEmpty(message = "{validation.not.empty.password}")
|
||||||
|
private String password;
|
||||||
|
|
||||||
|
@NotEmpty(message = "{validation.not.empty.phone}")
|
||||||
|
@Phone
|
||||||
|
private String phone;
|
||||||
|
|
||||||
|
public SignUpDTO toSignUpDto(PasswordEncoder passwordEncoder) {
|
||||||
|
return new SignUpDTO(name, email, getEncodePassword(passwordEncoder), phone);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getEncodePassword(PasswordEncoder passwordEncoder) {
|
||||||
|
return passwordEncoder.encode(password);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
package com.ticketing.server.user.application.request;
|
||||||
|
|
||||||
|
import com.ticketing.server.user.service.dto.DeleteUserDTO;
|
||||||
|
import javax.validation.constraints.Email;
|
||||||
|
import javax.validation.constraints.NotEmpty;
|
||||||
|
import lombok.Getter;
|
||||||
|
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
public class UserDeleteRequest {
|
||||||
|
|
||||||
|
@NotEmpty(message = "{validation.not.empty.email}")
|
||||||
|
@Email(message = "{validation.email}")
|
||||||
|
private String email;
|
||||||
|
|
||||||
|
@NotEmpty(message = "{validation.not.empty.password}")
|
||||||
|
private String password;
|
||||||
|
|
||||||
|
public DeleteUserDTO toDeleteUserDto(PasswordEncoder passwordEncoder) {
|
||||||
|
return new DeleteUserDTO(email, password, passwordEncoder);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
package com.ticketing.server.user.application.request;
|
||||||
|
|
||||||
|
import com.ticketing.server.user.service.dto.ChangePasswordDTO;
|
||||||
|
import javax.validation.constraints.Email;
|
||||||
|
import javax.validation.constraints.NotEmpty;
|
||||||
|
import lombok.Getter;
|
||||||
|
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
public class UserModifyPasswordRequest {
|
||||||
|
|
||||||
|
@NotEmpty(message = "{validation.not.empty.email}")
|
||||||
|
@Email(message = "{validation.email}")
|
||||||
|
private String email;
|
||||||
|
|
||||||
|
@NotEmpty(message = "{validation.not.empty.oldpassword}")
|
||||||
|
private String oldPassword;
|
||||||
|
|
||||||
|
@NotEmpty(message = "{validation.not.empty.newpassword}")
|
||||||
|
private String newPassword;
|
||||||
|
|
||||||
|
public ChangePasswordDTO toChangePasswordDto(PasswordEncoder passwordEncoder) {
|
||||||
|
return new ChangePasswordDTO(email, oldPassword, newPassword, passwordEncoder);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean oldEqualNew() {
|
||||||
|
return oldPassword.equals(newPassword);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
package com.ticketing.server.user.application.response;
|
||||||
|
|
||||||
|
import com.ticketing.server.user.domain.User;
|
||||||
|
|
||||||
|
public class SignUpResponse {
|
||||||
|
|
||||||
|
public static SignUpResponse of(User user) {
|
||||||
|
return new SignUpResponse(user.getName(), user.getEmail());
|
||||||
|
}
|
||||||
|
|
||||||
|
public SignUpResponse(String name, String email) {
|
||||||
|
this.name = name;
|
||||||
|
this.email = email;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
private String email;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
package com.ticketing.server.user.application.response;
|
||||||
|
|
||||||
|
import com.ticketing.server.user.domain.User;
|
||||||
|
|
||||||
|
public class UserChangePasswordResponse {
|
||||||
|
|
||||||
|
public static SignUpResponse of(User user) {
|
||||||
|
return new SignUpResponse(user.getName(), user.getEmail());
|
||||||
|
}
|
||||||
|
|
||||||
|
public UserChangePasswordResponse(String name, String email) {
|
||||||
|
this.name = name;
|
||||||
|
this.email = email;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
private String email;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
package com.ticketing.server.user.application.response;
|
||||||
|
|
||||||
|
import com.ticketing.server.user.domain.User;
|
||||||
|
|
||||||
|
public class UserDeleteResponse {
|
||||||
|
|
||||||
|
public static SignUpResponse of(User user) {
|
||||||
|
return new SignUpResponse(user.getName(), user.getEmail());
|
||||||
|
}
|
||||||
|
|
||||||
|
public UserDeleteResponse(String name, String email) {
|
||||||
|
this.name = name;
|
||||||
|
this.email = email;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
private String email;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,86 @@
|
|||||||
|
package com.ticketing.server.user.domain;
|
||||||
|
|
||||||
|
import com.ticketing.server.global.dto.repository.AbstractEntity;
|
||||||
|
import com.ticketing.server.global.exception.AlreadyDeletedException;
|
||||||
|
import com.ticketing.server.global.exception.PasswordMismatchException;
|
||||||
|
import com.ticketing.server.global.validator.constraints.Phone;
|
||||||
|
import com.ticketing.server.user.service.dto.ChangePasswordDTO;
|
||||||
|
import com.ticketing.server.user.service.dto.DeleteUserDTO;
|
||||||
|
import com.ticketing.server.user.service.dto.PasswordMatches;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import javax.persistence.Column;
|
||||||
|
import javax.persistence.Entity;
|
||||||
|
import javax.persistence.EnumType;
|
||||||
|
import javax.persistence.Enumerated;
|
||||||
|
import javax.validation.constraints.Email;
|
||||||
|
import javax.validation.constraints.NotEmpty;
|
||||||
|
import javax.validation.constraints.NotNull;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@Getter
|
||||||
|
@NoArgsConstructor
|
||||||
|
public class User extends AbstractEntity {
|
||||||
|
|
||||||
|
public User(String name, String email, String password, UserGrade grade, String phone) {
|
||||||
|
this.name = name;
|
||||||
|
this.email = email;
|
||||||
|
this.password = password;
|
||||||
|
this.grade = grade;
|
||||||
|
this.phone = phone;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Column(name = "name")
|
||||||
|
@NotEmpty(message = "{validation.not.empty.name}")
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
@Column(name = "email")
|
||||||
|
@NotEmpty(message = "{validation.not.empty.email}")
|
||||||
|
@Email(message = "{validation.email}")
|
||||||
|
private String email;
|
||||||
|
|
||||||
|
@Column(name = "password")
|
||||||
|
@NotEmpty(message = "{validation.not.empty.password}")
|
||||||
|
private String password;
|
||||||
|
|
||||||
|
@Column(name = "grade")
|
||||||
|
@NotNull(message = "{validation.not.empty.grade}")
|
||||||
|
@Enumerated(value = EnumType.STRING)
|
||||||
|
private UserGrade grade = UserGrade.GUEST;
|
||||||
|
|
||||||
|
@Column(name = "phone")
|
||||||
|
@NotEmpty(message = "{validation.not.empty.phone}")
|
||||||
|
@Phone
|
||||||
|
private String phone;
|
||||||
|
|
||||||
|
private boolean isDeleted = false;
|
||||||
|
|
||||||
|
private LocalDateTime deletedAt;
|
||||||
|
|
||||||
|
public User delete(DeleteUserDTO deleteUser) {
|
||||||
|
if (isDeleted) {
|
||||||
|
throw new AlreadyDeletedException("이미 탈퇴된 회원 입니다.");
|
||||||
|
}
|
||||||
|
|
||||||
|
checkPassword(deleteUser);
|
||||||
|
|
||||||
|
isDeleted = true;
|
||||||
|
deletedAt = LocalDateTime.now();
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public User changePassword(ChangePasswordDTO changePassword) {
|
||||||
|
checkPassword(changePassword);
|
||||||
|
|
||||||
|
this.password = changePassword.getEncodePassword();
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void checkPassword(PasswordMatches passwordMatches) {
|
||||||
|
if (!passwordMatches.passwordMatches(password)) {
|
||||||
|
throw new PasswordMismatchException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
package com.ticketing.server.user.domain;
|
||||||
|
|
||||||
|
public enum UserGrade {
|
||||||
|
GUEST, STAFF
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
package com.ticketing.server.user.domain.repository;
|
||||||
|
|
||||||
|
import com.ticketing.server.user.domain.User;
|
||||||
|
import java.util.Optional;
|
||||||
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
import org.springframework.stereotype.Repository;
|
||||||
|
|
||||||
|
@Repository
|
||||||
|
public interface UserRepository extends JpaRepository<User, Long> {
|
||||||
|
|
||||||
|
Optional<User> findByEmail(String email);
|
||||||
|
|
||||||
|
Optional<User> findByEmailAndIsDeletedFalse(String email);
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,65 @@
|
|||||||
|
package com.ticketing.server.user.service;
|
||||||
|
|
||||||
|
import com.ticketing.server.global.exception.NotFoundEmailException;
|
||||||
|
import com.ticketing.server.user.domain.User;
|
||||||
|
import com.ticketing.server.user.domain.repository.UserRepository;
|
||||||
|
import com.ticketing.server.user.service.dto.ChangePasswordDTO;
|
||||||
|
import com.ticketing.server.user.service.dto.DeleteUserDTO;
|
||||||
|
import com.ticketing.server.user.service.dto.SignUpDTO;
|
||||||
|
import com.ticketing.server.user.service.interfaces.UserService;
|
||||||
|
import java.util.Optional;
|
||||||
|
import javax.validation.Valid;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
import org.springframework.validation.annotation.Validated;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
@Transactional(readOnly = true)
|
||||||
|
@Validated
|
||||||
|
@Slf4j
|
||||||
|
public class UserServiceImpl implements UserService {
|
||||||
|
|
||||||
|
private final UserRepository userRepository;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional
|
||||||
|
public User register(@Valid SignUpDTO signUpDto) {
|
||||||
|
Optional<User> user = userRepository.findByEmail(signUpDto.getEmail());
|
||||||
|
if (user.isPresent()) {
|
||||||
|
log.error("이미 존재하는 이메일이기 때문에 신규 회원가입을 진행할 수 없습니다. :: {}", signUpDto);
|
||||||
|
throw new IllegalArgumentException("이미 존재하는 이메일이기 때문에 신규 회원가입을 진행할 수 없습니다.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return userRepository.save(signUpDto.toUser());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional
|
||||||
|
public User delete(@Valid DeleteUserDTO deleteUserDto) {
|
||||||
|
Optional<User> optionalUser = userRepository.findByEmail(deleteUserDto.getEmail());
|
||||||
|
if (optionalUser.isEmpty()) {
|
||||||
|
log.error("존재하지 않는 이메일 입니다. :: {}", deleteUserDto);
|
||||||
|
throw new NotFoundEmailException();
|
||||||
|
}
|
||||||
|
|
||||||
|
User user = optionalUser.get();
|
||||||
|
return user.delete(deleteUserDto);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional
|
||||||
|
public User changePassword(@Valid ChangePasswordDTO changePasswordDto) {
|
||||||
|
Optional<User> optionalUser = userRepository.findByEmailAndIsDeletedFalse(changePasswordDto.getEmail());
|
||||||
|
if (optionalUser.isEmpty()) {
|
||||||
|
log.error("존재하지 않는 이메일 입니다. :: {}", changePasswordDto);
|
||||||
|
throw new NotFoundEmailException();
|
||||||
|
}
|
||||||
|
|
||||||
|
User user = optionalUser.get();
|
||||||
|
return user.changePassword(changePasswordDto);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
package com.ticketing.server.user.service.dto;
|
||||||
|
|
||||||
|
import javax.validation.constraints.Email;
|
||||||
|
import javax.validation.constraints.NotEmpty;
|
||||||
|
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||||
|
|
||||||
|
public class ChangePasswordDTO implements PasswordMatches {
|
||||||
|
|
||||||
|
public ChangePasswordDTO(String email, String oldPassword, String newPassword, PasswordEncoder passwordEncoder) {
|
||||||
|
this.email = email;
|
||||||
|
this.oldPassword = oldPassword;
|
||||||
|
this.newPassword = newPassword;
|
||||||
|
this.passwordEncoder = passwordEncoder;
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotEmpty(message = "{validation.not.empty.email}")
|
||||||
|
@Email(message = "{validation.email}")
|
||||||
|
private String email;
|
||||||
|
|
||||||
|
@NotEmpty(message = "{validation.not.empty.oldpassword}")
|
||||||
|
private String oldPassword;
|
||||||
|
|
||||||
|
@NotEmpty(message = "{validation.not.empty.newpassword}")
|
||||||
|
private String newPassword;
|
||||||
|
|
||||||
|
private PasswordEncoder passwordEncoder;
|
||||||
|
|
||||||
|
public String getEmail() {
|
||||||
|
return email;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean passwordMatches(String password) {
|
||||||
|
return passwordEncoder.matches(oldPassword, password);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getEncodePassword() {
|
||||||
|
return passwordEncoder.encode(newPassword);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "ChangePassword{" +
|
||||||
|
"email='" + email + '\'' +
|
||||||
|
'}';
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
package com.ticketing.server.user.service.dto;
|
||||||
|
|
||||||
|
import javax.validation.constraints.Email;
|
||||||
|
import javax.validation.constraints.NotEmpty;
|
||||||
|
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||||
|
|
||||||
|
public class DeleteUserDTO implements PasswordMatches {
|
||||||
|
|
||||||
|
public DeleteUserDTO(String email, String inputPassword, PasswordEncoder passwordEncoder) {
|
||||||
|
this.email = email;
|
||||||
|
this.inputPassword = inputPassword;
|
||||||
|
this.passwordEncoder = passwordEncoder;
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotEmpty(message = "{validation.not.empty.email}")
|
||||||
|
@Email(message = "{validation.email}")
|
||||||
|
private String email;
|
||||||
|
|
||||||
|
@NotEmpty(message = "{validation.not.empty.password}")
|
||||||
|
private String inputPassword;
|
||||||
|
|
||||||
|
private PasswordEncoder passwordEncoder;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean passwordMatches(String password) {
|
||||||
|
return passwordEncoder.matches(this.inputPassword, password);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getEmail() {
|
||||||
|
return email;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "DeleteUser{" +
|
||||||
|
"email='" + email + '\'' +
|
||||||
|
'}';
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
package com.ticketing.server.user.service.dto;
|
||||||
|
|
||||||
|
@FunctionalInterface
|
||||||
|
public interface PasswordMatches {
|
||||||
|
|
||||||
|
boolean passwordMatches(String password);
|
||||||
|
}
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
package com.ticketing.server.user.service.dto;
|
||||||
|
|
||||||
|
import com.ticketing.server.global.validator.constraints.Phone;
|
||||||
|
import com.ticketing.server.user.domain.User;
|
||||||
|
import com.ticketing.server.user.domain.UserGrade;
|
||||||
|
import javax.validation.constraints.Email;
|
||||||
|
import javax.validation.constraints.NotEmpty;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
public class SignUpDTO {
|
||||||
|
|
||||||
|
@NotEmpty(message = "{validation.not.empty.name}")
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
@NotEmpty(message = "{validation.not.empty.email}")
|
||||||
|
@Email(message = "{validation.email}")
|
||||||
|
private String email;
|
||||||
|
|
||||||
|
@NotEmpty(message = "{validation.not.empty.password}")
|
||||||
|
private String password;
|
||||||
|
|
||||||
|
@NotEmpty(message = "{validation.not.empty.phone}")
|
||||||
|
@Phone
|
||||||
|
private String phone;
|
||||||
|
|
||||||
|
public SignUpDTO(String name, String email, String password, String phone) {
|
||||||
|
this.name = name;
|
||||||
|
this.email = email;
|
||||||
|
this.password = password;
|
||||||
|
this.phone = phone;
|
||||||
|
}
|
||||||
|
|
||||||
|
public User toUser() {
|
||||||
|
return new User(this.name, this.email, password, UserGrade.GUEST, this.phone);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "SignUp{" +
|
||||||
|
"name='" + name + '\'' +
|
||||||
|
", email='" + email + '\'' +
|
||||||
|
", phone='" + phone + '\'' +
|
||||||
|
'}';
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
package com.ticketing.server.user.service.interfaces;
|
||||||
|
|
||||||
|
import com.ticketing.server.user.domain.User;
|
||||||
|
import com.ticketing.server.user.service.dto.ChangePasswordDTO;
|
||||||
|
import com.ticketing.server.user.service.dto.DeleteUserDTO;
|
||||||
|
import com.ticketing.server.user.service.dto.SignUpDTO;
|
||||||
|
import javax.validation.Valid;
|
||||||
|
|
||||||
|
public interface UserService {
|
||||||
|
|
||||||
|
User register(@Valid SignUpDTO signUpDto);
|
||||||
|
|
||||||
|
User delete(@Valid DeleteUserDTO deleteUserDto);
|
||||||
|
|
||||||
|
User changePassword(@Valid ChangePasswordDTO changePasswordDto);
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
spring:
|
spring:
|
||||||
datasource:
|
datasource:
|
||||||
url: jdbc:mysql://localhost:3306/ticketing?serverTimezone=Asia/Seoul&characterEncoding=UTF-8
|
url: jdbc:mysql://localhost:3306/ticketing?serverTimezone=Asia/Seoul&characterEncoding=UTF-8
|
||||||
username: ticketing
|
username: ENC(LowN1n4w0Ep/DqLD8+q5Bq6AXM4b8e3V)
|
||||||
password: ticketing
|
password: ENC(OMvGcpZLpggFTiGNkqNe66Zq/SmJXF6o)
|
||||||
driver-class-name: com.mysql.cj.jdbc.Driver
|
driver-class-name: com.mysql.cj.jdbc.Driver
|
||||||
|
|
||||||
jpa:
|
jpa:
|
||||||
|
|||||||
@@ -14,14 +14,7 @@ spring:
|
|||||||
connection-timeout: 30000 # default 30s
|
connection-timeout: 30000 # default 30s
|
||||||
maximum-pool-size: 10 # default 10
|
maximum-pool-size: 10 # default 10
|
||||||
max-lifetime: 1800000 # default 30 minutes
|
max-lifetime: 1800000 # default 30 minutes
|
||||||
data-source-properties:
|
|
||||||
cachePrepStmts: true
|
jasypt:
|
||||||
prepStmtCacheSize: 250
|
encryptor:
|
||||||
prepStmtCacheSqlLimit: 2048
|
bean: jasyptStringEncryptor
|
||||||
useServerPrepStmts: true
|
|
||||||
useLocalSessionState: true
|
|
||||||
rewriteBatchedStatements: true
|
|
||||||
cacheResultSetMetadata: true
|
|
||||||
cacheServerConfiguration: true
|
|
||||||
elideSetAutoCommits: true
|
|
||||||
maintainTimeStats: false
|
|
||||||
|
|||||||
9
server/src/main/resources/i18n/messages.properties
Normal file
9
server/src/main/resources/i18n/messages.properties
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
validation.not.empty.name="\uC774\uB984\uC740 \uD544\uC218 \uC785\uB2C8\uB2E4."
|
||||||
|
validation.not.empty.email="\uC774\uBA54\uC77C\uC740 \uD544\uC218 \uC785\uB2C8\uB2E4."
|
||||||
|
validation.not.empty.password="\uD328\uC2A4\uC6CC\uB4DC\uB294 \uD544\uC218 \uC785\uB2C8\uB2E4."
|
||||||
|
validation.not.empty.oldpassword="\uD604\uC7AC \uD328\uC2A4\uC6CC\uB4DC\uB294 \uD544\uC218 \uC785\uB2C8\uB2E4."
|
||||||
|
validation.not.empty.newpassword="\uBCC0\uACBD\uD560 \uD328\uC2A4\uC6CC\uB4DC\uB294 \uD544\uC218 \uC785\uB2C8\uB2E4."
|
||||||
|
validation.not.empty.grade="\uC0AC\uC6A9\uC790 \uB4F1\uAE09\uC740 \uD544\uC218 \uC785\uB2C8\uB2E4."
|
||||||
|
validation.not.empty.phone="\uD734\uB300\uBC88\uD638\uB294 \uD544\uC218 \uC785\uB2C8\uB2E4."
|
||||||
|
validation.email="\uC774\uBA54\uC77C\uC774 \uC62C\uBC14\uB974\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4."
|
||||||
|
validation.phone="\uD734\uB300\uBC88\uD638\uAC00 \uC62C\uBC14\uB974\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4."
|
||||||
9
server/src/main/resources/i18n/messages_en.properties
Normal file
9
server/src/main/resources/i18n/messages_en.properties
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
validation.not.empty.name="name is required."
|
||||||
|
validation.not.empty.email="email is required."
|
||||||
|
validation.not.empty.password="password is required."
|
||||||
|
validation.not.empty.oldpassword="Old Password is required."
|
||||||
|
validation.not.empty.newpassword="New Password is required."
|
||||||
|
validation.not.empty.grade="user grade is required."
|
||||||
|
validation.not.empty.phone="phone is required."
|
||||||
|
validation.email="email is not valid."
|
||||||
|
validation.phone="phone is not valid."
|
||||||
9
server/src/main/resources/i18n/messages_ko.properties
Normal file
9
server/src/main/resources/i18n/messages_ko.properties
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
validation.not.empty.name="\uC774\uB984\uC740 \uD544\uC218 \uC785\uB2C8\uB2E4."
|
||||||
|
validation.not.empty.email="\uC774\uBA54\uC77C\uC740 \uD544\uC218 \uC785\uB2C8\uB2E4."
|
||||||
|
validation.not.empty.password="\uD328\uC2A4\uC6CC\uB4DC\uB294 \uD544\uC218 \uC785\uB2C8\uB2E4."
|
||||||
|
validation.not.empty.oldpassword="\uD604\uC7AC \uD328\uC2A4\uC6CC\uB4DC\uB294 \uD544\uC218 \uC785\uB2C8\uB2E4."
|
||||||
|
validation.not.empty.newpassword="\uBCC0\uACBD\uD560 \uD328\uC2A4\uC6CC\uB4DC\uB294 \uD544\uC218 \uC785\uB2C8\uB2E4."
|
||||||
|
validation.not.empty.grade="\uC0AC\uC6A9\uC790 \uB4F1\uAE09\uC740 \uD544\uC218 \uC785\uB2C8\uB2E4."
|
||||||
|
validation.not.empty.phone="\uD734\uB300\uBC88\uD638\uB294 \uD544\uC218 \uC785\uB2C8\uB2E4."
|
||||||
|
validation.email="\uC774\uBA54\uC77C\uC774 \uC62C\uBC14\uB974\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4."
|
||||||
|
validation.phone="\uD734\uB300\uBC88\uD638\uAC00 \uC62C\uBC14\uB974\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4."
|
||||||
38
server/src/main/resources/log4j2.xml
Normal file
38
server/src/main/resources/log4j2.xml
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" ?>
|
||||||
|
<Configuration status="INFO" monitorInterval="30">
|
||||||
|
|
||||||
|
<Properties>
|
||||||
|
<Property name="LOG_PATH">./logs/log</Property>
|
||||||
|
<Property name="LOG_PATTERN">%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n</Property>
|
||||||
|
</Properties>
|
||||||
|
|
||||||
|
<Appenders>
|
||||||
|
<Console name="ConsoleLog" target="SYSTEM_OUT">
|
||||||
|
<PatternLayout pattern="${LOG_PATTERN}" charset="UTF-8"/>
|
||||||
|
</Console>
|
||||||
|
|
||||||
|
<RollingFile name="FileLog"
|
||||||
|
fileName="${LOG_PATH}.log"
|
||||||
|
filePattern="${LOG_PATH}-%d{yyyy-MM-dd}-%i.log">
|
||||||
|
<PatternLayout pattern="${LOG_PATTERN}" charset="UTF-8" />
|
||||||
|
|
||||||
|
<Policies>
|
||||||
|
<SizeBasedTriggeringPolicy size="15MB" />
|
||||||
|
<TimeBasedTriggeringPolicy modulate="true" interval="1" />
|
||||||
|
</Policies>
|
||||||
|
|
||||||
|
<DefaultRolloverStrategy>
|
||||||
|
<Delete basePath="${LOG_PATH}" maxDepth="1">
|
||||||
|
<IfLastModified age="30d"/>
|
||||||
|
</Delete>
|
||||||
|
</DefaultRolloverStrategy>
|
||||||
|
</RollingFile>
|
||||||
|
</Appenders>
|
||||||
|
|
||||||
|
<Loggers>
|
||||||
|
<Root level="info">
|
||||||
|
<AppenderRef ref="ConsoleLog" />
|
||||||
|
<AppenderRef ref="FileLog" />
|
||||||
|
</Root>
|
||||||
|
</Loggers>
|
||||||
|
</Configuration>
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
package com.ticketing.server.global.health;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.boot.test.context.SpringBootTest;
|
||||||
|
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
|
||||||
|
import org.springframework.boot.test.web.client.TestRestTemplate;
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
|
||||||
|
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
|
||||||
|
class L7checkControllerTest {
|
||||||
|
|
||||||
|
private static final String L7CHECK = "/l7check";
|
||||||
|
private static final String HEALTH = "/actuator/health";
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
TestRestTemplate restTemplate;
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void downAndUp() throws InterruptedException {
|
||||||
|
// before
|
||||||
|
expectUrlStatus(L7CHECK, HttpStatus.OK);
|
||||||
|
expectUrlStatus(HEALTH, HttpStatus.OK);
|
||||||
|
|
||||||
|
// down
|
||||||
|
restTemplate.delete(L7CHECK);
|
||||||
|
|
||||||
|
// then down
|
||||||
|
TimeUnit.MILLISECONDS.sleep(1000);
|
||||||
|
expectUrlStatus(L7CHECK, HttpStatus.SERVICE_UNAVAILABLE);
|
||||||
|
expectUrlStatus(HEALTH, HttpStatus.SERVICE_UNAVAILABLE);
|
||||||
|
|
||||||
|
// up
|
||||||
|
restTemplate.postForEntity(L7CHECK, null, Object.class);
|
||||||
|
|
||||||
|
// then up
|
||||||
|
TimeUnit.MILLISECONDS.sleep(1000);
|
||||||
|
expectUrlStatus(L7CHECK, HttpStatus.OK);
|
||||||
|
expectUrlStatus(HEALTH, HttpStatus.OK);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void expectUrlStatus(String url, HttpStatus status) {
|
||||||
|
ResponseEntity<Object> res = restTemplate.getForEntity(url, Object.class);
|
||||||
|
assertThat(res.getStatusCode()).isEqualTo(status);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,280 @@
|
|||||||
|
package com.ticketing.server.user.domain;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertAll;
|
||||||
|
|
||||||
|
import com.ticketing.server.global.exception.AlreadyDeletedException;
|
||||||
|
import com.ticketing.server.global.exception.PasswordMismatchException;
|
||||||
|
import com.ticketing.server.user.service.dto.ChangePasswordDTO;
|
||||||
|
import com.ticketing.server.user.service.dto.DeleteUserDTO;
|
||||||
|
import com.ticketing.server.user.service.dto.DeleteUserDtoTest;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
import javax.validation.ConstraintViolation;
|
||||||
|
import javax.validation.Validation;
|
||||||
|
import javax.validation.Validator;
|
||||||
|
import javax.validation.ValidatorFactory;
|
||||||
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
|
import org.junit.jupiter.api.DisplayName;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.junit.jupiter.params.ParameterizedTest;
|
||||||
|
import org.junit.jupiter.params.provider.MethodSource;
|
||||||
|
|
||||||
|
class UserTest {
|
||||||
|
|
||||||
|
private Validator validator;
|
||||||
|
private Map<String, User> users;
|
||||||
|
|
||||||
|
@BeforeEach
|
||||||
|
void init() {
|
||||||
|
ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
|
||||||
|
validator = factory.getValidator();
|
||||||
|
users = provideCorrectUsers().collect(Collectors.toMap(User::getEmail, user -> user));
|
||||||
|
}
|
||||||
|
|
||||||
|
@ParameterizedTest
|
||||||
|
@MethodSource("provideDifferentPasswordDeleteUsers")
|
||||||
|
@DisplayName("입력된 패스워드가 다를 경우")
|
||||||
|
void passwordMismatchException(DeleteUserDTO deleteUser) {
|
||||||
|
// given
|
||||||
|
User user = users.get(deleteUser.getEmail());
|
||||||
|
|
||||||
|
// when
|
||||||
|
// then
|
||||||
|
assertThatThrownBy(() -> user.delete(deleteUser))
|
||||||
|
.isInstanceOf(PasswordMismatchException.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@ParameterizedTest
|
||||||
|
@MethodSource("provideDeleteUsers")
|
||||||
|
@DisplayName("이미 회원탈퇴 되어 있는 경우")
|
||||||
|
void alreadyDeletedException(DeleteUserDTO deleteUserDto) {
|
||||||
|
// given
|
||||||
|
User user = users.get(deleteUserDto.getEmail());
|
||||||
|
|
||||||
|
// when
|
||||||
|
user.delete(deleteUserDto);
|
||||||
|
|
||||||
|
// then
|
||||||
|
assertThatThrownBy(() -> user.delete(deleteUserDto))
|
||||||
|
.isInstanceOf(AlreadyDeletedException.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@ParameterizedTest
|
||||||
|
@MethodSource("provideDeleteUsers")
|
||||||
|
@DisplayName("회원탈퇴 성공")
|
||||||
|
void deleteSuccess(DeleteUserDTO deleteUserDto) {
|
||||||
|
// given
|
||||||
|
User user = users.get(deleteUserDto.getEmail());
|
||||||
|
|
||||||
|
// when
|
||||||
|
User deletedUser = user.delete(deleteUserDto);
|
||||||
|
|
||||||
|
// then
|
||||||
|
assertAll(
|
||||||
|
() -> assertThat(deletedUser.getDeletedAt()).isNotNull()
|
||||||
|
, () -> assertThat(deletedUser.isDeleted()).isTrue()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("입력받은 패스워드와 불일치로 변경 실패")
|
||||||
|
void changePasswordFail() {
|
||||||
|
// given
|
||||||
|
ChangePasswordDTO changePasswordDto = new ChangePasswordDTO("ticketing1@gmail.com", "1234567", "ticketing1234", DeleteUserDtoTest.CUSTOM_PASSWORD_ENCODER);
|
||||||
|
User user = users.get(changePasswordDto.getEmail());
|
||||||
|
|
||||||
|
// when
|
||||||
|
// then
|
||||||
|
assertThatThrownBy(() -> user.changePassword(changePasswordDto))
|
||||||
|
.isInstanceOf(PasswordMismatchException.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("패스워드 변경 성공")
|
||||||
|
void changePasswordSuccess() {
|
||||||
|
// given
|
||||||
|
ChangePasswordDTO changePasswordDto = new ChangePasswordDTO("ticketing1@gmail.com", "123456", "ticketing1234", DeleteUserDtoTest.CUSTOM_PASSWORD_ENCODER);
|
||||||
|
User user = users.get(changePasswordDto.getEmail());
|
||||||
|
String oldPassword = user.getPassword();
|
||||||
|
|
||||||
|
// when
|
||||||
|
User modifiedUser = user.changePassword(changePasswordDto);
|
||||||
|
|
||||||
|
// then
|
||||||
|
assertThat(modifiedUser.getPassword()).isNotEqualTo(oldPassword);
|
||||||
|
}
|
||||||
|
|
||||||
|
@ParameterizedTest
|
||||||
|
@MethodSource("provideCorrectUsers")
|
||||||
|
@DisplayName("유저 검증 성공")
|
||||||
|
void validateSuccess(User user) {
|
||||||
|
// given
|
||||||
|
// when
|
||||||
|
Set<ConstraintViolation<User>> constraintViolations = validator.validate(user);
|
||||||
|
|
||||||
|
// then
|
||||||
|
assertThat(constraintViolations).isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
@ParameterizedTest
|
||||||
|
@MethodSource("provideNullOrEmptyOfName")
|
||||||
|
@DisplayName("name null 혹은 빈값 검증")
|
||||||
|
void nameNullOrEmpty(User user) {
|
||||||
|
// given
|
||||||
|
// when
|
||||||
|
Set<ConstraintViolation<User>> constraintViolations = validator.validate(user);
|
||||||
|
|
||||||
|
// then
|
||||||
|
assertThat(constraintViolations).hasSize(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@ParameterizedTest
|
||||||
|
@MethodSource("provideNullOrEmptyOfEmail")
|
||||||
|
@DisplayName("email null or empty 검증")
|
||||||
|
void emailNullOrEmpty(User user) {
|
||||||
|
// given
|
||||||
|
// when
|
||||||
|
Set<ConstraintViolation<User>> constraintViolations = validator.validate(user);
|
||||||
|
|
||||||
|
// then
|
||||||
|
assertThat(constraintViolations).hasSize(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@ParameterizedTest
|
||||||
|
@MethodSource("provideValidationFailedOfEmail")
|
||||||
|
@DisplayName("email 실패 검증")
|
||||||
|
void emailValid(User user) {
|
||||||
|
// given
|
||||||
|
// when
|
||||||
|
Set<ConstraintViolation<User>> constraintViolations = validator.validate(user);
|
||||||
|
|
||||||
|
// then
|
||||||
|
assertThat(constraintViolations).hasSize(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@ParameterizedTest
|
||||||
|
@MethodSource("provideNullOrEmptyOfPassword")
|
||||||
|
@DisplayName("password null 혹은 빈값 검증")
|
||||||
|
void passwordNullOrEmpty(User user) {
|
||||||
|
// given
|
||||||
|
// when
|
||||||
|
Set<ConstraintViolation<User>> constraintViolations = validator.validate(user);
|
||||||
|
|
||||||
|
// then
|
||||||
|
assertThat(constraintViolations).hasSize(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("grade null 검증")
|
||||||
|
void gradeNull() {
|
||||||
|
// given
|
||||||
|
User user = new User("유저1", "email@gmail.com", "testPassword01", null, "010-1234-5678");
|
||||||
|
|
||||||
|
// when
|
||||||
|
Set<ConstraintViolation<User>> constraintViolations = validator.validate(user);
|
||||||
|
|
||||||
|
// then
|
||||||
|
assertThat(constraintViolations).hasSize(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@ParameterizedTest
|
||||||
|
@MethodSource("provideNullOrEmptyOfPhone")
|
||||||
|
@DisplayName("phone null or empty 검증")
|
||||||
|
void phoneNullOrEmpty(User user) {
|
||||||
|
// given
|
||||||
|
// when
|
||||||
|
Set<ConstraintViolation<User>> constraintViolations = validator.validate(user);
|
||||||
|
|
||||||
|
// then
|
||||||
|
assertThat(constraintViolations).hasSize(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@ParameterizedTest
|
||||||
|
@MethodSource("provideValidationFailedOfPhone")
|
||||||
|
@DisplayName("phone 실패 검증")
|
||||||
|
void phoneValid(User user) {
|
||||||
|
// given
|
||||||
|
// when
|
||||||
|
Set<ConstraintViolation<User>> constraintViolations = validator.validate(user);
|
||||||
|
|
||||||
|
// then
|
||||||
|
assertThat(constraintViolations).hasSize(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Stream<User> provideCorrectUsers() {
|
||||||
|
return Stream.of(
|
||||||
|
new User("유저1", "ticketing1@gmail.com", "123456", UserGrade.GUEST, "010-1234-5678")
|
||||||
|
, new User("유저2", "ticketing2@gmail.com", "qwe123", UserGrade.GUEST, "010-2234-5678")
|
||||||
|
, new User("유저3", "ticketing3@gmail.com", "ticketing", UserGrade.STAFF, "010-3234-5678")
|
||||||
|
, new User("유저4", "ticketing4@gmail.com", "ticketing123456", UserGrade.STAFF, "010-4234-5678")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Stream<User> provideNullOrEmptyOfName() {
|
||||||
|
return Stream.of(
|
||||||
|
new User(null, "ticketing1@gmail.com", "123456", UserGrade.GUEST, "010-1234-5678")
|
||||||
|
, new User("", "ticketing2@gmail.com", "qwe123", UserGrade.GUEST, "010-2234-5678")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Stream<User> provideNullOrEmptyOfEmail() {
|
||||||
|
return Stream.of(
|
||||||
|
new User("유저1", null, "123456", UserGrade.GUEST, "010-1234-5678")
|
||||||
|
, new User("유저2", "", "qwe123", UserGrade.GUEST, "010-2234-5678")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Stream<User> provideValidationFailedOfEmail() {
|
||||||
|
return Stream.of(
|
||||||
|
new User("유저1", "email", "123456", UserGrade.GUEST, "010-1234-5678")
|
||||||
|
, new User("유저2", "@gmail.com", "qwe123", UserGrade.GUEST, "010-2234-5678")
|
||||||
|
, new User("유저3", "12Bye#domain.com", "ticketing", UserGrade.STAFF, "010-3234-5678")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Stream<User> provideNullOrEmptyOfPassword() {
|
||||||
|
return Stream.of(
|
||||||
|
new User("유저1", "ticketing1@gmail.com", null, UserGrade.GUEST, "010-1234-5678")
|
||||||
|
, new User("유저2", "ticketing2@gmail.com", "", UserGrade.GUEST, "010-2234-5678")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Stream<User> provideNullOrEmptyOfPhone() {
|
||||||
|
return Stream.of(
|
||||||
|
new User("유저1", "ticketing1@gmail.com", "123456", UserGrade.GUEST, null)
|
||||||
|
, new User("유저2", "ticketing2@gmail.com", "qwe123", UserGrade.GUEST, "")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Stream<User> provideValidationFailedOfPhone() {
|
||||||
|
return Stream.of(
|
||||||
|
new User("유저1", "ticketing1@gmail.com", "123456", UserGrade.GUEST, "010-123-1234")
|
||||||
|
, new User("유저2", "ticketing2@gmail.com", "qwe123", UserGrade.GUEST, "02-0444-4044")
|
||||||
|
, new User("유저3", "ticketing3@gmail.com", "ticketing", UserGrade.STAFF, "033-7953")
|
||||||
|
, new User("유저4", "ticketing4@gmail.com", "ticketing123456", UserGrade.STAFF, "033-0455-504")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Stream<DeleteUserDTO> provideDifferentPasswordDeleteUsers() {
|
||||||
|
return Stream.of(
|
||||||
|
new DeleteUserDTO("ticketing1@gmail.com", "1234561", DeleteUserDtoTest.CUSTOM_PASSWORD_ENCODER)
|
||||||
|
, new DeleteUserDTO("ticketing2@gmail.com", "qwe1231", DeleteUserDtoTest.CUSTOM_PASSWORD_ENCODER)
|
||||||
|
, new DeleteUserDTO("ticketing3@gmail.com", "ticketing1", DeleteUserDtoTest.CUSTOM_PASSWORD_ENCODER)
|
||||||
|
, new DeleteUserDTO("ticketing4@gmail.com", "ticketing1234561", DeleteUserDtoTest.CUSTOM_PASSWORD_ENCODER)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Stream<DeleteUserDTO> provideDeleteUsers() {
|
||||||
|
return Stream.of(
|
||||||
|
new DeleteUserDTO("ticketing1@gmail.com", "123456", DeleteUserDtoTest.CUSTOM_PASSWORD_ENCODER)
|
||||||
|
, new DeleteUserDTO("ticketing2@gmail.com", "qwe123", DeleteUserDtoTest.CUSTOM_PASSWORD_ENCODER)
|
||||||
|
, new DeleteUserDTO("ticketing3@gmail.com", "ticketing", DeleteUserDtoTest.CUSTOM_PASSWORD_ENCODER)
|
||||||
|
, new DeleteUserDTO("ticketing4@gmail.com", "ticketing123456", DeleteUserDtoTest.CUSTOM_PASSWORD_ENCODER)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
package com.ticketing.server.user.domain.repository;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
|
||||||
|
import com.ticketing.server.user.domain.User;
|
||||||
|
import com.ticketing.server.user.domain.UserGrade;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.boot.test.context.SpringBootTest;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
@SpringBootTest
|
||||||
|
@Transactional
|
||||||
|
class UserRepositoryTest {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
UserRepository userRepository;
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void 유저레포지토리테스트() {
|
||||||
|
// given
|
||||||
|
User user = new User("유저1", "email@gmail.com", "testPassword01", UserGrade.GUEST, "010-1234-5678");
|
||||||
|
|
||||||
|
// when
|
||||||
|
userRepository.save(user);
|
||||||
|
|
||||||
|
// then
|
||||||
|
assertThat(user).isNotNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,123 @@
|
|||||||
|
package com.ticketing.server.user.service;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||||
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
|
import com.ticketing.server.global.exception.NotFoundEmailException;
|
||||||
|
import com.ticketing.server.user.domain.User;
|
||||||
|
import com.ticketing.server.user.domain.UserGrade;
|
||||||
|
import com.ticketing.server.user.domain.repository.UserRepository;
|
||||||
|
import com.ticketing.server.user.service.dto.ChangePasswordDTO;
|
||||||
|
import com.ticketing.server.user.service.dto.DeleteUserDTO;
|
||||||
|
import com.ticketing.server.user.service.dto.DeleteUserDtoTest;
|
||||||
|
import com.ticketing.server.user.service.dto.SignUpDTO;
|
||||||
|
import java.util.Optional;
|
||||||
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
|
import org.junit.jupiter.api.DisplayName;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.junit.jupiter.api.extension.ExtendWith;
|
||||||
|
import org.mockito.InjectMocks;
|
||||||
|
import org.mockito.Mock;
|
||||||
|
import org.mockito.junit.jupiter.MockitoExtension;
|
||||||
|
|
||||||
|
@ExtendWith(MockitoExtension.class)
|
||||||
|
class UserServiceImplTest {
|
||||||
|
|
||||||
|
User user;
|
||||||
|
SignUpDTO signUpDto;
|
||||||
|
DeleteUserDTO deleteUserDto;
|
||||||
|
ChangePasswordDTO changePasswordDto;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
UserRepository userRepository;
|
||||||
|
|
||||||
|
@InjectMocks
|
||||||
|
UserServiceImpl userService;
|
||||||
|
|
||||||
|
@BeforeEach
|
||||||
|
void init() {
|
||||||
|
signUpDto = new SignUpDTO("유저", "ticketing@gmail.com", "123456", "010-1234-5678");
|
||||||
|
user = new User("유저", "ticketing@gmail.com", "123456", UserGrade.GUEST, "010-1234-5678");
|
||||||
|
deleteUserDto = new DeleteUserDTO("ticketing@gmail.com", "123456", DeleteUserDtoTest.CUSTOM_PASSWORD_ENCODER);
|
||||||
|
changePasswordDto = new ChangePasswordDTO("ticketing@gmail.com", "123456", "ticketing1234", DeleteUserDtoTest.CUSTOM_PASSWORD_ENCODER);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("이미 동일한 이메일이 있을 경우")
|
||||||
|
void duplicateEmailException() {
|
||||||
|
// given
|
||||||
|
when(userRepository.findByEmail("ticketing@gmail.com")).thenReturn(Optional.of(user));
|
||||||
|
|
||||||
|
// when
|
||||||
|
// then
|
||||||
|
assertThatThrownBy(() -> userService.register(signUpDto))
|
||||||
|
.isInstanceOf(IllegalArgumentException.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("회원가입 성공했을 경우")
|
||||||
|
void registerSuccess() {
|
||||||
|
// given
|
||||||
|
when(userRepository.findByEmail("ticketing@gmail.com")).thenReturn(Optional.empty());
|
||||||
|
when(userRepository.save(any())).thenReturn(user);
|
||||||
|
|
||||||
|
// when
|
||||||
|
User user = userService.register(signUpDto);
|
||||||
|
|
||||||
|
// then
|
||||||
|
assertThat(user).isNotNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("회원탈퇴 시 이메일이 존재하지 않을 경우")
|
||||||
|
void deleteFail() {
|
||||||
|
// given
|
||||||
|
when(userRepository.findByEmail("ticketing@gmail.com")).thenReturn(Optional.empty());
|
||||||
|
|
||||||
|
// when
|
||||||
|
// then
|
||||||
|
assertThatThrownBy(() -> userService.delete(deleteUserDto))
|
||||||
|
.isInstanceOf(NotFoundEmailException.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("회원탈퇴 성공했을 경우")
|
||||||
|
void deleteSuccess() {
|
||||||
|
// given
|
||||||
|
when(userRepository.findByEmail("ticketing@gmail.com")).thenReturn(Optional.of(user));
|
||||||
|
|
||||||
|
// when
|
||||||
|
User user = userService.delete(deleteUserDto);
|
||||||
|
|
||||||
|
// then
|
||||||
|
assertThat(user).isNotNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("패스워드 변경 시 이메일이 존재하지 않을 경우")
|
||||||
|
void changePasswordFail() {
|
||||||
|
// given
|
||||||
|
when(userRepository.findByEmailAndIsDeletedFalse("ticketing@gmail.com")).thenReturn(Optional.empty());
|
||||||
|
|
||||||
|
// when
|
||||||
|
// then
|
||||||
|
assertThatThrownBy(() -> userService.changePassword(changePasswordDto))
|
||||||
|
.isInstanceOf(NotFoundEmailException.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("패스워드 변경 성공했을 경우")
|
||||||
|
void changePasswordSuccess() {
|
||||||
|
// given
|
||||||
|
when(userRepository.findByEmailAndIsDeletedFalse("ticketing@gmail.com")).thenReturn(Optional.of(user));
|
||||||
|
|
||||||
|
// when
|
||||||
|
User user = userService.changePassword(changePasswordDto);
|
||||||
|
|
||||||
|
// then
|
||||||
|
assertThat(user).isNotNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
package com.ticketing.server.user.service.dto;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.DisplayName;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||||
|
|
||||||
|
public class DeleteUserDtoTest {
|
||||||
|
|
||||||
|
public static PasswordEncoder CUSTOM_PASSWORD_ENCODER = new CustomPasswordEncoder();
|
||||||
|
|
||||||
|
public static class CustomPasswordEncoder implements PasswordEncoder {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String encode(CharSequence rawPassword) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean matches(CharSequence rawPassword, String encodedPassword) {
|
||||||
|
return rawPassword.toString().equals(encodedPassword);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("CustomPasswordEncoder matches 테스트")
|
||||||
|
void customPasswordEncoderMatches() {
|
||||||
|
// given
|
||||||
|
DeleteUserDTO deleteUserDto = new DeleteUserDTO("ticketing@gmail.com", "123456", CUSTOM_PASSWORD_ENCODER);
|
||||||
|
|
||||||
|
// when
|
||||||
|
// then
|
||||||
|
assertThat(deleteUserDto.passwordMatches("123456")).isTrue();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
package com.ticketing.server.user.service.dto;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
|
||||||
|
import com.ticketing.server.user.domain.User;
|
||||||
|
import org.junit.jupiter.api.DisplayName;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
class SignUpDtoTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("toUser 메소드로 User 객체 생성")
|
||||||
|
void toUser() {
|
||||||
|
// given
|
||||||
|
SignUpDTO signUp = new SignUpDTO("유저1", "ticketing@gmail.com", "123456", "010-1234-5678");
|
||||||
|
|
||||||
|
// when
|
||||||
|
User user = signUp.toUser();
|
||||||
|
|
||||||
|
// then
|
||||||
|
assertThat(user).isInstanceOf(User.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
spring:
|
spring:
|
||||||
datasource:
|
datasource:
|
||||||
url: jdbc:mysql://localhost:3306/ticketing_test?serverTimezone=Asia/Seoul&characterEncoding=UTF-8
|
url: jdbc:mysql://localhost:3306/ticketing_test?serverTimezone=Asia/Seoul&characterEncoding=UTF-8
|
||||||
username: ticketing
|
username: ENC(LowN1n4w0Ep/DqLD8+q5Bq6AXM4b8e3V)
|
||||||
password: ticketing
|
password: ENC(OMvGcpZLpggFTiGNkqNe66Zq/SmJXF6o)
|
||||||
driver-class-name: com.mysql.cj.jdbc.Driver
|
driver-class-name: com.mysql.cj.jdbc.Driver
|
||||||
|
|
||||||
jpa:
|
jpa:
|
||||||
@@ -12,3 +12,7 @@ spring:
|
|||||||
format_sql: true
|
format_sql: true
|
||||||
hibernate:
|
hibernate:
|
||||||
ddl-auto: create
|
ddl-auto: create
|
||||||
|
|
||||||
|
jasypt:
|
||||||
|
encryptor:
|
||||||
|
bean: jasyptStringEncryptor
|
||||||
|
|||||||
Reference in New Issue
Block a user