diff --git a/docs/docs.go b/docs/docs.go index 77a19c21..47eb274e 100644 --- a/docs/docs.go +++ b/docs/docs.go @@ -3654,6 +3654,83 @@ const docTemplate = `{ } } }, + "/answer/api/v1/question/invite_user": { + "get": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "description": "get question invite user info", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Question" + ], + "summary": "get question invite user info", + "parameters": [ + { + "type": "string", + "default": "1", + "description": "Question ID", + "name": "id", + "in": "query", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "string" + } + } + } + } + }, + "/answer/api/v1/question/inviter_user": { + "put": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "description": "update question invite user", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Question" + ], + "summary": "update question invite user", + "parameters": [ + { + "description": "question", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/schema.QuestionUpdateInviteUser" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/handler.RespBody" + } + } + } + } + }, "/answer/api/v1/question/operation": { "put": { "security": [ @@ -7857,6 +7934,23 @@ const docTemplate = `{ } } }, + "schema.QuestionUpdateInviteUser": { + "type": "object", + "required": [ + "id" + ], + "properties": { + "id": { + "type": "string" + }, + "invite_user": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, "schema.RemoveAnswerReq": { "type": "object", "required": [ diff --git a/docs/swagger.json b/docs/swagger.json index 31fdf372..a3c2e8e6 100644 --- a/docs/swagger.json +++ b/docs/swagger.json @@ -3642,6 +3642,83 @@ } } }, + "/answer/api/v1/question/invite_user": { + "get": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "description": "get question invite user info", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Question" + ], + "summary": "get question invite user info", + "parameters": [ + { + "type": "string", + "default": "1", + "description": "Question ID", + "name": "id", + "in": "query", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "string" + } + } + } + } + }, + "/answer/api/v1/question/inviter_user": { + "put": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "description": "update question invite user", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Question" + ], + "summary": "update question invite user", + "parameters": [ + { + "description": "question", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/schema.QuestionUpdateInviteUser" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/handler.RespBody" + } + } + } + } + }, "/answer/api/v1/question/operation": { "put": { "security": [ @@ -7845,6 +7922,23 @@ } } }, + "schema.QuestionUpdateInviteUser": { + "type": "object", + "required": [ + "id" + ], + "properties": { + "id": { + "type": "string" + }, + "invite_user": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, "schema.RemoveAnswerReq": { "type": "object", "required": [ diff --git a/docs/swagger.yaml b/docs/swagger.yaml index b3ef8a9d..88f3e18a 100644 --- a/docs/swagger.yaml +++ b/docs/swagger.yaml @@ -1358,6 +1358,17 @@ definitions: - tags - title type: object + schema.QuestionUpdateInviteUser: + properties: + id: + type: string + invite_user: + items: + type: string + type: array + required: + - id + type: object schema.RemoveAnswerReq: properties: id: @@ -4481,6 +4492,54 @@ paths: summary: get question details tags: - Question + /answer/api/v1/question/invite_user: + get: + consumes: + - application/json + description: get question invite user info + parameters: + - default: "1" + description: Question ID + in: query + name: id + required: true + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + type: string + security: + - ApiKeyAuth: [] + summary: get question invite user info + tags: + - Question + /answer/api/v1/question/inviter_user: + put: + consumes: + - application/json + description: update question invite user + parameters: + - description: question + in: body + name: data + required: true + schema: + $ref: '#/definitions/schema.QuestionUpdateInviteUser' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/handler.RespBody' + security: + - ApiKeyAuth: [] + summary: update question invite user + tags: + - Question /answer/api/v1/question/operation: put: consumes: diff --git a/internal/controller/question_controller.go b/internal/controller/question_controller.go index e72a692e..107c469f 100644 --- a/internal/controller/question_controller.go +++ b/internal/controller/question_controller.go @@ -221,6 +221,44 @@ func (qc *QuestionController) GetQuestion(ctx *gin.Context) { handler.HandleResponse(ctx, nil, info) } +// GetQuestionInviteUserInfo get question invite user info +// @Summary get question invite user info +// @Description get question invite user info +// @Tags Question +// @Security ApiKeyAuth +// @Accept json +// @Produce json +// @Param id query string true "Question ID" default(1) +// @Success 200 {string} string "" +// @Router /answer/api/v1/question/invite_user [get] +func (qc *QuestionController) GetQuestionInviteUserInfo(ctx *gin.Context) { + id := ctx.Query("id") + id = uid.DeShortID(id) + userID := middleware.GetLoginUserIDFromContext(ctx) + req := schema.QuestionPermission{} + canList, err := qc.rankService.CheckOperationPermissions(ctx, userID, []string{ + permission.QuestionEdit, + }) + if err != nil { + handler.HandleResponse(ctx, err, nil) + return + } + objectOwner := qc.rankService.CheckOperationObjectOwner(ctx, userID, id) + + req.CanEdit = canList[0] || objectOwner + if !req.CanEdit { + handler.HandleResponse(ctx, errors.Forbidden(reason.RankFailToMeetTheCondition), nil) + return + } + list, err := qc.questionService.InviteUserInfo(ctx, id) + if err != nil { + handler.HandleResponse(ctx, err, nil) + return + } + handler.HandleResponse(ctx, nil, list) + +} + // SimilarQuestion godoc // @Summary Search Similar Question // @Description Search Similar Question @@ -500,6 +538,51 @@ func (qc *QuestionController) UpdateQuestion(ctx *gin.Context) { handler.HandleResponse(ctx, nil, &schema.UpdateQuestionResp{WaitForReview: !req.NoNeedReview}) } +// UpdateQuestionInviteUser update question invite user +// @Summary update question invite user +// @Description update question invite user +// @Tags Question +// @Accept json +// @Produce json +// @Security ApiKeyAuth +// @Param data body schema.QuestionUpdateInviteUser true "question" +// @Success 200 {object} handler.RespBody +// @Router /answer/api/v1/question/inviter_user [put] +func (qc *QuestionController) UpdateQuestionInviteUser(ctx *gin.Context) { + req := &schema.QuestionUpdateInviteUser{} + errFields := handler.BindAndCheckReturnErr(ctx, req) + if ctx.IsAborted() { + return + } + req.ID = uid.DeShortID(req.ID) + req.UserID = middleware.GetLoginUserIDFromContext(ctx) + + canList, err := qc.rankService.CheckOperationPermissions(ctx, req.UserID, []string{ + permission.QuestionEdit, + }) + if err != nil { + handler.HandleResponse(ctx, err, nil) + return + } + + objectOwner := qc.rankService.CheckOperationObjectOwner(ctx, req.UserID, req.ID) + req.CanEdit = canList[0] || objectOwner + if !req.CanEdit { + handler.HandleResponse(ctx, errors.Forbidden(reason.RankFailToMeetTheCondition), nil) + return + } + if len(errFields) > 0 { + handler.HandleResponse(ctx, errors.BadRequest(reason.RequestFormatError), errFields) + return + } + err = qc.questionService.UpdateQuestionInviteUser(ctx, req) + if err != nil { + handler.HandleResponse(ctx, err, nil) + return + } + handler.HandleResponse(ctx, nil, nil) +} + // CloseMsgList close question msg list // @Summary close question msg list // @Description close question msg list diff --git a/internal/router/answer_api_router.go b/internal/router/answer_api_router.go index 5c3f60d6..3f90218c 100644 --- a/internal/router/answer_api_router.go +++ b/internal/router/answer_api_router.go @@ -130,6 +130,7 @@ func (a *AnswerAPIRouter) RegisterUnAuthAnswerAPIRouter(r *gin.RouterGroup) { //question r.GET("/question/info", a.questionController.GetQuestion) + r.GET("/question/invite_user", a.questionController.GetQuestionInviteUserInfo) r.GET("/question/page", a.questionController.QuestionPage) r.GET("/question/similar/tag", a.questionController.SimilarQuestion) r.GET("/personal/qa/top", a.questionController.UserTop) @@ -194,6 +195,7 @@ func (a *AnswerAPIRouter) RegisterAnswerAPIRouter(r *gin.RouterGroup) { r.POST("/question", a.questionController.AddQuestion) r.POST("/question/answer", a.questionController.AddQuestionByAnswer) r.PUT("/question", a.questionController.UpdateQuestion) + r.PUT("/question/inviter_user", a.questionController.UpdateQuestionInviteUser) r.DELETE("/question", a.questionController.RemoveQuestion) r.PUT("/question/status", a.questionController.CloseQuestion) r.PUT("/question/operation", a.questionController.OperationQuestion) diff --git a/internal/schema/question_schema.go b/internal/schema/question_schema.go index 9ef45d7a..3f0b518c 100644 --- a/internal/schema/question_schema.go +++ b/internal/schema/question_schema.go @@ -152,6 +152,13 @@ type QuestionUpdate struct { QuestionPermission } +type QuestionUpdateInviteUser struct { + ID string `validate:"required" json:"id"` + InviteUser []string `validate:"omitempty" json:"invite_user"` + UserID string `json:"-"` + QuestionPermission +} + func (req *QuestionUpdate) Check() (errFields []*validator.FormErrorField, err error) { req.HTML = converter.Markdown2HTML(req.Content) return nil, nil diff --git a/internal/service/question_common/question.go b/internal/service/question_common/question.go index 46a76067..26eb2cc6 100644 --- a/internal/service/question_common/question.go +++ b/internal/service/question_common/question.go @@ -150,6 +150,34 @@ func (qs *QuestionCommon) FindInfoByID(ctx context.Context, questionIDs []string return list, nil } +func (qs *QuestionCommon) InviteUserInfo(ctx context.Context, questionID string) (inviteList []*schema.UserBasicInfo, err error) { + InviteUserInfo := make([]*schema.UserBasicInfo, 0) + dbinfo, has, err := qs.questionRepo.GetQuestion(ctx, questionID) + if err != nil { + return InviteUserInfo, err + } + if !has { + return InviteUserInfo, errors.NotFound(reason.QuestionNotFound) + } + //InviteUser + if dbinfo.InviteUserID != "" { + InviteUserIDs := make([]string, 0) + err := json.Unmarshal([]byte(dbinfo.InviteUserID), &InviteUserIDs) + if err == nil { + inviteUserInfoMap, err := qs.userCommon.BatchUserBasicInfoByID(ctx, InviteUserIDs) + if err == nil { + for _, userid := range InviteUserIDs { + _, ok := inviteUserInfoMap[userid] + if ok { + InviteUserInfo = append(InviteUserInfo, inviteUserInfoMap[userid]) + } + } + } + } + } + return InviteUserInfo, nil +} + func (qs *QuestionCommon) Info(ctx context.Context, questionID string, loginUserID string) (showinfo *schema.QuestionInfo, err error) { dbinfo, has, err := qs.questionRepo.GetQuestion(ctx, questionID) if err != nil { @@ -186,9 +214,7 @@ func (qs *QuestionCommon) Info(ctx context.Context, questionID string, loginUser operation.Level = schema.OperationLevelInfo showinfo.Operation = operation } - } - } } diff --git a/internal/service/question_service.go b/internal/service/question_service.go index 73c89386..32b24a5e 100644 --- a/internal/service/question_service.go +++ b/internal/service/question_service.go @@ -550,6 +550,38 @@ func (qs *QuestionService) UpdateQuestionCheckTags(ctx context.Context, req *sch return nil, nil } +func (qs *QuestionService) UpdateQuestionInviteUser(ctx context.Context, req *schema.QuestionUpdateInviteUser) (err error) { + //verify invite user + inviteUserInfoList, err := qs.userCommon.BatchGetUserBasicInfoByUserNames(ctx, req.InviteUser) + if err != nil { + log.Error("BatchGetUserBasicInfoByUserNames error", err.Error()) + } + inviteUser := make([]string, 0) + for _, item := range req.InviteUser { + _, ok := inviteUserInfoList[item] + if ok { + inviteUser = append(inviteUser, inviteUserInfoList[item].ID) + } + } + inviteUserStr := "" + inviteUserByte, err := json.Marshal(inviteUser) + if err != nil { + log.Error("json.Marshal error", err.Error()) + inviteUserStr = "[]" + } else { + inviteUserStr = string(inviteUserByte) + } + question := &entity.Question{} + question.ID = uid.DeShortID(req.ID) + question.InviteUserID = inviteUserStr + + saveerr := qs.questionRepo.UpdateQuestion(ctx, question, []string{"invite_user_id"}) + if saveerr != nil { + return saveerr + } + return nil +} + // UpdateQuestion update question func (qs *QuestionService) UpdateQuestion(ctx context.Context, req *schema.QuestionUpdate) (questionInfo any, err error) { var canUpdate bool @@ -577,27 +609,6 @@ func (qs *QuestionService) UpdateQuestion(ctx context.Context, req *schema.Quest return nil, err } - //verify invite user - inviteUserInfoList, err := qs.userCommon.BatchGetUserBasicInfoByUserNames(ctx, req.InviteUser) - if err != nil { - log.Error("BatchGetUserBasicInfoByUserNames error", err.Error()) - } - inviteUser := make([]string, 0) - for _, item := range req.InviteUser { - _, ok := inviteUserInfoList[item] - if ok { - inviteUser = append(inviteUser, inviteUserInfoList[item].ID) - } - } - inviteUserStr := "" - inviteUserByte, err := json.Marshal(inviteUser) - if err != nil { - log.Error("json.Marshal error", err.Error()) - inviteUserStr = "[]" - } else { - inviteUserStr = string(inviteUserByte) - } - now := time.Now() question := &entity.Question{} question.Title = req.Title @@ -605,7 +616,6 @@ func (qs *QuestionService) UpdateQuestion(ctx context.Context, req *schema.Quest question.ParsedText = req.HTML question.ID = uid.DeShortID(req.ID) question.UpdatedAt = now - question.InviteUserID = inviteUserStr question.PostUpdateTime = now question.UserID = dbinfo.UserID question.LastEditUserID = req.UserID @@ -699,7 +709,7 @@ func (qs *QuestionService) UpdateQuestion(ctx context.Context, req *schema.Quest //Direct modification revisionDTO.Status = entity.RevisionReviewPassStatus //update question to db - saveerr := qs.questionRepo.UpdateQuestion(ctx, question, []string{"title", "original_text", "parsed_text", "updated_at", "post_update_time", "last_edit_user_id", "invite_user_id"}) + saveerr := qs.questionRepo.UpdateQuestion(ctx, question, []string{"title", "original_text", "parsed_text", "updated_at", "post_update_time", "last_edit_user_id"}) if saveerr != nil { return questionInfo, saveerr } @@ -793,6 +803,10 @@ func (qs *QuestionService) GetQuestionAndAddPV(ctx context.Context, questionID, return qs.GetQuestion(ctx, questionID, loginUserID, per) } +func (qs *QuestionService) InviteUserInfo(ctx context.Context, questionID string) (inviteList []*schema.UserBasicInfo, err error) { + return qs.questioncommon.InviteUserInfo(ctx, questionID) +} + func (qs *QuestionService) ChangeTag(ctx context.Context, objectTagData *schema.TagChange) error { return qs.tagCommon.ObjectChangeTag(ctx, objectTagData) }