diff --git a/i18n/en_US.yaml b/i18n/en_US.yaml index 28073b70..78a6d447 100644 --- a/i18n/en_US.yaml +++ b/i18n/en_US.yaml @@ -1,4 +1,5 @@ # The following fields are used for back-end + backend: base: success: @@ -97,7 +98,7 @@ backend: other: "Theme not found." revision: review_underway: - other: "Revision review underway." + other: "Can't edit currently, there is a version in the review queue." no_permission: other: "No permission to Revision." user: diff --git a/internal/base/handler/lang.go b/internal/base/handler/lang.go index a6b2122c..4f4a0763 100644 --- a/internal/base/handler/lang.go +++ b/internal/base/handler/lang.go @@ -1,6 +1,8 @@ package handler import ( + "context" + "github.com/answerdev/answer/internal/base/constant" "github.com/gin-gonic/gin" "github.com/segmentfault/pacman/i18n" @@ -18,3 +20,12 @@ func GetLang(ctx *gin.Context) i18n.Language { return i18n.DefaultLang } } + +// GetLangByCtx get language from header +func GetLangByCtx(ctx context.Context) i18n.Language { + acceptLanguage, ok := ctx.Value(constant.AcceptLanguageFlag).(i18n.Language) + if ok { + return acceptLanguage + } + return i18n.DefaultLang +} diff --git a/internal/controller/question_controller.go b/internal/controller/question_controller.go index 68995496..25ddcfd4 100644 --- a/internal/controller/question_controller.go +++ b/internal/controller/question_controller.go @@ -270,39 +270,6 @@ func (qc *QuestionController) UpdateQuestion(ctx *gin.Context) { handler.HandleResponse(ctx, err, resp) } -// CheckCanUpdateQuestion check can update question -// @Summary check can update question -// @Description check can update question -// @Tags Revision -// @Accept json -// @Produce json -// @Security ApiKeyAuth -// @Param id query string true "id" default(string) -// @Success 200 {object} handler.RespBody -// @Router /answer/api/v1/revisions/edit/check [get] -func (qc *QuestionController) CheckCanUpdateQuestion(ctx *gin.Context) { - req := &schema.CheckCanQuestionUpdate{} - if handler.BindAndCheck(ctx, req) { - return - } - req.UserID = middleware.GetLoginUserIDFromContext(ctx) - req.IsAdmin = middleware.GetIsAdminFromContext(ctx) - can, err := qc.rankService.CheckOperationPermission(ctx, req.UserID, rank.QuestionEditRank, req.ID) - if err != nil { - handler.HandleResponse(ctx, err, nil) - return - } - if !can { - handler.HandleResponse(ctx, errors.Forbidden(reason.RankFailToMeetTheCondition), nil) - return - } - - resp, err := qc.questionService.CheckCanUpdate(ctx, req) - handler.HandleResponse(ctx, err, gin.H{ - "unreviewed": resp, - }) -} - // CloseMsgList close question msg list // @Summary close question msg list // @Description close question msg list diff --git a/internal/controller/revision_controller.go b/internal/controller/revision_controller.go index f9693c19..090209b2 100644 --- a/internal/controller/revision_controller.go +++ b/internal/controller/revision_controller.go @@ -1,12 +1,14 @@ package controller import ( + "github.com/answerdev/answer/internal/base/constant" "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/schema" "github.com/answerdev/answer/internal/service" "github.com/answerdev/answer/internal/service/rank" + "github.com/answerdev/answer/pkg/obj" "github.com/gin-gonic/gin" "github.com/segmentfault/pacman/errors" ) @@ -58,7 +60,7 @@ func (rc *RevisionController) GetRevisionList(ctx *gin.Context) { // @Produce json // @Security ApiKeyAuth // @Param page query string true "page id" -// @Success 200 {object} handler.RespBody{data=[]schema.GetRevisionResp} +// @Success 200 {object} handler.RespBody{data=pager.PageModel{list=[]schema.GetUnreviewedRevisionResp}} // @Router /answer/api/v1/revisions/unreviewed [get] func (rc *RevisionController) GetUnreviewedRevisionList(ctx *gin.Context) { req := &schema.RevisionSearch{} @@ -80,11 +82,8 @@ func (rc *RevisionController) GetUnreviewedRevisionList(ctx *gin.Context) { req.CanReviewAnswer = canList[1] req.CanReviewTag = canList[2] - resp, count, err := rc.revisionListService.GetUnreviewedRevisionList(ctx, req) - handler.HandleResponse(ctx, err, gin.H{ - "list": resp, - "count": count, - }) + resp, err := rc.revisionListService.GetUnreviewedRevisionPage(ctx, req) + handler.HandleResponse(ctx, err, resp) } // RevisionAudit godoc @@ -118,3 +117,48 @@ func (rc *RevisionController) RevisionAudit(ctx *gin.Context) { err = rc.revisionListService.RevisionAudit(ctx, req) handler.HandleResponse(ctx, err, gin.H{}) } + +// CheckCanUpdateRevision check can update revision +// @Summary check can update revision +// @Description check can update revision +// @Tags Revision +// @Accept json +// @Produce json +// @Security ApiKeyAuth +// @Param id query string true "id" default(string) +// @Success 200 {object} handler.RespBody +// @Router /answer/api/v1/revisions/edit/check [get] +func (rc *RevisionController) CheckCanUpdateRevision(ctx *gin.Context) { + req := &schema.CheckCanQuestionUpdate{} + if handler.BindAndCheck(ctx, req) { + return + } + req.UserID = middleware.GetLoginUserIDFromContext(ctx) + + action := "" + objectTypeStr, _ := obj.GetObjectTypeStrByObjectID(req.ID) + switch objectTypeStr { + case constant.QuestionObjectType: + action = rank.QuestionEditRank + case constant.AnswerObjectType: + action = rank.AnswerEditRank + case constant.TagObjectType: + action = rank.TagEditRank + default: + handler.HandleResponse(ctx, errors.BadRequest(reason.ObjectNotFound), nil) + return + } + + can, err := rc.rankService.CheckOperationPermission(ctx, req.UserID, action, req.ID) + if err != nil { + handler.HandleResponse(ctx, err, nil) + return + } + if !can { + handler.HandleResponse(ctx, errors.Forbidden(reason.RankFailToMeetTheCondition), nil) + return + } + + err = rc.revisionListService.CheckCanUpdateRevision(ctx, req) + handler.HandleResponse(ctx, err, nil) +} diff --git a/internal/entity/revision_entity.go b/internal/entity/revision_entity.go index ae09cecd..46bfd228 100644 --- a/internal/entity/revision_entity.go +++ b/internal/entity/revision_entity.go @@ -1,6 +1,8 @@ package entity -import "time" +import ( + "time" +) const ( // RevisionUnreviewedStatus this revision is unreviewed @@ -17,7 +19,7 @@ type Revision struct { CreatedAt time.Time `xorm:"created TIMESTAMP created_at"` UpdatedAt time.Time `xorm:"updated TIMESTAMP updated_at"` UserID string `xorm:"not null default 0 BIGINT(20) user_id"` - ObjectType int `xorm:"not null default 0 ) INT(11) object_type"` + ObjectType int `xorm:"not null default 0 INT(11) object_type"` ObjectID string `xorm:"not null default 0 BIGINT(20) INDEX object_id"` Title string `xorm:"not null default '' VARCHAR(255) title"` Content string `xorm:"not null TEXT content"` @@ -26,13 +28,6 @@ type Revision struct { ReviewUserID int64 `xorm:"not null default 0 BIGINT(20) review_user_id"` } -type RevisionSearch struct { - Page int `json:"page" form:"page"` // Query number of pages - CanReviewQuestion bool `json:"-"` - CanReviewAnswer bool `json:"-"` - CanReviewTag bool `json:"-"` -} - // TableName revision table name func (Revision) TableName() string { return "revision" diff --git a/internal/repo/revision/revision_repo.go b/internal/repo/revision/revision_repo.go index f5a1b170..d72a5bb8 100644 --- a/internal/repo/revision/revision_repo.go +++ b/internal/repo/revision/revision_repo.go @@ -5,6 +5,7 @@ import ( "github.com/answerdev/answer/internal/base/constant" "github.com/answerdev/answer/internal/base/data" + "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/service/revision" @@ -165,37 +166,21 @@ func (rr *revisionRepo) allowRecord(objectType int) (ok bool) { } } -func (rr *revisionRepo) SearchUnreviewedList(ctx context.Context, search *entity.RevisionSearch) ([]*entity.Revision, int64, error) { - var count int64 - var err error - rows := make([]*entity.Revision, 0) - if search.Page > 0 { - search.Page = search.Page - 1 - } else { - search.Page = 0 +// GetUnreviewedRevisionPage get unreviewed revision page +func (rr *revisionRepo) GetUnreviewedRevisionPage(ctx context.Context, page int, pageSize int, + objectTypeList []int) (revisionList []*entity.Revision, total int64, err error) { + revisionList = make([]*entity.Revision, 0) + if len(objectTypeList) == 0 { + return revisionList, 0, nil } - PageSize := 1 - offset := search.Page * PageSize - objectType := make([]int, 0) - if search.CanReviewAnswer { - objectType = append(objectType, constant.ObjectTypeStrMapping[constant.AnswerObjectType]) - } - if search.CanReviewQuestion { - objectType = append(objectType, constant.ObjectTypeStrMapping[constant.QuestionObjectType]) - } - if search.CanReviewTag { - objectType = append(objectType, constant.ObjectTypeStrMapping[constant.TagObjectType]) - } - - session := rr.data.DB.Where("") - session = session.And("status = ?", entity.RevisionUnreviewedStatus) - session = session.In("object_type", objectType) + session := rr.data.DB.NewSession() session = session.And("status = ?", entity.RevisionUnreviewedStatus) + session = session.In("object_type", objectTypeList) session = session.OrderBy("created_at desc") - session = session.Limit(PageSize, offset) - count, err = session.FindAndCount(&rows) + + total, err = pager.Help(page, pageSize, &revisionList, &entity.Revision{}, session) if err != nil { - return rows, count, errors.InternalServer(reason.DatabaseError).WithError(err).WithStack() + err = errors.InternalServer(reason.DatabaseError).WithError(err).WithStack() } - return rows, count, nil + return } diff --git a/internal/router/answer_api_router.go b/internal/router/answer_api_router.go index c45aa659..29d6cea4 100644 --- a/internal/router/answer_api_router.go +++ b/internal/router/answer_api_router.go @@ -147,7 +147,7 @@ func (a *AnswerAPIRouter) RegisterAnswerAPIRouter(r *gin.RouterGroup) { //revisions r.GET("/revisions/unreviewed", a.revisionController.GetUnreviewedRevisionList) r.PUT("/revisions/audit", a.revisionController.RevisionAudit) - r.GET("/revisions/edit/check", a.questionController.CheckCanUpdateQuestion) + r.GET("/revisions/edit/check", a.revisionController.CheckCanUpdateRevision) // comment r.POST("/comment", a.commentController.AddComment) diff --git a/internal/schema/revision_schema.go b/internal/schema/revision_schema.go index 01f05828..becb7935 100644 --- a/internal/schema/revision_schema.go +++ b/internal/schema/revision_schema.go @@ -2,6 +2,8 @@ package schema import ( "time" + + "github.com/answerdev/answer/internal/base/constant" ) // AddRevisionDTO add revision request @@ -47,6 +49,20 @@ type RevisionSearch struct { UserID string `json:"-"` } +func (r RevisionSearch) GetCanReviewObjectTypes() []int { + objectType := make([]int, 0) + if r.CanReviewAnswer { + objectType = append(objectType, constant.ObjectTypeStrMapping[constant.AnswerObjectType]) + } + if r.CanReviewQuestion { + objectType = append(objectType, constant.ObjectTypeStrMapping[constant.QuestionObjectType]) + } + if r.CanReviewTag { + objectType = append(objectType, constant.ObjectTypeStrMapping[constant.TagObjectType]) + } + return objectType +} + type GetUnreviewedRevisionResp struct { Type string `json:"type"` Info *UnreviewedRevisionInfoInfo `json:"info"` diff --git a/internal/service/question_service.go b/internal/service/question_service.go index a6523864..536f8c41 100644 --- a/internal/service/question_service.go +++ b/internal/service/question_service.go @@ -7,6 +7,7 @@ import ( "time" "github.com/answerdev/answer/internal/base/constant" + "github.com/answerdev/answer/internal/base/handler" "github.com/answerdev/answer/internal/base/reason" "github.com/answerdev/answer/internal/base/translator" "github.com/answerdev/answer/internal/base/validator" @@ -129,7 +130,7 @@ func (qs *QuestionService) AddQuestion(ctx context.Context, req *schema.Question errorlist := make([]*validator.FormErrorField, 0) errorlist = append(errorlist, &validator.FormErrorField{ ErrorField: "tags", - ErrorMsg: reason.RecommendTagEnter, + ErrorMsg: translator.GlobalTrans.Tr(handler.GetLangByCtx(ctx), reason.RecommendTagEnter), }) err = errors.BadRequest(reason.RecommendTagEnter) return errorlist, err @@ -350,7 +351,7 @@ func (qs *QuestionService) UpdateQuestion(ctx context.Context, req *schema.Quest errorlist := make([]*validator.FormErrorField, 0) errorlist = append(errorlist, &validator.FormErrorField{ ErrorField: "tags", - ErrorMsg: reason.RecommendTagEnter, + ErrorMsg: translator.GlobalTrans.Tr(handler.GetLangByCtx(ctx), reason.RecommendTagEnter), }) err = errors.BadRequest(reason.RecommendTagEnter) return errorlist, err @@ -858,16 +859,3 @@ func (qs *QuestionService) changeQuestionToRevision(ctx context.Context, questio } return questionRevision, nil } - -// CheckCanUpdate can check question answer -func (qs *QuestionService) CheckCanUpdate(ctx context.Context, req *schema.CheckCanQuestionUpdate) (exist bool, err error) { - _, existUnreviewed, err := qs.revisionService.ExistUnreviewedByObjectID(ctx, req.ID) - if err != nil { - return false, err - } - if existUnreviewed { - err = errors.BadRequest(reason.RevisionReviewUnderway) - return existUnreviewed, err - } - return existUnreviewed, nil -} diff --git a/internal/service/revision/revision.go b/internal/service/revision/revision.go index cf146947..f368a27b 100644 --- a/internal/service/revision/revision.go +++ b/internal/service/revision/revision.go @@ -15,6 +15,6 @@ type RevisionRepo interface { GetRevisionList(ctx context.Context, revision *entity.Revision) (revisionList []entity.Revision, err error) UpdateObjectRevisionId(ctx context.Context, revision *entity.Revision, session *xorm.Session) (err error) ExistUnreviewedByObjectID(ctx context.Context, objectID string) (revision *entity.Revision, exist bool, err error) - SearchUnreviewedList(ctx context.Context, search *entity.RevisionSearch) ([]*entity.Revision, int64, error) + GetUnreviewedRevisionPage(ctx context.Context, page, pageSize int, objectTypes []int) ([]*entity.Revision, int64, error) UpdateStatus(ctx context.Context, id string, status int) (err error) } diff --git a/internal/service/revision_common/revision_service.go b/internal/service/revision_common/revision_service.go index 13e4d5ef..cd5c067a 100644 --- a/internal/service/revision_common/revision_service.go +++ b/internal/service/revision_common/revision_service.go @@ -27,10 +27,10 @@ func NewRevisionService(revisionRepo revision.RevisionRepo, userRepo usercommon. } func (rs *RevisionService) GetUnreviewedRevisionCount(ctx context.Context, req *schema.RevisionSearch) (count int64, err error) { - search := &entity.RevisionSearch{} - search.Page = 1 - _ = copier.Copy(search, req) - _, count, err = rs.revisionRepo.SearchUnreviewedList(ctx, search) + if len(req.GetCanReviewObjectTypes()) == 0 { + return 0, nil + } + _, count, err = rs.revisionRepo.GetUnreviewedRevisionPage(ctx, req.Page, 1, req.GetCanReviewObjectTypes()) return count, err } diff --git a/internal/service/revision_service.go b/internal/service/revision_service.go index 20fb14ba..1d13599e 100644 --- a/internal/service/revision_service.go +++ b/internal/service/revision_service.go @@ -6,6 +6,7 @@ import ( "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" @@ -48,7 +49,6 @@ func NewRevisionService( answerRepo answercommon.AnswerRepo, tagRepo tag_common.TagRepo, tagCommon *tagcommon.TagCommonService, - ) *RevisionService { return &RevisionService{ revisionRepo: revisionRepo, @@ -247,43 +247,48 @@ func (rs *RevisionService) revisionAuditTag(ctx context.Context, revisionitem *s return nil } -// SearchUnreviewedList get unreviewed list -func (rs *RevisionService) GetUnreviewedRevisionList(ctx context.Context, req *schema.RevisionSearch) (resp []*schema.GetUnreviewedRevisionResp, count int64, err error) { - resp = []*schema.GetUnreviewedRevisionResp{} - search := &entity.RevisionSearch{} - _ = copier.Copy(search, req) - list, count, err := rs.revisionRepo.SearchUnreviewedList(ctx, search) - for _, revision := range list { +// 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[revision.ObjectType] + _, ok := constant.ObjectTypeNumberMapping[rev.ObjectType] if !ok { continue } - item.Type = constant.ObjectTypeNumberMapping[revision.ObjectType] - info, infoerr := rs.objectInfoService.GetUnreviewedRevisionInfo(ctx, revision.ObjectID) - if infoerr != nil { - return resp, 0, infoerr + 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, revision) + _ = 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 resp, 0, e + return nil, e } if exists { var uinfo schema.UserBasicInfo err = copier.Copy(&uinfo, userInfo) item.UnreviewedInfo.UserInfo = uinfo } - - resp = append(resp, item) + revisionResp = append(revisionResp, item) } - return + return pager.NewPageModel(total, revisionResp), nil } // GetRevisionList get revision list all @@ -377,3 +382,15 @@ func (rs *RevisionService) parseItem(ctx context.Context, item *schema.GetRevisi } item.CreatedAtParsed = item.CreatedAt.Unix() } + +// CheckCanUpdateRevision can check revision +func (rs *RevisionService) CheckCanUpdateRevision(ctx context.Context, req *schema.CheckCanQuestionUpdate) (err error) { + _, exist, err := rs.revisionRepo.ExistUnreviewedByObjectID(ctx, req.ID) + if err != nil { + return err + } + if exist { + return errors.BadRequest(reason.RevisionReviewUnderway) + } + return nil +}