From c2d44b3428fe100eae258089abfd4a659c883a0d Mon Sep 17 00:00:00 2001 From: vladp Date: Wed, 26 Nov 2025 15:49:51 +0700 Subject: [PATCH] NCP-3 Update entity like helper.php --- .../configuration/SubscriptionConfig.java | 35 ++++++++++++ .../ru/soune/no_copy/entity/AuthToken.java | 31 ++++++---- .../ru/soune/no_copy/entity/BaseEntity.java | 29 ++++++++++ .../soune/no_copy/entity/ContentStatus.java | 17 +++++- .../ru/soune/no_copy/entity/FileType.java | 18 +++++- .../soune/no_copy/entity/ImageProtection.java | 49 ++++++++++++++++ .../no_copy/entity/SubscriptionType.java | 21 +++++++ .../java/ru/soune/no_copy/entity/User.java | 57 +++++++++++++++---- .../ru/soune/no_copy/entity/UserAction.java | 44 ++++++++++++++ .../ru/soune/no_copy/entity/UserContent.java | 45 ++++++++------- .../ru/soune/no_copy/entity/Violation.java | 56 ++++++++++++++++++ 11 files changed, 360 insertions(+), 42 deletions(-) create mode 100644 src/main/java/ru/soune/no_copy/configuration/SubscriptionConfig.java create mode 100644 src/main/java/ru/soune/no_copy/entity/BaseEntity.java create mode 100644 src/main/java/ru/soune/no_copy/entity/ImageProtection.java create mode 100644 src/main/java/ru/soune/no_copy/entity/SubscriptionType.java create mode 100644 src/main/java/ru/soune/no_copy/entity/UserAction.java create mode 100644 src/main/java/ru/soune/no_copy/entity/Violation.java diff --git a/src/main/java/ru/soune/no_copy/configuration/SubscriptionConfig.java b/src/main/java/ru/soune/no_copy/configuration/SubscriptionConfig.java new file mode 100644 index 0000000..7eb41ec --- /dev/null +++ b/src/main/java/ru/soune/no_copy/configuration/SubscriptionConfig.java @@ -0,0 +1,35 @@ +package ru.soune.no_copy.configuration; + +import lombok.Getter; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; + +import java.util.Map; + +@Component +@ConfigurationProperties(prefix = "subscription") +@Getter +public class SubscriptionConfig { + + private final Map limits = Map.of( + SubscriptionType.START, new SubscriptionLimits(50, 5.0), + SubscriptionType.BASIC, new SubscriptionLimits(200, 20.0), + SubscriptionType.PRO, new SubscriptionLimits(1000, 100.0), + SubscriptionType.ENTERPRISE, new SubscriptionLimits(-1, 500.0) + ); + + @Getter + public static class SubscriptionLimits { + private final int monthlyFiles; + private final double storageGB; + + public SubscriptionLimits(int monthlyFiles, double storageGB) { + this.monthlyFiles = monthlyFiles; + this.storageGB = storageGB; + } + } + + public enum SubscriptionType { + START, BASIC, PRO, ENTERPRISE + } +} diff --git a/src/main/java/ru/soune/no_copy/entity/AuthToken.java b/src/main/java/ru/soune/no_copy/entity/AuthToken.java index ee78fe9..938d31c 100644 --- a/src/main/java/ru/soune/no_copy/entity/AuthToken.java +++ b/src/main/java/ru/soune/no_copy/entity/AuthToken.java @@ -1,37 +1,48 @@ package ru.soune.no_copy.entity; import jakarta.persistence.*; -import lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.Setter; +import lombok.*; import org.springframework.data.annotation.CreatedDate; import org.springframework.data.jpa.domain.support.AuditingEntityListener; import java.time.LocalDateTime; @Entity -@NoArgsConstructor +@Table(name = "auth_tokens") @Getter @Setter +@NoArgsConstructor +@AllArgsConstructor +@ToString @EntityListeners(AuditingEntityListener.class) -@Table(name = "auth_tokens") public class AuthToken { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) - private Long id; + private Long tokenId; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "user_id", nullable = false) + @ToString.Exclude + private User user; @Column(nullable = false, unique = true, length = 64) private String token; @Column(name = "expires_at", nullable = false) - private LocalDateTime expiresAt = LocalDateTime.now().plusDays(30); + private LocalDateTime expiresAt; @CreatedDate @Column(name = "created_at", updatable = false, nullable = false) private LocalDateTime createdAt; - @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "user_id", nullable = false) - private User user; + @Column(name = "last_used_at") + private LocalDateTime lastUsedAt; + + @Column(name = "is_active") + private Boolean isActive = true; + + public boolean isValid() { + return Boolean.TRUE.equals(isActive) && expiresAt.isAfter(LocalDateTime.now()); + } } diff --git a/src/main/java/ru/soune/no_copy/entity/BaseEntity.java b/src/main/java/ru/soune/no_copy/entity/BaseEntity.java new file mode 100644 index 0000000..b51c525 --- /dev/null +++ b/src/main/java/ru/soune/no_copy/entity/BaseEntity.java @@ -0,0 +1,29 @@ +package ru.soune.no_copy.entity; + +import jakarta.persistence.*; +import lombok.Getter; +import lombok.Setter; +import org.springframework.data.annotation.CreatedDate; +import org.springframework.data.annotation.LastModifiedDate; +import org.springframework.data.jpa.domain.support.AuditingEntityListener; + +import java.time.LocalDateTime; + +@MappedSuperclass +@EntityListeners(AuditingEntityListener.class) +@Getter +@Setter +public abstract class BaseEntity { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @CreatedDate + @Column(name = "created_at", updatable = false, nullable = false) + private LocalDateTime createdAt; + + @LastModifiedDate + @Column(name = "updated_at") + private LocalDateTime updatedAt; +} diff --git a/src/main/java/ru/soune/no_copy/entity/ContentStatus.java b/src/main/java/ru/soune/no_copy/entity/ContentStatus.java index 4009ee9..d97f66c 100644 --- a/src/main/java/ru/soune/no_copy/entity/ContentStatus.java +++ b/src/main/java/ru/soune/no_copy/entity/ContentStatus.java @@ -1,5 +1,20 @@ package ru.soune.no_copy.entity; +import lombok.Getter; + +@Getter public enum ContentStatus { - PROCESSING, COMPLETED, ERROR + PROCESSING("processing"), + COMPLETED("completed"), + ERROR("error"); + + private final String code; + + ContentStatus(String code) { + this.code = code; + } + + public String getCode() { + return code; + } } diff --git a/src/main/java/ru/soune/no_copy/entity/FileType.java b/src/main/java/ru/soune/no_copy/entity/FileType.java index b07bc9b..4e0406d 100644 --- a/src/main/java/ru/soune/no_copy/entity/FileType.java +++ b/src/main/java/ru/soune/no_copy/entity/FileType.java @@ -1,5 +1,21 @@ package ru.soune.no_copy.entity; +import lombok.Getter; + +@Getter public enum FileType { - PHOTO, DOCUMENT, AUDIO, VIDEO + PHOTO("photo"), + VIDEO("video"), + AUDIO("audio"), + DOCUMENT("document"); + + private final String code; + + FileType(String code) { + this.code = code; + } + + public String getCode() { + return code; + } } diff --git a/src/main/java/ru/soune/no_copy/entity/ImageProtection.java b/src/main/java/ru/soune/no_copy/entity/ImageProtection.java new file mode 100644 index 0000000..79a8c8d --- /dev/null +++ b/src/main/java/ru/soune/no_copy/entity/ImageProtection.java @@ -0,0 +1,49 @@ +package ru.soune.no_copy.entity; + +import jakarta.persistence.*; +import lombok.*; +import org.springframework.data.annotation.CreatedDate; +import org.springframework.data.jpa.domain.support.AuditingEntityListener; + +import java.time.LocalDateTime; + +@Entity +@Table(name = "image_protection") +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +@ToString +@EntityListeners(AuditingEntityListener.class) +public class ImageProtection { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long protectionId; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "user_id", nullable = false) + @ToString.Exclude + private User user; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "content_id", nullable = false) + @ToString.Exclude + private UserContent content; + + @Column(name = "protection_method", nullable = false, length = 50) + private String protectionMethod; + + @Column(name = "protection_level", nullable = false) + private Integer protectionLevel; + + @Column(name = "is_active", nullable = false) + private Boolean isActive = true; + + @CreatedDate + @Column(name = "applied_at", nullable = false, updatable = false) + private LocalDateTime appliedAt; + + @Column(name = "metadata", columnDefinition = "JSON") + private String metadata; +} diff --git a/src/main/java/ru/soune/no_copy/entity/SubscriptionType.java b/src/main/java/ru/soune/no_copy/entity/SubscriptionType.java new file mode 100644 index 0000000..510e8e9 --- /dev/null +++ b/src/main/java/ru/soune/no_copy/entity/SubscriptionType.java @@ -0,0 +1,21 @@ +package ru.soune.no_copy.entity; + +import lombok.Getter; + +@Getter +public enum SubscriptionType { + START("СТАРТ"), + BASIC("БАЗОВЫЙ"), + PRO("ПРО"), + ENTERPRISE("ЭНТЕРПРАЙЗ"); + + private final String displayName; + + SubscriptionType(String displayName) { + this.displayName = displayName; + } + + public String getDisplayName() { + return displayName; + } +} diff --git a/src/main/java/ru/soune/no_copy/entity/User.java b/src/main/java/ru/soune/no_copy/entity/User.java index 6301a33..d4595f5 100644 --- a/src/main/java/ru/soune/no_copy/entity/User.java +++ b/src/main/java/ru/soune/no_copy/entity/User.java @@ -12,13 +12,13 @@ import java.util.ArrayList; import java.util.List; @Entity -@AllArgsConstructor -@NoArgsConstructor -@ToString -@EqualsAndHashCode -@Getter @Setter -@EntityListeners(AuditingEntityListener.class) @Table(name = "users") +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +@ToString +@EntityListeners(AuditingEntityListener.class) public class User { @Id @@ -26,15 +26,15 @@ public class User { private Long userId; @Size(max = 64) - @Column(name = "firstName", nullable = false, length = 64) + @Column(name = "first_name", nullable = false, length = 64) private String firstName; @Size(max = 64) - @Column(name = "lastName", nullable = false, length = 64) + @Column(name = "last_name", nullable = false, length = 64) private String lastName; @Size(max = 64) - @Column(name = "secondName", length = 64) + @Column(name = "second_name", length = 64) private String secondName; @Size(max = 1024) @@ -45,14 +45,49 @@ public class User { @JsonIgnore private String password; - @OneToMany(mappedBy = "user", cascade = CascadeType.ALL, orphanRemoval = true) - private List tokens = new ArrayList<>(); + @Enumerated(EnumType.STRING) + @Column(name = "subscription_type", nullable = false, length = 20) + private SubscriptionType subscriptionType = SubscriptionType.START; @CreatedDate @Column(name = "created_at", updatable = false, nullable = false) private LocalDateTime createdAt; + @Column(name = "last_login_at") + private LocalDateTime lastLoginAt; + @Column(name = "is_active") private Boolean isActive = true; + @OneToMany(mappedBy = "user", cascade = CascadeType.ALL, orphanRemoval = true) + @JsonIgnore + @ToString.Exclude + private List tokens = new ArrayList<>(); + + @OneToMany(mappedBy = "user", cascade = CascadeType.ALL, orphanRemoval = true) + @JsonIgnore + @ToString.Exclude + private List userContents = new ArrayList<>(); + + @OneToMany(mappedBy = "user", cascade = CascadeType.ALL, orphanRemoval = true) + @JsonIgnore + @ToString.Exclude + private List userActions = new ArrayList<>(); + + @OneToMany(mappedBy = "user", cascade = CascadeType.ALL, orphanRemoval = true) + @JsonIgnore + @ToString.Exclude + private List violations = new ArrayList<>(); + + @OneToMany(mappedBy = "user", cascade = CascadeType.ALL, orphanRemoval = true) + @JsonIgnore + @ToString.Exclude + private List imageProtections = new ArrayList<>(); + + public String getFullName() { + if (secondName != null && !secondName.isBlank()) { + return String.format("%s %s %s", lastName, firstName, secondName); + } + return String.format("%s %s", lastName, firstName); + } } diff --git a/src/main/java/ru/soune/no_copy/entity/UserAction.java b/src/main/java/ru/soune/no_copy/entity/UserAction.java new file mode 100644 index 0000000..d9d22ef --- /dev/null +++ b/src/main/java/ru/soune/no_copy/entity/UserAction.java @@ -0,0 +1,44 @@ +package ru.soune.no_copy.entity; + +import jakarta.persistence.*; +import lombok.*; +import org.springframework.data.annotation.CreatedDate; +import org.springframework.data.jpa.domain.support.AuditingEntityListener; + +import java.time.LocalDateTime; + +@Entity +@Table(name = "user_actions") +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +@ToString +@EntityListeners(AuditingEntityListener.class) +public class UserAction { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long actionId; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "user_id", nullable = false) + @ToString.Exclude + private User user; + + @Column(name = "action", nullable = false, length = 100) + private String action; + + @Column(name = "details", columnDefinition = "TEXT") + private String details; + + @Column(name = "ip_address", length = 45) + private String ipAddress; + + @Column(name = "user_agent", columnDefinition = "TEXT") + private String userAgent; + + @CreatedDate + @Column(name = "created_at", nullable = false, updatable = false) + private LocalDateTime createdAt; +} diff --git a/src/main/java/ru/soune/no_copy/entity/UserContent.java b/src/main/java/ru/soune/no_copy/entity/UserContent.java index eda224a..22ee0b0 100644 --- a/src/main/java/ru/soune/no_copy/entity/UserContent.java +++ b/src/main/java/ru/soune/no_copy/entity/UserContent.java @@ -3,52 +3,51 @@ package ru.soune.no_copy.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; import java.time.LocalDateTime; @Entity +@Table(name = "user_content") +@Getter +@Setter @NoArgsConstructor @AllArgsConstructor -@Builder -@Getter @Setter -@Table(name = "user_content", -indexes = { - @Index(name = "idx_user_id", columnList = "user_id"), - @Index(name = "idx_file_type", columnList = "file_type"), - @Index(name = "idx_upload_date", columnList = "upload_date") -}) +@ToString +@EntityListeners(AuditingEntityListener.class) public class UserContent { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) - private Long id; + private Long contentId; @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "user_id", nullable = false, - foreignKey = @ForeignKey(name = "fk_usercontent_user")) + @JoinColumn(name = "user_id", nullable = false) + @ToString.Exclude private User user; - @Column(nullable = false) + @Column(name = "filename", nullable = false, length = 255) private String filename; - @Column(name = "original_filename", nullable = false) + @Column(name = "original_filename", nullable = false, length = 255) private String originalFilename; @Enumerated(EnumType.STRING) - @Column(name = "file_type", nullable = false, length = 16) + @Column(name = "file_type", nullable = false, length = 20) private FileType fileType; - @Column(name = "file_extension", length = 16) + @Column(name = "file_extension", nullable = false, length = 10) private String fileExtension; @Column(name = "file_size", nullable = false) private Long fileSize; - @Column(name = "file_path", columnDefinition = "TEXT", nullable = false) + @Column(name = "file_path", nullable = false, columnDefinition = "TEXT") private String filePath; @Column(name = "protection_level") - private Integer protectionLevel; + private Integer protectionLevel = 0; @Column(name = "geometric_resistant") private Boolean geometricResistant = false; @@ -63,11 +62,19 @@ public class UserContent { private String watermarkId; @Enumerated(EnumType.STRING) - @Column(length = 16) + @Column(name = "status", nullable = false, length = 20) private ContentStatus status = ContentStatus.PROCESSING; - @CreationTimestamp + @CreatedDate @Column(name = "upload_date", nullable = false, updatable = false) private LocalDateTime uploadDate; + + public Double getFileSizeInGB() { + return fileSize != null ? fileSize / (1024.0 * 1024.0 * 1024.0) : 0.0; + } + + public Boolean isProtected() { + return protectionLevel != null && protectionLevel > 0; + } } diff --git a/src/main/java/ru/soune/no_copy/entity/Violation.java b/src/main/java/ru/soune/no_copy/entity/Violation.java new file mode 100644 index 0000000..6e1768c --- /dev/null +++ b/src/main/java/ru/soune/no_copy/entity/Violation.java @@ -0,0 +1,56 @@ +package ru.soune.no_copy.entity; + +import jakarta.persistence.*; +import lombok.*; +import org.springframework.data.annotation.CreatedDate; +import org.springframework.data.jpa.domain.support.AuditingEntityListener; + +import java.time.LocalDateTime; + +@Entity +@Table(name = "violations") +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +@ToString +@EntityListeners(AuditingEntityListener.class) +public class Violation { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long violationId; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "user_id", nullable = false) + @ToString.Exclude + private User user; + + @Column(name = "violation_type", nullable = false, length = 50) + private String violationType; + + @Column(name = "description", columnDefinition = "TEXT") + private String description; + + @Column(name = "content_id") + private Long contentId; + + @Column(name = "status", nullable = false, length = 20) + private String status = "new"; + + @Column(name = "severity", length = 20) + private String severity; + + @Column(name = "resolved_at") + private LocalDateTime resolvedAt; + + @Column(name = "resolved_by") + private Long resolvedBy; + + @Column(name = "resolution_notes", columnDefinition = "TEXT") + private String resolutionNotes; + + @CreatedDate + @Column(name = "created_at", nullable = false, updatable = false) + private LocalDateTime createdAt; +}