Merge branch 'feat/backyard-search' into 'main'

Feat/backyard search

See merge request opensource/answer!137
This commit is contained in:
杨光富 2022-11-01 01:19:11 +00:00
commit ee723d2bfc
13 changed files with 185 additions and 51 deletions

View File

@ -56,6 +56,12 @@ const docTemplate = `{
"description": "user status",
"name": "status",
"in": "query"
},
{
"type": "string",
"description": "answer id or question title",
"name": "query",
"in": "query"
}
],
"responses": {
@ -173,6 +179,12 @@ const docTemplate = `{
"description": "user status",
"name": "status",
"in": "query"
},
{
"type": "string",
"description": "question id or title",
"name": "query",
"in": "query"
}
],
"responses": {
@ -709,19 +721,12 @@ const docTemplate = `{
},
{
"type": "string",
"description": "username",
"name": "username",
"in": "query"
},
{
"type": "string",
"description": "email",
"name": "e_mail",
"description": "search query: email, username or id:[id]",
"name": "query",
"in": "query"
},
{
"enum": [
"normal",
"suspended",
"deleted",
"inactive"

View File

@ -44,6 +44,12 @@
"description": "user status",
"name": "status",
"in": "query"
},
{
"type": "string",
"description": "answer id or question title",
"name": "query",
"in": "query"
}
],
"responses": {
@ -161,6 +167,12 @@
"description": "user status",
"name": "status",
"in": "query"
},
{
"type": "string",
"description": "question id or title",
"name": "query",
"in": "query"
}
],
"responses": {
@ -697,19 +709,12 @@
},
{
"type": "string",
"description": "username",
"name": "username",
"in": "query"
},
{
"type": "string",
"description": "email",
"name": "e_mail",
"description": "search query: email, username or id:[id]",
"name": "query",
"in": "query"
},
{
"enum": [
"normal",
"suspended",
"deleted",
"inactive"

View File

@ -1390,6 +1390,10 @@ paths:
in: query
name: status
type: string
- description: answer id or question title
in: query
name: query
type: string
produces:
- application/json
responses:
@ -1463,6 +1467,10 @@ paths:
in: query
name: status
type: string
- description: question id or title
in: query
name: query
type: string
produces:
- application/json
responses:
@ -1788,17 +1796,12 @@ paths:
in: query
name: page_size
type: integer
- description: username
- description: 'search query: email, username or id:[id]'
in: query
name: username
type: string
- description: email
in: query
name: e_mail
name: query
type: string
- description: user status
enum:
- normal
- suspended
- deleted
- inactive

View File

@ -365,6 +365,7 @@ func (qc *QuestionController) UserCollectionList(ctx *gin.Context) {
// @Param page query int false "page size"
// @Param page_size query int false "page size"
// @Param status query string false "user status" Enums(available, closed, deleted)
// @Param query query string false "question id or title"
// @Success 200 {object} handler.RespBody
// @Router /answer/admin/api/question/page [get]
func (qc *QuestionController) CmsSearchList(ctx *gin.Context) {
@ -390,6 +391,7 @@ func (qc *QuestionController) CmsSearchList(ctx *gin.Context) {
// @Param page query int false "page size"
// @Param page_size query int false "page size"
// @Param status query string false "user status" Enums(available,deleted)
// @Param query query string false "answer id or question title"
// @Success 200 {object} handler.RespBody
// @Router /answer/admin/api/answer/page [get]
func (qc *QuestionController) CmsSearchAnswerList(ctx *gin.Context) {

View File

@ -45,9 +45,8 @@ func (uc *UserBackyardController) UpdateUserStatus(ctx *gin.Context) {
// @Produce json
// @Param page query int false "page size"
// @Param page_size query int false "page size"
// @Param username query string false "username"
// @Param e_mail query string false "email"
// @Param status query string false "user status" Enums(normal, suspended, deleted, inactive)
// @Param query query string false "search query: email, username or id:[id]"
// @Param status query string false "user status" Enums(suspended, deleted, inactive)
// @Success 200 {object} handler.RespBody{data=pager.PageModel{records=[]schema.GetUserPageResp}}
// @Router /answer/admin/api/users/page [get]
func (uc *UserBackyardController) GetUserPage(ctx *gin.Context) {

View File

@ -44,6 +44,7 @@ type CmsAnswerSearch struct {
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
}
type AdminSetAnswerStatusRequest struct {

View File

@ -2,7 +2,10 @@ package repo
import (
"context"
"strings"
"time"
"unicode"
"xorm.io/builder"
"github.com/answerdev/answer/internal/base/constant"
"github.com/answerdev/answer/internal/base/data"
@ -202,11 +205,16 @@ func (ar *answerRepo) SearchList(ctx context.Context, search *entity.AnswerSearc
}
func (ar *answerRepo) CmsSearchList(ctx context.Context, search *entity.CmsAnswerSearch) ([]*entity.Answer, int64, error) {
var count int64
var err error
if search.Status == 0 {
search.Status = 1
}
var (
count int64
err error
session = ar.data.DB.Table([]string{entity.Answer{}.TableName(), "a"}).Select("a.*")
)
session.Where(builder.Eq{
"a.status": search.Status,
})
rows := make([]*entity.Answer, 0)
if search.Page > 0 {
search.Page = search.Page - 1
@ -216,11 +224,42 @@ func (ar *answerRepo) CmsSearchList(ctx context.Context, search *entity.CmsAnswe
if search.PageSize == 0 {
search.PageSize = constant.Default_PageSize
}
// 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, "id:") {
idSearch = true
id = strings.TrimSpace(strings.TrimPrefix(search.Query, "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,
})
}
}
offset := search.Page * search.PageSize
session := ar.data.DB.Where("")
session = session.And("status =?", search.Status)
session = session.OrderBy("updated_at desc")
session = session.Limit(search.PageSize, offset)
session.
OrderBy("a.updated_at desc").
Limit(search.PageSize, offset)
count, err = session.FindAndCount(&rows)
if err != nil {
return rows, count, errors.InternalServer(reason.DatabaseError).WithError(err).WithStack()

View File

@ -2,7 +2,10 @@ package repo
import (
"context"
"strings"
"time"
"unicode"
"xorm.io/builder"
"github.com/answerdev/answer/internal/base/constant"
"github.com/answerdev/answer/internal/base/data"
@ -225,8 +228,16 @@ func (qr *questionRepo) SearchList(ctx context.Context, search *schema.QuestionS
}
func (qr *questionRepo) CmsSearchList(ctx context.Context, search *schema.CmsQuestionSearch) ([]*entity.Question, int64, error) {
var count int64
var err error
var (
count int64
err error
session = qr.data.DB.Table("question")
)
session.Where(builder.Eq{
"status": search.Status,
})
rows := make([]*entity.Question, 0)
if search.Page > 0 {
search.Page = search.Page - 1
@ -236,11 +247,40 @@ func (qr *questionRepo) CmsSearchList(ctx context.Context, search *schema.CmsQue
if search.PageSize == 0 {
search.PageSize = constant.Default_PageSize
}
// search by question title like or question id
if len(search.Query) > 0 {
// check id search
var (
idSearch = false
id = ""
)
if strings.Contains(search.Query, "id:") {
idSearch = true
id = strings.TrimSpace(strings.TrimPrefix(search.Query, "id:"))
for _, r := range id {
if !unicode.IsDigit(r) {
idSearch = false
break
}
}
}
if idSearch {
session.And(builder.Eq{
"id": id,
})
} else {
session.And(builder.Like{
"title", search.Query,
})
}
}
offset := search.Page * search.PageSize
session := qr.data.DB.Table("question")
session = session.And("status =?", search.Status)
session = session.OrderBy("updated_at desc")
session = session.Limit(search.PageSize, offset)
session.OrderBy("updated_at desc").
Limit(search.PageSize, offset)
count, err = session.FindAndCount(&rows)
if err != nil {
err = errors.InternalServer(reason.DatabaseError).WithError(err).WithStack()

View File

@ -3,7 +3,11 @@ package user
import (
"context"
"encoding/json"
"net/mail"
"strings"
"time"
"unicode"
"xorm.io/builder"
"github.com/answerdev/answer/internal/base/constant"
"github.com/answerdev/answer/internal/base/data"
@ -68,7 +72,7 @@ func (ur *userBackyardRepo) GetUserInfo(ctx context.Context, userID string) (use
}
// GetUserPage get user page
func (ur *userBackyardRepo) GetUserPage(ctx context.Context, page, pageSize int, user *entity.User) (users []*entity.User, total int64, err error) {
func (ur *userBackyardRepo) GetUserPage(ctx context.Context, page, pageSize int, user *entity.User, query string) (users []*entity.User, total int64, err error) {
users = make([]*entity.User, 0)
session := ur.data.DB.NewSession()
if user.Status == entity.UserStatusDeleted {
@ -78,6 +82,40 @@ func (ur *userBackyardRepo) GetUserPage(ctx context.Context, page, pageSize int,
} else {
session.Desc("created_at")
}
if len(query) > 0 {
if email, e := mail.ParseAddress(query); e == nil {
session.And(builder.Eq{"e_mail": email.Address})
} else {
var (
idSearch = false
id = ""
)
if strings.Contains(query, "id:") {
idSearch = true
id = strings.TrimSpace(strings.TrimPrefix(query, "id:"))
for _, r := range id {
if !unicode.IsDigit(r) {
idSearch = false
break
}
}
}
if idSearch {
session.And(builder.Eq{
"id": id,
})
} else {
session.And(builder.Or(
builder.Like{"username", query},
builder.Like{"display_name", query},
))
}
}
}
total, err = pager.Help(page, pageSize, &users, user, session)
if err != nil {
err = errors.InternalServer(reason.DatabaseError).WithError(err).WithStack()

View File

@ -26,10 +26,8 @@ type GetUserPageReq struct {
Page int `validate:"omitempty,min=1" form:"page"`
// page size
PageSize int `validate:"omitempty,min=1" form:"page_size"`
// username
Username string `validate:"omitempty,gt=0,lte=50" form:"username"`
// email
EMail string `validate:"omitempty,gt=0,lte=100" form:"e_mail"`
Query string `validate:"omitempty,gt=0,lte=100" form:"query"`
// user status
Status string `validate:"omitempty,oneof=suspended deleted inactive" form:"status"`
}

View File

@ -171,6 +171,7 @@ type CmsQuestionSearch struct {
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 AdminSetQuestionStatusRequest struct {

View File

@ -42,6 +42,9 @@ func (as *AnswerCommon) SearchAnswered(ctx context.Context, userId, questionId s
}
func (as *AnswerCommon) CmsSearchList(ctx context.Context, search *entity.CmsAnswerSearch) ([]*entity.Answer, int64, error) {
if search.Status == 0 {
search.Status = 1
}
return as.answerRepo.CmsSearchList(ctx, search)
}

View File

@ -17,7 +17,7 @@ import (
type UserBackyardRepo interface {
UpdateUserStatus(ctx context.Context, userID string, userStatus, mailStatus int, email string) (err error)
GetUserInfo(ctx context.Context, userID string) (user *entity.User, exist bool, err error)
GetUserPage(ctx context.Context, page, pageSize int, user *entity.User) (users []*entity.User, total int64, err error)
GetUserPage(ctx context.Context, page, pageSize int, user *entity.User, query string) (users []*entity.User, total int64, err error)
}
// UserBackyardService user service
@ -91,7 +91,7 @@ func (us *UserBackyardService) GetUserPage(ctx context.Context, req *schema.GetU
user.Status = entity.UserStatusDeleted
}
users, total, err := us.userRepo.GetUserPage(ctx, req.Page, req.PageSize, user)
users, total, err := us.userRepo.GetUserPage(ctx, req.Page, req.PageSize, user, req.Query)
if err != nil {
return
}