diff --git a/build.gradle b/build.gradle index 471b957..5a0e93b 100644 --- a/build.gradle +++ b/build.gradle @@ -45,7 +45,6 @@ dependencies { implementation 'io.jsonwebtoken:jjwt-api:0.12.3' implementation 'io.jsonwebtoken:jjwt-impl:0.12.3' implementation 'io.jsonwebtoken:jjwt-jackson:0.12.3' - } tasks.named('test') { diff --git a/src/main/java/EatPic/spring/domain/user/controller/UserController.java b/src/main/java/EatPic/spring/domain/user/controller/UserController.java index 397892b..f8e2d2d 100644 --- a/src/main/java/EatPic/spring/domain/user/controller/UserController.java +++ b/src/main/java/EatPic/spring/domain/user/controller/UserController.java @@ -8,12 +8,8 @@ import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.MethodArgumentNotValidException; import org.springframework.web.bind.annotation.*; -import java.util.HashMap; -import java.util.Map; - @RestController @RequestMapping("/api/auth") @RequiredArgsConstructor @@ -39,20 +35,4 @@ public ResponseEntity signup(@Valid @RequestBody SignupReques return ResponseEntity.ok(response); } - - // 필수 동의 약관 확인 - @RestControllerAdvice - public static class GlobalExceptionHandler { - - @ExceptionHandler(MethodArgumentNotValidException.class) - public ResponseEntity handleValidationErrors(MethodArgumentNotValidException ex) { - Map errors = new HashMap<>(); - ex.getBindingResult().getFieldErrors().forEach(error -> { - errors.put(error.getField(), error.getDefaultMessage()); - }); - - return ResponseEntity.badRequest().body(errors); - } - } - } diff --git a/src/main/java/EatPic/spring/domain/user/converter/UserConverter.java b/src/main/java/EatPic/spring/domain/user/converter/UserConverter.java index 29f4441..ced9873 100644 --- a/src/main/java/EatPic/spring/domain/user/converter/UserConverter.java +++ b/src/main/java/EatPic/spring/domain/user/converter/UserConverter.java @@ -4,6 +4,7 @@ import EatPic.spring.domain.card.entity.Card; import EatPic.spring.domain.reaction.dto.ReactionResponseDTO; import EatPic.spring.domain.reaction.entity.ReactionType; +import EatPic.spring.domain.user.dto.request.SignupRequestDTO; import EatPic.spring.domain.user.dto.response.UserResponseDTO; import EatPic.spring.domain.user.entity.User; import EatPic.spring.domain.user.mapping.UserBlock; @@ -70,4 +71,12 @@ public static UserResponseDTO.UserBlockResponseDto toUserBlockResponseDto(UserBl .targetUserId(userBlock.getBlockedUser().getId()) .build(); } + +// public static User toUser(SignupRequestDTO request) { +// return User.builder() +// .email(request.getEmail()) +// .password(request.getPassword()) +// .role(request.getRole()) +// .build(); +// } } diff --git a/src/main/java/EatPic/spring/domain/user/dto/request/SignupRequestDTO.java b/src/main/java/EatPic/spring/domain/user/dto/request/SignupRequestDTO.java index d4e7278..c90fe8e 100644 --- a/src/main/java/EatPic/spring/domain/user/dto/request/SignupRequestDTO.java +++ b/src/main/java/EatPic/spring/domain/user/dto/request/SignupRequestDTO.java @@ -1,6 +1,7 @@ package EatPic.spring.domain.user.dto.request; +import EatPic.spring.domain.user.entity.Role; import jakarta.validation.constraints.*; import lombok.Getter; import lombok.Setter; @@ -8,6 +9,8 @@ @Getter @Setter public class SignupRequestDTO { + @NotNull + Role role; @NotBlank @Email @@ -43,5 +46,7 @@ public boolean isPasswordMatching() { @AssertTrue(message = "개인정보 처리방침에 동의해야 합니다.") private Boolean privacyPolicyAgreed; // (필수) 개인정보 처리방침 - private Boolean marketingAgreed; // (선택) 마케팅 수신 동의 + private Boolean marketingAgreed; // (선택) 마케팅 수신 동의 + + private Boolean notificationAgreed; // (선택) 알림 수신 동의 } diff --git a/src/main/java/EatPic/spring/domain/user/dto/response/SignupResponseDTO.java b/src/main/java/EatPic/spring/domain/user/dto/response/SignupResponseDTO.java index ac7b329..27f7f54 100644 --- a/src/main/java/EatPic/spring/domain/user/dto/response/SignupResponseDTO.java +++ b/src/main/java/EatPic/spring/domain/user/dto/response/SignupResponseDTO.java @@ -1,5 +1,6 @@ package EatPic.spring.domain.user.dto.response; +import EatPic.spring.domain.user.entity.Role; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Getter; @@ -8,10 +9,12 @@ @AllArgsConstructor @Builder public class SignupResponseDTO { - private Long userId; // DB에 저장된 유저 ID - private String email; // 회원가입 시 입력한 이메일 - private String nameId; // 사용자 ID - private String nickname; // 닉네임 - private Boolean marketingAgreed; // 마케팅 수신 동의 여부 - private String message; // 예: "회원가입이 완료되었습니다." + private Role role; // 역할 + private Long userId; // DB에 저장된 유저 ID + private String email; // 회원가입 시 입력한 이메일 + private String nameId; // 사용자 ID + private String nickname; // 닉네임 + private Boolean marketingAgreed; // 마케팅 수신 동의 여부 + private Boolean notificationAgreed; // 알림 수신 동의 여부 + private String message; // 예: "회원가입이 완료되었습니다." } diff --git a/src/main/java/EatPic/spring/domain/user/entity/Role.java b/src/main/java/EatPic/spring/domain/user/entity/Role.java new file mode 100644 index 0000000..f224b5d --- /dev/null +++ b/src/main/java/EatPic/spring/domain/user/entity/Role.java @@ -0,0 +1,5 @@ +package EatPic.spring.domain.user.entity; + +public enum Role { + USER, ADMIN +} diff --git a/src/main/java/EatPic/spring/domain/user/entity/User.java b/src/main/java/EatPic/spring/domain/user/entity/User.java index ee652b6..73f1446 100644 --- a/src/main/java/EatPic/spring/domain/user/entity/User.java +++ b/src/main/java/EatPic/spring/domain/user/entity/User.java @@ -30,6 +30,9 @@ public class User extends BaseEntity { @Column(name = "password", length = 255, nullable = false) private String password; + @Enumerated(EnumType.STRING) + private Role role = Role.USER; + // 유저 아이디 @Column(name = "name_id", length = 100, nullable = false) @Size(min = 5, message = "5자 이상") @@ -69,6 +72,9 @@ public class User extends BaseEntity { @Column(name = "marketing_agreed", nullable = false) private Boolean marketingAgreed; + @Column(name = "notification_agreed", nullable = false) + private Boolean notificationAgreed; + @Column(name = "last_notification_check_at", nullable = true) private LocalDateTime lastNotificationCheckAt; diff --git a/src/main/java/EatPic/spring/global/common/exception/ExceptionAdvice.java b/src/main/java/EatPic/spring/global/common/exception/ExceptionAdvice.java index 0a9ef7b..2813175 100644 --- a/src/main/java/EatPic/spring/global/common/exception/ExceptionAdvice.java +++ b/src/main/java/EatPic/spring/global/common/exception/ExceptionAdvice.java @@ -26,7 +26,6 @@ @RestControllerAdvice(annotations = {RestController.class}) public class ExceptionAdvice extends ResponseEntityExceptionHandler { - @ExceptionHandler public ResponseEntity validation(ConstraintViolationException e, WebRequest request) { String errorMessage = e.getConstraintViolations().stream() @@ -118,3 +117,6 @@ private ResponseEntity handleExceptionInternalConstraint(Exception e, Er ); } } + + + diff --git a/src/main/java/EatPic/spring/global/common/exception/GeneralException.java b/src/main/java/EatPic/spring/global/common/exception/GeneralException.java index 7a17022..132378b 100644 --- a/src/main/java/EatPic/spring/global/common/exception/GeneralException.java +++ b/src/main/java/EatPic/spring/global/common/exception/GeneralException.java @@ -4,6 +4,13 @@ import EatPic.spring.global.common.code.ErrorReasonDTO; import lombok.AllArgsConstructor; import lombok.Getter; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.MethodArgumentNotValidException; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.RestControllerAdvice; + +import java.util.HashMap; +import java.util.Map; @Getter @AllArgsConstructor diff --git a/src/main/java/EatPic/spring/global/config/SecurityConfig.java b/src/main/java/EatPic/spring/global/config/SecurityConfig.java index 2048a75..43f8ae9 100644 --- a/src/main/java/EatPic/spring/global/config/SecurityConfig.java +++ b/src/main/java/EatPic/spring/global/config/SecurityConfig.java @@ -6,6 +6,7 @@ import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.config.Customizer; import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration; +import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity; 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.configurers.AbstractHttpConfigurer; @@ -17,6 +18,7 @@ @Configuration @EnableWebSecurity @RequiredArgsConstructor +@EnableMethodSecurity(prePostEnabled = true) public class SecurityConfig { //private final CorsConfig corsConfig; @@ -41,6 +43,8 @@ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { .requestMatchers("/swagger-ui/**", "/v3/api-docs/**").permitAll() // 인증 없이 허용할 경로 .requestMatchers("/api/**").permitAll() + // ADMIN 권한 + .requestMatchers("/admin/**").hasRole("ADMIN") // 그 외 모든 요청은 모두 인증 필요 .anyRequest().authenticated()); //.addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);