package entity import ( "errors" "time" "backend/pkg/post/domain/post" "github.com/gocql/gocql" ) // Post represents a post entity in the system. // It contains the main content and metadata for user posts. type Post struct { ID gocql.UUID `db:"id" partition_key:"true"` // Post unique identifier AuthorUID string `db:"author_uid"` // Author user UID Title string `db:"title"` // Post title Content string `db:"content"` // Post content Type post.Type `db:"type"` // Post type (text, image, video, etc.) Status post.Status `db:"status"` // Post status (draft, published, etc.) CategoryID *gocql.UUID `db:"category_id,omitempty"` // Category ID (optional) Tags []string `db:"tags,omitempty"` // Post tags Images []string `db:"images,omitempty"` // Image URLs (optional) VideoURL *string `db:"video_url,omitempty"` // Video URL (optional) LinkURL *string `db:"link_url,omitempty"` // Link URL (optional) LikeCount int64 `db:"like_count"` // Number of likes CommentCount int64 `db:"comment_count"` // Number of comments ViewCount int64 `db:"view_count"` // Number of views IsPinned bool `db:"is_pinned"` // Whether the post is pinned PinnedAt *int64 `db:"pinned_at,omitempty"` // Pinned timestamp (optional) PublishedAt *int64 `db:"published_at,omitempty"` // Published timestamp (optional) CreatedAt int64 `db:"created_at"` // Creation timestamp UpdatedAt int64 `db:"updated_at"` // Last update timestamp } // TableName returns the Cassandra table name for Post entities. func (p *Post) TableName() string { return "posts" } // Validate validates the Post entity func (p *Post) Validate() error { if p.AuthorUID == "" { return errors.New("author_uid is required") } if len(p.Title) < 1 || len(p.Title) > 200 { return errors.New("title length must be between 1 and 200 characters") } if len(p.Content) < 1 || len(p.Content) > 10000 { return errors.New("content length must be between 1 and 10000 characters") } if !p.Type.IsValid() { return errors.New("invalid post type") } if !p.Status.IsValid() { return errors.New("invalid post status") } if len(p.Tags) > 10 { return errors.New("maximum 10 tags allowed per post") } return nil } // SetTimestamps sets the create and update timestamps func (p *Post) SetTimestamps() { now := time.Now().UTC().UnixNano() / 1e6 // milliseconds if p.CreatedAt == 0 { p.CreatedAt = now } p.UpdatedAt = now } // IsNew returns true if this is a new post (no ID set) func (p *Post) IsNew() bool { var zeroUUID gocql.UUID return p.ID == zeroUUID } // Publish marks the post as published func (p *Post) Publish() { p.Status = post.PostStatusPublished now := time.Now().UTC().UnixNano() / 1e6 p.PublishedAt = &now p.SetTimestamps() } // Archive marks the post as archived func (p *Post) Archive() { p.Status = post.PostStatusArchived p.SetTimestamps() } // Delete marks the post as deleted (soft delete) func (p *Post) Delete() { p.Status = post.PostStatusDeleted p.SetTimestamps() } // IsVisible returns true if the post is visible to public func (p *Post) IsVisible() bool { return p.Status.IsVisible() } // IsEditable returns true if the post can be edited func (p *Post) IsEditable() bool { return p.Status.IsEditable() } // IncrementLikeCount increments the like count func (p *Post) IncrementLikeCount() { p.LikeCount++ p.SetTimestamps() } // DecrementLikeCount decrements the like count func (p *Post) DecrementLikeCount() { if p.LikeCount > 0 { p.LikeCount-- p.SetTimestamps() } } // IncrementCommentCount increments the comment count func (p *Post) IncrementCommentCount() { p.CommentCount++ p.SetTimestamps() } // DecrementCommentCount decrements the comment count func (p *Post) DecrementCommentCount() { if p.CommentCount > 0 { p.CommentCount-- p.SetTimestamps() } } // IncrementViewCount increments the view count func (p *Post) IncrementViewCount() { p.ViewCount++ p.SetTimestamps() } // Pin pins the post func (p *Post) Pin() { p.IsPinned = true now := time.Now().UTC().UnixNano() / 1e6 p.PinnedAt = &now p.SetTimestamps() } // Unpin unpins the post func (p *Post) Unpin() { p.IsPinned = false p.PinnedAt = nil p.SetTimestamps() }