diff --git a/i18n/en_US.yaml b/i18n/en_US.yaml
index 121be734..d173ee2c 100644
--- a/i18n/en_US.yaml
+++ b/i18n/en_US.yaml
@@ -204,7 +204,13 @@ backend:
other: "something else"
desc:
other: "This post requires another reason not listed above."
-
+ operation_type:
+ asked:
+ other: "asked"
+ answered:
+ other: "answered"
+ modified:
+ other: "modified"
notification:
action:
update_question:
diff --git a/internal/controller/question_controller.go b/internal/controller/question_controller.go
index 94c7b92c..dd0ee9ac 100644
--- a/internal/controller/question_controller.go
+++ b/internal/controller/question_controller.go
@@ -1,10 +1,9 @@
package controller
import (
- "context"
-
"github.com/answerdev/answer/internal/base/handler"
"github.com/answerdev/answer/internal/base/middleware"
+ "github.com/answerdev/answer/internal/base/pager"
"github.com/answerdev/answer/internal/base/reason"
"github.com/answerdev/answer/internal/base/validator"
"github.com/answerdev/answer/internal/entity"
@@ -31,7 +30,7 @@ func NewQuestionController(questionService *service.QuestionService, rankService
// RemoveQuestion delete question
// @Summary delete question
// @Description delete question
-// @Tags api-question
+// @Tags Question
// @Accept json
// @Produce json
// @Security ApiKeyAuth
@@ -62,7 +61,7 @@ func (qc *QuestionController) RemoveQuestion(ctx *gin.Context) {
// CloseQuestion Close question
// @Summary Close question
// @Description Close question
-// @Tags api-question
+// @Tags Question
// @Accept json
// @Produce json
// @Security ApiKeyAuth
@@ -92,7 +91,7 @@ func (qc *QuestionController) CloseQuestion(ctx *gin.Context) {
// ReopenQuestion reopen question
// @Summary reopen question
// @Description reopen question
-// @Tags api-question
+// @Tags Question
// @Accept json
// @Produce json
// @Security ApiKeyAuth
@@ -119,10 +118,10 @@ func (qc *QuestionController) ReopenQuestion(ctx *gin.Context) {
handler.HandleResponse(ctx, err, nil)
}
-// GetQuestion godoc
-// @Summary GetQuestion Question
-// @Description GetQuestion Question
-// @Tags api-question
+// GetQuestion get question details
+// @Summary get question details
+// @Description get question details
+// @Tags Question
// @Security ApiKeyAuth
// @Accept json
// @Produce json
@@ -161,7 +160,7 @@ func (qc *QuestionController) GetQuestion(ctx *gin.Context) {
// SimilarQuestion godoc
// @Summary Search Similar Question
// @Description Search Similar Question
-// @Tags api-question
+// @Tags Question
// @Accept json
// @Produce json
// @Param question_id query string true "question_id" default()
@@ -181,65 +180,34 @@ func (qc *QuestionController) SimilarQuestion(ctx *gin.Context) {
})
}
-// Index godoc
-// @Summary SearchQuestionList
-// @Description SearchQuestionList
"order" Enums(newest, active,frequent,score,unanswered)
-// @Tags api-question
+// QuestionPage get questions by page
+// @Summary get questions by page
+// @Description get questions by page
+// @Tags Question
// @Accept json
// @Produce json
-// @Param data body schema.QuestionSearch true "QuestionSearch"
-// @Success 200 {string} string ""
+// @Param data body schema.QuestionPageReq true "QuestionPageReq"
+// @Success 200 {object} handler.RespBody{data=pager.PageModel{list=[]schema.QuestionPageResp}}
// @Router /answer/api/v1/question/page [get]
-func (qc *QuestionController) Index(ctx *gin.Context) {
- req := &schema.QuestionSearch{}
+func (qc *QuestionController) QuestionPage(ctx *gin.Context) {
+ req := &schema.QuestionPageReq{}
if handler.BindAndCheck(ctx, req) {
return
}
- userID := middleware.GetLoginUserIDFromContext(ctx)
- list, count, err := qc.questionService.SearchList(ctx, req, userID)
+ req.LoginUserID = middleware.GetLoginUserIDFromContext(ctx)
+
+ questions, total, err := qc.questionService.GetQuestionPage(ctx, req)
if err != nil {
handler.HandleResponse(ctx, err, nil)
return
}
- handler.HandleResponse(ctx, nil, gin.H{
- "list": list,
- "count": count,
- })
-}
-
-// SearchList godoc
-// @Summary SearchQuestionList
-// @Description SearchQuestionList
-// @Tags api-question
-// @Accept json
-// @Produce json
-// @Param data body schema.QuestionSearch true "QuestionSearch"
-// @Router /answer/api/v1/question/search [post]
-// @Success 200 {string} string ""
-func (qc *QuestionController) SearchList(c *gin.Context) {
- Request := new(schema.QuestionSearch)
- err := c.BindJSON(Request)
- if err != nil {
- handler.HandleResponse(c, err, nil)
- return
- }
- ctx := context.Background()
- userID := middleware.GetLoginUserIDFromContext(c)
- list, count, err := qc.questionService.SearchList(ctx, Request, userID)
- if err != nil {
- handler.HandleResponse(c, err, nil)
- return
- }
- handler.HandleResponse(c, nil, gin.H{
- "list": list,
- "count": count,
- })
+ handler.HandleResponse(ctx, nil, pager.NewPageModel(total, questions))
}
// AddQuestion add question
// @Summary add question
// @Description add question
-// @Tags api-question
+// @Tags Question
// @Accept json
// @Produce json
// @Security ApiKeyAuth
@@ -309,7 +277,7 @@ func (qc *QuestionController) AddQuestion(ctx *gin.Context) {
// UpdateQuestion update question
// @Summary update question
// @Description update question
-// @Tags api-question
+// @Tags Question
// @Accept json
// @Produce json
// @Security ApiKeyAuth
@@ -366,7 +334,7 @@ func (qc *QuestionController) UpdateQuestion(ctx *gin.Context) {
// CloseMsgList close question msg list
// @Summary close question msg list
// @Description close question msg list
-// @Tags api-question
+// @Tags Question
// @Accept json
// @Produce json
// @Security ApiKeyAuth
@@ -380,7 +348,7 @@ func (qc *QuestionController) CloseMsgList(ctx *gin.Context) {
// SearchByTitleLike add question title like
// @Summary add question title like
// @Description add question title like
-// @Tags api-question
+// @Tags Question
// @Accept json
// @Produce json
// @Security ApiKeyAuth
@@ -397,7 +365,7 @@ func (qc *QuestionController) SearchByTitleLike(ctx *gin.Context) {
// UserTop godoc
// @Summary UserTop
// @Description UserTop
-// @Tags api-question
+// @Tags Question
// @Accept json
// @Produce json
// @Security ApiKeyAuth
@@ -417,7 +385,7 @@ func (qc *QuestionController) UserTop(ctx *gin.Context) {
// UserList godoc
// @Summary UserList
// @Description UserList
-// @Tags api-question
+// @Tags Question
// @Accept json
// @Produce json
// @Security ApiKeyAuth
diff --git a/internal/controller/template_controller.go b/internal/controller/template_controller.go
index 6d4327cc..c97c81b4 100644
--- a/internal/controller/template_controller.go
+++ b/internal/controller/template_controller.go
@@ -91,8 +91,8 @@ func (tc *TemplateController) SiteInfo(ctx *gin.Context) *schema.TemplateSiteInf
// Index question list
func (tc *TemplateController) Index(ctx *gin.Context) {
- req := &schema.QuestionSearch{
- Order: "newest",
+ req := &schema.QuestionPageReq{
+ OrderCond: "newest",
}
if handler.BindAndCheck(ctx, req) {
tc.Page404(ctx)
@@ -124,8 +124,8 @@ func (tc *TemplateController) Index(ctx *gin.Context) {
}
func (tc *TemplateController) QuestionList(ctx *gin.Context) {
- req := &schema.QuestionSearch{
- Order: "newest",
+ req := &schema.QuestionPageReq{
+ OrderCond: "newest",
}
if handler.BindAndCheck(ctx, req) {
tc.Page404(ctx)
diff --git a/internal/controller/template_render/question.go b/internal/controller/template_render/question.go
index 5025979c..fc0e5bab 100644
--- a/internal/controller/template_render/question.go
+++ b/internal/controller/template_render/question.go
@@ -11,8 +11,8 @@ import (
"github.com/segmentfault/pacman/log"
)
-func (t *TemplateRenderController) Index(ctx *gin.Context, req *schema.QuestionSearch) ([]*schema.QuestionInfo, int64, error) {
- return t.questionService.SearchList(ctx, req, req.UserID)
+func (t *TemplateRenderController) Index(ctx *gin.Context, req *schema.QuestionPageReq) ([]*schema.QuestionPageResp, int64, error) {
+ return t.questionService.GetQuestionPage(ctx, req)
}
func (t *TemplateRenderController) QuestionDetail(ctx *gin.Context, id string) (resp *schema.QuestionInfo, err error) {
diff --git a/internal/controller/template_render/tags.go b/internal/controller/template_render/tags.go
index d8a36b64..7e9268f2 100644
--- a/internal/controller/template_render/tags.go
+++ b/internal/controller/template_render/tags.go
@@ -15,19 +15,20 @@ func (q *TemplateRenderController) TagList(ctx context.Context, req *schema.GetT
return
}
-func (q *TemplateRenderController) TagInfo(ctx context.Context, req *schema.GetTamplateTagInfoReq) (resp *schema.GetTagResp, questionList []*schema.QuestionInfo, questionCount int64, err error) {
+func (q *TemplateRenderController) TagInfo(ctx context.Context, req *schema.GetTamplateTagInfoReq) (resp *schema.GetTagResp, questionList []*schema.QuestionPageResp, questionCount int64, err error) {
dto := &schema.GetTagInfoReq{}
_ = copier.Copy(dto, req)
resp, err = q.tagService.GetTagInfo(ctx, dto)
if err != nil {
return
}
- searchQuestion := &schema.QuestionSearch{}
+ searchQuestion := &schema.QuestionPageReq{}
searchQuestion.Page = req.Page
searchQuestion.PageSize = req.PageSize
- searchQuestion.Order = "newest"
+ searchQuestion.OrderCond = "newest"
searchQuestion.Tag = req.Name
- questionList, questionCount, err = q.questionService.SearchList(ctx, searchQuestion, "")
+ searchQuestion.LoginUserID = req.UserID
+ questionList, questionCount, err = q.questionService.GetQuestionPage(ctx, searchQuestion)
if err != nil {
return
}
diff --git a/internal/entity/question_entity.go b/internal/entity/question_entity.go
index a47f59b4..4b4f4923 100644
--- a/internal/entity/question_entity.go
+++ b/internal/entity/question_entity.go
@@ -22,11 +22,6 @@ var AdminQuestionSearchStatusIntToString = map[int]string{
QuestionStatusDeleted: "deleted",
}
-type QuestionTag struct {
- Question `xorm:"extends"`
- TagRel `xorm:"extends"`
-}
-
// Question question
type Question struct {
ID string `xorm:"not null pk BIGINT(20) id"`
diff --git a/internal/repo/question/question_repo.go b/internal/repo/question/question_repo.go
index 3f44a188..963cf667 100644
--- a/internal/repo/question/question_repo.go
+++ b/internal/repo/question/question_repo.go
@@ -205,70 +205,40 @@ func (qr *questionRepo) GetQuestionIDsPage(ctx context.Context, page, pageSize i
return questionIDList, nil
}
-// GetQuestionPage get question page
-func (qr *questionRepo) GetQuestionPage(ctx context.Context, page, pageSize int, question *entity.Question) (questionList []*entity.Question, total int64, err error) {
+// GetQuestionPage query question page
+func (qr *questionRepo) GetQuestionPage(ctx context.Context, page, pageSize int, userID, tagID, orderCond string) (
+ questionList []*entity.Question, total int64, err error) {
questionList = make([]*entity.Question, 0)
- total, err = pager.Help(page, pageSize, questionList, question, qr.data.DB.NewSession())
- if err != nil {
- err = errors.InternalServer(reason.DatabaseError).WithError(err).WithStack()
- }
- return
-}
-// SearchList
-func (qr *questionRepo) SearchList(ctx context.Context, search *schema.QuestionSearch) ([]*entity.QuestionTag, int64, error) {
- var count int64
- var err error
- rows := make([]*entity.QuestionTag, 0)
- if search.Page > 0 {
- search.Page = search.Page - 1
- } else {
- search.Page = 0
+ session := qr.data.DB.Where("question.status = ? OR question.status = ?",
+ entity.QuestionStatusAvailable, entity.QuestionStatusClosed)
+ if len(tagID) > 0 {
+ session.Join("LEFT", "tag_rel", "question.id = tag_rel.object_id")
+ session.And("tag_rel.tag_id = ?", tagID)
+ session.And("tag_rel.status = ?", entity.TagRelStatusAvailable)
}
- if search.PageSize == 0 {
- search.PageSize = constant.DefaultPageSize
+ if len(userID) > 0 {
+ session.And("question.user_id = ?", userID)
}
- offset := search.Page * search.PageSize
- session := qr.data.DB.Table("question")
-
- if len(search.TagIDs) > 0 {
- session = session.Join("LEFT", "tag_rel", "question.id = tag_rel.object_id")
- session = session.And("tag_rel.tag_id =?", search.TagIDs[0])
- // session = session.In("tag_rel.tag_id ", search.TagIDs)
- session = session.And("tag_rel.status =?", entity.TagRelStatusAvailable)
- }
-
- if len(search.UserID) > 0 {
- session = session.And("question.user_id = ?", search.UserID)
- }
-
- session = session.In("question.status", []int{entity.QuestionStatusAvailable, entity.QuestionStatusClosed})
- // if search.Status > 0 {
- // session = session.And("question.status = ?", search.Status)
- // }
- // switch
- // newest, active,frequent,score,unanswered
- switch search.Order {
+ switch orderCond {
case "newest":
- session = session.OrderBy("question.created_at desc")
+ session.OrderBy("question.created_at DESC")
case "active":
- session = session.OrderBy("question.post_update_time desc,question.updated_at desc")
+ session.OrderBy("question.post_update_time DESC, question.updated_at DESC")
case "frequent":
- session = session.OrderBy("question.view_count desc")
+ session.OrderBy("question.view_count DESC")
case "score":
- session = session.OrderBy("question.vote_count desc,question.view_count desc")
+ session.OrderBy("question.vote_count DESC, question.view_count DESC")
case "unanswered":
- session = session.And("question.last_answer_id = 0")
- session = session.OrderBy("question.created_at desc")
+ session.Where("question.last_answer_id = 0")
+ session.OrderBy("question.created_at DESC")
}
- session = session.Limit(search.PageSize, offset)
- session = session.Select("question.id,question.user_id,last_edit_user_id,question.title,question.original_text,question.parsed_text,question.status,question.view_count,question.unique_view_count,question.vote_count,question.answer_count,question.collection_count,question.follow_count,question.accepted_answer_id,question.last_answer_id,question.created_at,question.updated_at,question.post_update_time,question.revision_id")
- count, err = session.FindAndCount(&rows)
+
+ total, err = pager.Help(page, pageSize, &questionList, &entity.Question{}, session)
if err != nil {
err = errors.InternalServer(reason.DatabaseError).WithError(err).WithStack()
- return rows, count, err
}
- return rows, count, nil
+ return questionList, total, err
}
func (qr *questionRepo) AdminSearchList(ctx context.Context, search *schema.AdminQuestionSearch) ([]*entity.Question, int64, error) {
diff --git a/internal/router/answer_api_router.go b/internal/router/answer_api_router.go
index d425c746..8c61a426 100644
--- a/internal/router/answer_api_router.go
+++ b/internal/router/answer_api_router.go
@@ -124,8 +124,7 @@ func (a *AnswerAPIRouter) RegisterUnAuthAnswerAPIRouter(r *gin.RouterGroup) {
//question
r.GET("/question/info", a.questionController.GetQuestion)
- r.POST("/question/search", a.questionController.SearchList)
- r.GET("/question/page", a.questionController.Index)
+ r.GET("/question/page", a.questionController.QuestionPage)
r.GET("/question/similar/tag", a.questionController.SimilarQuestion)
r.GET("/personal/qa/top", a.questionController.UserTop)
r.GET("/personal/question/page", a.questionController.UserList)
@@ -143,7 +142,6 @@ func (a *AnswerAPIRouter) RegisterUnAuthAnswerAPIRouter(r *gin.RouterGroup) {
r.GET("/tags/following", a.tagController.GetFollowingTags)
r.GET("/tag", a.tagController.GetTagInfo)
r.GET("/tag/synonyms", a.tagController.GetTagSynonyms)
- r.GET("/question/index", a.questionController.Index)
//search
r.GET("/search", a.searchController.Search)
diff --git a/internal/schema/question_schema.go b/internal/schema/question_schema.go
index f5689297..6d0f93c5 100644
--- a/internal/schema/question_schema.go
+++ b/internal/schema/question_schema.go
@@ -1,6 +1,8 @@
package schema
import (
+ "time"
+
"github.com/answerdev/answer/internal/base/validator"
"github.com/answerdev/answer/pkg/converter"
)
@@ -222,15 +224,66 @@ type UserQuestionInfo struct {
Status string `json:"status"`
}
-type QuestionSearch struct {
- Page int `json:"page" form:"page"` // Query number of pages
- PageSize int `json:"page_size" form:"page_size"` // Search page size
- Order string `json:"order" form:"order"` // Search order by
- // Tags []string `json:"tags" form:"tags"` // Search tag
- Tag string `json:"tag" form:"tag"` //Search tag
- TagIDs []string `json:"-" form:"-"` // Search tag
- UserName string `json:"username" form:"username"` // Search username
- UserID string `json:"-" form:"-"`
+const (
+ QuestionOrderCondNewest = "newest"
+ QuestionOrderCondActive = "active"
+ QuestionOrderCondFrequent = "frequent"
+ QuestionOrderCondScore = "score"
+ QuestionOrderCondUnanswered = "unanswered"
+)
+
+// QuestionPageReq query questions page
+type QuestionPageReq struct {
+ Page int `validate:"omitempty,min=1" form:"page"`
+ PageSize int `validate:"omitempty,min=1" form:"page_size"`
+ OrderCond string `validate:"omitempty,oneof=newest active frequent score unanswered" form:"order"`
+ Tag string `validate:"omitempty,gt=0,lte=100" form:"tag"`
+ Username string `validate:"omitempty,gt=0,lte=100" form:"username"`
+
+ LoginUserID string `json:"-"`
+ UserIDBeSearched string `json:"-"`
+ TagID string `json:"-"`
+}
+
+const (
+ QuestionPageRespOperationTypeAsked = "question.operation_type.asked"
+ QuestionPageRespOperationTypeAnswered = "question.operation_type.answered"
+ QuestionPageRespOperationTypeModified = "question.operation_type.modified"
+)
+
+type QuestionPageResp struct {
+ ID string `json:"id" `
+ Title string `json:"title"`
+ UrlTitle string `json:"url_title"`
+ Description string `json:"description"`
+ Status int `json:"status"`
+ Tags []*TagResp `json:"tags"`
+
+ // question statistical information
+ ViewCount int `json:"view_count"`
+ UniqueViewCount int `json:"unique_view_count"`
+ VoteCount int `json:"vote_count"`
+ AnswerCount int `json:"answer_count"`
+ CollectionCount int `json:"collection_count"`
+ FollowCount int `json:"follow_count"`
+
+ // answer information
+ AcceptedAnswerID string `json:"accepted_answer_id"`
+ LastAnswerID string `json:"last_answer_id"`
+ LastAnsweredUserID string `json:"-"`
+ LastAnsweredAt time.Time `json:"-"`
+
+ // operator information
+ OperatedAt int64 `json:"operated_at"`
+ Operator *QuestionPageRespOperator `json:"operator"`
+ OperationType string `json:"operation_type"`
+}
+
+type QuestionPageRespOperator struct {
+ ID string `json:"id"`
+ Username string `json:"username"`
+ Rank int `json:"rank"`
+ DisplayName string `json:"display_name"`
}
type AdminQuestionSearch struct {
diff --git a/internal/service/notification_common/notification.go b/internal/service/notification_common/notification.go
index 5bb23f38..fe11a389 100644
--- a/internal/service/notification_common/notification.go
+++ b/internal/service/notification_common/notification.go
@@ -73,7 +73,7 @@ func (ns *NotificationCommon) HandleNotification() {
// AddNotification
// need set
-// UserID
+// LoginUserID
// Type 1 inbox 2 achievement
// [inbox] Activity
// [achievement] Rank
diff --git a/internal/service/question_common/question.go b/internal/service/question_common/question.go
index 5329c6db..451e1fa1 100644
--- a/internal/service/question_common/question.go
+++ b/internal/service/question_common/question.go
@@ -6,11 +6,14 @@ 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/service/activity_common"
"github.com/answerdev/answer/internal/service/activity_queue"
"github.com/answerdev/answer/internal/service/config"
"github.com/answerdev/answer/internal/service/meta"
+ "github.com/answerdev/answer/pkg/checker"
"github.com/answerdev/answer/pkg/htmltext"
"github.com/segmentfault/pacman/errors"
@@ -30,8 +33,8 @@ type QuestionRepo interface {
UpdateQuestion(ctx context.Context, question *entity.Question, Cols []string) (err error)
GetQuestion(ctx context.Context, id string) (question *entity.Question, exist bool, err error)
GetQuestionList(ctx context.Context, question *entity.Question) (questions []*entity.Question, err error)
- GetQuestionPage(ctx context.Context, page, pageSize int, question *entity.Question) (questions []*entity.Question, total int64, err error)
- SearchList(ctx context.Context, search *schema.QuestionSearch) ([]*entity.QuestionTag, int64, error)
+ GetQuestionPage(ctx context.Context, page, pageSize int, userID, tagID, orderCond string) (
+ questionList []*entity.Question, total int64, err error)
UpdateQuestionStatus(ctx context.Context, question *entity.Question) (err error)
SearchByTitleLike(ctx context.Context, title string) (questionList []*entity.Question, err error)
UpdatePvCount(ctx context.Context, questionID string) (err error)
@@ -126,21 +129,15 @@ func (qs *QuestionCommon) UpdataPostSetTime(ctx context.Context, questionID stri
func (qs *QuestionCommon) FindInfoByID(ctx context.Context, questionIDs []string, loginUserID string) (map[string]*schema.QuestionInfo, error) {
list := make(map[string]*schema.QuestionInfo)
- listAddTag := make([]*entity.QuestionTag, 0)
questionList, err := qs.questionRepo.FindByID(ctx, questionIDs)
if err != nil {
return list, err
}
- for _, item := range questionList {
- itemAddTag := &entity.QuestionTag{}
- itemAddTag.Question = *item
- listAddTag = append(listAddTag, itemAddTag)
- }
- QuestionInfo, err := qs.ListFormat(ctx, listAddTag, loginUserID)
+ questions, err := qs.FormatQuestions(ctx, questionList, loginUserID)
if err != nil {
return list, err
}
- for _, item := range QuestionInfo {
+ for _, item := range questions {
list[item.ID] = item
}
return list, nil
@@ -244,13 +241,114 @@ func (qs *QuestionCommon) Info(ctx context.Context, questionID string, loginUser
return showinfo, nil
}
-func (qs *QuestionCommon) ListFormat(ctx context.Context, questionList []*entity.QuestionTag, loginUserID string) ([]*schema.QuestionInfo, error) {
+func (qs *QuestionCommon) FormatQuestionsPage(
+ ctx context.Context, questionList []*entity.Question, loginUserID string, orderCond string) (
+ formattedQuestions []*schema.QuestionPageResp, err error) {
+ language := handler.GetLangByCtx(ctx)
+ askedOp := translator.GlobalTrans.Tr(language, schema.QuestionPageRespOperationTypeAsked)
+ answeredOp := translator.GlobalTrans.Tr(language, schema.QuestionPageRespOperationTypeAnswered)
+ modifiedOp := translator.GlobalTrans.Tr(language, schema.QuestionPageRespOperationTypeModified)
+
+ formattedQuestions = make([]*schema.QuestionPageResp, 0)
+
+ questionIDs := make([]string, 0)
+ userIDs := make([]string, 0)
+ for _, questionInfo := range questionList {
+ t := &schema.QuestionPageResp{
+ ID: questionInfo.ID,
+ Title: questionInfo.Title,
+ UrlTitle: htmltext.UrlTitle(questionInfo.Title),
+ Description: htmltext.FetchExcerpt(questionInfo.ParsedText, "...", 240),
+ Status: questionInfo.Status,
+ ViewCount: questionInfo.ViewCount,
+ UniqueViewCount: questionInfo.UniqueViewCount,
+ VoteCount: questionInfo.VoteCount,
+ AnswerCount: questionInfo.AnswerCount,
+ CollectionCount: questionInfo.CollectionCount,
+ FollowCount: questionInfo.FollowCount,
+ AcceptedAnswerID: questionInfo.AcceptedAnswerID,
+ LastAnswerID: questionInfo.LastAnswerID,
+ }
+
+ questionIDs = append(questionIDs, questionInfo.ID)
+ userIDs = append(userIDs, questionInfo.UserID)
+ haveEdited, haveAnswered := false, false
+ if checker.IsNotZeroString(questionInfo.LastEditUserID) {
+ haveEdited = true
+ userIDs = append(userIDs, questionInfo.LastEditUserID)
+ }
+ if checker.IsNotZeroString(questionInfo.LastAnswerID) {
+ haveAnswered = true
+
+ answerInfo, exist, err := qs.answerRepo.GetAnswer(ctx, questionInfo.LastAnswerID)
+ if err == nil && exist {
+ if answerInfo.LastEditUserID != "0" {
+ t.LastAnsweredUserID = answerInfo.LastEditUserID
+ } else {
+ t.LastAnsweredUserID = answerInfo.UserID
+ }
+ t.LastAnsweredAt = answerInfo.CreatedAt
+ userIDs = append(userIDs, t.LastAnsweredUserID)
+ }
+ }
+
+ // if order condition is newest or nobody edited or nobody answered, only show question author
+ if orderCond == schema.QuestionOrderCondNewest || (!haveEdited && !haveAnswered) {
+ t.OperationType = askedOp
+ t.OperatedAt = questionInfo.CreatedAt.Unix()
+ t.Operator = &schema.QuestionPageRespOperator{ID: questionInfo.UserID}
+ }
+
+ // if no one
+ if haveEdited {
+ t.OperationType = modifiedOp
+ t.OperatedAt = questionInfo.UpdatedAt.Unix()
+ t.Operator = &schema.QuestionPageRespOperator{ID: questionInfo.LastEditUserID}
+ }
+
+ if haveAnswered {
+ if t.LastAnsweredAt.Unix() > t.OperatedAt {
+ t.OperationType = answeredOp
+ t.OperatedAt = t.LastAnsweredAt.Unix()
+ t.Operator = &schema.QuestionPageRespOperator{ID: t.LastAnsweredUserID}
+ }
+ }
+ formattedQuestions = append(formattedQuestions, t)
+ }
+
+ tagsMap, err := qs.tagCommon.BatchGetObjectTag(ctx, questionIDs)
+ if err != nil {
+ return formattedQuestions, err
+ }
+ userInfoMap, err := qs.userCommon.BatchUserBasicInfoByID(ctx, userIDs)
+ if err != nil {
+ return formattedQuestions, err
+ }
+
+ for _, item := range formattedQuestions {
+ tags, ok := tagsMap[item.ID]
+ if ok {
+ item.Tags = tags
+ } else {
+ item.Tags = make([]*schema.TagResp, 0)
+ }
+ userInfo := userInfoMap[item.Operator.ID]
+ if userInfo != nil {
+ item.Operator.DisplayName = userInfo.DisplayName
+ item.Operator.Username = userInfo.Username
+ item.Operator.Rank = userInfo.Rank
+ }
+ }
+ return formattedQuestions, nil
+}
+
+func (qs *QuestionCommon) FormatQuestions(ctx context.Context, questionList []*entity.Question, loginUserID string) ([]*schema.QuestionInfo, error) {
list := make([]*schema.QuestionInfo, 0)
objectIds := make([]string, 0)
userIds := make([]string, 0)
for _, questionInfo := range questionList {
- item := qs.ShowListFormat(ctx, questionInfo)
+ item := qs.ShowFormat(ctx, questionInfo)
list = append(list, item)
objectIds = append(objectIds, item.ID)
userIds = append(userIds, item.UserID)
@@ -387,8 +485,8 @@ func (as *QuestionCommon) RemoveAnswer(ctx context.Context, id string) (err erro
return as.answerRepo.RemoveAnswer(ctx, id)
}
-func (qs *QuestionCommon) ShowListFormat(ctx context.Context, data *entity.QuestionTag) *schema.QuestionInfo {
- return qs.ShowFormat(ctx, &data.Question)
+func (qs *QuestionCommon) ShowListFormat(ctx context.Context, data *entity.Question) *schema.QuestionInfo {
+ return qs.ShowFormat(ctx, data)
}
func (qs *QuestionCommon) ShowFormat(ctx context.Context, data *entity.Question) *schema.QuestionInfo {
diff --git a/internal/service/question_service.go b/internal/service/question_service.go
index 71ab9123..a5b48556 100644
--- a/internal/service/question_service.go
+++ b/internal/service/question_service.go
@@ -655,12 +655,13 @@ func (qs *QuestionService) SearchUserList(ctx context.Context, userName, order s
if !Exist {
return userlist, 0, nil
}
- search := &schema.QuestionSearch{}
- search.Order = order
+ search := &schema.QuestionPageReq{}
+ search.OrderCond = order
search.Page = page
search.PageSize = pageSize
- search.UserID = userinfo.ID
- questionlist, count, err := qs.SearchList(ctx, search, loginUserID)
+ search.UserIDBeSearched = userinfo.ID
+ search.LoginUserID = loginUserID
+ questionlist, count, err := qs.GetQuestionPage(ctx, search)
if err != nil {
return userlist, 0, err
}
@@ -778,12 +779,13 @@ func (qs *QuestionService) SearchUserTopList(ctx context.Context, userName strin
if !Exist {
return userQuestionlist, userAnswerlist, nil
}
- search := &schema.QuestionSearch{}
- search.Order = "score"
+ search := &schema.QuestionPageReq{}
+ search.OrderCond = "score"
search.Page = 0
search.PageSize = 5
- search.UserID = userinfo.ID
- questionlist, _, err := qs.SearchList(ctx, search, loginUserID)
+ search.UserIDBeSearched = userinfo.ID
+ search.LoginUserID = loginUserID
+ questionlist, _, err := qs.GetQuestionPage(ctx, search)
if err != nil {
return userQuestionlist, userAnswerlist, err
}
@@ -858,57 +860,64 @@ func (qs *QuestionService) SearchByTitleLike(ctx context.Context, title string,
}
// SimilarQuestion
-func (qs *QuestionService) SimilarQuestion(ctx context.Context, questionID string, loginUserID string) ([]*schema.QuestionInfo, int64, error) {
- list := make([]*schema.QuestionInfo, 0)
+func (qs *QuestionService) SimilarQuestion(ctx context.Context, questionID string, loginUserID string) ([]*schema.QuestionPageResp, int64, error) {
question, err := qs.questioncommon.Info(ctx, questionID, loginUserID)
if err != nil {
- return list, 0, nil
+ return nil, 0, nil
}
tagNames := make([]string, 0, len(question.Tags))
for _, tag := range question.Tags {
tagNames = append(tagNames, tag.SlugName)
}
- search := &schema.QuestionSearch{}
- search.Order = "frequent"
+ search := &schema.QuestionPageReq{}
+ search.OrderCond = "frequent"
search.Page = 0
search.PageSize = 6
if len(tagNames) > 0 {
search.Tag = tagNames[0]
}
- return qs.SearchList(ctx, search, loginUserID)
+ search.LoginUserID = loginUserID
+ return qs.GetQuestionPage(ctx, search)
}
-// SearchList
-func (qs *QuestionService) SearchList(ctx context.Context, req *schema.QuestionSearch, loginUserID string) ([]*schema.QuestionInfo, int64, error) {
+// GetQuestionPage query questions page
+func (qs *QuestionService) GetQuestionPage(ctx context.Context, req *schema.QuestionPageReq) (
+ questions []*schema.QuestionPageResp, total int64, err error) {
+ questions = make([]*schema.QuestionPageResp, 0)
+
+ // query by tag condition
if len(req.Tag) > 0 {
- tagInfo, has, err := qs.tagCommon.GetTagBySlugName(ctx, strings.ToLower(req.Tag))
+ tagInfo, exist, err := qs.tagCommon.GetTagBySlugName(ctx, strings.ToLower(req.Tag))
if err != nil {
- log.Error("tagCommon.GetTagListByNames error", err)
+ return nil, 0, err
}
- if has {
- req.TagIDs = append(req.TagIDs, tagInfo.ID)
+ if exist {
+ req.TagID = tagInfo.ID
}
}
- list := make([]*schema.QuestionInfo, 0)
- if req.UserName != "" {
- userinfo, exist, err := qs.userCommon.GetUserBasicInfoByUserName(ctx, req.UserName)
+
+ // query by user condition
+ if req.Username != "" {
+ userinfo, exist, err := qs.userCommon.GetUserBasicInfoByUserName(ctx, req.Username)
if err != nil {
- return list, 0, err
+ return nil, 0, err
}
if !exist {
- return list, 0, err
+ return questions, 0, nil
}
- req.UserID = userinfo.ID
+ req.UserIDBeSearched = userinfo.ID
}
- questionList, count, err := qs.questionRepo.SearchList(ctx, req)
+
+ questionList, total, err := qs.questionRepo.GetQuestionPage(ctx, req.Page, req.PageSize,
+ req.UserIDBeSearched, req.TagID, req.OrderCond)
if err != nil {
- return list, count, err
+ return nil, 0, err
}
- list, err = qs.questioncommon.ListFormat(ctx, questionList, loginUserID)
+ questions, err = qs.questioncommon.FormatQuestionsPage(ctx, questionList, req.LoginUserID, req.OrderCond)
if err != nil {
- return list, count, err
+ return nil, 0, err
}
- return list, count, nil
+ return questions, total, nil
}
func (qs *QuestionService) AdminSetQuestionStatus(ctx context.Context, questionID string, setStatusStr string) error {
diff --git a/pkg/checker/zero_string.go b/pkg/checker/zero_string.go
new file mode 100644
index 00000000..a318af28
--- /dev/null
+++ b/pkg/checker/zero_string.go
@@ -0,0 +1,6 @@
+package checker
+
+// IsNotZeroString check s is not empty string and is not "0"
+func IsNotZeroString(s string) bool {
+ return len(s) > 0 && s != "0"
+}
diff --git a/ui/template/question.html b/ui/template/question.html
index cad6d1a8..8b4347b8 100644
--- a/ui/template/question.html
+++ b/ui/template/question.html
@@ -25,31 +25,21 @@
>