mirror of https://gitee.com/answerdev/answer.git
feat(answer): support recover answer, question and tag
This commit is contained in:
parent
4825f991e7
commit
fd0b62c1f1
283
docs/docs.go
283
docs/docs.go
|
@ -103,7 +103,7 @@ const docTemplate = `{
|
|||
"ApiKeyAuth": []
|
||||
}
|
||||
],
|
||||
"description": "Status:[available,deleted]",
|
||||
"description": "update answer status",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
|
@ -113,15 +113,15 @@ const docTemplate = `{
|
|||
"tags": [
|
||||
"admin"
|
||||
],
|
||||
"summary": "AdminSetAnswerStatus",
|
||||
"summary": "update answer status",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "AdminSetAnswerStatusRequest",
|
||||
"description": "AdminUpdateAnswerStatusReq",
|
||||
"name": "data",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/schema.AdminSetAnswerStatusRequest"
|
||||
"$ref": "#/definitions/schema.AdminUpdateAnswerStatusReq"
|
||||
}
|
||||
}
|
||||
],
|
||||
|
@ -428,7 +428,7 @@ const docTemplate = `{
|
|||
"ApiKeyAuth": []
|
||||
}
|
||||
],
|
||||
"description": "Status:[available,closed,deleted]",
|
||||
"description": "update question status",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
|
@ -438,15 +438,15 @@ const docTemplate = `{
|
|||
"tags": [
|
||||
"admin"
|
||||
],
|
||||
"summary": "AdminSetQuestionStatus",
|
||||
"summary": "update question status",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "AdminSetQuestionStatusRequest",
|
||||
"description": "AdminUpdateQuestionStatusReq",
|
||||
"name": "data",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/schema.AdminSetQuestionStatusRequest"
|
||||
"$ref": "#/definitions/schema.AdminUpdateQuestionStatusReq"
|
||||
}
|
||||
}
|
||||
],
|
||||
|
@ -2142,12 +2142,12 @@ const docTemplate = `{
|
|||
"summary": "Accepted",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "AnswerAcceptedReq",
|
||||
"description": "AcceptAnswerReq",
|
||||
"name": "data",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/schema.AnswerAcceptedReq"
|
||||
"$ref": "#/definitions/schema.AcceptAnswerReq"
|
||||
}
|
||||
}
|
||||
],
|
||||
|
@ -2252,6 +2252,45 @@ const docTemplate = `{
|
|||
}
|
||||
}
|
||||
},
|
||||
"/answer/api/v1/answer/recover": {
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"ApiKeyAuth": []
|
||||
}
|
||||
],
|
||||
"description": "recover deleted answer",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Answer"
|
||||
],
|
||||
"summary": "recover answer",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "answer",
|
||||
"name": "data",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/schema.RecoverAnswerReq"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/handler.RespBody"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/answer/api/v1/collection/switch": {
|
||||
"post": {
|
||||
"security": [
|
||||
|
@ -4031,6 +4070,45 @@ const docTemplate = `{
|
|||
}
|
||||
}
|
||||
},
|
||||
"/answer/api/v1/question/recover": {
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"ApiKeyAuth": []
|
||||
}
|
||||
],
|
||||
"description": "recover deleted question",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Question"
|
||||
],
|
||||
"summary": "recover deleted question",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "question",
|
||||
"name": "data",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/schema.QuestionRecoverReq"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/handler.RespBody"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/answer/api/v1/question/reopen": {
|
||||
"put": {
|
||||
"security": [
|
||||
|
@ -4077,7 +4155,7 @@ const docTemplate = `{
|
|||
"ApiKeyAuth": []
|
||||
}
|
||||
],
|
||||
"description": "add question title like",
|
||||
"description": "fuzzy query similar questions based on title",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
|
@ -4087,7 +4165,7 @@ const docTemplate = `{
|
|||
"tags": [
|
||||
"Question"
|
||||
],
|
||||
"summary": "add question title like",
|
||||
"summary": "fuzzy query similar questions based on title",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
|
@ -4820,6 +4898,40 @@ const docTemplate = `{
|
|||
}
|
||||
}
|
||||
},
|
||||
"/answer/api/v1/tag/recover": {
|
||||
"post": {
|
||||
"description": "recover delete tag",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Tag"
|
||||
],
|
||||
"summary": "recover delete tag",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "tag",
|
||||
"name": "data",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/schema.RecoverTagReq"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/handler.RespBody"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/answer/api/v1/tag/synonym": {
|
||||
"put": {
|
||||
"description": "update tag",
|
||||
|
@ -6378,6 +6490,21 @@ const docTemplate = `{
|
|||
"list": {}
|
||||
}
|
||||
},
|
||||
"schema.AcceptAnswerReq": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"question_id"
|
||||
],
|
||||
"properties": {
|
||||
"answer_id": {
|
||||
"type": "string"
|
||||
},
|
||||
"question_id": {
|
||||
"type": "string",
|
||||
"maxLength": 30
|
||||
}
|
||||
}
|
||||
},
|
||||
"schema.ActObjectInfo": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
|
@ -6425,9 +6552,6 @@ const docTemplate = `{
|
|||
"created_at": {
|
||||
"type": "integer"
|
||||
},
|
||||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
"object_id": {
|
||||
"type": "string"
|
||||
},
|
||||
|
@ -6437,11 +6561,8 @@ const docTemplate = `{
|
|||
"revision_id": {
|
||||
"type": "string"
|
||||
},
|
||||
"user_display_name": {
|
||||
"type": "string"
|
||||
},
|
||||
"username": {
|
||||
"type": "string"
|
||||
"user_info": {
|
||||
"$ref": "#/definitions/schema.UserBasicInfo"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -6584,36 +6705,42 @@ const docTemplate = `{
|
|||
}
|
||||
}
|
||||
},
|
||||
"schema.AdminSetAnswerStatusRequest": {
|
||||
"schema.AdminUpdateAnswerStatusReq": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"answer_id",
|
||||
"status"
|
||||
],
|
||||
"properties": {
|
||||
"answer_id": {
|
||||
"type": "string"
|
||||
},
|
||||
"status": {
|
||||
"type": "string"
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"available",
|
||||
"deleted"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"schema.AdminSetQuestionStatusRequest": {
|
||||
"schema.AdminUpdateQuestionStatusReq": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"question_id",
|
||||
"status"
|
||||
],
|
||||
"properties": {
|
||||
"question_id": {
|
||||
"type": "string"
|
||||
},
|
||||
"status": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"schema.AnswerAcceptedReq": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"answer_id": {
|
||||
"type": "string"
|
||||
},
|
||||
"question_id": {
|
||||
"type": "string"
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"available",
|
||||
"closed",
|
||||
"deleted"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -7088,10 +7215,6 @@ const docTemplate = `{
|
|||
"description": "user id",
|
||||
"type": "string"
|
||||
},
|
||||
"ip_info": {
|
||||
"description": "ip info",
|
||||
"type": "string"
|
||||
},
|
||||
"language": {
|
||||
"description": "language",
|
||||
"type": "string"
|
||||
|
@ -8088,11 +8211,25 @@ const docTemplate = `{
|
|||
"rank": {
|
||||
"type": "integer"
|
||||
},
|
||||
"status": {
|
||||
"type": "string"
|
||||
},
|
||||
"username": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"schema.QuestionRecoverReq": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"question_id"
|
||||
],
|
||||
"properties": {
|
||||
"question_id": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"schema.QuestionUpdate": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
|
@ -8168,6 +8305,28 @@ const docTemplate = `{
|
|||
}
|
||||
}
|
||||
},
|
||||
"schema.RecoverAnswerReq": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"answer_id"
|
||||
],
|
||||
"properties": {
|
||||
"answer_id": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"schema.RecoverTagReq": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"tag_id"
|
||||
],
|
||||
"properties": {
|
||||
"tag_id": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"schema.RemoveAnswerReq": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
|
@ -8317,7 +8476,7 @@ const docTemplate = `{
|
|||
"description": "user info",
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/schema.UserBasicInfo"
|
||||
"$ref": "#/definitions/schema.SearchObjectUser"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
@ -8326,6 +8485,26 @@ const docTemplate = `{
|
|||
}
|
||||
}
|
||||
},
|
||||
"schema.SearchObjectUser": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"display_name": {
|
||||
"type": "string"
|
||||
},
|
||||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
"rank": {
|
||||
"type": "integer"
|
||||
},
|
||||
"status": {
|
||||
"type": "string"
|
||||
},
|
||||
"username": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"schema.SearchResp": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
|
@ -8967,7 +9146,7 @@ const docTemplate = `{
|
|||
"type": "string"
|
||||
},
|
||||
"captcha_id": {
|
||||
"description": "captcha_id",
|
||||
"description": "whether user can delete it",
|
||||
"type": "string"
|
||||
},
|
||||
"comment_id": {
|
||||
|
@ -8998,35 +9177,25 @@ const docTemplate = `{
|
|||
"type": "object",
|
||||
"properties": {
|
||||
"avatar": {
|
||||
"description": "avatar",
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/schema.AvatarInfo"
|
||||
}
|
||||
]
|
||||
"$ref": "#/definitions/schema.AvatarInfo"
|
||||
},
|
||||
"bio": {
|
||||
"description": "bio",
|
||||
"type": "string",
|
||||
"maxLength": 4096
|
||||
},
|
||||
"display_name": {
|
||||
"description": "display_name",
|
||||
"type": "string",
|
||||
"maxLength": 30
|
||||
},
|
||||
"location": {
|
||||
"description": "location",
|
||||
"type": "string",
|
||||
"maxLength": 100
|
||||
},
|
||||
"username": {
|
||||
"description": "username",
|
||||
"type": "string",
|
||||
"maxLength": 30
|
||||
},
|
||||
"website": {
|
||||
"description": "website",
|
||||
"type": "string",
|
||||
"maxLength": 500
|
||||
}
|
||||
|
@ -9250,6 +9419,9 @@ const docTemplate = `{
|
|||
"user_id"
|
||||
],
|
||||
"properties": {
|
||||
"remove_all_content": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"status": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
|
@ -9276,9 +9448,6 @@ const docTemplate = `{
|
|||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
"ip_info": {
|
||||
"type": "string"
|
||||
},
|
||||
"location": {
|
||||
"type": "string"
|
||||
},
|
||||
|
@ -9408,10 +9577,6 @@ const docTemplate = `{
|
|||
"description": "user id",
|
||||
"type": "string"
|
||||
},
|
||||
"ip_info": {
|
||||
"description": "ip info",
|
||||
"type": "string"
|
||||
},
|
||||
"language": {
|
||||
"description": "language",
|
||||
"type": "string"
|
||||
|
|
|
@ -91,7 +91,7 @@
|
|||
"ApiKeyAuth": []
|
||||
}
|
||||
],
|
||||
"description": "Status:[available,deleted]",
|
||||
"description": "update answer status",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
|
@ -101,15 +101,15 @@
|
|||
"tags": [
|
||||
"admin"
|
||||
],
|
||||
"summary": "AdminSetAnswerStatus",
|
||||
"summary": "update answer status",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "AdminSetAnswerStatusRequest",
|
||||
"description": "AdminUpdateAnswerStatusReq",
|
||||
"name": "data",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/schema.AdminSetAnswerStatusRequest"
|
||||
"$ref": "#/definitions/schema.AdminUpdateAnswerStatusReq"
|
||||
}
|
||||
}
|
||||
],
|
||||
|
@ -416,7 +416,7 @@
|
|||
"ApiKeyAuth": []
|
||||
}
|
||||
],
|
||||
"description": "Status:[available,closed,deleted]",
|
||||
"description": "update question status",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
|
@ -426,15 +426,15 @@
|
|||
"tags": [
|
||||
"admin"
|
||||
],
|
||||
"summary": "AdminSetQuestionStatus",
|
||||
"summary": "update question status",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "AdminSetQuestionStatusRequest",
|
||||
"description": "AdminUpdateQuestionStatusReq",
|
||||
"name": "data",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/schema.AdminSetQuestionStatusRequest"
|
||||
"$ref": "#/definitions/schema.AdminUpdateQuestionStatusReq"
|
||||
}
|
||||
}
|
||||
],
|
||||
|
@ -2130,12 +2130,12 @@
|
|||
"summary": "Accepted",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "AnswerAcceptedReq",
|
||||
"description": "AcceptAnswerReq",
|
||||
"name": "data",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/schema.AnswerAcceptedReq"
|
||||
"$ref": "#/definitions/schema.AcceptAnswerReq"
|
||||
}
|
||||
}
|
||||
],
|
||||
|
@ -2240,6 +2240,45 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"/answer/api/v1/answer/recover": {
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"ApiKeyAuth": []
|
||||
}
|
||||
],
|
||||
"description": "recover deleted answer",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Answer"
|
||||
],
|
||||
"summary": "recover answer",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "answer",
|
||||
"name": "data",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/schema.RecoverAnswerReq"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/handler.RespBody"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/answer/api/v1/collection/switch": {
|
||||
"post": {
|
||||
"security": [
|
||||
|
@ -4019,6 +4058,45 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"/answer/api/v1/question/recover": {
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"ApiKeyAuth": []
|
||||
}
|
||||
],
|
||||
"description": "recover deleted question",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Question"
|
||||
],
|
||||
"summary": "recover deleted question",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "question",
|
||||
"name": "data",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/schema.QuestionRecoverReq"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/handler.RespBody"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/answer/api/v1/question/reopen": {
|
||||
"put": {
|
||||
"security": [
|
||||
|
@ -4065,7 +4143,7 @@
|
|||
"ApiKeyAuth": []
|
||||
}
|
||||
],
|
||||
"description": "add question title like",
|
||||
"description": "fuzzy query similar questions based on title",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
|
@ -4075,7 +4153,7 @@
|
|||
"tags": [
|
||||
"Question"
|
||||
],
|
||||
"summary": "add question title like",
|
||||
"summary": "fuzzy query similar questions based on title",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
|
@ -4808,6 +4886,40 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"/answer/api/v1/tag/recover": {
|
||||
"post": {
|
||||
"description": "recover delete tag",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Tag"
|
||||
],
|
||||
"summary": "recover delete tag",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "tag",
|
||||
"name": "data",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/schema.RecoverTagReq"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/handler.RespBody"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/answer/api/v1/tag/synonym": {
|
||||
"put": {
|
||||
"description": "update tag",
|
||||
|
@ -6366,6 +6478,21 @@
|
|||
"list": {}
|
||||
}
|
||||
},
|
||||
"schema.AcceptAnswerReq": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"question_id"
|
||||
],
|
||||
"properties": {
|
||||
"answer_id": {
|
||||
"type": "string"
|
||||
},
|
||||
"question_id": {
|
||||
"type": "string",
|
||||
"maxLength": 30
|
||||
}
|
||||
}
|
||||
},
|
||||
"schema.ActObjectInfo": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
|
@ -6413,9 +6540,6 @@
|
|||
"created_at": {
|
||||
"type": "integer"
|
||||
},
|
||||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
"object_id": {
|
||||
"type": "string"
|
||||
},
|
||||
|
@ -6425,11 +6549,8 @@
|
|||
"revision_id": {
|
||||
"type": "string"
|
||||
},
|
||||
"user_display_name": {
|
||||
"type": "string"
|
||||
},
|
||||
"username": {
|
||||
"type": "string"
|
||||
"user_info": {
|
||||
"$ref": "#/definitions/schema.UserBasicInfo"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -6572,36 +6693,42 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"schema.AdminSetAnswerStatusRequest": {
|
||||
"schema.AdminUpdateAnswerStatusReq": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"answer_id",
|
||||
"status"
|
||||
],
|
||||
"properties": {
|
||||
"answer_id": {
|
||||
"type": "string"
|
||||
},
|
||||
"status": {
|
||||
"type": "string"
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"available",
|
||||
"deleted"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"schema.AdminSetQuestionStatusRequest": {
|
||||
"schema.AdminUpdateQuestionStatusReq": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"question_id",
|
||||
"status"
|
||||
],
|
||||
"properties": {
|
||||
"question_id": {
|
||||
"type": "string"
|
||||
},
|
||||
"status": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"schema.AnswerAcceptedReq": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"answer_id": {
|
||||
"type": "string"
|
||||
},
|
||||
"question_id": {
|
||||
"type": "string"
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"available",
|
||||
"closed",
|
||||
"deleted"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -7076,10 +7203,6 @@
|
|||
"description": "user id",
|
||||
"type": "string"
|
||||
},
|
||||
"ip_info": {
|
||||
"description": "ip info",
|
||||
"type": "string"
|
||||
},
|
||||
"language": {
|
||||
"description": "language",
|
||||
"type": "string"
|
||||
|
@ -8076,11 +8199,25 @@
|
|||
"rank": {
|
||||
"type": "integer"
|
||||
},
|
||||
"status": {
|
||||
"type": "string"
|
||||
},
|
||||
"username": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"schema.QuestionRecoverReq": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"question_id"
|
||||
],
|
||||
"properties": {
|
||||
"question_id": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"schema.QuestionUpdate": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
|
@ -8156,6 +8293,28 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"schema.RecoverAnswerReq": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"answer_id"
|
||||
],
|
||||
"properties": {
|
||||
"answer_id": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"schema.RecoverTagReq": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"tag_id"
|
||||
],
|
||||
"properties": {
|
||||
"tag_id": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"schema.RemoveAnswerReq": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
|
@ -8305,7 +8464,7 @@
|
|||
"description": "user info",
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/schema.UserBasicInfo"
|
||||
"$ref": "#/definitions/schema.SearchObjectUser"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
@ -8314,6 +8473,26 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"schema.SearchObjectUser": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"display_name": {
|
||||
"type": "string"
|
||||
},
|
||||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
"rank": {
|
||||
"type": "integer"
|
||||
},
|
||||
"status": {
|
||||
"type": "string"
|
||||
},
|
||||
"username": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"schema.SearchResp": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
|
@ -8955,7 +9134,7 @@
|
|||
"type": "string"
|
||||
},
|
||||
"captcha_id": {
|
||||
"description": "captcha_id",
|
||||
"description": "whether user can delete it",
|
||||
"type": "string"
|
||||
},
|
||||
"comment_id": {
|
||||
|
@ -8986,35 +9165,25 @@
|
|||
"type": "object",
|
||||
"properties": {
|
||||
"avatar": {
|
||||
"description": "avatar",
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/schema.AvatarInfo"
|
||||
}
|
||||
]
|
||||
"$ref": "#/definitions/schema.AvatarInfo"
|
||||
},
|
||||
"bio": {
|
||||
"description": "bio",
|
||||
"type": "string",
|
||||
"maxLength": 4096
|
||||
},
|
||||
"display_name": {
|
||||
"description": "display_name",
|
||||
"type": "string",
|
||||
"maxLength": 30
|
||||
},
|
||||
"location": {
|
||||
"description": "location",
|
||||
"type": "string",
|
||||
"maxLength": 100
|
||||
},
|
||||
"username": {
|
||||
"description": "username",
|
||||
"type": "string",
|
||||
"maxLength": 30
|
||||
},
|
||||
"website": {
|
||||
"description": "website",
|
||||
"type": "string",
|
||||
"maxLength": 500
|
||||
}
|
||||
|
@ -9238,6 +9407,9 @@
|
|||
"user_id"
|
||||
],
|
||||
"properties": {
|
||||
"remove_all_content": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"status": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
|
@ -9264,9 +9436,6 @@
|
|||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
"ip_info": {
|
||||
"type": "string"
|
||||
},
|
||||
"location": {
|
||||
"type": "string"
|
||||
},
|
||||
|
@ -9396,10 +9565,6 @@
|
|||
"description": "user id",
|
||||
"type": "string"
|
||||
},
|
||||
"ip_info": {
|
||||
"description": "ip info",
|
||||
"type": "string"
|
||||
},
|
||||
"language": {
|
||||
"description": "language",
|
||||
"type": "string"
|
||||
|
|
|
@ -99,6 +99,16 @@ definitions:
|
|||
type: integer
|
||||
list: {}
|
||||
type: object
|
||||
schema.AcceptAnswerReq:
|
||||
properties:
|
||||
answer_id:
|
||||
type: string
|
||||
question_id:
|
||||
maxLength: 30
|
||||
type: string
|
||||
required:
|
||||
- question_id
|
||||
type: object
|
||||
schema.ActObjectInfo:
|
||||
properties:
|
||||
answer_id:
|
||||
|
@ -130,18 +140,14 @@ definitions:
|
|||
type: string
|
||||
created_at:
|
||||
type: integer
|
||||
id:
|
||||
type: string
|
||||
object_id:
|
||||
type: string
|
||||
object_type:
|
||||
type: string
|
||||
revision_id:
|
||||
type: string
|
||||
user_display_name:
|
||||
type: string
|
||||
username:
|
||||
type: string
|
||||
user_info:
|
||||
$ref: '#/definitions/schema.UserBasicInfo'
|
||||
type: object
|
||||
schema.ActionRecordResp:
|
||||
properties:
|
||||
|
@ -244,26 +250,32 @@ definitions:
|
|||
description: users info line by line
|
||||
type: string
|
||||
type: object
|
||||
schema.AdminSetAnswerStatusRequest:
|
||||
schema.AdminUpdateAnswerStatusReq:
|
||||
properties:
|
||||
answer_id:
|
||||
type: string
|
||||
status:
|
||||
enum:
|
||||
- available
|
||||
- deleted
|
||||
type: string
|
||||
required:
|
||||
- answer_id
|
||||
- status
|
||||
type: object
|
||||
schema.AdminSetQuestionStatusRequest:
|
||||
schema.AdminUpdateQuestionStatusReq:
|
||||
properties:
|
||||
question_id:
|
||||
type: string
|
||||
status:
|
||||
enum:
|
||||
- available
|
||||
- closed
|
||||
- deleted
|
||||
type: string
|
||||
type: object
|
||||
schema.AnswerAcceptedReq:
|
||||
properties:
|
||||
answer_id:
|
||||
type: string
|
||||
question_id:
|
||||
type: string
|
||||
required:
|
||||
- question_id
|
||||
- status
|
||||
type: object
|
||||
schema.AnswerAddReq:
|
||||
properties:
|
||||
|
@ -596,9 +608,6 @@ definitions:
|
|||
id:
|
||||
description: user id
|
||||
type: string
|
||||
ip_info:
|
||||
description: ip info
|
||||
type: string
|
||||
language:
|
||||
description: language
|
||||
type: string
|
||||
|
@ -1304,9 +1313,18 @@ definitions:
|
|||
type: string
|
||||
rank:
|
||||
type: integer
|
||||
status:
|
||||
type: string
|
||||
username:
|
||||
type: string
|
||||
type: object
|
||||
schema.QuestionRecoverReq:
|
||||
properties:
|
||||
question_id:
|
||||
type: string
|
||||
required:
|
||||
- question_id
|
||||
type: object
|
||||
schema.QuestionUpdate:
|
||||
properties:
|
||||
captcha_code:
|
||||
|
@ -1361,6 +1379,20 @@ definitions:
|
|||
required:
|
||||
- id
|
||||
type: object
|
||||
schema.RecoverAnswerReq:
|
||||
properties:
|
||||
answer_id:
|
||||
type: string
|
||||
required:
|
||||
- answer_id
|
||||
type: object
|
||||
schema.RecoverTagReq:
|
||||
properties:
|
||||
tag_id:
|
||||
type: string
|
||||
required:
|
||||
- tag_id
|
||||
type: object
|
||||
schema.RemoveAnswerReq:
|
||||
properties:
|
||||
captcha_code:
|
||||
|
@ -1461,11 +1493,24 @@ definitions:
|
|||
type: string
|
||||
user_info:
|
||||
allOf:
|
||||
- $ref: '#/definitions/schema.UserBasicInfo'
|
||||
- $ref: '#/definitions/schema.SearchObjectUser'
|
||||
description: user info
|
||||
vote_count:
|
||||
type: integer
|
||||
type: object
|
||||
schema.SearchObjectUser:
|
||||
properties:
|
||||
display_name:
|
||||
type: string
|
||||
id:
|
||||
type: string
|
||||
rank:
|
||||
type: integer
|
||||
status:
|
||||
type: string
|
||||
username:
|
||||
type: string
|
||||
type: object
|
||||
schema.SearchResp:
|
||||
properties:
|
||||
count:
|
||||
|
@ -1902,7 +1947,7 @@ definitions:
|
|||
captcha_code:
|
||||
type: string
|
||||
captcha_id:
|
||||
description: captcha_id
|
||||
description: whether user can delete it
|
||||
type: string
|
||||
comment_id:
|
||||
description: comment id
|
||||
|
@ -1927,27 +1972,20 @@ definitions:
|
|||
schema.UpdateInfoRequest:
|
||||
properties:
|
||||
avatar:
|
||||
allOf:
|
||||
- $ref: '#/definitions/schema.AvatarInfo'
|
||||
description: avatar
|
||||
$ref: '#/definitions/schema.AvatarInfo'
|
||||
bio:
|
||||
description: bio
|
||||
maxLength: 4096
|
||||
type: string
|
||||
display_name:
|
||||
description: display_name
|
||||
maxLength: 30
|
||||
type: string
|
||||
location:
|
||||
description: location
|
||||
maxLength: 100
|
||||
type: string
|
||||
username:
|
||||
description: username
|
||||
maxLength: 30
|
||||
type: string
|
||||
website:
|
||||
description: website
|
||||
maxLength: 500
|
||||
type: string
|
||||
type: object
|
||||
|
@ -2099,6 +2137,8 @@ definitions:
|
|||
type: object
|
||||
schema.UpdateUserStatusReq:
|
||||
properties:
|
||||
remove_all_content:
|
||||
type: boolean
|
||||
status:
|
||||
enum:
|
||||
- normal
|
||||
|
@ -2120,8 +2160,6 @@ definitions:
|
|||
type: string
|
||||
id:
|
||||
type: string
|
||||
ip_info:
|
||||
type: string
|
||||
location:
|
||||
type: string
|
||||
rank:
|
||||
|
@ -2214,9 +2252,6 @@ definitions:
|
|||
id:
|
||||
description: user id
|
||||
type: string
|
||||
ip_info:
|
||||
description: ip info
|
||||
type: string
|
||||
language:
|
||||
description: language
|
||||
type: string
|
||||
|
@ -2455,14 +2490,14 @@ paths:
|
|||
put:
|
||||
consumes:
|
||||
- application/json
|
||||
description: Status:[available,deleted]
|
||||
description: update answer status
|
||||
parameters:
|
||||
- description: AdminSetAnswerStatusRequest
|
||||
- description: AdminUpdateAnswerStatusReq
|
||||
in: body
|
||||
name: data
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/schema.AdminSetAnswerStatusRequest'
|
||||
$ref: '#/definitions/schema.AdminUpdateAnswerStatusReq'
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
|
@ -2472,7 +2507,7 @@ paths:
|
|||
$ref: '#/definitions/handler.RespBody'
|
||||
security:
|
||||
- ApiKeyAuth: []
|
||||
summary: AdminSetAnswerStatus
|
||||
summary: update answer status
|
||||
tags:
|
||||
- admin
|
||||
/answer/admin/api/dashboard:
|
||||
|
@ -2653,14 +2688,14 @@ paths:
|
|||
put:
|
||||
consumes:
|
||||
- application/json
|
||||
description: Status:[available,closed,deleted]
|
||||
description: update question status
|
||||
parameters:
|
||||
- description: AdminSetQuestionStatusRequest
|
||||
- description: AdminUpdateQuestionStatusReq
|
||||
in: body
|
||||
name: data
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/schema.AdminSetQuestionStatusRequest'
|
||||
$ref: '#/definitions/schema.AdminUpdateQuestionStatusReq'
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
|
@ -2670,7 +2705,7 @@ paths:
|
|||
$ref: '#/definitions/handler.RespBody'
|
||||
security:
|
||||
- ApiKeyAuth: []
|
||||
summary: AdminSetQuestionStatus
|
||||
summary: update question status
|
||||
tags:
|
||||
- admin
|
||||
/answer/admin/api/reasons:
|
||||
|
@ -3667,12 +3702,12 @@ paths:
|
|||
- application/json
|
||||
description: Accepted
|
||||
parameters:
|
||||
- description: AnswerAcceptedReq
|
||||
- description: AcceptAnswerReq
|
||||
in: body
|
||||
name: data
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/schema.AnswerAcceptedReq'
|
||||
$ref: '#/definitions/schema.AcceptAnswerReq'
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
|
@ -3745,6 +3780,30 @@ paths:
|
|||
summary: AnswerList
|
||||
tags:
|
||||
- api-answer
|
||||
/answer/api/v1/answer/recover:
|
||||
post:
|
||||
consumes:
|
||||
- application/json
|
||||
description: recover deleted answer
|
||||
parameters:
|
||||
- description: answer
|
||||
in: body
|
||||
name: data
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/schema.RecoverAnswerReq'
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
$ref: '#/definitions/handler.RespBody'
|
||||
security:
|
||||
- ApiKeyAuth: []
|
||||
summary: recover answer
|
||||
tags:
|
||||
- Answer
|
||||
/answer/api/v1/collection/switch:
|
||||
post:
|
||||
consumes:
|
||||
|
@ -4830,6 +4889,30 @@ paths:
|
|||
summary: get questions by page
|
||||
tags:
|
||||
- Question
|
||||
/answer/api/v1/question/recover:
|
||||
post:
|
||||
consumes:
|
||||
- application/json
|
||||
description: recover deleted question
|
||||
parameters:
|
||||
- description: question
|
||||
in: body
|
||||
name: data
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/schema.QuestionRecoverReq'
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
$ref: '#/definitions/handler.RespBody'
|
||||
security:
|
||||
- ApiKeyAuth: []
|
||||
summary: recover deleted question
|
||||
tags:
|
||||
- Question
|
||||
/answer/api/v1/question/reopen:
|
||||
put:
|
||||
consumes:
|
||||
|
@ -4858,7 +4941,7 @@ paths:
|
|||
get:
|
||||
consumes:
|
||||
- application/json
|
||||
description: add question title like
|
||||
description: fuzzy query similar questions based on title
|
||||
parameters:
|
||||
- default: string
|
||||
description: title
|
||||
|
@ -4875,7 +4958,7 @@ paths:
|
|||
$ref: '#/definitions/handler.RespBody'
|
||||
security:
|
||||
- ApiKeyAuth: []
|
||||
summary: add question title like
|
||||
summary: fuzzy query similar questions based on title
|
||||
tags:
|
||||
- Question
|
||||
/answer/api/v1/question/similar/tag:
|
||||
|
@ -5312,6 +5395,28 @@ paths:
|
|||
summary: update tag
|
||||
tags:
|
||||
- Tag
|
||||
/answer/api/v1/tag/recover:
|
||||
post:
|
||||
consumes:
|
||||
- application/json
|
||||
description: recover delete tag
|
||||
parameters:
|
||||
- description: tag
|
||||
in: body
|
||||
name: data
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/schema.RecoverTagReq'
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
$ref: '#/definitions/handler.RespBody'
|
||||
summary: recover delete tag
|
||||
tags:
|
||||
- Tag
|
||||
/answer/api/v1/tag/synonym:
|
||||
put:
|
||||
consumes:
|
||||
|
|
|
@ -37,6 +37,8 @@ backend:
|
|||
other: List
|
||||
invite_someone_to_answer:
|
||||
other: Edit
|
||||
undelete:
|
||||
other: Undelete
|
||||
role:
|
||||
name:
|
||||
user:
|
||||
|
|
|
@ -90,6 +90,40 @@ func (ac *AnswerController) RemoveAnswer(ctx *gin.Context) {
|
|||
handler.HandleResponse(ctx, err, nil)
|
||||
}
|
||||
|
||||
// RecoverAnswer recover answer
|
||||
// @Summary recover answer
|
||||
// @Description recover deleted answer
|
||||
// @Tags Answer
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Security ApiKeyAuth
|
||||
// @Param data body schema.RecoverAnswerReq true "answer"
|
||||
// @Success 200 {object} handler.RespBody
|
||||
// @Router /answer/api/v1/answer/recover [post]
|
||||
func (ac *AnswerController) RecoverAnswer(ctx *gin.Context) {
|
||||
req := &schema.RecoverAnswerReq{}
|
||||
if handler.BindAndCheck(ctx, req) {
|
||||
return
|
||||
}
|
||||
req.AnswerID = uid.DeShortID(req.AnswerID)
|
||||
req.UserID = middleware.GetLoginUserIDFromContext(ctx)
|
||||
|
||||
canList, err := ac.rankService.CheckOperationPermissions(ctx, req.UserID, []string{
|
||||
permission.AnswerUnDelete,
|
||||
})
|
||||
if err != nil {
|
||||
handler.HandleResponse(ctx, err, nil)
|
||||
return
|
||||
}
|
||||
if !canList[0] {
|
||||
handler.HandleResponse(ctx, errors.Forbidden(reason.RankFailToMeetTheCondition), nil)
|
||||
return
|
||||
}
|
||||
|
||||
err = ac.answerService.RecoverAnswer(ctx, req)
|
||||
handler.HandleResponse(ctx, err, nil)
|
||||
}
|
||||
|
||||
// Get godoc
|
||||
// @Summary Get Answer
|
||||
// @Description Get Answer
|
||||
|
@ -196,7 +230,8 @@ func (ac *AnswerController) Add(ctx *gin.Context) {
|
|||
handler.HandleResponse(ctx, errors.Forbidden(reason.RankFailToMeetTheCondition), nil)
|
||||
return
|
||||
}
|
||||
info.MemberActions = permission.GetAnswerPermission(ctx, req.UserID, info.UserID, req.CanEdit, req.CanDelete)
|
||||
info.MemberActions = permission.GetAnswerPermission(ctx, req.UserID, info.UserID,
|
||||
0, req.CanEdit, req.CanDelete, false)
|
||||
handler.HandleResponse(ctx, nil, gin.H{
|
||||
"info": info,
|
||||
"question": questionInfo,
|
||||
|
@ -293,6 +328,7 @@ func (ac *AnswerController) AnswerList(ctx *gin.Context) {
|
|||
canList, err := ac.rankService.CheckOperationPermissions(ctx, req.UserID, []string{
|
||||
permission.AnswerEdit,
|
||||
permission.AnswerDelete,
|
||||
permission.AnswerUnDelete,
|
||||
})
|
||||
if err != nil {
|
||||
handler.HandleResponse(ctx, err, nil)
|
||||
|
@ -300,6 +336,7 @@ func (ac *AnswerController) AnswerList(ctx *gin.Context) {
|
|||
}
|
||||
req.CanEdit = canList[0]
|
||||
req.CanDelete = canList[1]
|
||||
req.CanRecover = canList[2]
|
||||
|
||||
list, count, err := ac.answerService.SearchList(ctx, req)
|
||||
if err != nil {
|
||||
|
@ -345,25 +382,24 @@ func (ac *AnswerController) Accepted(ctx *gin.Context) {
|
|||
handler.HandleResponse(ctx, err, nil)
|
||||
}
|
||||
|
||||
// AdminSetAnswerStatus godoc
|
||||
// @Summary AdminSetAnswerStatus
|
||||
// @Description Status:[available,deleted]
|
||||
// AdminUpdateAnswerStatus update answer status
|
||||
// @Summary update answer status
|
||||
// @Description update answer status
|
||||
// @Tags admin
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Security ApiKeyAuth
|
||||
// @Param data body schema.AdminSetAnswerStatusRequest true "AdminSetAnswerStatusRequest"
|
||||
// @Router /answer/admin/api/answer/status [put]
|
||||
// @Param data body schema.AdminUpdateAnswerStatusReq true "AdminUpdateAnswerStatusReq"
|
||||
// @Success 200 {object} handler.RespBody
|
||||
func (ac *AnswerController) AdminSetAnswerStatus(ctx *gin.Context) {
|
||||
req := &schema.AdminSetAnswerStatusRequest{}
|
||||
// @Router /answer/admin/api/answer/status [put]
|
||||
func (ac *AnswerController) AdminUpdateAnswerStatus(ctx *gin.Context) {
|
||||
req := &schema.AdminUpdateAnswerStatusReq{}
|
||||
if handler.BindAndCheck(ctx, req) {
|
||||
return
|
||||
}
|
||||
req.AnswerID = uid.DeShortID(req.AnswerID)
|
||||
|
||||
req.UserID = middleware.GetLoginUserIDFromContext(ctx)
|
||||
|
||||
err := ac.answerService.AdminSetAnswerStatus(ctx, req)
|
||||
handler.HandleResponse(ctx, err, gin.H{})
|
||||
handler.HandleResponse(ctx, err, nil)
|
||||
}
|
||||
|
|
|
@ -221,6 +221,7 @@ func (qc *QuestionController) GetQuestion(ctx *gin.Context) {
|
|||
permission.QuestionHide,
|
||||
permission.QuestionShow,
|
||||
permission.AnswerInviteSomeoneToAnswer,
|
||||
permission.QuestionUnDelete,
|
||||
})
|
||||
if err != nil {
|
||||
handler.HandleResponse(ctx, err, nil)
|
||||
|
@ -237,6 +238,7 @@ func (qc *QuestionController) GetQuestion(ctx *gin.Context) {
|
|||
req.CanHide = canList[6]
|
||||
req.CanShow = canList[7]
|
||||
req.CanInviteOtherToAnswer = canList[8]
|
||||
req.CanRecover = canList[9]
|
||||
|
||||
info, err := qc.questionService.GetQuestionAndAddPV(ctx, id, userID, req)
|
||||
if err != nil {
|
||||
|
@ -627,6 +629,40 @@ func (qc *QuestionController) UpdateQuestion(ctx *gin.Context) {
|
|||
handler.HandleResponse(ctx, nil, &schema.UpdateQuestionResp{WaitForReview: !req.NoNeedReview})
|
||||
}
|
||||
|
||||
// QuestionRecover recover deleted question
|
||||
// @Summary recover deleted question
|
||||
// @Description recover deleted question
|
||||
// @Tags Question
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Security ApiKeyAuth
|
||||
// @Param data body schema.QuestionRecoverReq true "question"
|
||||
// @Success 200 {object} handler.RespBody
|
||||
// @Router /answer/api/v1/question/recover [post]
|
||||
func (qc *QuestionController) QuestionRecover(ctx *gin.Context) {
|
||||
req := &schema.QuestionRecoverReq{}
|
||||
if handler.BindAndCheck(ctx, req) {
|
||||
return
|
||||
}
|
||||
req.QuestionID = uid.DeShortID(req.QuestionID)
|
||||
req.UserID = middleware.GetLoginUserIDFromContext(ctx)
|
||||
|
||||
canList, err := qc.rankService.CheckOperationPermissions(ctx, req.UserID, []string{
|
||||
permission.QuestionUnDelete,
|
||||
})
|
||||
if err != nil {
|
||||
handler.HandleResponse(ctx, err, nil)
|
||||
return
|
||||
}
|
||||
if !canList[0] {
|
||||
handler.HandleResponse(ctx, errors.Forbidden(reason.RankFailToMeetTheCondition), nil)
|
||||
return
|
||||
}
|
||||
|
||||
err = qc.questionService.RecoverQuestion(ctx, req)
|
||||
handler.HandleResponse(ctx, err, nil)
|
||||
}
|
||||
|
||||
// UpdateQuestionInviteUser update question invite user
|
||||
// @Summary update question invite user
|
||||
// @Description update question invite user
|
||||
|
@ -842,22 +878,24 @@ func (qc *QuestionController) AdminAnswerPage(ctx *gin.Context) {
|
|||
handler.HandleResponse(ctx, err, resp)
|
||||
}
|
||||
|
||||
// AdminSetQuestionStatus godoc
|
||||
// @Summary AdminSetQuestionStatus
|
||||
// @Description Status:[available,closed,deleted]
|
||||
// AdminUpdateQuestionStatus update question status
|
||||
// @Summary update question status
|
||||
// @Description update question status
|
||||
// @Tags admin
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Security ApiKeyAuth
|
||||
// @Param data body schema.AdminSetQuestionStatusRequest true "AdminSetQuestionStatusRequest"
|
||||
// @Router /answer/admin/api/question/status [put]
|
||||
// @Param data body schema.AdminUpdateQuestionStatusReq true "AdminUpdateQuestionStatusReq"
|
||||
// @Success 200 {object} handler.RespBody
|
||||
func (qc *QuestionController) AdminSetQuestionStatus(ctx *gin.Context) {
|
||||
req := &schema.AdminSetQuestionStatusRequest{}
|
||||
// @Router /answer/admin/api/question/status [put]
|
||||
func (qc *QuestionController) AdminUpdateQuestionStatus(ctx *gin.Context) {
|
||||
req := &schema.AdminUpdateQuestionStatusReq{}
|
||||
if handler.BindAndCheck(ctx, req) {
|
||||
return
|
||||
}
|
||||
req.QuestionID = uid.DeShortID(req.QuestionID)
|
||||
err := qc.questionService.AdminSetQuestionStatus(ctx, req.QuestionID, req.StatusStr)
|
||||
handler.HandleResponse(ctx, err, gin.H{})
|
||||
req.UserID = middleware.GetLoginUserIDFromContext(ctx)
|
||||
|
||||
err := qc.questionService.AdminSetQuestionStatus(ctx, req)
|
||||
handler.HandleResponse(ctx, err, nil)
|
||||
}
|
||||
|
|
|
@ -167,6 +167,38 @@ func (tc *TagController) UpdateTag(ctx *gin.Context) {
|
|||
}
|
||||
}
|
||||
|
||||
// RecoverTag recover delete tag
|
||||
// @Summary recover delete tag
|
||||
// @Description recover delete tag
|
||||
// @Tags Tag
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param data body schema.RecoverTagReq true "tag"
|
||||
// @Success 200 {object} handler.RespBody
|
||||
// @Router /answer/api/v1/tag/recover [post]
|
||||
func (tc *TagController) RecoverTag(ctx *gin.Context) {
|
||||
req := &schema.RecoverTagReq{}
|
||||
if handler.BindAndCheck(ctx, req) {
|
||||
return
|
||||
}
|
||||
req.UserID = middleware.GetLoginUserIDFromContext(ctx)
|
||||
|
||||
canList, err := tc.rankService.CheckOperationPermissions(ctx, req.UserID, []string{
|
||||
permission.TagUnDelete,
|
||||
})
|
||||
if err != nil {
|
||||
handler.HandleResponse(ctx, err, nil)
|
||||
return
|
||||
}
|
||||
if !canList[0] {
|
||||
handler.HandleResponse(ctx, errors.Forbidden(reason.RankFailToMeetTheCondition), nil)
|
||||
return
|
||||
}
|
||||
|
||||
err = tc.tagService.RecoverTag(ctx, req)
|
||||
handler.HandleResponse(ctx, err, nil)
|
||||
}
|
||||
|
||||
// GetTagInfo get tag one
|
||||
// @Summary get tag one
|
||||
// @Description get tag one
|
||||
|
@ -187,6 +219,7 @@ func (tc *TagController) GetTagInfo(ctx *gin.Context) {
|
|||
canList, err := tc.rankService.CheckOperationPermissions(ctx, req.UserID, []string{
|
||||
permission.TagEdit,
|
||||
permission.TagDelete,
|
||||
permission.TagUnDelete,
|
||||
})
|
||||
if err != nil {
|
||||
handler.HandleResponse(ctx, err, nil)
|
||||
|
@ -194,6 +227,7 @@ func (tc *TagController) GetTagInfo(ctx *gin.Context) {
|
|||
}
|
||||
req.CanEdit = canList[0]
|
||||
req.CanDelete = canList[1]
|
||||
req.CanRecover = canList[2]
|
||||
|
||||
resp, err := tc.tagService.GetTagInfo(ctx, req)
|
||||
handler.HandleResponse(ctx, err, resp)
|
||||
|
|
|
@ -7,6 +7,11 @@ const (
|
|||
TagStatusDeleted = 10
|
||||
)
|
||||
|
||||
var TagStatusDisplayMapping = map[int]string{
|
||||
TagStatusAvailable: "available",
|
||||
TagStatusDeleted: "deleted",
|
||||
}
|
||||
|
||||
// Tag tag
|
||||
type Tag struct {
|
||||
ID string `xorm:"not null pk comment('tag_id') BIGINT(20) id"`
|
||||
|
|
|
@ -95,6 +95,9 @@ var (
|
|||
{ID: 36, Name: "question unpin", PowerType: permission.QuestionUnPin, Description: "untop the question"},
|
||||
{ID: 37, Name: "question show", PowerType: permission.QuestionShow, Description: "show the question"},
|
||||
{ID: 38, Name: "invite someone to answer", PowerType: permission.AnswerInviteSomeoneToAnswer, Description: "invite someone to answer"},
|
||||
{ID: 39, Name: "recover answer", PowerType: permission.AnswerUnDelete, Description: "recover deleted answer"},
|
||||
{ID: 40, Name: "recover question", PowerType: permission.QuestionUnDelete, Description: "recover deleted question"},
|
||||
{ID: 41, Name: "recover tag", PowerType: permission.TagUnDelete, Description: "recover deleted tag"},
|
||||
}
|
||||
|
||||
rolePowerRels = []*entity.RolePowerRel{
|
||||
|
@ -137,6 +140,9 @@ var (
|
|||
{RoleID: 2, PowerType: permission.QuestionUnPin},
|
||||
{RoleID: 2, PowerType: permission.QuestionShow},
|
||||
{RoleID: 2, PowerType: permission.AnswerInviteSomeoneToAnswer},
|
||||
{RoleID: 2, PowerType: permission.AnswerUnDelete},
|
||||
{RoleID: 2, PowerType: permission.QuestionUnDelete},
|
||||
{RoleID: 2, PowerType: permission.TagUnDelete},
|
||||
|
||||
{RoleID: 3, PowerType: permission.QuestionAdd},
|
||||
{RoleID: 3, PowerType: permission.QuestionEdit},
|
||||
|
@ -176,6 +182,9 @@ var (
|
|||
{RoleID: 3, PowerType: permission.QuestionUnPin},
|
||||
{RoleID: 3, PowerType: permission.QuestionShow},
|
||||
{RoleID: 3, PowerType: permission.AnswerInviteSomeoneToAnswer},
|
||||
{RoleID: 3, PowerType: permission.AnswerUnDelete},
|
||||
{RoleID: 3, PowerType: permission.QuestionUnDelete},
|
||||
{RoleID: 3, PowerType: permission.TagUnDelete},
|
||||
}
|
||||
|
||||
adminUserRoleRel = &entity.UserRoleRel{
|
||||
|
@ -310,5 +319,8 @@ var (
|
|||
{ID: 125, Key: "rank.question.show", Value: `-1`},
|
||||
{ID: 126, Key: "rank.question.hide", Value: `-1`},
|
||||
{ID: 127, Key: "rank.answer.invite_someone_to_answer", Value: `1000`},
|
||||
{ID: 128, Key: "rank.answer.undeleted", Value: `-1`},
|
||||
{ID: 129, Key: "rank.question.undeleted", Value: `-1`},
|
||||
{ID: 130, Key: "rank.tag.undeleted", Value: `-1`},
|
||||
}
|
||||
)
|
||||
|
|
|
@ -73,6 +73,7 @@ var migrations = []Migration{
|
|||
NewMigration("v1.1.1", "update the length of revision content", updateTheLengthOfRevisionContent, false),
|
||||
NewMigration("v1.1.2", "add notification config", addNoticeConfig, true),
|
||||
NewMigration("v1.1.3", "set default user notification config", setDefaultUserNotificationConfig, false),
|
||||
NewMigration("v1.2.0", "add recover answer permission", addRecoverPermission, false),
|
||||
}
|
||||
|
||||
func GetMigrations() []Migration {
|
||||
|
|
|
@ -0,0 +1,79 @@
|
|||
package migrations
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/answerdev/answer/internal/entity"
|
||||
"github.com/answerdev/answer/internal/service/permission"
|
||||
"github.com/segmentfault/pacman/log"
|
||||
"xorm.io/xorm"
|
||||
)
|
||||
|
||||
func addRecoverPermission(ctx context.Context, x *xorm.Engine) error {
|
||||
powers := []*entity.Power{
|
||||
{ID: 39, Name: "recover answer", PowerType: permission.AnswerUnDelete, Description: "recover deleted answer"},
|
||||
{ID: 40, Name: "recover question", PowerType: permission.QuestionUnDelete, Description: "recover deleted question"},
|
||||
{ID: 41, Name: "recover tag", PowerType: permission.TagUnDelete, Description: "recover deleted tag"},
|
||||
}
|
||||
for _, power := range powers {
|
||||
exist, err := x.Context(ctx).Get(&entity.Power{ID: power.ID})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if exist {
|
||||
_, err = x.Context(ctx).ID(power.ID).Update(power)
|
||||
} else {
|
||||
_, err = x.Context(ctx).Insert(power)
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
rolePowerRels := []*entity.RolePowerRel{
|
||||
{RoleID: 2, PowerType: permission.AnswerUnDelete},
|
||||
{RoleID: 2, PowerType: permission.QuestionUnDelete},
|
||||
{RoleID: 2, PowerType: permission.TagUnDelete},
|
||||
|
||||
{RoleID: 3, PowerType: permission.AnswerUnDelete},
|
||||
{RoleID: 3, PowerType: permission.QuestionUnDelete},
|
||||
{RoleID: 3, PowerType: permission.TagUnDelete},
|
||||
}
|
||||
for _, rel := range rolePowerRels {
|
||||
exist, err := x.Context(ctx).Get(&entity.RolePowerRel{RoleID: rel.RoleID, PowerType: rel.PowerType})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if exist {
|
||||
continue
|
||||
}
|
||||
_, err = x.Context(ctx).Insert(rel)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
defaultConfigTable := []*entity.Config{
|
||||
{ID: 128, Key: "rank.answer.undeleted", Value: `-1`},
|
||||
{ID: 129, Key: "rank.question.undeleted", Value: `-1`},
|
||||
{ID: 130, Key: "rank.tag.undeleted", Value: `-1`},
|
||||
}
|
||||
for _, c := range defaultConfigTable {
|
||||
exist, err := x.Context(ctx).Get(&entity.Config{ID: c.ID})
|
||||
if err != nil {
|
||||
return fmt.Errorf("get config failed: %w", err)
|
||||
}
|
||||
if exist {
|
||||
if _, err = x.Context(ctx).Update(c, &entity.Config{ID: c.ID}); err != nil {
|
||||
log.Errorf("update %+v config failed: %s", c, err)
|
||||
return fmt.Errorf("update config failed: %w", err)
|
||||
}
|
||||
continue
|
||||
}
|
||||
if _, err = x.Context(ctx).Insert(&entity.Config{ID: c.ID, Key: c.Key, Value: c.Value}); err != nil {
|
||||
log.Errorf("insert %+v config failed: %s", c, err)
|
||||
return fmt.Errorf("add config failed: %w", err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
|
@ -66,17 +66,28 @@ func (ar *answerRepo) AddAnswer(ctx context.Context, answer *entity.Answer) (err
|
|||
}
|
||||
|
||||
// RemoveAnswer delete answer
|
||||
func (ar *answerRepo) RemoveAnswer(ctx context.Context, id string) (err error) {
|
||||
id = uid.DeShortID(id)
|
||||
answer := &entity.Answer{
|
||||
ID: id,
|
||||
func (ar *answerRepo) RemoveAnswer(ctx context.Context, answerID string) (err error) {
|
||||
answerID = uid.DeShortID(answerID)
|
||||
_, err = ar.data.DB.Context(ctx).ID(answerID).Cols("status").Update(&entity.Answer{
|
||||
Status: entity.AnswerStatusDeleted,
|
||||
}
|
||||
_, err = ar.data.DB.Context(ctx).Where("id = ?", id).Cols("status").Update(answer)
|
||||
})
|
||||
if err != nil {
|
||||
return errors.InternalServer(reason.DatabaseError).WithError(err).WithStack()
|
||||
}
|
||||
_ = ar.updateSearch(ctx, answer.ID)
|
||||
_ = ar.updateSearch(ctx, answerID)
|
||||
return nil
|
||||
}
|
||||
|
||||
// RecoverAnswer recover answer
|
||||
func (ar *answerRepo) RecoverAnswer(ctx context.Context, answerID string) (err error) {
|
||||
answerID = uid.DeShortID(answerID)
|
||||
_, err = ar.data.DB.Context(ctx).ID(answerID).Cols("status").Update(&entity.Answer{
|
||||
Status: entity.AnswerStatusAvailable,
|
||||
})
|
||||
if err != nil {
|
||||
return errors.InternalServer(reason.DatabaseError).WithError(err).WithStack()
|
||||
}
|
||||
_ = ar.updateSearch(ctx, answerID)
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -226,10 +237,10 @@ func (ar *answerRepo) UpdateAcceptedStatus(ctx context.Context, acceptedAnswerID
|
|||
}
|
||||
|
||||
// GetByID
|
||||
func (ar *answerRepo) GetByID(ctx context.Context, id string) (*entity.Answer, bool, error) {
|
||||
func (ar *answerRepo) GetByID(ctx context.Context, answerID string) (*entity.Answer, bool, error) {
|
||||
var resp entity.Answer
|
||||
id = uid.DeShortID(id)
|
||||
has, err := ar.data.DB.Context(ctx).Where("id =? ", id).Get(&resp)
|
||||
answerID = uid.DeShortID(answerID)
|
||||
has, err := ar.data.DB.Context(ctx).ID(answerID).Get(&resp)
|
||||
if err != nil {
|
||||
return &resp, false, errors.InternalServer(reason.DatabaseError).WithError(err).WithStack()
|
||||
}
|
||||
|
|
|
@ -138,6 +138,16 @@ func (qr *questionRepo) UpdateQuestionStatusWithOutUpdateTime(ctx context.Contex
|
|||
return nil
|
||||
}
|
||||
|
||||
func (qr *questionRepo) RecoverQuestion(ctx context.Context, questionID string) (err error) {
|
||||
questionID = uid.DeShortID(questionID)
|
||||
_, err = qr.data.DB.Context(ctx).ID(questionID).Cols("status").Update(&entity.Question{Status: entity.QuestionStatusAvailable})
|
||||
if err != nil {
|
||||
return errors.InternalServer(reason.DatabaseError).WithError(err).WithStack()
|
||||
}
|
||||
_ = qr.updateSearch(ctx, questionID)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (qr *questionRepo) UpdateQuestionOperation(ctx context.Context, question *entity.Question) (err error) {
|
||||
question.ID = uid.DeShortID(question.ID)
|
||||
_, err = qr.data.DB.Context(ctx).Where("id =?", question.ID).Cols("pin", "show").Update(question)
|
||||
|
|
|
@ -54,6 +54,16 @@ func (tr *tagRelRepo) RemoveTagRelListByObjectID(ctx context.Context, objectID s
|
|||
return
|
||||
}
|
||||
|
||||
// RecoverTagRelListByObjectID recover tag list
|
||||
func (tr *tagRelRepo) RecoverTagRelListByObjectID(ctx context.Context, objectID string) (err error) {
|
||||
objectID = uid.DeShortID(objectID)
|
||||
_, err = tr.data.DB.Context(ctx).Where("object_id = ?", objectID).Update(&entity.TagRel{Status: entity.TagRelStatusAvailable})
|
||||
if err != nil {
|
||||
err = errors.InternalServer(reason.DatabaseError).WithError(err).WithStack()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (tr *tagRelRepo) HideTagRelListByObjectID(ctx context.Context, objectID string) (err error) {
|
||||
objectID = uid.DeShortID(objectID)
|
||||
_, err = tr.data.DB.Context(ctx).Where("object_id = ?", objectID).Cols("status").Update(&entity.TagRel{Status: entity.TagRelStatusHide})
|
||||
|
|
|
@ -2,7 +2,6 @@ package tag
|
|||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/answerdev/answer/internal/base/data"
|
||||
"github.com/answerdev/answer/internal/base/reason"
|
||||
"github.com/answerdev/answer/internal/entity"
|
||||
|
@ -49,6 +48,36 @@ func (tr *tagRepo) UpdateTag(ctx context.Context, tag *entity.Tag) (err error) {
|
|||
return
|
||||
}
|
||||
|
||||
// RecoverTag recover deleted tag
|
||||
func (tr *tagRepo) RecoverTag(ctx context.Context, tagID string) (err error) {
|
||||
_, err = tr.data.DB.Context(ctx).ID(tagID).Update(&entity.Tag{Status: entity.TagStatusAvailable})
|
||||
if err != nil {
|
||||
err = errors.InternalServer(reason.DatabaseError).WithError(err).WithStack()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// MustGetTagByID get tag by id
|
||||
func (tr *tagRepo) MustGetTagByNameOrID(ctx context.Context, tagID, slugName string) (
|
||||
tag *entity.Tag, exist bool, err error) {
|
||||
if len(tagID) == 0 && len(slugName) == 0 {
|
||||
return nil, false, nil
|
||||
}
|
||||
tag = &entity.Tag{}
|
||||
session := tr.data.DB.Context(ctx)
|
||||
if len(tagID) > 0 {
|
||||
session.ID(tagID)
|
||||
}
|
||||
if len(slugName) > 0 {
|
||||
session.Where(builder.Eq{"slug_name": slugName})
|
||||
}
|
||||
exist, err = session.Get(tag)
|
||||
if err != nil {
|
||||
return nil, false, errors.InternalServer(reason.DatabaseError).WithError(err).WithStack()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// UpdateTagSynonym update synonym tag
|
||||
func (tr *tagRepo) UpdateTagSynonym(ctx context.Context, tagSlugNameList []string, mainTagID int64,
|
||||
mainTagSlugName string,
|
||||
|
|
|
@ -187,6 +187,7 @@ func (a *AnswerAPIRouter) RegisterAnswerAPIRouter(r *gin.RouterGroup) {
|
|||
r.GET("/question/tags", a.tagController.SearchTagLike)
|
||||
r.POST("/tag", a.tagController.AddTag)
|
||||
r.PUT("/tag", a.tagController.UpdateTag)
|
||||
r.POST("/tag/recover", a.tagController.RecoverTag)
|
||||
r.DELETE("/tag", a.tagController.RemoveTag)
|
||||
r.PUT("/tag/synonym", a.tagController.UpdateTagSynonym)
|
||||
|
||||
|
@ -204,12 +205,14 @@ func (a *AnswerAPIRouter) RegisterAnswerAPIRouter(r *gin.RouterGroup) {
|
|||
r.PUT("/question/operation", a.questionController.OperationQuestion)
|
||||
r.PUT("/question/reopen", a.questionController.ReopenQuestion)
|
||||
r.GET("/question/similar", a.questionController.GetSimilarQuestions)
|
||||
r.POST("/question/recover", a.questionController.QuestionRecover)
|
||||
|
||||
// answer
|
||||
r.POST("/answer", a.answerController.Add)
|
||||
r.PUT("/answer", a.answerController.Update)
|
||||
r.POST("/answer/acceptance", a.answerController.Accepted)
|
||||
r.DELETE("/answer", a.answerController.RemoveAnswer)
|
||||
r.POST("/answer/recover", a.answerController.RecoverAnswer)
|
||||
|
||||
// user
|
||||
r.PUT("/user/password", middleware.BanAPIForUserCenter, a.userController.UserModifyPassWord)
|
||||
|
@ -247,9 +250,9 @@ func (a *AnswerAPIRouter) RegisterAnswerAPIRouter(r *gin.RouterGroup) {
|
|||
|
||||
func (a *AnswerAPIRouter) RegisterAnswerAdminAPIRouter(r *gin.RouterGroup) {
|
||||
r.GET("/question/page", a.questionController.AdminQuestionPage)
|
||||
r.PUT("/question/status", a.questionController.AdminSetQuestionStatus)
|
||||
r.PUT("/question/status", a.questionController.AdminUpdateQuestionStatus)
|
||||
r.GET("/answer/page", a.questionController.AdminAnswerPage)
|
||||
r.PUT("/answer/status", a.answerController.AdminSetAnswerStatus)
|
||||
r.PUT("/answer/status", a.answerController.AdminUpdateAnswerStatus)
|
||||
|
||||
// report
|
||||
r.GET("/reports/page", a.adminReportController.ListReportPage)
|
||||
|
|
|
@ -14,6 +14,12 @@ type RemoveAnswerReq struct {
|
|||
CaptchaCode string `json:"captcha_code"`
|
||||
}
|
||||
|
||||
// RecoverAnswerReq recover answer request
|
||||
type RecoverAnswerReq struct {
|
||||
AnswerID string `validate:"required" json:"answer_id"`
|
||||
UserID string `json:"-"`
|
||||
}
|
||||
|
||||
const (
|
||||
AnswerAcceptedFailed = 1
|
||||
AnswerAcceptedEnable = 2
|
||||
|
@ -26,6 +32,7 @@ type AnswerAddReq struct {
|
|||
UserID string `json:"-"`
|
||||
CanEdit bool `json:"-"`
|
||||
CanDelete bool `json:"-"`
|
||||
CanRecover bool `json:"-"`
|
||||
CaptchaID string `json:"captcha_id"`
|
||||
CaptchaCode string `json:"captcha_code"`
|
||||
}
|
||||
|
@ -68,6 +75,7 @@ type AnswerListReq struct {
|
|||
IsAdmin bool `json:"-"`
|
||||
CanEdit bool `json:"-"`
|
||||
CanDelete bool `json:"-"`
|
||||
CanRecover bool `json:"-"`
|
||||
}
|
||||
|
||||
type AnswerInfo struct {
|
||||
|
@ -121,8 +129,8 @@ func (req *AcceptAnswerReq) Check() (errFields []*validator.FormErrorField, err
|
|||
return nil, nil
|
||||
}
|
||||
|
||||
type AdminSetAnswerStatusRequest struct {
|
||||
StatusStr string `json:"status"`
|
||||
AnswerID string `json:"answer_id"`
|
||||
UserID string `json:"-"`
|
||||
type AdminUpdateAnswerStatusReq struct {
|
||||
AnswerID string `validate:"required" json:"answer_id"`
|
||||
Status string `validate:"required,oneof=available deleted" json:"status"`
|
||||
UserID string `json:"-"`
|
||||
}
|
||||
|
|
|
@ -131,6 +131,7 @@ type QuestionPermission struct {
|
|||
// whether user can invite other user to answer this question
|
||||
CanInviteOtherToAnswer bool `json:"-"`
|
||||
CanAddTag bool `json:"-"`
|
||||
CanRecover bool `json:"-"`
|
||||
}
|
||||
|
||||
type CheckCanQuestionUpdate struct {
|
||||
|
@ -163,6 +164,11 @@ type QuestionUpdate struct {
|
|||
CaptchaCode string `json:"captcha_code"`
|
||||
}
|
||||
|
||||
type QuestionRecoverReq struct {
|
||||
QuestionID string `validate:"required" json:"question_id"`
|
||||
UserID string `json:"-"`
|
||||
}
|
||||
|
||||
type QuestionUpdateInviteUser struct {
|
||||
ID string `validate:"required" json:"id"`
|
||||
InviteUser []string `validate:"omitempty" json:"invite_user"`
|
||||
|
@ -430,9 +436,10 @@ func (req *AdminAnswerPageReq) Check() (errField []*validator.FormErrorField, er
|
|||
return nil, nil
|
||||
}
|
||||
|
||||
type AdminSetQuestionStatusRequest struct {
|
||||
StatusStr string `json:"status" form:"status"`
|
||||
QuestionID string `json:"question_id" form:"question_id"`
|
||||
type AdminUpdateQuestionStatusReq struct {
|
||||
QuestionID string `validate:"required" json:"question_id"`
|
||||
Status string `validate:"required,oneof=available closed deleted" json:"status"`
|
||||
UserID string `json:"-"`
|
||||
}
|
||||
|
||||
type PersonalQuestionPageReq struct {
|
||||
|
|
|
@ -3,10 +3,8 @@ package schema
|
|||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/answerdev/answer/internal/base/reason"
|
||||
"github.com/answerdev/answer/internal/base/validator"
|
||||
"github.com/answerdev/answer/pkg/converter"
|
||||
"github.com/segmentfault/pacman/errors"
|
||||
)
|
||||
|
||||
// SearchTagLikeReq get tag list all request
|
||||
|
@ -27,13 +25,11 @@ type GetTagInfoReq struct {
|
|||
// tag id
|
||||
ID string `validate:"omitempty" form:"id"`
|
||||
// tag slug name
|
||||
Name string `validate:"omitempty,gt=0,lte=35" form:"name"`
|
||||
// user id
|
||||
UserID string `json:"-"`
|
||||
// whether user can edit it
|
||||
CanEdit bool `json:"-"`
|
||||
// whether user can delete it
|
||||
CanDelete bool `json:"-"`
|
||||
Name string `validate:"omitempty,gt=0,lte=35" form:"name"`
|
||||
UserID string `json:"-"`
|
||||
CanEdit bool `json:"-"`
|
||||
CanDelete bool `json:"-"`
|
||||
CanRecover bool `json:"-"`
|
||||
}
|
||||
|
||||
type GetTamplateTagInfoReq struct {
|
||||
|
@ -48,40 +44,25 @@ type GetTamplateTagInfoReq struct {
|
|||
}
|
||||
|
||||
func (r *GetTagInfoReq) Check() (errFields []*validator.FormErrorField, err error) {
|
||||
if len(r.ID) == 0 && len(r.Name) == 0 {
|
||||
return nil, errors.BadRequest(reason.RequestFormatError)
|
||||
}
|
||||
r.Name = strings.ToLower(r.Name)
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// GetTagResp get tag response
|
||||
type GetTagResp struct {
|
||||
// tag id
|
||||
TagID string `json:"tag_id"`
|
||||
// created time
|
||||
CreatedAt int64 `json:"created_at"`
|
||||
// updated time
|
||||
UpdatedAt int64 `json:"updated_at"`
|
||||
// slug name
|
||||
SlugName string `json:"slug_name"`
|
||||
// display name
|
||||
DisplayName string `json:"display_name"`
|
||||
// excerpt
|
||||
Excerpt string `json:"excerpt"`
|
||||
// original text
|
||||
OriginalText string `json:"original_text"`
|
||||
// parsed text
|
||||
ParsedText string `json:"parsed_text"`
|
||||
// description text
|
||||
Description string `json:"description"`
|
||||
// follower amount
|
||||
FollowCount int `json:"follow_count"`
|
||||
// question amount
|
||||
QuestionCount int `json:"question_count"`
|
||||
// is follower
|
||||
IsFollower bool `json:"is_follower"`
|
||||
// MemberActions
|
||||
TagID string `json:"tag_id"`
|
||||
CreatedAt int64 `json:"created_at"`
|
||||
UpdatedAt int64 `json:"updated_at"`
|
||||
SlugName string `json:"slug_name"`
|
||||
DisplayName string `json:"display_name"`
|
||||
Excerpt string `json:"excerpt"`
|
||||
OriginalText string `json:"original_text"`
|
||||
ParsedText string `json:"parsed_text"`
|
||||
Description string `json:"description"`
|
||||
FollowCount int `json:"follow_count"`
|
||||
QuestionCount int `json:"question_count"`
|
||||
IsFollower bool `json:"is_follower"`
|
||||
Status string `json:"status"`
|
||||
MemberActions []*PermissionMemberAction `json:"member_actions"`
|
||||
// if main tag slug name is not empty, this tag is synonymous with the main tag
|
||||
MainTagSlugName string `json:"main_tag_slug_name"`
|
||||
|
@ -212,6 +193,12 @@ func (r *UpdateTagReq) Check() (errFields []*validator.FormErrorField, err error
|
|||
return nil, nil
|
||||
}
|
||||
|
||||
// RecoverTagReq update tag request
|
||||
type RecoverTagReq struct {
|
||||
TagID string `validate:"required" json:"tag_id"`
|
||||
UserID string `json:"-"`
|
||||
}
|
||||
|
||||
// UpdateTagResp update tag response
|
||||
type UpdateTagResp struct {
|
||||
WaitForReview bool `json:"wait_for_review"`
|
||||
|
|
|
@ -13,12 +13,13 @@ import (
|
|||
type AnswerRepo interface {
|
||||
AddAnswer(ctx context.Context, answer *entity.Answer) (err error)
|
||||
RemoveAnswer(ctx context.Context, id string) (err error)
|
||||
RecoverAnswer(ctx context.Context, answerID string) (err error)
|
||||
UpdateAnswer(ctx context.Context, answer *entity.Answer, cols []string) (err error)
|
||||
GetAnswer(ctx context.Context, id string) (answer *entity.Answer, exist bool, err error)
|
||||
GetAnswerList(ctx context.Context, answer *entity.Answer) (answerList []*entity.Answer, err error)
|
||||
GetAnswerPage(ctx context.Context, page, pageSize int, answer *entity.Answer) (answerList []*entity.Answer, total int64, err error)
|
||||
UpdateAcceptedStatus(ctx context.Context, acceptedAnswerID string, questionID string) error
|
||||
GetByID(ctx context.Context, id string) (*entity.Answer, bool, error)
|
||||
GetByID(ctx context.Context, answerID string) (*entity.Answer, bool, error)
|
||||
GetCountByQuestionID(ctx context.Context, questionID string) (int64, error)
|
||||
GetCountByUserID(ctx context.Context, userID string) (int64, error)
|
||||
GetByUserIDQuestionID(ctx context.Context, userID string, questionID string) (*entity.Answer, bool, error)
|
||||
|
|
|
@ -3,7 +3,7 @@ package service
|
|||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/answerdev/answer/pkg/converter"
|
||||
"github.com/answerdev/answer/pkg/token"
|
||||
"time"
|
||||
|
||||
|
@ -153,6 +153,44 @@ func (as *AnswerService) RemoveAnswer(ctx context.Context, req *schema.RemoveAns
|
|||
return
|
||||
}
|
||||
|
||||
// RecoverAnswer recover deleted answer
|
||||
func (as *AnswerService) RecoverAnswer(ctx context.Context, req *schema.RecoverAnswerReq) (err error) {
|
||||
answerInfo, exist, err := as.answerRepo.GetByID(ctx, req.AnswerID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !exist {
|
||||
return errors.BadRequest(reason.AnswerNotFound)
|
||||
}
|
||||
if answerInfo.Status != entity.AnswerStatusDeleted {
|
||||
return nil
|
||||
}
|
||||
if err = as.answerRepo.RecoverAnswer(ctx, req.AnswerID); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err = as.questionCommon.UpdateAnswerCount(ctx, answerInfo.QuestionID); err != nil {
|
||||
log.Errorf("update answer count failed: %s", err.Error())
|
||||
}
|
||||
userAnswerCount, err := as.answerRepo.GetCountByUserID(ctx, answerInfo.UserID)
|
||||
if err != nil {
|
||||
log.Errorf("get user answer count failed: %s", err.Error())
|
||||
} else {
|
||||
err = as.userCommon.UpdateAnswerCount(ctx, answerInfo.UserID, int(userAnswerCount))
|
||||
if err != nil {
|
||||
log.Errorf("update user answer count failed: %s", err.Error())
|
||||
}
|
||||
}
|
||||
as.activityQueueService.Send(ctx, &schema.ActivityMsg{
|
||||
UserID: req.UserID,
|
||||
TriggerUserID: converter.StringToInt64(req.UserID),
|
||||
ObjectID: answerInfo.ID,
|
||||
OriginalObjectID: answerInfo.ID,
|
||||
ActivityTypeKey: constant.ActAnswerUndeleted,
|
||||
})
|
||||
return nil
|
||||
}
|
||||
|
||||
func (as *AnswerService) Insert(ctx context.Context, req *schema.AnswerAddReq) (string, error) {
|
||||
questionInfo, exist, err := as.questionRepo.GetQuestion(ctx, req.QuestionID)
|
||||
if err != nil {
|
||||
|
@ -438,20 +476,19 @@ func (as *AnswerService) Get(ctx context.Context, answerID, loginUserID string)
|
|||
return info, questionInfo, has, nil
|
||||
}
|
||||
|
||||
func (as *AnswerService) AdminSetAnswerStatus(ctx context.Context, req *schema.AdminSetAnswerStatusRequest) error {
|
||||
setStatus, ok := entity.AdminAnswerSearchStatus[req.StatusStr]
|
||||
func (as *AnswerService) AdminSetAnswerStatus(ctx context.Context, req *schema.AdminUpdateAnswerStatusReq) error {
|
||||
setStatus, ok := entity.AdminAnswerSearchStatus[req.Status]
|
||||
if !ok {
|
||||
return fmt.Errorf("question status does not exist")
|
||||
return errors.BadRequest(reason.RequestFormatError)
|
||||
}
|
||||
answerInfo, exist, err := as.answerRepo.GetAnswer(ctx, req.AnswerID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !exist {
|
||||
return fmt.Errorf("answer does not exist")
|
||||
return errors.BadRequest(reason.AnswerNotFound)
|
||||
}
|
||||
answerInfo.Status = setStatus
|
||||
err = as.answerRepo.UpdateAnswerStatus(ctx, req.AnswerID, setStatus)
|
||||
err = as.answerRepo.UpdateAnswerStatus(ctx, answerInfo.ID, setStatus)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -469,17 +506,27 @@ func (as *AnswerService) AdminSetAnswerStatus(ctx context.Context, req *schema.A
|
|||
OriginalObjectID: answerInfo.ID,
|
||||
ActivityTypeKey: constant.ActAnswerDeleted,
|
||||
})
|
||||
|
||||
msg := &schema.NotificationMsg{}
|
||||
msg.ObjectID = answerInfo.ID
|
||||
msg.Type = schema.NotificationTypeInbox
|
||||
msg.ReceiverUserID = answerInfo.UserID
|
||||
msg.TriggerUserID = answerInfo.UserID
|
||||
msg.ObjectType = constant.AnswerObjectType
|
||||
msg.NotificationAction = constant.NotificationYourAnswerWasDeleted
|
||||
as.notificationQueueService.Send(ctx, msg)
|
||||
}
|
||||
|
||||
msg := &schema.NotificationMsg{}
|
||||
msg.ObjectID = answerInfo.ID
|
||||
msg.Type = schema.NotificationTypeInbox
|
||||
msg.ReceiverUserID = answerInfo.UserID
|
||||
msg.TriggerUserID = answerInfo.UserID
|
||||
msg.ObjectType = constant.AnswerObjectType
|
||||
msg.NotificationAction = constant.NotificationYourAnswerWasDeleted
|
||||
as.notificationQueueService.Send(ctx, msg)
|
||||
|
||||
// recover
|
||||
if setStatus == entity.QuestionStatusAvailable && answerInfo.Status == entity.QuestionStatusDeleted {
|
||||
as.activityQueueService.Send(ctx, &schema.ActivityMsg{
|
||||
UserID: req.UserID,
|
||||
TriggerUserID: converter.StringToInt64(req.UserID),
|
||||
ObjectID: answerInfo.ID,
|
||||
OriginalObjectID: answerInfo.ID,
|
||||
ActivityTypeKey: constant.ActAnswerUndeleted,
|
||||
})
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -534,7 +581,13 @@ func (as *AnswerService) SearchFormatInfo(ctx context.Context, answers []*entity
|
|||
for _, item := range list {
|
||||
item.VoteStatus = as.voteRepo.GetVoteStatus(ctx, item.ID, req.UserID)
|
||||
item.Collected = collectedMap[item.ID]
|
||||
item.MemberActions = permission.GetAnswerPermission(ctx, req.UserID, item.UserID, req.CanEdit, req.CanDelete)
|
||||
item.MemberActions = permission.GetAnswerPermission(ctx,
|
||||
req.UserID,
|
||||
item.UserID,
|
||||
item.Status,
|
||||
req.CanEdit,
|
||||
req.CanDelete,
|
||||
req.CanRecover)
|
||||
}
|
||||
return list, nil
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ package permission
|
|||
|
||||
import (
|
||||
"context"
|
||||
"github.com/answerdev/answer/internal/entity"
|
||||
|
||||
"github.com/answerdev/answer/internal/base/handler"
|
||||
"github.com/answerdev/answer/internal/base/translator"
|
||||
|
@ -9,7 +10,8 @@ import (
|
|||
)
|
||||
|
||||
// GetAnswerPermission get answer permission
|
||||
func GetAnswerPermission(ctx context.Context, userID string, creatorUserID string, canEdit, canDelete bool) (
|
||||
func GetAnswerPermission(ctx context.Context, userID, creatorUserID string,
|
||||
status int, canEdit, canDelete, canRecover bool) (
|
||||
actions []*schema.PermissionMemberAction) {
|
||||
lang := handler.GetLangByCtx(ctx)
|
||||
actions = make([]*schema.PermissionMemberAction, 0)
|
||||
|
@ -28,12 +30,20 @@ func GetAnswerPermission(ctx context.Context, userID string, creatorUserID strin
|
|||
})
|
||||
}
|
||||
|
||||
if canDelete || userID == creatorUserID {
|
||||
if (canDelete || userID == creatorUserID) && status != entity.AnswerStatusDeleted {
|
||||
actions = append(actions, &schema.PermissionMemberAction{
|
||||
Action: "delete",
|
||||
Name: translator.Tr(lang, deleteActionName),
|
||||
Type: "confirm",
|
||||
})
|
||||
}
|
||||
|
||||
if canRecover && status == entity.AnswerStatusDeleted {
|
||||
actions = append(actions, &schema.PermissionMemberAction{
|
||||
Action: "undelete",
|
||||
Name: translator.Tr(lang, undeleteActionName),
|
||||
Type: "confirm",
|
||||
})
|
||||
}
|
||||
return actions
|
||||
}
|
||||
|
|
|
@ -40,12 +40,16 @@ const (
|
|||
QuestionAudit = "question.audit"
|
||||
TagAudit = "tag.audit"
|
||||
TagUseReservedTag = "tag.use_reserved_tag"
|
||||
AnswerUnDelete = "answer.undeleted"
|
||||
QuestionUnDelete = "question.undeleted"
|
||||
TagUnDelete = "tag.undeleted"
|
||||
)
|
||||
|
||||
const (
|
||||
reportActionName = "action.report"
|
||||
editActionName = "action.edit"
|
||||
deleteActionName = "action.delete"
|
||||
undeleteActionName = "action.undelete"
|
||||
closeActionName = "action.close"
|
||||
reopenActionName = "action.reopen"
|
||||
pinActionName = "action.pin"
|
||||
|
|
|
@ -2,6 +2,7 @@ package permission
|
|||
|
||||
import (
|
||||
"context"
|
||||
"github.com/answerdev/answer/internal/entity"
|
||||
|
||||
"github.com/answerdev/answer/internal/base/handler"
|
||||
"github.com/answerdev/answer/internal/base/translator"
|
||||
|
@ -9,8 +10,8 @@ import (
|
|||
)
|
||||
|
||||
// GetQuestionPermission get question permission
|
||||
func GetQuestionPermission(ctx context.Context, userID string, creatorUserID string,
|
||||
canEdit, canDelete, canClose, canReopen, canPin, canHide, CanUnPin, canShow bool) (
|
||||
func GetQuestionPermission(ctx context.Context, userID string, creatorUserID string, status int,
|
||||
canEdit, canDelete, canClose, canReopen, canPin, canHide, canUnPin, canShow, canRecover bool) (
|
||||
actions []*schema.PermissionMemberAction) {
|
||||
lang := handler.GetLangByCtx(ctx)
|
||||
actions = make([]*schema.PermissionMemberAction, 0)
|
||||
|
@ -21,14 +22,14 @@ func GetQuestionPermission(ctx context.Context, userID string, creatorUserID str
|
|||
Type: "reason",
|
||||
})
|
||||
}
|
||||
if canEdit || userID == creatorUserID {
|
||||
if (canEdit || userID == creatorUserID) && status != entity.QuestionStatusDeleted {
|
||||
actions = append(actions, &schema.PermissionMemberAction{
|
||||
Action: "edit",
|
||||
Name: translator.Tr(lang, editActionName),
|
||||
Type: "edit",
|
||||
})
|
||||
}
|
||||
if canClose {
|
||||
if canClose && status == entity.QuestionStatusAvailable {
|
||||
actions = append(actions, &schema.PermissionMemberAction{
|
||||
Action: "close",
|
||||
Name: translator.Tr(lang, closeActionName),
|
||||
|
@ -57,7 +58,7 @@ func GetQuestionPermission(ctx context.Context, userID string, creatorUserID str
|
|||
})
|
||||
}
|
||||
|
||||
if CanUnPin {
|
||||
if canUnPin {
|
||||
actions = append(actions, &schema.PermissionMemberAction{
|
||||
Action: "unpin",
|
||||
Name: translator.Tr(lang, unpinActionName),
|
||||
|
@ -79,6 +80,14 @@ func GetQuestionPermission(ctx context.Context, userID string, creatorUserID str
|
|||
Type: "confirm",
|
||||
})
|
||||
}
|
||||
|
||||
if canRecover && status == entity.QuestionStatusDeleted {
|
||||
actions = append(actions, &schema.PermissionMemberAction{
|
||||
Action: "undelete",
|
||||
Name: translator.Tr(lang, undeleteActionName),
|
||||
Type: "confirm",
|
||||
})
|
||||
}
|
||||
return actions
|
||||
}
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@ package permission
|
|||
|
||||
import (
|
||||
"context"
|
||||
"github.com/answerdev/answer/internal/entity"
|
||||
|
||||
"github.com/answerdev/answer/internal/base/handler"
|
||||
"github.com/answerdev/answer/internal/base/translator"
|
||||
|
@ -9,7 +10,7 @@ import (
|
|||
)
|
||||
|
||||
// GetTagPermission get tag permission
|
||||
func GetTagPermission(ctx context.Context, canEdit, canDelete bool) (
|
||||
func GetTagPermission(ctx context.Context, status int, canEdit, canDelete, canRecover bool) (
|
||||
actions []*schema.PermissionMemberAction) {
|
||||
lang := handler.GetLangByCtx(ctx)
|
||||
actions = make([]*schema.PermissionMemberAction, 0)
|
||||
|
@ -21,13 +22,21 @@ func GetTagPermission(ctx context.Context, canEdit, canDelete bool) (
|
|||
})
|
||||
}
|
||||
|
||||
if canDelete {
|
||||
if canDelete && status != entity.TagStatusDeleted {
|
||||
actions = append(actions, &schema.PermissionMemberAction{
|
||||
Action: "delete",
|
||||
Name: translator.Tr(lang, deleteActionName),
|
||||
Type: "reason",
|
||||
})
|
||||
}
|
||||
|
||||
if canRecover && status == entity.QuestionStatusDeleted {
|
||||
actions = append(actions, &schema.PermissionMemberAction{
|
||||
Action: "undelete",
|
||||
Name: translator.Tr(lang, undeleteActionName),
|
||||
Type: "confirm",
|
||||
})
|
||||
}
|
||||
return actions
|
||||
}
|
||||
|
||||
|
|
|
@ -39,6 +39,7 @@ type QuestionRepo interface {
|
|||
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)
|
||||
UpdateQuestionOperation(ctx context.Context, question *entity.Question) (err error)
|
||||
GetQuestionsByTitle(ctx context.Context, title string, pageSize int) (questionList []*entity.Question, err error)
|
||||
UpdatePvCount(ctx context.Context, questionID string) (err error)
|
||||
|
|
|
@ -563,13 +563,70 @@ func (qs *QuestionService) UpdateQuestionCheckTags(ctx context.Context, req *sch
|
|||
return nil, nil
|
||||
}
|
||||
|
||||
func (qs *QuestionService) RecoverQuestion(ctx context.Context, req *schema.QuestionRecoverReq) (err error) {
|
||||
questionInfo, exist, err := qs.questionRepo.GetQuestion(ctx, req.QuestionID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !exist {
|
||||
return errors.BadRequest(reason.QuestionNotFound)
|
||||
}
|
||||
if questionInfo.Status != entity.QuestionStatusDeleted {
|
||||
return nil
|
||||
}
|
||||
|
||||
err = qs.questionRepo.RecoverQuestion(ctx, req.QuestionID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// update user's question count
|
||||
userQuestionCount, err := qs.questioncommon.GetUserQuestionCount(ctx, questionInfo.UserID)
|
||||
if err != nil {
|
||||
log.Error("user GetUserQuestionCount error", err.Error())
|
||||
} else {
|
||||
err = qs.userCommon.UpdateQuestionCount(ctx, questionInfo.UserID, userQuestionCount)
|
||||
if err != nil {
|
||||
log.Error("user IncreaseQuestionCount error", err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
// update tag's question count
|
||||
if err = qs.tagCommon.RemoveTagRelListByObjectID(ctx, questionInfo.ID); err != nil {
|
||||
log.Errorf("remove tag rel list by object id error %v", err)
|
||||
}
|
||||
|
||||
tagIDs := make([]string, 0)
|
||||
tags, err := qs.tagCommon.GetObjectEntityTag(ctx, questionInfo.ID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, v := range tags {
|
||||
tagIDs = append(tagIDs, v.ID)
|
||||
}
|
||||
if len(tagIDs) > 0 {
|
||||
if err = qs.tagCommon.RefreshTagQuestionCount(ctx, tagIDs); err != nil {
|
||||
log.Errorf("update tag's question count failed, %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
qs.activityQueueService.Send(ctx, &schema.ActivityMsg{
|
||||
UserID: req.UserID,
|
||||
TriggerUserID: converter.StringToInt64(req.UserID),
|
||||
ObjectID: questionInfo.ID,
|
||||
OriginalObjectID: questionInfo.ID,
|
||||
ActivityTypeKey: constant.ActQuestionUndeleted,
|
||||
})
|
||||
return nil
|
||||
}
|
||||
|
||||
func (qs *QuestionService) UpdateQuestionInviteUser(ctx context.Context, req *schema.QuestionUpdateInviteUser) (err error) {
|
||||
originQuestion, exist, err := qs.questionRepo.GetQuestion(ctx, req.ID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !exist {
|
||||
return errors.NotFound(reason.ObjectNotFound)
|
||||
return errors.BadRequest(reason.QuestionNotFound)
|
||||
}
|
||||
|
||||
//verify invite user
|
||||
|
@ -875,8 +932,10 @@ func (qs *QuestionService) GetQuestion(ctx context.Context, questionID, userID s
|
|||
}
|
||||
|
||||
question.Description = htmltext.FetchExcerpt(question.HTML, "...", 240)
|
||||
question.MemberActions = permission.GetQuestionPermission(ctx, userID, question.UserID,
|
||||
per.CanEdit, per.CanDelete, per.CanClose, per.CanReopen, per.CanPin, per.CanHide, per.CanUnPin, per.CanShow)
|
||||
question.MemberActions = permission.GetQuestionPermission(ctx, userID, question.UserID, question.Status,
|
||||
per.CanEdit, per.CanDelete,
|
||||
per.CanClose, per.CanReopen, per.CanPin, per.CanHide, per.CanUnPin, per.CanShow,
|
||||
per.CanRecover)
|
||||
question.ExtendsActions = permission.GetQuestionExtendsPermission(ctx, per.CanInviteOtherToAnswer)
|
||||
return question, nil
|
||||
}
|
||||
|
@ -1195,12 +1254,12 @@ func (qs *QuestionService) GetQuestionPage(ctx context.Context, req *schema.Ques
|
|||
return questions, total, nil
|
||||
}
|
||||
|
||||
func (qs *QuestionService) AdminSetQuestionStatus(ctx context.Context, questionID string, setStatusStr string) error {
|
||||
setStatus, ok := entity.AdminQuestionSearchStatus[setStatusStr]
|
||||
func (qs *QuestionService) AdminSetQuestionStatus(ctx context.Context, req *schema.AdminUpdateQuestionStatusReq) error {
|
||||
setStatus, ok := entity.AdminQuestionSearchStatus[req.Status]
|
||||
if !ok {
|
||||
return fmt.Errorf("question status does not exist")
|
||||
return errors.BadRequest(reason.RequestFormatError)
|
||||
}
|
||||
questionInfo, exist, err := qs.questionRepo.GetQuestion(ctx, questionID)
|
||||
questionInfo, exist, err := qs.questionRepo.GetQuestion(ctx, req.QuestionID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -1212,6 +1271,7 @@ func (qs *QuestionService) AdminSetQuestionStatus(ctx context.Context, questionI
|
|||
return err
|
||||
}
|
||||
|
||||
msg := &schema.NotificationMsg{}
|
||||
if setStatus == entity.QuestionStatusDeleted {
|
||||
// #2372 In order to simplify the process and complexity, as well as to consider if it is in-house,
|
||||
// facing the problem of recovery.
|
||||
|
@ -1225,6 +1285,7 @@ func (qs *QuestionService) AdminSetQuestionStatus(ctx context.Context, questionI
|
|||
OriginalObjectID: questionInfo.ID,
|
||||
ActivityTypeKey: constant.ActQuestionDeleted,
|
||||
})
|
||||
msg.NotificationAction = constant.NotificationYourQuestionWasDeleted
|
||||
}
|
||||
if setStatus == entity.QuestionStatusAvailable && questionInfo.Status == entity.QuestionStatusClosed {
|
||||
qs.activityQueueService.Send(ctx, &schema.ActivityMsg{
|
||||
|
@ -1241,15 +1302,27 @@ func (qs *QuestionService) AdminSetQuestionStatus(ctx context.Context, questionI
|
|||
OriginalObjectID: questionInfo.ID,
|
||||
ActivityTypeKey: constant.ActQuestionClosed,
|
||||
})
|
||||
msg.NotificationAction = constant.NotificationYourQuestionIsClosed
|
||||
}
|
||||
// recover
|
||||
if setStatus == entity.QuestionStatusAvailable && questionInfo.Status == entity.QuestionStatusDeleted {
|
||||
qs.activityQueueService.Send(ctx, &schema.ActivityMsg{
|
||||
UserID: req.UserID,
|
||||
TriggerUserID: converter.StringToInt64(req.UserID),
|
||||
ObjectID: questionInfo.ID,
|
||||
OriginalObjectID: questionInfo.ID,
|
||||
ActivityTypeKey: constant.ActQuestionUndeleted,
|
||||
})
|
||||
}
|
||||
|
||||
if len(msg.NotificationAction) > 0 {
|
||||
msg.ObjectID = questionInfo.ID
|
||||
msg.Type = schema.NotificationTypeInbox
|
||||
msg.ReceiverUserID = questionInfo.UserID
|
||||
msg.TriggerUserID = req.UserID
|
||||
msg.ObjectType = constant.QuestionObjectType
|
||||
qs.notificationQueueService.Send(ctx, msg)
|
||||
}
|
||||
msg := &schema.NotificationMsg{}
|
||||
msg.ObjectID = questionInfo.ID
|
||||
msg.Type = schema.NotificationTypeInbox
|
||||
msg.ReceiverUserID = questionInfo.UserID
|
||||
msg.TriggerUserID = questionInfo.UserID
|
||||
msg.ObjectType = constant.QuestionObjectType
|
||||
msg.NotificationAction = constant.NotificationYourQuestionWasDeleted
|
||||
qs.notificationQueueService.Send(ctx, msg)
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
@ -91,6 +91,33 @@ func (ts *TagService) UpdateTag(ctx context.Context, req *schema.UpdateTagReq) (
|
|||
return ts.tagCommonService.UpdateTag(ctx, req)
|
||||
}
|
||||
|
||||
// RecoverTag recover tag
|
||||
func (ts *TagService) RecoverTag(ctx context.Context, req *schema.RecoverTagReq) (err error) {
|
||||
tagInfo, exist, err := ts.tagRepo.MustGetTagByNameOrID(ctx, req.TagID, "")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !exist {
|
||||
return errors.BadRequest(reason.TagNotFound)
|
||||
}
|
||||
if tagInfo.Status != entity.TagStatusDeleted {
|
||||
return nil
|
||||
}
|
||||
|
||||
err = ts.tagRepo.RecoverTag(ctx, req.TagID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ts.activityQueueService.Send(ctx, &schema.ActivityMsg{
|
||||
UserID: req.UserID,
|
||||
TriggerUserID: converter.StringToInt64(req.UserID),
|
||||
ObjectID: req.TagID,
|
||||
OriginalObjectID: req.TagID,
|
||||
ActivityTypeKey: constant.ActTagUndeleted,
|
||||
})
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetTagInfo get tag one
|
||||
func (ts *TagService) GetTagInfo(ctx context.Context, req *schema.GetTagInfoReq) (resp *schema.GetTagResp, err error) {
|
||||
var (
|
||||
|
@ -102,6 +129,10 @@ func (ts *TagService) GetTagInfo(ctx context.Context, req *schema.GetTagInfoReq)
|
|||
} else {
|
||||
tagInfo, exist, err = ts.tagCommonService.GetTagBySlugName(ctx, req.Name)
|
||||
}
|
||||
// If user can recover deleted tag, try to search in all tags including deleted tags
|
||||
if !exist && req.CanRecover {
|
||||
tagInfo, exist, err = ts.tagRepo.MustGetTagByNameOrID(ctx, req.ID, req.Name)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -134,7 +165,8 @@ func (ts *TagService) GetTagInfo(ctx context.Context, req *schema.GetTagInfoReq)
|
|||
resp.Recommend = tagInfo.Recommend
|
||||
resp.Reserved = tagInfo.Reserved
|
||||
resp.IsFollower = ts.checkTagIsFollow(ctx, req.UserID, tagInfo.ID)
|
||||
resp.MemberActions = permission.GetTagPermission(ctx, req.CanEdit, req.CanDelete)
|
||||
resp.Status = entity.TagStatusDisplayMapping[tagInfo.Status]
|
||||
resp.MemberActions = permission.GetTagPermission(ctx, tagInfo.Status, req.CanEdit, req.CanDelete, req.CanRecover)
|
||||
resp.GetExcerpt()
|
||||
return resp, nil
|
||||
}
|
||||
|
|
|
@ -37,6 +37,8 @@ type TagCommonRepo interface {
|
|||
type TagRepo interface {
|
||||
RemoveTag(ctx context.Context, tagID string) (err error)
|
||||
UpdateTag(ctx context.Context, tag *entity.Tag) (err error)
|
||||
RecoverTag(ctx context.Context, tagID string) (err error)
|
||||
MustGetTagByNameOrID(ctx context.Context, tagID, slugName string) (tag *entity.Tag, exist bool, err error)
|
||||
UpdateTagSynonym(ctx context.Context, tagSlugNameList []string, mainTagID int64, mainTagSlugName string) (err error)
|
||||
GetTagSynonymCount(ctx context.Context, tagID string) (count int64, err error)
|
||||
GetTagList(ctx context.Context, tag *entity.Tag) (tagList []*entity.Tag, err error)
|
||||
|
@ -45,6 +47,7 @@ type TagRepo interface {
|
|||
type TagRelRepo interface {
|
||||
AddTagRelList(ctx context.Context, tagList []*entity.TagRel) (err error)
|
||||
RemoveTagRelListByObjectID(ctx context.Context, objectID string) (err error)
|
||||
RecoverTagRelListByObjectID(ctx context.Context, objectID string) (err error)
|
||||
ShowTagRelListByObjectID(ctx context.Context, objectID string) (err error)
|
||||
HideTagRelListByObjectID(ctx context.Context, objectID string) (err error)
|
||||
RemoveTagRelListByIDs(ctx context.Context, ids []int64) (err error)
|
||||
|
@ -713,6 +716,11 @@ func (ts *TagCommonService) RemoveTagRelListByObjectID(ctx context.Context, obje
|
|||
return ts.tagRelRepo.RemoveTagRelListByObjectID(ctx, objectID)
|
||||
}
|
||||
|
||||
// RecoverTagRelListByObjectID recover tag relation by object id
|
||||
func (ts *TagCommonService) RecoverTagRelListByObjectID(ctx context.Context, objectID string) (err error) {
|
||||
return ts.tagRelRepo.RecoverTagRelListByObjectID(ctx, objectID)
|
||||
}
|
||||
|
||||
func (ts *TagCommonService) HideTagRelListByObjectID(ctx context.Context, objectID string) (err error) {
|
||||
return ts.tagRelRepo.HideTagRelListByObjectID(ctx, objectID)
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue