mirror of https://gitee.com/answerdev/answer.git
426 lines
13 KiB
Go
426 lines
13 KiB
Go
package service
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"time"
|
|
|
|
"github.com/answerdev/answer/internal/base/constant"
|
|
"github.com/answerdev/answer/internal/base/pager"
|
|
"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_queue"
|
|
answercommon "github.com/answerdev/answer/internal/service/answer_common"
|
|
"github.com/answerdev/answer/internal/service/notice_queue"
|
|
"github.com/answerdev/answer/internal/service/object_info"
|
|
questioncommon "github.com/answerdev/answer/internal/service/question_common"
|
|
"github.com/answerdev/answer/internal/service/revision"
|
|
"github.com/answerdev/answer/internal/service/tag_common"
|
|
tagcommon "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/jinzhu/copier"
|
|
"github.com/segmentfault/pacman/errors"
|
|
"github.com/segmentfault/pacman/log"
|
|
)
|
|
|
|
// RevisionService user service
|
|
type RevisionService struct {
|
|
revisionRepo revision.RevisionRepo
|
|
userCommon *usercommon.UserCommon
|
|
questionCommon *questioncommon.QuestionCommon
|
|
answerService *AnswerService
|
|
objectInfoService *object_info.ObjService
|
|
questionRepo questioncommon.QuestionRepo
|
|
answerRepo answercommon.AnswerRepo
|
|
tagRepo tag_common.TagRepo
|
|
tagCommon *tagcommon.TagCommonService
|
|
notificationQueueService notice_queue.NotificationQueueService
|
|
activityQueueService activity_queue.ActivityQueueService
|
|
}
|
|
|
|
func NewRevisionService(
|
|
revisionRepo revision.RevisionRepo,
|
|
userCommon *usercommon.UserCommon,
|
|
questionCommon *questioncommon.QuestionCommon,
|
|
answerService *AnswerService,
|
|
objectInfoService *object_info.ObjService,
|
|
questionRepo questioncommon.QuestionRepo,
|
|
answerRepo answercommon.AnswerRepo,
|
|
tagRepo tag_common.TagRepo,
|
|
tagCommon *tagcommon.TagCommonService,
|
|
notificationQueueService notice_queue.NotificationQueueService,
|
|
activityQueueService activity_queue.ActivityQueueService,
|
|
) *RevisionService {
|
|
return &RevisionService{
|
|
revisionRepo: revisionRepo,
|
|
userCommon: userCommon,
|
|
questionCommon: questionCommon,
|
|
answerService: answerService,
|
|
objectInfoService: objectInfoService,
|
|
questionRepo: questionRepo,
|
|
answerRepo: answerRepo,
|
|
tagRepo: tagRepo,
|
|
tagCommon: tagCommon,
|
|
notificationQueueService: notificationQueueService,
|
|
activityQueueService: activityQueueService,
|
|
}
|
|
}
|
|
|
|
func (rs *RevisionService) RevisionAudit(ctx context.Context, req *schema.RevisionAuditReq) (err error) {
|
|
revisioninfo, exist, err := rs.revisionRepo.GetRevisionByID(ctx, req.ID)
|
|
if err != nil {
|
|
return
|
|
}
|
|
if !exist {
|
|
return
|
|
}
|
|
if revisioninfo.Status != entity.RevisionUnreviewedStatus {
|
|
return
|
|
}
|
|
if req.Operation == schema.RevisionAuditReject {
|
|
err = rs.revisionRepo.UpdateStatus(ctx, req.ID, entity.RevisionReviewRejectStatus, req.UserID)
|
|
return
|
|
}
|
|
if req.Operation == schema.RevisionAuditApprove {
|
|
objectType, objectTypeerr := obj.GetObjectTypeStrByObjectID(revisioninfo.ObjectID)
|
|
if objectTypeerr != nil {
|
|
return objectTypeerr
|
|
}
|
|
revisionitem := &schema.GetRevisionResp{}
|
|
_ = copier.Copy(revisionitem, revisioninfo)
|
|
rs.parseItem(ctx, revisionitem)
|
|
var saveErr error
|
|
switch objectType {
|
|
case constant.QuestionObjectType:
|
|
if !req.CanReviewQuestion {
|
|
saveErr = errors.BadRequest(reason.RevisionNoPermission)
|
|
} else {
|
|
saveErr = rs.revisionAuditQuestion(ctx, revisionitem)
|
|
}
|
|
case constant.AnswerObjectType:
|
|
if !req.CanReviewAnswer {
|
|
saveErr = errors.BadRequest(reason.RevisionNoPermission)
|
|
} else {
|
|
saveErr = rs.revisionAuditAnswer(ctx, revisionitem)
|
|
}
|
|
case constant.TagObjectType:
|
|
if !req.CanReviewTag {
|
|
saveErr = errors.BadRequest(reason.RevisionNoPermission)
|
|
} else {
|
|
saveErr = rs.revisionAuditTag(ctx, revisionitem)
|
|
}
|
|
}
|
|
if saveErr != nil {
|
|
return saveErr
|
|
}
|
|
err = rs.revisionRepo.UpdateStatus(ctx, req.ID, entity.RevisionReviewPassStatus, req.UserID)
|
|
return
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (rs *RevisionService) revisionAuditQuestion(ctx context.Context, revisionitem *schema.GetRevisionResp) (err error) {
|
|
questioninfo, ok := revisionitem.ContentParsed.(*schema.QuestionInfo)
|
|
if ok {
|
|
var PostUpdateTime time.Time
|
|
dbquestion, exist, dberr := rs.questionRepo.GetQuestion(ctx, questioninfo.ID)
|
|
if dberr != nil || !exist {
|
|
return
|
|
}
|
|
|
|
PostUpdateTime = time.Unix(questioninfo.UpdateTime, 0)
|
|
if dbquestion.PostUpdateTime.Unix() > PostUpdateTime.Unix() {
|
|
PostUpdateTime = dbquestion.PostUpdateTime
|
|
}
|
|
question := &entity.Question{}
|
|
question.ID = questioninfo.ID
|
|
question.Title = questioninfo.Title
|
|
question.OriginalText = questioninfo.Content
|
|
question.ParsedText = questioninfo.HTML
|
|
question.UpdatedAt = time.Unix(questioninfo.UpdateTime, 0)
|
|
question.PostUpdateTime = PostUpdateTime
|
|
question.LastEditUserID = revisionitem.UserID
|
|
saveerr := rs.questionRepo.UpdateQuestion(ctx, question, []string{"title", "original_text", "parsed_text", "updated_at", "post_update_time", "last_edit_user_id"})
|
|
if saveerr != nil {
|
|
return saveerr
|
|
}
|
|
objectTagTags := make([]*schema.TagItem, 0)
|
|
for _, tag := range questioninfo.Tags {
|
|
item := &schema.TagItem{}
|
|
item.SlugName = tag.SlugName
|
|
objectTagTags = append(objectTagTags, item)
|
|
}
|
|
objectTagData := schema.TagChange{}
|
|
objectTagData.ObjectID = question.ID
|
|
objectTagData.Tags = objectTagTags
|
|
saveerr = rs.tagCommon.ObjectChangeTag(ctx, &objectTagData)
|
|
if saveerr != nil {
|
|
return saveerr
|
|
}
|
|
rs.activityQueueService.Send(ctx, &schema.ActivityMsg{
|
|
UserID: revisionitem.UserID,
|
|
ObjectID: revisionitem.ObjectID,
|
|
ActivityTypeKey: constant.ActQuestionEdited,
|
|
RevisionID: revisionitem.ID,
|
|
OriginalObjectID: revisionitem.ObjectID,
|
|
})
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (rs *RevisionService) revisionAuditAnswer(ctx context.Context, revisionitem *schema.GetRevisionResp) (err error) {
|
|
answerinfo, ok := revisionitem.ContentParsed.(*schema.AnswerInfo)
|
|
if ok {
|
|
|
|
var PostUpdateTime time.Time
|
|
dbquestion, exist, dberr := rs.questionRepo.GetQuestion(ctx, answerinfo.QuestionID)
|
|
if dberr != nil || !exist {
|
|
return
|
|
}
|
|
|
|
PostUpdateTime = time.Unix(answerinfo.UpdateTime, 0)
|
|
if dbquestion.PostUpdateTime.Unix() > PostUpdateTime.Unix() {
|
|
PostUpdateTime = dbquestion.PostUpdateTime
|
|
}
|
|
|
|
insertData := new(entity.Answer)
|
|
insertData.ID = answerinfo.ID
|
|
insertData.OriginalText = answerinfo.Content
|
|
insertData.ParsedText = answerinfo.HTML
|
|
insertData.UpdatedAt = time.Unix(answerinfo.UpdateTime, 0)
|
|
insertData.LastEditUserID = revisionitem.UserID
|
|
saveerr := rs.answerRepo.UpdateAnswer(ctx, insertData, []string{"original_text", "parsed_text", "updated_at", "last_edit_user_id"})
|
|
if saveerr != nil {
|
|
return saveerr
|
|
}
|
|
saveerr = rs.questionCommon.UpdatePostSetTime(ctx, answerinfo.QuestionID, PostUpdateTime)
|
|
if saveerr != nil {
|
|
return saveerr
|
|
}
|
|
questionInfo, exist, err := rs.questionRepo.GetQuestion(ctx, answerinfo.QuestionID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if !exist {
|
|
return errors.BadRequest(reason.QuestionNotFound)
|
|
}
|
|
msg := &schema.NotificationMsg{
|
|
TriggerUserID: revisionitem.UserID,
|
|
ReceiverUserID: questionInfo.UserID,
|
|
Type: schema.NotificationTypeInbox,
|
|
ObjectID: answerinfo.ID,
|
|
}
|
|
msg.ObjectType = constant.AnswerObjectType
|
|
msg.NotificationAction = constant.NotificationUpdateAnswer
|
|
rs.notificationQueueService.Send(ctx, msg)
|
|
|
|
rs.activityQueueService.Send(ctx, &schema.ActivityMsg{
|
|
UserID: revisionitem.UserID,
|
|
ObjectID: insertData.ID,
|
|
OriginalObjectID: insertData.ID,
|
|
ActivityTypeKey: constant.ActAnswerEdited,
|
|
RevisionID: revisionitem.ID,
|
|
})
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (rs *RevisionService) revisionAuditTag(ctx context.Context, revisionitem *schema.GetRevisionResp) (err error) {
|
|
taginfo, ok := revisionitem.ContentParsed.(*schema.GetTagResp)
|
|
if ok {
|
|
tag := &entity.Tag{}
|
|
tag.ID = taginfo.TagID
|
|
tag.OriginalText = taginfo.OriginalText
|
|
tag.ParsedText = taginfo.ParsedText
|
|
saveerr := rs.tagRepo.UpdateTag(ctx, tag)
|
|
if saveerr != nil {
|
|
return saveerr
|
|
}
|
|
|
|
tagInfo, exist, err := rs.tagCommon.GetTagByID(ctx, taginfo.TagID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if !exist {
|
|
return errors.BadRequest(reason.TagNotFound)
|
|
}
|
|
if tagInfo.MainTagID == 0 && len(tagInfo.SlugName) > 0 {
|
|
log.Debugf("tag %s update slug_name", tagInfo.SlugName)
|
|
tagList, err := rs.tagRepo.GetTagList(ctx, &entity.Tag{MainTagID: converter.StringToInt64(tagInfo.ID)})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
updateTagSlugNames := make([]string, 0)
|
|
for _, tag := range tagList {
|
|
updateTagSlugNames = append(updateTagSlugNames, tag.SlugName)
|
|
}
|
|
err = rs.tagRepo.UpdateTagSynonym(ctx, updateTagSlugNames, converter.StringToInt64(tagInfo.ID), tagInfo.MainTagSlugName)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
rs.activityQueueService.Send(ctx, &schema.ActivityMsg{
|
|
UserID: revisionitem.UserID,
|
|
ObjectID: taginfo.TagID,
|
|
OriginalObjectID: taginfo.TagID,
|
|
ActivityTypeKey: constant.ActTagEdited,
|
|
RevisionID: revisionitem.ID,
|
|
})
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// GetUnreviewedRevisionPage get unreviewed list
|
|
func (rs *RevisionService) GetUnreviewedRevisionPage(ctx context.Context, req *schema.RevisionSearch) (
|
|
resp *pager.PageModel, err error) {
|
|
revisionResp := make([]*schema.GetUnreviewedRevisionResp, 0)
|
|
if len(req.GetCanReviewObjectTypes()) == 0 {
|
|
return pager.NewPageModel(0, revisionResp), nil
|
|
}
|
|
revisionPage, total, err := rs.revisionRepo.GetUnreviewedRevisionPage(
|
|
ctx, req.Page, 1, req.GetCanReviewObjectTypes())
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
for _, rev := range revisionPage {
|
|
item := &schema.GetUnreviewedRevisionResp{}
|
|
_, ok := constant.ObjectTypeNumberMapping[rev.ObjectType]
|
|
if !ok {
|
|
continue
|
|
}
|
|
item.Type = constant.ObjectTypeNumberMapping[rev.ObjectType]
|
|
info, err := rs.objectInfoService.GetUnreviewedRevisionInfo(ctx, rev.ObjectID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
item.Info = info
|
|
revisionitem := &schema.GetRevisionResp{}
|
|
_ = copier.Copy(revisionitem, rev)
|
|
rs.parseItem(ctx, revisionitem)
|
|
item.UnreviewedInfo = revisionitem
|
|
|
|
// get user info
|
|
userInfo, exists, e := rs.userCommon.GetUserBasicInfoByID(ctx, revisionitem.UserID)
|
|
if e != nil {
|
|
return nil, e
|
|
}
|
|
if exists {
|
|
var uinfo schema.UserBasicInfo
|
|
_ = copier.Copy(&uinfo, userInfo)
|
|
item.UnreviewedInfo.UserInfo = uinfo
|
|
}
|
|
revisionResp = append(revisionResp, item)
|
|
}
|
|
return pager.NewPageModel(total, revisionResp), nil
|
|
}
|
|
|
|
// GetRevisionList get revision list all
|
|
func (rs *RevisionService) GetRevisionList(ctx context.Context, req *schema.GetRevisionListReq) (resp []schema.GetRevisionResp, err error) {
|
|
var (
|
|
rev entity.Revision
|
|
revs []entity.Revision
|
|
)
|
|
|
|
resp = []schema.GetRevisionResp{}
|
|
_ = copier.Copy(&rev, req)
|
|
|
|
revs, err = rs.revisionRepo.GetRevisionList(ctx, &rev)
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
for _, r := range revs {
|
|
var (
|
|
uinfo schema.UserBasicInfo
|
|
item schema.GetRevisionResp
|
|
)
|
|
|
|
_ = copier.Copy(&item, r)
|
|
rs.parseItem(ctx, &item)
|
|
|
|
// get user info
|
|
userInfo, exists, e := rs.userCommon.GetUserBasicInfoByID(ctx, item.UserID)
|
|
if e != nil {
|
|
return nil, e
|
|
}
|
|
if exists {
|
|
err = copier.Copy(&uinfo, userInfo)
|
|
item.UserInfo = uinfo
|
|
}
|
|
resp = append(resp, item)
|
|
}
|
|
return
|
|
}
|
|
|
|
func (rs *RevisionService) parseItem(ctx context.Context, item *schema.GetRevisionResp) {
|
|
var (
|
|
err error
|
|
question entity.QuestionWithTagsRevision
|
|
questionInfo *schema.QuestionInfo
|
|
answer entity.Answer
|
|
answerInfo *schema.AnswerInfo
|
|
tag entity.Tag
|
|
tagInfo *schema.GetTagResp
|
|
)
|
|
|
|
switch item.ObjectType {
|
|
case constant.ObjectTypeStrMapping["question"]:
|
|
err = json.Unmarshal([]byte(item.Content), &question)
|
|
if err != nil {
|
|
break
|
|
}
|
|
questionInfo = rs.questionCommon.ShowFormatWithTag(ctx, &question)
|
|
item.ContentParsed = questionInfo
|
|
case constant.ObjectTypeStrMapping["answer"]:
|
|
err = json.Unmarshal([]byte(item.Content), &answer)
|
|
if err != nil {
|
|
break
|
|
}
|
|
answerInfo = rs.answerService.ShowFormat(ctx, &answer)
|
|
item.ContentParsed = answerInfo
|
|
case constant.ObjectTypeStrMapping["tag"]:
|
|
err = json.Unmarshal([]byte(item.Content), &tag)
|
|
if err != nil {
|
|
break
|
|
}
|
|
tagInfo = &schema.GetTagResp{
|
|
TagID: tag.ID,
|
|
CreatedAt: tag.CreatedAt.Unix(),
|
|
UpdatedAt: tag.UpdatedAt.Unix(),
|
|
SlugName: tag.SlugName,
|
|
DisplayName: tag.DisplayName,
|
|
OriginalText: tag.OriginalText,
|
|
ParsedText: tag.ParsedText,
|
|
FollowCount: tag.FollowCount,
|
|
QuestionCount: tag.QuestionCount,
|
|
Recommend: tag.Recommend,
|
|
Reserved: tag.Reserved,
|
|
}
|
|
tagInfo.GetExcerpt()
|
|
item.ContentParsed = tagInfo
|
|
}
|
|
|
|
if err != nil {
|
|
item.ContentParsed = item.Content
|
|
}
|
|
item.CreatedAtParsed = item.CreatedAt.Unix()
|
|
}
|
|
|
|
// CheckCanUpdateRevision can check revision
|
|
func (rs *RevisionService) CheckCanUpdateRevision(ctx context.Context, req *schema.CheckCanQuestionUpdate) (
|
|
resp *schema.ErrTypeData, err error) {
|
|
_, exist, err := rs.revisionRepo.ExistUnreviewedByObjectID(ctx, req.ID)
|
|
if err != nil {
|
|
return nil, nil
|
|
}
|
|
if exist {
|
|
return &schema.ErrTypeToast, errors.BadRequest(reason.RevisionReviewUnderway)
|
|
}
|
|
return nil, nil
|
|
}
|