Merge remote-tracking branch 'origin/feat/1.0.2/user' into test

This commit is contained in:
LinkinStar 2022-12-30 17:09:47 +08:00
commit 7268fe2331
14 changed files with 294 additions and 200 deletions

View File

@ -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:

View File

@ -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 <br> "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

View File

@ -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)

View File

@ -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) {

View File

@ -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
}

View File

@ -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"`

View File

@ -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) {

View File

@ -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)

View File

@ -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 {

View File

@ -73,7 +73,7 @@ func (ns *NotificationCommon) HandleNotification() {
// AddNotification
// need set
// UserID
// LoginUserID
// Type 1 inbox 2 achievement
// [inbox] Activity
// [achievement] Rank

View File

@ -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 {

View File

@ -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 {

View File

@ -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"
}

View File

@ -25,31 +25,21 @@
>
<div class="d-flex">
<div class="text-secondary me-1">
<a href="/users/{{.UserInfo.Username}}"
<a href="/users/{{.Operator.Username}}"
><span class="me-1 text-break"
>{{.UserInfo.DisplayName}}</span
>{{.Operator.DisplayName}}</span
></a
><span class="fw-bold" title="Reputation"
>{{.UserInfo.Rank}}</span
>{{.Operator.Rank}}</span
>
</div>
• {{if eq .CreateTime .UpdateTime}}
<time
class="text-secondary ms-1"
datetime="{{timeFormatISO $.timezone .CreateTime}}"
title="{{translatorTimeFormatLongDate $.language $.timezone .CreateTime}}"
datetime="{{timeFormatISO $.timezone .OperatedAt}}"
title="{{translatorTimeFormatLongDate $.language $.timezone .OperatedAt}}"
>{{translator $.language "ui.question.asked"}}
{{translatorTimeFormat $.language $.timezone .CreateTime}}
{{translatorTimeFormat $.language $.timezone .OperatedAt}}
</time>
{{else if gt .UpdateTime 0}}
<time
class="text-secondary ms-1"
datetime="{{timeFormatISO $.timezone .UpdateTime}}"
title="{{translatorTimeFormatLongDate $.language $.timezone .UpdateTime}}"
>{{translator $.language "ui.question.modified"}}
{{translatorTimeFormat $.language $.timezone .UpdateTime}}
</time>
{{end}}
</div>
<div class="ms-0 ms-md-3 mt-2 mt-md-0">
<span