diff --git a/docs/docs.go b/docs/docs.go index 96f9cf1a..780e41dd 100644 --- a/docs/docs.go +++ b/docs/docs.go @@ -49,7 +49,7 @@ const docTemplate = `{ "tags": [ "admin" ], - "summary": "AdminSearchAnswerList", + "summary": "AdminAnswerPage admin answer page", "parameters": [ { "type": "integer", @@ -379,7 +379,7 @@ const docTemplate = `{ "tags": [ "admin" ], - "summary": "AdminSearchList", + "summary": "AdminQuestionPage admin question page", "parameters": [ { "type": "integer", @@ -8186,7 +8186,7 @@ const docTemplate = `{ "type": "string" }, "site_seo": { - "$ref": "#/definitions/schema.SiteSeoReq" + "$ref": "#/definitions/schema.SiteSeoResp" }, "site_users": { "$ref": "#/definitions/schema.SiteUsersResp" diff --git a/docs/swagger.json b/docs/swagger.json index 8a0db0e1..df3eee70 100644 --- a/docs/swagger.json +++ b/docs/swagger.json @@ -37,7 +37,7 @@ "tags": [ "admin" ], - "summary": "AdminSearchAnswerList", + "summary": "AdminAnswerPage admin answer page", "parameters": [ { "type": "integer", @@ -367,7 +367,7 @@ "tags": [ "admin" ], - "summary": "AdminSearchList", + "summary": "AdminQuestionPage admin question page", "parameters": [ { "type": "integer", @@ -8174,7 +8174,7 @@ "type": "string" }, "site_seo": { - "$ref": "#/definitions/schema.SiteSeoReq" + "$ref": "#/definitions/schema.SiteSeoResp" }, "site_users": { "$ref": "#/definitions/schema.SiteUsersResp" diff --git a/docs/swagger.yaml b/docs/swagger.yaml index 4f73fe51..e2b9c829 100644 --- a/docs/swagger.yaml +++ b/docs/swagger.yaml @@ -1507,7 +1507,7 @@ definitions: revision: type: string site_seo: - $ref: '#/definitions/schema.SiteSeoReq' + $ref: '#/definitions/schema.SiteSeoResp' site_users: $ref: '#/definitions/schema.SiteUsersResp' theme: @@ -2335,7 +2335,7 @@ paths: $ref: '#/definitions/handler.RespBody' security: - ApiKeyAuth: [] - summary: AdminSearchAnswerList + summary: AdminAnswerPage admin answer page tags: - admin /answer/admin/api/answer/status: @@ -2533,7 +2533,7 @@ paths: $ref: '#/definitions/handler.RespBody' security: - ApiKeyAuth: [] - summary: AdminSearchList + summary: AdminQuestionPage admin question page tags: - admin /answer/admin/api/question/status: diff --git a/internal/controller/question_controller.go b/internal/controller/question_controller.go index 29eda5ff..aa24fd32 100644 --- a/internal/controller/question_controller.go +++ b/internal/controller/question_controller.go @@ -7,7 +7,6 @@ import ( "github.com/answerdev/answer/internal/base/reason" "github.com/answerdev/answer/internal/base/translator" "github.com/answerdev/answer/internal/base/validator" - "github.com/answerdev/answer/internal/entity" "github.com/answerdev/answer/internal/schema" "github.com/answerdev/answer/internal/service" "github.com/answerdev/answer/internal/service/permission" @@ -709,8 +708,8 @@ func (qc *QuestionController) PersonalCollectionPage(ctx *gin.Context) { handler.HandleResponse(ctx, err, resp) } -// AdminSearchList godoc -// @Summary AdminSearchList +// AdminQuestionPage admin question page +// @Summary AdminQuestionPage admin question page // @Description Status:[available,closed,deleted] // @Tags admin // @Accept json @@ -722,21 +721,19 @@ func (qc *QuestionController) PersonalCollectionPage(ctx *gin.Context) { // @Param query query string false "question id or title" // @Success 200 {object} handler.RespBody // @Router /answer/admin/api/question/page [get] -func (qc *QuestionController) AdminSearchList(ctx *gin.Context) { - req := &schema.AdminQuestionSearch{} +func (qc *QuestionController) AdminQuestionPage(ctx *gin.Context) { + req := &schema.AdminQuestionPageReq{} if handler.BindAndCheck(ctx, req) { return } - userID := middleware.GetLoginUserIDFromContext(ctx) - questionList, count, err := qc.questionService.AdminSearchList(ctx, req, userID) - handler.HandleResponse(ctx, err, gin.H{ - "list": questionList, - "count": count, - }) + + req.LoginUserID = middleware.GetLoginUserIDFromContext(ctx) + resp, err := qc.questionService.AdminQuestionPage(ctx, req) + handler.HandleResponse(ctx, err, resp) } -// AdminSearchAnswerList godoc -// @Summary AdminSearchAnswerList +// AdminAnswerPage admin answer page +// @Summary AdminAnswerPage admin answer page // @Description Status:[available,deleted] // @Tags admin // @Accept json @@ -749,21 +746,15 @@ func (qc *QuestionController) AdminSearchList(ctx *gin.Context) { // @Param question_id query string false "question id" // @Success 200 {object} handler.RespBody // @Router /answer/admin/api/answer/page [get] -func (qc *QuestionController) AdminSearchAnswerList(ctx *gin.Context) { - req := &entity.AdminAnswerSearch{} +func (qc *QuestionController) AdminAnswerPage(ctx *gin.Context) { + req := &schema.AdminAnswerPageReq{} if handler.BindAndCheck(ctx, req) { return } - req.QuestionID = uid.DeShortID(req.QuestionID) - if req.QuestionID == "0" { - req.QuestionID = "" - } - userID := middleware.GetLoginUserIDFromContext(ctx) - questionList, count, err := qc.questionService.AdminSearchAnswerList(ctx, req, userID) - handler.HandleResponse(ctx, err, gin.H{ - "list": questionList, - "count": count, - }) + + req.LoginUserID = middleware.GetLoginUserIDFromContext(ctx) + resp, err := qc.questionService.AdminAnswerPage(ctx, req) + handler.HandleResponse(ctx, err, resp) } // AdminSetQuestionStatus godoc diff --git a/internal/entity/answer_entity.go b/internal/entity/answer_entity.go index 43567efd..74b599dc 100644 --- a/internal/entity/answer_entity.go +++ b/internal/entity/answer_entity.go @@ -42,15 +42,6 @@ type AnswerSearch struct { PageSize int `json:"page_size" form:"page_size"` // Search page size } -type AdminAnswerSearch struct { - Page int `json:"page" form:"page"` // Query number of pages - PageSize int `json:"page_size" form:"page_size"` // Search page size - Status int `json:"-" form:"-"` - StatusStr string `json:"status" form:"status"` // Status 1 Available 2 closed 10 Deleted - Query string `validate:"omitempty,gt=0,lte=100" json:"query" form:"query" ` //Query string - QuestionID string `validate:"omitempty,gt=0,lte=24" json:"question_id" form:"question_id" ` //Query string -} - // TableName answer table name func (Answer) TableName() string { return "answer" diff --git a/internal/repo/answer/answer_repo.go b/internal/repo/answer/answer_repo.go index 1176d43e..2cf18c9d 100644 --- a/internal/repo/answer/answer_repo.go +++ b/internal/repo/answer/answer_repo.go @@ -2,15 +2,11 @@ package answer import ( "context" - "strings" "time" - "unicode" - - "github.com/answerdev/answer/internal/base/handler" - "xorm.io/builder" "github.com/answerdev/answer/internal/base/constant" "github.com/answerdev/answer/internal/base/data" + "github.com/answerdev/answer/internal/base/handler" "github.com/answerdev/answer/internal/base/pager" "github.com/answerdev/answer/internal/base/reason" "github.com/answerdev/answer/internal/entity" @@ -295,82 +291,31 @@ func (ar *answerRepo) SearchList(ctx context.Context, search *entity.AnswerSearc return rows, count, nil } -func (ar *answerRepo) AdminSearchList(ctx context.Context, search *entity.AdminAnswerSearch) ([]*entity.Answer, int64, error) { - var ( - count int64 - err error - session = ar.data.DB.Context(ctx).Table([]string{entity.Answer{}.TableName(), "a"}).Select("a.*") - ) - if search.QuestionID != "" { - search.QuestionID = uid.DeShortID(search.QuestionID) - } - - session.Where(builder.Eq{ - "a.status": search.Status, - }) - - rows := make([]*entity.Answer, 0) - if search.Page > 0 { - search.Page = search.Page - 1 - } else { - search.Page = 0 - } - if search.PageSize == 0 { - search.PageSize = constant.DefaultPageSize - } - - // search by question title like or answer id - if len(search.Query) > 0 { - // check id search - var ( - idSearch = false - id = "" - ) - - if strings.Contains(search.Query, "answer:") { - idSearch = true - id = strings.TrimSpace(strings.TrimPrefix(search.Query, "answer:")) - id = uid.DeShortID(id) - for _, r := range id { - if !unicode.IsDigit(r) { - idSearch = false - break - } - } - } - - if idSearch { - session.And(builder.Eq{ - "id": id, - }) - } else { - session.Join("LEFT", []string{entity.Question{}.TableName(), "q"}, "q.id = a.question_id") - session.And(builder.Like{ - "q.title", search.Query, - }) +func (ar *answerRepo) AdminSearchList(ctx context.Context, req *schema.AdminAnswerPageReq) ( + resp []*entity.Answer, total int64, err error) { + cond := &entity.Answer{} + session := ar.data.DB.Context(ctx) + if len(req.QuestionID) == 0 && len(req.AnswerID) == 0 { + session.Join("INNER", "question", "answer.question_id = question.id") + if len(req.QuestionTitle) > 0 { + session.Where("question.title like ?", "%"+req.QuestionTitle+"%") } } - - // check search by question id - if len(search.QuestionID) > 0 { - session.And(builder.Eq{ - "question_id": search.QuestionID, - }) + if len(req.AnswerID) > 0 { + cond.ID = req.AnswerID } + if len(req.QuestionID) > 0 { + session.Where("answer.question_id = ?", req.QuestionID) + } + if req.Status > 0 { + cond.Status = req.Status + } + session.Desc("answer.created_at") - offset := search.Page * search.PageSize - session. - OrderBy("a.created_at desc"). - Limit(search.PageSize, offset) - count, err = session.FindAndCount(&rows) + resp = make([]*entity.Answer, 0) + total, err = pager.Help(req.Page, req.PageSize, &resp, cond, session) if err != nil { - return rows, count, errors.InternalServer(reason.DatabaseError).WithError(err).WithStack() + return nil, 0, errors.InternalServer(reason.DatabaseError).WithError(err).WithStack() } - if handler.GetEnableShortID(ctx) { - for _, item := range rows { - item.ID = uid.EnShortID(item.ID) - item.QuestionID = uid.EnShortID(item.QuestionID) - } - } - return rows, count, nil + return resp, total, nil } diff --git a/internal/repo/question/question_repo.go b/internal/repo/question/question_repo.go index 7c20724d..c14f0cb7 100644 --- a/internal/repo/question/question_repo.go +++ b/internal/repo/question/question_repo.go @@ -333,7 +333,7 @@ func (qr *questionRepo) GetQuestionPage(ctx context.Context, page, pageSize int, return questionList, total, err } -func (qr *questionRepo) AdminSearchList(ctx context.Context, search *schema.AdminQuestionSearch) ([]*entity.Question, int64, error) { +func (qr *questionRepo) AdminQuestionPage(ctx context.Context, search *schema.AdminQuestionPageReq) ([]*entity.Question, int64, error) { var ( count int64 err error diff --git a/internal/router/answer_api_router.go b/internal/router/answer_api_router.go index 5aaebb86..897deace 100644 --- a/internal/router/answer_api_router.go +++ b/internal/router/answer_api_router.go @@ -244,9 +244,9 @@ func (a *AnswerAPIRouter) RegisterAnswerAPIRouter(r *gin.RouterGroup) { } func (a *AnswerAPIRouter) RegisterAnswerAdminAPIRouter(r *gin.RouterGroup) { - r.GET("/question/page", a.questionController.AdminSearchList) + r.GET("/question/page", a.questionController.AdminQuestionPage) r.PUT("/question/status", a.questionController.AdminSetQuestionStatus) - r.GET("/answer/page", a.questionController.AdminSearchAnswerList) + r.GET("/answer/page", a.questionController.AdminAnswerPage) r.PUT("/answer/status", a.answerController.AdminSetAnswerStatus) // report diff --git a/internal/schema/question_schema.go b/internal/schema/question_schema.go index acabc0d2..82c3f749 100644 --- a/internal/schema/question_schema.go +++ b/internal/schema/question_schema.go @@ -1,10 +1,13 @@ package schema import ( + "strings" "time" "github.com/answerdev/answer/internal/base/validator" + "github.com/answerdev/answer/internal/entity" "github.com/answerdev/answer/pkg/converter" + "github.com/answerdev/answer/pkg/uid" ) const ( @@ -361,12 +364,62 @@ type QuestionPageRespOperator struct { DisplayName string `json:"display_name"` } -type AdminQuestionSearch struct { - Page int `json:"page" form:"page"` // Query number of pages - PageSize int `json:"page_size" form:"page_size"` // Search page size - Status int `json:"-" form:"-"` - StatusStr string `json:"status" form:"status"` // Status 1 Available 2 closed 10 UserDeleted - Query string `validate:"omitempty,gt=0,lte=100" json:"query" form:"query" ` //Query string +type AdminQuestionPageReq struct { + Page int `validate:"omitempty,min=1" form:"page"` + PageSize int `validate:"omitempty,min=1" form:"page_size"` + StatusCond string `validate:"omitempty,oneof=normal closed deleted" form:"status"` + Query string `validate:"omitempty,gt=0,lte=100" json:"query" form:"query" ` + Status int `json:"-"` + LoginUserID string `json:"-"` +} + +func (req *AdminQuestionPageReq) Check() (errField []*validator.FormErrorField, err error) { + status, ok := entity.AdminQuestionSearchStatus[req.StatusCond] + if ok { + req.Status = status + } + if req.Status == 0 { + req.Status = 1 + } + return nil, nil +} + +// AdminAnswerPageReq admin answer page req +type AdminAnswerPageReq struct { + Page int `validate:"omitempty,min=1" form:"page"` + PageSize int `validate:"omitempty,min=1" form:"page_size"` + StatusCond string `validate:"omitempty,oneof=normal deleted" form:"status"` + Query string `validate:"omitempty,gt=0,lte=100" form:"query"` + QuestionID string `validate:"omitempty,gt=0,lte=24" form:"question_id"` + QuestionTitle string `json:"-"` + AnswerID string `json:"-"` + Status int `json:"-"` + LoginUserID string `json:"-"` +} + +func (req *AdminAnswerPageReq) Check() (errField []*validator.FormErrorField, err error) { + req.QuestionID = uid.DeShortID(req.QuestionID) + if req.QuestionID == "0" { + req.QuestionID = "" + } + + if status, ok := entity.AdminAnswerSearchStatus[req.StatusCond]; ok { + req.Status = status + } + if req.Status == 0 { + req.Status = 1 + } + + // parse query condition + if len(req.Query) > 0 { + prefix := "answer:" + if strings.Contains(req.Query, prefix) { + req.AnswerID = uid.DeShortID(strings.TrimSpace(strings.TrimPrefix(req.Query, prefix))) + } else { + req.QuestionTitle = strings.TrimSpace(req.Query) + } + } + return nil, nil } type AdminSetQuestionStatusRequest struct { diff --git a/internal/service/answer_common/answer.go b/internal/service/answer_common/answer.go index c23e6822..2373a6d0 100644 --- a/internal/service/answer_common/answer.go +++ b/internal/service/answer_common/answer.go @@ -3,9 +3,11 @@ package answercommon import ( "context" + "github.com/answerdev/answer/internal/base/handler" "github.com/answerdev/answer/internal/entity" "github.com/answerdev/answer/internal/schema" "github.com/answerdev/answer/pkg/htmltext" + "github.com/answerdev/answer/pkg/uid" ) type AnswerRepo interface { @@ -21,7 +23,7 @@ type AnswerRepo interface { GetCountByUserID(ctx context.Context, userID string) (int64, error) GetByUserIDQuestionID(ctx context.Context, userID string, questionID string) (*entity.Answer, bool, error) SearchList(ctx context.Context, search *entity.AnswerSearch) ([]*entity.Answer, int64, error) - AdminSearchList(ctx context.Context, search *entity.AdminAnswerSearch) ([]*entity.Answer, int64, error) + AdminSearchList(ctx context.Context, search *schema.AdminAnswerPageReq) ([]*entity.Answer, int64, error) UpdateAnswerStatus(ctx context.Context, answer *entity.Answer) (err error) GetAnswerCount(ctx context.Context) (count int64, err error) } @@ -45,11 +47,16 @@ func (as *AnswerCommon) SearchAnswered(ctx context.Context, userID, questionID s return has, nil } -func (as *AnswerCommon) AdminSearchList(ctx context.Context, search *entity.AdminAnswerSearch) ([]*entity.Answer, int64, error) { - if search.Status == 0 { - search.Status = 1 +func (as *AnswerCommon) AdminSearchList(ctx context.Context, req *schema.AdminAnswerPageReq) ( + resp []*entity.Answer, count int64, err error) { + resp, count, err = as.answerRepo.AdminSearchList(ctx, req) + if handler.GetEnableShortID(ctx) { + for _, item := range resp { + item.ID = uid.EnShortID(item.ID) + item.QuestionID = uid.EnShortID(item.QuestionID) + } } - return as.answerRepo.AdminSearchList(ctx, search) + return resp, count, err } func (as *AnswerCommon) Search(ctx context.Context, search *entity.AnswerSearch) ([]*entity.Answer, int64, error) { diff --git a/internal/service/question_common/question.go b/internal/service/question_common/question.go index 2f8a9073..a3ba10c4 100644 --- a/internal/service/question_common/question.go +++ b/internal/service/question_common/question.go @@ -48,7 +48,7 @@ type QuestionRepo interface { UpdateAccepted(ctx context.Context, question *entity.Question) (err error) UpdateLastAnswer(ctx context.Context, question *entity.Question) (err error) FindByID(ctx context.Context, id []string) (questionList []*entity.Question, err error) - AdminSearchList(ctx context.Context, search *schema.AdminQuestionSearch) ([]*entity.Question, int64, error) + AdminQuestionPage(ctx context.Context, search *schema.AdminQuestionPageReq) ([]*entity.Question, int64, error) GetQuestionCount(ctx context.Context) (count int64, err error) GetUserQuestionCount(ctx context.Context, userID string) (count int64, err error) GetQuestionCountByIDs(ctx context.Context, ids []string) (count int64, err error) @@ -68,7 +68,7 @@ type QuestionCommon struct { metaService *meta.MetaService configService *config.ConfigService activityQueueService activity_queue.ActivityQueueService - data *data.Data + data *data.Data } func NewQuestionCommon(questionRepo QuestionRepo, @@ -96,7 +96,7 @@ func NewQuestionCommon(questionRepo QuestionRepo, metaService: metaService, configService: configService, activityQueueService: activityQueueService, - data: data, + data: data, } } diff --git a/internal/service/question_service.go b/internal/service/question_service.go index 6bfab8a0..dff02550 100644 --- a/internal/service/question_service.go +++ b/internal/service/question_service.go @@ -1256,89 +1256,73 @@ func (qs *QuestionService) AdminSetQuestionStatus(ctx context.Context, questionI return nil } -func (qs *QuestionService) AdminSearchList(ctx context.Context, search *schema.AdminQuestionSearch, loginUserID string) ([]*schema.AdminQuestionInfo, int64, error) { +func (qs *QuestionService) AdminQuestionPage( + ctx context.Context, req *schema.AdminQuestionPageReq) ( + resp *pager.PageModel, err error) { + list := make([]*schema.AdminQuestionInfo, 0) - - status, ok := entity.AdminQuestionSearchStatus[search.StatusStr] - if ok { - search.Status = status - } - - if search.Status == 0 { - search.Status = 1 - } - dblist, count, err := qs.questionRepo.AdminSearchList(ctx, search) + questionList, count, err := qs.questionRepo.AdminQuestionPage(ctx, req) if err != nil { - return list, count, err + return nil, err } + userIds := make([]string, 0) - for _, dbitem := range dblist { + for _, info := range questionList { item := &schema.AdminQuestionInfo{} - _ = copier.Copy(item, dbitem) - item.CreateTime = dbitem.CreatedAt.Unix() - item.UpdateTime = dbitem.PostUpdateTime.Unix() - item.EditTime = dbitem.UpdatedAt.Unix() + _ = copier.Copy(item, info) + item.CreateTime = info.CreatedAt.Unix() + item.UpdateTime = info.PostUpdateTime.Unix() + item.EditTime = info.UpdatedAt.Unix() list = append(list, item) - userIds = append(userIds, dbitem.UserID) + userIds = append(userIds, info.UserID) } userInfoMap, err := qs.userCommon.BatchUserBasicInfoByID(ctx, userIds) if err != nil { - return list, count, err + return nil, err } for _, item := range list { - _, ok = userInfoMap[item.UserID] - if ok { - item.UserInfo = userInfoMap[item.UserID] + if u, ok := userInfoMap[item.UserID]; ok { + item.UserInfo = u } } - - return list, count, nil + return pager.NewPageModel(count, list), nil } -// AdminSearchList -func (qs *QuestionService) AdminSearchAnswerList(ctx context.Context, search *entity.AdminAnswerSearch, loginUserID string) ([]*schema.AdminAnswerInfo, int64, error) { - answerlist := make([]*schema.AdminAnswerInfo, 0) - - status, ok := entity.AdminAnswerSearchStatus[search.StatusStr] - if ok { - search.Status = status - } - - if search.Status == 0 { - search.Status = 1 - } - dblist, count, err := qs.questioncommon.AnswerCommon.AdminSearchList(ctx, search) +// AdminAnswerPage search answer list +func (qs *QuestionService) AdminAnswerPage(ctx context.Context, req *schema.AdminAnswerPageReq) ( + resp *pager.PageModel, err error) { + answerList, count, err := qs.questioncommon.AnswerCommon.AdminSearchList(ctx, req) if err != nil { - return answerlist, count, err + return nil, err } + questionIDs := make([]string, 0) userIds := make([]string, 0) - for _, item := range dblist { - answerinfo := qs.questioncommon.AnswerCommon.AdminShowFormat(ctx, item) - answerlist = append(answerlist, answerinfo) + answerResp := make([]*schema.AdminAnswerInfo, 0) + for _, item := range answerList { + answerInfo := qs.questioncommon.AnswerCommon.AdminShowFormat(ctx, item) + answerResp = append(answerResp, answerInfo) questionIDs = append(questionIDs, item.QuestionID) userIds = append(userIds, item.UserID) } userInfoMap, err := qs.userCommon.BatchUserBasicInfoByID(ctx, userIds) if err != nil { - return answerlist, count, err + return nil, err + } + questionMaps, err := qs.questioncommon.FindInfoByID(ctx, questionIDs, req.LoginUserID) + if err != nil { + return nil, err } - questionMaps, err := qs.questioncommon.FindInfoByID(ctx, questionIDs, loginUserID) - if err != nil { - return answerlist, count, err - } - for _, item := range answerlist { - _, ok := questionMaps[item.QuestionID] - if ok { - item.QuestionInfo.Title = questionMaps[item.QuestionID].Title + for _, item := range answerResp { + if q, ok := questionMaps[item.QuestionID]; ok { + item.QuestionInfo.Title = q.Title } - _, ok = userInfoMap[item.UserID] - if ok { - item.UserInfo = userInfoMap[item.UserID] + if u, ok := userInfoMap[item.UserID]; ok { + item.UserInfo = u } } - return answerlist, count, nil + return pager.NewPageModel(count, answerResp), nil } func (qs *QuestionService) changeQuestionToRevision(ctx context.Context, questionInfo *entity.Question, tags []*entity.Tag) (