From 76ace2c9a3bb878626d00a99e43b4bbf20747db7 Mon Sep 17 00:00:00 2001 From: aichy126 <16996097+aichy126@users.noreply.github.com> Date: Tue, 22 Nov 2022 11:12:08 +0800 Subject: [PATCH 1/9] fix question delete --- i18n/en_US.yaml | 4 ++++ internal/base/reason/reason.go | 2 ++ internal/service/answer_service.go | 14 +++++++------- internal/service/question_service.go | 6 +++--- 4 files changed, 16 insertions(+), 10 deletions(-) diff --git a/i18n/en_US.yaml b/i18n/en_US.yaml index 824c92e6..01a89c0a 100644 --- a/i18n/en_US.yaml +++ b/i18n/en_US.yaml @@ -24,6 +24,8 @@ error: answer: not_found: other: "Answer do not found." + cannot_deleted: + other: "Unable to delete answer." comment: edit_without_permission: other: "Comment are not allowed to edit." @@ -61,6 +63,8 @@ error: question: not_found: other: "Question not found." + cannot_deleted: + other: "Unable to delete problem." rank: fail_to_meet_the_condition: other: "Rank fail to meet the condition." diff --git a/internal/base/reason/reason.go b/internal/base/reason/reason.go index abe1bd23..68051269 100644 --- a/internal/base/reason/reason.go +++ b/internal/base/reason/reason.go @@ -17,7 +17,9 @@ const ( EmailOrPasswordWrong = "error.user.email_or_password_wrong" CommentNotFound = "error.comment.not_found" QuestionNotFound = "error.question.not_found" + QuestionCannotDeleted = "error.question.cannot_deleted" AnswerNotFound = "error.answer.not_found" + AnswerCannotDeleted = "error.answer.cannot_deleted" CommentEditWithoutPermission = "error.comment.edit_without_permission" DisallowVote = "error.object.disallow_vote" DisallowFollow = "error.object.disallow_follow" diff --git a/internal/service/answer_service.go b/internal/service/answer_service.go index 30f8e42d..af7a1bd3 100644 --- a/internal/service/answer_service.go +++ b/internal/service/answer_service.go @@ -74,26 +74,26 @@ func (as *AnswerService) RemoveAnswer(ctx context.Context, req *schema.RemoveAns return nil } if answerInfo.UserID != req.UserID { - return errors.BadRequest(reason.UnauthorizedError) + return errors.BadRequest(reason.AnswerCannotDeleted) } if answerInfo.VoteCount > 0 { - return errors.BadRequest(reason.UnauthorizedError) + return errors.BadRequest(reason.AnswerCannotDeleted) } if answerInfo.Adopted == schema.AnswerAdoptedEnable { - return errors.BadRequest(reason.UnauthorizedError) + return errors.BadRequest(reason.AnswerCannotDeleted) } questionInfo, exist, err := as.questionRepo.GetQuestion(ctx, answerInfo.QuestionID) if err != nil { - return errors.BadRequest(reason.UnauthorizedError) + return errors.BadRequest(reason.AnswerCannotDeleted) } if !exist { - return errors.BadRequest(reason.UnauthorizedError) + return errors.BadRequest(reason.AnswerCannotDeleted) } if questionInfo.AnswerCount > 1 { - return errors.BadRequest(reason.UnauthorizedError) + return errors.BadRequest(reason.AnswerCannotDeleted) } if questionInfo.AcceptedAnswerID != "" { - return errors.BadRequest(reason.UnauthorizedError) + return errors.BadRequest(reason.AnswerCannotDeleted) } // user add question count diff --git a/internal/service/question_service.go b/internal/service/question_service.go index 72f885b1..259ae2f2 100644 --- a/internal/service/question_service.go +++ b/internal/service/question_service.go @@ -164,14 +164,14 @@ func (qs *QuestionService) RemoveQuestion(ctx context.Context, req *schema.Remov return nil } if questionInfo.UserID != req.UserID { - return errors.BadRequest(reason.UnauthorizedError) + return errors.BadRequest(reason.QuestionCannotDeleted) } if questionInfo.AcceptedAnswerID != "" { - return errors.BadRequest(reason.UnauthorizedError) + return errors.BadRequest(reason.QuestionCannotDeleted) } if questionInfo.AnswerCount > 0 { - return errors.BadRequest(reason.UnauthorizedError) + return errors.BadRequest(reason.QuestionCannotDeleted) } questionInfo.Status = entity.QuestionStatusDeleted From 4f1762f01a24c8280ba38b07a62b1517721a8265 Mon Sep 17 00:00:00 2001 From: aichy126 <16996097+aichy126@users.noreply.github.com> Date: Tue, 22 Nov 2022 16:13:55 +0800 Subject: [PATCH 2/9] fix question delete --- i18n/en_US.yaml | 4 ++-- internal/service/question_service.go | 16 +++++++++++++++- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/i18n/en_US.yaml b/i18n/en_US.yaml index 01a89c0a..2c0908ad 100644 --- a/i18n/en_US.yaml +++ b/i18n/en_US.yaml @@ -25,7 +25,7 @@ error: not_found: other: "Answer do not found." cannot_deleted: - other: "Unable to delete answer." + other: "No permission to delete." comment: edit_without_permission: other: "Comment are not allowed to edit." @@ -64,7 +64,7 @@ error: not_found: other: "Question not found." cannot_deleted: - other: "Unable to delete problem." + other: "No permission to delete." rank: fail_to_meet_the_condition: other: "Rank fail to meet the condition." diff --git a/internal/service/question_service.go b/internal/service/question_service.go index 259ae2f2..2f440ca6 100644 --- a/internal/service/question_service.go +++ b/internal/service/question_service.go @@ -167,13 +167,27 @@ func (qs *QuestionService) RemoveQuestion(ctx context.Context, req *schema.Remov return errors.BadRequest(reason.QuestionCannotDeleted) } - if questionInfo.AcceptedAnswerID != "" { + if questionInfo.AcceptedAnswerID != "0" { return errors.BadRequest(reason.QuestionCannotDeleted) } if questionInfo.AnswerCount > 0 { return errors.BadRequest(reason.QuestionCannotDeleted) } + if questionInfo.AnswerCount == 1 { + answersearch := &entity.AnswerSearch{} + answersearch.QuestionID = req.ID + answerList, _, err := qs.questioncommon.AnswerCommon.Search(ctx, answersearch) + if err != nil { + return err + } + for _, answer := range answerList { + if answer.VoteCount > 0 { + return errors.BadRequest(reason.QuestionCannotDeleted) + } + } + } + questionInfo.Status = entity.QuestionStatusDeleted err = qs.questionRepo.UpdateQuestionStatus(ctx, questionInfo) if err != nil { From f216536e263de4beb95b9fb5a0286cf8032d6b1e Mon Sep 17 00:00:00 2001 From: aichy126 <16996097+aichy126@users.noreply.github.com> Date: Tue, 22 Nov 2022 16:22:30 +0800 Subject: [PATCH 3/9] update question delete --- internal/controller/question_controller.go | 2 ++ internal/schema/question_schema.go | 7 ++-- internal/service/question_service.go | 42 +++++++++++----------- 3 files changed, 28 insertions(+), 23 deletions(-) diff --git a/internal/controller/question_controller.go b/internal/controller/question_controller.go index 281a7e1b..ff8a6eba 100644 --- a/internal/controller/question_controller.go +++ b/internal/controller/question_controller.go @@ -46,6 +46,8 @@ func (qc *QuestionController) RemoveQuestion(ctx *gin.Context) { handler.HandleResponse(ctx, err, errors.Forbidden(reason.RankFailToMeetTheCondition)) return } + userinfo := middleware.GetUserInfoFromContext(ctx) + req.IsAdmin = userinfo.IsAdmin err := qc.questionService.RemoveQuestion(ctx, req) handler.HandleResponse(ctx, err, nil) diff --git a/internal/schema/question_schema.go b/internal/schema/question_schema.go index 29b85be8..9005f07a 100644 --- a/internal/schema/question_schema.go +++ b/internal/schema/question_schema.go @@ -3,8 +3,9 @@ package schema // RemoveQuestionReq delete question request type RemoveQuestionReq struct { // question id - ID string `validate:"required" comment:"question id" json:"id"` - UserID string `json:"-" ` // user_id + ID string `validate:"required" comment:"question id" json:"id"` + UserID string `json:"-" ` // user_id + IsAdmin bool `json:"-"` } type CloseQuestionReq struct { @@ -169,7 +170,7 @@ type CmsQuestionSearch struct { Page int `json:"page" form:"page"` // Query number of pages PageSize int `json:"page_size" form:"page_size"` // Search page size Status int `json:"-" form:"-"` - StatusStr string `json:"status" form:"status"` // Status 1 Available 2 closed 10 UserDeleted + StatusStr string `json:"status" form:"status"` // Status 1 Available 2 closed 10 UserDeleted Query string `validate:"omitempty,gt=0,lte=100" json:"query" form:"query" ` //Query string } diff --git a/internal/service/question_service.go b/internal/service/question_service.go index 4abfe08a..931bb940 100644 --- a/internal/service/question_service.go +++ b/internal/service/question_service.go @@ -174,27 +174,29 @@ func (qs *QuestionService) RemoveQuestion(ctx context.Context, req *schema.Remov if !has { return nil } - if questionInfo.UserID != req.UserID { - return errors.BadRequest(reason.QuestionCannotDeleted) - } - - if questionInfo.AcceptedAnswerID != "0" { - return errors.BadRequest(reason.QuestionCannotDeleted) - } - if questionInfo.AnswerCount > 0 { - return errors.BadRequest(reason.QuestionCannotDeleted) - } - - if questionInfo.AnswerCount == 1 { - answersearch := &entity.AnswerSearch{} - answersearch.QuestionID = req.ID - answerList, _, err := qs.questioncommon.AnswerCommon.Search(ctx, answersearch) - if err != nil { - return err + if !req.IsAdmin { + if questionInfo.UserID != req.UserID { + return errors.BadRequest(reason.QuestionCannotDeleted) } - for _, answer := range answerList { - if answer.VoteCount > 0 { - return errors.BadRequest(reason.QuestionCannotDeleted) + + if questionInfo.AcceptedAnswerID != "0" { + return errors.BadRequest(reason.QuestionCannotDeleted) + } + if questionInfo.AnswerCount > 0 { + return errors.BadRequest(reason.QuestionCannotDeleted) + } + + if questionInfo.AnswerCount == 1 { + answersearch := &entity.AnswerSearch{} + answersearch.QuestionID = req.ID + answerList, _, err := qs.questioncommon.AnswerCommon.Search(ctx, answersearch) + if err != nil { + return err + } + for _, answer := range answerList { + if answer.VoteCount > 0 { + return errors.BadRequest(reason.QuestionCannotDeleted) + } } } } From 26768223312a5a61c89b848c9e0c7f1b39000f8e Mon Sep 17 00:00:00 2001 From: aichy126 <16996097+aichy126@users.noreply.github.com> Date: Tue, 22 Nov 2022 16:54:28 +0800 Subject: [PATCH 4/9] fix question answer delete --- i18n/en_US.yaml | 176 +++++++++++---------- internal/base/reason/reason.go | 71 +++++---- internal/controller/answer_controller.go | 5 +- internal/controller/question_controller.go | 5 +- internal/schema/answer_schema.go | 4 +- internal/schema/question_schema.go | 4 +- internal/service/answer_service.go | 57 ++++--- internal/service/question_service.go | 13 +- 8 files changed, 189 insertions(+), 146 deletions(-) diff --git a/i18n/en_US.yaml b/i18n/en_US.yaml index c3ccf96a..1cd93624 100644 --- a/i18n/en_US.yaml +++ b/i18n/en_US.yaml @@ -20,92 +20,98 @@ backend: email_or_password_wrong_error: &email_or_password_wrong other: "Email and password do not match." -error: - admin: - email_or_password_wrong: *email_or_password_wrong - answer: - not_found: - other: "Answer do not found." - cannot_deleted: - other: "No permission to delete." - comment: - edit_without_permission: - other: "Comment are not allowed to edit." - not_found: - other: "Comment not found." - email: - duplicate: - other: "Email already exists." - need_to_be_verified: - other: "Email should be verified." - verify_url_expired: - other: "Email verified URL has expired, please resend the email." - lang: - not_found: - other: "Language file not found." - object: - captcha_verification_failed: - other: "Captcha wrong." - disallow_follow: - other: "You are not allowed to follow." - disallow_vote: - other: "You are not allowed to vote." - disallow_vote_your_self: - other: "You can't vote for your own post." - not_found: - other: "Object not found." - verification_failed: - other: "Verification failed." - email_or_password_incorrect: - other: "Email and password do not match." - old_password_verification_failed: - other: "The old password verification failed" - new_password_same_as_previous_setting: - other: "The new password is the same as the previous one." - question: - not_found: - other: "Question not found." - cannot_deleted: - other: "No permission to delete." - rank: - fail_to_meet_the_condition: - other: "Rank fail to meet the condition." - report: - handle_failed: - other: "Report handle failed." - not_found: - other: "Report not found." - tag: - not_found: - other: "Tag not found." - theme: - not_found: - other: "Theme not found." - user: - email_or_password_wrong: - other: *email_or_password_wrong - not_found: - other: "User not found." - suspended: - other: "User has been suspended." - username_invalid: - other: "Username is invalid." - username_duplicate: - other: "Username is already in use." - set_avatar: - other: "Avatar set failed." + error: + admin: + email_or_password_wrong: *email_or_password_wrong + answer: + not_found: + other: "Answer do not found." + cannot_deleted: + other: "No permission to delete." + cannot_update: + other: "No permission to update." + comment: + edit_without_permission: + other: "Comment are not allowed to edit." + not_found: + other: "Comment not found." + email: + duplicate: + other: "Email already exists." + need_to_be_verified: + other: "Email should be verified." + verify_url_expired: + other: "Email verified URL has expired, please resend the email." + lang: + not_found: + other: "Language file not found." + object: + captcha_verification_failed: + other: "Captcha wrong." + disallow_follow: + other: "You are not allowed to follow." + disallow_vote: + other: "You are not allowed to vote." + disallow_vote_your_self: + other: "You can't vote for your own post." + not_found: + other: "Object not found." + verification_failed: + other: "Verification failed." + email_or_password_incorrect: + other: "Email and password do not match." + old_password_verification_failed: + other: "The old password verification failed" + new_password_same_as_previous_setting: + other: "The new password is the same as the previous one." + question: + not_found: + other: "Question not found." + cannot_deleted: + other: "No permission to delete." + cannot_close: + other: "No permission to close." + cannot_update: + other: "No permission to update." + rank: + fail_to_meet_the_condition: + other: "Rank fail to meet the condition." + report: + handle_failed: + other: "Report handle failed." + not_found: + other: "Report not found." + tag: + not_found: + other: "Tag not found." + theme: + not_found: + other: "Theme not found." + user: + email_or_password_wrong: + other: *email_or_password_wrong + not_found: + other: "User not found." + suspended: + other: "User has been suspended." + username_invalid: + other: "Username is invalid." + username_duplicate: + other: "Username is already in use." + set_avatar: + other: "Avatar set failed." - config: - read_config_failed: - other: "Read config failed" - database: - connection_failed: - other: "Database connection failed" - create_table_failed: - other: "Create table failed" - install: - create_config_failed: - other: "Can’t create the config.yaml file." + config: + read_config_failed: + other: "Read config failed" + database: + connection_failed: + other: "Database connection failed" + create_table_failed: + other: "Create table failed" + install: + create_config_failed: + other: "Can’t create the config.yaml file." report: spam: name: diff --git a/internal/base/reason/reason.go b/internal/base/reason/reason.go index 7ac8f556..e8f6aded 100644 --- a/internal/base/reason/reason.go +++ b/internal/base/reason/reason.go @@ -14,40 +14,43 @@ const ( ) const ( - EmailOrPasswordWrong = "error.object.email_or_password_incorrect" - CommentNotFound = "error.comment.not_found" - QuestionNotFound = "error.question.not_found" - QuestionCannotDeleted = "error.question.cannot_deleted" - AnswerNotFound = "error.answer.not_found" - AnswerCannotDeleted = "error.answer.cannot_deleted" - CommentEditWithoutPermission = "error.comment.edit_without_permission" - DisallowVote = "error.object.disallow_vote" - DisallowFollow = "error.object.disallow_follow" - DisallowVoteYourSelf = "error.object.disallow_vote_your_self" - CaptchaVerificationFailed = "error.object.captcha_verification_failed" + EmailOrPasswordWrong = "error.object.email_or_password_incorrect" + CommentNotFound = "error.comment.not_found" + QuestionNotFound = "error.question.not_found" + QuestionCannotDeleted = "error.question.cannot_deleted" + QuestionCannotClose = "error.question.cannot_close" + QuestionCannotUpdate = "error.question.cannot_update" + AnswerNotFound = "error.answer.not_found" + AnswerCannotDeleted = "error.answer.cannot_deleted" + AnswerCannotUpdate = "error.answer.cannot_update" + CommentEditWithoutPermission = "error.comment.edit_without_permission" + DisallowVote = "error.object.disallow_vote" + DisallowFollow = "error.object.disallow_follow" + DisallowVoteYourSelf = "error.object.disallow_vote_your_self" + CaptchaVerificationFailed = "error.object.captcha_verification_failed" OldPasswordVerificationFailed = "error.object.old_password_verification_failed" NewPasswordSameAsPreviousSetting = "error.object.new_password_same_as_previous_setting" - UserNotFound = "error.user.not_found" - UsernameInvalid = "error.user.username_invalid" - UsernameDuplicate = "error.user.username_duplicate" - UserSetAvatar = "error.user.set_avatar" - EmailDuplicate = "error.email.duplicate" - EmailVerifyURLExpired = "error.email.verify_url_expired" - EmailNeedToBeVerified = "error.email.need_to_be_verified" - UserSuspended = "error.user.suspended" - ObjectNotFound = "error.object.not_found" - TagNotFound = "error.tag.not_found" - TagNotContainSynonym = "error.tag.not_contain_synonym_tags" - RankFailToMeetTheCondition = "error.rank.fail_to_meet_the_condition" - ThemeNotFound = "error.theme.not_found" - LangNotFound = "error.lang.not_found" - ReportHandleFailed = "error.report.handle_failed" - ReportNotFound = "error.report.not_found" - ReadConfigFailed = "error.config.read_config_failed" - DatabaseConnectionFailed = "error.database.connection_failed" - InstallCreateTableFailed = "error.database.create_table_failed" - InstallConfigFailed = "error.install.create_config_failed" - SiteInfoNotFound = "error.site_info.not_found" - UploadFileSourceUnsupported = "error.upload.source_unsupported" - RecommendTagNotExist = "error.tag.recommend_tag_not_found" + UserNotFound = "error.user.not_found" + UsernameInvalid = "error.user.username_invalid" + UsernameDuplicate = "error.user.username_duplicate" + UserSetAvatar = "error.user.set_avatar" + EmailDuplicate = "error.email.duplicate" + EmailVerifyURLExpired = "error.email.verify_url_expired" + EmailNeedToBeVerified = "error.email.need_to_be_verified" + UserSuspended = "error.user.suspended" + ObjectNotFound = "error.object.not_found" + TagNotFound = "error.tag.not_found" + TagNotContainSynonym = "error.tag.not_contain_synonym_tags" + RankFailToMeetTheCondition = "error.rank.fail_to_meet_the_condition" + ThemeNotFound = "error.theme.not_found" + LangNotFound = "error.lang.not_found" + ReportHandleFailed = "error.report.handle_failed" + ReportNotFound = "error.report.not_found" + ReadConfigFailed = "error.config.read_config_failed" + DatabaseConnectionFailed = "error.database.connection_failed" + InstallCreateTableFailed = "error.database.create_table_failed" + InstallConfigFailed = "error.install.create_config_failed" + SiteInfoNotFound = "error.site_info.not_found" + UploadFileSourceUnsupported = "error.upload.source_unsupported" + RecommendTagNotExist = "error.tag.recommend_tag_not_found" ) diff --git a/internal/controller/answer_controller.go b/internal/controller/answer_controller.go index 6db77008..ff0b3ff2 100644 --- a/internal/controller/answer_controller.go +++ b/internal/controller/answer_controller.go @@ -55,7 +55,8 @@ func (ac *AnswerController) RemoveAnswer(ctx *gin.Context) { handler.HandleResponse(ctx, err, errors.Forbidden(reason.RankFailToMeetTheCondition)) return } - + userinfo := middleware.GetUserInfoFromContext(ctx) + req.IsAdmin = userinfo.IsAdmin err := ac.answerService.RemoveAnswer(ctx, req) handler.HandleResponse(ctx, err, nil) } @@ -147,6 +148,8 @@ func (ac *AnswerController) Update(ctx *gin.Context) { return } req.UserID = middleware.GetLoginUserIDFromContext(ctx) + userinfo := middleware.GetUserInfoFromContext(ctx) + req.IsAdmin = userinfo.IsAdmin if can, err := ac.rankService.CheckRankPermission(ctx, req.UserID, rank.AnswerEditRank); err != nil || !can { handler.HandleResponse(ctx, err, errors.Forbidden(reason.RankFailToMeetTheCondition)) diff --git a/internal/controller/question_controller.go b/internal/controller/question_controller.go index ff8a6eba..4d7e2366 100644 --- a/internal/controller/question_controller.go +++ b/internal/controller/question_controller.go @@ -69,6 +69,8 @@ func (qc *QuestionController) CloseQuestion(ctx *gin.Context) { return } req.UserID = middleware.GetLoginUserIDFromContext(ctx) + userinfo := middleware.GetUserInfoFromContext(ctx) + req.IsAdmin = userinfo.IsAdmin err := qc.questionService.CloseQuestion(ctx, req) handler.HandleResponse(ctx, err, nil) } @@ -215,7 +217,8 @@ func (qc *QuestionController) UpdateQuestion(ctx *gin.Context) { return } req.UserID = middleware.GetLoginUserIDFromContext(ctx) - + userinfo := middleware.GetUserInfoFromContext(ctx) + req.IsAdmin = userinfo.IsAdmin if can, err := qc.rankService.CheckRankPermission(ctx, req.UserID, rank.QuestionEditRank); err != nil || !can { handler.HandleResponse(ctx, err, errors.Forbidden(reason.RankFailToMeetTheCondition)) return diff --git a/internal/schema/answer_schema.go b/internal/schema/answer_schema.go index 0c396865..390f90dc 100644 --- a/internal/schema/answer_schema.go +++ b/internal/schema/answer_schema.go @@ -5,7 +5,8 @@ type RemoveAnswerReq struct { // answer id ID string `validate:"required" json:"id"` // user id - UserID string `json:"-"` + UserID string `json:"-"` + IsAdmin bool `json:"-"` } const ( @@ -28,6 +29,7 @@ type AnswerUpdateReq struct { Content string `json:"content"` // content HTML string `json:"html" ` // html EditSummary string `validate:"omitempty" json:"edit_summary"` // edit_summary + IsAdmin bool `json:"-"` } type AnswerList struct { diff --git a/internal/schema/question_schema.go b/internal/schema/question_schema.go index 9005f07a..0669a7ec 100644 --- a/internal/schema/question_schema.go +++ b/internal/schema/question_schema.go @@ -13,6 +13,7 @@ type CloseQuestionReq struct { UserID string `json:"-" ` // user_id CloseType int `json:"close_type" ` // close_type CloseMsg string `json:"close_msg" ` // close_type + IsAdmin bool `json:"-"` } type CloseQuestionMeta struct { @@ -47,7 +48,8 @@ type QuestionUpdate struct { // edit summary EditSummary string `validate:"omitempty" json:"edit_summary"` // user id - UserID string `json:"-"` + UserID string `json:"-"` + IsAdmin bool `json:"-"` } type QuestionBaseInfo struct { diff --git a/internal/service/answer_service.go b/internal/service/answer_service.go index af7a1bd3..3fd37a3d 100644 --- a/internal/service/answer_service.go +++ b/internal/service/answer_service.go @@ -73,27 +73,29 @@ func (as *AnswerService) RemoveAnswer(ctx context.Context, req *schema.RemoveAns if !exist { return nil } - if answerInfo.UserID != req.UserID { - return errors.BadRequest(reason.AnswerCannotDeleted) - } - if answerInfo.VoteCount > 0 { - return errors.BadRequest(reason.AnswerCannotDeleted) - } - if answerInfo.Adopted == schema.AnswerAdoptedEnable { - return errors.BadRequest(reason.AnswerCannotDeleted) - } - questionInfo, exist, err := as.questionRepo.GetQuestion(ctx, answerInfo.QuestionID) - if err != nil { - return errors.BadRequest(reason.AnswerCannotDeleted) - } - if !exist { - return errors.BadRequest(reason.AnswerCannotDeleted) - } - if questionInfo.AnswerCount > 1 { - return errors.BadRequest(reason.AnswerCannotDeleted) - } - if questionInfo.AcceptedAnswerID != "" { - return errors.BadRequest(reason.AnswerCannotDeleted) + if !req.IsAdmin { + if answerInfo.UserID != req.UserID { + return errors.BadRequest(reason.AnswerCannotDeleted) + } + if answerInfo.VoteCount > 0 { + return errors.BadRequest(reason.AnswerCannotDeleted) + } + if answerInfo.Adopted == schema.AnswerAdoptedEnable { + return errors.BadRequest(reason.AnswerCannotDeleted) + } + questionInfo, exist, err := as.questionRepo.GetQuestion(ctx, answerInfo.QuestionID) + if err != nil { + return errors.BadRequest(reason.AnswerCannotDeleted) + } + if !exist { + return errors.BadRequest(reason.AnswerCannotDeleted) + } + if questionInfo.AnswerCount > 1 { + return errors.BadRequest(reason.AnswerCannotDeleted) + } + if questionInfo.AcceptedAnswerID != "" { + return errors.BadRequest(reason.AnswerCannotDeleted) + } } // user add question count @@ -180,6 +182,19 @@ func (as *AnswerService) Update(ctx context.Context, req *schema.AnswerUpdateReq if !exist { return "", errors.BadRequest(reason.QuestionNotFound) } + if !req.IsAdmin { + answerInfo, exist, err := as.answerRepo.GetByID(ctx, req.ID) + if err != nil { + return "", err + } + if !exist { + return "", nil + } + if answerInfo.UserID != req.UserID { + return "", errors.BadRequest(reason.AnswerCannotUpdate) + } + } + now := time.Now() insertData := new(entity.Answer) insertData.ID = req.ID diff --git a/internal/service/question_service.go b/internal/service/question_service.go index 931bb940..0409ff2d 100644 --- a/internal/service/question_service.go +++ b/internal/service/question_service.go @@ -71,6 +71,12 @@ func (qs *QuestionService) CloseQuestion(ctx context.Context, req *schema.CloseQ if !has { return nil } + + if !req.IsAdmin { + if questionInfo.UserID != req.UserID { + return errors.BadRequest(reason.QuestionCannotClose) + } + } questionInfo.Status = entity.QuestionStatusclosed err = qs.questionRepo.UpdateQuestionStatus(ctx, questionInfo) if err != nil { @@ -239,8 +245,11 @@ func (qs *QuestionService) UpdateQuestion(ctx context.Context, req *schema.Quest if !has { return } - if dbinfo.UserID != req.UserID { - return + if !req.IsAdmin { + if dbinfo.UserID != req.UserID { + return questionInfo, errors.BadRequest(reason.QuestionCannotUpdate) + } + } //CheckChangeTag From 0fac38860f12d98760ab3f78fa11fb7eece53118 Mon Sep 17 00:00:00 2001 From: aichy126 <16996097+aichy126@users.noreply.github.com> Date: Tue, 22 Nov 2022 17:06:15 +0800 Subject: [PATCH 5/9] en_US.yaml --- i18n/en_US.yaml | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/i18n/en_US.yaml b/i18n/en_US.yaml index 1cd93624..04102618 100644 --- a/i18n/en_US.yaml +++ b/i18n/en_US.yaml @@ -28,8 +28,8 @@ backend: other: "Answer do not found." cannot_deleted: other: "No permission to delete." - cannot_update: - other: "No permission to update." + cannot_update: + other: "No permission to update." comment: edit_without_permission: other: "Comment are not allowed to edit." @@ -84,6 +84,12 @@ backend: tag: not_found: other: "Tag not found." + recommend_tag_not_found: + other: "Recommend Tag is not exist." + recommend_tag_enter: + other: "Please enter at least one required tag." + not_contain_synonym_tags: + other: "Should not contain synonym tags." theme: not_found: other: "Theme not found." @@ -100,7 +106,6 @@ backend: other: "Username is already in use." set_avatar: other: "Avatar set failed." - config: read_config_failed: other: "Read config failed" From 6ec9dbec87da79cd8ed3cc4e16b7a6e2edb9c64f Mon Sep 17 00:00:00 2001 From: aichy126 <16996097+aichy126@users.noreply.github.com> Date: Tue, 22 Nov 2022 17:35:41 +0800 Subject: [PATCH 6/9] update permission --- internal/controller/answer_controller.go | 2 + internal/controller/question_controller.go | 3 +- internal/schema/answer_schema.go | 1 + internal/service/answer_service.go | 6 +- internal/service/comment/comment_service.go | 6 +- .../service/permission/comment_permission.go | 55 +++++++++++-------- internal/service/question_service.go | 10 ++-- internal/service/tag/tag_service.go | 2 +- 8 files changed, 48 insertions(+), 37 deletions(-) diff --git a/internal/controller/answer_controller.go b/internal/controller/answer_controller.go index ff0b3ff2..00f61280 100644 --- a/internal/controller/answer_controller.go +++ b/internal/controller/answer_controller.go @@ -193,6 +193,8 @@ func (ac *AnswerController) AnswerList(ctx *gin.Context) { return } req.LoginUserID = middleware.GetLoginUserIDFromContext(ctx) + userinfo := middleware.GetUserInfoFromContext(ctx) + req.IsAdmin = userinfo.IsAdmin list, count, err := ac.answerService.SearchList(ctx, req) if err != nil { handler.HandleResponse(ctx, err, nil) diff --git a/internal/controller/question_controller.go b/internal/controller/question_controller.go index 4d7e2366..bdb39b89 100644 --- a/internal/controller/question_controller.go +++ b/internal/controller/question_controller.go @@ -89,7 +89,8 @@ func (qc *QuestionController) GetQuestion(c *gin.Context) { id := c.Query("id") ctx := context.Background() userID := middleware.GetLoginUserIDFromContext(c) - info, err := qc.questionService.GetQuestion(ctx, id, userID, true) + userinfo := middleware.GetUserInfoFromContext(c) + info, err := qc.questionService.GetQuestion(ctx, id, userID, true, userinfo.IsAdmin) if err != nil { handler.HandleResponse(c, err, nil) return diff --git a/internal/schema/answer_schema.go b/internal/schema/answer_schema.go index 390f90dc..fb523164 100644 --- a/internal/schema/answer_schema.go +++ b/internal/schema/answer_schema.go @@ -38,6 +38,7 @@ type AnswerList struct { Page int `json:"page" form:"page"` // Query number of pages PageSize int `json:"page_size" form:"page_size"` // Search page size LoginUserID string `json:"-" ` + IsAdmin bool `json:"-"` } type AnswerInfo struct { diff --git a/internal/service/answer_service.go b/internal/service/answer_service.go index 3fd37a3d..56167a2b 100644 --- a/internal/service/answer_service.go +++ b/internal/service/answer_service.go @@ -392,14 +392,14 @@ func (as *AnswerService) SearchList(ctx context.Context, search *schema.AnswerLi if err != nil { return list, count, err } - AnswerList, err := as.SearchFormatInfo(ctx, dblist, search.LoginUserID) + AnswerList, err := as.SearchFormatInfo(ctx, dblist, search.LoginUserID, search.IsAdmin) if err != nil { return AnswerList, count, err } return AnswerList, count, nil } -func (as *AnswerService) SearchFormatInfo(ctx context.Context, dblist []*entity.Answer, loginUserID string) ([]*schema.AnswerInfo, error) { +func (as *AnswerService) SearchFormatInfo(ctx context.Context, dblist []*entity.Answer, loginUserID string, isAdmin bool) ([]*schema.AnswerInfo, error) { list := make([]*schema.AnswerInfo, 0) objectIds := make([]string, 0) userIds := make([]string, 0) @@ -442,7 +442,7 @@ func (as *AnswerService) SearchFormatInfo(ctx context.Context, dblist []*entity. } for _, item := range list { - item.MemberActions = permission.GetAnswerPermission(loginUserID, item.UserID) + item.MemberActions = permission.GetAnswerPermission(ctx, loginUserID, item.UserID, isAdmin) } return list, nil diff --git a/internal/service/comment/comment_service.go b/internal/service/comment/comment_service.go index a7156c76..0d4235ab 100644 --- a/internal/service/comment/comment_service.go +++ b/internal/service/comment/comment_service.go @@ -121,7 +121,7 @@ func (cs *CommentService) AddComment(ctx context.Context, req *schema.AddComment resp = &schema.GetCommentResp{} resp.SetFromComment(comment) - resp.MemberActions = permission.GetCommentPermission(req.UserID, resp.UserID) + resp.MemberActions = permission.GetCommentPermission(ctx, req.UserID, resp.UserID) // get reply user info if len(resp.ReplyUserID) > 0 { @@ -222,7 +222,7 @@ func (cs *CommentService) GetComment(ctx context.Context, req *schema.GetComment // check if current user vote this comment resp.IsVote = cs.checkIsVote(ctx, req.UserID, resp.CommentID) - resp.MemberActions = permission.GetCommentPermission(req.UserID, resp.UserID) + resp.MemberActions = permission.GetCommentPermission(ctx, req.UserID, resp.UserID) return resp, nil } @@ -282,7 +282,7 @@ func (cs *CommentService) GetCommentWithPage(ctx context.Context, req *schema.Ge // check if current user vote this comment commentResp.IsVote = cs.checkIsVote(ctx, req.UserID, commentResp.CommentID) - commentResp.MemberActions = permission.GetCommentPermission(req.UserID, commentResp.UserID) + commentResp.MemberActions = permission.GetCommentPermission(ctx, req.UserID, commentResp.UserID) resp = append(resp, commentResp) } return pager.NewPageModel(total, resp), nil diff --git a/internal/service/permission/comment_permission.go b/internal/service/permission/comment_permission.go index ba04e0c3..b73dab9f 100644 --- a/internal/service/permission/comment_permission.go +++ b/internal/service/permission/comment_permission.go @@ -1,9 +1,13 @@ package permission -import "github.com/answerdev/answer/internal/schema" +import ( + "context" + + "github.com/answerdev/answer/internal/schema" +) // TODO: There is currently no permission management -func GetCommentPermission(userID string, commentCreatorUserID string) ( +func GetCommentPermission(ctx context.Context, userID string, commentCreatorUserID string) ( actions []*schema.PermissionMemberAction) { actions = make([]*schema.PermissionMemberAction, 0) if len(userID) > 0 { @@ -31,7 +35,7 @@ func GetCommentPermission(userID string, commentCreatorUserID string) ( return actions } -func GetTagPermission(userID string, tagCreatorUserID string) ( +func GetTagPermission(ctx context.Context, userID string, tagCreatorUserID string) ( actions []*schema.PermissionMemberAction) { if userID != tagCreatorUserID { return []*schema.PermissionMemberAction{} @@ -50,18 +54,20 @@ func GetTagPermission(userID string, tagCreatorUserID string) ( } } -func GetAnswerPermission(userID string, answerAuthID string) ( +func GetAnswerPermission(ctx context.Context, userID string, answerAuthID string, isAdmin bool) ( actions []*schema.PermissionMemberAction) { actions = make([]*schema.PermissionMemberAction, 0) - if len(userID) > 0 { - actions = append(actions, &schema.PermissionMemberAction{ - Action: "report", - Name: "Flag", - Type: "reason", - }) - } - if userID != answerAuthID { - return actions + if !isAdmin { + if len(userID) > 0 { + actions = append(actions, &schema.PermissionMemberAction{ + Action: "report", + Name: "Flag", + Type: "reason", + }) + } + if userID != answerAuthID { + return actions + } } actions = append(actions, []*schema.PermissionMemberAction{ { @@ -78,18 +84,19 @@ func GetAnswerPermission(userID string, answerAuthID string) ( return actions } -func GetQuestionPermission(userID string, questionAuthID string) ( - actions []*schema.PermissionMemberAction) { +func GetQuestionPermission(ctx context.Context, userID string, questionAuthID string, isAdmin bool) (actions []*schema.PermissionMemberAction) { actions = make([]*schema.PermissionMemberAction, 0) - if len(userID) > 0 { - actions = append(actions, &schema.PermissionMemberAction{ - Action: "report", - Name: "Flag", - Type: "reason", - }) - } - if userID != questionAuthID { - return actions + if !isAdmin { + if len(userID) > 0 { + actions = append(actions, &schema.PermissionMemberAction{ + Action: "report", + Name: "Flag", + Type: "reason", + }) + } + if userID != questionAuthID { + return actions + } } actions = append(actions, []*schema.PermissionMemberAction{ { diff --git a/internal/service/question_service.go b/internal/service/question_service.go index 0409ff2d..f13dee2c 100644 --- a/internal/service/question_service.go +++ b/internal/service/question_service.go @@ -167,7 +167,7 @@ func (qs *QuestionService) AddQuestion(ctx context.Context, req *schema.Question log.Error("user IncreaseQuestionCount error", err.Error()) } - questionInfo, err = qs.GetQuestion(ctx, question.ID, question.UserID, false) + questionInfo, err = qs.GetQuestion(ctx, question.ID, question.UserID, false, false) return } @@ -299,12 +299,12 @@ func (qs *QuestionService) UpdateQuestion(ctx context.Context, req *schema.Quest return } - questionInfo, err = qs.GetQuestion(ctx, question.ID, question.UserID, false) + questionInfo, err = qs.GetQuestion(ctx, question.ID, question.UserID, false, false) return } // GetQuestion get question one -func (qs *QuestionService) GetQuestion(ctx context.Context, id, loginUserID string, addpv bool) (resp *schema.QuestionInfo, err error) { +func (qs *QuestionService) GetQuestion(ctx context.Context, id, loginUserID string, addpv bool, isAdmin bool) (resp *schema.QuestionInfo, err error) { question, err := qs.questioncommon.Info(ctx, id, loginUserID) if err != nil { return @@ -316,7 +316,7 @@ func (qs *QuestionService) GetQuestion(ctx context.Context, id, loginUserID stri } } - question.MemberActions = permission.GetQuestionPermission(loginUserID, question.UserID) + question.MemberActions = permission.GetQuestionPermission(ctx, loginUserID, question.UserID, isAdmin) return question, nil } @@ -543,7 +543,7 @@ func (qs *QuestionService) SearchByTitleLike(ctx context.Context, title string, // SimilarQuestion func (qs *QuestionService) SimilarQuestion(ctx context.Context, questionID string, loginUserID string) ([]*schema.QuestionInfo, int64, error) { list := make([]*schema.QuestionInfo, 0) - questionInfo, err := qs.GetQuestion(ctx, questionID, loginUserID, false) + questionInfo, err := qs.GetQuestion(ctx, questionID, loginUserID, false, false) if err != nil { return list, 0, err } diff --git a/internal/service/tag/tag_service.go b/internal/service/tag/tag_service.go index dcf02029..d7b5736e 100644 --- a/internal/service/tag/tag_service.go +++ b/internal/service/tag/tag_service.go @@ -154,7 +154,7 @@ 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(req.UserID, req.UserID) + resp.MemberActions = permission.GetTagPermission(ctx, req.UserID, req.UserID) resp.GetExcerpt() return resp, nil } From b7e6d3ee35c86aa5a3797958b261628a2f6b0906 Mon Sep 17 00:00:00 2001 From: aichy126 <16996097+aichy126@users.noreply.github.com> Date: Tue, 22 Nov 2022 18:03:18 +0800 Subject: [PATCH 7/9] fix delete question --- internal/controller/question_controller.go | 2 +- internal/service/question_service.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/internal/controller/question_controller.go b/internal/controller/question_controller.go index bdb39b89..203fbcf8 100644 --- a/internal/controller/question_controller.go +++ b/internal/controller/question_controller.go @@ -43,7 +43,7 @@ func (qc *QuestionController) RemoveQuestion(ctx *gin.Context) { } req.UserID = middleware.GetLoginUserIDFromContext(ctx) if can, err := qc.rankService.CheckRankPermission(ctx, req.UserID, rank.QuestionDeleteRank); err != nil || !can { - handler.HandleResponse(ctx, err, errors.Forbidden(reason.RankFailToMeetTheCondition)) + handler.HandleResponse(ctx, errors.Forbidden(reason.RankFailToMeetTheCondition), errors.Forbidden(reason.RankFailToMeetTheCondition)) return } userinfo := middleware.GetUserInfoFromContext(ctx) diff --git a/internal/service/question_service.go b/internal/service/question_service.go index f13dee2c..e5012427 100644 --- a/internal/service/question_service.go +++ b/internal/service/question_service.go @@ -188,7 +188,7 @@ func (qs *QuestionService) RemoveQuestion(ctx context.Context, req *schema.Remov if questionInfo.AcceptedAnswerID != "0" { return errors.BadRequest(reason.QuestionCannotDeleted) } - if questionInfo.AnswerCount > 0 { + if questionInfo.AnswerCount > 1 { return errors.BadRequest(reason.QuestionCannotDeleted) } From 9c2e05d280d7a8111baa06d020817eda642e2201 Mon Sep 17 00:00:00 2001 From: "haitao(lj)" Date: Wed, 23 Nov 2022 10:49:00 +0800 Subject: [PATCH 8/9] fix(router): remove unnecessary guard for `password-reset` @github: #92 --- ui/src/router/routes.ts | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/ui/src/router/routes.ts b/ui/src/router/routes.ts index be7e61ac..7c56db23 100644 --- a/ui/src/router/routes.ts +++ b/ui/src/router/routes.ts @@ -160,20 +160,10 @@ const routes: RouteNode[] = [ { path: 'users/password-reset', page: 'pages/Users/PasswordReset', - guard: async () => { - return guard.activated(); - }, }, { path: 'users/account-activation', page: 'pages/Users/ActiveEmail', - // guard: async () => { - // const notActivated = guard.notActivated(); - // if (notActivated.ok) { - // return notActivated; - // } - // return guard.notLogged(); - // }, }, { path: 'users/account-activation/success', From 98114a6a05561885de5616990e5c3458b29ed16e Mon Sep 17 00:00:00 2001 From: aichy126 <16996097+aichy126@users.noreply.github.com> Date: Wed, 23 Nov 2022 16:32:06 +0800 Subject: [PATCH 9/9] fix en_us --- i18n/en_US.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/i18n/en_US.yaml b/i18n/en_US.yaml index 04102618..19bc53cf 100644 --- a/i18n/en_US.yaml +++ b/i18n/en_US.yaml @@ -28,8 +28,8 @@ backend: other: "Answer do not found." cannot_deleted: other: "No permission to delete." - cannot_update: - other: "No permission to update." + cannot_update: + other: "No permission to update." comment: edit_without_permission: other: "Comment are not allowed to edit."