Merge branch 'dev' into test
# Conflicts: # cmd/wire_gen.go # internal/service/content/question_service.go
This commit is contained in:
+2
-2
@@ -195,12 +195,13 @@ func initApplication(debug bool, serverConf *conf.Server, dbConf *data.Database,
|
||||
rateLimitMiddleware := middleware.NewRateLimitMiddleware(limitRepo)
|
||||
commentController := controller.NewCommentController(commentService, rankService, captchaService, rateLimitMiddleware)
|
||||
reportRepo := report.NewReportRepo(dataData, uniqueIDRepo)
|
||||
tagService := tag2.NewTagService(tagRepo, tagCommonService, revisionService, followRepo, siteInfoCommonService, activityQueueService)
|
||||
answerActivityRepo := activity.NewAnswerActivityRepo(dataData, activityRepo, userRankRepo, notificationQueueService)
|
||||
answerActivityService := activity2.NewAnswerActivityService(answerActivityRepo, configService)
|
||||
externalNotificationService := notification.NewExternalNotificationService(dataData, userNotificationConfigRepo, followRepo, emailService, userRepo, externalNotificationQueueService, userExternalLoginRepo, siteInfoCommonService)
|
||||
reviewRepo := review.NewReviewRepo(dataData)
|
||||
reviewService := review2.NewReviewService(reviewRepo, objService, userCommon, userRepo, questionRepo, answerRepo, userRoleRelService, externalNotificationQueueService, tagCommonService, questionCommon, notificationQueueService, siteInfoCommonService)
|
||||
questionService := content.NewQuestionService(questionRepo, answerRepo, tagCommonService, questionCommon, userCommon, userRepo, userRoleRelService, revisionService, metaCommonService, collectionCommon, answerActivityService, emailService, notificationQueueService, externalNotificationQueueService, activityQueueService, siteInfoCommonService, externalNotificationService, reviewService, configService, eventQueueService)
|
||||
questionService := content.NewQuestionService(activityRepo, questionRepo, answerRepo, tagCommonService, tagService, questionCommon, userCommon, userRepo, userRoleRelService, revisionService, metaCommonService, collectionCommon, answerActivityService, emailService, notificationQueueService, externalNotificationQueueService, activityQueueService, siteInfoCommonService, externalNotificationService, reviewService, configService, eventQueueService)
|
||||
answerService := content.NewAnswerService(answerRepo, questionRepo, questionCommon, userCommon, collectionCommon, userRepo, revisionService, answerActivityService, answerCommon, voteRepo, emailService, userRoleRelService, notificationQueueService, externalNotificationQueueService, activityQueueService, reviewService, eventQueueService)
|
||||
reportHandle := report_handle.NewReportHandle(questionService, answerService, commentService)
|
||||
reportService := report2.NewReportService(reportRepo, objService, userCommon, answerRepo, questionRepo, commentCommonRepo, reportHandle, configService, eventQueueService)
|
||||
@@ -208,7 +209,6 @@ func initApplication(debug bool, serverConf *conf.Server, dbConf *data.Database,
|
||||
contentVoteRepo := activity.NewVoteRepo(dataData, activityRepo, userRankRepo, notificationQueueService)
|
||||
voteService := content.NewVoteService(contentVoteRepo, configService, questionRepo, answerRepo, commentCommonRepo, objService, eventQueueService)
|
||||
voteController := controller.NewVoteController(voteService, rankService, captchaService)
|
||||
tagService := tag2.NewTagService(tagRepo, tagCommonService, revisionService, followRepo, siteInfoCommonService, activityQueueService)
|
||||
tagController := controller.NewTagController(tagService, tagCommonService, rankService)
|
||||
followFollowRepo := activity.NewFollowRepo(dataData, uniqueIDRepo, activityRepo)
|
||||
followService := follow.NewFollowService(followFollowRepo, followRepo, tagCommonRepo)
|
||||
|
||||
+63
-1
@@ -4562,6 +4562,67 @@ const docTemplate = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"/answer/api/v1/question/recommend/page": {
|
||||
"get": {
|
||||
"description": "get recommend questions by page",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Question"
|
||||
],
|
||||
"summary": "get recommend questions by page",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "QuestionPageReq",
|
||||
"name": "data",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/schema.QuestionPageReq"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/handler.RespBody"
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"data": {
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/pager.PageModel"
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"list": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/schema.QuestionPageResp"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/answer/api/v1/question/recover": {
|
||||
"post": {
|
||||
"security": [
|
||||
@@ -9491,7 +9552,8 @@ const docTemplate = `{
|
||||
"active",
|
||||
"hot",
|
||||
"score",
|
||||
"unanswered"
|
||||
"unanswered",
|
||||
"recommend"
|
||||
]
|
||||
},
|
||||
"page": {
|
||||
|
||||
+63
-1
@@ -4536,6 +4536,67 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/answer/api/v1/question/recommend/page": {
|
||||
"get": {
|
||||
"description": "get recommend questions by page",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Question"
|
||||
],
|
||||
"summary": "get recommend questions by page",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "QuestionPageReq",
|
||||
"name": "data",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/schema.QuestionPageReq"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/handler.RespBody"
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"data": {
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/pager.PageModel"
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"list": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/schema.QuestionPageResp"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/answer/api/v1/question/recover": {
|
||||
"post": {
|
||||
"security": [
|
||||
@@ -9465,7 +9526,8 @@
|
||||
"active",
|
||||
"hot",
|
||||
"score",
|
||||
"unanswered"
|
||||
"unanswered",
|
||||
"recommend"
|
||||
]
|
||||
},
|
||||
"page": {
|
||||
|
||||
@@ -1555,6 +1555,7 @@ definitions:
|
||||
- hot
|
||||
- score
|
||||
- unanswered
|
||||
- recommend
|
||||
type: string
|
||||
page:
|
||||
minimum: 1
|
||||
@@ -5643,6 +5644,40 @@ paths:
|
||||
summary: get questions by page
|
||||
tags:
|
||||
- Question
|
||||
/answer/api/v1/question/recommend/page:
|
||||
get:
|
||||
consumes:
|
||||
- application/json
|
||||
description: get recommend questions by page
|
||||
parameters:
|
||||
- description: QuestionPageReq
|
||||
in: body
|
||||
name: data
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/schema.QuestionPageReq'
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
allOf:
|
||||
- $ref: '#/definitions/handler.RespBody'
|
||||
- properties:
|
||||
data:
|
||||
allOf:
|
||||
- $ref: '#/definitions/pager.PageModel'
|
||||
- properties:
|
||||
list:
|
||||
items:
|
||||
$ref: '#/definitions/schema.QuestionPageResp'
|
||||
type: array
|
||||
type: object
|
||||
type: object
|
||||
summary: get recommend questions by page
|
||||
tags:
|
||||
- Question
|
||||
/answer/api/v1/question/recover:
|
||||
post:
|
||||
consumes:
|
||||
|
||||
@@ -79,7 +79,6 @@ require (
|
||||
github.com/cenkalti/backoff/v4 v4.2.1 // indirect
|
||||
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect
|
||||
github.com/containerd/continuity v0.4.2 // indirect
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/docker/cli v24.0.6+incompatible // indirect
|
||||
github.com/docker/docker v24.0.6+incompatible // indirect
|
||||
@@ -129,7 +128,6 @@ require (
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
|
||||
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
||||
github.com/sirupsen/logrus v1.9.3 // indirect
|
||||
github.com/spf13/afero v1.9.2 // indirect
|
||||
github.com/spf13/cast v1.5.0 // indirect
|
||||
@@ -142,13 +140,12 @@ require (
|
||||
github.com/tidwall/pretty v1.2.0 // indirect
|
||||
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
|
||||
github.com/ugorji/go/codec v1.2.11 // indirect
|
||||
github.com/urfave/cli/v2 v2.3.0 // indirect
|
||||
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect
|
||||
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
|
||||
github.com/xeipuuv/gojsonschema v1.2.0 // indirect
|
||||
go.uber.org/atomic v1.10.0 // indirect
|
||||
go.uber.org/multierr v1.8.0 // indirect
|
||||
go.uber.org/zap v1.23.0 // indirect
|
||||
go.uber.org/multierr v1.10.0 // indirect
|
||||
go.uber.org/zap v1.24.0 // indirect
|
||||
golang.org/x/arch v0.3.0 // indirect
|
||||
golang.org/x/mod v0.12.0 // indirect
|
||||
golang.org/x/sys v0.18.0 // indirect
|
||||
|
||||
@@ -128,7 +128,6 @@ github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7
|
||||
github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
||||
github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||
github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
|
||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||
@@ -616,7 +615,6 @@ github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ=
|
||||
github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU=
|
||||
github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc=
|
||||
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
|
||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
|
||||
github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E=
|
||||
@@ -692,8 +690,6 @@ github.com/swaggo/files v1.0.0/go.mod h1:N59U6URJLyU1PQgFqPM7wXLMhJx7QAolnvfQkqO
|
||||
github.com/swaggo/gin-swagger v1.5.3 h1:8mWmHLolIbrhJJTflsaFoZzRBYVmEE7JZGIq08EiC0Q=
|
||||
github.com/swaggo/gin-swagger v1.5.3/go.mod h1:3XJKSfHjDMB5dBo/0rrTXidPmgLeqsX89Yp4uA50HpI=
|
||||
github.com/swaggo/swag v1.8.1/go.mod h1:ugemnJsPZm/kRwFUnzBlbHRd0JY9zE1M4F+uy2pAaPQ=
|
||||
github.com/swaggo/swag v1.16.1 h1:fTNRhKstPKxcnoKsytm4sahr8FaYzUcT7i1/3nd/fBg=
|
||||
github.com/swaggo/swag v1.16.1/go.mod h1:9/LMvHycG3NFHfR6LwvikHv5iFvmPADQ359cKikGxto=
|
||||
github.com/swaggo/swag v1.16.3 h1:PnCYjPCah8FK4I26l2F/KQ4yz3sILcVUN3cTlBFA9Pg=
|
||||
github.com/swaggo/swag v1.16.3/go.mod h1:DImHIuOFXKpMFAQjcC7FG4m3Dg4+QuUgUzJmKjI/gRk=
|
||||
github.com/syndtr/goleveldb v1.0.0 h1:fBdIW9lB4Iz0n9khmH8w27SJ3QEJ7+IgjPEwGSZiFdE=
|
||||
@@ -714,9 +710,7 @@ github.com/ugorji/go/codec v1.2.7/go.mod h1:WGN1fab3R1fzQlVQTkfxVtIBhWDRqOviHU95
|
||||
github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU=
|
||||
github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
|
||||
github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
|
||||
github.com/urfave/cli v1.22.1 h1:+mkCCcOFKPnCmVYVcURKps1Xe+3zP90gSYGNfRkjoIY=
|
||||
github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
|
||||
github.com/urfave/cli/v2 v2.3.0 h1:qph92Y649prgesehzOrQjdWyxFOp/QVM+6imKHad91M=
|
||||
github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI=
|
||||
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
|
||||
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo=
|
||||
@@ -752,21 +746,20 @@ go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
||||
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
||||
go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
|
||||
go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
|
||||
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
||||
go.uber.org/atomic v1.10.0 h1:9qC72Qh0+3MqyJbAn8YU5xVq1frD8bn3JtD2oXtafVQ=
|
||||
go.uber.org/atomic v1.10.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0=
|
||||
go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI=
|
||||
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
|
||||
go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4=
|
||||
go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU=
|
||||
go.uber.org/multierr v1.8.0 h1:dg6GjLku4EH+249NNmoIciG9N/jURbDG+pFlTkhzIC8=
|
||||
go.uber.org/multierr v1.8.0/go.mod h1:7EAYxJLBy9rStEaz58O2t4Uvip6FSURkq8/ppBp95ak=
|
||||
go.uber.org/multierr v1.10.0 h1:S0h4aNzvfcFsC3dRF1jLoaov7oRaKqRGC/pUEJ2yvPQ=
|
||||
go.uber.org/multierr v1.10.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
|
||||
go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA=
|
||||
go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
|
||||
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
|
||||
go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM=
|
||||
go.uber.org/zap v1.23.0 h1:OjGQ5KQDEUawVHxNwQgPpiypGHOxo2mNZsOqTak4fFY=
|
||||
go.uber.org/zap v1.23.0/go.mod h1:D+nX8jyLsMHMYrln8A0rJjFt/T/9/bGgIhAqxv5URuY=
|
||||
go.uber.org/zap v1.24.0 h1:FiJd5l1UOLj0wCgbSE0rwwXHzEdAZS6hiiSnxJN/D60=
|
||||
go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg=
|
||||
golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
|
||||
golang.org/x/arch v0.3.0 h1:02VY4/ZcO/gBOH6PUaoiptASxtXU10jazRCP865E97k=
|
||||
golang.org/x/arch v0.3.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
|
||||
|
||||
@@ -1558,6 +1558,7 @@ ui:
|
||||
newest: Newest
|
||||
active: Active
|
||||
hot: Hot
|
||||
recommend: Recommend
|
||||
score: Score
|
||||
unanswered: Unanswered
|
||||
modified: modified
|
||||
|
||||
@@ -859,6 +859,7 @@ ui:
|
||||
newest: Newest
|
||||
active: Active
|
||||
hot: Hot
|
||||
recommend: Recommend
|
||||
score: Score
|
||||
unanswered: Unanswered
|
||||
modified: modified
|
||||
|
||||
@@ -340,6 +340,35 @@ func (qc *QuestionController) QuestionPage(ctx *gin.Context) {
|
||||
handler.HandleResponse(ctx, nil, pager.NewPageModel(total, questions))
|
||||
}
|
||||
|
||||
// QuestionRecommendPage get recommend questions by page
|
||||
// @Summary get recommend questions by page
|
||||
// @Description get recommend questions by page
|
||||
// @Tags Question
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param data body schema.QuestionPageReq true "QuestionPageReq"
|
||||
// @Success 200 {object} handler.RespBody{data=pager.PageModel{list=[]schema.QuestionPageResp}}
|
||||
// @Router /answer/api/v1/question/recommend/page [get]
|
||||
func (qc *QuestionController) QuestionRecommendPage(ctx *gin.Context) {
|
||||
req := &schema.QuestionPageReq{}
|
||||
if handler.BindAndCheck(ctx, req) {
|
||||
return
|
||||
}
|
||||
req.LoginUserID = middleware.GetLoginUserIDFromContext(ctx)
|
||||
|
||||
if req.LoginUserID == "" {
|
||||
handler.HandleResponse(ctx, errors.Unauthorized(reason.UnauthorizedError), nil)
|
||||
return
|
||||
}
|
||||
|
||||
questions, total, err := qc.questionService.GetRecommendQuestionPage(ctx, req)
|
||||
if err != nil {
|
||||
handler.HandleResponse(ctx, err, nil)
|
||||
return
|
||||
}
|
||||
handler.HandleResponse(ctx, nil, pager.NewPageModel(total, questions))
|
||||
}
|
||||
|
||||
// AddQuestion add question
|
||||
// @Summary add question
|
||||
// @Description add question
|
||||
|
||||
@@ -107,6 +107,19 @@ func (ar *ActivityRepo) GetActivity(ctx context.Context, session *xorm.Session,
|
||||
return
|
||||
}
|
||||
|
||||
func (ar *ActivityRepo) GetUserActivitysByActivityType(ctx context.Context, userID string, activityType int) (
|
||||
activityList []*entity.Activity, err error) {
|
||||
activityList = make([]*entity.Activity, 0)
|
||||
err = ar.data.DB.Context(ctx).Where("user_id = ?", userID).
|
||||
And("activity_type = ?", activityType).
|
||||
And("cancelled = 0").
|
||||
Find(&activityList)
|
||||
if err != nil {
|
||||
err = errors.InternalServer(reason.DatabaseError).WithError(err).WithStack()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (ar *ActivityRepo) GetUserIDObjectIDActivitySum(ctx context.Context, userID, objectID string) (int, error) {
|
||||
sum := &entity.ActivityRankSum{}
|
||||
_, err := ar.data.DB.Context(ctx).Table(entity.Activity{}.TableName()).
|
||||
|
||||
@@ -401,6 +401,61 @@ func (qr *questionRepo) GetQuestionPage(ctx context.Context, page, pageSize int,
|
||||
return questionList, total, err
|
||||
}
|
||||
|
||||
// GetRecommendQuestionPageByTags get recommend question page by tags
|
||||
func (qr *questionRepo) GetRecommendQuestionPageByTags(ctx context.Context, userID string, tagIDs, followedQuestionIDs []string, page, pageSize int) (
|
||||
questionList []*entity.Question, total int64, err error) {
|
||||
questionList = make([]*entity.Question, 0)
|
||||
orderBySQL := "question.pin DESC, question.created_at DESC"
|
||||
|
||||
// Please Make sure every question has at least one tag
|
||||
selectSQL := entity.Question{}.TableName() + ".*"
|
||||
if len(followedQuestionIDs) > 0 {
|
||||
idStr := "'" + strings.Join(followedQuestionIDs, "','") + "'"
|
||||
selectSQL += fmt.Sprintf(", CASE WHEN question.id IN (%s) THEN 0 ELSE 1 END AS order_priority", idStr)
|
||||
orderBySQL = "order_priority, " + orderBySQL
|
||||
}
|
||||
session := qr.data.DB.Context(ctx).Select(selectSQL)
|
||||
|
||||
if len(tagIDs) > 0 {
|
||||
session.Where("question.user_id != ?", userID).
|
||||
And("question.id NOT IN (SELECT question_id FROM answer WHERE user_id = ?)", userID).
|
||||
Join("INNER", "tag_rel", "question.id = tag_rel.object_id").
|
||||
And("tag_rel.status = ?", entity.TagRelStatusAvailable).
|
||||
Join("INNER", "tag", "tag.id = tag_rel.tag_id").
|
||||
In("tag.id", tagIDs)
|
||||
} else if len(followedQuestionIDs) == 0 {
|
||||
return questionList, 0, nil
|
||||
}
|
||||
|
||||
if len(followedQuestionIDs) > 0 {
|
||||
if len(tagIDs) > 0 {
|
||||
// if tags provided, show followed questions and tag questions
|
||||
session.Or(builder.In("question.id", followedQuestionIDs))
|
||||
} else {
|
||||
// if no tags, only show followed questions
|
||||
session.Where(builder.In("question.id", followedQuestionIDs))
|
||||
}
|
||||
}
|
||||
|
||||
session.
|
||||
And("question.show = ? and question.status = ?", entity.QuestionShow, entity.QuestionStatusAvailable).
|
||||
Distinct("question.id").
|
||||
OrderBy(orderBySQL)
|
||||
|
||||
total, err = pager.Help(page, pageSize, &questionList, &entity.Question{}, session)
|
||||
if err != nil {
|
||||
err = errors.InternalServer(reason.DatabaseError).WithError(err).WithStack()
|
||||
}
|
||||
|
||||
if handler.GetEnableShortID(ctx) {
|
||||
for _, item := range questionList {
|
||||
item.ID = uid.EnShortID(item.ID)
|
||||
}
|
||||
}
|
||||
|
||||
return questionList, total, err
|
||||
}
|
||||
|
||||
func (qr *questionRepo) AdminQuestionPage(ctx context.Context, search *schema.AdminQuestionPageReq) ([]*entity.Question, int64, error) {
|
||||
var (
|
||||
count int64
|
||||
|
||||
@@ -0,0 +1,215 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
package repo_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/apache/incubator-answer/internal/entity"
|
||||
"github.com/apache/incubator-answer/internal/repo/activity"
|
||||
"github.com/apache/incubator-answer/internal/repo/activity_common"
|
||||
"github.com/apache/incubator-answer/internal/repo/config"
|
||||
"github.com/apache/incubator-answer/internal/repo/question"
|
||||
"github.com/apache/incubator-answer/internal/repo/tag"
|
||||
"github.com/apache/incubator-answer/internal/repo/tag_common"
|
||||
"github.com/apache/incubator-answer/internal/repo/unique"
|
||||
"github.com/apache/incubator-answer/internal/repo/user"
|
||||
config2 "github.com/apache/incubator-answer/internal/service/config"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func Test_questionRepo_GetRecommend(t *testing.T) {
|
||||
var (
|
||||
uniqueIDRepo = unique.NewUniqueIDRepo(testDataSource)
|
||||
questionRepo = question.NewQuestionRepo(testDataSource, uniqueIDRepo)
|
||||
userRepo = user.NewUserRepo(testDataSource)
|
||||
tagRelRepo = tag.NewTagRelRepo(testDataSource, uniqueIDRepo)
|
||||
tagRepo = tag.NewTagRepo(testDataSource, uniqueIDRepo)
|
||||
tagCommenRepo = tag_common.NewTagCommonRepo(testDataSource, uniqueIDRepo)
|
||||
configRepo = config.NewConfigRepo(testDataSource)
|
||||
configService = config2.NewConfigService(configRepo)
|
||||
activityCommonRepo = activity_common.NewActivityRepo(testDataSource, uniqueIDRepo, configService)
|
||||
followRepo = activity.NewFollowRepo(testDataSource, uniqueIDRepo, activityCommonRepo)
|
||||
)
|
||||
|
||||
// create question and user
|
||||
user := &entity.User{
|
||||
Username: "ferrischi201",
|
||||
Pass: "ferrischi201",
|
||||
EMail: "ferrischi201@example.com",
|
||||
MailStatus: entity.EmailStatusAvailable,
|
||||
Status: entity.UserStatusAvailable,
|
||||
DisplayName: "ferrischi201",
|
||||
IsAdmin: false,
|
||||
}
|
||||
err := userRepo.AddUser(context.TODO(), user)
|
||||
assert.NoError(t, err)
|
||||
assert.NotEqual(t, "", user.ID)
|
||||
|
||||
questions := make([]*entity.Question, 0)
|
||||
// tag, unjoin, unfollow
|
||||
questions = append(questions, &entity.Question{
|
||||
UserID: "1",
|
||||
Title: "Valid recommendation 1",
|
||||
OriginalText: "A go question",
|
||||
ParsedText: "Go question",
|
||||
Status: entity.QuestionStatusAvailable,
|
||||
Show: entity.QuestionShow,
|
||||
})
|
||||
// tag, unjoin, follow
|
||||
questions = append(questions, &entity.Question{
|
||||
UserID: "1",
|
||||
Title: "Valid recommendation 2",
|
||||
OriginalText: "A go question",
|
||||
ParsedText: "Go question",
|
||||
Status: entity.QuestionStatusAvailable,
|
||||
Show: entity.QuestionShow,
|
||||
})
|
||||
// tag, join, unfollow
|
||||
questions = append(questions, &entity.Question{
|
||||
UserID: user.ID,
|
||||
Title: "Invalid recommendation 1",
|
||||
OriginalText: "A go question 1",
|
||||
ParsedText: "Go question",
|
||||
Status: entity.QuestionStatusAvailable,
|
||||
Show: entity.QuestionShow,
|
||||
})
|
||||
// tag, join, follow
|
||||
questions = append(questions, &entity.Question{
|
||||
UserID: user.ID,
|
||||
Title: "Valid recommendation 3",
|
||||
OriginalText: "A java question",
|
||||
ParsedText: "Java question",
|
||||
Status: entity.QuestionStatusAvailable,
|
||||
Show: entity.QuestionShow,
|
||||
})
|
||||
// untag, unjoin, unfollow
|
||||
questions = append(questions, &entity.Question{
|
||||
UserID: "1",
|
||||
Title: "Invalid recommendation 2",
|
||||
OriginalText: "A go question",
|
||||
ParsedText: "Go question",
|
||||
Status: entity.QuestionStatusAvailable,
|
||||
Show: entity.QuestionShow,
|
||||
})
|
||||
// untag, unjoin, follow
|
||||
questions = append(questions, &entity.Question{
|
||||
UserID: "1",
|
||||
Title: "Valid recommendation 4",
|
||||
OriginalText: "A go question",
|
||||
ParsedText: "Go question",
|
||||
Status: entity.QuestionStatusAvailable,
|
||||
Show: entity.QuestionShow,
|
||||
})
|
||||
// untag, join, unfollow
|
||||
questions = append(questions, &entity.Question{
|
||||
UserID: user.ID,
|
||||
Title: "Invalid recommendation 3",
|
||||
OriginalText: "A go question 1",
|
||||
ParsedText: "Go question",
|
||||
Status: entity.QuestionStatusAvailable,
|
||||
Show: entity.QuestionShow,
|
||||
})
|
||||
// untag, join, follow
|
||||
questions = append(questions, &entity.Question{
|
||||
UserID: user.ID,
|
||||
Title: "Valid recommendation 5",
|
||||
OriginalText: "A java question",
|
||||
ParsedText: "Java question",
|
||||
Status: entity.QuestionStatusAvailable,
|
||||
Show: entity.QuestionShow,
|
||||
})
|
||||
|
||||
for _, question := range questions {
|
||||
err = questionRepo.AddQuestion(context.TODO(), question)
|
||||
assert.NoError(t, err)
|
||||
assert.NotEqual(t, "", question.ID)
|
||||
}
|
||||
|
||||
tags := []*entity.Tag{
|
||||
{
|
||||
SlugName: "go",
|
||||
DisplayName: "Golang",
|
||||
OriginalText: "golang",
|
||||
ParsedText: "<p>golang</p>",
|
||||
Status: entity.TagStatusAvailable,
|
||||
},
|
||||
{
|
||||
SlugName: "java",
|
||||
DisplayName: "Java",
|
||||
OriginalText: "java",
|
||||
ParsedText: "<p>java</p>",
|
||||
Status: entity.TagStatusAvailable,
|
||||
},
|
||||
}
|
||||
err = tagCommenRepo.AddTagList(context.TODO(), tags)
|
||||
assert.NoError(t, err)
|
||||
|
||||
tagRels := make([]*entity.TagRel, 0)
|
||||
for i, question := range questions {
|
||||
tagRel := &entity.TagRel{
|
||||
TagID: tags[i/4].ID,
|
||||
ObjectID: question.ID,
|
||||
Status: entity.TagRelStatusAvailable,
|
||||
}
|
||||
tagRels = append(tagRels, tagRel)
|
||||
}
|
||||
err = tagRelRepo.AddTagRelList(context.TODO(), tagRels)
|
||||
assert.NoError(t, err)
|
||||
|
||||
followQuestionIDs := make([]string, 0)
|
||||
for i := range questions {
|
||||
if i%2 == 0 {
|
||||
continue
|
||||
}
|
||||
err = followRepo.Follow(context.TODO(), questions[i].ID, user.ID)
|
||||
assert.NoError(t, err)
|
||||
followQuestionIDs = append(followQuestionIDs, questions[i].ID)
|
||||
}
|
||||
|
||||
// get recommend
|
||||
questionList, total, err := questionRepo.GetRecommendQuestionPageByTags(context.TODO(), user.ID, []string{tags[0].ID}, followQuestionIDs, 1, 20)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, int64(5), total)
|
||||
assert.Equal(t, 5, len(questionList))
|
||||
|
||||
// recovery
|
||||
t.Cleanup(func() {
|
||||
tagRelIDs := make([]int64, 0)
|
||||
for i, tagRel := range tagRels {
|
||||
if i%2 == 1 {
|
||||
err = followRepo.FollowCancel(context.TODO(), questions[i].ID, user.ID)
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
tagRelIDs = append(tagRelIDs, tagRel.ID)
|
||||
}
|
||||
err = tagRelRepo.RemoveTagRelListByIDs(context.TODO(), tagRelIDs)
|
||||
assert.NoError(t, err)
|
||||
for _, tag := range tags {
|
||||
err = tagRepo.RemoveTag(context.TODO(), tag.ID)
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
for _, q := range questions {
|
||||
err = questionRepo.RemoveQuestion(context.TODO(), q.ID)
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -165,6 +165,7 @@ func (a *AnswerAPIRouter) RegisterUnAuthAnswerAPIRouter(r *gin.RouterGroup) {
|
||||
r.GET("/question/info", a.questionController.GetQuestion)
|
||||
r.GET("/question/invite", a.questionController.GetQuestionInviteUserInfo)
|
||||
r.GET("/question/page", a.questionController.QuestionPage)
|
||||
r.GET("/question/recommend/page", a.questionController.QuestionRecommendPage)
|
||||
r.GET("/question/similar/tag", a.questionController.SimilarQuestion)
|
||||
r.GET("/personal/qa/top", a.questionController.UserTop)
|
||||
r.GET("/personal/question/page", a.questionController.PersonalQuestionPage)
|
||||
|
||||
@@ -355,7 +355,7 @@ const (
|
||||
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 hot score unanswered" form:"order"`
|
||||
OrderCond string `validate:"omitempty,oneof=newest active hot score unanswered recommend" form:"order"`
|
||||
Tag string `validate:"omitempty,gt=0,lte=100" form:"tag"`
|
||||
Username string `validate:"omitempty,gt=0,lte=100" form:"username"`
|
||||
InDays int `validate:"omitempty,min=1" form:"in_days"`
|
||||
|
||||
@@ -37,6 +37,7 @@ type ActivityRepo interface {
|
||||
GetActivityTypeByObjectType(ctx context.Context, objectKey, action string) (activityType int, err error)
|
||||
GetActivity(ctx context.Context, session *xorm.Session, objectID, userID string, activityType int) (
|
||||
existsActivity *entity.Activity, exist bool, err error)
|
||||
GetUserActivitysByActivityType(ctx context.Context, userID string, activityType int) (activityList []*entity.Activity, err error)
|
||||
GetUserIDObjectIDActivitySum(ctx context.Context, userID, objectID string) (int, error)
|
||||
GetActivityTypeByConfigKey(ctx context.Context, configKey string) (activityType int, err error)
|
||||
AddActivity(ctx context.Context, activity *entity.Activity) (err error)
|
||||
|
||||
@@ -22,7 +22,6 @@ package content
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
answercommon "github.com/apache/incubator-answer/internal/service/answer_common"
|
||||
"github.com/apache/incubator-answer/internal/service/event_queue"
|
||||
"strings"
|
||||
"time"
|
||||
@@ -36,11 +35,13 @@ import (
|
||||
"github.com/apache/incubator-answer/internal/entity"
|
||||
"github.com/apache/incubator-answer/internal/schema"
|
||||
"github.com/apache/incubator-answer/internal/service/activity"
|
||||
"github.com/apache/incubator-answer/internal/service/activity_common"
|
||||
"github.com/apache/incubator-answer/internal/service/activity_queue"
|
||||
answercommon "github.com/apache/incubator-answer/internal/service/answer_common"
|
||||
collectioncommon "github.com/apache/incubator-answer/internal/service/collection_common"
|
||||
"github.com/apache/incubator-answer/internal/service/config"
|
||||
"github.com/apache/incubator-answer/internal/service/export"
|
||||
"github.com/apache/incubator-answer/internal/service/meta_common"
|
||||
metacommon "github.com/apache/incubator-answer/internal/service/meta_common"
|
||||
"github.com/apache/incubator-answer/internal/service/notice_queue"
|
||||
"github.com/apache/incubator-answer/internal/service/notification"
|
||||
"github.com/apache/incubator-answer/internal/service/permission"
|
||||
@@ -49,6 +50,7 @@ import (
|
||||
"github.com/apache/incubator-answer/internal/service/revision_common"
|
||||
"github.com/apache/incubator-answer/internal/service/role"
|
||||
"github.com/apache/incubator-answer/internal/service/siteinfo_common"
|
||||
"github.com/apache/incubator-answer/internal/service/tag"
|
||||
tagcommon "github.com/apache/incubator-answer/internal/service/tag_common"
|
||||
usercommon "github.com/apache/incubator-answer/internal/service/user_common"
|
||||
"github.com/apache/incubator-answer/pkg/checker"
|
||||
@@ -66,9 +68,11 @@ import (
|
||||
|
||||
// QuestionService user service
|
||||
type QuestionService struct {
|
||||
activityRepo activity_common.ActivityRepo
|
||||
questionRepo questioncommon.QuestionRepo
|
||||
answerRepo answercommon.AnswerRepo
|
||||
tagCommon *tagcommon.TagCommonService
|
||||
tagService *tag.TagService
|
||||
questioncommon *questioncommon.QuestionCommon
|
||||
userCommon *usercommon.UserCommon
|
||||
userRepo usercommon.UserRepo
|
||||
@@ -89,9 +93,11 @@ type QuestionService struct {
|
||||
}
|
||||
|
||||
func NewQuestionService(
|
||||
activityRepo activity_common.ActivityRepo,
|
||||
questionRepo questioncommon.QuestionRepo,
|
||||
answerRepo answercommon.AnswerRepo,
|
||||
tagCommon *tagcommon.TagCommonService,
|
||||
tagService *tag.TagService,
|
||||
questioncommon *questioncommon.QuestionCommon,
|
||||
userCommon *usercommon.UserCommon,
|
||||
userRepo usercommon.UserRepo,
|
||||
@@ -111,9 +117,11 @@ func NewQuestionService(
|
||||
eventQueueService event_queue.EventQueueService,
|
||||
) *QuestionService {
|
||||
return &QuestionService{
|
||||
activityRepo: activityRepo,
|
||||
questionRepo: questionRepo,
|
||||
answerRepo: answerRepo,
|
||||
tagCommon: tagCommon,
|
||||
tagService: tagService,
|
||||
questioncommon: questioncommon,
|
||||
userCommon: userCommon,
|
||||
userRepo: userRepo,
|
||||
@@ -1358,6 +1366,47 @@ func (qs *QuestionService) GetQuestionPage(ctx context.Context, req *schema.Ques
|
||||
return questions, total, nil
|
||||
}
|
||||
|
||||
// GetRecommendQuestionPage retrieves recommended question page based on following tags and questions.
|
||||
func (qs *QuestionService) GetRecommendQuestionPage(ctx context.Context, req *schema.QuestionPageReq) (
|
||||
questions []*schema.QuestionPageResp, total int64, err error) {
|
||||
followingTagsResp, err := qs.tagService.GetFollowingTags(ctx, req.LoginUserID)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
tagIDs := make([]string, 0, len(followingTagsResp))
|
||||
for _, tag := range followingTagsResp {
|
||||
tagIDs = append(tagIDs, tag.TagID)
|
||||
}
|
||||
|
||||
activityType, err := qs.activityRepo.GetActivityTypeByObjectType(ctx, constant.QuestionObjectType, "follow")
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
activities, err := qs.activityRepo.GetUserActivitysByActivityType(ctx, req.LoginUserID, activityType)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
followedQuestionIDs := make([]string, 0, len(activities))
|
||||
for _, activity := range activities {
|
||||
if activity.Cancelled == entity.ActivityCancelled {
|
||||
continue
|
||||
}
|
||||
followedQuestionIDs = append(followedQuestionIDs, activity.ObjectID)
|
||||
}
|
||||
questionList, total, err := qs.questionRepo.GetRecommendQuestionPageByTags(ctx, req.LoginUserID, tagIDs, followedQuestionIDs, req.Page, req.PageSize)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
questions, err = qs.questioncommon.FormatQuestionsPage(ctx, questionList, req.LoginUserID, "frequent")
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
return questions, total, nil
|
||||
}
|
||||
|
||||
func (qs *QuestionService) AdminSetQuestionStatus(ctx context.Context, req *schema.AdminUpdateQuestionStatusReq) error {
|
||||
setStatus, ok := entity.AdminQuestionSearchStatus[req.Status]
|
||||
if !ok {
|
||||
|
||||
@@ -57,6 +57,7 @@ type QuestionRepo interface {
|
||||
GetQuestionList(ctx context.Context, question *entity.Question) (questions []*entity.Question, err error)
|
||||
GetQuestionPage(ctx context.Context, page, pageSize int, tagIDs []string, userID, orderCond string, inDays int, showHidden, showPending bool) (
|
||||
questionList []*entity.Question, total int64, err error)
|
||||
GetRecommendQuestionPageByTags(ctx context.Context, userID string, tagIDs, followedQuestionIDs []string, page, pageSize int) (questionList []*entity.Question, total int64, err error)
|
||||
UpdateQuestionStatus(ctx context.Context, questionID string, status int) (err error)
|
||||
UpdateQuestionStatusWithOutUpdateTime(ctx context.Context, question *entity.Question) (err error)
|
||||
RecoverQuestion(ctx context.Context, questionID string) (err error)
|
||||
|
||||
@@ -296,6 +296,7 @@ export interface LangsType {
|
||||
* @description interface for Question
|
||||
*/
|
||||
export type QuestionOrderBy =
|
||||
| 'recommend'
|
||||
| 'newest'
|
||||
| 'active'
|
||||
| 'hot'
|
||||
|
||||
@@ -43,11 +43,13 @@ export const QUESTION_ORDER_KEYS: Type.QuestionOrderBy[] = [
|
||||
'hot',
|
||||
'score',
|
||||
'unanswered',
|
||||
'recommend',
|
||||
];
|
||||
interface Props {
|
||||
source: 'questions' | 'tag';
|
||||
order?: Type.QuestionOrderBy;
|
||||
data;
|
||||
orderList?: Type.QuestionOrderBy[];
|
||||
isLoading: boolean;
|
||||
}
|
||||
|
||||
@@ -55,6 +57,7 @@ const QuestionList: FC<Props> = ({
|
||||
source,
|
||||
order,
|
||||
data,
|
||||
orderList,
|
||||
isLoading = false,
|
||||
}) => {
|
||||
const { t } = useTranslation('translation', { keyPrefix: 'question' });
|
||||
@@ -65,6 +68,7 @@ const QuestionList: FC<Props> = ({
|
||||
const curPage = Number(urlSearchParams.get('page')) || 1;
|
||||
const pageSize = 20;
|
||||
const count = data?.count || 0;
|
||||
const orderKeys = orderList || QUESTION_ORDER_KEYS;
|
||||
|
||||
return (
|
||||
<div>
|
||||
@@ -75,7 +79,7 @@ const QuestionList: FC<Props> = ({
|
||||
: t('x_questions', { count })}
|
||||
</h5>
|
||||
<QueryGroup
|
||||
data={QUESTION_ORDER_KEYS}
|
||||
data={orderKeys}
|
||||
currentSort={curOrder}
|
||||
pathname={source === 'questions' ? '/questions' : ''}
|
||||
i18nKeyPrefix="question"
|
||||
|
||||
@@ -110,7 +110,7 @@ const Index: FC<Props> = ({
|
||||
|
||||
return (
|
||||
<div
|
||||
className={classNames('d-block d-md-flex flex-wrap', {
|
||||
className={classNames('d-flex flex-wrap', {
|
||||
'mb-3': !showAddCommentBtn,
|
||||
})}>
|
||||
{showAddCommentBtn && (
|
||||
|
||||
@@ -34,7 +34,7 @@ import {
|
||||
loggedUserInfoStore,
|
||||
loginSettingStore,
|
||||
} from '@/stores';
|
||||
import { useQuestionList } from '@/services';
|
||||
import { useQuestionList, useQuestionRecommendList } from '@/services';
|
||||
import * as Type from '@/common/interface';
|
||||
import { userCenter, floppyNavigation } from '@/utils';
|
||||
import { QUESTION_ORDER_KEYS } from '@/components/QuestionList';
|
||||
@@ -52,7 +52,10 @@ const Questions: FC = () => {
|
||||
page: curPage,
|
||||
order: curOrder as Type.QuestionOrderBy,
|
||||
};
|
||||
const { data: listData, isLoading: listLoading } = useQuestionList(reqParams);
|
||||
const { data: listData, isLoading: listLoading } =
|
||||
curOrder === 'recommend'
|
||||
? useQuestionRecommendList(reqParams)
|
||||
: useQuestionList(reqParams);
|
||||
const isIndexPage = useMatch('/');
|
||||
let pageTitle = t('questions', { keyPrefix: 'page_title' });
|
||||
let slogan = '';
|
||||
@@ -71,6 +74,11 @@ const Questions: FC = () => {
|
||||
source="questions"
|
||||
data={listData}
|
||||
order={curOrder}
|
||||
orderList={
|
||||
loggedUser.username
|
||||
? QUESTION_ORDER_KEYS
|
||||
: QUESTION_ORDER_KEYS.filter((key) => key !== 'recommend')
|
||||
}
|
||||
isLoading={listLoading}
|
||||
/>
|
||||
</Col>
|
||||
|
||||
@@ -176,6 +176,7 @@ const Index: FC = () => {
|
||||
source="tag"
|
||||
data={listData}
|
||||
order={curOrder}
|
||||
orderList={QUESTION_ORDER_KEYS.slice(0, 4)}
|
||||
isLoading={listLoading}
|
||||
/>
|
||||
</Col>
|
||||
|
||||
@@ -36,6 +36,21 @@ export const useQuestionList = (params: Type.QueryQuestionsReq) => {
|
||||
};
|
||||
};
|
||||
|
||||
export const useQuestionRecommendList = (params: Type.QueryQuestionsReq) => {
|
||||
const apiUrl = `/answer/api/v1/question/recommend/page?${qs.stringify(
|
||||
params,
|
||||
)}`;
|
||||
const { data, error } = useSWR<Type.ListResult, Error>(
|
||||
[apiUrl],
|
||||
request.instance.get,
|
||||
);
|
||||
return {
|
||||
data,
|
||||
isLoading: !data && !error,
|
||||
error,
|
||||
};
|
||||
};
|
||||
|
||||
export const useHotQuestions = (
|
||||
params: Type.QueryQuestionsReq = {
|
||||
page: 1,
|
||||
|
||||
Reference in New Issue
Block a user