diff --git a/src/main/java/com/cadac/stone_inscription/admin/entity/ArchiveComment.java b/src/main/java/com/cadac/stone_inscription/admin/entity/ArchiveComment.java new file mode 100644 index 0000000..94ce833 --- /dev/null +++ b/src/main/java/com/cadac/stone_inscription/admin/entity/ArchiveComment.java @@ -0,0 +1,87 @@ +package com.cadac.stone_inscription.admin.entity; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; +import com.cadac.stone_inscription.entity.enums.PostStatus; +import com.cadac.stone_inscription.entity.model.Report; +import com.cadac.stone_inscription.moderation.model.ContentModeration; + +import lombok.*; +import org.bson.types.ObjectId; +import org.springframework.data.annotation.CreatedDate; +import org.springframework.data.annotation.Id; +import org.springframework.data.annotation.LastModifiedDate; +import org.springframework.data.mongodb.core.mapping.Document; +import org.springframework.data.mongodb.core.mapping.Field; + +import java.util.Date; + +/** + * Archive of rejected comments. + * A comment is moved here from postdescription when admin rejects it. + * Preserves the full original comment structure for audit/record purposes. + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +@Document(collection = "archive_comments") +public class ArchiveComment { + + @Id + @JsonProperty("id") + @JsonSerialize(using = ToStringSerializer.class) + private ObjectId id; + + @Field("postId") + @JsonProperty("postId") + @JsonSerialize(using = ToStringSerializer.class) + private ObjectId postId; + + @Field("userId") + @JsonProperty("userId") + @JsonSerialize(using = ToStringSerializer.class) + private ObjectId userId; + + @Field("username") + @JsonProperty("username") + private String username; + + @Field("userImageUrl") + @JsonProperty("userImageUrl") + private String userImageUrl; + + @Field("description") + @JsonProperty("description") + private String description; + + @Field("moderation") + @JsonProperty("moderation") + private ContentModeration moderation; + + @Field("upvote") + @JsonProperty("upvote") + @Builder.Default + private Integer upvote = 0; + + @CreatedDate + @Field("createdAt") + @JsonProperty("createdAt") + private Date createdAt; + + @LastModifiedDate + @Field("updatedAt") + @JsonProperty("updatedAt") + private Date updatedAt; + + @Field("status") + @JsonProperty("status") + @Builder.Default + private PostStatus status = PostStatus.REJECTED; + + @Field("report") + @JsonProperty("report") + @Builder.Default + private Report report = new Report(); +} diff --git a/src/main/java/com/cadac/stone_inscription/admin/entity/ArchivePost.java b/src/main/java/com/cadac/stone_inscription/admin/entity/ArchivePost.java new file mode 100644 index 0000000..9278439 --- /dev/null +++ b/src/main/java/com/cadac/stone_inscription/admin/entity/ArchivePost.java @@ -0,0 +1,172 @@ +package com.cadac.stone_inscription.admin.entity; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; +import com.cadac.stone_inscription.entity.enums.PostStatus; +import com.cadac.stone_inscription.entity.model.Report; +import com.cadac.stone_inscription.moderation.model.ContentModeration; + +import lombok.*; +import org.bson.types.ObjectId; +import org.springframework.data.annotation.CreatedDate; +import org.springframework.data.annotation.Id; +import org.springframework.data.annotation.LastModifiedDate; +import org.springframework.data.mongodb.core.mapping.Document; +import org.springframework.data.mongodb.core.mapping.Field; + +import java.util.Date; +import java.util.List; + +/** + * Archive of rejected posts. + * A post is moved here from inscriptionposts when admin rejects it. + * Preserves the full original post structure for audit/record purposes. + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +@Document(collection = "archive_posts") +public class ArchivePost { + + @Id + @JsonProperty("_id") + @JsonSerialize(using = ToStringSerializer.class) + private ObjectId id; + + @Field("user_id") + @JsonProperty("user_id") + @JsonSerialize(using = ToStringSerializer.class) + private ObjectId userId; + + @CreatedDate + @Field("createdAt") + @JsonProperty("createdAt") + private Date createdAt; + + @LastModifiedDate + @Field("updatedAt") + @JsonProperty("updatedAt") + private Date updatedAt; + + @Field("images") + @JsonProperty("images") + private Images images; + + @Field("description") + @JsonProperty("description") + private Description description; + + @Field("topic") + @JsonProperty("topic") + private String topic; + + @Field("script") + @JsonProperty("script") + private List script; + + @Field("type") + @JsonProperty("type") + private String type; + + @Field("status") + @JsonProperty("status") + @Builder.Default + private PostStatus status = PostStatus.REJECTED; + + @Field("report") + @JsonProperty("report") + @Builder.Default + private Report report = new Report(); + + // ---------- Nested Classes ---------- + + @Data + @Builder + @NoArgsConstructor + @AllArgsConstructor + public static class Images { + + @Field("thumbnailImage") + @JsonProperty("thumbnailImage") + private String thumbnailImage; + + @Field("image") + @JsonProperty("image") + private List image; + } + + @Data + @Builder + @NoArgsConstructor + @AllArgsConstructor + public static class Description { + + @Field("title") + @JsonProperty("title") + private String title; + + @Field("subject") + @JsonProperty("subject") + private String subject; + + @Field("description") + @JsonProperty("description") + private String description; + + @Field("scriptLanguage") + @JsonProperty("scriptLanguage") + private List scriptLanguage; + + @Field("language") + @JsonProperty("language") + private List language; + + @Field("englishTranslation") + @JsonProperty("englishTranslation") + private String englishTranslation; + + @Field("moderation") + @JsonProperty("moderation") + private ContentModeration moderation; + + @Field("upvote") + @JsonProperty("upvote") + @Builder.Default + private Integer upvote = 0; + + @Field("geolocation") + @JsonProperty("geolocation") + private GeoLocation geolocation; + + @CreatedDate + @Field("createdAt") + @JsonProperty("createdAt") + private Date createdAt; + + @LastModifiedDate + @Field("updatedAt") + @JsonProperty("updatedAt") + private Date updatedAt; + } + + @Data + @Builder + @NoArgsConstructor + @AllArgsConstructor + public static class GeoLocation { + + @Field("lon") + @JsonProperty("lon") + private String lon; + + @Field("lat") + @JsonProperty("lat") + private String lat; + + private String state; + private String city; + private String country; + } +} diff --git a/src/main/java/com/cadac/stone_inscription/admin/entity/BlacklistUser.java b/src/main/java/com/cadac/stone_inscription/admin/entity/BlacklistUser.java new file mode 100644 index 0000000..51fe200 --- /dev/null +++ b/src/main/java/com/cadac/stone_inscription/admin/entity/BlacklistUser.java @@ -0,0 +1,57 @@ +package com.cadac.stone_inscription.admin.entity; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; + +import lombok.*; +import org.bson.types.ObjectId; +import org.springframework.data.annotation.Id; +import org.springframework.data.mongodb.core.mapping.Document; +import org.springframework.data.mongodb.core.mapping.Field; + +/** + * Admin-facing registry of blacklisted users. + * A record is created/updated here when a user's reportCount hits the + * threshold. + * Allows admin to quickly query all blacklisted users without scanning + * users_profile. + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +@Document(collection = "blacklist_users") +public class BlacklistUser { + + @Id + @JsonProperty("_id") + @JsonSerialize(using = ToStringSerializer.class) + private ObjectId id; + + /** + * Reference to the user in users_profile collection. + */ + @Field("userId") + @JsonProperty("userId") + @JsonSerialize(using = ToStringSerializer.class) + private ObjectId userId; + + @Field("name") + @JsonProperty("name") + private String name; + + /** + * Total number of admin-validated reports against this user. + * Synced from User.reportCount at time of blacklisting. + */ + @Field("reportCount") + @JsonProperty("reportCount") + @Builder.Default + private Integer reportCount = 0; + + @Field("blackListed") + @JsonProperty("blackListed") + @Builder.Default + private Boolean blackListed = true; +} diff --git a/src/main/java/com/cadac/stone_inscription/entity/InscriptionPost.java b/src/main/java/com/cadac/stone_inscription/entity/InscriptionPost.java index 9cd70dd..38c33b0 100644 --- a/src/main/java/com/cadac/stone_inscription/entity/InscriptionPost.java +++ b/src/main/java/com/cadac/stone_inscription/entity/InscriptionPost.java @@ -4,6 +4,8 @@ import com.fasterxml.jackson.databind.annotation.JsonSerialize; import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; import com.cadac.stone_inscription.moderation.model.ContentModeration; +import com.cadac.stone_inscription.entity.enums.PostStatus; +import com.cadac.stone_inscription.entity.model.Report; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotEmpty; @@ -99,6 +101,26 @@ public class InscriptionPost { @Builder.Default private List userRating = new LinkedList<>(); + /** + * Admin-managed status of the post. + * Defaults to ACCEPTED. Set to UNDER_REVIEW when first report comes in. + * Set to REJECTED when admin rejects — post is then archived. + */ + @Field("status") + @JsonProperty("status") + @Builder.Default + private PostStatus status = PostStatus.ACCEPTED; + + /** + * Embedded report metadata. + * reporters list grows with each user report. + * count is incremented only when admin validates a report as genuine. + */ + @Field("report") + @JsonProperty("report") + @Builder.Default + private Report report = new Report(); + // ---------- Nested Classes ---------- @Data diff --git a/src/main/java/com/cadac/stone_inscription/entity/PublicPostDescription.java b/src/main/java/com/cadac/stone_inscription/entity/PublicPostDescription.java index 3587f28..e87883c 100644 --- a/src/main/java/com/cadac/stone_inscription/entity/PublicPostDescription.java +++ b/src/main/java/com/cadac/stone_inscription/entity/PublicPostDescription.java @@ -4,6 +4,8 @@ import com.fasterxml.jackson.databind.annotation.JsonSerialize; import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; import com.cadac.stone_inscription.moderation.model.ContentModeration; +import com.cadac.stone_inscription.entity.enums.PostStatus; +import com.cadac.stone_inscription.entity.model.Report; import lombok.*; import org.bson.types.ObjectId; @@ -76,6 +78,24 @@ public class PublicPostDescription { @JsonProperty("updatedAt") private Date updatedAt; + /** + * Admin-managed status of the comment. + * Defaults to ACCEPTED. Changes to UNDER_REVIEW on first report. + */ + @Field("status") + @JsonProperty("status") + @Builder.Default + private PostStatus status = PostStatus.ACCEPTED; + + /** + * Embedded report metadata for this comment. + * count incremented only when admin validates the report. + */ + @Field("report") + @JsonProperty("report") + @Builder.Default + private Report report = new Report(); + @Data @Builder @NoArgsConstructor diff --git a/src/main/java/com/cadac/stone_inscription/entity/User.java b/src/main/java/com/cadac/stone_inscription/entity/User.java index 1206b7d..4ba54e3 100644 --- a/src/main/java/com/cadac/stone_inscription/entity/User.java +++ b/src/main/java/com/cadac/stone_inscription/entity/User.java @@ -25,12 +25,12 @@ public class User { @Id @JsonProperty("_id") - @JsonSerialize(using = ToStringSerializer.class) -private ObjectId id; + @JsonSerialize(using = ToStringSerializer.class) + private ObjectId id; @Field("authid") @JsonProperty("authId") - @JsonSerialize(using = ToStringSerializer.class) + @JsonSerialize(using = ToStringSerializer.class) private ObjectId authId; @Field("name") @@ -54,18 +54,18 @@ public class User { @JsonProperty("profileImage") private String profileImage; - @Field("coverImage") - @JsonProperty("coverImage") - private String coverImage; - - @Field("bio") - @JsonProperty("bio") - private String bio; - - @Field("imagesUploaded") - @JsonProperty("imagesUploaded") - @Builder.Default - private Integer imagesUploaded = 0; + @Field("coverImage") + @JsonProperty("coverImage") + private String coverImage; + + @Field("bio") + @JsonProperty("bio") + private String bio; + + @Field("imagesUploaded") + @JsonProperty("imagesUploaded") + @Builder.Default + private Integer imagesUploaded = 0; @Field("upvotesReceived") @JsonProperty("upvotesReceived") @@ -96,4 +96,21 @@ public class User { @Field("active") @JsonProperty("active") private Boolean active; + + /** + * Incremented by admin when a report against this user's content is validated. + * When this reaches the configured threshold, the user is blacklisted. + */ + @Field("reportCount") + @JsonProperty("reportCount") + @Builder.Default + private Integer reportCount = 0; + + /** + * Set to true when reportCount >= blacklist threshold (configured via env). + */ + @Field("blackListed") + @JsonProperty("blackListed") + @Builder.Default + private Boolean blackListed = false; } diff --git a/src/main/java/com/cadac/stone_inscription/entity/enums/PostStatus.java b/src/main/java/com/cadac/stone_inscription/entity/enums/PostStatus.java new file mode 100644 index 0000000..403cb02 --- /dev/null +++ b/src/main/java/com/cadac/stone_inscription/entity/enums/PostStatus.java @@ -0,0 +1,7 @@ +package com.cadac.stone_inscription.entity.enums; + +public enum PostStatus { + ACCEPTED, + REJECTED, + UNDER_REVIEW +} diff --git a/src/main/java/com/cadac/stone_inscription/entity/model/Report.java b/src/main/java/com/cadac/stone_inscription/entity/model/Report.java new file mode 100644 index 0000000..290ebf6 --- /dev/null +++ b/src/main/java/com/cadac/stone_inscription/entity/model/Report.java @@ -0,0 +1,36 @@ +package com.cadac.stone_inscription.entity.model; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.springframework.data.mongodb.core.mapping.Field; + +import java.util.LinkedList; +import java.util.List; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class Report { + + /** + * Incremented only when admin validates a report as spam/abuse/violation. + * Not incremented on every report submission. + */ + @Field("count") + @JsonProperty("count") + @Builder.Default + private Integer count = 0; + + /** + * List of all reporters with their reason. + * Admin reviews this list to decide on validation. + */ + @Field("reporters") + @JsonProperty("reporters") + @Builder.Default + private List reporters = new LinkedList<>(); +} diff --git a/src/main/java/com/cadac/stone_inscription/entity/model/ReportEntry.java b/src/main/java/com/cadac/stone_inscription/entity/model/ReportEntry.java new file mode 100644 index 0000000..c30d042 --- /dev/null +++ b/src/main/java/com/cadac/stone_inscription/entity/model/ReportEntry.java @@ -0,0 +1,27 @@ +package com.cadac.stone_inscription.entity.model; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.springframework.data.mongodb.core.mapping.Field; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class ReportEntry { + + @Field("userId") + @JsonProperty("userId") + private String userId; + + @Field("name") + @JsonProperty("name") + private String name; + + @Field("reason") + @JsonProperty("reason") + private String reason; +}