package model import ( "time" "spark-server/internal/module/square/entity" ) // Post maps table square_posts. type Post struct { ID int64 `gorm:"column:id;primaryKey;autoIncrement:false;comment:Snowflake 帖 id"` UserID int64 `gorm:"column:user_id;comment:作者 users.id"` Channel string `gorm:"column:channel;comment:广场实例"` Category string `gorm:"column:category;comment:内容标签"` Kind int16 `gorm:"column:kind;comment:1纯文 2图 3视频"` Text string `gorm:"column:text;comment:正文"` Content []byte `gorm:"column:content;type:varbinary(16384);comment:序列化 JSON 字节"` POILat float64 `gorm:"column:poi_lat;comment:地点纬度"` POILng float64 `gorm:"column:poi_lng;comment:地点经度"` POIName string `gorm:"column:poi_name;comment:地点名称"` POIAddress string `gorm:"column:poi_address;comment:地点地址"` Visibility int16 `gorm:"column:visibility;comment:0公开 1私密 2白名单 3黑名单"` AuditStatus int16 `gorm:"column:audit_status;comment:0待审 1通过 2拒绝"` AuditNote string `gorm:"column:audit_note;comment:拒绝原因"` AuditedAt *time.Time `gorm:"column:audited_at;comment:审核时间"` Status int16 `gorm:"column:status;comment:0正常 1已删"` Source int16 `gorm:"column:source;comment:0用户 1机器人海外媒体RSS"` SourceURL string `gorm:"column:source_url;comment:原文 URL"` ExpiresAt *time.Time `gorm:"column:expires_at;comment:机器人帖过期时间"` LikeCount int `gorm:"column:like_count;comment:点赞数"` CommentCount int `gorm:"column:comment_count;comment:评论数"` CreatedAt time.Time `gorm:"column:created_at;comment:发帖时间"` } func (Post) TableName() string { return "t_square_posts" } func (r *Post) Entity() *entity.Post { if r == nil { return nil } ch := entity.Channel(r.Channel) if ch == "" { ch = entity.ChannelSquare } p := &entity.Post{ ID: r.ID, UserID: r.UserID, Channel: ch, Category: entity.Category(r.Category), Kind: entity.Kind(r.Kind), Text: r.Text, Content: r.Content, POI: entity.POI{Lat: r.POILat, Lng: r.POILng, Name: r.POIName, Address: r.POIAddress}, Visibility: entity.Visibility(r.Visibility), AuditStatus: entity.AuditStatus(r.AuditStatus), Status: entity.Status(r.Status), Source: entity.Source(r.Source), SourceURL: r.SourceURL, LikeCount: r.LikeCount, CommentCount: r.CommentCount, CreatedAtMS: r.CreatedAt.UnixMilli(), } if r.ExpiresAt != nil { p.ExpiresAtMS = r.ExpiresAt.UnixMilli() } return p } func postFrom(p *entity.Post) *Post { if p == nil { return nil } ch := string(p.Channel) if ch == "" { ch = string(entity.ChannelSquare) } row := &Post{ ID: p.ID, UserID: p.UserID, Channel: ch, Category: string(p.Category), Kind: int16(p.Kind), Text: p.Text, Content: p.Content, POILat: p.POI.Lat, POILng: p.POI.Lng, POIName: p.POI.Name, POIAddress: p.POI.Address, Visibility: int16(p.Visibility), AuditStatus: int16(p.AuditStatus), Status: int16(p.Status), Source: int16(p.Source), SourceURL: p.SourceURL, LikeCount: p.LikeCount, CommentCount: p.CommentCount, } if p.CreatedAtMS > 0 { row.CreatedAt = time.UnixMilli(p.CreatedAtMS) } if p.ExpiresAtMS > 0 { t := time.UnixMilli(p.ExpiresAtMS) row.ExpiresAt = &t } if p.AuditStatus == entity.AuditApproved { t := row.CreatedAt if t.IsZero() { t = time.Now() } row.AuditedAt = &t } return row } // BotLink maps t_square_bot_links (RSS URL 去重). type BotLink struct { URLHash string `gorm:"column:url_hash;primaryKey;comment:URL SHA-256 hex"` URL string `gorm:"column:url;comment:原文 URL"` PostID int64 `gorm:"column:post_id;comment:帖 id"` CreatedAt time.Time `gorm:"column:created_at;comment:入库时间"` } func (BotLink) TableName() string { return "t_square_bot_links" } // Audience maps square_audience. type Audience struct { PostID int64 `gorm:"column:post_id;primaryKey;comment:帖 id"` PeerID int64 `gorm:"column:peer_id;primaryKey;comment:好友 uid"` } func (Audience) TableName() string { return "t_square_audience" } // Like maps square_likes. type Like struct { PostID int64 `gorm:"column:post_id;primaryKey;comment:帖 id"` UserID int64 `gorm:"column:user_id;primaryKey;comment:点赞人"` CreatedAt time.Time `gorm:"column:created_at;comment:点赞时间"` } func (Like) TableName() string { return "t_square_likes" } func (r *Like) Entity() *entity.Like { if r == nil { return nil } return &entity.Like{PostID: r.PostID, UserID: r.UserID, CreatedAtMS: r.CreatedAt.UnixMilli()} } // Comment maps square_comments. type Comment struct { ID int64 `gorm:"column:id;primaryKey;autoIncrement:false;comment:Snowflake 评论 id"` PostID int64 `gorm:"column:post_id;comment:帖 id"` UserID int64 `gorm:"column:user_id;comment:评论人"` ReplyToID int64 `gorm:"column:reply_to_id;comment:父评论 id"` ReplyToUID int64 `gorm:"column:reply_to_uid;comment:被回复用户"` Text string `gorm:"column:text;comment:评论文本"` Status int16 `gorm:"column:status;comment:0正常 1已删"` CreatedAt time.Time `gorm:"column:created_at;comment:评论时间"` } func (Comment) TableName() string { return "t_square_comments" } func (r *Comment) Entity() *entity.Comment { if r == nil { return nil } return &entity.Comment{ ID: r.ID, PostID: r.PostID, UserID: r.UserID, ReplyToID: r.ReplyToID, ReplyToUID: r.ReplyToUID, Text: r.Text, Status: entity.Status(r.Status), CreatedAtMS: r.CreatedAt.UnixMilli(), } } func commentFrom(c *entity.Comment) *Comment { if c == nil { return nil } row := &Comment{ ID: c.ID, PostID: c.PostID, UserID: c.UserID, ReplyToID: c.ReplyToID, ReplyToUID: c.ReplyToUID, Text: c.Text, Status: int16(c.Status), } if c.CreatedAtMS > 0 { row.CreatedAt = time.UnixMilli(c.CreatedAtMS) } return row } // Notice maps square_notices. type Notice struct { ID int64 `gorm:"column:id;primaryKey;autoIncrement:false;comment:Snowflake 通知 id"` ToUserID int64 `gorm:"column:to_user_id;comment:接收人"` Channel string `gorm:"column:channel;comment:广场实例"` FromUserID int64 `gorm:"column:from_user_id;comment:发起人"` Kind int16 `gorm:"column:kind;comment:1赞 2评论 3回复"` PostID int64 `gorm:"column:post_id;comment:帖 id"` CommentID int64 `gorm:"column:comment_id;comment:评论 id"` ReadAt *time.Time `gorm:"column:read_at;comment:已读时间"` CreatedAt time.Time `gorm:"column:created_at;comment:通知时间"` } func (Notice) TableName() string { return "t_square_notices" } func (r *Notice) Entity() *entity.Notice { if r == nil { return nil } ch := entity.Channel(r.Channel) if ch == "" { ch = entity.ChannelSquare } n := &entity.Notice{ ID: r.ID, ToUserID: r.ToUserID, Channel: ch, FromUserID: r.FromUserID, Kind: entity.NoticeKind(r.Kind), PostID: r.PostID, CommentID: r.CommentID, CreatedAtMS: r.CreatedAt.UnixMilli(), } if r.ReadAt != nil { n.ReadAtMS = r.ReadAt.UnixMilli() } return n } // NoticeState maps square_notice_state. type NoticeState struct { UserID int64 `gorm:"column:user_id;primaryKey;comment:用户 id"` Channel string `gorm:"column:channel;primaryKey;comment:广场实例"` LastReadNoticeID int64 `gorm:"column:last_read_notice_id;comment:已读水位"` UpdatedAt time.Time `gorm:"column:updated_at;comment:更新时间"` } func (NoticeState) TableName() string { return "t_square_notice_state" } func (r *NoticeState) Entity() *entity.NoticeState { if r == nil { return nil } ch := entity.Channel(r.Channel) if ch == "" { ch = entity.ChannelSquare } return &entity.NoticeState{ UserID: r.UserID, Channel: ch, LastReadNoticeID: r.LastReadNoticeID, UpdatedAtMS: r.UpdatedAt.UnixMilli(), } }