11package models
22
33import (
4+ "database/sql/driver"
5+ "encoding/json"
6+ "errors"
47 "time"
58
69 "gorm.io/gorm"
710)
811
12+ type Post struct {
13+ ID uint `json:"id" gorm:"primaryKey"`
14+ Title string `json:"title" gorm:"size:255;not null"`
15+ Content string `json:"content" gorm:"type:text;not null"`
16+ Type string `json:"type" gorm:"not null" validate:"required,oneof=discussion announcement post poll review annotation" default:"discussion"`
17+ TypeData PostTypeData `json:"type_data,omitempty" gorm:"type:jsonb"`
18+ IsPinned bool `json:"is_pinned" gorm:"default:false"`
19+ LikesCount int `json:"likes_count" gorm:"default:0"`
20+ CommentsCount int `json:"comments_count" gorm:"default:0"`
21+ ViewsCount int `json:"views_count" gorm:"default:0"`
22+ UserID uint `json:"user_id"`
23+ ClubID uint `json:"club_id"`
24+
25+ Club Club `json:"club" gorm:"foreignKey:ClubID" swaggerignore:"true"`
26+ User User `json:"user" gorm:"foreignKey:UserID" swaggerignore:"true"`
27+ Comments []Comment `json:"comments,omitempty" gorm:"foreignKey:PostID" swaggerignore:"true"`
28+ Likes []PostLike `json:"likes,omitempty" gorm:"foreignKey:PostID" swaggerignore:"true"`
29+
30+ CreatedAt time.Time `json:"created_at"`
31+ UpdatedAt time.Time `json:"updated_at"`
32+ DeletedAt gorm.DeletedAt `json:"-" gorm:"index"`
33+ }
34+
35+ type PostTypeData json.RawMessage
36+
37+ func (ptd * PostTypeData ) Scan (value interface {}) error {
38+ if value == nil {
39+ * ptd = nil
40+ return nil
41+ }
42+ bytes , ok := value .([]byte )
43+ if ! ok {
44+ return errors .New ("cannot scan into PostTypeData" )
45+ }
46+ * ptd = bytes
47+ return nil
48+ }
49+
50+ func (ptd PostTypeData ) Value () (driver.Value , error ) {
51+ if len (ptd ) == 0 {
52+ return nil , nil
53+ }
54+ return []byte (ptd ), nil
55+ }
56+
957type PostLike struct {
1058 ID uint `json:"id" gorm:"primaryKey"`
1159 UserID uint `json:"user_id" gorm:"uniqueIndex:idx_user_post_like"`
@@ -17,62 +65,132 @@ type PostLike struct {
1765 UpdatedAt time.Time `json:"updated_at"`
1866}
1967
20- type Post struct {
21- ID uint `json:"id" gorm:"primaryKey"`
22- Title string `json:"title" gorm:"size:255;not null"`
23- Content string `json:"content" gorm:"type:text;not null"`
24- Type string `json:"type" gorm:"not null" validate:"required,oneof=discussion announcement event poll review annotation" default:"discussion"`
25- IsPinned bool `json:"is_pinned" gorm:"default:false"`
26- LikesCount int `json:"likes_count" gorm:"default:0"`
27- CommentsCount int `json:"comments_count" gorm:"default:0"`
28- ViewsCount int `json:"views_count" gorm:"default:0"`
29- UserID uint `json:"user_id"`
30- ClubID uint `json:"club_id"`
68+ type PollVote struct {
69+ ID uint `json:"id" gorm:"primaryKey"`
70+ PostID uint `json:"post_id" gorm:"index"`
71+ UserID uint `json:"user_id" gorm:"index"`
72+ OptionID string `json:"option_id"`
3173
32- Club Club `json:"club" gorm:"foreignKey:ClubID" swaggerignore:"true"`
33- User User `json:"user" gorm:"foreignKey:UserID" swaggerignore:"true"`
34- Comments []Comment `json:"comments,omitempty" gorm:"foreignKey:PostID" swaggerignore:"true"`
35- Likes []PostLike `json:"likes,omitempty" gorm:"foreignKey:PostID" swaggerignore:"true"`
74+ CreatedAt time.Time `json:"created_at"`
75+ UpdatedAt time.Time `json:"updated_at"`
76+ }
3677
37- CreatedAt time.Time `json:"created_at"`
38- UpdatedAt time.Time `json:"updated_at"`
39- DeletedAt gorm.DeletedAt `json:"-" gorm:"index"`
78+ type ReviewData struct {
79+ BookID uint `json:"book_id" validate:"required"`
80+ Rating float32 `json:"rating" validate:"required,gte=1,lte=5"`
81+ BookTitle string `json:"book_title,omitempty"`
82+ BookAuthor string `json:"book_author,omitempty"`
83+ ReviewText * string `json:"review_text,omitempty"`
84+ }
85+
86+ type PollData struct {
87+ Question string `json:"question" validate:"required,min=1,max=500"`
88+ Options []PollOption `json:"options" validate:"required,min=2,max=10,dive"`
89+ AllowMultiple bool `json:"allow_multiple"`
90+ ExpiresAt * time.Time `json:"expires_at,omitempty"`
91+ }
92+
93+ type PollOption struct {
94+ ID string `json:"id"`
95+ Text string `json:"text" validate:"required,min=1,max=200"`
96+ Votes int `json:"votes"`
97+ }
98+
99+ type AnnotationData struct {
100+ BookID uint `json:"book_id" validate:"required"`
101+ Page * int `json:"page,omitempty" validate:"omitempty,gte=1"`
102+ Chapter * int `json:"chapter,omitempty" validate:"omitempty,gte=1"`
103+ Quote string `json:"quote,omitempty" validate:"omitempty,max=1000"`
104+ BookTitle string `json:"book_title,omitempty"`
105+ BookAuthor string `json:"book_author,omitempty"`
106+ }
107+
108+ type PostData struct {
109+ PostID uint `json:"post_id,omitempty"`
110+ PostTitle string `json:"post_title,omitempty"`
111+ PostContent string `json:"post_content,omitempty"`
112+ }
113+
114+ func (p * Post ) GetReviewData () (* ReviewData , error ) {
115+ if p .Type != "review" || len (p .TypeData ) == 0 {
116+ return nil , nil
117+ }
118+ var data ReviewData
119+ err := json .Unmarshal (p .TypeData , & data )
120+ return & data , err
121+ }
122+
123+ func (p * Post ) GetPollData () (* PollData , error ) {
124+ if p .Type != "poll" || len (p .TypeData ) == 0 {
125+ return nil , nil
126+ }
127+ var data PollData
128+ err := json .Unmarshal (p .TypeData , & data )
129+ return & data , err
130+ }
131+
132+ func (p * Post ) GetAnnotationData () (* AnnotationData , error ) {
133+ if p .Type != "annotation" || len (p .TypeData ) == 0 {
134+ return nil , nil
135+ }
136+ var data AnnotationData
137+ err := json .Unmarshal (p .TypeData , & data )
138+ return & data , err
139+ }
140+
141+ func (p * Post ) GetPostData () (* PostData , error ) {
142+ if p .Type != "post" || len (p .TypeData ) == 0 {
143+ return nil , nil
144+ }
145+ var data PostData
146+ err := json .Unmarshal (p .TypeData , & data )
147+ return & data , err
40148}
41149
42150type CreatePostRequest struct {
43- Title string `json:"title" validate:"required,min=1,max=255"`
44- Content string `json:"content" validate:"required,min=1"`
45- Type string `json:"type" validate:"required,oneof=discussion announcement event poll review annotation"`
46- ClubID uint `json:"club_id" validate:"required"`
151+ Title string `json:"title" validate:"required,min=1,max=255"`
152+ Content string `json:"content" validate:"required,min=1"`
153+ Type string `json:"type" validate:"required,oneof=discussion announcement post poll review annotation"`
154+ ClubID uint `json:"club_id" validate:"required"`
155+ TypeData interface {} `json:"type_data,omitempty"`
47156}
48157
49158type UpdatePostRequest struct {
50- Title * string `json:"title,omitempty" validate:"omitempty,min=1,max=255"`
51- Content * string `json:"content,omitempty" validate:"omitempty,min=1"`
52- Type * string `json:"type,omitempty" validate:"omitempty,oneof=discussion announcement event poll review annotation"`
53- ClubID * uint `json:"club_id,omitempty" validate:"omitempty"`
54- IsPinned * bool `json:"is_pinned,omitempty"`
159+ Title * string `json:"title,omitempty" validate:"omitempty,min=1,max=255"`
160+ Content * string `json:"content,omitempty" validate:"omitempty,min=1"`
161+ Type * string `json:"type,omitempty" validate:"omitempty,oneof=discussion announcement post poll review annotation"`
162+ ClubID * uint `json:"club_id,omitempty" validate:"omitempty"`
163+ IsPinned * bool `json:"is_pinned,omitempty"`
164+ TypeData interface {} `json:"type_data,omitempty"`
55165}
56166
57167type PostResponse struct {
58- ID uint `json:"id"`
59- Title string `json:"title"`
60- Content string `json:"content"`
61- Type string `json:"type"`
62- IsPinned bool `json:"is_pinned"`
63- LikesCount int `json:"likes_count"`
64- CommentsCount int `json:"comments_count"`
65- ViewsCount int `json:"views_count"`
66- UserID uint `json:"user_id"`
67- ClubID uint `json:"club_id"`
68- User User `json:"user" swaggerignore:"true"`
69- Comments []Comment `json:"comments,omitempty" swaggerignore:"true"`
70- Likes []PostLike `json:"likes,omitempty" swaggerignore:"true"`
168+ ID uint `json:"id"`
169+ Title string `json:"title"`
170+ Content string `json:"content"`
171+ Type string `json:"type"`
172+ TypeData interface {} `json:"type_data,omitempty"`
173+ IsPinned bool `json:"is_pinned"`
174+ LikesCount int `json:"likes_count"`
175+ CommentsCount int `json:"comments_count"`
176+ ViewsCount int `json:"views_count"`
177+ UserID uint `json:"user_id"`
178+ ClubID uint `json:"club_id"`
179+ User User `json:"user" swaggerignore:"true"`
180+ Comments []Comment `json:"comments,omitempty" swaggerignore:"true"`
181+ Likes []PostLike `json:"likes,omitempty" swaggerignore:"true"`
182+
183+ UserVoted bool `json:"user_voted,omitempty"`
184+ UserVotes []string `json:"user_votes,omitempty"`
71185
72186 CreatedAt time.Time `json:"created_at"`
73187 UpdatedAt time.Time `json:"updated_at"`
74188}
75189
190+ type PollVoteRequest struct {
191+ OptionIDs []string `json:"option_ids" validate:"required,min=1"`
192+ }
193+
76194type PostLikeResponse struct {
77195 ID uint `json:"id"`
78196 User UserResponse `json:"user"`
@@ -88,7 +206,7 @@ func (pl PostLike) ToResponse() PostLikeResponse {
88206}
89207
90208func (p * Post ) ToResponse () PostResponse {
91- return PostResponse {
209+ response := PostResponse {
92210 ID : p .ID ,
93211 Title : p .Title ,
94212 Content : p .Content ,
@@ -105,4 +223,11 @@ func (p *Post) ToResponse() PostResponse {
105223 CreatedAt : p .CreatedAt ,
106224 UpdatedAt : p .UpdatedAt ,
107225 }
226+
227+ if len (p .TypeData ) > 0 {
228+ var typeData interface {}
229+ json .Unmarshal (p .TypeData , & typeData )
230+ response .TypeData = typeData
231+ }
232+ return response
108233}
0 commit comments