diff --git a/internal/dao/slonik/authority.go b/internal/dao/slonik/authority.go index f72fdc4d..4d022cc0 100644 --- a/internal/dao/slonik/authority.go +++ b/internal/dao/slonik/authority.go @@ -5,10 +5,15 @@ package slonik import ( + "context" + "strconv" + "github.com/jackc/pgx/v5" "github.com/rocboss/paopao-ce/internal/core" "github.com/rocboss/paopao-ce/internal/core/ms" - "github.com/rocboss/paopao-ce/pkg/debug" + "github.com/rocboss/paopao-ce/internal/dao/slonik/sqlc/auto/pgc" + "github.com/rocboss/paopao-ce/pkg/types" + "github.com/sirupsen/logrus" ) var ( @@ -16,41 +21,57 @@ var ( ) type authorizationManageSrv struct { - *pgxSrv + *pgcSrv } func (s *authorizationManageSrv) IsAllow(user *ms.User, action *ms.Action) bool { - // TODO - debug.NotImplemented() - return false + // user is activation if had bind phone + isActivation := (len(user.Phone) != 0) + isFriend := s.isFriend(user.ID, action.UserId) + // TODO: just use defaut act authorization chek rule now + return action.Act.IsAllow(user, action.UserId, isFriend, isActivation) } func (s *authorizationManageSrv) MyFriendSet(userId int64) ms.FriendSet { - // TODO - debug.NotImplemented() - return nil + ids, err := s.q.MyFriendSet(context.Background(), userId) + if err != nil { + logrus.Warnf("get my FriendSet error: %s", err) + return ms.FriendSet{} + } + resp := make(ms.FriendSet, len(ids)) + for _, id := range ids { + resp[strconv.FormatInt(id, 10)] = types.Empty{} + } + return resp } func (s *authorizationManageSrv) BeFriendFilter(userId int64) ms.FriendFilter { - // TODO - debug.NotImplemented() - return nil + ids, err := s.q.BeFriendIds(context.Background(), userId) + if err != nil { + logrus.Warnf("get my BeFriendFilter error: %s", err) + return ms.FriendFilter{} + } + resp := make(ms.FriendFilter, len(ids)) + for _, id := range ids { + resp[id] = types.Empty{} + } + return resp } func (s *authorizationManageSrv) BeFriendIds(userId int64) ([]int64, error) { - // TODO - debug.NotImplemented() - return nil, nil + return s.q.BeFriendIds(context.Background(), userId) } func (s *authorizationManageSrv) isFriend(userId int64, friendId int64) bool { - // TODO - debug.NotImplemented() - return false + ok, _ := s.q.IsFriend(context.Background(), &pgc.IsFriendParams{ + UserID: userId, + FriendID: friendId, + }) + return ok } func newAuthorizationManageService(db *pgx.Conn) core.AuthorizationManageService { return &authorizationManageSrv{ - pgxSrv: newPgxSrv(db), + pgcSrv: newPgcSrv(db), } } diff --git a/internal/dao/slonik/comments.go b/internal/dao/slonik/comments.go index 973a74f5..72e19a3a 100644 --- a/internal/dao/slonik/comments.go +++ b/internal/dao/slonik/comments.go @@ -5,11 +5,15 @@ package slonik import ( + "context" + "time" + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgtype" "github.com/rocboss/paopao-ce/internal/core" "github.com/rocboss/paopao-ce/internal/core/cs" "github.com/rocboss/paopao-ce/internal/core/ms" - "github.com/rocboss/paopao-ce/pkg/debug" + "github.com/rocboss/paopao-ce/internal/dao/slonik/sqlc/auto/pgc" ) var ( @@ -18,110 +22,540 @@ var ( ) type commentSrv struct { - *pgxSrv + *pgcSrv } type commentManageSrv struct { - *pgxSrv + *pgcSrv } -func (s *commentSrv) GetComments(tweetId int64, style cs.StyleCommentType, limit int, offset int) ([]*ms.Comment, int64, error) { - // TODO - return nil, 0, cs.ErrNotImplemented +func (s *commentSrv) GetComments(tweetId int64, style cs.StyleCommentType, limit int, offset int) (res []*ms.Comment, total int64, err error) { + c := context.Background() + if total, err = s.q.GetCommentCount(c, tweetId); err != nil && total == 0 { + return + } + var ( + comments []*pgc.PComment + ) + switch style { + case cs.StyleCommentHots: + comments, err = s.q.GetHotsComments(c, &pgc.GetHotsCommentsParams{ + PostID: tweetId, + Limit: int32(limit), + Offset: int32(offset), + }) + case cs.StyleCommentNewest: + comments, err = s.q.GetNewestComments(c, &pgc.GetNewestCommentsParams{ + PostID: tweetId, + Limit: int32(limit), + Offset: int32(offset), + }) + case cs.StyleCommentDefault: + fallthrough + default: + comments, err = s.q.GetDefaultComments(c, &pgc.GetDefaultCommentsParams{ + PostID: tweetId, + Limit: int32(limit), + Offset: int32(offset), + }) + } + for _, comment := range comments { + res = append(res, &ms.Comment{ + Model: &ms.Model{ + ID: comment.ID, + CreatedOn: comment.CreatedOn, + ModifiedOn: comment.ModifiedOn, + }, + PostID: comment.PostID, + UserID: comment.UserID, + IPLoc: comment.IpLoc, + IsEssence: int8(comment.IsEssence), + ReplyCount: comment.ReplyCount, + ThumbsUpCount: comment.ThumbsUpCount, + ThumbsDownCount: comment.ThumbsDownCount, + }) + } + return } func (s *commentSrv) GetCommentByID(id int64) (*ms.Comment, error) { - // TODO - debug.NotImplemented() - return nil, nil + comment, err := s.q.GetCommentById(context.Background(), id) + if err != nil { + return nil, err + } + return &ms.Comment{ + Model: &ms.Model{ + ID: comment.ID, + CreatedOn: comment.CreatedOn, + }, + PostID: comment.PostID, + UserID: comment.UserID, + IPLoc: comment.IpLoc, + IsEssence: int8(comment.IsEssence), + ReplyCount: comment.ReplyCount, + ThumbsUpCount: comment.ThumbsUpCount, + ThumbsDownCount: comment.ThumbsDownCount, + }, nil } func (s *commentSrv) GetCommentReplyByID(id int64) (*ms.CommentReply, error) { - // TODO - debug.NotImplemented() - return nil, nil + reply, err := s.q.GetCommentReplyById(context.Background(), id) + if err != nil { + return nil, err + } + return &ms.CommentReply{ + Model: &ms.Model{ + ID: reply.ID, + CreatedOn: reply.CreatedOn, + }, + CommentID: reply.CommentID, + UserID: reply.UserID, + AtUserID: reply.AtUserID, + Content: reply.Content, + IP: reply.Ip, + IPLoc: reply.IpLoc, + ThumbsUpCount: reply.ThumbsUpCount, + ThumbsDownCount: reply.ThumbsDownCount, + }, nil } -func (s *commentSrv) GetCommentContentsByIDs(ids []int64) ([]*ms.CommentContent, error) { - // TODO - debug.NotImplemented() +func (s *commentSrv) GetCommentContentsByIDs(ids []int64) (res []*ms.CommentContent, _ error) { + if len(ids) == 0 { + return []*ms.CommentContent{}, nil + } + contents, err := s.q.GetCommentContentsByIds(context.Background(), ids) + if err != nil { + return nil, err + } + for _, content := range contents { + res = append(res, &ms.CommentContent{ + Model: &ms.Model{ + ID: content.ID, + CreatedOn: content.CreatedOn, + }, + CommentID: content.CommentID, + UserID: content.UserID, + Content: content.Content, + Type: ms.PostContentT(content.Type), + Sort: content.Sort, + }) + } return nil, nil } func (s *commentSrv) GetCommentRepliesByID(ids []int64) ([]*ms.CommentReplyFormated, error) { - // TODO - debug.NotImplemented() - return nil, nil + if len(ids) == 0 { + return nil, nil + } + ctx := context.Background() + replies, err := s.q.GetCommentRepliesByIds(ctx, ids) + if err != nil { + return nil, err + } + userIds := []int64{} + for _, reply := range replies { + userIds = append(userIds, reply.UserID, reply.AtUserID) + } + var users []*pgc.PUser + if len(userIds) > 0 { + users, err = s.q.GetUsersByIds(ctx, userIds) + if err != nil { + return nil, err + } + } + repliesFormated := []*ms.CommentReplyFormated{} + for _, reply := range replies { + replyFormated := &ms.CommentReplyFormated{ + ID: reply.ID, + CommentID: reply.CommentID, + UserID: reply.UserID, + AtUserID: reply.AtUserID, + Content: reply.Content, + IPLoc: reply.IpLoc, + ThumbsUpCount: reply.ThumbsUpCount, + CreatedOn: reply.CreatedOn, + ModifiedOn: reply.ModifiedOn, + } + for _, user := range users { + formatedUser := &ms.UserFormated{ + ID: user.ID, + Nickname: user.Nickname, + Status: int(user.Status), + Avatar: user.Avatar, + IsAdmin: user.IsAdmin, + } + if reply.UserID == user.ID { + replyFormated.User = formatedUser + } + if reply.AtUserID == user.ID { + replyFormated.AtUser = formatedUser + } + } + repliesFormated = append(repliesFormated, replyFormated) + } + return repliesFormated, nil } func (s *commentSrv) GetCommentThumbsMap(userId int64, tweetId int64) (cs.CommentThumbsMap, cs.CommentThumbsMap, error) { - // TODO - return nil, nil, debug.ErrNotImplemented + if userId < 0 { + return nil, nil, nil + } + ctx := context.Background() + commentThumbsList, err := s.q.GetCommentThumbs(ctx, &pgc.GetCommentThumbsParams{ + UserID: userId, + TweetID: tweetId, + }) + if err != nil { + return nil, nil, err + } + commentThumbs, replyThumbs := make(cs.CommentThumbsMap), make(cs.CommentThumbsMap) + for _, thumb := range commentThumbsList { + commentThumb := &cs.CommentThumbs{ + UserID: thumb.UserID, + TweetID: thumb.TweetID, + CommentID: thumb.CommentID, + ReplyID: thumb.ReplyID.Int64, + CommentType: int8(thumb.CommentType), + IsThumbsUp: int8(thumb.IsThumbsUp), + IsThumbsDown: int8(thumb.IsThumbsDown), + } + if thumb.CommentType == 0 { + commentThumbs[thumb.CommentID] = commentThumb + } else { + replyThumbs[thumb.ReplyID.Int64] = commentThumb + } + } + return commentThumbs, replyThumbs, nil } func (s *commentManageSrv) DeleteComment(comment *ms.Comment) error { - // TODO - debug.NotImplemented() - return nil + return with(s.db, s.q.WithTx, func(c context.Context, q *pgc.Queries) error { + now := time.Now().Unix() + err := q.DeleteComment(c, &pgc.DeleteCommentParams{ + DeletedOn: now, + ID: comment.ID, + }) + if err != nil { + return err + } + return q.DeleteCommentThumbs(c, &pgc.DeleteCommentThumbsParams{ + DeletedOn: now, + UserID: comment.UserID, + TweetID: comment.PostID, + CommentID: comment.ID, + }) + }) } -func (s *commentManageSrv) HighlightComment(userId, commentId int64) (res int8, err error) { - // TODO - return 0, cs.ErrNotImplemented +func (s *commentManageSrv) HighlightComment(userId, commentId int64) (int8, error) { + res, err := s.q.HighlightComment(context.Background(), &pgc.HighlightCommentParams{ + UserID: userId, + ID: commentId, + ModifiedOn: time.Now().Unix(), + }) + return int8(res), err } -func (s *commentManageSrv) CreateComment(comment *ms.Comment) (*ms.Comment, error) { - // TODO - debug.NotImplemented() - return nil, nil +func (s *commentManageSrv) CreateComment(comment *ms.Comment) (res *ms.Comment, err error) { + res, comment.Model = comment, &ms.Model{CreatedOn: time.Now().Unix()} + res.ID, err = s.q.CreateComment(context.Background(), &pgc.CreateCommentParams{ + PostID: comment.PostID, + UserID: comment.UserID, + Ip: comment.IP, + IpLoc: comment.IPLoc, + CreatedOn: res.CreatedOn, + }) + return } -func (s *commentManageSrv) CreateCommentReply(reply *ms.CommentReply) (*ms.CommentReply, error) { - // TODO - debug.NotImplemented() - return nil, nil +func (s *commentManageSrv) CreateCommentReply(reply *ms.CommentReply) (res *ms.CommentReply, err error) { + res, reply.Model = reply, &ms.Model{CreatedOn: time.Now().Unix()} + res.ID, err = s.q.CreateCommentReply(context.Background(), &pgc.CreateCommentReplyParams{ + CommentID: reply.CommentID, + UserID: reply.UserID, + Content: reply.Content, + AtUserID: reply.AtUserID, + Ip: reply.IP, + IpLoc: reply.IPLoc, + CreatedOn: reply.CreatedOn, + }) + return } func (s *commentManageSrv) DeleteCommentReply(reply *ms.CommentReply) error { - // TODO - debug.NotImplemented() - return nil + return with(s.db, s.q.WithTx, func(c context.Context, q *pgc.Queries) error { + now := time.Now().Unix() + err := q.DeleteCommentReply(c, &pgc.DeleteCommentReplyParams{ + DeletedOn: now, + ID: reply.ID, + }) + if err != nil { + return err + } + return q.DeleteReplyThumbs(c, &pgc.DeleteReplyThumbsParams{ + DeletedOn: now, + UserID: reply.UserID, + CommentID: reply.CommentID, + ReplyID: pgtype.Int8{Int64: reply.ID, Valid: true}, + }) + }) } -func (s *commentManageSrv) CreateCommentContent(content *ms.CommentContent) (*ms.CommentContent, error) { - // TODO - debug.NotImplemented() - return nil, nil +func (s *commentManageSrv) CreateCommentContent(content *ms.CommentContent) (res *ms.CommentContent, err error) { + res, content.Model = content, &ms.Model{CreatedOn: time.Now().Unix()} + res.ID, err = s.q.CreateCommentContent(context.Background(), &pgc.CreateCommentContentParams{ + CommentID: content.ID, + UserID: content.UserID, + Content: content.Content, + Type: int16(content.Type), + Sort: content.Sort, + CreatedOn: res.CreatedOn, + }) + return } func (s *commentManageSrv) ThumbsUpComment(userId int64, tweetId, commentId int64) error { - // TODO - return debug.ErrNotImplemented + return with(s.db, s.q.WithTx, func(c context.Context, q *pgc.Queries) error { + var ( + thumbsUpCount int32 = 0 + thumbsDownCount int32 = 0 + ) + now := time.Now().Unix() + // 检查thumbs状态 + commentThumbs, err := q.GetTweetCommentThumb(c, &pgc.GetTweetCommentThumbParams{ + UserID: userId, + TweetID: tweetId, + CommentID: commentId, + }) + yes, no := int16(1), int16(0) + if err == nil { + switch { + case commentThumbs.IsThumbsUp == yes && commentThumbs.IsThumbsDown == no: + thumbsUpCount, thumbsDownCount = -1, 0 + case commentThumbs.IsThumbsUp == no && commentThumbs.IsThumbsDown == no: + thumbsUpCount, thumbsDownCount = 1, 0 + default: + thumbsUpCount, thumbsDownCount = 1, -1 + commentThumbs.IsThumbsDown = no + } + commentThumbs.IsThumbsUp = 1 - commentThumbs.IsThumbsUp + if err = q.UpdateThumbsUpDownComment(c, &pgc.UpdateThumbsUpDownCommentParams{ + IsThumbsUp: commentThumbs.IsThumbsUp, + IsThumbsDown: commentThumbs.IsThumbsDown, + ModifiedOn: now, + ID: commentThumbs.ID, + }); err != nil { + return err + } + } else { + thumbsUpCount, thumbsDownCount = 1, 0 + if _, err = q.CreateThumbsUpDownComment(c, &pgc.CreateThumbsUpDownCommentParams{ + UserID: userId, + TweetID: tweetId, + CommentID: commentId, + ReplyID: pgtype.Int8{Int64: 0, Valid: true}, + IsThumbsUp: yes, + IsThumbsDown: no, + CommentType: 0, + CreatedOn: now, + }); err != nil { + return err + } + } + // 更新comment thumbsUpCount + return q.UpdateCommentThumbsCount(c, &pgc.UpdateCommentThumbsCountParams{ + ThumbsUpCount: thumbsUpCount, + ThumbsDownCount: thumbsDownCount, + ModifiedOn: now, + ID: commentId, + }) + }) } func (s *commentManageSrv) ThumbsDownComment(userId int64, tweetId, commentId int64) error { - // TODO - return debug.ErrNotImplemented + return with(s.db, s.q.WithTx, func(c context.Context, q *pgc.Queries) error { + var ( + thumbsUpCount int32 = 0 + thumbsDownCount int32 = 0 + ) + now := time.Now().Unix() + // 检查thumbs状态 + commentThumbs, err := q.GetTweetCommentThumb(c, &pgc.GetTweetCommentThumbParams{ + UserID: userId, + TweetID: tweetId, + CommentID: commentId, + }) + yes, no := int16(1), int16(0) + if err == nil { + switch { + case commentThumbs.IsThumbsDown == yes: + thumbsUpCount, thumbsDownCount = 0, -1 + case commentThumbs.IsThumbsDown == no && commentThumbs.IsThumbsUp == yes: + thumbsUpCount, thumbsDownCount = 0, 1 + default: + thumbsUpCount, thumbsDownCount = -1, 1 + commentThumbs.IsThumbsUp = no + } + commentThumbs.IsThumbsDown = 1 - commentThumbs.IsThumbsDown + if err = q.UpdateThumbsUpDownComment(c, &pgc.UpdateThumbsUpDownCommentParams{ + IsThumbsUp: commentThumbs.IsThumbsUp, + IsThumbsDown: commentThumbs.IsThumbsDown, + ModifiedOn: now, + ID: commentThumbs.ID, + }); err != nil { + return err + } + } else { + thumbsUpCount, thumbsDownCount = 0, 1 + if _, err = q.CreateThumbsUpDownComment(c, &pgc.CreateThumbsUpDownCommentParams{ + UserID: userId, + TweetID: tweetId, + CommentID: commentId, + ReplyID: pgtype.Int8{Int64: 0, Valid: true}, + IsThumbsUp: no, + IsThumbsDown: yes, + CommentType: 0, + CreatedOn: now, + }); err != nil { + return err + } + } + // 更新comment thumbsUpCount + return q.UpdateCommentThumbsCount(c, &pgc.UpdateCommentThumbsCountParams{ + ThumbsUpCount: thumbsUpCount, + ThumbsDownCount: thumbsDownCount, + ModifiedOn: now, + ID: commentId, + }) + }) } func (s *commentManageSrv) ThumbsUpReply(userId int64, tweetId, commentId, replyId int64) error { - // TODO - return debug.ErrNotImplemented + return with(s.db, s.q.WithTx, func(c context.Context, q *pgc.Queries) error { + var ( + thumbsUpCount int32 = 0 + thumbsDownCount int32 = 0 + ) + now := time.Now().Unix() + // 检查thumbs状态 + commentThumbs, err := q.GetCommentReplyThumb(c, &pgc.GetCommentReplyThumbParams{ + UserID: userId, + TweetID: tweetId, + CommentID: commentId, + ReplyID: pgtype.Int8{Int64: replyId, Valid: true}, + }) + yes, no := int16(1), int16(0) + if err == nil { + switch { + case commentThumbs.IsThumbsUp == yes: + thumbsUpCount, thumbsDownCount = -1, 0 + case commentThumbs.IsThumbsUp == no && commentThumbs.IsThumbsDown == no: + thumbsUpCount, thumbsDownCount = 1, 0 + default: + thumbsUpCount, thumbsDownCount = 1, -1 + commentThumbs.IsThumbsDown = no + } + commentThumbs.IsThumbsUp = 1 - commentThumbs.IsThumbsUp + if err = q.UpdateThumbsUpDownComment(c, &pgc.UpdateThumbsUpDownCommentParams{ + IsThumbsUp: commentThumbs.IsThumbsUp, + IsThumbsDown: commentThumbs.IsThumbsDown, + ModifiedOn: now, + ID: commentThumbs.ID, + }); err != nil { + return err + } + } else { + thumbsUpCount, thumbsDownCount = 1, 0 + if _, err = q.CreateThumbsUpDownComment(c, &pgc.CreateThumbsUpDownCommentParams{ + UserID: userId, + TweetID: tweetId, + CommentID: commentId, + ReplyID: pgtype.Int8{Int64: replyId, Valid: true}, + IsThumbsUp: yes, + IsThumbsDown: no, + CommentType: 1, + CreatedOn: now, + }); err != nil { + return err + } + } + // 更新comment_reply thumbsUpCount + return q.UpdateReplyThumbsCount(c, &pgc.UpdateReplyThumbsCountParams{ + ThumbsUpCount: thumbsUpCount, + ThumbsDownCount: thumbsDownCount, + ModifiedOn: now, + ID: replyId, + }) + }) } func (s *commentManageSrv) ThumbsDownReply(userId int64, tweetId, commentId, replyId int64) error { - // TODO - return debug.ErrNotImplemented + return with(s.db, s.q.WithTx, func(c context.Context, q *pgc.Queries) error { + var ( + thumbsUpCount int32 = 0 + thumbsDownCount int32 = 0 + ) + now := time.Now().Unix() + // 检查thumbs状态 + commentThumbs, err := q.GetCommentReplyThumb(c, &pgc.GetCommentReplyThumbParams{ + UserID: userId, + TweetID: tweetId, + CommentID: commentId, + ReplyID: pgtype.Int8{Int64: replyId, Valid: true}, + }) + yes, no := int16(1), int16(0) + if err == nil { + switch { + case commentThumbs.IsThumbsDown == yes: + thumbsUpCount, thumbsDownCount = 0, -1 + case commentThumbs.IsThumbsUp == no && commentThumbs.IsThumbsDown == no: + thumbsUpCount, thumbsDownCount = 0, 1 + default: + thumbsUpCount, thumbsDownCount = -1, 1 + commentThumbs.IsThumbsUp = no + } + commentThumbs.IsThumbsDown = 1 - commentThumbs.IsThumbsDown + if err = q.UpdateThumbsUpDownComment(c, &pgc.UpdateThumbsUpDownCommentParams{ + IsThumbsUp: commentThumbs.IsThumbsUp, + IsThumbsDown: commentThumbs.IsThumbsDown, + ModifiedOn: now, + ID: commentThumbs.ID, + }); err != nil { + return err + } + } else { + thumbsUpCount, thumbsDownCount = 0, 1 + if _, err = q.CreateThumbsUpDownComment(c, &pgc.CreateThumbsUpDownCommentParams{ + UserID: userId, + TweetID: tweetId, + CommentID: commentId, + ReplyID: pgtype.Int8{Int64: replyId, Valid: true}, + IsThumbsUp: no, + IsThumbsDown: yes, + CommentType: 1, + CreatedOn: now, + }); err != nil { + return err + } + } + // 更新comment_reply thumbsUpCount + return q.UpdateReplyThumbsCount(c, &pgc.UpdateReplyThumbsCountParams{ + ThumbsUpCount: thumbsUpCount, + ThumbsDownCount: thumbsDownCount, + ModifiedOn: now, + ID: replyId, + }) + }) } func newCommentService(db *pgx.Conn) core.CommentService { return &commentSrv{ - pgxSrv: newPgxSrv(db), + pgcSrv: newPgcSrv(db), } } func newCommentManageService(db *pgx.Conn) core.CommentManageService { return &commentManageSrv{ - pgxSrv: newPgxSrv(db), + pgcSrv: newPgcSrv(db), } } diff --git a/internal/dao/slonik/contacts.go b/internal/dao/slonik/contacts.go index 31c50ee2..0b098fd2 100644 --- a/internal/dao/slonik/contacts.go +++ b/internal/dao/slonik/contacts.go @@ -5,10 +5,15 @@ package slonik import ( + "context" + "time" + "github.com/jackc/pgx/v5" "github.com/rocboss/paopao-ce/internal/core" + "github.com/rocboss/paopao-ce/internal/core/cs" "github.com/rocboss/paopao-ce/internal/core/ms" - "github.com/rocboss/paopao-ce/pkg/debug" + "github.com/rocboss/paopao-ce/internal/dao/slonik/sqlc/auto/pgc" + "github.com/sirupsen/logrus" ) var ( @@ -16,47 +21,202 @@ var ( ) type contactManageSrv struct { - *pgxSrv + *pgcSrv } func (s *contactManageSrv) RequestingFriend(userId int64, friendId int64, greetings string) (err error) { - // TODO - debug.NotImplemented() - return nil + return with(s.db, s.q.WithTx, func(c context.Context, q *pgc.Queries) error { + now := time.Now().Unix() + contact, err := q.UpsertContact(c, &pgc.UpsertContactParams{ + UserID: userId, + FriendID: friendId, + Status: int16(cs.ContactStatusRequesting), + CreatedOn: now, + }) + if err != nil { + return err + } + // 如果已经好友,啥也不干 + if contact.Status == int16(cs.ContactStatusAgree) { + return nil + } else if contact.Status == int16(cs.ContactStatusReject) || contact.Status == int16(cs.ContactStatusDeleted) { + contact.Status = int16(cs.ContactStatusRequesting) + if err = q.FreshContactStatus(c, &pgc.FreshContactStatusParams{ + Status: contact.Status, + ModifiedOn: now, + ID: contact.ID, + }); err != nil { + return err + } + } + if _, err = q.CreateMessage(c, &pgc.CreateMessageParams{ + SenderUserID: userId, + ReceiverUserID: friendId, + Type: int16(ms.MsgTypeRequestingFriend), + Brief: "请求添加好友,并附言:", + Content: greetings, + ReplyID: int64(cs.ContactStatusRequesting), + CreatedOn: now, + }); err != nil { + return err + } + return nil + }) } func (s *contactManageSrv) AddFriend(userId int64, friendId int64) (err error) { - // TODO - debug.NotImplemented() - return nil + return with(s.db, s.q.WithTx, func(c context.Context, q *pgc.Queries) error { + contact, err := q.GetUserFriend(c, &pgc.GetUserFriendParams{ + UserID: friendId, + FriendID: userId, + }) + if err != nil { + return err + } + // 如果还不是请求好友,啥也不干 + if contact.Status != int16(cs.ContactStatusRequesting) { + logrus.Debugf("contactManageSrv.AddFriend not reuesting status now so skip") + return nil + } + now := time.Now().Unix() + if err = q.FreshContactStatus(c, &pgc.FreshContactStatusParams{ + Status: int16(cs.ContactStatusAgree), + ModifiedOn: now, + ID: contact.ID, + }); err != nil { + return err + } + var row *pgc.UpsertContactRow + row, err = q.UpsertContact(c, &pgc.UpsertContactParams{ + UserID: userId, + FriendID: friendId, + Status: int16(cs.ContactStatusAgree), + CreatedOn: now, + }) + if err != nil { + return err + } + // 如果已经好友,啥也不干 + if row.Status != int16(cs.ContactStatusAgree) { + if err = q.FreshContactStatus(c, &pgc.FreshContactStatusParams{ + Status: int16(cs.ContactStatusAgree), + ModifiedOn: now, + ID: row.ID, + }); err != nil { + return err + } + } + if err = q.AddFriendMsgsUpdate(c, &pgc.AddFriendMsgsUpdateParams{ + ReplyID: int64(cs.ContactStatusAgree), + ModifiedOn: now, + SenderUserID: userId, + ReceiverUserID: friendId, + Type: int16(ms.MsgTypeRequestingFriend), + ReplyID_2: int64(cs.ContactStatusRequesting), + }); err != nil { + return err + } + return nil + }) } func (s *contactManageSrv) RejectFriend(userId int64, friendId int64) (err error) { - // TODO - debug.NotImplemented() - return nil + return with(s.db, s.q.WithTx, func(c context.Context, q *pgc.Queries) error { + contact, err := q.GetUserFriend(c, &pgc.GetUserFriendParams{ + UserID: friendId, + FriendID: userId, + }) + if err != nil { + return err + } + // 如果还不是请求好友,啥也不干 + if contact.Status != int16(cs.ContactStatusRequesting) { + return nil + } + now := time.Now().Unix() + if err = q.FreshContactStatus(c, &pgc.FreshContactStatusParams{ + Status: int16(cs.ContactStatusReject), + ModifiedOn: now, + ID: contact.ID, + }); err != nil { + return err + } + if err = q.RejectFriendMsgsUpdate(c, &pgc.RejectFriendMsgsUpdateParams{ + ReplyID: int64(cs.ContactStatusReject), + ModifiedOn: now, + SenderUserID: friendId, + ReceiverUserID: userId, + Type: int16(ms.MsgTypeRequestingFriend), + ReplyID_2: int64(cs.ContactStatusRequesting), + }); err != nil { + return err + } + return nil + }) } func (s *contactManageSrv) DeleteFriend(userId int64, friendId int64) (err error) { - // TODO - debug.NotImplemented() - return nil + return with(s.db, s.q.WithTx, func(c context.Context, q *pgc.Queries) error { + contacts, err := q.GetContacts(c, &pgc.GetContactsParams{ + UserID: userId, + FriendID: friendId, + }) + if err != nil { + return err + } + ids := make([]int64, 0, 2) + for _, contact := range contacts { + // 如果还不是好友,啥也不干 + if contact.Status != int16(cs.ContactStatusAgree) { + continue + } + ids = append(ids, contact.ID) + } + if err = q.DeleteFriendByIds(c, &pgc.DeleteFriendByIdsParams{ + DeletedOn: time.Now().Unix(), + Ids: ids, + }); err != nil { + return err + } + return nil + }) } -func (s *contactManageSrv) GetContacts(userId int64, offset int, limit int) (*ms.ContactList, error) { - // TODO - debug.NotImplemented() - return nil, nil +func (s *contactManageSrv) GetContacts(userId int64, offset int, limit int) (res *ms.ContactList, err error) { + res = &ms.ContactList{} + if res.Total, err = s.q.CountFriendsById(context.Background(), userId); err == nil && res.Total > 0 { + var rows []*pgc.ListFriendRow + rows, err = s.q.ListFriend(context.Background(), &pgc.ListFriendParams{ + UserID: userId, + Limit: int32(limit), + Offset: int32(offset), + }) + if err != nil { + return + } + for _, contact := range rows { + res.Contacts = append(res.Contacts, ms.ContactItem{ + UserId: contact.UserID, + Username: contact.Username, + Nickname: contact.Nickname, + Avatar: contact.Avatar, + Phone: contact.Phone, + }) + } + } + return } func (s *contactManageSrv) IsFriend(userId int64, friendId int64) bool { - // TODO - debug.NotImplemented() - return false + ok, _ := s.q.IsFriend(context.Background(), &pgc.IsFriendParams{ + UserID: userId, + FriendID: friendId, + }) + return ok } func newContactManageService(db *pgx.Conn) core.ContactManageService { return &contactManageSrv{ - pgxSrv: newPgxSrv(db), + pgcSrv: newPgcSrv(db), } } diff --git a/internal/dao/slonik/pgx.go b/internal/dao/slonik/pgx.go index aa60c3fa..12764010 100644 --- a/internal/dao/slonik/pgx.go +++ b/internal/dao/slonik/pgx.go @@ -11,6 +11,8 @@ import ( "github.com/jackc/pgx/v5" "github.com/rocboss/paopao-ce/internal/conf" pg "github.com/rocboss/paopao-ce/internal/dao/slonik/sqlc/auto" + "github.com/rocboss/paopao-ce/internal/dao/slonik/sqlc/auto/pga" + "github.com/rocboss/paopao-ce/internal/dao/slonik/sqlc/auto/pgc" ) var ( @@ -20,7 +22,67 @@ var ( type pgxSrv struct { db *pgx.Conn - p pg.Querier + p *pg.Queries +} + +type pgcSrv struct { + *pgxSrv + q *pgc.Queries +} + +type pgaSrv struct { + *pgxSrv + q *pga.Queries +} + +func with[Q any](db *pgx.Conn, txFn func(pgx.Tx) Q, fn func(c context.Context, q Q) error) error { + ctx := context.Background() + tx, err := db.Begin(ctx) + if err != nil { + return err + } + defer tx.Rollback(ctx) + if err = fn(ctx, txFn(tx)); err != nil { + return err + } + return tx.Commit(ctx) +} + +func withTx[Q any](txOptions pgx.TxOptions, db *pgx.Conn, txFn func(pgx.Tx) Q, fn func(c context.Context, q Q) error) error { + ctx := context.Background() + tx, err := db.BeginTx(ctx, txOptions) + if err != nil { + return err + } + defer tx.Rollback(ctx) + if err = fn(ctx, txFn(tx)); err != nil { + return err + } + return tx.Commit(ctx) +} + +func withCtx[Q any](ctx context.Context, db *pgx.Conn, txFn func(pgx.Tx) Q, fn func(c context.Context, q Q) error) error { + tx, err := db.Begin(ctx) + if err != nil { + return err + } + defer tx.Rollback(ctx) + if err = fn(ctx, txFn(tx)); err != nil { + return err + } + return tx.Commit(ctx) +} + +func withTxCtx[Q any](ctx context.Context, txOptions pgx.TxOptions, db *pgx.Conn, txFn func(pgx.Tx) Q, fn func(c context.Context, q Q) error) error { + tx, err := db.BeginTx(ctx, txOptions) + if err != nil { + return err + } + defer tx.Rollback(ctx) + if err = fn(ctx, txFn(tx)); err != nil { + return err + } + return tx.Commit(ctx) } func (s *pgxSrv) with(fn func(c context.Context, tx pgx.Tx) error) error { @@ -80,6 +142,20 @@ func newPgxSrv(db *pgx.Conn) *pgxSrv { } } +func newPgcSrv(db *pgx.Conn) *pgcSrv { + return &pgcSrv{ + pgxSrv: newPgxSrv(db), + q: pgc.New(db), + } +} + +func newPgaSrv(db *pgx.Conn) *pgaSrv { + return &pgaSrv{ + pgxSrv: newPgxSrv(db), + q: pga.New(db), + } +} + func pgxDB() *pgx.Conn { _oncePgx.Do(func() { _pgxDB = conf.MustPgxDB() diff --git a/internal/dao/slonik/sqlc/auto/pgc/comments.sql.go b/internal/dao/slonik/sqlc/auto/pgc/comments.sql.go index 5cb50b17..8b937d0b 100644 --- a/internal/dao/slonik/sqlc/auto/pgc/comments.sql.go +++ b/internal/dao/slonik/sqlc/auto/pgc/comments.sql.go @@ -639,6 +639,27 @@ func (q *Queries) GetTweetCommentThumb(ctx context.Context, arg *GetTweetComment return &i, err } +const highlightComment = `-- name: HighlightComment :one +UPDATE p_comment +SET is_essence=1-is_essence, + modified_on=$1 +WHERE id=$2 AND user_id=$3 AND is_del=0 +RETURNING is_essence +` + +type HighlightCommentParams struct { + ModifiedOn int64 + ID int64 + UserID int64 +} + +func (q *Queries) HighlightComment(ctx context.Context, arg *HighlightCommentParams) (int16, error) { + row := q.db.QueryRow(ctx, highlightComment, arg.ModifiedOn, arg.ID, arg.UserID) + var is_essence int16 + err := row.Scan(&is_essence) + return is_essence, err +} + const incrCommentReplyCount = `-- name: IncrCommentReplyCount :exec UPDATE p_comment SET reply_count=reply_count+1, diff --git a/internal/dao/slonik/sqlc/auto/pgc/contacts.sql.go b/internal/dao/slonik/sqlc/auto/pgc/contacts.sql.go index 686d70da..8e98a923 100644 --- a/internal/dao/slonik/sqlc/auto/pgc/contacts.sql.go +++ b/internal/dao/slonik/sqlc/auto/pgc/contacts.sql.go @@ -119,6 +119,20 @@ func (q *Queries) DeleteFriend(ctx context.Context, arg *DeleteFriendParams) err return err } +const deleteFriendByIds = `-- name: DeleteFriendByIds :exec +UPDATE p_contact SET status=4, is_del=1, deleted_on=$1 WHERE id=ANY($2::BIGINT[]) +` + +type DeleteFriendByIdsParams struct { + DeletedOn int64 + Ids []int64 +} + +func (q *Queries) DeleteFriendByIds(ctx context.Context, arg *DeleteFriendByIdsParams) error { + _, err := q.db.Exec(ctx, deleteFriendByIds, arg.DeletedOn, arg.Ids) + return err +} + const freshContactStatus = `-- name: FreshContactStatus :exec UPDATE p_contact SET status=$1, modified_on=$2, is_del=0 WHERE id=$3 ` @@ -179,14 +193,12 @@ func (q *Queries) GetContact(ctx context.Context, arg *GetContactParams) (*GetCo const getContacts = `-- name: GetContacts :many SELECT id, user_id, friend_id, group_id, remark, status, is_top, is_black, notice_enable, is_del FROM p_contact -WHERE (user_id=$1 AND friend_id=$2) OR (user_id=$3 AND friend_id=$4) +WHERE (user_id=$1 AND friend_id=$2) OR (user_id=$2 AND friend_id=$1) ` type GetContactsParams struct { - UserID int64 - FriendID int64 - UserID_2 int64 - FriendID_2 int64 + UserID int64 + FriendID int64 } type GetContactsRow struct { @@ -203,12 +215,7 @@ type GetContactsRow struct { } func (q *Queries) GetContacts(ctx context.Context, arg *GetContactsParams) ([]*GetContactsRow, error) { - rows, err := q.db.Query(ctx, getContacts, - arg.UserID, - arg.FriendID, - arg.UserID_2, - arg.FriendID_2, - ) + rows, err := q.db.Query(ctx, getContacts, arg.UserID, arg.FriendID) if err != nil { return nil, err } @@ -376,3 +383,35 @@ func (q *Queries) RejectFriendMsgsUpdate(ctx context.Context, arg *RejectFriendM ) return err } + +const upsertContact = `-- name: UpsertContact :one +INSERT INTO p_contact (user_id, friend_id, status, created_on) +VALUES ($1, $2, $3, $4) +ON CONFLICT ON CONSTRAINT idx_contact_user_friend + DO UPDATE SET is_del=0 +RETURNING id, status +` + +type UpsertContactParams struct { + UserID int64 + FriendID int64 + Status int16 + CreatedOn int64 +} + +type UpsertContactRow struct { + ID int64 + Status int16 +} + +func (q *Queries) UpsertContact(ctx context.Context, arg *UpsertContactParams) (*UpsertContactRow, error) { + row := q.db.QueryRow(ctx, upsertContact, + arg.UserID, + arg.FriendID, + arg.Status, + arg.CreatedOn, + ) + var i UpsertContactRow + err := row.Scan(&i.ID, &i.Status) + return &i, err +} diff --git a/internal/dao/slonik/sqlc/auto/pgc/querier.go b/internal/dao/slonik/sqlc/auto/pgc/querier.go index ca40b223..4d00e2ab 100644 --- a/internal/dao/slonik/sqlc/auto/pgc/querier.go +++ b/internal/dao/slonik/sqlc/auto/pgc/querier.go @@ -94,6 +94,7 @@ type Querier interface { DeleteCommentThumbs(ctx context.Context, arg *DeleteCommentThumbsParams) error DeleteFollowing(ctx context.Context, arg *DeleteFollowingParams) error DeleteFriend(ctx context.Context, arg *DeleteFriendParams) error + DeleteFriendByIds(ctx context.Context, arg *DeleteFriendByIdsParams) error DeletePostById(ctx context.Context, arg *DeletePostByIdParams) error DeletePostCollecton(ctx context.Context, arg *DeletePostCollectonParams) error DeletePostStar(ctx context.Context, arg *DeletePostStarParams) error @@ -174,6 +175,7 @@ type Querier interface { GetUsersByIds(ctx context.Context, ids []int64) ([]*PUser, error) GetUsersByKeyword(ctx context.Context, username string) ([]*PUser, error) GetWhisperMessages(ctx context.Context, arg *GetWhisperMessagesParams) ([]*PMessage, error) + HighlightComment(ctx context.Context, arg *HighlightCommentParams) (int16, error) HighlightPost(ctx context.Context, id int64) (int16, error) HotTags(ctx context.Context, arg *HotTagsParams) ([]*HotTagsRow, error) IncrCommentReplyCount(ctx context.Context, arg *IncrCommentReplyCountParams) error @@ -232,6 +234,7 @@ type Querier interface { //------------------------------------------------------------------------------ UpdateUserMetric(ctx context.Context, arg *UpdateUserMetricParams) error UpsertCommentMetric(ctx context.Context, arg *UpsertCommentMetricParams) error + UpsertContact(ctx context.Context, arg *UpsertContactParams) (*UpsertContactRow, error) UpsertTweetMetric(ctx context.Context, arg *UpsertTweetMetricParams) error UsePhoneCaptcha(ctx context.Context, arg *UsePhoneCaptchaParams) error UserCommentTweetsByFriend(ctx context.Context, arg *UserCommentTweetsByFriendParams) ([]*UserCommentTweetsByFriendRow, error) diff --git a/internal/dao/slonik/sqlc/postgres/query_pgc/comments.sql b/internal/dao/slonik/sqlc/postgres/query_pgc/comments.sql index bcf646a0..f19f264f 100644 --- a/internal/dao/slonik/sqlc/postgres/query_pgc/comments.sql +++ b/internal/dao/slonik/sqlc/postgres/query_pgc/comments.sql @@ -76,6 +76,13 @@ INSERT INTO p_comment_reply (comment_id, user_id, content, at_user_id, ip, ip_lo VALUES ($1, $2, $3, $4, $5, $6, $7) RETURNING id; +-- name: HighlightComment :one +UPDATE p_comment +SET is_essence=1-is_essence, + modified_on=$1 +WHERE id=$2 AND user_id=$3 AND is_del=0 +RETURNING is_essence; + -- name: IncrCommentReplyCount :exec UPDATE p_comment SET reply_count=reply_count+1, diff --git a/internal/dao/slonik/sqlc/postgres/query_pgc/contacts.sql b/internal/dao/slonik/sqlc/postgres/query_pgc/contacts.sql index 33eeb2ca..00b12aa2 100644 --- a/internal/dao/slonik/sqlc/postgres/query_pgc/contacts.sql +++ b/internal/dao/slonik/sqlc/postgres/query_pgc/contacts.sql @@ -5,6 +5,13 @@ -- name: CreateContact :exec INSERT INTO p_contact (user_id, friend_id, status, created_on) VALUES ($1, $2, $3, $4); +-- name: UpsertContact :one +INSERT INTO p_contact (user_id, friend_id, status, created_on) +VALUES ($1, $2, $3, $4) +ON CONFLICT ON CONSTRAINT idx_contact_user_friend + DO UPDATE SET is_del=0 +RETURNING id, status; + -- name: FreshContactStatus :exec UPDATE p_contact SET status=$1, modified_on=$2, is_del=0 WHERE id=$3; @@ -28,6 +35,9 @@ WHERE sender_user_id=$3 AND receiver_user_id=$4 AND type=$5 AND reply_id=$6; -- name: DeleteFriend :exec UPDATE p_contact SET status=4, is_del=1, deleted_on=$1 WHERE id=$2; +-- name: DeleteFriendByIds :exec +UPDATE p_contact SET status=4, is_del=1, deleted_on=$1 WHERE id=ANY(@ids::BIGINT[]); + -- name: ListFriend :many SELECT c.friend_id user_id, u.username username, @@ -47,7 +57,7 @@ SELECT count(*) FROM p_contact WHERE user_id=$1 AND status=2 AND is_del=0; -- name: GetContacts :many SELECT id, user_id, friend_id, group_id, remark, status, is_top, is_black, notice_enable, is_del FROM p_contact -WHERE (user_id=$1 AND friend_id=$2) OR (user_id=$3 AND friend_id=$4); +WHERE (user_id=$1 AND friend_id=$2) OR (user_id=$2 AND friend_id=$1); -- name: GetUserFriend :one SELECT id, user_id, friend_id, group_id, remark, status, is_top, is_black, notice_enable, is_del diff --git a/internal/dao/slonik/topics.go b/internal/dao/slonik/topics.go index 29d92816..a3f6e646 100644 --- a/internal/dao/slonik/topics.go +++ b/internal/dao/slonik/topics.go @@ -28,9 +28,8 @@ type topicSrv struct { // UpsertTags update/insert tags info. // Assume tags slice is distinct elements. func (s *topicSrv) UpsertTags(userId int64, tags []string) (res cs.TagInfoList, err error) { - err = s.with(func(c context.Context, tx pgx.Tx) error { + err = with(s.db, s.q.WithTx, func(c context.Context, q *pgc.Queries) error { now := time.Now().Unix() - q := s.q.WithTx(tx) upTags, err := q.IncrTags(c, &pgc.IncrTagsParams{ Tags: tags, ModifiedOn: now,