Merge remote-tracking branch 'origin/feat/0.5.0/timeline' into test

This commit is contained in:
LinkinStar 2022-11-24 09:29:14 +08:00
commit 63f624c2be
17 changed files with 266 additions and 100 deletions

View File

@ -189,7 +189,7 @@ func initApplication(debug bool, serverConf *conf.Server, dbConf *data.Database,
activityCommon := activity_common2.NewActivityCommon(activityRepo)
activityActivityRepo := activity.NewActivityRepo(dataData)
commentCommonService := comment_common.NewCommentCommonService(commentCommonRepo)
activityService := activity2.NewActivityService(activityActivityRepo, userCommon, activityCommon, tagCommonService, objService, commentCommonService, revisionService)
activityService := activity2.NewActivityService(activityActivityRepo, userCommon, activityCommon, tagCommonService, objService, commentCommonService, revisionService, metaService)
activityController := controller.NewActivityController(activityCommon, activityService)
answerAPIRouter := router.NewAnswerAPIRouter(langController, userController, commentController, reportController, voteController, tagController, followController, collectionController, questionController, answerController, searchController, revisionController, rankController, controller_backyardReportController, userBackyardController, reasonController, themeController, siteInfoController, siteinfoController, notificationController, dashboardController, uploadController, activityController)
swaggerRouter := router.NewSwaggerRouter(swaggerConf)

View File

@ -1,9 +1,18 @@
package constant
// question activity
type ActivityTypeKey string
const (
ActEdited = "edited"
ActClosed = "closed"
ActVotedDown = "voted_down"
ActVotedUp = "voted_up"
ActVoteDown = "vote_down"
ActVoteUp = "vote_up"
ActUpVote = "upvote"
ActDownVote = "downvote"
)
const (
ActQuestionAsked ActivityTypeKey = "question.asked"
ActQuestionClosed ActivityTypeKey = "question.closed"
@ -12,29 +21,25 @@ const (
ActQuestionCommented ActivityTypeKey = "question.commented"
ActQuestionAccept ActivityTypeKey = "question.accept"
ActQuestionUpvote ActivityTypeKey = "question.upvote"
ActQuestionDownvote ActivityTypeKey = "question.downvote"
ActQuestionDownVote ActivityTypeKey = "question.downvote"
ActQuestionEdited ActivityTypeKey = "question.edited"
ActQuestionRollback ActivityTypeKey = "question.rollback"
ActQuestionDeleted ActivityTypeKey = "question.deleted"
ActQuestionUndeleted ActivityTypeKey = "question.undeleted"
)
// answer activity
const (
ActAnswerAnswered ActivityTypeKey = "answer.answered"
ActAnswerCommented ActivityTypeKey = "answer.commented"
ActAnswerAccept ActivityTypeKey = "answer.accept"
ActAnswerUpvote ActivityTypeKey = "answer.upvote"
ActAnswerDownvote ActivityTypeKey = "answer.downvote"
ActAnswerDownVote ActivityTypeKey = "answer.downvote"
ActAnswerEdited ActivityTypeKey = "answer.edited"
ActAnswerRollback ActivityTypeKey = "answer.rollback"
ActAnswerDeleted ActivityTypeKey = "answer.deleted"
ActAnswerUndeleted ActivityTypeKey = "answer.undeleted"
)
// tag activity
const (
ActTagCreated ActivityTypeKey = "tag.created"
ActTagEdited ActivityTypeKey = "tag.edited"

View File

@ -39,6 +39,9 @@ func (ac *ActivityController) GetObjectTimeline(ctx *gin.Context) {
}
req.UserID = middleware.GetLoginUserIDFromContext(ctx)
if userInfo := middleware.GetUserInfoFromContext(ctx); userInfo != nil {
req.IsAdmin = userInfo.IsAdmin
}
resp, err := ac.activityService.GetObjectTimeline(ctx, req)
handler.HandleResponse(ctx, err, resp)

View File

@ -6,7 +6,6 @@ import (
"github.com/answerdev/answer/internal/base/handler"
"github.com/answerdev/answer/internal/base/middleware"
"github.com/answerdev/answer/internal/base/reason"
"github.com/answerdev/answer/internal/entity"
"github.com/answerdev/answer/internal/schema"
"github.com/answerdev/answer/internal/service"
"github.com/answerdev/answer/internal/service/dashboard"
@ -243,10 +242,13 @@ func (ac *AnswerController) Adopted(ctx *gin.Context) {
// @Router /answer/admin/api/answer/status [put]
// @Success 200 {object} handler.RespBody
func (ac *AnswerController) AdminSetAnswerStatus(ctx *gin.Context) {
req := &entity.AdminSetAnswerStatusRequest{}
req := &schema.AdminSetAnswerStatusRequest{}
if handler.BindAndCheck(ctx, req) {
return
}
err := ac.answerService.AdminSetAnswerStatus(ctx, req.AnswerID, req.StatusStr)
req.UserID = middleware.GetLoginUserIDFromContext(ctx)
err := ac.answerService.AdminSetAnswerStatus(ctx, req)
handler.HandleResponse(ctx, err, gin.H{})
}

View File

@ -69,7 +69,7 @@ func (tc *TagController) RemoveTag(ctx *gin.Context) {
return
}
err := tc.tagService.RemoveTag(ctx, req.TagID)
err := tc.tagService.RemoveTag(ctx, req)
handler.HandleResponse(ctx, err, nil)
}

View File

@ -48,11 +48,6 @@ type CmsAnswerSearch struct {
QuestionID string `validate:"omitempty,gt=0,lte=24" json:"question_id" form:"question_id" ` //Query string
}
type AdminSetAnswerStatusRequest struct {
StatusStr string `json:"status" form:"status"`
AnswerID string `json:"answer_id" form:"answer_id"`
}
// TableName answer table name
func (Answer) TableName() string {
return "answer"

View File

@ -62,11 +62,12 @@ type QuestionWithTagsRevision struct {
// TagSimpleInfoForRevision tag simple info for revision
type TagSimpleInfoForRevision struct {
ID string `xorm:"not null pk comment('tag_id') BIGINT(20) id"`
MainTagID int64 `xorm:"not null default 0 BIGINT(20) main_tag_id"`
SlugName string `xorm:"not null default '' unique VARCHAR(35) slug_name"`
DisplayName string `xorm:"not null default '' VARCHAR(35) display_name"`
Recommend bool `xorm:"not null default false BOOL recommend"`
Reserved bool `xorm:"not null default false BOOL reserved"`
RevisionID string `xorm:"not null default 0 BIGINT(20) revision_id"`
ID string `xorm:"not null pk comment('tag_id') BIGINT(20) id"`
MainTagID int64 `xorm:"not null default 0 BIGINT(20) main_tag_id"`
MainTagSlugName string `xorm:"not null default '' VARCHAR(35) main_tag_slug_name"`
SlugName string `xorm:"not null default '' unique VARCHAR(35) slug_name"`
DisplayName string `xorm:"not null default '' VARCHAR(35) display_name"`
Recommend bool `xorm:"not null default false BOOL recommend"`
Reserved bool `xorm:"not null default false BOOL reserved"`
RevisionID string `xorm:"not null default 0 BIGINT(20) revision_id"`
}

View File

@ -2,10 +2,13 @@ package activity
import (
"context"
"fmt"
"github.com/answerdev/answer/internal/base/constant"
"github.com/answerdev/answer/internal/base/data"
"github.com/answerdev/answer/internal/base/reason"
"github.com/answerdev/answer/internal/entity"
"github.com/answerdev/answer/internal/repo/config"
"github.com/answerdev/answer/internal/service/activity"
"github.com/segmentfault/pacman/errors"
)
@ -27,7 +30,23 @@ func NewActivityRepo(
func (ar *activityRepo) GetObjectAllActivity(ctx context.Context, objectID string, showVote bool) (
activityList []*entity.Activity, err error) {
activityList = make([]*entity.Activity, 0)
err = ar.data.DB.Find(&activityList, &entity.Activity{OriginalObjectID: objectID})
session := ar.data.DB.Desc("created_at")
if !showVote {
var activityTypeNotShown []int
for _, obj := range []string{constant.AnswerObjectType, constant.QuestionObjectType, constant.CommentObjectType} {
for _, act := range []string{
constant.ActVotedDown,
constant.ActVotedUp,
constant.ActVoteDown,
constant.ActVoteUp,
} {
activityTypeNotShown = append(activityTypeNotShown, config.Key2IDMapping[fmt.Sprintf("%s.%s", obj, act)])
}
}
session.NotIn("activity_type", activityTypeNotShown)
}
err = session.Find(&activityList, &entity.Activity{OriginalObjectID: objectID})
if err != nil {
return nil, errors.InternalServer(reason.DatabaseError).WithError(err).WithStack()
}

View File

@ -144,9 +144,11 @@ func (ar *AnswerActivityRepo) AcceptAnswer(ctx context.Context,
if action == acceptAction {
addActivity.UserID = questionUserID
addActivity.TriggerUserID = converter.StringToInt64(answerUserID)
addActivity.OriginalObjectID = questionObjID // if activity is 'accept' means this question is accept the answer.
} else {
addActivity.UserID = answerUserID
addActivity.TriggerUserID = converter.StringToInt64(answerUserID)
addActivity.OriginalObjectID = answerObjID // if activity is 'accepted' means this answer was accepted.
}
if isSelf {
addActivity.Rank = 0
@ -234,16 +236,17 @@ func (ar *AnswerActivityRepo) CancelAcceptAnswer(ctx context.Context,
return errors.InternalServer(reason.DatabaseError).WithError(e).WithStack()
}
addActivity := &entity.Activity{
ObjectID: answerObjID,
OriginalObjectID: questionObjID,
ActivityType: activityType,
Rank: -deltaRank,
HasRank: hasRank,
ObjectID: answerObjID,
ActivityType: activityType,
Rank: -deltaRank,
HasRank: hasRank,
}
if action == acceptAction {
addActivity.UserID = questionUserID
addActivity.OriginalObjectID = questionObjID
} else {
addActivity.UserID = answerUserID
addActivity.OriginalObjectID = answerObjID
}
addActivityList = append(addActivityList, addActivity)
}

View File

@ -17,6 +17,7 @@ type GetObjectTimelineReq struct {
ObjectID string `validate:"omitempty,gt=0,lte=100" form:"object_id"`
ShowVote bool `validate:"omitempty" form:"show_vote"`
UserID string `json:"-"`
IsAdmin bool `json:"-"`
}
// GetObjectTimelineResp get object timeline response
@ -38,14 +39,16 @@ type ActObjectTimeline struct {
ObjectType string `json:"object_type"`
Cancelled bool `json:"cancelled"`
CancelledAt int64 `json:"cancelled_at"`
UserID string `json:"-"`
}
// ActObjectInfo act object info
type ActObjectInfo struct {
Title string `json:"title"`
ObjectType string `json:"object_type"`
QuestionID string `json:"question_id"`
AnswerID string `json:"answer_id"`
ObjectType string `json:"object_type"`
Title string `json:"title"`
QuestionID string `json:"question_id"`
AnswerID string `json:"answer_id"`
MainTagSlugName string `json:"main_tag_slug_name"`
}
// GetObjectTimelineDetailReq get object timeline detail request
@ -63,7 +66,18 @@ type GetObjectTimelineDetailResp struct {
// ObjectTimelineDetail object timeline detail
type ObjectTimelineDetail struct {
Title string `json:"title"`
Tags []string `json:"tags"`
OriginalText string `json:"original_text"`
Title string `json:"title"`
Tags []*ObjectTimelineTag `json:"tags"`
OriginalText string `json:"original_text"`
SlugName string `json:"slug_name"`
MainTagSlugName string `json:"main_tag_slug_name"`
}
// ObjectTimelineTag object timeline tags
type ObjectTimelineTag struct {
SlugName string `json:"slug_name"`
DisplayName string `json:"display_name"`
MainTagSlugName string `json:"main_tag_slug_name"`
Recommend bool `json:"recommend"`
Reserved bool `json:"reserved"`
}

View File

@ -77,7 +77,13 @@ type AdminAnswerInfo struct {
}
type AnswerAdoptedReq struct {
QuestionID string `json:"question_id" ` // question_id
AnswerID string `json:"answer_id" `
QuestionID string `json:"question_id"`
AnswerID string `json:"answer_id"`
UserID string `json:"-" `
}
type AdminSetAnswerStatusRequest struct {
StatusStr string `json:"status"`
AnswerID string `json:"answer_id"`
UserID string `json:"-" `
}

View File

@ -11,11 +11,13 @@ import (
"github.com/answerdev/answer/internal/schema"
"github.com/answerdev/answer/internal/service/activity_common"
"github.com/answerdev/answer/internal/service/comment_common"
"github.com/answerdev/answer/internal/service/meta"
"github.com/answerdev/answer/internal/service/object_info"
"github.com/answerdev/answer/internal/service/revision_common"
"github.com/answerdev/answer/internal/service/tag_common"
usercommon "github.com/answerdev/answer/internal/service/user_common"
"github.com/answerdev/answer/pkg/converter"
"github.com/answerdev/answer/pkg/obj"
"github.com/segmentfault/pacman/log"
)
@ -33,6 +35,7 @@ type ActivityService struct {
objectInfoService *object_info.ObjService
commentCommonService *comment_common.CommentCommonService
revisionService *revision_common.RevisionService
metaService *meta.MetaService
}
// NewActivityService new activity service
@ -44,6 +47,7 @@ func NewActivityService(
objectInfoService *object_info.ObjService,
commentCommonService *comment_common.CommentCommonService,
revisionService *revision_common.RevisionService,
metaService *meta.MetaService,
) *ActivityService {
return &ActivityService{
objectInfoService: objectInfoService,
@ -53,6 +57,7 @@ func NewActivityService(
tagCommonService: tagCommonService,
commentCommonService: commentCommonService,
revisionService: revisionService,
metaService: metaService,
}
}
@ -64,14 +69,10 @@ func (as *ActivityService) GetObjectTimeline(ctx context.Context, req *schema.Ge
Timeline: make([]*schema.ActObjectTimeline, 0),
}
objInfo, err := as.objectInfoService.GetInfo(ctx, req.ObjectID)
resp.ObjectInfo, err = as.getTimelineMainObjInfo(ctx, req.ObjectID)
if err != nil {
return nil, err
}
resp.ObjectInfo.Title = objInfo.Title
resp.ObjectInfo.ObjectType = objInfo.ObjectType
resp.ObjectInfo.QuestionID = objInfo.QuestionID
resp.ObjectInfo.AnswerID = objInfo.AnswerID
activityList, err := as.activityRepo.GetObjectAllActivity(ctx, req.ObjectID, req.ShowVote)
if err != nil {
@ -85,67 +86,144 @@ func (as *ActivityService) GetObjectTimeline(ctx context.Context, req *schema.Ge
Cancelled: act.Cancelled == entity.ActivityCancelled,
ObjectID: act.ObjectID,
}
item.ObjectType, _ = obj.GetObjectTypeStrByObjectID(act.ObjectID)
if item.Cancelled {
item.CancelledAt = act.CancelledAt.Unix()
}
// database save activity type is number, change to activity type string is like "question.asked".
// so we need to cut the front part of '.'
item.ObjectType, item.ActivityType, _ = strings.Cut(config.ID2KeyMapping[act.ActivityType], ".")
isHidden, formattedActivityType := formatActivity(item.ActivityType)
if isHidden {
_, item.ActivityType, _ = strings.Cut(config.ID2KeyMapping[act.ActivityType], ".")
// format activity type string to show
if isHidden, formattedActivityType := formatActivity(item.ActivityType); isHidden {
continue
}
item.ActivityType = formattedActivityType
// get user info
userBasicInfo, exist, err := as.userCommon.GetUserBasicInfoByID(ctx, act.UserID)
if err != nil {
return nil, err
}
if exist {
item.Username = userBasicInfo.Username
item.UserDisplayName = userBasicInfo.DisplayName
} else {
item.ActivityType = formattedActivityType
}
if item.ObjectType == constant.CommentObjectType {
comment, err := as.commentCommonService.GetComment(ctx, item.ObjectID)
if err != nil {
log.Error(err)
} else {
item.Comment = comment.ParsedText
}
// if activity is down vote, only admin can see who does it.
if item.ActivityType == constant.ActDownVote && !req.IsAdmin {
item.Username = "N/A"
item.UserDisplayName = "N/A"
} else {
item.UserID = act.UserID
}
item.Comment = as.getTimelineActivityComment(ctx, item.ObjectID, item.ObjectType, item.ActivityType, item.RevisionID)
resp.Timeline = append(resp.Timeline, item)
}
as.formatTimelineUserInfo(ctx, resp.Timeline)
return
}
func (as *ActivityService) getTimelineMainObjInfo(ctx context.Context, objectID string) (
resp *schema.ActObjectInfo, err error) {
resp = &schema.ActObjectInfo{}
objInfo, err := as.objectInfoService.GetInfo(ctx, objectID)
if err != nil {
return nil, err
}
resp.Title = objInfo.Title
if objInfo.ObjectType == constant.TagObjectType {
tag, exist, _ := as.tagCommonService.GetTagByID(ctx, objInfo.TagID)
if exist {
resp.Title = tag.SlugName
resp.MainTagSlugName = tag.MainTagSlugName
}
}
resp.ObjectType = objInfo.ObjectType
resp.QuestionID = objInfo.QuestionID
resp.AnswerID = objInfo.AnswerID
return resp, nil
}
func (as *ActivityService) getTimelineActivityComment(ctx context.Context, objectID, objectType,
activityType, revisionID string) (comment string) {
if objectType == constant.CommentObjectType {
commentInfo, err := as.commentCommonService.GetComment(ctx, objectID)
if err != nil {
log.Error(err)
} else {
return commentInfo.ParsedText
}
return
}
if activityType == constant.ActEdited {
revision, err := as.revisionService.GetRevision(ctx, revisionID)
if err != nil {
log.Error(err)
} else {
return revision.Log
}
return
}
if activityType == constant.ActClosed {
// only question can be closed
metaInfo, err := as.metaService.GetMetaByObjectIdAndKey(ctx, objectID, entity.QuestionCloseReasonKey)
if err != nil {
log.Error(err)
} else {
closeMsg := &schema.CloseQuestionMeta{}
if err := json.Unmarshal([]byte(metaInfo.Value), closeMsg); err != nil {
return closeMsg.CloseMsg
}
}
}
return ""
}
func (as *ActivityService) formatTimelineUserInfo(ctx context.Context, timeline []*schema.ActObjectTimeline) {
userExist := make(map[string]bool)
userIDs := make([]string, 0)
for _, info := range timeline {
if len(info.UserID) == 0 || userExist[info.UserID] {
continue
}
userIDs = append(userIDs, info.UserID)
}
if len(userIDs) == 0 {
return
}
userInfoMapping, err := as.userCommon.BatchUserBasicInfoByID(ctx, userIDs)
if err != nil {
log.Error(err)
return
}
for _, info := range timeline {
if len(info.UserID) == 0 {
continue
}
if userInfo, ok := userInfoMapping[info.UserID]; ok {
info.Username = userInfo.Username
info.UserDisplayName = userInfo.DisplayName
}
}
}
// GetObjectTimelineDetail get object timeline
func (as *ActivityService) GetObjectTimelineDetail(ctx context.Context, req *schema.GetObjectTimelineDetailReq) (
resp *schema.GetObjectTimelineDetailResp, err error) {
resp = &schema.GetObjectTimelineDetailResp{}
resp.OldRevision, err = as.getOneObjectDetail(ctx, req.OldRevisionID)
if err != nil {
return nil, err
}
resp.NewRevision, err = as.getOneObjectDetail(ctx, req.NewRevisionID)
if err != nil {
return nil, err
}
resp.OldRevision, _ = as.getOneObjectDetail(ctx, req.OldRevisionID)
resp.NewRevision, _ = as.getOneObjectDetail(ctx, req.NewRevisionID)
return resp, nil
}
// GetObjectTimelineDetail get object detail
func (as *ActivityService) getOneObjectDetail(ctx context.Context, revisionID string) (
resp *schema.ObjectTimelineDetail, err error) {
resp = &schema.ObjectTimelineDetail{Tags: make([]string, 0)}
resp = &schema.ObjectTimelineDetail{Tags: make([]*schema.ObjectTimelineTag, 0)}
// if request revision is 0, return null object detail.
if revisionID == "0" {
return nil, nil
}
revision, err := as.revisionService.GetRevision(ctx, revisionID)
if err != nil {
return nil, err
log.Warn(err)
return nil, nil
}
objInfo, err := as.objectInfoService.GetInfo(ctx, revision.ObjectID)
if err != nil {
@ -160,7 +238,13 @@ func (as *ActivityService) getOneObjectDetail(ctx context.Context, revisionID st
return resp, nil
}
for _, tag := range data.Tags {
resp.Tags = append(resp.Tags, tag.SlugName)
resp.Tags = append(resp.Tags, &schema.ObjectTimelineTag{
SlugName: tag.SlugName,
DisplayName: tag.DisplayName,
MainTagSlugName: tag.MainTagSlugName,
Recommend: tag.Recommend,
Reserved: tag.Reserved,
})
}
resp.Title = data.Title
resp.OriginalText = data.OriginalText
@ -178,8 +262,10 @@ func (as *ActivityService) getOneObjectDetail(ctx context.Context, revisionID st
log.Errorf("revision parsing error %s", err)
return resp, nil
}
resp.Title = data.SlugName
resp.Title = data.DisplayName
resp.OriginalText = data.OriginalText
resp.SlugName = data.SlugName
resp.MainTagSlugName = data.MainTagSlugName
default:
log.Errorf("unknown object type %s", objInfo.ObjectType)
}
@ -187,14 +273,15 @@ func (as *ActivityService) getOneObjectDetail(ctx context.Context, revisionID st
}
func formatActivity(activityType string) (isHidden bool, formattedActivityType string) {
if activityType == "voted_up" || activityType == "voted_down" || activityType == "accepted" {
if activityType == constant.ActVotedUp ||
activityType == constant.ActVotedDown {
return true, ""
}
if activityType == "vote_up" {
return false, "upvote"
if activityType == constant.ActVoteUp {
return false, constant.ActUpVote
}
if activityType == "vote_down" {
return false, "downvote"
if activityType == constant.ActVoteDown {
return false, constant.ActDownVote
}
return false, activityType
}

View File

@ -7,19 +7,18 @@ import (
"time"
"github.com/answerdev/answer/internal/base/constant"
"github.com/answerdev/answer/internal/service/activity"
"github.com/answerdev/answer/internal/service/activity_common"
"github.com/answerdev/answer/internal/service/activity_queue"
"github.com/answerdev/answer/internal/service/notice_queue"
"github.com/answerdev/answer/internal/service/revision_common"
"github.com/answerdev/answer/internal/base/reason"
"github.com/answerdev/answer/internal/entity"
"github.com/answerdev/answer/internal/schema"
"github.com/answerdev/answer/internal/service/activity"
"github.com/answerdev/answer/internal/service/activity_common"
"github.com/answerdev/answer/internal/service/activity_queue"
answercommon "github.com/answerdev/answer/internal/service/answer_common"
collectioncommon "github.com/answerdev/answer/internal/service/collection_common"
"github.com/answerdev/answer/internal/service/notice_queue"
"github.com/answerdev/answer/internal/service/permission"
questioncommon "github.com/answerdev/answer/internal/service/question_common"
"github.com/answerdev/answer/internal/service/revision_common"
usercommon "github.com/answerdev/answer/internal/service/user_common"
"github.com/segmentfault/pacman/errors"
"github.com/segmentfault/pacman/log"
@ -118,6 +117,12 @@ func (as *AnswerService) RemoveAnswer(ctx context.Context, req *schema.RemoveAns
if err != nil {
log.Errorf("delete answer activity change failed: %s", err.Error())
}
activity_queue.AddActivity(&schema.ActivityMsg{
UserID: req.UserID,
ObjectID: answerInfo.ID,
OriginalObjectID: answerInfo.ID,
ActivityTypeKey: constant.ActAnswerDeleted,
})
return
}
@ -367,12 +372,12 @@ func (as *AnswerService) Get(ctx context.Context, answerID, loginUserID string)
return info, questionInfo, has, nil
}
func (as *AnswerService) AdminSetAnswerStatus(ctx context.Context, answerID string, setStatusStr string) error {
setStatus, ok := entity.CmsAnswerSearchStatus[setStatusStr]
func (as *AnswerService) AdminSetAnswerStatus(ctx context.Context, req *schema.AdminSetAnswerStatusRequest) error {
setStatus, ok := entity.CmsAnswerSearchStatus[req.StatusStr]
if !ok {
return fmt.Errorf("question status does not exist")
}
answerInfo, exist, err := as.answerRepo.GetAnswer(ctx, answerID)
answerInfo, exist, err := as.answerRepo.GetAnswer(ctx, req.AnswerID)
if err != nil {
return err
}
@ -389,6 +394,13 @@ func (as *AnswerService) AdminSetAnswerStatus(ctx context.Context, answerID stri
err = as.answerActivityService.DeleteAnswer(ctx, answerInfo.ID, answerInfo.CreatedAt, answerInfo.VoteCount)
if err != nil {
log.Errorf("admin delete question then rank rollback error %s", err.Error())
} else {
activity_queue.AddActivity(&schema.ActivityMsg{
UserID: req.UserID,
ObjectID: answerInfo.ID,
OriginalObjectID: answerInfo.ID,
ActivityTypeKey: constant.ActAnswerDeleted,
})
}
}

View File

@ -150,12 +150,19 @@ func (cs *CommentService) AddComment(ctx context.Context, req *schema.AddComment
resp.UserStatus = userInfo.Status
}
activity_queue.AddActivity(&schema.ActivityMsg{
activityMsg := &schema.ActivityMsg{
UserID: comment.UserID,
ObjectID: comment.ID,
OriginalObjectID: req.ObjectID,
ActivityTypeKey: constant.ActQuestionCommented,
})
}
switch objInfo.ObjectType {
case constant.QuestionObjectType:
activityMsg.ActivityTypeKey = constant.ActQuestionCommented
case constant.AnswerObjectType:
activityMsg.ActivityTypeKey = constant.ActAnswerCommented
}
activity_queue.AddActivity(activityMsg)
return resp, nil
}

View File

@ -710,13 +710,19 @@ func (qs *QuestionService) AdminSetQuestionStatus(ctx context.Context, questionI
if err != nil {
log.Errorf("admin delete question then rank rollback error %s", err.Error())
}
activity_queue.AddActivity(&schema.ActivityMsg{
UserID: questionInfo.UserID,
ObjectID: questionInfo.ID,
OriginalObjectID: questionInfo.ID,
ActivityTypeKey: constant.ActQuestionDeleted,
})
}
if setStatus == entity.QuestionStatusAvailable && questionInfo.Status == entity.QuestionStatusClosed {
activity_queue.AddActivity(&schema.ActivityMsg{
UserID: questionInfo.UserID,
ObjectID: questionInfo.ID,
OriginalObjectID: questionInfo.ID,
ActivityTypeKey: constant.ActQuestionDeleted,
ActivityTypeKey: constant.ActQuestionReopened,
})
}
if setStatus == entity.QuestionStatusClosed && questionInfo.Status != entity.QuestionStatusClosed {

View File

@ -7,6 +7,7 @@ import (
"github.com/answerdev/answer/internal/service/revision"
usercommon "github.com/answerdev/answer/internal/service/user_common"
"github.com/segmentfault/pacman/errors"
"github.com/segmentfault/pacman/log"
"github.com/answerdev/answer/internal/entity"
"github.com/answerdev/answer/internal/schema"
@ -47,6 +48,7 @@ func (rs *RevisionService) GetRevision(ctx context.Context, revisionID string) (
revision *entity.Revision, err error) {
revisionInfo, exist, err := rs.revisionRepo.GetRevisionByID(ctx, revisionID)
if err != nil {
log.Error(err)
return nil, err
}
if !exist {

View File

@ -56,13 +56,17 @@ func NewTagService(
}
// RemoveTag delete tag
func (ts *TagService) RemoveTag(ctx context.Context, tagID string) (err error) {
// TODO permission
err = ts.tagRepo.RemoveTag(ctx, tagID)
func (ts *TagService) RemoveTag(ctx context.Context, req *schema.RemoveTagReq) (err error) {
err = ts.tagRepo.RemoveTag(ctx, req.TagID)
if err != nil {
return err
}
activity_queue.AddActivity(&schema.ActivityMsg{
UserID: req.UserID,
ObjectID: req.TagID,
OriginalObjectID: req.TagID,
ActivityTypeKey: constant.ActTagDeleted,
})
return nil
}