From 5433eb9e8f02d313dd3e306d9274233c70b6f8ad Mon Sep 17 00:00:00 2001 From: Michael Li Date: Fri, 11 Nov 2022 13:45:24 +0800 Subject: [PATCH] prepare use mir --- Makefile | 5 + go.mod | 5 + internal/dao/jinzhu/dbr/attachment.go | 27 +++ internal/dao/jinzhu/dbr/captcha.go | 38 ++++ internal/dao/jinzhu/dbr/comment.go | 127 +++++++++++ internal/dao/jinzhu/dbr/comment_content.go | 59 +++++ internal/dao/jinzhu/dbr/comment_reply.go | 110 +++++++++ internal/dao/jinzhu/dbr/contact.go | 119 ++++++++++ internal/dao/jinzhu/dbr/dbr.go | 36 +++ internal/dao/jinzhu/dbr/message.go | 148 +++++++++++++ internal/dao/jinzhu/dbr/post.go | 208 ++++++++++++++++++ .../dao/jinzhu/dbr/post_attachment_bill.go | 36 +++ internal/dao/jinzhu/dbr/post_collection.go | 102 +++++++++ internal/dao/jinzhu/dbr/post_content.go | 121 ++++++++++ internal/dao/jinzhu/dbr/post_star.go | 98 +++++++++ internal/dao/jinzhu/dbr/tag.go | 97 ++++++++ internal/dao/jinzhu/dbr/user.go | 94 ++++++++ internal/dao/jinzhu/dbr/wallet_recharge.go | 34 +++ internal/dao/jinzhu/dbr/wallet_statement.go | 83 +++++++ internal/mirc/auto/api/v1/site.go | 144 ++++++++++++ internal/mirc/main.go | 24 ++ internal/mirc/routes/README.md | 1 + internal/mirc/routes/v1/localoss.go | 15 ++ internal/mirc/routes/v1/web_admin.go | 15 ++ internal/mirc/routes/v1/web_alipay.go | 15 ++ internal/mirc/routes/v1/web_core.go | 44 ++++ internal/mirc/routes/v1/web_followship.go | 15 ++ internal/mirc/routes/v1/web_friendship.go | 15 ++ internal/mirc/routes/v1/web_loose.go | 15 ++ internal/mirc/routes/v1/web_priv.go | 15 ++ internal/mirc/routes/v1/web_pub.go | 15 ++ internal/servants/chain/admin.go | 25 +++ internal/servants/chain/jwt.go | 113 ++++++++++ internal/servants/chain/priv.go | 45 ++++ internal/servants/core.go | 26 +++ internal/servants/localoss.go | 5 + internal/servants/servants.go | 12 + internal/servants/web_admin.go | 5 + internal/servants/web_alipay.go | 5 + internal/servants/web_core.go | 32 +++ internal/servants/web_followship.go | 5 + internal/servants/web_friendship.go | 5 + internal/servants/web_loose.go | 5 + internal/servants/web_priv.go | 5 + internal/servants/web_pub.go | 5 + 45 files changed, 2173 insertions(+) create mode 100644 internal/dao/jinzhu/dbr/attachment.go create mode 100644 internal/dao/jinzhu/dbr/captcha.go create mode 100644 internal/dao/jinzhu/dbr/comment.go create mode 100644 internal/dao/jinzhu/dbr/comment_content.go create mode 100644 internal/dao/jinzhu/dbr/comment_reply.go create mode 100644 internal/dao/jinzhu/dbr/contact.go create mode 100644 internal/dao/jinzhu/dbr/dbr.go create mode 100644 internal/dao/jinzhu/dbr/message.go create mode 100644 internal/dao/jinzhu/dbr/post.go create mode 100644 internal/dao/jinzhu/dbr/post_attachment_bill.go create mode 100644 internal/dao/jinzhu/dbr/post_collection.go create mode 100644 internal/dao/jinzhu/dbr/post_content.go create mode 100644 internal/dao/jinzhu/dbr/post_star.go create mode 100644 internal/dao/jinzhu/dbr/tag.go create mode 100644 internal/dao/jinzhu/dbr/user.go create mode 100644 internal/dao/jinzhu/dbr/wallet_recharge.go create mode 100644 internal/dao/jinzhu/dbr/wallet_statement.go create mode 100644 internal/mirc/auto/api/v1/site.go create mode 100644 internal/mirc/main.go create mode 100644 internal/mirc/routes/README.md create mode 100644 internal/mirc/routes/v1/localoss.go create mode 100644 internal/mirc/routes/v1/web_admin.go create mode 100644 internal/mirc/routes/v1/web_alipay.go create mode 100644 internal/mirc/routes/v1/web_core.go create mode 100644 internal/mirc/routes/v1/web_followship.go create mode 100644 internal/mirc/routes/v1/web_friendship.go create mode 100644 internal/mirc/routes/v1/web_loose.go create mode 100644 internal/mirc/routes/v1/web_priv.go create mode 100644 internal/mirc/routes/v1/web_pub.go create mode 100644 internal/servants/chain/admin.go create mode 100644 internal/servants/chain/jwt.go create mode 100644 internal/servants/chain/priv.go create mode 100644 internal/servants/core.go create mode 100644 internal/servants/localoss.go create mode 100644 internal/servants/servants.go create mode 100644 internal/servants/web_admin.go create mode 100644 internal/servants/web_alipay.go create mode 100644 internal/servants/web_core.go create mode 100644 internal/servants/web_followship.go create mode 100644 internal/servants/web_friendship.go create mode 100644 internal/servants/web_loose.go create mode 100644 internal/servants/web_priv.go create mode 100644 internal/servants/web_pub.go diff --git a/Makefile b/Makefile index 4d0b94a2..700e2d29 100644 --- a/Makefile +++ b/Makefile @@ -68,6 +68,11 @@ windows-x64: @echo Build paopao-ce [windows-x64] CGO_ENABLED=$(CGO_ENABLED) @CGO_ENABLED=$(CGO_ENABLED) GOOS=windows GOARCH=amd64 go build -trimpath -tags '$(TAGS)' -ldflags '$(LDFLAGS)' -o $(RELEASE_WINDOWS_AMD64)/$(basename $(TARGET)).exe +.PHONY: generate +generate: + @go generate internal/mirc/main.go + @go fmt ./internal/mirc/... + clean: @go clean @find ./release -type f -exec rm -r {} + diff --git a/go.mod b/go.mod index 8f4c9435..8e3819e5 100644 --- a/go.mod +++ b/go.mod @@ -39,6 +39,7 @@ require ( gorm.io/plugin/dbresolver v1.1.0 gorm.io/plugin/soft_delete v1.1.0 modernc.org/sqlite v1.17.3 + github.com/alimy/mir/v3 v3.0.0 ) require ( @@ -131,3 +132,7 @@ require ( modernc.org/strutil v1.1.1 // indirect modernc.org/token v1.0.0 // indirect ) + +replace ( + github.com/alimy/mir/v3 => ../../alimy/mir +) \ No newline at end of file diff --git a/internal/dao/jinzhu/dbr/attachment.go b/internal/dao/jinzhu/dbr/attachment.go new file mode 100644 index 00000000..0c748b00 --- /dev/null +++ b/internal/dao/jinzhu/dbr/attachment.go @@ -0,0 +1,27 @@ +package model + +import "gorm.io/gorm" + +type AttachmentType int + +const ( + ATTACHMENT_TYPE_IMAGE AttachmentType = iota + 1 + ATTACHMENT_TYPE_VIDEO + ATTACHMENT_TYPE_OTHER +) + +type Attachment struct { + *Model + UserID int64 `json:"user_id"` + FileSize int64 `json:"file_size"` + ImgWidth int `json:"img_width"` + ImgHeight int `json:"img_height"` + Type AttachmentType `json:"type"` + Content string `json:"content"` +} + +func (a *Attachment) Create(db *gorm.DB) (*Attachment, error) { + err := db.Create(&a).Error + + return a, err +} diff --git a/internal/dao/jinzhu/dbr/captcha.go b/internal/dao/jinzhu/dbr/captcha.go new file mode 100644 index 00000000..210cc691 --- /dev/null +++ b/internal/dao/jinzhu/dbr/captcha.go @@ -0,0 +1,38 @@ +package model + +import "gorm.io/gorm" + +type Captcha struct { + *Model + Phone string `json:"phone"` + Captcha string `json:"captcha"` + UseTimes int `json:"use_times"` + ExpiredOn int64 `json:"expired_on"` +} + +func (c *Captcha) Create(db *gorm.DB) (*Captcha, error) { + err := db.Create(&c).Error + + return c, err +} + +func (c *Captcha) Update(db *gorm.DB) error { + return db.Model(&Captcha{}).Where("id = ? AND is_del = ?", c.Model.ID, 0).Save(c).Error +} + +func (c *Captcha) Get(db *gorm.DB) (*Captcha, error) { + var captcha Captcha + if c.Model != nil && c.ID > 0 { + db = db.Where("id = ? AND is_del = ?", c.ID, 0) + } + if c.Phone != "" { + db = db.Where("phone = ?", c.Phone) + } + + err := db.Last(&captcha).Error + if err != nil { + return &captcha, err + } + + return &captcha, nil +} diff --git a/internal/dao/jinzhu/dbr/comment.go b/internal/dao/jinzhu/dbr/comment.go new file mode 100644 index 00000000..72494b53 --- /dev/null +++ b/internal/dao/jinzhu/dbr/comment.go @@ -0,0 +1,127 @@ +package model + +import ( + "time" + + "gorm.io/gorm" +) + +type Comment struct { + *Model + PostID int64 `json:"post_id"` + UserID int64 `json:"user_id"` + IP string `json:"ip"` + IPLoc string `json:"ip_loc"` +} + +type CommentFormated struct { + ID int64 `json:"id"` + PostID int64 `json:"post_id"` + UserID int64 `json:"user_id"` + User *UserFormated `json:"user"` + Contents []*CommentContent `json:"contents"` + Replies []*CommentReplyFormated `json:"replies"` + IPLoc string `json:"ip_loc"` + CreatedOn int64 `json:"created_on"` + ModifiedOn int64 `json:"modified_on"` +} + +func (c *Comment) Format() *CommentFormated { + if c.Model == nil { + return &CommentFormated{} + } + return &CommentFormated{ + ID: c.Model.ID, + PostID: c.PostID, + UserID: c.UserID, + User: &UserFormated{}, + Contents: []*CommentContent{}, + Replies: []*CommentReplyFormated{}, + IPLoc: c.IPLoc, + CreatedOn: c.CreatedOn, + ModifiedOn: c.ModifiedOn, + } +} + +func (c *Comment) Get(db *gorm.DB) (*Comment, error) { + var comment Comment + if c.Model != nil && c.ID > 0 { + db = db.Where("id = ? AND is_del = ?", c.ID, 0) + } else { + return nil, gorm.ErrRecordNotFound + } + + err := db.First(&comment).Error + if err != nil { + return &comment, err + } + + return &comment, nil +} + +func (c *Comment) List(db *gorm.DB, conditions *ConditionsT, offset, limit int) ([]*Comment, error) { + var comments []*Comment + var err error + if offset >= 0 && limit > 0 { + db = db.Offset(offset).Limit(limit) + } + if c.PostID > 0 { + db = db.Where("id = ?", c.PostID) + } + + for k, v := range *conditions { + if k == "ORDER" { + db = db.Order(v) + } else { + db = db.Where(k, v) + } + } + + if err = db.Where("is_del = ?", 0).Find(&comments).Error; err != nil { + return nil, err + } + + return comments, nil +} + +func (c *Comment) Count(db *gorm.DB, conditions *ConditionsT) (int64, error) { + var count int64 + if c.PostID > 0 { + db = db.Where("post_id = ?", c.PostID) + } + for k, v := range *conditions { + if k != "ORDER" { + db = db.Where(k, v) + } + } + if err := db.Model(c).Count(&count).Error; err != nil { + return 0, err + } + + return count, nil +} + +func (c *Comment) Create(db *gorm.DB) (*Comment, error) { + err := db.Create(&c).Error + + return c, err +} + +func (c *Comment) Delete(db *gorm.DB) error { + return db.Model(c).Where("id = ?", c.Model.ID).Updates(map[string]any{ + "deleted_on": time.Now().Unix(), + "is_del": 1, + }).Error +} + +func (c *Comment) CommentIdsByPostId(db *gorm.DB, postId int64) (ids []int64, err error) { + err = db.Model(c).Where("post_id = ?", postId).Select("id").Find(&ids).Error + return +} + +func (c *Comment) DeleteByPostId(db *gorm.DB, postId int64) error { + return db.Model(c).Where("post_id = ?", postId).Updates(map[string]any{ + "deleted_on": time.Now().Unix(), + "is_del": 1, + }).Error +} diff --git a/internal/dao/jinzhu/dbr/comment_content.go b/internal/dao/jinzhu/dbr/comment_content.go new file mode 100644 index 00000000..b7d42dfd --- /dev/null +++ b/internal/dao/jinzhu/dbr/comment_content.go @@ -0,0 +1,59 @@ +package model + +import ( + "time" + + "gorm.io/gorm" +) + +type CommentContent struct { + *Model + CommentID int64 `json:"comment_id"` + UserID int64 `json:"user_id"` + Content string `json:"content"` + Type PostContentT `json:"type"` + Sort int64 `json:"sort"` +} + +func (c *CommentContent) List(db *gorm.DB, conditions *ConditionsT, offset, limit int) ([]*CommentContent, error) { + var comments []*CommentContent + var err error + if offset >= 0 && limit > 0 { + db = db.Offset(offset).Limit(limit) + } + if c.CommentID > 0 { + db = db.Where("id = ?", c.CommentID) + } + + for k, v := range *conditions { + if k == "ORDER" { + db = db.Order(v) + } else { + db = db.Where(k, v) + } + } + + if err = db.Where("is_del = ?", 0).Find(&comments).Error; err != nil { + return nil, err + } + + return comments, nil +} + +func (c *CommentContent) Create(db *gorm.DB) (*CommentContent, error) { + err := db.Create(&c).Error + + return c, err +} + +func (c *CommentContent) MediaContentsByCommentId(db *gorm.DB, commentIds []int64) (contents []string, err error) { + err = db.Model(c).Where("comment_id IN ? AND type = ?", commentIds, CONTENT_TYPE_IMAGE).Select("content").Find(&contents).Error + return +} + +func (c *CommentContent) DeleteByCommentIds(db *gorm.DB, commentIds []int64) error { + return db.Model(c).Where("comment_id IN ?", commentIds).Updates(map[string]any{ + "deleted_on": time.Now().Unix(), + "is_del": 1, + }).Error +} diff --git a/internal/dao/jinzhu/dbr/comment_reply.go b/internal/dao/jinzhu/dbr/comment_reply.go new file mode 100644 index 00000000..fd22702f --- /dev/null +++ b/internal/dao/jinzhu/dbr/comment_reply.go @@ -0,0 +1,110 @@ +package model + +import ( + "time" + + "gorm.io/gorm" +) + +type CommentReply struct { + *Model + CommentID int64 `json:"comment_id"` + UserID int64 `json:"user_id"` + AtUserID int64 `json:"at_user_id"` + Content string `json:"content"` + IP string `json:"ip"` + IPLoc string `json:"ip_loc"` +} + +type CommentReplyFormated struct { + ID int64 `json:"id"` + CommentID int64 `json:"comment_id"` + UserID int64 `json:"user_id"` + User *UserFormated `json:"user"` + AtUserID int64 `json:"at_user_id"` + AtUser *UserFormated `json:"at_user"` + Content string `json:"content"` + IPLoc string `json:"ip_loc"` + CreatedOn int64 `json:"created_on"` + ModifiedOn int64 `json:"modified_on"` +} + +func (c *CommentReply) Format() *CommentReplyFormated { + if c.Model == nil { + return &CommentReplyFormated{} + } + + return &CommentReplyFormated{ + ID: c.ID, + CommentID: c.CommentID, + UserID: c.UserID, + User: &UserFormated{}, + AtUserID: c.AtUserID, + AtUser: &UserFormated{}, + Content: c.Content, + IPLoc: c.IPLoc, + CreatedOn: c.CreatedOn, + ModifiedOn: c.ModifiedOn, + } +} + +func (c *CommentReply) List(db *gorm.DB, conditions *ConditionsT, offset, limit int) ([]*CommentReply, error) { + var comments []*CommentReply + var err error + if offset >= 0 && limit > 0 { + db = db.Offset(offset).Limit(limit) + } + if c.CommentID > 0 { + db = db.Where("id = ?", c.CommentID) + } + + for k, v := range *conditions { + if k == "ORDER" { + db = db.Order(v) + } else { + db = db.Where(k, v) + } + } + + if err = db.Where("is_del = ?", 0).Find(&comments).Error; err != nil { + return nil, err + } + + return comments, nil +} + +func (c *CommentReply) Create(db *gorm.DB) (*CommentReply, error) { + err := db.Create(&c).Error + + return c, err +} + +func (c *CommentReply) Get(db *gorm.DB) (*CommentReply, error) { + var reply CommentReply + if c.Model != nil && c.ID > 0 { + db = db.Where("id = ? AND is_del = ?", c.ID, 0) + } else { + return nil, gorm.ErrRecordNotFound + } + + err := db.First(&reply).Error + if err != nil { + return &reply, err + } + + return &reply, nil +} + +func (c *CommentReply) Delete(db *gorm.DB) error { + return db.Model(&CommentReply{}).Where("id = ? AND is_del = ?", c.Model.ID, 0).Updates(map[string]any{ + "deleted_on": time.Now().Unix(), + "is_del": 1, + }).Error +} + +func (c *CommentReply) DeleteByCommentIds(db *gorm.DB, commentIds []int64) error { + return db.Model(c).Where("comment_id IN ?", commentIds).Updates(map[string]any{ + "deleted_on": time.Now().Unix(), + "is_del": 1, + }).Error +} diff --git a/internal/dao/jinzhu/dbr/contact.go b/internal/dao/jinzhu/dbr/contact.go new file mode 100644 index 00000000..14049f77 --- /dev/null +++ b/internal/dao/jinzhu/dbr/contact.go @@ -0,0 +1,119 @@ +package model + +import ( + "github.com/sirupsen/logrus" + "gorm.io/gorm" +) + +const ( + ContactStatusRequesting int8 = iota + 1 + ContactStatusAgree + ContactStatusReject + ContactStatusDeleted +) + +type Contact struct { + *Model + User *User `json:"-" gorm:"foreignKey:ID;references:FriendId"` + UserId int64 `json:"user_id"` + FriendId int64 `json:"friend_id"` + GroupId int64 `json:"group_id"` + Remark string `json:"remark"` + Status int8 `json:"status"` // 1请求好友, 2已同意好友, 3已拒绝好友, 4已删除好友 + IsTop int8 `json:"is_top"` + IsBlack int8 `json:"is_black"` + NoticeEnable int8 `json:"notice_enable"` +} + +func (c *Contact) FetchUser(db *gorm.DB) (*Contact, error) { + var contact Contact + err := db.Omit("User").Unscoped().Where("user_id = ? AND friend_id = ?", c.UserId, c.FriendId).First(&contact).Error + if err != nil { + logrus.Debugf("Contact.FetchUser fetch user error:%s", err) + return nil, err + } + return &contact, nil +} + +func (c *Contact) GetByUserFriend(db *gorm.DB) (*Contact, error) { + var contact Contact + err := db.Omit("User").Where("user_id = ? AND friend_id = ?", c.UserId, c.FriendId).First(&contact).Error + if err != nil { + return nil, err + } + return &contact, nil +} + +func (c *Contact) FetchByUserFriendAll(db *gorm.DB) ([]*Contact, error) { + var contacts []*Contact + if err := db.Omit("User"). + Where("(user_id = ? AND friend_id = ?) OR (user_id = ? AND friend_id = ?)", + c.UserId, c.FriendId, c.FriendId, c.UserId). + Find(&contacts).Error; err != nil { + return nil, err + } + return contacts, nil +} + +func (c *Contact) List(db *gorm.DB, conditions ConditionsT, offset, limit int) ([]*Contact, error) { + var contacts []*Contact + var err error + tn := db.NamingStrategy.TableName("Contact") + "." + + if offset >= 0 && limit > 0 { + db = db.Offset(offset).Limit(limit) + } + for k, v := range conditions { + if k != "ORDER" { + db = db.Where(tn+k, v) + } + } + + db.Joins("User").Order("`User`.`nickname` ASC") + if err = db.Find(&contacts).Error; err != nil { + return nil, err + } + return contacts, nil +} + +func (c *Contact) BeFriendIds(db *gorm.DB) (ids []int64, err error) { + if err = db.Model(c).Omit("User").Select("user_id").Where("friend_id = ? AND status = ?", c.FriendId, ContactStatusAgree).Find(&ids).Error; err != nil { + return nil, err + } + return +} + +func (c *Contact) MyFriendIds(db *gorm.DB) (ids []string, err error) { + if err = db.Model(c).Omit("User").Select("friend_id").Where("user_id = ? AND status = ?", c.UserId, ContactStatusAgree).Find(&ids).Error; err != nil { + return nil, err + } + return +} + +func (m *Contact) Count(db *gorm.DB, conditions ConditionsT) (int64, error) { + var count int64 + + for k, v := range conditions { + if k != "ORDER" { + db = db.Where(k, v) + } + } + if err := db.Model(m).Omit("User").Count(&count).Error; err != nil { + return 0, err + } + + return count, nil +} + +func (c *Contact) Create(db *gorm.DB) (*Contact, error) { + err := db.Omit("User").Create(&c).Error + return c, err +} + +func (c *Contact) Update(db *gorm.DB) error { + return db.Model(&Contact{}).Omit("User").Where("id = ?", c.Model.ID).Save(c).Error +} + +func (c *Contact) UpdateInUnscoped(db *gorm.DB) error { + return db.Unscoped().Omit("User").Save(c).Error +} diff --git a/internal/dao/jinzhu/dbr/dbr.go b/internal/dao/jinzhu/dbr/dbr.go new file mode 100644 index 00000000..99bc8296 --- /dev/null +++ b/internal/dao/jinzhu/dbr/dbr.go @@ -0,0 +1,36 @@ +package model + +import ( + "time" + + "gorm.io/gorm" + "gorm.io/plugin/soft_delete" +) + +// Model 公共Model +type Model struct { + ID int64 `gorm:"primary_key" json:"id"` + CreatedOn int64 `json:"created_on"` + ModifiedOn int64 `json:"modified_on"` + DeletedOn int64 `json:"deleted_on"` + IsDel soft_delete.DeletedAt `gorm:"softDelete:flag" json:"is_del"` +} + +type ConditionsT map[string]any +type Predicates map[string][]any + +func (m *Model) BeforeCreate(tx *gorm.DB) (err error) { + nowTime := time.Now().Unix() + + tx.Statement.SetColumn("created_on", nowTime) + tx.Statement.SetColumn("modified_on", nowTime) + return +} + +func (m *Model) BeforeUpdate(tx *gorm.DB) (err error) { + if !tx.Statement.Changed("modified_on") { + tx.Statement.SetColumn("modified_on", time.Now().Unix()) + } + + return +} diff --git a/internal/dao/jinzhu/dbr/message.go b/internal/dao/jinzhu/dbr/message.go new file mode 100644 index 00000000..c1277cf7 --- /dev/null +++ b/internal/dao/jinzhu/dbr/message.go @@ -0,0 +1,148 @@ +package model + +import "gorm.io/gorm" + +type MessageT int8 + +const ( + MsgTypePost MessageT = iota + 1 + MsgtypeComment + MsgTypeReply + MsgTypeWhisper + MsgTypeRequestingFriend + MsgTypeSystem MessageT = 99 + + MsgStatusUnread = 0 + MsgStatusReaded = 1 +) + +type Message struct { + *Model + SenderUserID int64 `json:"sender_user_id"` + ReceiverUserID int64 `json:"receiver_user_id"` + Type MessageT `json:"type"` + Brief string `json:"brief"` + Content string `json:"content"` + PostID int64 `json:"post_id"` + CommentID int64 `json:"comment_id"` + ReplyID int64 `json:"reply_id"` + IsRead int8 `json:"is_read"` +} + +type MessageFormated struct { + ID int64 `json:"id"` + SenderUserID int64 `json:"sender_user_id"` + SenderUser *UserFormated `json:"sender_user"` + ReceiverUserID int64 `json:"receiver_user_id"` + Type MessageT `json:"type"` + Brief string `json:"brief"` + Content string `json:"content"` + PostID int64 `json:"post_id"` + Post *PostFormated `json:"post"` + CommentID int64 `json:"comment_id"` + Comment *Comment `json:"comment"` + ReplyID int64 `json:"reply_id"` + Reply *CommentReply `json:"reply"` + IsRead int8 `json:"is_read"` + CreatedOn int64 `json:"created_on"` + ModifiedOn int64 `json:"modified_on"` +} + +func (m *Message) Format() *MessageFormated { + if m.Model == nil || m.Model.ID == 0 { + return nil + } + mf := &MessageFormated{ + ID: m.ID, + SenderUserID: m.SenderUserID, + SenderUser: &UserFormated{}, + ReceiverUserID: m.ReceiverUserID, + Type: m.Type, + Brief: m.Brief, + Content: m.Content, + PostID: m.PostID, + Post: &PostFormated{}, + CommentID: m.CommentID, + Comment: &Comment{}, + ReplyID: m.ReplyID, + Reply: &CommentReply{}, + IsRead: m.IsRead, + CreatedOn: m.CreatedOn, + ModifiedOn: m.ModifiedOn, + } + + return mf +} + +func (m *Message) Create(db *gorm.DB) (*Message, error) { + err := db.Create(&m).Error + + return m, err +} + +func (m *Message) Update(db *gorm.DB) error { + return db.Model(&Message{}).Where("id = ? AND is_del = ?", m.Model.ID, 0).Save(m).Error +} + +func (m *Message) Get(db *gorm.DB) (*Message, error) { + var message Message + if m.Model != nil && m.ID > 0 { + db = db.Where("id = ? AND is_del = ?", m.ID, 0) + } + if m.ReceiverUserID > 0 { + db = db.Where("receiver_user_id = ?", m.ReceiverUserID) + } + if err := db.First(&message).Error; err != nil { + return nil, err + } + return &message, nil +} + +func (m *Message) FetchBy(db *gorm.DB, predicates Predicates) ([]*Message, error) { + var messages []*Message + for k, v := range predicates { + db = db.Where(k, v...) + } + db = db.Where("is_del = 0") + if err := db.Find(&messages).Error; err != nil { + return nil, err + } + return messages, nil +} + +func (c *Message) List(db *gorm.DB, conditions *ConditionsT, offset, limit int) ([]*Message, error) { + var messages []*Message + var err error + if offset >= 0 && limit > 0 { + db = db.Offset(offset).Limit(limit) + } + + for k, v := range *conditions { + if k == "ORDER" { + db = db.Order(v) + } else { + db = db.Where(k, v) + } + } + + if err = db.Where("is_del = ?", 0).Find(&messages).Error; err != nil { + return nil, err + } + + return messages, nil +} + +func (m *Message) Count(db *gorm.DB, conditions *ConditionsT) (int64, error) { + var count int64 + + for k, v := range *conditions { + if k != "ORDER" { + db = db.Where(k, v) + } + } + if err := db.Model(m).Count(&count).Error; err != nil { + return 0, err + } + + return count, nil +} diff --git a/internal/dao/jinzhu/dbr/post.go b/internal/dao/jinzhu/dbr/post.go new file mode 100644 index 00000000..ae428a9a --- /dev/null +++ b/internal/dao/jinzhu/dbr/post.go @@ -0,0 +1,208 @@ +package model + +import ( + "strings" + "time" + + "gorm.io/gorm" +) + +// PostVisibleT 可访问类型,0公开,1私密,2好友 +type PostVisibleT uint8 + +const ( + PostVisitPublic PostVisibleT = iota + PostVisitPrivate + PostVisitFriend + PostVisitInvalid +) + +type Post struct { + *Model + UserID int64 `json:"user_id"` + CommentCount int64 `json:"comment_count"` + CollectionCount int64 `json:"collection_count"` + UpvoteCount int64 `json:"upvote_count"` + Visibility PostVisibleT `json:"visibility"` + IsTop int `json:"is_top"` + IsEssence int `json:"is_essence"` + IsLock int `json:"is_lock"` + LatestRepliedOn int64 `json:"latest_replied_on"` + Tags string `json:"tags"` + AttachmentPrice int64 `json:"attachment_price"` + IP string `json:"ip"` + IPLoc string `json:"ip_loc"` +} + +type PostFormated struct { + ID int64 `json:"id"` + UserID int64 `json:"user_id"` + User *UserFormated `json:"user"` + Contents []*PostContentFormated `json:"contents"` + CommentCount int64 `json:"comment_count"` + CollectionCount int64 `json:"collection_count"` + UpvoteCount int64 `json:"upvote_count"` + Visibility PostVisibleT `json:"visibility"` + IsTop int `json:"is_top"` + IsEssence int `json:"is_essence"` + IsLock int `json:"is_lock"` + LatestRepliedOn int64 `json:"latest_replied_on"` + CreatedOn int64 `json:"created_on"` + ModifiedOn int64 `json:"modified_on"` + Tags map[string]int8 `json:"tags"` + AttachmentPrice int64 `json:"attachment_price"` + IPLoc string `json:"ip_loc"` +} + +func (p *Post) Format() *PostFormated { + if p.Model != nil { + tagsMap := map[string]int8{} + for _, tag := range strings.Split(p.Tags, ",") { + tagsMap[tag] = 1 + } + return &PostFormated{ + ID: p.ID, + UserID: p.UserID, + User: &UserFormated{}, + Contents: []*PostContentFormated{}, + CommentCount: p.CommentCount, + CollectionCount: p.CollectionCount, + UpvoteCount: p.UpvoteCount, + Visibility: p.Visibility, + IsTop: p.IsTop, + IsEssence: p.IsEssence, + IsLock: p.IsLock, + LatestRepliedOn: p.LatestRepliedOn, + CreatedOn: p.CreatedOn, + ModifiedOn: p.ModifiedOn, + AttachmentPrice: p.AttachmentPrice, + Tags: tagsMap, + IPLoc: p.IPLoc, + } + } + + return nil +} + +func (p *Post) Create(db *gorm.DB) (*Post, error) { + err := db.Create(&p).Error + + return p, err +} + +func (s *Post) Delete(db *gorm.DB) error { + return db.Model(s).Where("id = ?", s.Model.ID).Updates(map[string]any{ + "deleted_on": time.Now().Unix(), + "is_del": 1, + }).Error +} + +func (p *Post) Get(db *gorm.DB) (*Post, error) { + var post Post + if p.Model != nil && p.ID > 0 { + db = db.Where("id = ? AND is_del = ?", p.ID, 0) + } else { + return nil, gorm.ErrRecordNotFound + } + + err := db.First(&post).Error + if err != nil { + return &post, err + } + + return &post, nil +} + +func (p *Post) List(db *gorm.DB, conditions *ConditionsT, offset, limit int) ([]*Post, error) { + var posts []*Post + var err error + if offset >= 0 && limit > 0 { + db = db.Offset(offset).Limit(limit) + } + if p.UserID > 0 { + db = db.Where("user_id = ?", p.UserID) + } + for k, v := range *conditions { + if k == "ORDER" { + db = db.Order(v) + } else { + db = db.Where(k, v) + } + } + + if err = db.Where("is_del = ?", 0).Find(&posts).Error; err != nil { + return nil, err + } + + return posts, nil +} + +func (p *Post) Fetch(db *gorm.DB, predicates Predicates, offset, limit int) ([]*Post, error) { + var posts []*Post + var err error + if offset >= 0 && limit > 0 { + db = db.Offset(offset).Limit(limit) + } + if p.UserID > 0 { + db = db.Where("user_id = ?", p.UserID) + } + for query, args := range predicates { + if query == "ORDER" { + db = db.Order(args[0]) + } else { + db = db.Where(query, args...) + } + } + + if err = db.Where("is_del = ?", 0).Find(&posts).Error; err != nil { + return nil, err + } + + return posts, nil +} + +func (p *Post) CountBy(db *gorm.DB, predicates Predicates) (count int64, err error) { + for query, args := range predicates { + if query != "ORDER" { + db = db.Where(query, args...) + } + } + err = db.Model(p).Count(&count).Error + return +} + +func (p *Post) Count(db *gorm.DB, conditions *ConditionsT) (int64, error) { + var count int64 + if p.UserID > 0 { + db = db.Where("user_id = ?", p.UserID) + } + for k, v := range *conditions { + if k != "ORDER" { + db = db.Where(k, v) + } + } + if err := db.Model(p).Count(&count).Error; err != nil { + return 0, err + } + + return count, nil +} + +func (p *Post) Update(db *gorm.DB) error { + return db.Model(&Post{}).Where("id = ? AND is_del = ?", p.Model.ID, 0).Save(p).Error +} + +func (p PostVisibleT) String() string { + switch p { + case PostVisitPublic: + return "public" + case PostVisitPrivate: + return "private" + case PostVisitFriend: + return "friend" + case PostVisitInvalid: + return "invalid" + default: + return "unknow" + } +} diff --git a/internal/dao/jinzhu/dbr/post_attachment_bill.go b/internal/dao/jinzhu/dbr/post_attachment_bill.go new file mode 100644 index 00000000..8ee7aae6 --- /dev/null +++ b/internal/dao/jinzhu/dbr/post_attachment_bill.go @@ -0,0 +1,36 @@ +package model + +import "gorm.io/gorm" + +type PostAttachmentBill struct { + *Model + PostID int64 `json:"post_id"` + UserID int64 `json:"user_id"` + PaidAmount int64 `json:"paid_amount"` +} + +func (p *PostAttachmentBill) Get(db *gorm.DB) (*PostAttachmentBill, error) { + var pas PostAttachmentBill + if p.Model != nil && p.ID > 0 { + db = db.Where("id = ? AND is_del = ?", p.ID, 0) + } + if p.PostID > 0 { + db = db.Where("post_id = ?", p.PostID) + } + if p.UserID > 0 { + db = db.Where("user_id = ?", p.UserID) + } + + err := db.First(&pas).Error + if err != nil { + return &pas, err + } + + return &pas, nil +} + +func (p *PostAttachmentBill) Create(db *gorm.DB) (*PostAttachmentBill, error) { + err := db.Create(&p).Error + + return p, err +} diff --git a/internal/dao/jinzhu/dbr/post_collection.go b/internal/dao/jinzhu/dbr/post_collection.go new file mode 100644 index 00000000..0ea0cb29 --- /dev/null +++ b/internal/dao/jinzhu/dbr/post_collection.go @@ -0,0 +1,102 @@ +package model + +import ( + "time" + + "gorm.io/gorm" +) + +type PostCollection struct { + *Model + Post *Post `json:"-"` + PostID int64 `json:"post_id"` + UserID int64 `json:"user_id"` +} + +func (p *PostCollection) Get(db *gorm.DB) (*PostCollection, error) { + var star PostCollection + tn := db.NamingStrategy.TableName("PostCollection") + "." + + if p.Model != nil && p.ID > 0 { + db = db.Where(tn+"id = ? AND "+tn+"is_del = ?", p.ID, 0) + } + if p.PostID > 0 { + db = db.Where(tn+"post_id = ?", p.PostID) + } + if p.UserID > 0 { + db = db.Where(tn+"user_id = ?", p.UserID) + } + + db = db.Joins("Post").Where("Post.visibility <> ?", PostVisitPrivate).Order("Post.id DESC") + err := db.First(&star).Error + if err != nil { + return &star, err + } + + return &star, nil +} + +func (p *PostCollection) Create(db *gorm.DB) (*PostCollection, error) { + err := db.Omit("Post").Create(&p).Error + + return p, err +} + +func (p *PostCollection) Delete(db *gorm.DB) error { + return db.Model(&PostCollection{}).Omit("Post").Where("id = ? AND is_del = ?", p.Model.ID, 0).Updates(map[string]any{ + "deleted_on": time.Now().Unix(), + "is_del": 1, + }).Error +} + +func (p *PostCollection) List(db *gorm.DB, conditions *ConditionsT, offset, limit int) ([]*PostCollection, error) { + var collections []*PostCollection + var err error + tn := db.NamingStrategy.TableName("PostCollection") + "." + + if offset >= 0 && limit > 0 { + db = db.Offset(offset).Limit(limit) + } + if p.UserID > 0 { + db = db.Where(tn+"user_id = ?", p.UserID) + } + + for k, v := range *conditions { + if k == "ORDER" { + db = db.Order(v) + } else { + db = db.Where(tn+k, v) + } + } + + db = db.Joins("Post").Where("Post.visibility <> ?", PostVisitPrivate).Order("Post.id DESC") + if err = db.Where(tn+"is_del = ?", 0).Find(&collections).Error; err != nil { + return nil, err + } + + return collections, nil +} + +func (p *PostCollection) Count(db *gorm.DB, conditions *ConditionsT) (int64, error) { + var count int64 + tn := db.NamingStrategy.TableName("PostCollection") + "." + + if p.PostID > 0 { + db = db.Where(tn+"post_id = ?", p.PostID) + } + if p.UserID > 0 { + db = db.Where(tn+"user_id = ?", p.UserID) + } + for k, v := range *conditions { + if k != "ORDER" { + db = db.Where(tn+k, v) + } + } + + db = db.Joins("Post").Where("Post.visibility <> ?", PostVisitPrivate) + if err := db.Model(p).Count(&count).Error; err != nil { + return 0, err + } + + return count, nil +} diff --git a/internal/dao/jinzhu/dbr/post_content.go b/internal/dao/jinzhu/dbr/post_content.go new file mode 100644 index 00000000..b301de62 --- /dev/null +++ b/internal/dao/jinzhu/dbr/post_content.go @@ -0,0 +1,121 @@ +package model + +import ( + "time" + + "gorm.io/gorm" +) + +// 类型,1标题,2文字段落,3图片地址,4视频地址,5语音地址,6链接地址,7附件资源 + +type PostContentT int + +const ( + CONTENT_TYPE_TITLE PostContentT = iota + 1 + CONTENT_TYPE_TEXT + CONTENT_TYPE_IMAGE + CONTENT_TYPE_VIDEO + CONTENT_TYPE_AUDIO + CONTENT_TYPE_LINK + CONTENT_TYPE_ATTACHMENT + CONTENT_TYPE_CHARGE_ATTACHMENT +) + +var ( + mediaContentType = []PostContentT{ + CONTENT_TYPE_IMAGE, + CONTENT_TYPE_VIDEO, + CONTENT_TYPE_AUDIO, + CONTENT_TYPE_ATTACHMENT, + CONTENT_TYPE_CHARGE_ATTACHMENT, + } +) + +type PostContent struct { + *Model + PostID int64 `json:"post_id"` + UserID int64 `json:"user_id"` + Content string `json:"content"` + Type PostContentT `json:"type"` + Sort int64 `json:"sort"` +} + +type PostContentFormated struct { + ID int64 `json:"id"` + PostID int64 `json:"post_id"` + Content string `json:"content"` + Type PostContentT `json:"type"` + Sort int64 `json:"sort"` +} + +func (p *PostContent) DeleteByPostId(db *gorm.DB, postId int64) error { + return db.Model(p).Where("post_id = ?", postId).Updates(map[string]any{ + "deleted_on": time.Now().Unix(), + "is_del": 1, + }).Error +} + +func (p *PostContent) MediaContentsByPostId(db *gorm.DB, postId int64) (contents []string, err error) { + err = db.Model(p).Where("post_id = ? AND type IN ?", postId, mediaContentType).Select("content").Find(&contents).Error + return +} + +func (p *PostContent) Create(db *gorm.DB) (*PostContent, error) { + err := db.Create(&p).Error + + return p, err +} + +func (p *PostContent) Format() *PostContentFormated { + if p.Model == nil { + return nil + } + return &PostContentFormated{ + ID: p.ID, + PostID: p.PostID, + Content: p.Content, + Type: p.Type, + Sort: p.Sort, + } +} + +func (p *PostContent) List(db *gorm.DB, conditions *ConditionsT, offset, limit int) ([]*PostContent, error) { + var contents []*PostContent + var err error + if offset >= 0 && limit > 0 { + db = db.Offset(offset).Limit(limit) + } + if p.PostID > 0 { + db = db.Where("id = ?", p.PostID) + } + + for k, v := range *conditions { + if k == "ORDER" { + db = db.Order(v) + } else { + db = db.Where(k, v) + } + } + + if err = db.Where("is_del = ?", 0).Find(&contents).Error; err != nil { + return nil, err + } + + return contents, nil +} + +func (p *PostContent) Get(db *gorm.DB) (*PostContent, error) { + var content PostContent + if p.Model != nil && p.ID > 0 { + db = db.Where("id = ? AND is_del = ?", p.ID, 0) + } else { + return nil, gorm.ErrRecordNotFound + } + + err := db.First(&content).Error + if err != nil { + return &content, err + } + + return &content, nil +} diff --git a/internal/dao/jinzhu/dbr/post_star.go b/internal/dao/jinzhu/dbr/post_star.go new file mode 100644 index 00000000..3846a9c2 --- /dev/null +++ b/internal/dao/jinzhu/dbr/post_star.go @@ -0,0 +1,98 @@ +package model + +import ( + "time" + + "gorm.io/gorm" +) + +type PostStar struct { + *Model + Post *Post `json:"-"` + PostID int64 `json:"post_id"` + UserID int64 `json:"user_id"` +} + +func (p *PostStar) Get(db *gorm.DB) (*PostStar, error) { + var star PostStar + tn := db.NamingStrategy.TableName("PostStar") + "." + + if p.Model != nil && p.ID > 0 { + db = db.Where(tn+"id = ? AND "+tn+"is_del = ?", p.ID, 0) + } + if p.PostID > 0 { + db = db.Where(tn+"post_id = ?", p.PostID) + } + if p.UserID > 0 { + db = db.Where(tn+"user_id = ?", p.UserID) + } + + db = db.Joins("Post").Where("Post.visibility <> ?", PostVisitPrivate).Order("Post.id DESC") + if err := db.First(&star).Error; err != nil { + return nil, err + } + return &star, nil +} + +func (p *PostStar) Create(db *gorm.DB) (*PostStar, error) { + err := db.Omit("Post").Create(&p).Error + + return p, err +} + +func (p *PostStar) Delete(db *gorm.DB) error { + return db.Model(&PostStar{}).Omit("Post").Where("id = ? AND is_del = ?", p.Model.ID, 0).Updates(map[string]any{ + "deleted_on": time.Now().Unix(), + "is_del": 1, + }).Error +} + +func (p *PostStar) List(db *gorm.DB, conditions *ConditionsT, offset, limit int) ([]*PostStar, error) { + var stars []*PostStar + var err error + tn := db.NamingStrategy.TableName("PostStar") + "." + + if offset >= 0 && limit > 0 { + db = db.Offset(offset).Limit(limit) + } + if p.UserID > 0 { + db = db.Where(tn+"user_id = ?", p.UserID) + } + + for k, v := range *conditions { + if k == "ORDER" { + db = db.Order(v) + } else { + db = db.Where(tn+k, v) + } + } + + db = db.Joins("Post").Where("Post.visibility <> ?", PostVisitPrivate).Order("Post.id DESC") + if err = db.Find(&stars).Error; err != nil { + return nil, err + } + return stars, nil +} + +func (p *PostStar) Count(db *gorm.DB, conditions *ConditionsT) (int64, error) { + var count int64 + tn := db.NamingStrategy.TableName("PostStar") + "." + + if p.PostID > 0 { + db = db.Where(tn+"post_id = ?", p.PostID) + } + if p.UserID > 0 { + db = db.Where(tn+"user_id = ?", p.UserID) + } + for k, v := range *conditions { + if k != "ORDER" { + db = db.Where(tn+k, v) + } + } + + db = db.Joins("Post").Where("Post.visibility <> ?", PostVisitPrivate) + if err := db.Model(p).Count(&count).Error; err != nil { + return 0, err + } + return count, nil +} diff --git a/internal/dao/jinzhu/dbr/tag.go b/internal/dao/jinzhu/dbr/tag.go new file mode 100644 index 00000000..34bb64f9 --- /dev/null +++ b/internal/dao/jinzhu/dbr/tag.go @@ -0,0 +1,97 @@ +package model + +import ( + "time" + + "gorm.io/gorm" +) + +type Tag struct { + *Model + UserID int64 `json:"user_id"` + Tag string `json:"tag"` + QuoteNum int64 `json:"quote_num"` +} +type TagFormated struct { + ID int64 `json:"id"` + UserID int64 `json:"user_id"` + User *UserFormated `json:"user"` + Tag string `json:"tag"` + QuoteNum int64 `json:"quote_num"` +} + +func (t *Tag) Format() *TagFormated { + if t.Model == nil { + return &TagFormated{} + } + + return &TagFormated{ + ID: t.ID, + UserID: t.UserID, + User: &UserFormated{}, + Tag: t.Tag, + QuoteNum: t.QuoteNum, + } +} + +func (t *Tag) Get(db *gorm.DB) (*Tag, error) { + var tag Tag + if t.Model != nil && t.Model.ID > 0 { + db = db.Where("id= ? AND is_del = ?", t.Model.ID, 0) + } else { + db = db.Where("tag = ? AND is_del = ?", t.Tag, 0) + } + + err := db.First(&tag).Error + if err != nil { + return &tag, err + } + + return &tag, nil +} + +func (t *Tag) Create(db *gorm.DB) (*Tag, error) { + err := db.Create(&t).Error + + return t, err +} + +func (t *Tag) Update(db *gorm.DB) error { + return db.Model(&Tag{}).Where("id = ? AND is_del = ?", t.Model.ID, 0).Save(t).Error +} + +func (t *Tag) Delete(db *gorm.DB) error { + return db.Model(t).Where("id = ?", t.Model.ID).Updates(map[string]any{ + "deleted_on": time.Now().Unix(), + "is_del": 1, + }).Error +} + +func (t *Tag) List(db *gorm.DB, conditions *ConditionsT, offset, limit int) ([]*Tag, error) { + var tags []*Tag + var err error + if offset >= 0 && limit > 0 { + db = db.Offset(offset).Limit(limit) + } + if t.UserID > 0 { + db = db.Where("user_id = ?", t.UserID) + } + for k, v := range *conditions { + if k == "ORDER" { + db = db.Order(v) + } else { + db = db.Where(k, v) + } + } + + if err = db.Where("is_del = ?", 0).Find(&tags).Error; err != nil { + return nil, err + } + + return tags, nil +} + +func (t *Tag) TagsFrom(db *gorm.DB, tags []string) (res []*Tag, err error) { + err = db.Where("tag IN ?", tags).Find(&res).Error + return +} diff --git a/internal/dao/jinzhu/dbr/user.go b/internal/dao/jinzhu/dbr/user.go new file mode 100644 index 00000000..39c52d79 --- /dev/null +++ b/internal/dao/jinzhu/dbr/user.go @@ -0,0 +1,94 @@ +package model + +import "gorm.io/gorm" + +const ( + UserStatusNormal int = iota + 1 + UserStatusClosed +) + +type User struct { + *Model + Nickname string `json:"nickname"` + Username string `json:"username"` + Phone string `json:"phone"` + Password string `json:"password"` + Salt string `json:"salt"` + Status int `json:"status"` + Avatar string `json:"avatar"` + Balance int64 `json:"balance"` + IsAdmin bool `json:"is_admin"` +} + +type UserFormated struct { + ID int64 `json:"id"` + Nickname string `json:"nickname"` + Username string `json:"username"` + Status int `json:"status"` + Avatar string `json:"avatar"` + IsAdmin bool `json:"is_admin"` +} + +func (u *User) Format() *UserFormated { + if u.Model != nil { + return &UserFormated{ + ID: u.ID, + Nickname: u.Nickname, + Username: u.Username, + Status: u.Status, + Avatar: u.Avatar, + IsAdmin: u.IsAdmin, + } + } + + return nil +} + +func (u *User) Get(db *gorm.DB) (*User, error) { + var user User + if u.Model != nil && u.Model.ID > 0 { + db = db.Where("id= ? AND is_del = ?", u.Model.ID, 0) + } else if u.Phone != "" { + db = db.Where("phone = ? AND is_del = ?", u.Phone, 0) + } else { + db = db.Where("username = ? AND is_del = ?", u.Username, 0) + } + + err := db.First(&user).Error + if err != nil { + return &user, err + } + + return &user, nil +} + +func (u *User) List(db *gorm.DB, conditions *ConditionsT, offset, limit int) ([]*User, error) { + var users []*User + var err error + if offset >= 0 && limit > 0 { + db = db.Offset(offset).Limit(limit) + } + for k, v := range *conditions { + if k == "ORDER" { + db = db.Order(v) + } else { + db = db.Where(k, v) + } + } + + if err = db.Where("is_del = ?", 0).Find(&users).Error; err != nil { + return nil, err + } + + return users, nil +} + +func (u *User) Create(db *gorm.DB) (*User, error) { + err := db.Create(&u).Error + + return u, err +} + +func (u *User) Update(db *gorm.DB) error { + return db.Model(&User{}).Where("id = ? AND is_del = ?", u.Model.ID, 0).Save(u).Error +} diff --git a/internal/dao/jinzhu/dbr/wallet_recharge.go b/internal/dao/jinzhu/dbr/wallet_recharge.go new file mode 100644 index 00000000..bfb3bc6f --- /dev/null +++ b/internal/dao/jinzhu/dbr/wallet_recharge.go @@ -0,0 +1,34 @@ +package model + +import "gorm.io/gorm" + +type WalletRecharge struct { + *Model + UserID int64 `json:"user_id"` + Amount int64 `json:"amount"` + TradeNo string `json:"trade_no"` + TradeStatus string `json:"trade_status"` +} + +func (p *WalletRecharge) Get(db *gorm.DB) (*WalletRecharge, error) { + var pas WalletRecharge + if p.Model != nil && p.ID > 0 { + db = db.Where("id = ? AND is_del = ?", p.ID, 0) + } + if p.UserID > 0 { + db = db.Where("user_id = ?", p.UserID) + } + + err := db.First(&pas).Error + if err != nil { + return &pas, err + } + + return &pas, nil +} + +func (p *WalletRecharge) Create(db *gorm.DB) (*WalletRecharge, error) { + err := db.Create(&p).Error + + return p, err +} diff --git a/internal/dao/jinzhu/dbr/wallet_statement.go b/internal/dao/jinzhu/dbr/wallet_statement.go new file mode 100644 index 00000000..163e2430 --- /dev/null +++ b/internal/dao/jinzhu/dbr/wallet_statement.go @@ -0,0 +1,83 @@ +package model + +import "gorm.io/gorm" + +type WalletStatement struct { + *Model + UserID int64 `json:"user_id"` + ChangeAmount int64 `json:"change_amount"` + BalanceSnapshot int64 `json:"balance_snapshot"` + Reason string `json:"reason"` + PostID int64 `json:"post_id"` +} + +func (w *WalletStatement) Get(db *gorm.DB) (*WalletStatement, error) { + var ws WalletStatement + if w.Model != nil && w.ID > 0 { + db = db.Where("id = ? AND is_del = ?", w.ID, 0) + } + if w.PostID > 0 { + db = db.Where("post_id = ?", w.PostID) + } + if w.UserID > 0 { + db = db.Where("user_id = ?", w.UserID) + } + + err := db.First(&ws).Error + if err != nil { + return &ws, err + } + + return &ws, nil +} + +func (w *WalletStatement) Create(db *gorm.DB) (*WalletStatement, error) { + err := db.Create(&w).Error + + return w, err +} + +func (w *WalletStatement) List(db *gorm.DB, conditions *ConditionsT, offset, limit int) ([]*WalletStatement, error) { + var records []*WalletStatement + var err error + if offset >= 0 && limit > 0 { + db = db.Offset(offset).Limit(limit) + } + if w.UserID > 0 { + db = db.Where("user_id = ?", w.UserID) + } + + for k, v := range *conditions { + if k == "ORDER" { + db = db.Order(v) + } else { + db = db.Where(k, v) + } + } + + if err = db.Where("is_del = ?", 0).Find(&records).Error; err != nil { + return nil, err + } + + return records, nil +} + +func (w *WalletStatement) Count(db *gorm.DB, conditions *ConditionsT) (int64, error) { + var count int64 + if w.PostID > 0 { + db = db.Where("post_id = ?", w.PostID) + } + if w.UserID > 0 { + db = db.Where("user_id = ?", w.UserID) + } + for k, v := range *conditions { + if k != "ORDER" { + db = db.Where(k, v) + } + } + if err := db.Model(w).Count(&count).Error; err != nil { + return 0, err + } + + return count, nil +} diff --git a/internal/mirc/auto/api/v1/site.go b/internal/mirc/auto/api/v1/site.go new file mode 100644 index 00000000..03c50281 --- /dev/null +++ b/internal/mirc/auto/api/v1/site.go @@ -0,0 +1,144 @@ +// Code generated by go-mir. DO NOT EDIT. + +package v1 + +import ( + "errors" + "net/http" + + gin "github.com/gin-gonic/gin" +) + +type AgentInfo struct { + Platform string `json:"platform"` + UserAgent string `json:"user_agent"` +} + +type ServerInfo struct { + ApiVer string `json:"api_ver"` +} + +type UserInfo struct { + Name string `json:"name"` +} + +type LoginReq struct { + AgentInfo AgentInfo `json:"agent_info"` + Name string `json:"name"` + Passwd string `json:"passwd"` +} + +type LoginResp struct { + UserInfo + ServerInfo ServerInfo `json:"server_info"` + JwtToken string `json:"jwt_token"` +} + +type WebCore interface { + // Chain provide handlers chain for gin + Chain() gin.HandlersChain + + Index(c *gin.Context) error + Articles(c *gin.Context) error + Login(c *gin.Context, req *LoginReq) (*LoginResp, error) + Logout(c *gin.Context) error + + mustEmbedUnimplementedWebCoreServant() +} + +type WebCoreBinding interface { + BindLogin(c *gin.Context) (*LoginReq, error) + + mustEmbedUnimplementedWebCoreBinding() +} + +type WebCoreRender interface { + RenderIndex(c *gin.Context, err error) + RenderArticles(c *gin.Context, err error) + RenderLogin(c *gin.Context, data *LoginResp, err error) + RenderLogout(c *gin.Context, err error) + + mustEmbedUnimplementedWebCoreRender() +} + +// RegisterWebCoreServant register WebCore servant to gin +func RegisterWebCoreServant(e *gin.Engine, s WebCore, b WebCoreBinding, r WebCoreRender) { + router := e.Group("v1") + // use chain for router + middlewares := s.Chain() + router.Use(middlewares...) + + // register routes info to router + router.Handle("GET", "/index/", func(c *gin.Context) { + r.RenderIndex(c, s.Index(c)) + }) + router.Handle("GET", "/articles/:category/", func(c *gin.Context) { + r.RenderArticles(c, s.Articles(c)) + }) + router.Handle("POST", "/user/login/", func(c *gin.Context) { + req, err := b.BindLogin(c) + if err != nil { + r.RenderLogin(c, nil, err) + } + resp, err := s.Login(c, req) + r.RenderLogin(c, resp, err) + }) + router.Handle("POST", "/user/logout/", func(c *gin.Context) { + r.RenderLogout(c, s.Logout(c)) + }) +} + +// UnimplementedWebCoreServant can be embedded to have forward compatible implementations. +type UnimplementedWebCoreServant struct{} + +// UnimplementedWebCoreBinding can be embedded to have forward compatible implementations. +type UnimplementedWebCoreBinding struct{} + +// UnimplementedWebCoreRender can be embedded to have forward compatible implementations. +type UnimplementedWebCoreRender struct{} + +func (UnimplementedWebCoreServant) Chain() gin.HandlersChain { + return nil +} + +func (UnimplementedWebCoreServant) Index(c *gin.Context) error { + return errors.New("method Index not implemented") +} + +func (UnimplementedWebCoreServant) Articles(c *gin.Context) error { + return errors.New("method Index not implemented") +} + +func (UnimplementedWebCoreServant) Login(c *gin.Context, req *LoginReq) (*LoginResp, error) { + return nil, errors.New("method Login not implemented") +} + +func (UnimplementedWebCoreServant) Logout(c *gin.Context) error { + return errors.New("method Logout not implemented") +} + +func (UnimplementedWebCoreServant) mustEmbedUnimplementedWebCoreServant() {} + +func (UnimplementedWebCoreBinding) BindLogin(c *gin.Context) (*LoginReq, error) { + return nil, errors.New("method BindLogin not implemented") +} + +func (UnimplementedWebCoreBinding) mustEmbedUnimplementedWebCoreBinding() {} + +func (UnimplementedWebCoreRender) RenderIndex(c *gin.Context, err error) { + c.String(http.StatusInternalServerError, "method RenderLogout not implemented") +} + +func (UnimplementedWebCoreRender) RenderArticles(c *gin.Context, err error) { + c.String(http.StatusInternalServerError, "method RenderLogout not implemented") +} + +func (UnimplementedWebCoreRender) RenderLogin(c *gin.Context, data *LoginResp, err error) { + c.String(http.StatusInternalServerError, "method RenderLogin not implemented") +} + +func (UnimplementedWebCoreRender) RenderLogout(c *gin.Context, err error) { + c.String(http.StatusInternalServerError, "method RenderLogout not implemented") +} + +func (UnimplementedWebCoreRender) mustEmbedUnimplementedWebCoreRender() {} diff --git a/internal/mirc/main.go b/internal/mirc/main.go new file mode 100644 index 00000000..c2e47411 --- /dev/null +++ b/internal/mirc/main.go @@ -0,0 +1,24 @@ +package main + +import ( + "log" + + . "github.com/alimy/mir/v3/core" + . "github.com/alimy/mir/v3/engine" + + _ "github.com/rocboss/paopao-ce/internal/mirc/routes/v1" +) + +//go:generate go run main.go +func main() { + log.Println("generate code start") + opts := Options{ + RunMode(InSerialMode), + GeneratorName(GeneratorGin), + SinkPath("auto"), + } + if err := Generate(opts); err != nil { + log.Fatal(err) + } + log.Println("generate code finish") +} diff --git a/internal/mirc/routes/README.md b/internal/mirc/routes/README.md new file mode 100644 index 00000000..0d7ac0c1 --- /dev/null +++ b/internal/mirc/routes/README.md @@ -0,0 +1 @@ +### RESTful API for paopao-ce diff --git a/internal/mirc/routes/v1/localoss.go b/internal/mirc/routes/v1/localoss.go new file mode 100644 index 00000000..bf2d09d8 --- /dev/null +++ b/internal/mirc/routes/v1/localoss.go @@ -0,0 +1,15 @@ +package v1 + +import ( + . "github.com/alimy/mir/v3" + . "github.com/alimy/mir/v3/engine" +) + +func init() { + AddEntry(new(LocalOSS)) +} + +type LocalOSS struct { + Chain Chain `mir:"-"` + Group Group `mir:"v1"` +} diff --git a/internal/mirc/routes/v1/web_admin.go b/internal/mirc/routes/v1/web_admin.go new file mode 100644 index 00000000..db95fc86 --- /dev/null +++ b/internal/mirc/routes/v1/web_admin.go @@ -0,0 +1,15 @@ +package v1 + +import ( + . "github.com/alimy/mir/v3" + . "github.com/alimy/mir/v3/engine" +) + +func init() { + AddEntry(new(WebAdmin)) +} + +type WebAdmin struct { + Chain Chain `mir:"-"` + Group Group `mir:"v1"` +} diff --git a/internal/mirc/routes/v1/web_alipay.go b/internal/mirc/routes/v1/web_alipay.go new file mode 100644 index 00000000..61de0906 --- /dev/null +++ b/internal/mirc/routes/v1/web_alipay.go @@ -0,0 +1,15 @@ +package v1 + +import ( + . "github.com/alimy/mir/v3" + . "github.com/alimy/mir/v3/engine" +) + +func init() { + AddEntry(new(WebAlipay)) +} + +type WebAlipay struct { + Chain Chain `mir:"-"` + Group Group `mir:"v1"` +} diff --git a/internal/mirc/routes/v1/web_core.go b/internal/mirc/routes/v1/web_core.go new file mode 100644 index 00000000..565fb04a --- /dev/null +++ b/internal/mirc/routes/v1/web_core.go @@ -0,0 +1,44 @@ +package v1 + +import ( + . "github.com/alimy/mir/v3" + . "github.com/alimy/mir/v3/engine" +) + +func init() { + AddEntry(new(WebCore)) +} + +type AgentInfo struct { + Platform string `json:"platform"` + UserAgent string `json:"user_agent"` +} + +type ServerInfo struct { + ApiVer string `json:"api_ver"` +} + +type UserInfo struct { + Name string `json:"name"` +} + +type LoginReq struct { + AgentInfo AgentInfo `json:"agent_info"` + Name string `json:"name"` + Passwd string `json:"passwd"` +} + +type LoginResp struct { + UserInfo + ServerInfo ServerInfo `json:"server_info"` + JwtToken string `json:"jwt_token"` +} + +type WebCore struct { + Chain Chain `mir:"-"` + Group Group `mir:"v1"` + Index func(Get) `mir:"/index/"` + Articles func(Get) `mir:"/articles/:category/"` + Login func(Post, LoginReq) LoginResp `mir:"/user/login/"` + Logout func(Post) `mir:"/user/logout/"` +} diff --git a/internal/mirc/routes/v1/web_followship.go b/internal/mirc/routes/v1/web_followship.go new file mode 100644 index 00000000..1dd9de82 --- /dev/null +++ b/internal/mirc/routes/v1/web_followship.go @@ -0,0 +1,15 @@ +package v1 + +import ( + . "github.com/alimy/mir/v3" + . "github.com/alimy/mir/v3/engine" +) + +func init() { + AddEntry(new(WebFollowship)) +} + +type WebFollowship struct { + Chain Chain `mir:"-"` + Group Group `mir:"v1"` +} diff --git a/internal/mirc/routes/v1/web_friendship.go b/internal/mirc/routes/v1/web_friendship.go new file mode 100644 index 00000000..e1276e99 --- /dev/null +++ b/internal/mirc/routes/v1/web_friendship.go @@ -0,0 +1,15 @@ +package v1 + +import ( + . "github.com/alimy/mir/v3" + . "github.com/alimy/mir/v3/engine" +) + +func init() { + AddEntry(new(WebFriendship)) +} + +type WebFriendship struct { + Chain Chain `mir:"-"` + Group Group `mir:"v1"` +} diff --git a/internal/mirc/routes/v1/web_loose.go b/internal/mirc/routes/v1/web_loose.go new file mode 100644 index 00000000..7eff7d44 --- /dev/null +++ b/internal/mirc/routes/v1/web_loose.go @@ -0,0 +1,15 @@ +package v1 + +import ( + . "github.com/alimy/mir/v3" + . "github.com/alimy/mir/v3/engine" +) + +func init() { + AddEntry(new(WebLoose)) +} + +type WebLoose struct { + Chain Chain `mir:"-"` + Group Group `mir:"v1"` +} diff --git a/internal/mirc/routes/v1/web_priv.go b/internal/mirc/routes/v1/web_priv.go new file mode 100644 index 00000000..3d73eb1b --- /dev/null +++ b/internal/mirc/routes/v1/web_priv.go @@ -0,0 +1,15 @@ +package v1 + +import ( + . "github.com/alimy/mir/v3" + . "github.com/alimy/mir/v3/engine" +) + +func init() { + AddEntry(new(WebPriv)) +} + +type WebPriv struct { + Chain Chain `mir:"-"` + Group Group `mir:"v1"` +} diff --git a/internal/mirc/routes/v1/web_pub.go b/internal/mirc/routes/v1/web_pub.go new file mode 100644 index 00000000..7bfe2e3a --- /dev/null +++ b/internal/mirc/routes/v1/web_pub.go @@ -0,0 +1,15 @@ +package v1 + +import ( + . "github.com/alimy/mir/v3" + . "github.com/alimy/mir/v3/engine" +) + +func init() { + AddEntry(new(WebPub)) +} + +type WebPub struct { + Chain Chain `mir:"-"` + Group Group `mir:"v1"` +} diff --git a/internal/servants/chain/admin.go b/internal/servants/chain/admin.go new file mode 100644 index 00000000..846d6b68 --- /dev/null +++ b/internal/servants/chain/admin.go @@ -0,0 +1,25 @@ +package chain + +import ( + "github.com/gin-gonic/gin" + "github.com/rocboss/paopao-ce/internal/model" + "github.com/rocboss/paopao-ce/pkg/app" + "github.com/rocboss/paopao-ce/pkg/errcode" +) + +func Admin() gin.HandlerFunc { + return func(c *gin.Context) { + if user, exist := c.Get("USER"); exist { + if userModel, ok := user.(*model.User); ok { + if userModel.Status == model.UserStatusNormal && userModel.IsAdmin { + c.Next() + return + } + } + } + + response := app.NewResponse(c) + response.ToErrorResponse(errcode.NoAdminPermission) + c.Abort() + } +} diff --git a/internal/servants/chain/jwt.go b/internal/servants/chain/jwt.go new file mode 100644 index 00000000..75a4c9ad --- /dev/null +++ b/internal/servants/chain/jwt.go @@ -0,0 +1,113 @@ +package chain + +import ( + "strings" + + "github.com/gin-gonic/gin" + "github.com/golang-jwt/jwt/v4" + "github.com/rocboss/paopao-ce/internal/conf" + "github.com/rocboss/paopao-ce/internal/model" + "github.com/rocboss/paopao-ce/pkg/app" + "github.com/rocboss/paopao-ce/pkg/errcode" +) + +func JWT() gin.HandlerFunc { + // TODO: optimize get user from a simple service that provide fetch a user info interface. + db := conf.MustGormDB() + return func(c *gin.Context) { + var ( + token string + ecode = errcode.Success + ) + if s, exist := c.GetQuery("token"); exist { + token = s + } else { + token = c.GetHeader("Authorization") + + // 验证前端传过来的token格式,不为空,开头为Bearer + if token == "" || !strings.HasPrefix(token, "Bearer ") { + response := app.NewResponse(c) + response.ToErrorResponse(errcode.UnauthorizedTokenError) + c.Abort() + return + } + + // 验证通过,提取有效部分(除去Bearer) + token = token[7:] + } + if token == "" { + ecode = errcode.InvalidParams + } else { + claims, err := app.ParseToken(token) + if err != nil { + switch err.(*jwt.ValidationError).Errors { + case jwt.ValidationErrorExpired: + ecode = errcode.UnauthorizedTokenTimeout + default: + ecode = errcode.UnauthorizedTokenError + } + } else { + c.Set("UID", claims.UID) + c.Set("USERNAME", claims.Username) + + // 加载用户信息 + user := &model.User{ + Model: &model.Model{ + ID: claims.UID, + }, + } + user, _ = user.Get(db) + c.Set("USER", user) + + // 强制下线机制 + if (conf.JWTSetting.Issuer + ":" + user.Salt) != claims.Issuer { + ecode = errcode.UnauthorizedTokenTimeout + } + } + } + + if ecode != errcode.Success { + response := app.NewResponse(c) + response.ToErrorResponse(ecode) + c.Abort() + return + } + + c.Next() + } +} + +func JwtLoose() gin.HandlerFunc { + // TODO: optimize get user from a simple service that provide fetch a user info interface. + db := conf.MustGormDB() + return func(c *gin.Context) { + token, exist := c.GetQuery("token") + if !exist { + token = c.GetHeader("Authorization") + // 验证前端传过来的token格式,不为空,开头为Bearer + if strings.HasPrefix(token, "Bearer ") { + // 验证通过,提取有效部分(除去Bearer) + token = token[7:] + } else { + c.Next() + } + } + if len(token) > 0 { + if claims, err := app.ParseToken(token); err == nil { + c.Set("UID", claims.UID) + c.Set("USERNAME", claims.Username) + // 加载用户信息 + user := &model.User{ + Model: &model.Model{ + ID: claims.UID, + }, + } + user, err := user.Get(db) + if err == nil && (conf.JWTSetting.Issuer+":"+user.Salt) == claims.Issuer { + c.Set("USER", user) + } + } + } + c.Next() + } +} diff --git a/internal/servants/chain/priv.go b/internal/servants/chain/priv.go new file mode 100644 index 00000000..60409b6b --- /dev/null +++ b/internal/servants/chain/priv.go @@ -0,0 +1,45 @@ +package chain + +import ( + "github.com/gin-gonic/gin" + "github.com/rocboss/paopao-ce/internal/conf" + "github.com/rocboss/paopao-ce/internal/model" + "github.com/rocboss/paopao-ce/pkg/app" + "github.com/rocboss/paopao-ce/pkg/errcode" +) + +func Priv() gin.HandlerFunc { + if conf.CfgIf("PhoneBind") { + return func(c *gin.Context) { + if u, exist := c.Get("USER"); exist { + if user, ok := u.(*model.User); ok { + if user.Status == model.UserStatusNormal { + if user.Phone == "" { + response := app.NewResponse(c) + response.ToErrorResponse(errcode.AccountNoPhoneBind) + c.Abort() + return + } + c.Next() + return + } + } + } + response := app.NewResponse(c) + response.ToErrorResponse(errcode.UserHasBeenBanned) + c.Abort() + } + } else { + return func(c *gin.Context) { + if u, exist := c.Get("USER"); exist { + if user, ok := u.(*model.User); ok && user.Status == model.UserStatusNormal { + c.Next() + return + } + } + response := app.NewResponse(c) + response.ToErrorResponse(errcode.UserHasBeenBanned) + c.Abort() + } + } +} diff --git a/internal/servants/core.go b/internal/servants/core.go new file mode 100644 index 00000000..6deb274c --- /dev/null +++ b/internal/servants/core.go @@ -0,0 +1,26 @@ +package servants + +import ( + "github.com/gin-gonic/gin" + "github.com/rocboss/paopao-ce/internal/model" +) + +type baseServant struct { + // TODO +} + +type baseBinding struct { + // TODO +} + +type baseRender struct { + // TODO +} + +func (baseServant) userFrom(c *gin.Context) (*model.User, bool) { + if u, exists := c.Get("USER"); exists { + user, ok := u.(*model.User) + return user, ok + } + return nil, false +} diff --git a/internal/servants/localoss.go b/internal/servants/localoss.go new file mode 100644 index 00000000..b99a78f0 --- /dev/null +++ b/internal/servants/localoss.go @@ -0,0 +1,5 @@ +package servants + +type localossSrv struct { + // TODO +} diff --git a/internal/servants/servants.go b/internal/servants/servants.go new file mode 100644 index 00000000..cc808cdb --- /dev/null +++ b/internal/servants/servants.go @@ -0,0 +1,12 @@ +package servants + +import ( + "github.com/gin-gonic/gin" + + api "github.com/rocboss/paopao-ce/internal/mirc/auto/api/v1" +) + +// RegisterServants register all the servants to gin.Engine +func RegisterServants(e *gin.Engine) { + api.RegisterWebCoreServant(e, newWebCoreSrv(), newWebCoreBinding(), newWebCoreRender()) +} diff --git a/internal/servants/web_admin.go b/internal/servants/web_admin.go new file mode 100644 index 00000000..f527df8a --- /dev/null +++ b/internal/servants/web_admin.go @@ -0,0 +1,5 @@ +package servants + +type webAdminSrv struct { + // TODO +} diff --git a/internal/servants/web_alipay.go b/internal/servants/web_alipay.go new file mode 100644 index 00000000..680a3df8 --- /dev/null +++ b/internal/servants/web_alipay.go @@ -0,0 +1,5 @@ +package servants + +type webAlipaySrv struct { + // TODO +} diff --git a/internal/servants/web_core.go b/internal/servants/web_core.go new file mode 100644 index 00000000..027676b8 --- /dev/null +++ b/internal/servants/web_core.go @@ -0,0 +1,32 @@ +package servants + +import ( + api "github.com/rocboss/paopao-ce/internal/mirc/auto/api/v1" +) + +type webCoreSrv struct { + baseServant + api.UnimplementedWebCoreServant +} + +type webCoreBinding struct { + baseBinding + api.UnimplementedWebCoreBinding +} + +type webCoreRender struct { + baseRender + api.UnimplementedWebCoreRender +} + +func newWebCoreSrv() api.WebCore { + return &webCoreSrv{} +} + +func newWebCoreBinding() api.WebCoreBinding { + return &webCoreBinding{} +} + +func newWebCoreRender() api.WebCoreRender { + return &webCoreRender{} +} diff --git a/internal/servants/web_followship.go b/internal/servants/web_followship.go new file mode 100644 index 00000000..f069d8e7 --- /dev/null +++ b/internal/servants/web_followship.go @@ -0,0 +1,5 @@ +package servants + +type webFollowshipSrv struct { + // TODO +} diff --git a/internal/servants/web_friendship.go b/internal/servants/web_friendship.go new file mode 100644 index 00000000..63bd9896 --- /dev/null +++ b/internal/servants/web_friendship.go @@ -0,0 +1,5 @@ +package servants + +type webFriendshipSrv struct { + // TODO +} diff --git a/internal/servants/web_loose.go b/internal/servants/web_loose.go new file mode 100644 index 00000000..04eaa907 --- /dev/null +++ b/internal/servants/web_loose.go @@ -0,0 +1,5 @@ +package servants + +type webLooseSrv struct { + // TODO +} diff --git a/internal/servants/web_priv.go b/internal/servants/web_priv.go new file mode 100644 index 00000000..8a0a830e --- /dev/null +++ b/internal/servants/web_priv.go @@ -0,0 +1,5 @@ +package servants + +type webPrivSrv struct { + // TODO +} diff --git a/internal/servants/web_pub.go b/internal/servants/web_pub.go new file mode 100644 index 00000000..d66a09b2 --- /dev/null +++ b/internal/servants/web_pub.go @@ -0,0 +1,5 @@ +package servants + +type webPubSrv struct { + // TODO +}