257 lines
6.5 KiB
Go
257 lines
6.5 KiB
Go
package model
|
|
|
|
import (
|
|
"context"
|
|
"time"
|
|
|
|
"gorm.io/gorm"
|
|
"gorm.io/gorm/clause"
|
|
|
|
"spark-server/internal/module/moment/entity"
|
|
"spark-server/internal/pkg/errs"
|
|
)
|
|
|
|
func (m *Repo) CreatePost(ctx context.Context, post *entity.Post, audience []int64) error {
|
|
if post == nil || post.ID <= 0 || post.UserID <= 0 {
|
|
return errs.ErrInvalidArgument
|
|
}
|
|
db, err := m.session(ctx)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
row := postFrom(post)
|
|
if row.CreatedAt.IsZero() {
|
|
row.CreatedAt = time.Now()
|
|
}
|
|
return db.Transaction(func(tx *gorm.DB) error {
|
|
if err := tx.Create(row).Error; err != nil {
|
|
return mapDBErr(err)
|
|
}
|
|
for _, peer := range audience {
|
|
if err := tx.Create(&Audience{PostID: post.ID, PeerID: peer}).Error; err != nil {
|
|
return mapDBErr(err)
|
|
}
|
|
}
|
|
return nil
|
|
})
|
|
}
|
|
|
|
func (m *Repo) SoftDeletePost(ctx context.Context, userID, postID int64) (*entity.Post, error) {
|
|
db, err := m.session(ctx)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
var row Post
|
|
err = db.Transaction(func(tx *gorm.DB) error {
|
|
if err := tx.Where("id = ? AND user_id = ?", postID, userID).Take(&row).Error; err != nil {
|
|
return mapDBErr(err)
|
|
}
|
|
if row.Status == int16(entity.StatusDeleted) {
|
|
return errs.ErrNotFound
|
|
}
|
|
res := tx.Model(&row).Update("status", entity.StatusDeleted)
|
|
if res.Error != nil {
|
|
return mapDBErr(res.Error)
|
|
}
|
|
if res.RowsAffected == 0 {
|
|
return errs.ErrNotFound
|
|
}
|
|
row.Status = int16(entity.StatusDeleted)
|
|
return nil
|
|
})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return row.Entity(), nil
|
|
}
|
|
|
|
func (m *Repo) AddLike(ctx context.Context, like *entity.Like) (bool, error) {
|
|
if like == nil || like.PostID <= 0 || like.UserID <= 0 {
|
|
return false, errs.ErrInvalidArgument
|
|
}
|
|
db, err := m.session(ctx)
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
row := Like{PostID: like.PostID, UserID: like.UserID, CreatedAt: time.Now()}
|
|
if like.CreatedAtMS > 0 {
|
|
row.CreatedAt = time.UnixMilli(like.CreatedAtMS)
|
|
}
|
|
created := false
|
|
err = db.Transaction(func(tx *gorm.DB) error {
|
|
res := tx.Clauses(clause.OnConflict{DoNothing: true}).Create(&row)
|
|
if res.Error != nil {
|
|
return mapDBErr(res.Error)
|
|
}
|
|
if res.RowsAffected == 0 {
|
|
return nil
|
|
}
|
|
created = true
|
|
return bumpCount(tx, like.PostID, "like_count", 1)
|
|
})
|
|
return created, err
|
|
}
|
|
|
|
func (m *Repo) RemoveLike(ctx context.Context, postID, userID int64) error {
|
|
db, err := m.session(ctx)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return db.Transaction(func(tx *gorm.DB) error {
|
|
res := tx.Where("post_id = ? AND user_id = ?", postID, userID).Delete(&Like{})
|
|
if res.Error != nil {
|
|
return mapDBErr(res.Error)
|
|
}
|
|
if res.RowsAffected == 0 {
|
|
return errs.ErrNotFound
|
|
}
|
|
return bumpCount(tx, postID, "like_count", -1)
|
|
})
|
|
}
|
|
|
|
func (m *Repo) AddComment(ctx context.Context, c *entity.Comment) error {
|
|
if c == nil || c.ID <= 0 || c.PostID <= 0 || c.UserID <= 0 {
|
|
return errs.ErrInvalidArgument
|
|
}
|
|
db, err := m.session(ctx)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
row := commentFrom(c)
|
|
if row.CreatedAt.IsZero() {
|
|
row.CreatedAt = time.Now()
|
|
}
|
|
return db.Transaction(func(tx *gorm.DB) error {
|
|
if err := tx.Create(row).Error; err != nil {
|
|
return mapDBErr(err)
|
|
}
|
|
return bumpCount(tx, c.PostID, "comment_count", 1)
|
|
})
|
|
}
|
|
|
|
func (m *Repo) SoftDeleteComment(ctx context.Context, id int64) error {
|
|
db, err := m.session(ctx)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return db.Transaction(func(tx *gorm.DB) error {
|
|
var row Comment
|
|
if err := tx.Where("id = ?", id).Take(&row).Error; err != nil {
|
|
return mapDBErr(err)
|
|
}
|
|
if row.Status == int16(entity.StatusDeleted) {
|
|
return errs.ErrNotFound
|
|
}
|
|
if err := tx.Model(&row).Update("status", entity.StatusDeleted).Error; err != nil {
|
|
return mapDBErr(err)
|
|
}
|
|
return bumpCount(tx, row.PostID, "comment_count", -1)
|
|
})
|
|
}
|
|
|
|
func (m *Repo) CreateNotices(ctx context.Context, rows []*entity.Notice) error {
|
|
if len(rows) == 0 {
|
|
return nil
|
|
}
|
|
db, err := m.session(ctx)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
now := time.Now()
|
|
for _, n := range rows {
|
|
row := Notice{
|
|
ID: n.ID, ToUserID: n.ToUserID, FromUserID: n.FromUserID, Kind: int16(n.Kind),
|
|
PostID: n.PostID, CommentID: n.CommentID, CreatedAt: now,
|
|
}
|
|
if n.CreatedAtMS > 0 {
|
|
row.CreatedAt = time.UnixMilli(n.CreatedAtMS)
|
|
}
|
|
if err := db.Create(&row).Error; err != nil {
|
|
return mapDBErr(err)
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (m *Repo) MarkNoticesRead(ctx context.Context, userID, cursor int64) error {
|
|
db, err := m.session(ctx)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
q := db.Model(&Notice{}).Where("to_user_id = ? AND read_at IS NULL", userID)
|
|
if cursor > 0 {
|
|
q = q.Where("id <= ?", cursor)
|
|
}
|
|
return mapDBErr(q.Update("read_at", time.Now()).Error)
|
|
}
|
|
|
|
func (m *Repo) UpsertSettings(ctx context.Context, s *entity.Settings) error {
|
|
if s == nil || s.UserID <= 0 {
|
|
return errs.ErrInvalidArgument
|
|
}
|
|
db, err := m.session(ctx)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
row := settingFrom(s)
|
|
if row.UpdatedAt.IsZero() {
|
|
row.UpdatedAt = time.Now()
|
|
}
|
|
return mapDBErr(db.Save(row).Error)
|
|
}
|
|
|
|
func (m *Repo) AdvanceRead(ctx context.Context, userID, postID int64) error {
|
|
if userID <= 0 || postID <= 0 {
|
|
return errs.ErrInvalidArgument
|
|
}
|
|
cur, err := m.GetSettings(ctx, userID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if cur.LastReadPostID >= postID {
|
|
return nil
|
|
}
|
|
cur.LastReadPostID = postID
|
|
cur.UpdatedAtMS = time.Now().UnixMilli()
|
|
return m.UpsertSettings(ctx, cur)
|
|
}
|
|
|
|
func (m *Repo) UpsertHide(ctx context.Context, h *entity.Hide) error {
|
|
if h == nil || h.UserID <= 0 || h.PeerID <= 0 {
|
|
return errs.ErrInvalidArgument
|
|
}
|
|
db, err := m.session(ctx)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
row := Hide{UserID: h.UserID, PeerID: h.PeerID, HideHim: h.HideHim, HideMe: h.HideMe}
|
|
return mapDBErr(db.Clauses(clause.OnConflict{
|
|
Columns: []clause.Column{{Name: "user_id"}, {Name: "peer_id"}},
|
|
DoUpdates: clause.AssignmentColumns([]string{"hide_him", "hide_me"}),
|
|
}).Create(&row).Error)
|
|
}
|
|
|
|
func (m *Repo) DeleteHide(ctx context.Context, userID, peerID int64) error {
|
|
db, err := m.session(ctx)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
res := db.Where("user_id = ? AND peer_id = ?", userID, peerID).Delete(&Hide{})
|
|
if res.Error != nil {
|
|
return mapDBErr(res.Error)
|
|
}
|
|
if res.RowsAffected == 0 {
|
|
return errs.ErrNotFound
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func bumpCount(tx *gorm.DB, postID int64, col string, delta int) error {
|
|
expr := col + " + ?"
|
|
if delta < 0 {
|
|
expr = "CASE WHEN " + col + " + ? < 0 THEN 0 ELSE " + col + " + ? END"
|
|
return mapDBErr(tx.Model(&Post{}).Where("id = ?", postID).Update(col, gorm.Expr(expr, delta, delta)).Error)
|
|
}
|
|
return mapDBErr(tx.Model(&Post{}).Where("id = ?", postID).Update(col, gorm.Expr(expr, delta)).Error)
|
|
}
|