diff --git a/docker-compose.yaml b/docker-compose.yaml index a6a02d4..a7824c4 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -1,32 +1,15 @@ version: '3.9' services: - postfix: - image: boky/postfix:latest - container_name: postfix-production - hostname: ${DOMAIN:-no-copy.ru} - environment: - - DOMAIN=${DOMAIN:-no-copy.ru} - - ALLOWED_SENDER_DOMAINS=* - - RELAYHOST= - - DISABLE_SMTP_AUTH= - - SMTP_USERNAME=${MAIL_USERNAME:-noreply@no-copy.ru} - - SMTP_PASSWORD=${SMTP_PASSWORD:-nocopy!nocopy!} - - RELAY_NETWORKS=172.16.0.0/12 - - POSTFIX_mynetworks=127.0.0.0/8 172.17.0.0/16 172.16.0.0/12 - - POSTFIX_smtpd_relay_restrictions=permit_mynetworks, permit_sasl_authenticated, reject_unauth_destination - - POSTFIX_smtpd_recipient_restrictions=permit_mynetworks, permit_sasl_authenticated, reject_unauth_destination - - DISABLE_SIGNING=true - ports: - - "25:25" - - "587:587" - networks: - - app-network - restart: unless-stopped - storage: image: alpine:latest container_name: file-storage + deploy: + resources: + limits: + memory: 128M + reservations: + memory: 64M networks: - app-network volumes: @@ -34,11 +17,44 @@ services: command: tail -f /dev/null restart: unless-stopped +# postfix: +# image: boky/postfix:latest +# container_name: postfix-production +# hostname: ${DOMAIN:-no-copy.ru} +# environment: +# - DOMAIN=${DOMAIN:-no-copy.ru} +# - ALLOWED_SENDER_DOMAINS=* +# - RELAYHOST= +# - DISABLE_SMTP_AUTH= +# - SMTP_USERNAME=${MAIL_USERNAME:-noreply@no-copy.ru} +# - SMTP_PASSWORD=${SMTP_PASSWORD:-nocopy!nocopy!} +# - RELAY_NETWORKS=172.16.0.0/12 +# - POSTFIX_mynetworks=127.0.0.0/8 172.17.0.0/16 172.16.0.0/12 +# - POSTFIX_smtpd_relay_restrictions=permit_mynetworks, permit_sasl_authenticated, reject_unauth_destination +# - POSTFIX_smtpd_recipient_restrictions=permit_mynetworks, permit_sasl_authenticated, reject_unauth_destination +# - DISABLE_SIGNING=true +# ports: +# - "25:25" +# - "587:587" +# networks: +# - app-network +# restart: unless-stopped + db: image: postgres:17.7 - container_name: postgres + restart: always + deploy: + resources: + limits: + cpus: '2.0' + memory: 2G + reservations: + cpus: '1.0' + memory: 1G environment: POSTGRES_DB: no_copy_ + # POSTGRES_USER: postgres + # POSTGRES_PASSWORD: postgres POSTGRES_USER: ${POSTGRES_USER} POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} POSTGRES_SHARED_BUFFERS: 512MB @@ -48,36 +64,49 @@ services: volumes: - pgdata:/var/lib/postgresql/data - ./init-scripts:/docker-entrypoint-initdb.d:ro + container_name: postgres networks: app-network: aliases: - database - restart: unless-stopped app: build: . container_name: app-backend + deploy: + resources: + limits: + cpus: '1.5' + memory: 1G + reservations: + cpus: '0.5' + memory: 512M environment: FILE_STORAGE_PATH: /data/uploads MAX_FILE_SIZE: 10737418240 + # FILE_CHUNK_SIZE: 1048576 FILE_CHUNK_SIZE: 1000000 POSTGRES_DB: no_copy_ + # POSTGRES_USER: postgres + # POSTGRES_PASSWORD: postgres POSTGRES_USER: ${POSTGRES_USER} POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} POSTGRES_PORT: 5432 POSTGRES_HOST: db STORAGE_SERVICE_URL: http://storage:8081 SPRING_PROFILES_ACTIVE: docker - MAIL_HOST: postfix - MAIL_PORT: 25 - MAIL_USERNAME: noreply@no-copy.ru - SMTP_PASSWORD: nocopy!nocopy! - SPRING_MAIL_PROPERTIES_MAIL_SMTP_STARTTLS_ENABLE: "false" - SPRING_MAIL_PROPERTIES_MAIL_SMTP_AUTH: "false" - SPRING_MAIL_PROPERTIES_MAIL_DEBUG: "true" + YANDEX_API_KEY: AQVNyaVaUmgUb1GMCtf5zSEqFxy0woXrcMOOB43q + YANDEX_FOLDER_ID: b1gokpdbm6qfpsou8pcd + YANDEX_SEARCH_URL: "https://searchapi.api.cloud.yandex.net/v2/image/search_by_image" +# MAIL_HOST: postfix +# MAIL_PORT: 25 +# MAIL_USERNAME: noreply@no-copy.ru +# SMTP_PASSWORD: nocopy!nocopy! +# SPRING_MAIL_PROPERTIES_MAIL_SMTP_STARTTLS_ENABLE: "false" +# SPRING_MAIL_PROPERTIES_MAIL_SMTP_AUTH: "false" +# SPRING_MAIL_PROPERTIES_MAIL_DEBUG: "true" depends_on: - db - - postfix ports: - "80:8080" networks: @@ -89,17 +118,163 @@ services: volumes: - uploads_data:/data/uploads:rw healthcheck: - test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER} -d no_copy_"] + test: [ "CMD-SHELL", "pg_isready -U ${POSTGRES_USER} -d no_copy_" ] interval: 10s retries: 5 - restart: unless-stopped + + grafana: + image: grafana/grafana:10.3.1 + container_name: grafana + deploy: + resources: + limits: + cpus: '0.5' + memory: 512M + reservations: + memory: 256M + ports: + - "3000:3000" + depends_on: + prometheus: + condition: service_healthy + loki: + condition: service_healthy + tempo: + condition: service_started + alloy: + condition: service_started + environment: + GF_AUTH_ANONYMOUS_ENABLED: "true" + GF_SECURITY_ADMIN_USER: admin + GF_SECURITY_ADMIN_PASSWORD: admin + GF_METRICS_ENABLED: "true" + GF_DATABASE_MAX_IDLE_CONN: "2" + GF_DATABASE_MAX_OPEN_CONN: "10" + volumes: + - ./infrastructure/grafana/provisioning:/etc/grafana/provisioning + - ./infrastructure/grafana/dashboards:/var/lib/grafana/dashboards + healthcheck: + test: [ "CMD", "wget", "--spider", "http://localhost:3000/api/health" ] + interval: 10s + timeout: 5s + retries: 10 + networks: + - app-network + + prometheus: + image: prom/prometheus:latest + container_name: prometheus + deploy: + resources: + limits: + cpus: '0.5' + memory: 1G + reservations: + memory: 512M + ports: + - "9090:9090" + volumes: + - ./infrastructure/prometheus/prometheus.yml:/etc/prometheus/prometheus.yml + - prometheus_data:/prometheus + command: + - '--config.file=/etc/prometheus/prometheus.yml' + - '--storage.tsdb.path=/prometheus' + - '--storage.tsdb.retention.time=15d' # Удерживать 15 дней + - '--web.enable-lifecycle' + healthcheck: + test: [ "CMD", "wget", "--spider", "http://localhost:9090/-/healthy" ] + interval: 10s + timeout: 5s + retries: 5 + networks: + - app-network + + loki: + image: grafana/loki:2.9.2 + container_name: loki + deploy: + resources: + limits: + cpus: '1.0' + memory: 2G + reservations: + memory: 1G + ports: + - "3100:3100" + volumes: + - ./infrastructure/loki/loki-config.yaml:/etc/loki/loki-config.yaml:ro + - loki_data:/loki + command: + - -config.file=/etc/loki/loki-config.yaml + healthcheck: + test: [ "CMD", "wget", "--spider", "-q", "http://localhost:3100/ready" ] + interval: 10s + timeout: 5s + retries: 5 + networks: + - app-network + + tempo: + image: grafana/tempo:2.4.1 + container_name: tempo + deploy: + resources: + limits: + cpus: '0.5' + memory: 512M + reservations: + memory: 256M + command: [ "-config.file=/etc/tempo/tempo.yaml" ] + volumes: + - ./infrastructure/tempo/tempo.yaml:/etc/tempo/tempo.yaml + - tempo_data:/var/tempo + ports: + - "3200:3200" + networks: + - app-network + + alloy: + image: grafana/alloy:latest + container_name: alloy + deploy: + resources: + limits: + cpus: '0.5' + memory: 256M + reservations: + memory: 128M + user: root + ports: + - "9080:9080" + - "4317:4317" + - "4318:4318" + volumes: + - ./infrastructure/alloy/config.alloy:/etc/alloy/config.alloy:ro + - /var/lib/docker/containers:/var/lib/docker/containers:ro + - /var/run/docker.sock:/var/run/docker.sock + - /var/log:/var/log:ro + environment: + GRAFANA_LOKI_URL: http://loki:3100/loki/api/v1/push + command: + - run + - --server.http.listen-addr=0.0.0.0:9080 + - --storage.path=/var/lib/alloy/data + - /etc/alloy/config.alloy + networks: + - app-network volumes: pgdata: + artifacts: + tempo_data: + loki_data: + loki_chunks: + loki_index: + loki_rules: uploads_data: - postfix-data: - + prometheus_data: +# postfix-data: networks: app-network: external: true - driver: bridge + driver: bridge \ No newline at end of file diff --git a/src/main/java/ru/soune/nocopy/configuration/HandlerConfig.java b/src/main/java/ru/soune/nocopy/configuration/HandlerConfig.java index 674b27c..6c435d6 100644 --- a/src/main/java/ru/soune/nocopy/configuration/HandlerConfig.java +++ b/src/main/java/ru/soune/nocopy/configuration/HandlerConfig.java @@ -17,7 +17,8 @@ public class HandlerConfig { FileUploadHandler upload, FileEntityHandler file, LogoutRequestHandler logoutHandler, - ImageFoundRequestHandler imageFoundRequestHandler + ImageFoundRequestHandler imageFoundRequestHandler, + VerifyRegisterUserHandler verifyRegisterUser ) { Map map = new HashMap<>(); map.put(20001, login); @@ -26,6 +27,7 @@ public class HandlerConfig { map.put(20005, file); map.put(20006, logoutHandler); map.put(20007, imageFoundRequestHandler); + map.put(20009, verifyRegisterUser); return map; } diff --git a/src/main/java/ru/soune/nocopy/controller/ApiController.java b/src/main/java/ru/soune/nocopy/controller/ApiController.java index 8cd26af..92557a1 100644 --- a/src/main/java/ru/soune/nocopy/controller/ApiController.java +++ b/src/main/java/ru/soune/nocopy/controller/ApiController.java @@ -14,7 +14,7 @@ import org.springframework.web.multipart.MultipartFile; 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.dto.register.RegAnswer; import ru.soune.nocopy.dto.file.ChunkUploadResponse; import ru.soune.nocopy.dto.file.CompleteUploadResponse; import ru.soune.nocopy.dto.file.FileEntityResponse; diff --git a/src/main/java/ru/soune/nocopy/controller/UserController.java b/src/main/java/ru/soune/nocopy/controller/UserController.java index 77df18a..cdb376c 100644 --- a/src/main/java/ru/soune/nocopy/controller/UserController.java +++ b/src/main/java/ru/soune/nocopy/controller/UserController.java @@ -3,9 +3,9 @@ package ru.soune.nocopy.controller; import lombok.RequiredArgsConstructor; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; -import ru.soune.nocopy.dto.ChangePasswordRequest; -import ru.soune.nocopy.dto.UserDTO; -import ru.soune.nocopy.dto.UserRequest; +import ru.soune.nocopy.dto.register.ChangePasswordRequest; +import ru.soune.nocopy.dto.user.UserDTO; +import ru.soune.nocopy.dto.user.UserRequest; import ru.soune.nocopy.entity.user.AuthToken; import ru.soune.nocopy.entity.user.User; import ru.soune.nocopy.exception.InvalidUserEmail; @@ -13,7 +13,7 @@ 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 ru.soune.nocopy.service.user.UserService; import java.util.List; import java.util.Optional; diff --git a/src/main/java/ru/soune/nocopy/dto/AuthResponse.java b/src/main/java/ru/soune/nocopy/dto/AuthResponse.java deleted file mode 100644 index 168e09a..0000000 --- a/src/main/java/ru/soune/nocopy/dto/AuthResponse.java +++ /dev/null @@ -1,10 +0,0 @@ -package ru.soune.nocopy.dto; - -import java.time.LocalDateTime; - -public record AuthResponse ( - boolean success, - String message, - String token, - LocalDateTime expiresAt -) {} diff --git a/src/main/java/ru/soune/nocopy/dto/UserContentDTO.java b/src/main/java/ru/soune/nocopy/dto/UserContentDTO.java deleted file mode 100644 index 934bfda..0000000 --- a/src/main/java/ru/soune/nocopy/dto/UserContentDTO.java +++ /dev/null @@ -1,14 +0,0 @@ -package ru.soune.nocopy.dto; - -import lombok.Data; - -@Data -public class UserContentDTO { - String fileName; - String originalFilename; - String fileType; - String fileExtension; - Long fileSize; - String filePath; - Integer protectionLevel; -} diff --git a/src/main/java/ru/soune/nocopy/dto/UserContentResponse.java b/src/main/java/ru/soune/nocopy/dto/UserContentResponse.java deleted file mode 100644 index 8c14615..0000000 --- a/src/main/java/ru/soune/nocopy/dto/UserContentResponse.java +++ /dev/null @@ -1,17 +0,0 @@ -package ru.soune.nocopy.dto; - -import ru.soune.nocopy.entity.ContentStatus; -import ru.soune.nocopy.entity.file.FileType; - -import java.time.LocalDateTime; - -public record UserContentResponse( - Long id, - String filename, - String originalFilename, - FileType fileType, - long fileSize, - String filePath, - ContentStatus status, - LocalDateTime uploadDate -) {} diff --git a/src/main/java/ru/soune/nocopy/dto/ChangePasswordRequest.java b/src/main/java/ru/soune/nocopy/dto/register/ChangePasswordRequest.java similarity index 86% rename from src/main/java/ru/soune/nocopy/dto/ChangePasswordRequest.java rename to src/main/java/ru/soune/nocopy/dto/register/ChangePasswordRequest.java index 204db58..2e33460 100644 --- a/src/main/java/ru/soune/nocopy/dto/ChangePasswordRequest.java +++ b/src/main/java/ru/soune/nocopy/dto/register/ChangePasswordRequest.java @@ -1,4 +1,4 @@ -package ru.soune.nocopy.dto; +package ru.soune.nocopy.dto.register; 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/register/LogOutAnswer.java similarity index 83% rename from src/main/java/ru/soune/nocopy/dto/LogOutAnswer.java rename to src/main/java/ru/soune/nocopy/dto/register/LogOutAnswer.java index 009f5f5..04478d5 100644 --- a/src/main/java/ru/soune/nocopy/dto/LogOutAnswer.java +++ b/src/main/java/ru/soune/nocopy/dto/register/LogOutAnswer.java @@ -1,4 +1,4 @@ -package ru.soune.nocopy.dto; +package ru.soune.nocopy.dto.register; import lombok.AllArgsConstructor; import lombok.Data; diff --git a/src/main/java/ru/soune/nocopy/dto/LoginAnswer.java b/src/main/java/ru/soune/nocopy/dto/register/LoginAnswer.java similarity index 88% rename from src/main/java/ru/soune/nocopy/dto/LoginAnswer.java rename to src/main/java/ru/soune/nocopy/dto/register/LoginAnswer.java index e791d8d..b244fd8 100644 --- a/src/main/java/ru/soune/nocopy/dto/LoginAnswer.java +++ b/src/main/java/ru/soune/nocopy/dto/register/LoginAnswer.java @@ -1,4 +1,4 @@ -package ru.soune.nocopy.dto; +package ru.soune.nocopy.dto.register; import lombok.AllArgsConstructor; import lombok.Data; diff --git a/src/main/java/ru/soune/nocopy/dto/LoginRequest.java b/src/main/java/ru/soune/nocopy/dto/register/LoginRequest.java similarity index 94% rename from src/main/java/ru/soune/nocopy/dto/LoginRequest.java rename to src/main/java/ru/soune/nocopy/dto/register/LoginRequest.java index b0548bc..6e99b07 100644 --- a/src/main/java/ru/soune/nocopy/dto/LoginRequest.java +++ b/src/main/java/ru/soune/nocopy/dto/register/LoginRequest.java @@ -1,4 +1,4 @@ -package ru.soune.nocopy.dto; +package ru.soune.nocopy.dto.register; import com.fasterxml.jackson.annotation.JsonFormat; import jakarta.validation.constraints.Email; diff --git a/src/main/java/ru/soune/nocopy/dto/LogoutRequest.java b/src/main/java/ru/soune/nocopy/dto/register/LogoutRequest.java similarity index 92% rename from src/main/java/ru/soune/nocopy/dto/LogoutRequest.java rename to src/main/java/ru/soune/nocopy/dto/register/LogoutRequest.java index 33a43e4..d0c30eb 100644 --- a/src/main/java/ru/soune/nocopy/dto/LogoutRequest.java +++ b/src/main/java/ru/soune/nocopy/dto/register/LogoutRequest.java @@ -1,4 +1,4 @@ -package ru.soune.nocopy.dto; +package ru.soune.nocopy.dto.register; import jakarta.validation.constraints.Email; import jakarta.validation.constraints.NotBlank; diff --git a/src/main/java/ru/soune/nocopy/dto/RegAnswer.java b/src/main/java/ru/soune/nocopy/dto/register/RegAnswer.java similarity index 88% rename from src/main/java/ru/soune/nocopy/dto/RegAnswer.java rename to src/main/java/ru/soune/nocopy/dto/register/RegAnswer.java index b51b4cc..5b265ad 100644 --- a/src/main/java/ru/soune/nocopy/dto/RegAnswer.java +++ b/src/main/java/ru/soune/nocopy/dto/register/RegAnswer.java @@ -1,4 +1,4 @@ -package ru.soune.nocopy.dto; +package ru.soune.nocopy.dto.register; import lombok.AllArgsConstructor; import lombok.Data; diff --git a/src/main/java/ru/soune/nocopy/dto/RegRequest.java b/src/main/java/ru/soune/nocopy/dto/register/RegRequest.java similarity index 95% rename from src/main/java/ru/soune/nocopy/dto/RegRequest.java rename to src/main/java/ru/soune/nocopy/dto/register/RegRequest.java index d7adfea..4ae695f 100644 --- a/src/main/java/ru/soune/nocopy/dto/RegRequest.java +++ b/src/main/java/ru/soune/nocopy/dto/register/RegRequest.java @@ -1,4 +1,4 @@ -package ru.soune.nocopy.dto; +package ru.soune.nocopy.dto.register; import com.fasterxml.jackson.annotation.JsonFormat; import jakarta.validation.constraints.*; diff --git a/src/main/java/ru/soune/nocopy/dto/register/VerifyUserRequest.java b/src/main/java/ru/soune/nocopy/dto/register/VerifyUserRequest.java new file mode 100644 index 0000000..a0e3472 --- /dev/null +++ b/src/main/java/ru/soune/nocopy/dto/register/VerifyUserRequest.java @@ -0,0 +1,17 @@ +package ru.soune.nocopy.dto.register; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@AllArgsConstructor +@NoArgsConstructor +public class VerifyUserRequest { + @JsonProperty("verify_token") + private String verifyToken; + + @JsonProperty("user_id") + private Long userId; +} diff --git a/src/main/java/ru/soune/nocopy/dto/UserContentRequest.java b/src/main/java/ru/soune/nocopy/dto/user/UserContentRequest.java similarity index 92% rename from src/main/java/ru/soune/nocopy/dto/UserContentRequest.java rename to src/main/java/ru/soune/nocopy/dto/user/UserContentRequest.java index bd28100..2de4791 100644 --- a/src/main/java/ru/soune/nocopy/dto/UserContentRequest.java +++ b/src/main/java/ru/soune/nocopy/dto/user/UserContentRequest.java @@ -1,4 +1,4 @@ -package ru.soune.nocopy.dto; +package ru.soune.nocopy.dto.user; import jakarta.validation.constraints.Email; import jakarta.validation.constraints.NotBlank; diff --git a/src/main/java/ru/soune/nocopy/dto/UserContentUpdateRequest.java b/src/main/java/ru/soune/nocopy/dto/user/UserContentUpdateRequest.java similarity index 93% rename from src/main/java/ru/soune/nocopy/dto/UserContentUpdateRequest.java rename to src/main/java/ru/soune/nocopy/dto/user/UserContentUpdateRequest.java index 7595b21..1b4f3dc 100644 --- a/src/main/java/ru/soune/nocopy/dto/UserContentUpdateRequest.java +++ b/src/main/java/ru/soune/nocopy/dto/user/UserContentUpdateRequest.java @@ -1,4 +1,4 @@ -package ru.soune.nocopy.dto; +package ru.soune.nocopy.dto.user; import jakarta.validation.constraints.Email; import jakarta.validation.constraints.NotBlank; diff --git a/src/main/java/ru/soune/nocopy/dto/UserDTO.java b/src/main/java/ru/soune/nocopy/dto/user/UserDTO.java similarity index 87% rename from src/main/java/ru/soune/nocopy/dto/UserDTO.java rename to src/main/java/ru/soune/nocopy/dto/user/UserDTO.java index e5a6b63..45f9cbe 100644 --- a/src/main/java/ru/soune/nocopy/dto/UserDTO.java +++ b/src/main/java/ru/soune/nocopy/dto/user/UserDTO.java @@ -1,11 +1,11 @@ -package ru.soune.nocopy.dto; +package ru.soune.nocopy.dto.user; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; import ru.soune.nocopy.entity.user.GenderType; -import ru.soune.nocopy.entity.SubscriptionType; +import ru.soune.nocopy.entity.user.SubscriptionType; import java.time.LocalDate; import java.time.LocalDateTime; diff --git a/src/main/java/ru/soune/nocopy/dto/UserRequest.java b/src/main/java/ru/soune/nocopy/dto/user/UserRequest.java similarity index 95% rename from src/main/java/ru/soune/nocopy/dto/UserRequest.java rename to src/main/java/ru/soune/nocopy/dto/user/UserRequest.java index ca89d88..9a5e48e 100644 --- a/src/main/java/ru/soune/nocopy/dto/UserRequest.java +++ b/src/main/java/ru/soune/nocopy/dto/user/UserRequest.java @@ -1,4 +1,4 @@ -package ru.soune.nocopy.dto; +package ru.soune.nocopy.dto.user; import com.fasterxml.jackson.annotation.JsonFormat; import jakarta.validation.constraints.Email; diff --git a/src/main/java/ru/soune/nocopy/entity/ContentStatus.java b/src/main/java/ru/soune/nocopy/entity/file/ContentStatus.java similarity index 88% rename from src/main/java/ru/soune/nocopy/entity/ContentStatus.java rename to src/main/java/ru/soune/nocopy/entity/file/ContentStatus.java index c2dfa41..2bb47f6 100644 --- a/src/main/java/ru/soune/nocopy/entity/ContentStatus.java +++ b/src/main/java/ru/soune/nocopy/entity/file/ContentStatus.java @@ -1,4 +1,4 @@ -package ru.soune.nocopy.entity; +package ru.soune.nocopy.entity.file; import lombok.Getter; diff --git a/src/main/java/ru/soune/nocopy/entity/ImageProtection.java b/src/main/java/ru/soune/nocopy/entity/file/ImageProtection.java similarity index 97% rename from src/main/java/ru/soune/nocopy/entity/ImageProtection.java rename to src/main/java/ru/soune/nocopy/entity/file/ImageProtection.java index 92cdedc..52d7c8c 100644 --- a/src/main/java/ru/soune/nocopy/entity/ImageProtection.java +++ b/src/main/java/ru/soune/nocopy/entity/file/ImageProtection.java @@ -1,4 +1,4 @@ -package ru.soune.nocopy.entity; +package ru.soune.nocopy.entity.file; import jakarta.persistence.*; import lombok.*; diff --git a/src/main/java/ru/soune/nocopy/entity/Violation.java b/src/main/java/ru/soune/nocopy/entity/file/Violation.java similarity index 97% rename from src/main/java/ru/soune/nocopy/entity/Violation.java rename to src/main/java/ru/soune/nocopy/entity/file/Violation.java index b8a7a1a..c5317bc 100644 --- a/src/main/java/ru/soune/nocopy/entity/Violation.java +++ b/src/main/java/ru/soune/nocopy/entity/file/Violation.java @@ -1,4 +1,4 @@ -package ru.soune.nocopy.entity; +package ru.soune.nocopy.entity.file; import jakarta.persistence.*; import lombok.*; diff --git a/src/main/java/ru/soune/nocopy/entity/user/EmailVerificationToken.java b/src/main/java/ru/soune/nocopy/entity/user/EmailVerificationToken.java index 7b009e1..1b02bcf 100644 --- a/src/main/java/ru/soune/nocopy/entity/user/EmailVerificationToken.java +++ b/src/main/java/ru/soune/nocopy/entity/user/EmailVerificationToken.java @@ -24,7 +24,7 @@ public class EmailVerificationToken { private String token; @Column(name = "expires_at", nullable = false) - private LocalDateTime expiresAt; + private LocalDateTime expiresAt = LocalDateTime.now().plusMinutes(15); @Column(name = "created_at", nullable = false) private LocalDateTime createdAt; diff --git a/src/main/java/ru/soune/nocopy/entity/SubscriptionType.java b/src/main/java/ru/soune/nocopy/entity/user/SubscriptionType.java similarity index 74% rename from src/main/java/ru/soune/nocopy/entity/SubscriptionType.java rename to src/main/java/ru/soune/nocopy/entity/user/SubscriptionType.java index 952722e..2648e98 100644 --- a/src/main/java/ru/soune/nocopy/entity/SubscriptionType.java +++ b/src/main/java/ru/soune/nocopy/entity/user/SubscriptionType.java @@ -1,4 +1,4 @@ -package ru.soune.nocopy.entity; +package ru.soune.nocopy.entity.user; import lombok.Getter; diff --git a/src/main/java/ru/soune/nocopy/entity/user/User.java b/src/main/java/ru/soune/nocopy/entity/user/User.java index 5a146fe..0aa4990 100644 --- a/src/main/java/ru/soune/nocopy/entity/user/User.java +++ b/src/main/java/ru/soune/nocopy/entity/user/User.java @@ -6,9 +6,8 @@ import jakarta.validation.constraints.Size; import lombok.*; import org.springframework.data.annotation.CreatedDate; import org.springframework.data.jpa.domain.support.AuditingEntityListener; -import ru.soune.nocopy.entity.ImageProtection; -import ru.soune.nocopy.entity.SubscriptionType; -import ru.soune.nocopy.entity.Violation; +import ru.soune.nocopy.entity.file.ImageProtection; +import ru.soune.nocopy.entity.file.Violation; import java.time.LocalDate; import java.time.LocalDateTime; diff --git a/src/main/java/ru/soune/nocopy/entity/user/UserContent.java b/src/main/java/ru/soune/nocopy/entity/user/UserContent.java index 0472791..4dcf724 100644 --- a/src/main/java/ru/soune/nocopy/entity/user/UserContent.java +++ b/src/main/java/ru/soune/nocopy/entity/user/UserContent.java @@ -4,7 +4,7 @@ import jakarta.persistence.*; import lombok.*; import org.springframework.data.annotation.CreatedDate; import org.springframework.data.jpa.domain.support.AuditingEntityListener; -import ru.soune.nocopy.entity.ContentStatus; +import ru.soune.nocopy.entity.file.ContentStatus; import ru.soune.nocopy.entity.file.FileType; import java.time.LocalDateTime; diff --git a/src/main/java/ru/soune/nocopy/handler/ImageFoundRequestHandler.java b/src/main/java/ru/soune/nocopy/handler/ImageFoundRequestHandler.java index 3d13d4a..13e005e 100644 --- a/src/main/java/ru/soune/nocopy/handler/ImageFoundRequestHandler.java +++ b/src/main/java/ru/soune/nocopy/handler/ImageFoundRequestHandler.java @@ -3,14 +3,13 @@ package ru.soune.nocopy.handler; import com.fasterxml.jackson.databind.ObjectMapper; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import ru.soune.nocopy.dto.BaseRequest; import ru.soune.nocopy.dto.BaseResponse; import ru.soune.nocopy.dto.MessageCode; import ru.soune.nocopy.dto.file.ImageSearchRequest; import ru.soune.nocopy.dto.file.YandexSearchResponse; -import ru.soune.nocopy.service.YandexSearchService; +import ru.soune.nocopy.service.search.YandexSearchService; @Slf4j @Component diff --git a/src/main/java/ru/soune/nocopy/handler/LoginRequestHandler.java b/src/main/java/ru/soune/nocopy/handler/LoginRequestHandler.java index 8cc115a..5c023ce 100644 --- a/src/main/java/ru/soune/nocopy/handler/LoginRequestHandler.java +++ b/src/main/java/ru/soune/nocopy/handler/LoginRequestHandler.java @@ -4,10 +4,12 @@ import com.fasterxml.jackson.databind.ObjectMapper; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Component; import ru.soune.nocopy.dto.*; +import ru.soune.nocopy.dto.register.LoginAnswer; +import ru.soune.nocopy.dto.register.LoginRequest; import ru.soune.nocopy.entity.user.AuthToken; import ru.soune.nocopy.exception.NotValidFieldException; import ru.soune.nocopy.repository.UserRepository; -import ru.soune.nocopy.service.AuthService; +import ru.soune.nocopy.service.register.AuthService; import java.util.Arrays; import java.util.Map; diff --git a/src/main/java/ru/soune/nocopy/handler/LogoutRequestHandler.java b/src/main/java/ru/soune/nocopy/handler/LogoutRequestHandler.java index f4aa19f..4fa77b1 100644 --- a/src/main/java/ru/soune/nocopy/handler/LogoutRequestHandler.java +++ b/src/main/java/ru/soune/nocopy/handler/LogoutRequestHandler.java @@ -4,12 +4,14 @@ import com.fasterxml.jackson.databind.ObjectMapper; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Component; import ru.soune.nocopy.dto.*; +import ru.soune.nocopy.dto.register.LogOutAnswer; +import ru.soune.nocopy.dto.register.LogoutRequest; import ru.soune.nocopy.entity.user.AuthToken; import ru.soune.nocopy.entity.user.User; import ru.soune.nocopy.exception.NotValidFieldException; import ru.soune.nocopy.repository.AuthTokenRepository; import ru.soune.nocopy.repository.UserRepository; -import ru.soune.nocopy.service.AuthService; +import ru.soune.nocopy.service.register.AuthService; import java.util.Objects; import java.util.Optional; diff --git a/src/main/java/ru/soune/nocopy/handler/RegRequestHandler.java b/src/main/java/ru/soune/nocopy/handler/RegRequestHandler.java index 847c19d..3e655e0 100644 --- a/src/main/java/ru/soune/nocopy/handler/RegRequestHandler.java +++ b/src/main/java/ru/soune/nocopy/handler/RegRequestHandler.java @@ -7,20 +7,19 @@ import org.springframework.stereotype.Component; import org.springframework.validation.BeanPropertyBindingResult; import org.springframework.validation.BindingResult; import ru.soune.nocopy.dto.*; +import ru.soune.nocopy.dto.register.RegAnswer; +import ru.soune.nocopy.dto.register.RegRequest; import ru.soune.nocopy.entity.user.AuthToken; import ru.soune.nocopy.entity.user.EmailVerificationToken; import ru.soune.nocopy.exception.NotValidFieldException; import ru.soune.nocopy.exception.ValidationException; import ru.soune.nocopy.handler.validator.RegRequestValidator; -import ru.soune.nocopy.repository.EmailVerificationTokenRepository; import ru.soune.nocopy.repository.UserRepository; -import ru.soune.nocopy.service.AuthService; -import ru.soune.nocopy.service.EmailService; +import ru.soune.nocopy.service.register.AuthService; +import ru.soune.nocopy.service.mail.EmailService; -import java.time.LocalDateTime; import java.util.Arrays; import java.util.Map; -import java.util.UUID; @Slf4j @Component @@ -36,8 +35,6 @@ public class RegRequestHandler implements RequestHandler { private final EmailService emailService; - private final EmailVerificationTokenRepository emailVerificationTokenRepository; - @Override public BaseResponse handle(BaseRequest request) throws ValidationException { RegRequest regRequest = objectMapper.convertValue(request.getMessageBody(), RegRequest.class); diff --git a/src/main/java/ru/soune/nocopy/handler/VerifyRegisterUserHandler.java b/src/main/java/ru/soune/nocopy/handler/VerifyRegisterUserHandler.java new file mode 100644 index 0000000..b6163b7 --- /dev/null +++ b/src/main/java/ru/soune/nocopy/handler/VerifyRegisterUserHandler.java @@ -0,0 +1,68 @@ +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 ru.soune.nocopy.dto.BaseRequest; +import ru.soune.nocopy.dto.BaseResponse; +import ru.soune.nocopy.dto.MessageCode; +import ru.soune.nocopy.dto.register.RegAnswer; +import ru.soune.nocopy.dto.register.VerifyUserRequest; +import ru.soune.nocopy.entity.user.AuthToken; +import ru.soune.nocopy.entity.user.EmailVerificationToken; +import ru.soune.nocopy.exception.NotValidFieldException; +import ru.soune.nocopy.exception.TokenNotFoundException; +import ru.soune.nocopy.repository.AuthTokenRepository; +import ru.soune.nocopy.repository.EmailVerificationTokenRepository; +import ru.soune.nocopy.service.user.UserService; + +import java.util.Map; +import java.util.Optional; + +@Component +@Slf4j +@RequiredArgsConstructor +public class VerifyRegisterUserHandler implements RequestHandler{ + + private final ObjectMapper objectMapper; + + private final EmailVerificationTokenRepository emailVerificationTokenRepository; + + private final UserService userService; + + private final AuthTokenRepository authTokenRepository; + + @Override + public BaseResponse handle(BaseRequest request) { + VerifyUserRequest verifyUserRequest = objectMapper.convertValue(request.getMessageBody(), + VerifyUserRequest.class); + + String verifyToken = verifyUserRequest.getVerifyToken(); + Long userId = verifyUserRequest.getUserId(); + + EmailVerificationToken emailVerificationToken = + emailVerificationTokenRepository.findByUserIdAndToken(userId, verifyToken); + + if (emailVerificationToken == null) { + throw new NotValidFieldException("Token was incorrected:" + verifyToken, + new BaseResponse(request.getMsgId(), MessageCode.INVALID_TOKEN.getCode(), + MessageCode.INVALID_TOKEN.getDescription(), Map.of( + "userId", userId, + "token", verifyToken))); + } + + userService.activateAndVerifyUser(userId); + emailVerificationTokenRepository.delete(emailVerificationToken); + + Optional byUserIdAndIsActive = authTokenRepository.findByUserIdAndIsActive(userId, true); + AuthToken authToken = byUserIdAndIsActive.orElseThrow(() -> + new TokenNotFoundException("Token not found with user id: " + userId)); + + RegAnswer regAnswer = new RegAnswer(); + regAnswer.setToken(authToken.getToken()); + + return new BaseResponse(request.getMsgId(), MessageCode.SUCCESS.getCode(), + MessageCode.SUCCESS.getDescription(), regAnswer); + } +} diff --git a/src/main/java/ru/soune/nocopy/handler/validator/RegRequestValidator.java b/src/main/java/ru/soune/nocopy/handler/validator/RegRequestValidator.java index e01df8e..71fb43b 100644 --- a/src/main/java/ru/soune/nocopy/handler/validator/RegRequestValidator.java +++ b/src/main/java/ru/soune/nocopy/handler/validator/RegRequestValidator.java @@ -1,14 +1,11 @@ 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 ru.soune.nocopy.dto.register.RegRequest; -import java.net.InetAddress; -import java.net.UnknownHostException; import java.util.*; @Component diff --git a/src/main/java/ru/soune/nocopy/mapper/UserContentMapper.java b/src/main/java/ru/soune/nocopy/mapper/UserContentMapper.java index ed7c734..16e411a 100644 --- a/src/main/java/ru/soune/nocopy/mapper/UserContentMapper.java +++ b/src/main/java/ru/soune/nocopy/mapper/UserContentMapper.java @@ -4,7 +4,7 @@ import org.mapstruct.Mapper; import org.mapstruct.MappingTarget; import org.mapstruct.NullValuePropertyMappingStrategy; import org.mapstruct.factory.Mappers; -import ru.soune.nocopy.dto.UserContentUpdateRequest; +import ru.soune.nocopy.dto.user.UserContentUpdateRequest; import ru.soune.nocopy.entity.user.UserContent; @Mapper(componentModel = "spring", diff --git a/src/main/java/ru/soune/nocopy/mapper/UserMapper.java b/src/main/java/ru/soune/nocopy/mapper/UserMapper.java index a6c4de6..9d05f14 100644 --- a/src/main/java/ru/soune/nocopy/mapper/UserMapper.java +++ b/src/main/java/ru/soune/nocopy/mapper/UserMapper.java @@ -3,7 +3,7 @@ package ru.soune.nocopy.mapper; import org.mapstruct.Mapper; import org.mapstruct.NullValuePropertyMappingStrategy; import org.mapstruct.factory.Mappers; -import ru.soune.nocopy.dto.UserDTO; +import ru.soune.nocopy.dto.user.UserDTO; import ru.soune.nocopy.entity.user.User; @Mapper(componentModel = "spring", diff --git a/src/main/java/ru/soune/nocopy/repository/AuthTokenRepository.java b/src/main/java/ru/soune/nocopy/repository/AuthTokenRepository.java index b5b0d88..66995d1 100644 --- a/src/main/java/ru/soune/nocopy/repository/AuthTokenRepository.java +++ b/src/main/java/ru/soune/nocopy/repository/AuthTokenRepository.java @@ -11,4 +11,5 @@ import java.util.Optional; public interface AuthTokenRepository extends JpaRepository { Optional findByTokenAndExpiresAtAfter(String token, LocalDate expiresAtAfter); Optional findByToken(String token); + Optional findByUserIdAndIsActive(Long userId, boolean isActive); } diff --git a/src/main/java/ru/soune/nocopy/repository/EmailVerificationTokenRepository.java b/src/main/java/ru/soune/nocopy/repository/EmailVerificationTokenRepository.java index f67573e..34a3233 100644 --- a/src/main/java/ru/soune/nocopy/repository/EmailVerificationTokenRepository.java +++ b/src/main/java/ru/soune/nocopy/repository/EmailVerificationTokenRepository.java @@ -3,8 +3,12 @@ package ru.soune.nocopy.repository; import org.springframework.data.jpa.repository.JpaRepository; import ru.soune.nocopy.entity.user.EmailVerificationToken; +import java.time.LocalDateTime; +import java.util.List; import java.util.Optional; public interface EmailVerificationTokenRepository extends JpaRepository { Optional findByToken(String token); + EmailVerificationToken findByUserIdAndToken(Long userId, String token); + List findByExpiresAtBefore(LocalDateTime expiresAtBefore); } diff --git a/src/main/java/ru/soune/nocopy/service/EmailService.java b/src/main/java/ru/soune/nocopy/service/mail/EmailService.java similarity index 88% rename from src/main/java/ru/soune/nocopy/service/EmailService.java rename to src/main/java/ru/soune/nocopy/service/mail/EmailService.java index ed18525..cc3b1cb 100644 --- a/src/main/java/ru/soune/nocopy/service/EmailService.java +++ b/src/main/java/ru/soune/nocopy/service/mail/EmailService.java @@ -1,6 +1,5 @@ -package ru.soune.nocopy.service; +package ru.soune.nocopy.service.mail; -import jakarta.mail.MessagingException; import jakarta.mail.internet.MimeMessage; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -29,14 +28,23 @@ public class EmailService { private final EmailVerificationTokenRepository emailVerificationTokenRepository; + @Value("${app.email.verification.standart-subject}") + private String standartSubject; + + @Value("${app.email.verification.standart-address-from}") + private String standartAdressFrom; + + @Value("${app.email.verification.user}") + private String user; + public void sendVerificationEmail(User user, String code) { try { MimeMessage message = mailSender.createMimeMessage(); MimeMessageHelper helper = new MimeMessageHelper(message, true, "UTF-8"); - helper.setFrom("NO COPY "); + helper.setFrom(standartAdressFrom); helper.setTo(user.getEmail()); - helper.setSubject("NO COPY - Подтверждение email"); + helper.setSubject(standartSubject); String htmlContent = loadAndProcessTemplate(user.getFullName(), code); helper.setText(htmlContent, true); @@ -55,7 +63,6 @@ public class EmailService { EmailVerificationToken emailToken = new EmailVerificationToken(); emailToken.setUser(authToken.getUser()); emailToken.setToken(generateVerificationCode()); - emailToken.setExpiresAt(LocalDateTime.now().plusMinutes(15)); emailToken.setCreatedAt(LocalDateTime.now()); return emailVerificationTokenRepository.save(emailToken); @@ -71,7 +78,7 @@ public class EmailService { private String loadAndProcessTemplate(String username, String code) throws IOException { ClassPathResource resource = new ClassPathResource("templates/email-verification.html"); String template = new String(resource.getInputStream().readAllBytes(), StandardCharsets.UTF_8); - String safeUsername = escapeHtml(username != null ? username : "Пользователь"); + String safeUsername = escapeHtml(username != null ? username : user); String safeCode = escapeHtml(code); return template diff --git a/src/main/java/ru/soune/nocopy/service/AuthService.java b/src/main/java/ru/soune/nocopy/service/register/AuthService.java similarity index 94% rename from src/main/java/ru/soune/nocopy/service/AuthService.java rename to src/main/java/ru/soune/nocopy/service/register/AuthService.java index ad58219..d410236 100644 --- a/src/main/java/ru/soune/nocopy/service/AuthService.java +++ b/src/main/java/ru/soune/nocopy/service/register/AuthService.java @@ -1,4 +1,4 @@ -package ru.soune.nocopy.service; +package ru.soune.nocopy.service.register; import lombok.RequiredArgsConstructor; import org.springframework.context.MessageSource; @@ -6,6 +6,9 @@ import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import ru.soune.nocopy.dto.*; +import ru.soune.nocopy.dto.register.LoginAnswer; +import ru.soune.nocopy.dto.register.LoginRequest; +import ru.soune.nocopy.dto.register.RegRequest; import ru.soune.nocopy.entity.user.AuthToken; import ru.soune.nocopy.entity.user.User; import ru.soune.nocopy.exception.NotValidFieldException; diff --git a/src/main/java/ru/soune/nocopy/service/register/CleanUpVerifyTokens.java b/src/main/java/ru/soune/nocopy/service/register/CleanUpVerifyTokens.java new file mode 100644 index 0000000..455d8e8 --- /dev/null +++ b/src/main/java/ru/soune/nocopy/service/register/CleanUpVerifyTokens.java @@ -0,0 +1,31 @@ +package ru.soune.nocopy.service.register; + +import lombok.RequiredArgsConstructor; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import ru.soune.nocopy.entity.user.EmailVerificationToken; +import ru.soune.nocopy.repository.EmailVerificationTokenRepository; + +import java.time.LocalDateTime; +import java.util.List; + +@Service +@RequiredArgsConstructor +public class CleanUpVerifyTokens { + + private final EmailVerificationTokenRepository emailVerificationTokenRepository; + + @Transactional + @Scheduled(fixedDelay = 30000) + public void cleanupExpiredTokens() { + LocalDateTime now = LocalDateTime.now(); + + + List expiredTokens = emailVerificationTokenRepository.findByExpiresAtBefore(now); + + if (!expiredTokens.isEmpty()) { + emailVerificationTokenRepository.deleteAll(expiredTokens); + } + } +} diff --git a/src/main/java/ru/soune/nocopy/service/YandexSearchService.java b/src/main/java/ru/soune/nocopy/service/search/YandexSearchService.java similarity index 98% rename from src/main/java/ru/soune/nocopy/service/YandexSearchService.java rename to src/main/java/ru/soune/nocopy/service/search/YandexSearchService.java index d0f4710..d22bbc9 100644 --- a/src/main/java/ru/soune/nocopy/service/YandexSearchService.java +++ b/src/main/java/ru/soune/nocopy/service/search/YandexSearchService.java @@ -1,4 +1,4 @@ -package ru.soune.nocopy.service; +package ru.soune.nocopy.service.search; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; @@ -12,7 +12,6 @@ import ru.soune.nocopy.dto.BaseResponse; import ru.soune.nocopy.dto.MessageCode; import ru.soune.nocopy.dto.file.YandexSearchResponse; import ru.soune.nocopy.entity.file.FileEntity; -import ru.soune.nocopy.exception.FileEntityNotFoundException; import ru.soune.nocopy.exception.NotValidFieldException; import ru.soune.nocopy.repository.FileEntityRepository; diff --git a/src/main/java/ru/soune/nocopy/service/UserContentService.java b/src/main/java/ru/soune/nocopy/service/user/UserContentService.java similarity index 94% rename from src/main/java/ru/soune/nocopy/service/UserContentService.java rename to src/main/java/ru/soune/nocopy/service/user/UserContentService.java index 3d033e2..63510e8 100644 --- a/src/main/java/ru/soune/nocopy/service/UserContentService.java +++ b/src/main/java/ru/soune/nocopy/service/user/UserContentService.java @@ -1,10 +1,10 @@ -package ru.soune.nocopy.service; +package ru.soune.nocopy.service.user; import lombok.AllArgsConstructor; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import ru.soune.nocopy.dto.UserContentRequest; -import ru.soune.nocopy.dto.UserContentUpdateRequest; +import ru.soune.nocopy.dto.user.UserContentRequest; +import ru.soune.nocopy.dto.user.UserContentUpdateRequest; import ru.soune.nocopy.entity.file.FileType; import ru.soune.nocopy.entity.user.User; import ru.soune.nocopy.entity.user.UserContent; diff --git a/src/main/java/ru/soune/nocopy/service/UserService.java b/src/main/java/ru/soune/nocopy/service/user/UserService.java similarity index 83% rename from src/main/java/ru/soune/nocopy/service/UserService.java rename to src/main/java/ru/soune/nocopy/service/user/UserService.java index c590bb9..56c6341 100644 --- a/src/main/java/ru/soune/nocopy/service/UserService.java +++ b/src/main/java/ru/soune/nocopy/service/user/UserService.java @@ -1,18 +1,20 @@ -package ru.soune.nocopy.service; +package ru.soune.nocopy.service.user; import lombok.AllArgsConstructor; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import ru.soune.nocopy.dto.ChangePasswordRequest; -import ru.soune.nocopy.dto.UserDTO; -import ru.soune.nocopy.dto.UserRequest; +import ru.soune.nocopy.dto.register.ChangePasswordRequest; +import ru.soune.nocopy.dto.user.UserDTO; +import ru.soune.nocopy.dto.user.UserRequest; import ru.soune.nocopy.entity.user.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; +import java.util.Optional; + @Service @AllArgsConstructor public class UserService { @@ -44,6 +46,16 @@ public class UserService { return mapToDTO(updatedUser); } + @Transactional + public void activateAndVerifyUser(long userId) { + Optional users = userRepository.findById(userId); + User user = users.orElseThrow(() -> new UserNotFoundException("User not found with id: " + userId)); + user.setIsActive(true); + user.setEmailVerified(true); + + userRepository.save(user); + } + private void updateUserFromRequest(User user, UserRequest request) { if (request.getFullName() != null) { user.setFullName(request.getFullName()); diff --git a/src/main/resources/application.yaml b/src/main/resources/application.yaml index 985d913..b509055 100644 --- a/src/main/resources/application.yaml +++ b/src/main/resources/application.yaml @@ -1,13 +1,25 @@ spring: mail: - host: postfix - port: 25 - username: noreply@nocopy.com - password: nocopy!nocopy! + host: smtp.gmail.com + port: 587 + username: vlad.popovtsev@gmail.com + password: gocjwvrqrzlaatsr properties: - mail.smtp.auth: false - mail.smtp.starttls.enable: false - mail.debug: true + mail: + smtp: + auth: true + starttls: + enable: true + +# mail: +# host: postfix + # port: 25 + # username: noreply@nocopy.com + # password: nocopy!nocopy! + # properties: + # mail.smtp.auth: false + # mail.smtp.starttls.enable: false + # mail.debug: true datasource: url: jdbc:postgresql://${POSTGRES_HOST}:${POSTGRES_PORT}/${POSTGRES_DB} @@ -34,6 +46,8 @@ spring: file: storage: base-path: ${FILE_STORAGE_PATH:/data/uploads} + # chunk-size: ${FILE_CHUNK_SIZE:5242880} # 5MB +# chunk-size: ${FILE_CHUNK_SIZE:1048576} # 1MB chunk-size: ${FILE_CHUNK_SIZE:1000000} # 1MB max-file-size: ${MAX_FILE_SIZE:10737418240} # 10GB max-retry-attempts: ${MAX_RETRY_ATTEMPTS:3} @@ -65,3 +79,10 @@ yandex: api-key: ${YANDEX_API_KEY:AQVNyaVaUmgUb1GMCtf5zSEqFxy0woXrcMOOB43q} folder-id: ${YANDEX_FOLDER_ID:b1gokpdbm6qfpsou8pcd} search-url: ${YANDEX_SEARCH_URL:https://searchapi.api.cloud.yandex.net/v2/image/search_by_image} + +app: + email: + verification: + standart-subject: NO COPY - Подтверждение email адреса + standart-address-from: NO COPY + user: Пользователь \ No newline at end of file diff --git a/src/test/java/ru/soune/nocopy/service/AuthServiceTest.java b/src/test/java/ru/soune/nocopy/service/AuthServiceTest.java index 2a3a013..574ab25 100644 --- a/src/test/java/ru/soune/nocopy/service/AuthServiceTest.java +++ b/src/test/java/ru/soune/nocopy/service/AuthServiceTest.java @@ -8,13 +8,14 @@ import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.springframework.context.MessageSource; import org.springframework.security.crypto.password.PasswordEncoder; -import ru.soune.nocopy.dto.LoginRequest; +import ru.soune.nocopy.dto.register.LoginRequest; import ru.soune.nocopy.entity.user.AuthToken; import ru.soune.nocopy.entity.user.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 ru.soune.nocopy.service.register.AuthService; import java.util.Optional;