Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,5 @@ out/
.codegraph
work/
outputs/

/.env
2 changes: 0 additions & 2 deletions GithubTest/Example.md

This file was deleted.

2 changes: 0 additions & 2 deletions GithubTest/ryuyejun.md

This file was deleted.

2 changes: 0 additions & 2 deletions GithubTest/songeunyong.md

This file was deleted.

8 changes: 8 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,17 @@ repositories {

dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.security:spring-security-crypto'
implementation 'org.springframework.boot:spring-boot-starter-validation'
compileOnly 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok'

testImplementation 'org.springframework.boot:spring-boot-starter-test'
testCompileOnly 'org.projectlombok:lombok'
testAnnotationProcessor 'org.projectlombok:lombok'
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
runtimeOnly 'com.mysql:mysql-connector-j'
}

tasks.named('test') {
Expand Down
1 change: 0 additions & 1 deletion src/main/java/com/select/domain/package-info.java

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package com.select.domain.user.controller;

import com.select.domain.user.dto.request.SignupRequest;
import com.select.domain.user.dto.response.SignupResponse;
import com.select.domain.user.service.UserService;
import com.select.global.response.ApiResponse;
import jakarta.validation.Valid;
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
@RequestMapping("/babi/api/v1/auth")
public class UserController {

private final UserService userService;

public UserController(UserService userService) {
this.userService = userService;
}

@PostMapping("/signup")
public ApiResponse<SignupResponse> signup(@Valid @RequestBody SignupRequest request) {
SignupResponse response = userService.signup(request);
return new ApiResponse<>(true, "회원가입이 완료되었습니다.", response);
}
}

This file was deleted.

1 change: 0 additions & 1 deletion src/main/java/com/select/domain/user/dto/package-info.java

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package com.select.domain.user.dto.request;

import jakarta.validation.constraints.*;

public record SignupRequest(

@Email
@Size(max = 320)
@NotBlank
String email,

@NotBlank
@Size(min = 8,max = 20, message = "비밀번호는 최소 8자 이상 20자 이하여야 합니다.")
@Pattern(
regexp = "^[!-~]+$",
message = "비밀번호는 영문, 숫자, 특수문자만 입력할 수 있습니다."
)
String password,

@NotBlank
String passwordConfirm,

@NotBlank
@Size(max = 50)
String nickname

) {
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.select.domain.user.dto.response;

public record SignupResponse(
Long userId,
String email,
String nickname
) {
}

This file was deleted.

60 changes: 60 additions & 0 deletions src/main/java/com/select/domain/user/entity/User.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package com.select.domain.user.entity;

import jakarta.persistence.*;
import lombok.Builder;
import lombok.Getter;

import java.time.LocalDateTime;

@Entity
@Getter
@Table(
name = "users",
uniqueConstraints = @UniqueConstraint(
name = "email",
columnNames = "email"
)
)
public class User {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

@Column(nullable = false, length = 320)
private String email;

@Column(name = "password_hash", nullable = false, length = 255)
private String passwordHash;

@Column(nullable = false, length = 50)
private String nickname;

@Column(name = "created_at", nullable = false)
private LocalDateTime createdAt;

@Column(name = "updated_at", nullable = false)
private LocalDateTime updatedAt;

protected User() {
}

@PrePersist
public void onCreated() {
LocalDateTime now = LocalDateTime.now();
this.createdAt = now;
this.updatedAt = now;
}

@PreUpdate
public void onUpdated() {
this.updatedAt = LocalDateTime.now();
}

@Builder
public User(String email, String passwordHash, String nickname) {
this.email = email;
this.passwordHash = passwordHash;
this.nickname = nickname;
}
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.select.domain.user.exception;

public class DuplicateEmailException extends RuntimeException {

public DuplicateEmailException() {
super("이미 가입된 이메일입니다.");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.select.domain.user.exception;

public class PasswordMismatchException extends RuntimeException {

public PasswordMismatchException() {
super("비밀번호가 일치하지 않습니다.");
}
}
1 change: 0 additions & 1 deletion src/main/java/com/select/domain/user/package-info.java

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.select.domain.user.repository;

import com.select.domain.user.entity.User;
import org.springframework.data.jpa.repository.JpaRepository;

public interface UserRepository extends JpaRepository<User, Long> {

boolean existsByEmail(String email);

}

This file was deleted.

71 changes: 71 additions & 0 deletions src/main/java/com/select/domain/user/service/UserService.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
package com.select.domain.user.service;

import com.select.domain.user.dto.request.SignupRequest;
import com.select.domain.user.dto.response.SignupResponse;
import com.select.domain.user.entity.User;
import com.select.domain.user.exception.DuplicateEmailException;
import com.select.domain.user.exception.PasswordMismatchException;
import com.select.domain.user.repository.UserRepository;
import org.hibernate.exception.ConstraintViolationException;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
public class UserService {

private final UserRepository userRepository;
private final PasswordEncoder passwordEncoder;

public UserService(UserRepository userRepository, PasswordEncoder passwordEncoder) {
this.userRepository = userRepository;
this.passwordEncoder = passwordEncoder;
}

@Transactional
public SignupResponse signup(SignupRequest request) {
validateSignup(request);
User user = User
.builder()
.email(request.email())
.nickname(request.nickname())
.passwordHash(passwordEncoder.encode(request.password()))
.build();
try {
User savedUser = userRepository.saveAndFlush(user);
return new SignupResponse(savedUser.getId(),
savedUser.getEmail(),
savedUser.getNickname());
} catch (DataIntegrityViolationException e) {
if (isDuplicateEmailViolation(e)) {
throw new DuplicateEmailException();
}
throw e;
}
}
private void validateSignup(SignupRequest request) {
if (userRepository.existsByEmail(request.email())) {
throw new DuplicateEmailException();
}

if (!request.password().equals(request.passwordConfirm())) {
throw new PasswordMismatchException();
}
}

private boolean isDuplicateEmailViolation(DataIntegrityViolationException e) {
Throwable cause = e;
while (cause != null) {
if (cause instanceof ConstraintViolationException violation) {
String name = violation.getConstraintName();
if ("email".equals(name)
|| "users.email".equals(name)) {
return true;
}
}
cause = cause.getCause();
}
return false;
}
}

This file was deleted.

1 change: 0 additions & 1 deletion src/main/java/com/select/global/config/package-info.java

This file was deleted.

24 changes: 24 additions & 0 deletions src/main/java/com/select/global/exception/ErrorCode.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package com.select.global.exception;

import lombok.Getter;
import org.springframework.http.HttpStatus;

@Getter
public enum ErrorCode {

DUPLICATE_EMAIL(HttpStatus.CONFLICT, "이미 가입된 이메일입니다."),
PASSWORD_MISMATCH(HttpStatus.BAD_REQUEST, "비밀번호가 일치하지 않습니다."),
VALIDATION_ERROR(HttpStatus.BAD_REQUEST, "입력값을 확인해 주세요."),
INTERNAL_SERVER_ERROR(HttpStatus.INTERNAL_SERVER_ERROR, "서버에 오류가 발생했습니다."),
INVALID_REQUEST_BODY(HttpStatus.BAD_REQUEST, "요청 본문이 올바르지 않습니다."),
METHOD_NOT_ALLOWED(HttpStatus.METHOD_NOT_ALLOWED, "지원하지 않는 HTTP 메서드 입니다.");

private final HttpStatus httpStatus;
private final String message;

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

}
Loading
Loading