diff --git a/build.gradle b/build.gradle index c6cb590..d42173a 100644 --- a/build.gradle +++ b/build.gradle @@ -29,13 +29,19 @@ dependencies { implementation 'org.springframework.boot:spring-boot-starter-web' implementation 'org.springframework.security:spring-security-crypto:6.5.3' implementation 'org.mapstruct:mapstruct:1.5.5.Final' + implementation 'commons-validator:commons-validator:1.7' + annotationProcessor 'org.mapstruct:mapstruct-processor:1.5.5.Final' + annotationProcessor 'org.projectlombok:lombok' + compileOnly 'org.projectlombok:lombok' + developmentOnly 'org.springframework.boot:spring-boot-devtools' + runtimeOnly 'com.microsoft.sqlserver:mssql-jdbc' runtimeOnly 'com.mysql:mysql-connector-j' runtimeOnly 'org.postgresql:postgresql' - annotationProcessor 'org.projectlombok:lombok' + testImplementation 'org.springframework.boot:spring-boot-starter-test' testImplementation 'org.mockito:mockito-core:5.3.1' testRuntimeOnly 'org.junit.platform:junit-platform-launcher' diff --git a/src/main/java/ru/soune/no_copy/controller/AuthController.java b/src/main/java/ru/soune/no_copy/controller/AuthController.java deleted file mode 100644 index 764b1a8..0000000 --- a/src/main/java/ru/soune/no_copy/controller/AuthController.java +++ /dev/null @@ -1,58 +0,0 @@ -package ru.soune.no_copy.controller; - -import jakarta.validation.Valid; -import lombok.RequiredArgsConstructor; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.*; -import ru.soune.no_copy.dto.AuthResponse; -import ru.soune.no_copy.dto.LoginRequest; -import ru.soune.no_copy.dto.LoginResponse; -import ru.soune.no_copy.dto.RegisterRequest; -import ru.soune.no_copy.entity.AuthToken; -import ru.soune.no_copy.exception.TokenNotFoundException; -import ru.soune.no_copy.repository.AuthTokenRepository; -import ru.soune.no_copy.service.AuthService; - -import java.util.Map; -import java.util.Optional; - -@RestController -@RequestMapping("v1/api/auth") -@RequiredArgsConstructor -public class AuthController { - - private final AuthService authService; - - private final AuthTokenRepository authTokenRepository; - - @PostMapping("/register") - public ResponseEntity register(@Valid @RequestBody RegisterRequest registerRequest) { - AuthToken authToken = authService.register(registerRequest); - - return ResponseEntity.ok(new AuthResponse(true, "success.user.register", authToken.getToken(), - authToken.getExpiresAt())); - } - - @PostMapping("/login") - public ResponseEntity login(@Valid @RequestBody LoginRequest request) { - AuthToken login = authService.login(request); - - return ResponseEntity.ok(new LoginResponse(true, login.getUser().getEmail(), - login.getToken(),login.getExpiresAt().toString())); - } - - @PostMapping("/logout") - public ResponseEntity logout(@RequestHeader("Authorization") String tokenHeader) { - String token = tokenHeader.replace("Bearer ", ""); - - Optional opToken = authTokenRepository.findByToken(token); - - if (opToken.isEmpty()) { - throw new TokenNotFoundException("Token not found"); - } - - authService.logout(token); - - return ResponseEntity.ok(Map.of("success", true)); - } -} diff --git a/src/main/java/ru/soune/no_copy/dto/AuthResponse.java b/src/main/java/ru/soune/no_copy/dto/AuthResponse.java deleted file mode 100644 index c39301a..0000000 --- a/src/main/java/ru/soune/no_copy/dto/AuthResponse.java +++ /dev/null @@ -1,10 +0,0 @@ -package ru.soune.no_copy.dto; - -import java.time.LocalDateTime; - -public record AuthResponse ( - boolean success, - String message, - String token, - LocalDateTime expiresAt -) {} diff --git a/src/main/java/ru/soune/no_copy/dto/LoginResponse.java b/src/main/java/ru/soune/no_copy/dto/LoginResponse.java deleted file mode 100644 index 5fe7d73..0000000 --- a/src/main/java/ru/soune/no_copy/dto/LoginResponse.java +++ /dev/null @@ -1,14 +0,0 @@ -package ru.soune.no_copy.dto; - -import lombok.AllArgsConstructor; -import lombok.Data; -import ru.soune.no_copy.entity.User; - -@Data -@AllArgsConstructor -public class LoginResponse { - private boolean success; - private String email; - private String token; - private String expiresAt; -} diff --git a/src/main/java/ru/soune/no_copy/dto/RegisterRequest.java b/src/main/java/ru/soune/no_copy/dto/RegisterRequest.java deleted file mode 100644 index e08f39b..0000000 --- a/src/main/java/ru/soune/no_copy/dto/RegisterRequest.java +++ /dev/null @@ -1,40 +0,0 @@ -package ru.soune.no_copy.dto; - -import com.fasterxml.jackson.annotation.JsonFormat; -import jakarta.validation.constraints.Email; -import jakarta.validation.constraints.NotBlank; -import jakarta.validation.constraints.Past; -import jakarta.validation.constraints.Size; -import org.springframework.format.annotation.DateTimeFormat; -import ru.soune.no_copy.entity.GenderType; -import ru.soune.no_copy.entity.SubscriptionType; - -import java.time.LocalDate; - -public record RegisterRequest( - @NotBlank(message = "error.name.length") - String fullName, - - String companyName, - - @Size(min = 11, max = 14) - String phone, - - @NotBlank(message = "error.not.blank") - @Email(message = "error.not.email") - @Size(max = 128) - String email, - - @DateTimeFormat(pattern = "dd-MM-yyyy") - @JsonFormat(pattern = "dd-MM-yyyy") - @Past - LocalDate birthday, - - @NotBlank(message = "error.not.blank") - @Size(min = 8) - String password, - - SubscriptionType subscriptionType, - - GenderType genderType -) {} diff --git a/src/main/java/ru/soune/no_copy/exception/UserAlreadyExistsException.java b/src/main/java/ru/soune/no_copy/exception/UserAlreadyExistsException.java deleted file mode 100644 index 8815885..0000000 --- a/src/main/java/ru/soune/no_copy/exception/UserAlreadyExistsException.java +++ /dev/null @@ -1,7 +0,0 @@ -package ru.soune.no_copy.exception; - -public class UserAlreadyExistsException extends RuntimeException { - public UserAlreadyExistsException(String message) { - super(message); - } -} diff --git a/src/main/java/ru/soune/no_copy/handler/JwtTokenProvider.java b/src/main/java/ru/soune/no_copy/handler/JwtTokenProvider.java deleted file mode 100644 index 721869c..0000000 --- a/src/main/java/ru/soune/no_copy/handler/JwtTokenProvider.java +++ /dev/null @@ -1,7 +0,0 @@ -package ru.soune.no_copy.handler; - -import org.springframework.stereotype.Component; - -@Component -public class JwtTokenProvider { -} diff --git a/src/main/java/ru/soune/no_copy/NoCopyApplication.java b/src/main/java/ru/soune/nocopy/NoCopyApplication.java similarity index 91% rename from src/main/java/ru/soune/no_copy/NoCopyApplication.java rename to src/main/java/ru/soune/nocopy/NoCopyApplication.java index 74bec20..fd6b0f2 100644 --- a/src/main/java/ru/soune/no_copy/NoCopyApplication.java +++ b/src/main/java/ru/soune/nocopy/NoCopyApplication.java @@ -1,4 +1,4 @@ -package ru.soune.no_copy; +package ru.soune.nocopy; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; diff --git a/src/main/java/ru/soune/no_copy/configuration/ApplicationConfig.java b/src/main/java/ru/soune/nocopy/configuration/ApplicationConfig.java similarity index 92% rename from src/main/java/ru/soune/no_copy/configuration/ApplicationConfig.java rename to src/main/java/ru/soune/nocopy/configuration/ApplicationConfig.java index 8b0409b..85ae0b8 100644 --- a/src/main/java/ru/soune/no_copy/configuration/ApplicationConfig.java +++ b/src/main/java/ru/soune/nocopy/configuration/ApplicationConfig.java @@ -1,4 +1,4 @@ -package ru.soune.no_copy.configuration; +package ru.soune.nocopy.configuration; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.context.annotation.Bean; diff --git a/src/main/java/ru/soune/no_copy/configuration/JacksonConfig.java b/src/main/java/ru/soune/nocopy/configuration/JacksonConfig.java similarity index 97% rename from src/main/java/ru/soune/no_copy/configuration/JacksonConfig.java rename to src/main/java/ru/soune/nocopy/configuration/JacksonConfig.java index 0f726fb..99c5c00 100644 --- a/src/main/java/ru/soune/no_copy/configuration/JacksonConfig.java +++ b/src/main/java/ru/soune/nocopy/configuration/JacksonConfig.java @@ -1,4 +1,4 @@ -package ru.soune.no_copy.configuration; +package ru.soune.nocopy.configuration; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.SerializationFeature; diff --git a/src/main/java/ru/soune/no_copy/configuration/JpaConfiguration.java b/src/main/java/ru/soune/nocopy/configuration/JpaConfiguration.java similarity index 83% rename from src/main/java/ru/soune/no_copy/configuration/JpaConfiguration.java rename to src/main/java/ru/soune/nocopy/configuration/JpaConfiguration.java index 56ae18b..f62ccde 100644 --- a/src/main/java/ru/soune/no_copy/configuration/JpaConfiguration.java +++ b/src/main/java/ru/soune/nocopy/configuration/JpaConfiguration.java @@ -1,4 +1,4 @@ -package ru.soune.no_copy.configuration; +package ru.soune.nocopy.configuration; import org.springframework.context.annotation.Configuration; import org.springframework.data.jpa.repository.config.EnableJpaAuditing; diff --git a/src/main/java/ru/soune/no_copy/configuration/SubscriptionConfig.java b/src/main/java/ru/soune/nocopy/configuration/SubscriptionConfig.java similarity index 96% rename from src/main/java/ru/soune/no_copy/configuration/SubscriptionConfig.java rename to src/main/java/ru/soune/nocopy/configuration/SubscriptionConfig.java index 7eb41ec..198a544 100644 --- a/src/main/java/ru/soune/no_copy/configuration/SubscriptionConfig.java +++ b/src/main/java/ru/soune/nocopy/configuration/SubscriptionConfig.java @@ -1,4 +1,4 @@ -package ru.soune.no_copy.configuration; +package ru.soune.nocopy.configuration; import lombok.Getter; import org.springframework.boot.context.properties.ConfigurationProperties; diff --git a/src/main/java/ru/soune/nocopy/controller/ApiController.java b/src/main/java/ru/soune/nocopy/controller/ApiController.java new file mode 100644 index 0000000..460ad8b --- /dev/null +++ b/src/main/java/ru/soune/nocopy/controller/ApiController.java @@ -0,0 +1,105 @@ +package ru.soune.nocopy.controller; + +import jakarta.annotation.PostConstruct; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.context.ApplicationContext; +import org.springframework.http.ResponseEntity; +import org.springframework.validation.BindingResult; +import org.springframework.validation.FieldError; +import org.springframework.web.bind.annotation.*; +import ru.soune.nocopy.dto.BaseRequest; +import ru.soune.nocopy.dto.BaseResponse; +import ru.soune.nocopy.dto.MessageCode; +import ru.soune.nocopy.dto.RegAnswer; +import ru.soune.nocopy.exception.NotValidFieldException; +import ru.soune.nocopy.exception.ValidationException; +import ru.soune.nocopy.handler.LoginRequestHandler; +import ru.soune.nocopy.handler.RegRequestHandler; +import ru.soune.nocopy.handler.RequestHandler; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +@Slf4j +@RestController +@RequestMapping("/api") +@RequiredArgsConstructor +public class ApiController { + private final ApplicationContext applicationContext; + + private Map handlers = new HashMap<>(); + + @PostConstruct + public void init() { + RegRequestHandler regHandler = applicationContext.getBean(RegRequestHandler.class); + LoginRequestHandler loginHandler = applicationContext.getBean(LoginRequestHandler.class); + + handlers.put(20002, regHandler); + handlers.put(20001, loginHandler); + } + + @PostMapping("/v{version}/data") + public ResponseEntity handlePostRequest(@RequestBody BaseRequest request, + @PathVariable("version") int version) { + Integer msgId = request.getMsgId(); + BaseResponse response; + + try { + RequestHandler handler = handlers.get(msgId); + + if (handler == null) { + response = new BaseResponse(msgId, + MessageCode.MSG_ID_NOT_FOUND.getCode(), + MessageCode.MSG_ID_NOT_FOUND.getDescription(), + new HashMap<>()); + } else { + response = handler.handle(request); + } + + return ResponseEntity.ok().body(response); + } catch (ValidationException e) { + return createValidationErrorResponse(e.getBindingResult(), e.getMsgId()); + } catch (NotValidFieldException e) { + throw e; + } catch (Exception e) { + log.error("Handler execution failed for msgId: {}", msgId, e); + + BaseResponse errorResponse = new BaseResponse(msgId, + MessageCode.INVALID_JSON_BODY.getCode(), + MessageCode.INVALID_JSON_BODY.getDescription(), + new HashMap<>()); + + return ResponseEntity.ok().body(errorResponse); + } + } + + private ResponseEntity createValidationErrorResponse(BindingResult bindingResult, Integer msgId) { + List> fieldErrors = bindingResult.getFieldErrors() + .stream() + .map(this::createErrorDetail) + .collect(Collectors.toList()); + + RegAnswer regAnswer = new RegAnswer(); + regAnswer.setFieldErrors(fieldErrors); + + return ResponseEntity.ok().body(new BaseResponse(msgId, MessageCode.INVALID_FIELD.getCode(), + MessageCode.INVALID_FIELD.getDescription(), regAnswer)); + } + + private Map createErrorDetail(FieldError fieldError) { + Map errorDetail = new HashMap<>(); + errorDetail.put("field", fieldError.getField()); + errorDetail.put("code", fieldError.getCode() != null ? fieldError.getCode() : "VALIDATION_ERROR"); + errorDetail.put("message", fieldError.getDefaultMessage()); + + if (fieldError.getRejectedValue() != null && + !fieldError.getField().toLowerCase().contains("password")) { + errorDetail.put("rejected_value", fieldError.getRejectedValue().toString()); + } + + return errorDetail; + } +} \ No newline at end of file diff --git a/src/main/java/ru/soune/nocopy/controller/AuthController.java b/src/main/java/ru/soune/nocopy/controller/AuthController.java new file mode 100644 index 0000000..d9ba3d3 --- /dev/null +++ b/src/main/java/ru/soune/nocopy/controller/AuthController.java @@ -0,0 +1,37 @@ +package ru.soune.nocopy.controller; + +import lombok.RequiredArgsConstructor; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; +import ru.soune.nocopy.entity.AuthToken; +import ru.soune.nocopy.exception.TokenNotFoundException; +import ru.soune.nocopy.repository.AuthTokenRepository; +import ru.soune.nocopy.service.AuthService; + +import java.util.Map; +import java.util.Optional; + +@RestController +@RequestMapping("v1/api/auth") +@RequiredArgsConstructor +public class AuthController { + + private final AuthService authService; + + private final AuthTokenRepository authTokenRepository; + + @PostMapping("/logout") + public ResponseEntity logout(@RequestHeader("Authorization") String tokenHeader) { + String token = tokenHeader.replace("Bearer ", ""); + + Optional opToken = authTokenRepository.findByToken(token); + + if (opToken.isEmpty()) { + throw new TokenNotFoundException("Token not found"); + } + + authService.logout(token); + + return ResponseEntity.ok(Map.of("success", true)); + } +} diff --git a/src/main/java/ru/soune/no_copy/controller/HealtCheckController.java b/src/main/java/ru/soune/nocopy/controller/HealtCheckController.java similarity index 72% rename from src/main/java/ru/soune/no_copy/controller/HealtCheckController.java rename to src/main/java/ru/soune/nocopy/controller/HealtCheckController.java index 33b6ab9..57de3e8 100644 --- a/src/main/java/ru/soune/no_copy/controller/HealtCheckController.java +++ b/src/main/java/ru/soune/nocopy/controller/HealtCheckController.java @@ -1,11 +1,10 @@ -package ru.soune.no_copy.controller; +package ru.soune.nocopy.controller; -import org.apache.coyote.Response; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.*; @RestController -@RequestMapping("/api") +@RequestMapping("check/api") public class HealtCheckController { @GetMapping("/healt") diff --git a/src/main/java/ru/soune/no_copy/controller/UserContentController.java b/src/main/java/ru/soune/nocopy/controller/UserContentController.java similarity index 87% rename from src/main/java/ru/soune/no_copy/controller/UserContentController.java rename to src/main/java/ru/soune/nocopy/controller/UserContentController.java index ea25e8f..51a4d5c 100644 --- a/src/main/java/ru/soune/no_copy/controller/UserContentController.java +++ b/src/main/java/ru/soune/nocopy/controller/UserContentController.java @@ -1,4 +1,4 @@ -package ru.soune.no_copy.controller; +package ru.soune.nocopy.controller; import lombok.AllArgsConstructor; import org.springframework.web.bind.annotation.RequestMapping; diff --git a/src/main/java/ru/soune/no_copy/controller/UserController.java b/src/main/java/ru/soune/nocopy/controller/UserController.java similarity index 87% rename from src/main/java/ru/soune/no_copy/controller/UserController.java rename to src/main/java/ru/soune/nocopy/controller/UserController.java index 9f23605..39efe8e 100644 --- a/src/main/java/ru/soune/no_copy/controller/UserController.java +++ b/src/main/java/ru/soune/nocopy/controller/UserController.java @@ -1,19 +1,19 @@ -package ru.soune.no_copy.controller; +package ru.soune.nocopy.controller; import lombok.RequiredArgsConstructor; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; -import ru.soune.no_copy.dto.ChangePasswordRequest; -import ru.soune.no_copy.dto.UserDTO; -import ru.soune.no_copy.dto.UserRequest; -import ru.soune.no_copy.entity.AuthToken; -import ru.soune.no_copy.entity.User; -import ru.soune.no_copy.exception.InvalidUserEmail; -import ru.soune.no_copy.exception.NotFoundAuthToken; -import ru.soune.no_copy.mapper.UserMapper; -import ru.soune.no_copy.repository.AuthTokenRepository; -import ru.soune.no_copy.repository.UserRepository; -import ru.soune.no_copy.service.UserService; +import ru.soune.nocopy.dto.ChangePasswordRequest; +import ru.soune.nocopy.dto.UserDTO; +import ru.soune.nocopy.dto.UserRequest; +import ru.soune.nocopy.entity.AuthToken; +import ru.soune.nocopy.entity.User; +import ru.soune.nocopy.exception.InvalidUserEmail; +import ru.soune.nocopy.exception.NotFoundAuthToken; +import ru.soune.nocopy.mapper.UserMapper; +import ru.soune.nocopy.repository.AuthTokenRepository; +import ru.soune.nocopy.repository.UserRepository; +import ru.soune.nocopy.service.UserService; import java.util.List; import java.util.Optional; diff --git a/src/main/java/ru/soune/nocopy/dto/BaseRequest.java b/src/main/java/ru/soune/nocopy/dto/BaseRequest.java new file mode 100644 index 0000000..b02ad8c --- /dev/null +++ b/src/main/java/ru/soune/nocopy/dto/BaseRequest.java @@ -0,0 +1,16 @@ +package ru.soune.nocopy.dto; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; + +@Data +public class BaseRequest { + @JsonProperty("version") + Integer version; + + @JsonProperty("msg_id") + Integer msgId; + + @JsonProperty("message_body") + Object messageBody; +} diff --git a/src/main/java/ru/soune/nocopy/dto/BaseResponse.java b/src/main/java/ru/soune/nocopy/dto/BaseResponse.java new file mode 100644 index 0000000..b60419a --- /dev/null +++ b/src/main/java/ru/soune/nocopy/dto/BaseResponse.java @@ -0,0 +1,21 @@ +package ru.soune.nocopy.dto; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Data; + +@Data +@AllArgsConstructor +public class BaseResponse { + @JsonProperty("msg_id") + private Integer msgId; + + @JsonProperty("message_code") + private Integer messageCode; + + @JsonProperty("message_desc") + private String messageDesc; + + @JsonProperty("message_body") + private Object messageBody; +} diff --git a/src/main/java/ru/soune/no_copy/dto/ChangePasswordRequest.java b/src/main/java/ru/soune/nocopy/dto/ChangePasswordRequest.java similarity index 89% rename from src/main/java/ru/soune/no_copy/dto/ChangePasswordRequest.java rename to src/main/java/ru/soune/nocopy/dto/ChangePasswordRequest.java index aff7140..204db58 100644 --- a/src/main/java/ru/soune/no_copy/dto/ChangePasswordRequest.java +++ b/src/main/java/ru/soune/nocopy/dto/ChangePasswordRequest.java @@ -1,4 +1,4 @@ -package ru.soune.no_copy.dto; +package ru.soune.nocopy.dto; import lombok.AllArgsConstructor; import lombok.Data; diff --git a/src/main/java/ru/soune/nocopy/dto/LogOutAnswer.java b/src/main/java/ru/soune/nocopy/dto/LogOutAnswer.java new file mode 100644 index 0000000..fbb7e21 --- /dev/null +++ b/src/main/java/ru/soune/nocopy/dto/LogOutAnswer.java @@ -0,0 +1,17 @@ +package ru.soune.nocopy.dto; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; +import java.util.Map; + +@Data +@AllArgsConstructor +@NoArgsConstructor +public class LogOutAnswer { + private String Token; + + private List> fieldErrors; +} diff --git a/src/main/java/ru/soune/nocopy/dto/LoginAnswer.java b/src/main/java/ru/soune/nocopy/dto/LoginAnswer.java new file mode 100644 index 0000000..e791d8d --- /dev/null +++ b/src/main/java/ru/soune/nocopy/dto/LoginAnswer.java @@ -0,0 +1,17 @@ +package ru.soune.nocopy.dto; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; +import java.util.Map; + +@Data +@AllArgsConstructor +@NoArgsConstructor +public class LoginAnswer { + private String Token; + + private List> fieldErrors; +} diff --git a/src/main/java/ru/soune/no_copy/dto/LoginRequest.java b/src/main/java/ru/soune/nocopy/dto/LoginRequest.java similarity index 94% rename from src/main/java/ru/soune/no_copy/dto/LoginRequest.java rename to src/main/java/ru/soune/nocopy/dto/LoginRequest.java index c85fe97..d64fa8b 100644 --- a/src/main/java/ru/soune/no_copy/dto/LoginRequest.java +++ b/src/main/java/ru/soune/nocopy/dto/LoginRequest.java @@ -1,4 +1,4 @@ -package ru.soune.no_copy.dto; +package ru.soune.nocopy.dto; import jakarta.validation.constraints.Email; import jakarta.validation.constraints.NotBlank; diff --git a/src/main/java/ru/soune/nocopy/dto/MessageCode.java b/src/main/java/ru/soune/nocopy/dto/MessageCode.java new file mode 100644 index 0000000..baa48be --- /dev/null +++ b/src/main/java/ru/soune/nocopy/dto/MessageCode.java @@ -0,0 +1,30 @@ +package ru.soune.nocopy.dto; + +public enum MessageCode { + SUCCESS(0, "Operation successful"), + REG_EMAIL_EXISTS(1, "Email already registered"), + REG_EMAIL_OR_PHONE_EXISTS(1, "Email or phone already registered"), + INVALID_FIELD(2, "Invalid field"), + INVALID_JSON_BODY(2, "Invalid fields in JSON object"), + MSG_ID_NOT_FOUND(4, "Message id not found"), + + AUTH_EMAIL_NOT_FOUND(4, "Email not found"), + AUTH_PASSWORD_NOT_MATCHES(2, "Password does not match"); + + private final Integer code; + + private final String description; + + MessageCode(Integer code, String description) { + this.code = code; + this.description = description; + } + + public Integer getCode() { + return code; + } + + public String getDescription() { + return description; + } +} diff --git a/src/main/java/ru/soune/nocopy/dto/RegAnswer.java b/src/main/java/ru/soune/nocopy/dto/RegAnswer.java new file mode 100644 index 0000000..b51b4cc --- /dev/null +++ b/src/main/java/ru/soune/nocopy/dto/RegAnswer.java @@ -0,0 +1,17 @@ +package ru.soune.nocopy.dto; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; +import java.util.Map; + +@Data +@AllArgsConstructor +@NoArgsConstructor +public class RegAnswer { + private String Token; + + private List> fieldErrors; +} \ No newline at end of file diff --git a/src/main/java/ru/soune/nocopy/dto/RegRequest.java b/src/main/java/ru/soune/nocopy/dto/RegRequest.java new file mode 100644 index 0000000..e08f404 --- /dev/null +++ b/src/main/java/ru/soune/nocopy/dto/RegRequest.java @@ -0,0 +1,25 @@ +package ru.soune.nocopy.dto; + +import jakarta.validation.constraints.*; +import lombok.Data; + + +@Data +public class RegRequest { + @NotEmpty(message = "Full name is required") + private String fullName; + + private String companyName; + + @Size(min = 11, max = 14, message = "Phone must be 11-14 digits") + private String phone; + + @NotBlank(message = "Email is required") + @Email(message = "Invalid email format") + @Size(max = 128, message = "Email too long") + private String email; + + @NotBlank(message = "Password is required") + @Size(min = 8, message = "Password must be at least 8 characters") + private String password; +} diff --git a/src/main/java/ru/soune/no_copy/dto/UserContentDTO.java b/src/main/java/ru/soune/nocopy/dto/UserContentDTO.java similarity index 76% rename from src/main/java/ru/soune/no_copy/dto/UserContentDTO.java rename to src/main/java/ru/soune/nocopy/dto/UserContentDTO.java index 90df1d9..934bfda 100644 --- a/src/main/java/ru/soune/no_copy/dto/UserContentDTO.java +++ b/src/main/java/ru/soune/nocopy/dto/UserContentDTO.java @@ -1,7 +1,6 @@ -package ru.soune.no_copy.dto; +package ru.soune.nocopy.dto; import lombok.Data; -import ru.soune.no_copy.entity.FileType; @Data public class UserContentDTO { diff --git a/src/main/java/ru/soune/no_copy/dto/UserContentRequest.java b/src/main/java/ru/soune/nocopy/dto/UserContentRequest.java similarity index 93% rename from src/main/java/ru/soune/no_copy/dto/UserContentRequest.java rename to src/main/java/ru/soune/nocopy/dto/UserContentRequest.java index 06ef01e..bd28100 100644 --- a/src/main/java/ru/soune/no_copy/dto/UserContentRequest.java +++ b/src/main/java/ru/soune/nocopy/dto/UserContentRequest.java @@ -1,4 +1,4 @@ -package ru.soune.no_copy.dto; +package ru.soune.nocopy.dto; import jakarta.validation.constraints.Email; import jakarta.validation.constraints.NotBlank; diff --git a/src/main/java/ru/soune/no_copy/dto/UserContentResponse.java b/src/main/java/ru/soune/nocopy/dto/UserContentResponse.java similarity index 71% rename from src/main/java/ru/soune/no_copy/dto/UserContentResponse.java rename to src/main/java/ru/soune/nocopy/dto/UserContentResponse.java index 86d1d84..9257b05 100644 --- a/src/main/java/ru/soune/no_copy/dto/UserContentResponse.java +++ b/src/main/java/ru/soune/nocopy/dto/UserContentResponse.java @@ -1,7 +1,7 @@ -package ru.soune.no_copy.dto; +package ru.soune.nocopy.dto; -import ru.soune.no_copy.entity.ContentStatus; -import ru.soune.no_copy.entity.FileType; +import ru.soune.nocopy.entity.ContentStatus; +import ru.soune.nocopy.entity.FileType; import java.time.LocalDateTime; diff --git a/src/main/java/ru/soune/no_copy/dto/UserContentUpdateRequest.java b/src/main/java/ru/soune/nocopy/dto/UserContentUpdateRequest.java similarity index 93% rename from src/main/java/ru/soune/no_copy/dto/UserContentUpdateRequest.java rename to src/main/java/ru/soune/nocopy/dto/UserContentUpdateRequest.java index 8955969..7595b21 100644 --- a/src/main/java/ru/soune/no_copy/dto/UserContentUpdateRequest.java +++ b/src/main/java/ru/soune/nocopy/dto/UserContentUpdateRequest.java @@ -1,4 +1,4 @@ -package ru.soune.no_copy.dto; +package ru.soune.nocopy.dto; import jakarta.validation.constraints.Email; import jakarta.validation.constraints.NotBlank; diff --git a/src/main/java/ru/soune/no_copy/dto/UserDTO.java b/src/main/java/ru/soune/nocopy/dto/UserDTO.java similarity index 81% rename from src/main/java/ru/soune/no_copy/dto/UserDTO.java rename to src/main/java/ru/soune/nocopy/dto/UserDTO.java index ba5b278..45c19ee 100644 --- a/src/main/java/ru/soune/no_copy/dto/UserDTO.java +++ b/src/main/java/ru/soune/nocopy/dto/UserDTO.java @@ -1,11 +1,11 @@ -package ru.soune.no_copy.dto; +package ru.soune.nocopy.dto; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; -import ru.soune.no_copy.entity.GenderType; -import ru.soune.no_copy.entity.SubscriptionType; +import ru.soune.nocopy.entity.GenderType; +import ru.soune.nocopy.entity.SubscriptionType; import java.time.LocalDate; import java.time.LocalDateTime; diff --git a/src/main/java/ru/soune/no_copy/dto/UserRequest.java b/src/main/java/ru/soune/nocopy/dto/UserRequest.java similarity index 83% rename from src/main/java/ru/soune/no_copy/dto/UserRequest.java rename to src/main/java/ru/soune/nocopy/dto/UserRequest.java index db8c8fe..c5f1662 100644 --- a/src/main/java/ru/soune/no_copy/dto/UserRequest.java +++ b/src/main/java/ru/soune/nocopy/dto/UserRequest.java @@ -1,14 +1,13 @@ -package ru.soune.no_copy.dto; +package ru.soune.nocopy.dto; import com.fasterxml.jackson.annotation.JsonFormat; import jakarta.validation.constraints.Email; import jakarta.validation.constraints.Past; import jakarta.validation.constraints.Size; import lombok.Data; -import ru.soune.no_copy.entity.GenderType; +import ru.soune.nocopy.entity.GenderType; import java.time.LocalDate; -import java.time.LocalDateTime; @Data public class UserRequest { diff --git a/src/main/java/ru/soune/no_copy/entity/AuthToken.java b/src/main/java/ru/soune/nocopy/entity/AuthToken.java similarity index 97% rename from src/main/java/ru/soune/no_copy/entity/AuthToken.java rename to src/main/java/ru/soune/nocopy/entity/AuthToken.java index 6418073..63cf34a 100644 --- a/src/main/java/ru/soune/no_copy/entity/AuthToken.java +++ b/src/main/java/ru/soune/nocopy/entity/AuthToken.java @@ -1,4 +1,4 @@ -package ru.soune.no_copy.entity; +package ru.soune.nocopy.entity; import jakarta.persistence.*; import lombok.*; diff --git a/src/main/java/ru/soune/no_copy/entity/BaseEntity.java b/src/main/java/ru/soune/nocopy/entity/BaseEntity.java similarity index 95% rename from src/main/java/ru/soune/no_copy/entity/BaseEntity.java rename to src/main/java/ru/soune/nocopy/entity/BaseEntity.java index b51c525..2743abf 100644 --- a/src/main/java/ru/soune/no_copy/entity/BaseEntity.java +++ b/src/main/java/ru/soune/nocopy/entity/BaseEntity.java @@ -1,4 +1,4 @@ -package ru.soune.no_copy.entity; +package ru.soune.nocopy.entity; import jakarta.persistence.*; import lombok.Getter; diff --git a/src/main/java/ru/soune/no_copy/entity/ContentStatus.java b/src/main/java/ru/soune/nocopy/entity/ContentStatus.java similarity index 89% rename from src/main/java/ru/soune/no_copy/entity/ContentStatus.java rename to src/main/java/ru/soune/nocopy/entity/ContentStatus.java index d97f66c..c2dfa41 100644 --- a/src/main/java/ru/soune/no_copy/entity/ContentStatus.java +++ b/src/main/java/ru/soune/nocopy/entity/ContentStatus.java @@ -1,4 +1,4 @@ -package ru.soune.no_copy.entity; +package ru.soune.nocopy.entity; import lombok.Getter; diff --git a/src/main/java/ru/soune/no_copy/entity/FileType.java b/src/main/java/ru/soune/nocopy/entity/FileType.java similarity index 89% rename from src/main/java/ru/soune/no_copy/entity/FileType.java rename to src/main/java/ru/soune/nocopy/entity/FileType.java index 4e0406d..7802a4f 100644 --- a/src/main/java/ru/soune/no_copy/entity/FileType.java +++ b/src/main/java/ru/soune/nocopy/entity/FileType.java @@ -1,4 +1,4 @@ -package ru.soune.no_copy.entity; +package ru.soune.nocopy.entity; import lombok.Getter; diff --git a/src/main/java/ru/soune/no_copy/entity/GenderType.java b/src/main/java/ru/soune/nocopy/entity/GenderType.java similarity index 57% rename from src/main/java/ru/soune/no_copy/entity/GenderType.java rename to src/main/java/ru/soune/nocopy/entity/GenderType.java index e85f0f2..580d825 100644 --- a/src/main/java/ru/soune/no_copy/entity/GenderType.java +++ b/src/main/java/ru/soune/nocopy/entity/GenderType.java @@ -1,4 +1,4 @@ -package ru.soune.no_copy.entity; +package ru.soune.nocopy.entity; public enum GenderType { MALE, FEMALE diff --git a/src/main/java/ru/soune/no_copy/entity/ImageProtection.java b/src/main/java/ru/soune/nocopy/entity/ImageProtection.java similarity index 97% rename from src/main/java/ru/soune/no_copy/entity/ImageProtection.java rename to src/main/java/ru/soune/nocopy/entity/ImageProtection.java index 79a8c8d..eef9e95 100644 --- a/src/main/java/ru/soune/no_copy/entity/ImageProtection.java +++ b/src/main/java/ru/soune/nocopy/entity/ImageProtection.java @@ -1,4 +1,4 @@ -package ru.soune.no_copy.entity; +package ru.soune.nocopy.entity; import jakarta.persistence.*; import lombok.*; diff --git a/src/main/java/ru/soune/no_copy/entity/SubscriptionType.java b/src/main/java/ru/soune/nocopy/entity/SubscriptionType.java similarity index 76% rename from src/main/java/ru/soune/no_copy/entity/SubscriptionType.java rename to src/main/java/ru/soune/nocopy/entity/SubscriptionType.java index 4c78049..952722e 100644 --- a/src/main/java/ru/soune/no_copy/entity/SubscriptionType.java +++ b/src/main/java/ru/soune/nocopy/entity/SubscriptionType.java @@ -1,4 +1,4 @@ -package ru.soune.no_copy.entity; +package ru.soune.nocopy.entity; import lombok.Getter; diff --git a/src/main/java/ru/soune/no_copy/entity/User.java b/src/main/java/ru/soune/nocopy/entity/User.java similarity index 97% rename from src/main/java/ru/soune/no_copy/entity/User.java rename to src/main/java/ru/soune/nocopy/entity/User.java index 63a23f2..0841027 100644 --- a/src/main/java/ru/soune/no_copy/entity/User.java +++ b/src/main/java/ru/soune/nocopy/entity/User.java @@ -1,4 +1,4 @@ -package ru.soune.no_copy.entity; +package ru.soune.nocopy.entity; import com.fasterxml.jackson.annotation.JsonIgnore; import jakarta.persistence.*; @@ -42,6 +42,7 @@ public class User { private String password; @Size(min = 11, max = 14) + @Column(unique = true) private String phone; @Enumerated(EnumType.STRING) diff --git a/src/main/java/ru/soune/no_copy/entity/UserAction.java b/src/main/java/ru/soune/nocopy/entity/UserAction.java similarity index 97% rename from src/main/java/ru/soune/no_copy/entity/UserAction.java rename to src/main/java/ru/soune/nocopy/entity/UserAction.java index d9d22ef..661ab3a 100644 --- a/src/main/java/ru/soune/no_copy/entity/UserAction.java +++ b/src/main/java/ru/soune/nocopy/entity/UserAction.java @@ -1,4 +1,4 @@ -package ru.soune.no_copy.entity; +package ru.soune.nocopy.entity; import jakarta.persistence.*; import lombok.*; diff --git a/src/main/java/ru/soune/no_copy/entity/UserContent.java b/src/main/java/ru/soune/nocopy/entity/UserContent.java similarity index 96% rename from src/main/java/ru/soune/no_copy/entity/UserContent.java rename to src/main/java/ru/soune/nocopy/entity/UserContent.java index 22ee0b0..4c7fe9a 100644 --- a/src/main/java/ru/soune/no_copy/entity/UserContent.java +++ b/src/main/java/ru/soune/nocopy/entity/UserContent.java @@ -1,8 +1,7 @@ -package ru.soune.no_copy.entity; +package ru.soune.nocopy.entity; import jakarta.persistence.*; import lombok.*; -import org.hibernate.annotations.CreationTimestamp; import org.springframework.data.annotation.CreatedDate; import org.springframework.data.jpa.domain.support.AuditingEntityListener; diff --git a/src/main/java/ru/soune/no_copy/entity/Violation.java b/src/main/java/ru/soune/nocopy/entity/Violation.java similarity index 97% rename from src/main/java/ru/soune/no_copy/entity/Violation.java rename to src/main/java/ru/soune/nocopy/entity/Violation.java index 6e1768c..dd504bd 100644 --- a/src/main/java/ru/soune/no_copy/entity/Violation.java +++ b/src/main/java/ru/soune/nocopy/entity/Violation.java @@ -1,4 +1,4 @@ -package ru.soune.no_copy.entity; +package ru.soune.nocopy.entity; import jakarta.persistence.*; import lombok.*; diff --git a/src/main/java/ru/soune/no_copy/exception/ContentNotFoundException.java b/src/main/java/ru/soune/nocopy/exception/ContentNotFoundException.java similarity index 80% rename from src/main/java/ru/soune/no_copy/exception/ContentNotFoundException.java rename to src/main/java/ru/soune/nocopy/exception/ContentNotFoundException.java index af0f040..75b8af7 100644 --- a/src/main/java/ru/soune/no_copy/exception/ContentNotFoundException.java +++ b/src/main/java/ru/soune/nocopy/exception/ContentNotFoundException.java @@ -1,4 +1,4 @@ -package ru.soune.no_copy.exception; +package ru.soune.nocopy.exception; public class ContentNotFoundException extends RuntimeException { public ContentNotFoundException(String message) { diff --git a/src/main/java/ru/soune/no_copy/exception/InvalidPasswordException.java b/src/main/java/ru/soune/nocopy/exception/InvalidPasswordException.java similarity index 80% rename from src/main/java/ru/soune/no_copy/exception/InvalidPasswordException.java rename to src/main/java/ru/soune/nocopy/exception/InvalidPasswordException.java index b9f2820..72a43e9 100644 --- a/src/main/java/ru/soune/no_copy/exception/InvalidPasswordException.java +++ b/src/main/java/ru/soune/nocopy/exception/InvalidPasswordException.java @@ -1,4 +1,4 @@ -package ru.soune.no_copy.exception; +package ru.soune.nocopy.exception; public class InvalidPasswordException extends RuntimeException { public InvalidPasswordException(String message) { diff --git a/src/main/java/ru/soune/no_copy/exception/InvalidUserEmail.java b/src/main/java/ru/soune/nocopy/exception/InvalidUserEmail.java similarity index 79% rename from src/main/java/ru/soune/no_copy/exception/InvalidUserEmail.java rename to src/main/java/ru/soune/nocopy/exception/InvalidUserEmail.java index 7ce203b..850a7f1 100644 --- a/src/main/java/ru/soune/no_copy/exception/InvalidUserEmail.java +++ b/src/main/java/ru/soune/nocopy/exception/InvalidUserEmail.java @@ -1,4 +1,4 @@ -package ru.soune.no_copy.exception; +package ru.soune.nocopy.exception; public class InvalidUserEmail extends RuntimeException { public InvalidUserEmail(String message) { diff --git a/src/main/java/ru/soune/no_copy/exception/NotFoundAuthToken.java b/src/main/java/ru/soune/nocopy/exception/NotFoundAuthToken.java similarity index 79% rename from src/main/java/ru/soune/no_copy/exception/NotFoundAuthToken.java rename to src/main/java/ru/soune/nocopy/exception/NotFoundAuthToken.java index 7a61eea..473f486 100644 --- a/src/main/java/ru/soune/no_copy/exception/NotFoundAuthToken.java +++ b/src/main/java/ru/soune/nocopy/exception/NotFoundAuthToken.java @@ -1,4 +1,4 @@ -package ru.soune.no_copy.exception; +package ru.soune.nocopy.exception; public class NotFoundAuthToken extends RuntimeException { public NotFoundAuthToken(String message) { diff --git a/src/main/java/ru/soune/nocopy/exception/NotValidFieldException.java b/src/main/java/ru/soune/nocopy/exception/NotValidFieldException.java new file mode 100644 index 0000000..fee0335 --- /dev/null +++ b/src/main/java/ru/soune/nocopy/exception/NotValidFieldException.java @@ -0,0 +1,18 @@ +package ru.soune.nocopy.exception; + +import lombok.Getter; +import ru.soune.nocopy.dto.BaseResponse; + +@Getter +public class NotValidFieldException extends RuntimeException { + + private final String message; + + private final BaseResponse baseResponse; + + public NotValidFieldException(String message, BaseResponse baseResponse) { + super(message); + this.message = message; + this.baseResponse = baseResponse; + } +} diff --git a/src/main/java/ru/soune/no_copy/exception/NotValidationPasswordException.java b/src/main/java/ru/soune/nocopy/exception/NotValidationPasswordException.java similarity index 82% rename from src/main/java/ru/soune/no_copy/exception/NotValidationPasswordException.java rename to src/main/java/ru/soune/nocopy/exception/NotValidationPasswordException.java index 6e24040..48a2fe5 100644 --- a/src/main/java/ru/soune/no_copy/exception/NotValidationPasswordException.java +++ b/src/main/java/ru/soune/nocopy/exception/NotValidationPasswordException.java @@ -1,4 +1,4 @@ -package ru.soune.no_copy.exception; +package ru.soune.nocopy.exception; public class NotValidationPasswordException extends RuntimeException { public NotValidationPasswordException(String message) { diff --git a/src/main/java/ru/soune/no_copy/exception/TokenNotFoundException.java b/src/main/java/ru/soune/nocopy/exception/TokenNotFoundException.java similarity index 80% rename from src/main/java/ru/soune/no_copy/exception/TokenNotFoundException.java rename to src/main/java/ru/soune/nocopy/exception/TokenNotFoundException.java index d2e526b..b934cf4 100644 --- a/src/main/java/ru/soune/no_copy/exception/TokenNotFoundException.java +++ b/src/main/java/ru/soune/nocopy/exception/TokenNotFoundException.java @@ -1,4 +1,4 @@ -package ru.soune.no_copy.exception; +package ru.soune.nocopy.exception; public class TokenNotFoundException extends RuntimeException { public TokenNotFoundException(String message) { diff --git a/src/main/java/ru/soune/no_copy/exception/UserNotFoundException.java b/src/main/java/ru/soune/nocopy/exception/UserNotFoundException.java similarity index 80% rename from src/main/java/ru/soune/no_copy/exception/UserNotFoundException.java rename to src/main/java/ru/soune/nocopy/exception/UserNotFoundException.java index a8d8b03..919ff70 100644 --- a/src/main/java/ru/soune/no_copy/exception/UserNotFoundException.java +++ b/src/main/java/ru/soune/nocopy/exception/UserNotFoundException.java @@ -1,4 +1,4 @@ -package ru.soune.no_copy.exception; +package ru.soune.nocopy.exception; public class UserNotFoundException extends RuntimeException { public UserNotFoundException(String message) { diff --git a/src/main/java/ru/soune/nocopy/exception/ValidationException.java b/src/main/java/ru/soune/nocopy/exception/ValidationException.java new file mode 100644 index 0000000..71b8638 --- /dev/null +++ b/src/main/java/ru/soune/nocopy/exception/ValidationException.java @@ -0,0 +1,16 @@ +package ru.soune.nocopy.exception; + +import lombok.Getter; +import org.springframework.validation.BindingResult; + +@Getter +public class ValidationException extends RuntimeException { + private final BindingResult bindingResult; + private final Integer msgId; + + public ValidationException(BindingResult bindingResult, Integer msgId) { + super("Validation failed"); + this.bindingResult = bindingResult; + this.msgId = msgId; + } +} diff --git a/src/main/java/ru/soune/no_copy/handler/GlobalExceptionHandler.java b/src/main/java/ru/soune/nocopy/handler/GlobalExceptionHandler.java similarity index 85% rename from src/main/java/ru/soune/no_copy/handler/GlobalExceptionHandler.java rename to src/main/java/ru/soune/nocopy/handler/GlobalExceptionHandler.java index c3a02b2..071b9ae 100644 --- a/src/main/java/ru/soune/no_copy/handler/GlobalExceptionHandler.java +++ b/src/main/java/ru/soune/nocopy/handler/GlobalExceptionHandler.java @@ -1,4 +1,4 @@ -package ru.soune.no_copy.handler; +package ru.soune.nocopy.handler; import lombok.AllArgsConstructor; import org.springframework.context.support.DefaultMessageSourceResolvable; @@ -8,7 +8,7 @@ import org.springframework.web.bind.MethodArgumentNotValidException; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.ResponseStatus; import org.springframework.web.bind.annotation.RestControllerAdvice; -import ru.soune.no_copy.exception.*; +import ru.soune.nocopy.exception.*; import java.util.Map; @@ -29,15 +29,13 @@ public class GlobalExceptionHandler { "message" ,message)); } - @ExceptionHandler(UserAlreadyExistsException.class) - @ResponseStatus(HttpStatus.CONFLICT) - public ResponseEntity handleUserContainsException(UserAlreadyExistsException ex) { - return ResponseEntity. - badRequest() - .body(Map.of( - "success", false, - "message" ,ex.getMessage() - )); + @ExceptionHandler(NotValidFieldException.class) + @ResponseStatus(HttpStatus.OK) + public ResponseEntity handleUserContainsException(NotValidFieldException ex) { + + return ResponseEntity + .ok() + .body(ex.getBaseResponse()); } @ExceptionHandler(UserNotFoundException.class) diff --git a/src/main/java/ru/soune/nocopy/handler/LoginRequestHandler.java b/src/main/java/ru/soune/nocopy/handler/LoginRequestHandler.java new file mode 100644 index 0000000..95abf63 --- /dev/null +++ b/src/main/java/ru/soune/nocopy/handler/LoginRequestHandler.java @@ -0,0 +1,44 @@ +package ru.soune.nocopy.handler; + +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Component; +import ru.soune.nocopy.dto.*; +import ru.soune.nocopy.entity.AuthToken; +import ru.soune.nocopy.exception.NotValidFieldException; +import ru.soune.nocopy.repository.UserRepository; +import ru.soune.nocopy.service.AuthService; + +import java.util.Arrays; +import java.util.Map; + +@Component +@RequiredArgsConstructor +public class LoginRequestHandler implements RequestHandler { + + private final UserRepository userRepository; + private final AuthService authService; + private final ObjectMapper objectMapper; + + @Override + public BaseResponse handle(BaseRequest request) { + LoginRequest loginRequest = objectMapper.convertValue(request.getMessageBody(), LoginRequest.class); + + if (!userRepository.existsByEmail(loginRequest.getEmail())) { + LoginAnswer loginAnswer = new LoginAnswer(); + loginAnswer.setFieldErrors(Arrays.asList(Map.of("email", loginRequest.getEmail()))); + + throw new NotValidFieldException("User with email not found: " + loginRequest.getEmail(), + new BaseResponse(request.getMsgId(), MessageCode.AUTH_EMAIL_NOT_FOUND.getCode(), + MessageCode.AUTH_EMAIL_NOT_FOUND.getDescription(), loginAnswer)); + } + + AuthToken authToken = authService.login(loginRequest); + + LoginAnswer loginAnswer = new LoginAnswer(); + loginAnswer.setToken(authToken.getToken()); + + return new BaseResponse(request.getMsgId(), MessageCode.SUCCESS.getCode(), + MessageCode.SUCCESS.getDescription(), loginAnswer); + } +} diff --git a/src/main/java/ru/soune/nocopy/handler/RegRequestHandler.java b/src/main/java/ru/soune/nocopy/handler/RegRequestHandler.java new file mode 100644 index 0000000..349f0a7 --- /dev/null +++ b/src/main/java/ru/soune/nocopy/handler/RegRequestHandler.java @@ -0,0 +1,62 @@ +package ru.soune.nocopy.handler; + +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; +import org.springframework.validation.BeanPropertyBindingResult; +import org.springframework.validation.BindingResult; +import ru.soune.nocopy.dto.*; +import ru.soune.nocopy.entity.AuthToken; +import ru.soune.nocopy.exception.NotValidFieldException; +import ru.soune.nocopy.exception.ValidationException; +import ru.soune.nocopy.handler.validator.RegRequestValidator; +import ru.soune.nocopy.repository.UserRepository; +import ru.soune.nocopy.service.AuthService; + +import java.util.Arrays; +import java.util.Map; + +@Slf4j +@Component +@RequiredArgsConstructor +public class RegRequestHandler implements RequestHandler { + private final UserRepository userRepository; + + private final RegRequestValidator regRequestValidator; + + private final AuthService authService; + + private final ObjectMapper objectMapper; + + @Override + public BaseResponse handle(BaseRequest request) throws ValidationException { + RegRequest regRequest = objectMapper.convertValue(request.getMessageBody(), RegRequest.class); + + if (userRepository.existsByEmail(regRequest.getEmail()) || userRepository.existsByPhone(regRequest.getPhone())) { + RegAnswer regAnswer = new RegAnswer(); + regAnswer.setFieldErrors(Arrays.asList(Map.of("email", regRequest.getEmail()))); + regAnswer.setFieldErrors(Arrays.asList(Map.of("phone", regRequest.getPhone()))); + + throw new NotValidFieldException("User already exists with email:" + regRequest.getEmail() + " or phone: " + + regRequest.getPhone(), new BaseResponse(request.getMsgId(), + MessageCode.REG_EMAIL_OR_PHONE_EXISTS.getCode(), + MessageCode.REG_EMAIL_OR_PHONE_EXISTS.getDescription(), regAnswer)); + } + + BindingResult bindingResult = new BeanPropertyBindingResult(regRequest, "regRequest"); + regRequestValidator.validate(regRequest, bindingResult); + + if (bindingResult.hasErrors()) { + throw new ValidationException(bindingResult, request.getMsgId()); + } + + AuthToken authToken = authService.register(regRequest); + + RegAnswer regAnswer = new RegAnswer(); + regAnswer.setToken(authToken.getToken()); + + return new BaseResponse(request.getMsgId(), MessageCode.SUCCESS.getCode(), + MessageCode.SUCCESS.getDescription(), regAnswer); + } +} \ No newline at end of file diff --git a/src/main/java/ru/soune/nocopy/handler/RequestHandler.java b/src/main/java/ru/soune/nocopy/handler/RequestHandler.java new file mode 100644 index 0000000..230c87a --- /dev/null +++ b/src/main/java/ru/soune/nocopy/handler/RequestHandler.java @@ -0,0 +1,8 @@ +package ru.soune.nocopy.handler; + +import ru.soune.nocopy.dto.BaseRequest; +import ru.soune.nocopy.dto.BaseResponse; + +public interface RequestHandler { + BaseResponse handle(BaseRequest request) throws Exception; +} diff --git a/src/main/java/ru/soune/nocopy/handler/validator/RegRequestValidator.java b/src/main/java/ru/soune/nocopy/handler/validator/RegRequestValidator.java new file mode 100644 index 0000000..f3dbda7 --- /dev/null +++ b/src/main/java/ru/soune/nocopy/handler/validator/RegRequestValidator.java @@ -0,0 +1,225 @@ +package ru.soune.nocopy.handler.validator; + +import org.apache.commons.validator.routines.DomainValidator; +import org.apache.commons.validator.routines.EmailValidator; +import org.springframework.stereotype.Component; +import org.springframework.validation.Errors; +import org.springframework.validation.Validator; +import ru.soune.nocopy.dto.RegRequest; + +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.util.*; + +@Component +public class RegRequestValidator implements Validator { + private static final String COMPANY_REGEX = "^[a-zA-Zа-яА-ЯёЁ0-9\\s\\-&.,'()]{0,200}$"; + + private static final String NAME_REGEX = "^[a-zA-Zа-яА-ЯёЁ\\s\\-'.]{2,100}$"; + + @Override + public boolean supports(Class clazz) { + return RegRequest.class.isAssignableFrom(clazz); + } + + @Override + public void validate(Object target, Errors errors) { + RegRequest request = (RegRequest) target; + + validatePhone(request.getPhone(), errors); + validatePassword(request.getPassword(), errors); + validateEmail(request.getEmail(), errors); + validateCompanyName(request.getCompanyName(), errors); + validateFullName(request.getFullName(), errors); + } + + private void validateFullName(String fullName, Errors errors) { + if (fullName == null || fullName.trim().isEmpty()) { + errors.rejectValue("fullName", "fullName.required", + "Full name is required"); + return; + } + + String trimmedName = fullName.trim(); + + if (trimmedName.length() < 2) { + errors.rejectValue("fullName", "fullName.too.short", + "Full name must be at least 2 characters"); + } + + if (trimmedName.length() > 100) { + errors.rejectValue("fullName", "fullName.too.long", + "Full name must be less than 100 characters"); + } + + if (!trimmedName.matches(NAME_REGEX)) { + errors.rejectValue("fullName", "fullName.invalid.chars", + "Name can only contain letters, spaces, hyphens and apostrophes"); + } + } + + private void validateCompanyName(String companyName, Errors errors) { + if (companyName == null || companyName.trim().isEmpty()) { + return; + } + + String trimmedCompany = companyName.trim(); + + if (trimmedCompany.length() > 200) { + errors.rejectValue("companyName", "companyName.too.long", + "Company name must be less than 200 characters"); + } + + if (!trimmedCompany.matches(COMPANY_REGEX)) { + errors.rejectValue("companyName", "companyName.invalid.chars", + "Company name contains invalid characters"); + } + + validateForbiddenWords(trimmedCompany, "companyName", errors, + Arrays.asList("admin", "root", "system", "test")); + } + + private void validateForbiddenWords(String text, String fieldName, + Errors errors, List forbiddenWords) { + String lowerText = text.toLowerCase(); + for (String word : forbiddenWords) { + if (lowerText.contains(word)) { + errors.rejectValue(fieldName, fieldName + ".forbidden.word", + "Contains forbidden word: " + word); + break; + } + } + } + + private void validateEmail(String email, Errors errors) { + if (email == null || email.trim().isEmpty()) { + errors.rejectValue("email", "email.is.empty", "Email must not be empty"); + return; + } + + String trimmedEmail = email.trim().toLowerCase(); + + if (trimmedEmail.length() > 254) { + errors.rejectValue("email", "email.too.long", "Email is too long"); + return; + } + + EmailValidator emailValidator = EmailValidator.getInstance(true, true); + if (!emailValidator.isValid(trimmedEmail)) { + errors.rejectValue("email", "email.invalid", "Invalid email address"); + return; + } + } + + + private void validatePhone(String phone, Errors errors) { + if (phone == null || phone.trim().isEmpty()) { + errors.rejectValue("phone", "phone.empty", + "Test phone numbers are not allowed"); + return; + } + + String trimmedPhone = phone.trim(); + String digitsOnly = trimmedPhone.replaceAll("[^0-9+]", ""); + + if (digitsOnly.length() < 11 || digitsOnly.length() > 14) { + errors.rejectValue("phone", "phone.invalid.length", + "Phone number must contain 11-14 digits"); + return; + } + + if (!digitsOnly.matches("^(\\+7|8|7)[0-9]{10}$")) { + errors.rejectValue("phone", "phone.invalid.format", + "Invalid phone number format"); + return; + } + } + + private void validatePassword(String password, Errors errors) { + if (password == null || password.isEmpty()) { + errors.rejectValue("password", "password.empty", + "Password are not allowed"); + return; + } + + if (password.length() < 8) { + errors.rejectValue("password", "password.too.short", + "Password must be at least 8 characters"); + } + + if (password.length() > 50) { + errors.rejectValue("password", "password.too.long", + "Password must be less than 50 characters"); + } + + if (password.contains(" ")) { + errors.rejectValue("password", "password.contains.spaces", + "Password cannot contain spaces"); + } + +// recomment if need complexity +// checkPasswordComplexity(password, errors); + +// reccoment if need check simply standart password +// checkCommonPasswords(password, errors); + +// reccoment if need check simply standart password +// checkForSequences(password, errors); + } + + private void checkPasswordComplexity(String password, Errors errors) { + boolean hasUpper = false; + boolean hasLower = false; + boolean hasDigit = false; + boolean hasSpecial = false; + + for (char c : password.toCharArray()) { + if (Character.isUpperCase(c)) hasUpper = true; + if (Character.isLowerCase(c)) hasLower = true; + if (Character.isDigit(c)) hasDigit = true; + if ("!@#$%^&*()_+-=[]{}|;:,.<>?".indexOf(c) >= 0) hasSpecial = true; + } + + List missing = new ArrayList<>(); + if (!hasUpper) missing.add("uppercase letter"); + if (!hasLower) missing.add("lowercase letter"); + if (!hasDigit) missing.add("digit"); + if (!hasSpecial) missing.add("special character"); + + if (!missing.isEmpty()) { + String message = "Password must contain: " + String.join(", ", missing); + errors.rejectValue("password", "password.complexity.missing", message); + } + } + + private void checkCommonPasswords(String password, Errors errors) { + Set commonPasswords = Set.of( + "password", "12345678", "qwerty123", "admin123", + "welcome1", "password1", "123456789", "qwertyuiop" + ); + + if (commonPasswords.contains(password.toLowerCase())) { + errors.rejectValue("password", "password.too.common", + "This password is too common, please choose another"); + } + } + + private void checkForSequences(String password, Errors errors) { + String lower = password.toLowerCase(); + + if (lower.matches(".*123456.*") || lower.matches(".*987654.*")) { + errors.rejectValue("password", "password.sequence.numbers", + "Password contains predictable number sequence"); + } + + if (lower.matches(".*abcdef.*") || lower.matches(".*qwerty.*")) { + errors.rejectValue("password", "password.sequence.letters", + "Password contains predictable letter sequence"); + } + + if (lower.matches(".*(.)\\1{3,}.*")) { + errors.rejectValue("password", "password.repeating.chars", + "Password contains too many repeating characters"); + } + } +} diff --git a/src/main/java/ru/soune/no_copy/mapper/UserContentMapper.java b/src/main/java/ru/soune/nocopy/mapper/UserContentMapper.java similarity index 79% rename from src/main/java/ru/soune/no_copy/mapper/UserContentMapper.java rename to src/main/java/ru/soune/nocopy/mapper/UserContentMapper.java index 5617cbd..3959f8f 100644 --- a/src/main/java/ru/soune/no_copy/mapper/UserContentMapper.java +++ b/src/main/java/ru/soune/nocopy/mapper/UserContentMapper.java @@ -1,11 +1,11 @@ -package ru.soune.no_copy.mapper; +package ru.soune.nocopy.mapper; import org.mapstruct.Mapper; import org.mapstruct.MappingTarget; import org.mapstruct.NullValuePropertyMappingStrategy; import org.mapstruct.factory.Mappers; -import ru.soune.no_copy.dto.UserContentUpdateRequest; -import ru.soune.no_copy.entity.UserContent; +import ru.soune.nocopy.dto.UserContentUpdateRequest; +import ru.soune.nocopy.entity.UserContent; @Mapper(componentModel = "spring", nullValuePropertyMappingStrategy = NullValuePropertyMappingStrategy.IGNORE) diff --git a/src/main/java/ru/soune/no_copy/mapper/UserMapper.java b/src/main/java/ru/soune/nocopy/mapper/UserMapper.java similarity index 77% rename from src/main/java/ru/soune/no_copy/mapper/UserMapper.java rename to src/main/java/ru/soune/nocopy/mapper/UserMapper.java index 442f082..c151480 100644 --- a/src/main/java/ru/soune/no_copy/mapper/UserMapper.java +++ b/src/main/java/ru/soune/nocopy/mapper/UserMapper.java @@ -1,10 +1,10 @@ -package ru.soune.no_copy.mapper; +package ru.soune.nocopy.mapper; import org.mapstruct.Mapper; import org.mapstruct.NullValuePropertyMappingStrategy; import org.mapstruct.factory.Mappers; -import ru.soune.no_copy.dto.UserDTO; -import ru.soune.no_copy.entity.User; +import ru.soune.nocopy.dto.UserDTO; +import ru.soune.nocopy.entity.User; @Mapper(componentModel = "spring", nullValuePropertyMappingStrategy = NullValuePropertyMappingStrategy.IGNORE) diff --git a/src/main/java/ru/soune/no_copy/repository/AuthTokenRepository.java b/src/main/java/ru/soune/nocopy/repository/AuthTokenRepository.java similarity index 83% rename from src/main/java/ru/soune/no_copy/repository/AuthTokenRepository.java rename to src/main/java/ru/soune/nocopy/repository/AuthTokenRepository.java index af56845..74826fd 100644 --- a/src/main/java/ru/soune/no_copy/repository/AuthTokenRepository.java +++ b/src/main/java/ru/soune/nocopy/repository/AuthTokenRepository.java @@ -1,8 +1,8 @@ -package ru.soune.no_copy.repository; +package ru.soune.nocopy.repository; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; -import ru.soune.no_copy.entity.AuthToken; +import ru.soune.nocopy.entity.AuthToken; import java.time.LocalDate; import java.util.Optional; diff --git a/src/main/java/ru/soune/no_copy/repository/UserContentRepository.java b/src/main/java/ru/soune/nocopy/repository/UserContentRepository.java similarity index 82% rename from src/main/java/ru/soune/no_copy/repository/UserContentRepository.java rename to src/main/java/ru/soune/nocopy/repository/UserContentRepository.java index 95f524b..f1103a4 100644 --- a/src/main/java/ru/soune/no_copy/repository/UserContentRepository.java +++ b/src/main/java/ru/soune/nocopy/repository/UserContentRepository.java @@ -1,9 +1,9 @@ -package ru.soune.no_copy.repository; +package ru.soune.nocopy.repository; import org.springframework.data.domain.Pageable; import org.springframework.data.jpa.repository.JpaRepository; -import ru.soune.no_copy.entity.FileType; -import ru.soune.no_copy.entity.UserContent; +import ru.soune.nocopy.entity.FileType; +import ru.soune.nocopy.entity.UserContent; import java.util.List; diff --git a/src/main/java/ru/soune/no_copy/repository/UserRepository.java b/src/main/java/ru/soune/nocopy/repository/UserRepository.java similarity index 57% rename from src/main/java/ru/soune/no_copy/repository/UserRepository.java rename to src/main/java/ru/soune/nocopy/repository/UserRepository.java index 472fe58..f674629 100644 --- a/src/main/java/ru/soune/no_copy/repository/UserRepository.java +++ b/src/main/java/ru/soune/nocopy/repository/UserRepository.java @@ -1,11 +1,13 @@ -package ru.soune.no_copy.repository; +package ru.soune.nocopy.repository; +import jakarta.validation.constraints.Size; import org.springframework.data.jpa.repository.JpaRepository; -import ru.soune.no_copy.entity.User; +import ru.soune.nocopy.entity.User; import java.util.Optional; public interface UserRepository extends JpaRepository { Optional findByEmail(String email); boolean existsByEmail(String email); + boolean existsByPhone(@Size(min = 11, max = 14) String phone); } diff --git a/src/main/java/ru/soune/no_copy/service/AuthService.java b/src/main/java/ru/soune/nocopy/service/AuthService.java similarity index 61% rename from src/main/java/ru/soune/no_copy/service/AuthService.java rename to src/main/java/ru/soune/nocopy/service/AuthService.java index 1cb1966..2377b2b 100644 --- a/src/main/java/ru/soune/no_copy/service/AuthService.java +++ b/src/main/java/ru/soune/nocopy/service/AuthService.java @@ -1,24 +1,22 @@ -package ru.soune.no_copy.service; +package ru.soune.nocopy.service; import lombok.RequiredArgsConstructor; import org.springframework.context.MessageSource; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import ru.soune.no_copy.dto.LoginRequest; -import ru.soune.no_copy.dto.RegisterRequest; -import ru.soune.no_copy.entity.AuthToken; -import ru.soune.no_copy.entity.User; -import ru.soune.no_copy.exception.NotValidationPasswordException; -import ru.soune.no_copy.exception.UserAlreadyExistsException; -import ru.soune.no_copy.exception.UserNotFoundException; -import ru.soune.no_copy.repository.AuthTokenRepository; -import ru.soune.no_copy.repository.UserRepository; +import ru.soune.nocopy.dto.*; +import ru.soune.nocopy.entity.AuthToken; +import ru.soune.nocopy.entity.User; +import ru.soune.nocopy.exception.NotValidFieldException; +import ru.soune.nocopy.repository.AuthTokenRepository; +import ru.soune.nocopy.repository.UserRepository; import java.security.SecureRandom; import java.time.LocalDateTime; +import java.util.Arrays; import java.util.Base64; -import java.util.Locale; +import java.util.Map; import java.util.Optional; @Service @@ -36,22 +34,18 @@ public class AuthService { private final SecureRandom secureRandom = new SecureRandom(); @Transactional - public AuthToken register(RegisterRequest registerRequest) { - if (userRepository.existsByEmail(registerRequest.email())) { - throw new UserAlreadyExistsException("User already exists with email: " + registerRequest.email()); - } - + public AuthToken register(RegRequest registerRequest) { User user = new User(); - user.setFullName(registerRequest.fullName()); - user.setEmail(registerRequest.email()); - user.setPassword(passwordEncoder.encode(registerRequest.password())); + user.setFullName(registerRequest.getFullName()); + user.setEmail(registerRequest.getEmail()); + user.setPassword(passwordEncoder.encode(registerRequest.getPassword())); - if (registerRequest.companyName() != null) { - user.setCompany(registerRequest.companyName()); + if (registerRequest.getCompanyName() != null) { + user.setCompany(registerRequest.getCompanyName()); } - if (registerRequest.phone() != null) { - user.setPhone(registerRequest.phone()); + if (registerRequest.getPhone() != null) { + user.setPhone(registerRequest.getPhone()); } User savedUser = userRepository.save(user); @@ -66,15 +60,15 @@ public class AuthService { @Transactional public AuthToken login(LoginRequest request) { Optional userOpt = userRepository.findByEmail(request.getEmail()); - - if (userOpt.isEmpty()) { - throw new UserNotFoundException("User with email " + request.getEmail() + " not found"); - } - User user = userOpt.get(); if (!passwordEncoder.matches(request.getPassword(), user.getPassword())) { - throw new NotValidationPasswordException("Invalid password"); + LoginAnswer loginAnswer = new LoginAnswer(); + loginAnswer.setFieldErrors(Arrays.asList(Map.of("password", request.getPassword()))); + + throw new NotValidFieldException("Invalid password", new BaseResponse(20003, + MessageCode.AUTH_PASSWORD_NOT_MATCHES.getCode(), + MessageCode.AUTH_PASSWORD_NOT_MATCHES.getDescription(), loginAnswer)); } user.setLastLoginAt(LocalDateTime.now()); diff --git a/src/main/java/ru/soune/no_copy/service/UserContentService.java b/src/main/java/ru/soune/nocopy/service/UserContentService.java similarity index 81% rename from src/main/java/ru/soune/no_copy/service/UserContentService.java rename to src/main/java/ru/soune/nocopy/service/UserContentService.java index eb89f77..b1fe0b3 100644 --- a/src/main/java/ru/soune/no_copy/service/UserContentService.java +++ b/src/main/java/ru/soune/nocopy/service/UserContentService.java @@ -1,18 +1,18 @@ -package ru.soune.no_copy.service; +package ru.soune.nocopy.service; import lombok.AllArgsConstructor; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import ru.soune.no_copy.dto.UserContentRequest; -import ru.soune.no_copy.dto.UserContentUpdateRequest; -import ru.soune.no_copy.entity.FileType; -import ru.soune.no_copy.entity.User; -import ru.soune.no_copy.entity.UserContent; -import ru.soune.no_copy.exception.ContentNotFoundException; -import ru.soune.no_copy.exception.UserNotFoundException; -import ru.soune.no_copy.mapper.UserContentMapper; -import ru.soune.no_copy.repository.UserContentRepository; -import ru.soune.no_copy.repository.UserRepository; +import ru.soune.nocopy.dto.UserContentRequest; +import ru.soune.nocopy.dto.UserContentUpdateRequest; +import ru.soune.nocopy.entity.FileType; +import ru.soune.nocopy.entity.User; +import ru.soune.nocopy.entity.UserContent; +import ru.soune.nocopy.exception.ContentNotFoundException; +import ru.soune.nocopy.exception.UserNotFoundException; +import ru.soune.nocopy.mapper.UserContentMapper; +import ru.soune.nocopy.repository.UserContentRepository; +import ru.soune.nocopy.repository.UserRepository; import java.util.List; import java.util.Optional; diff --git a/src/main/java/ru/soune/no_copy/service/UserService.java b/src/main/java/ru/soune/nocopy/service/UserService.java similarity index 86% rename from src/main/java/ru/soune/no_copy/service/UserService.java rename to src/main/java/ru/soune/nocopy/service/UserService.java index 4cb0a51..7c4b79f 100644 --- a/src/main/java/ru/soune/no_copy/service/UserService.java +++ b/src/main/java/ru/soune/nocopy/service/UserService.java @@ -1,17 +1,17 @@ -package ru.soune.no_copy.service; +package ru.soune.nocopy.service; import lombok.AllArgsConstructor; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import ru.soune.no_copy.dto.ChangePasswordRequest; -import ru.soune.no_copy.dto.UserDTO; -import ru.soune.no_copy.dto.UserRequest; -import ru.soune.no_copy.entity.User; -import ru.soune.no_copy.exception.InvalidUserEmail; -import ru.soune.no_copy.exception.NotValidationPasswordException; -import ru.soune.no_copy.exception.UserNotFoundException; -import ru.soune.no_copy.repository.UserRepository; +import ru.soune.nocopy.dto.ChangePasswordRequest; +import ru.soune.nocopy.dto.UserDTO; +import ru.soune.nocopy.dto.UserRequest; +import ru.soune.nocopy.entity.User; +import ru.soune.nocopy.exception.InvalidUserEmail; +import ru.soune.nocopy.exception.NotValidationPasswordException; +import ru.soune.nocopy.exception.UserNotFoundException; +import ru.soune.nocopy.repository.UserRepository; @Service @AllArgsConstructor diff --git a/src/test/java/ru/soune/no_copy/service/AuthServiceTest.java b/src/test/java/ru/soune/nocopy/service/AuthServiceTest.java similarity index 57% rename from src/test/java/ru/soune/no_copy/service/AuthServiceTest.java rename to src/test/java/ru/soune/nocopy/service/AuthServiceTest.java index 2b75fcb..499d694 100644 --- a/src/test/java/ru/soune/no_copy/service/AuthServiceTest.java +++ b/src/test/java/ru/soune/nocopy/service/AuthServiceTest.java @@ -1,4 +1,4 @@ -package ru.soune.no_copy.service; +package ru.soune.nocopy.service; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -8,22 +8,18 @@ import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.springframework.context.MessageSource; import org.springframework.security.crypto.password.PasswordEncoder; -import ru.soune.no_copy.dto.LoginRequest; -import ru.soune.no_copy.dto.RegisterRequest; -import ru.soune.no_copy.entity.AuthToken; -import ru.soune.no_copy.entity.User; -import ru.soune.no_copy.exception.NotValidationPasswordException; -import ru.soune.no_copy.exception.UserAlreadyExistsException; -import ru.soune.no_copy.exception.UserNotFoundException; -import ru.soune.no_copy.repository.AuthTokenRepository; -import ru.soune.no_copy.repository.UserRepository; +import ru.soune.nocopy.dto.LoginRequest; +import ru.soune.nocopy.entity.AuthToken; +import ru.soune.nocopy.entity.User; +import ru.soune.nocopy.exception.NotValidationPasswordException; +import ru.soune.nocopy.exception.UserNotFoundException; +import ru.soune.nocopy.repository.AuthTokenRepository; +import ru.soune.nocopy.repository.UserRepository; -import java.util.Locale; import java.util.Optional; import static org.junit.jupiter.api.Assertions.*; import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -49,43 +45,6 @@ public class AuthServiceTest { MockitoAnnotations.openMocks(this); } - @Test - void registerSuccess() { - RegisterRequest request = new RegisterRequest("John","A.","124124", - "john@example.com", null,"password123", null, null); - - when(userRepository.existsByEmail(request.email())).thenReturn(false); - when(passwordEncoder.encode(request.password())).thenReturn("hashed"); - when(userRepository.save(any(User.class))).thenAnswer(invocation -> invocation.getArgument(0)); - when(authTokenRepository.save(any(AuthToken.class))).thenAnswer(invocation -> invocation.getArgument(0)); - - AuthToken token = authService.register(request); - User user = token.getUser(); - String email = user.getEmail(); - - assertNotNull(token); - assertNotNull(token.getToken()); - assertNotNull(token.getUser()); - assertEquals("john@example.com", email); - assertNotNull(token.getExpiresAt()); - } - - @Test - void registerExistingEmailThrows() { - RegisterRequest request = new RegisterRequest("John","A.","124124", - "john@example.com", null,"password123", null, null); - - when(userRepository.existsByEmail(request.email())) - .thenReturn(true); - when(messageSource.getMessage(anyString(), any(), any(Locale.class))) - .thenReturn("User exists"); - - UserAlreadyExistsException ex = assertThrows(UserAlreadyExistsException.class, - () -> authService.register(request)); - - assertEquals("User exists", ex.getMessage()); - } - @Test void login_success() { LoginRequest request = new LoginRequest("test@mail.com", "password");