mirror of https://gitee.com/answerdev/answer.git
Merge branch 'feat/1.1.0/report' into feat/1.1.0/context
This commit is contained in:
commit
0c43b9c7b1
|
@ -211,7 +211,8 @@ func initApplication(debug bool, serverConf *conf.Server, dbConf *data.Database,
|
|||
pluginConfigRepo := plugin_config.NewPluginConfigRepo(dataData)
|
||||
pluginCommonService := plugin_common.NewPluginCommonService(pluginConfigRepo, configService)
|
||||
pluginController := controller_admin.NewPluginController(pluginCommonService)
|
||||
answerAPIRouter := router.NewAnswerAPIRouter(langController, userController, commentController, reportController, voteController, tagController, followController, collectionController, questionController, answerController, searchController, revisionController, rankController, controller_adminReportController, userAdminController, reasonController, themeController, siteInfoController, siteinfoController, notificationController, dashboardController, uploadController, activityController, roleController, pluginController)
|
||||
permissionController := controller.NewPermissionController(rankService)
|
||||
answerAPIRouter := router.NewAnswerAPIRouter(langController, userController, commentController, reportController, voteController, tagController, followController, collectionController, questionController, answerController, searchController, revisionController, rankController, controller_adminReportController, userAdminController, reasonController, themeController, siteInfoController, siteinfoController, notificationController, dashboardController, uploadController, activityController, roleController, pluginController, permissionController)
|
||||
swaggerRouter := router.NewSwaggerRouter(swaggerConf)
|
||||
uiRouter := router.NewUIRouter(siteinfoController, siteInfoCommonService)
|
||||
authUserMiddleware := middleware.NewAuthUserMiddleware(authService, siteInfoCommonService)
|
||||
|
|
96
docs/docs.go
96
docs/docs.go
|
@ -3009,6 +3009,102 @@ const docTemplate = `{
|
|||
}
|
||||
}
|
||||
},
|
||||
"/answer/api/v1/permission": {
|
||||
"get": {
|
||||
"security": [
|
||||
{
|
||||
"ApiKeyAuth": []
|
||||
}
|
||||
],
|
||||
"description": "check user permission",
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Permission"
|
||||
],
|
||||
"summary": "check user permission",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "access-token",
|
||||
"name": "Authorization",
|
||||
"in": "header",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"enum": [
|
||||
"question.add",
|
||||
"question.edit",
|
||||
"question.edit_without_review",
|
||||
"question.delete",
|
||||
"question.close",
|
||||
"question.reopen",
|
||||
"question.vote_up",
|
||||
"question.vote_down",
|
||||
"question.pin",
|
||||
"question.unpin",
|
||||
"question.hide",
|
||||
"question.show",
|
||||
"answer.add",
|
||||
"answer.edit",
|
||||
"answer.edit_without_review",
|
||||
"answer.delete",
|
||||
"answer.accept",
|
||||
"answer.vote_up",
|
||||
"answer.vote_down",
|
||||
"answer.invite_someone_to_answer",
|
||||
"comment.add",
|
||||
"comment.edit",
|
||||
"comment.delete",
|
||||
"comment.vote_up",
|
||||
"comment.vote_down",
|
||||
"report.add",
|
||||
"tag.add",
|
||||
"tag.edit",
|
||||
"tag.edit_slug_name",
|
||||
"tag.edit_without_review",
|
||||
"tag.delete",
|
||||
"tag.synonym",
|
||||
"link.url_limit",
|
||||
"vote.detail",
|
||||
"answer.audit",
|
||||
"question.audit",
|
||||
"tag.audit",
|
||||
"tag.use_reserved_tag"
|
||||
],
|
||||
"type": "string",
|
||||
"description": "permission key",
|
||||
"name": "action",
|
||||
"in": "query",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/handler.RespBody"
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"data": {
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
"type": "boolean"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/answer/api/v1/personal/answer/page": {
|
||||
"get": {
|
||||
"security": [
|
||||
|
|
|
@ -2997,6 +2997,102 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"/answer/api/v1/permission": {
|
||||
"get": {
|
||||
"security": [
|
||||
{
|
||||
"ApiKeyAuth": []
|
||||
}
|
||||
],
|
||||
"description": "check user permission",
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Permission"
|
||||
],
|
||||
"summary": "check user permission",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "access-token",
|
||||
"name": "Authorization",
|
||||
"in": "header",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"enum": [
|
||||
"question.add",
|
||||
"question.edit",
|
||||
"question.edit_without_review",
|
||||
"question.delete",
|
||||
"question.close",
|
||||
"question.reopen",
|
||||
"question.vote_up",
|
||||
"question.vote_down",
|
||||
"question.pin",
|
||||
"question.unpin",
|
||||
"question.hide",
|
||||
"question.show",
|
||||
"answer.add",
|
||||
"answer.edit",
|
||||
"answer.edit_without_review",
|
||||
"answer.delete",
|
||||
"answer.accept",
|
||||
"answer.vote_up",
|
||||
"answer.vote_down",
|
||||
"answer.invite_someone_to_answer",
|
||||
"comment.add",
|
||||
"comment.edit",
|
||||
"comment.delete",
|
||||
"comment.vote_up",
|
||||
"comment.vote_down",
|
||||
"report.add",
|
||||
"tag.add",
|
||||
"tag.edit",
|
||||
"tag.edit_slug_name",
|
||||
"tag.edit_without_review",
|
||||
"tag.delete",
|
||||
"tag.synonym",
|
||||
"link.url_limit",
|
||||
"vote.detail",
|
||||
"answer.audit",
|
||||
"question.audit",
|
||||
"tag.audit",
|
||||
"tag.use_reserved_tag"
|
||||
],
|
||||
"type": "string",
|
||||
"description": "permission key",
|
||||
"name": "action",
|
||||
"in": "query",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/handler.RespBody"
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"data": {
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
"type": "boolean"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/answer/api/v1/personal/answer/page": {
|
||||
"get": {
|
||||
"security": [
|
||||
|
|
|
@ -4086,6 +4086,78 @@ paths:
|
|||
summary: DelRedDot
|
||||
tags:
|
||||
- Notification
|
||||
/answer/api/v1/permission:
|
||||
get:
|
||||
description: check user permission
|
||||
parameters:
|
||||
- description: access-token
|
||||
in: header
|
||||
name: Authorization
|
||||
required: true
|
||||
type: string
|
||||
- description: permission key
|
||||
enum:
|
||||
- question.add
|
||||
- question.edit
|
||||
- question.edit_without_review
|
||||
- question.delete
|
||||
- question.close
|
||||
- question.reopen
|
||||
- question.vote_up
|
||||
- question.vote_down
|
||||
- question.pin
|
||||
- question.unpin
|
||||
- question.hide
|
||||
- question.show
|
||||
- answer.add
|
||||
- answer.edit
|
||||
- answer.edit_without_review
|
||||
- answer.delete
|
||||
- answer.accept
|
||||
- answer.vote_up
|
||||
- answer.vote_down
|
||||
- answer.invite_someone_to_answer
|
||||
- comment.add
|
||||
- comment.edit
|
||||
- comment.delete
|
||||
- comment.vote_up
|
||||
- comment.vote_down
|
||||
- report.add
|
||||
- tag.add
|
||||
- tag.edit
|
||||
- tag.edit_slug_name
|
||||
- tag.edit_without_review
|
||||
- tag.delete
|
||||
- tag.synonym
|
||||
- link.url_limit
|
||||
- vote.detail
|
||||
- answer.audit
|
||||
- question.audit
|
||||
- tag.audit
|
||||
- tag.use_reserved_tag
|
||||
in: query
|
||||
name: action
|
||||
required: true
|
||||
type: string
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
allOf:
|
||||
- $ref: '#/definitions/handler.RespBody'
|
||||
- properties:
|
||||
data:
|
||||
additionalProperties:
|
||||
type: boolean
|
||||
type: object
|
||||
type: object
|
||||
security:
|
||||
- ApiKeyAuth: []
|
||||
summary: check user permission
|
||||
tags:
|
||||
- Permission
|
||||
/answer/api/v1/personal/answer/page:
|
||||
get:
|
||||
consumes:
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
# The following fields are used for back-end
|
||||
|
||||
backend:
|
||||
base:
|
||||
success:
|
||||
|
@ -184,7 +185,9 @@ backend:
|
|||
fail_to_meet_the_condition:
|
||||
other: Rank fail to meet the condition.
|
||||
vote_fail_to_meet_the_condition:
|
||||
other: Thanks for the feedback. You need at least {{ rank }} reputation to cast a vote.
|
||||
other: Thanks for the feedback. You need at least {{.Rank}} reputation to cast a vote.
|
||||
no_enough_rank_to_operate:
|
||||
other: You need at least {{.Rank}} reputation to do this.
|
||||
report:
|
||||
handle_failed:
|
||||
other: Report handle failed.
|
||||
|
@ -219,6 +222,8 @@ backend:
|
|||
no_permission:
|
||||
other: No permission to Revision.
|
||||
user:
|
||||
external_login_missing_user_id:
|
||||
other: The third-party platform does not provide a unique UserID, so you cannot login, please contact the website administrator.
|
||||
external_login_unbinding_forbidden:
|
||||
other: Please set a login password for your account before you remove this login.
|
||||
email_or_password_wrong:
|
||||
|
|
|
@ -178,7 +178,9 @@ backend:
|
|||
fail_to_meet_the_condition:
|
||||
other: 级别不符合条件
|
||||
vote_fail_to_meet_the_condition:
|
||||
other: 感谢您的投票。您至少需要{{ rank }}声望才能投票。
|
||||
other: 感谢您的投票。您至少需要{{.Rank}}声望才能投票。
|
||||
no_enough_rank_to_operate:
|
||||
other: 您至少需要{{.Rank}}声望才能执行此操作。
|
||||
report:
|
||||
handle_failed:
|
||||
other: 报告处理失败
|
||||
|
|
|
@ -38,3 +38,26 @@ const (
|
|||
// NotificationInvitedYouToAnswer invited you to answer
|
||||
NotificationInvitedYouToAnswer = "notification.action.invited_you_to_answer"
|
||||
)
|
||||
|
||||
var (
|
||||
NotificationMsgTypeMapping = map[string]int{
|
||||
NotificationUpdateQuestion: 1,
|
||||
NotificationAnswerTheQuestion: 1,
|
||||
NotificationUpVotedTheQuestion: 2,
|
||||
NotificationDownVotedTheQuestion: 2,
|
||||
NotificationUpdateAnswer: 1,
|
||||
NotificationAcceptAnswer: 1,
|
||||
NotificationUpVotedTheAnswer: 2,
|
||||
NotificationDownVotedTheAnswer: 2,
|
||||
NotificationCommentQuestion: 1,
|
||||
NotificationCommentAnswer: 1,
|
||||
NotificationUpVotedTheComment: 2,
|
||||
NotificationReplyToYou: 1,
|
||||
NotificationMentionYou: 1,
|
||||
NotificationYourQuestionIsClosed: 1,
|
||||
NotificationYourQuestionWasDeleted: 1,
|
||||
NotificationYourAnswerWasDeleted: 1,
|
||||
NotificationYourCommentWasDeleted: 1,
|
||||
NotificationInvitedYouToAnswer: 3,
|
||||
}
|
||||
)
|
||||
|
|
|
@ -16,64 +16,70 @@ const (
|
|||
)
|
||||
|
||||
const (
|
||||
EmailOrPasswordWrong = "error.object.email_or_password_incorrect"
|
||||
CommentNotFound = "error.comment.not_found"
|
||||
CommentCannotEditAfterDeadline = "error.comment.cannot_edit_after_deadline"
|
||||
QuestionNotFound = "error.question.not_found"
|
||||
QuestionCannotDeleted = "error.question.cannot_deleted"
|
||||
QuestionCannotClose = "error.question.cannot_close"
|
||||
QuestionCannotUpdate = "error.question.cannot_update"
|
||||
QuestionAlreadyDeleted = "error.question.already_deleted"
|
||||
AnswerNotFound = "error.answer.not_found"
|
||||
AnswerCannotDeleted = "error.answer.cannot_deleted"
|
||||
AnswerCannotUpdate = "error.answer.cannot_update"
|
||||
AnswerCannotAddByClosedQuestion = "error.answer.question_closed_cannot_add"
|
||||
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"
|
||||
EmailIllegalDomainError = "error.email.illegal_email_domain_error"
|
||||
UserSuspended = "error.user.suspended"
|
||||
ObjectNotFound = "error.object.not_found"
|
||||
TagNotFound = "error.tag.not_found"
|
||||
TagNotContainSynonym = "error.tag.not_contain_synonym_tags"
|
||||
TagCannotUpdate = "error.tag.cannot_update"
|
||||
TagIsUsedCannotDelete = "error.tag.is_used_cannot_delete"
|
||||
TagAlreadyExist = "error.tag.already_exist"
|
||||
RankFailToMeetTheCondition = "error.rank.fail_to_meet_the_condition"
|
||||
VoteRankFailToMeetTheCondition = "error.rank.vote_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"
|
||||
UploadFileUnsupportedFileFormat = "error.upload.unsupported_file_format"
|
||||
RecommendTagNotExist = "error.tag.recommend_tag_not_found"
|
||||
RecommendTagEnter = "error.tag.recommend_tag_enter"
|
||||
RevisionReviewUnderway = "error.revision.review_underway"
|
||||
RevisionNoPermission = "error.revision.no_permission"
|
||||
UserCannotUpdateYourRole = "error.user.cannot_update_your_role"
|
||||
TagCannotSetSynonymAsItself = "error.tag.cannot_set_synonym_as_itself"
|
||||
NotAllowedRegistration = "error.user.not_allowed_registration"
|
||||
SMTPConfigFromNameCannotBeEmail = "error.smtp.config_from_name_cannot_be_email"
|
||||
AdminCannotUpdateTheirPassword = "error.admin.cannot_update_their_password"
|
||||
AdminCannotModifySelfStatus = "error.admin.cannot_modify_self_status"
|
||||
UserExternalLoginUnbindingForbidden = "error.user.external_login_unbinding_forbidden"
|
||||
UserAccessDenied = "error.user.access_denied"
|
||||
UserPageAccessDenied = "error.user.page_access_denied"
|
||||
EmailOrPasswordWrong = "error.object.email_or_password_incorrect"
|
||||
CommentNotFound = "error.comment.not_found"
|
||||
CommentCannotEditAfterDeadline = "error.comment.cannot_edit_after_deadline"
|
||||
QuestionNotFound = "error.question.not_found"
|
||||
QuestionCannotDeleted = "error.question.cannot_deleted"
|
||||
QuestionCannotClose = "error.question.cannot_close"
|
||||
QuestionCannotUpdate = "error.question.cannot_update"
|
||||
QuestionAlreadyDeleted = "error.question.already_deleted"
|
||||
AnswerNotFound = "error.answer.not_found"
|
||||
AnswerCannotDeleted = "error.answer.cannot_deleted"
|
||||
AnswerCannotUpdate = "error.answer.cannot_update"
|
||||
AnswerCannotAddByClosedQuestion = "error.answer.question_closed_cannot_add"
|
||||
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"
|
||||
EmailIllegalDomainError = "error.email.illegal_email_domain_error"
|
||||
UserSuspended = "error.user.suspended"
|
||||
ObjectNotFound = "error.object.not_found"
|
||||
TagNotFound = "error.tag.not_found"
|
||||
TagNotContainSynonym = "error.tag.not_contain_synonym_tags"
|
||||
TagCannotUpdate = "error.tag.cannot_update"
|
||||
TagIsUsedCannotDelete = "error.tag.is_used_cannot_delete"
|
||||
TagAlreadyExist = "error.tag.already_exist"
|
||||
RankFailToMeetTheCondition = "error.rank.fail_to_meet_the_condition"
|
||||
VoteRankFailToMeetTheCondition = "error.rank.vote_fail_to_meet_the_condition"
|
||||
NoEnoughRankToOperate = "error.rank.no_enough_rank_to_operate"
|
||||
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"
|
||||
UploadFileUnsupportedFileFormat = "error.upload.unsupported_file_format"
|
||||
RecommendTagNotExist = "error.tag.recommend_tag_not_found"
|
||||
RecommendTagEnter = "error.tag.recommend_tag_enter"
|
||||
RevisionReviewUnderway = "error.revision.review_underway"
|
||||
RevisionNoPermission = "error.revision.no_permission"
|
||||
UserCannotUpdateYourRole = "error.user.cannot_update_your_role"
|
||||
TagCannotSetSynonymAsItself = "error.tag.cannot_set_synonym_as_itself"
|
||||
NotAllowedRegistration = "error.user.not_allowed_registration"
|
||||
SMTPConfigFromNameCannotBeEmail = "error.smtp.config_from_name_cannot_be_email"
|
||||
AdminCannotUpdateTheirPassword = "error.admin.cannot_update_their_password"
|
||||
AdminCannotModifySelfStatus = "error.admin.cannot_modify_self_status"
|
||||
UserAccessDenied = "error.user.access_denied"
|
||||
UserPageAccessDenied = "error.user.page_access_denied"
|
||||
)
|
||||
|
||||
// user external login reasons
|
||||
const (
|
||||
UserExternalLoginUnbindingForbidden = "error.user.external_login_unbinding_forbidden"
|
||||
UserExternalLoginMissingUserID = "error.user.external_login_missing_user_id"
|
||||
)
|
||||
|
|
|
@ -26,4 +26,5 @@ var ProviderSetController = wire.NewSet(
|
|||
NewTemplateController,
|
||||
NewConnectorController,
|
||||
NewUserCenterController,
|
||||
NewPermissionController,
|
||||
)
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
package controller
|
|
@ -0,0 +1,51 @@
|
|||
package controller
|
||||
|
||||
import (
|
||||
"github.com/answerdev/answer/internal/base/handler"
|
||||
"github.com/answerdev/answer/internal/base/middleware"
|
||||
"github.com/answerdev/answer/internal/schema"
|
||||
"github.com/answerdev/answer/internal/service/rank"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
type PermissionController struct {
|
||||
rankService *rank.RankService
|
||||
}
|
||||
|
||||
// NewPermissionController new language controller.
|
||||
func NewPermissionController(rankService *rank.RankService) *PermissionController {
|
||||
return &PermissionController{rankService: rankService}
|
||||
}
|
||||
|
||||
// GetPermission check user permission
|
||||
// @Summary check user permission
|
||||
// @Description check user permission
|
||||
// @Tags Permission
|
||||
// @Security ApiKeyAuth
|
||||
// @Param Authorization header string true "access-token"
|
||||
// @Produce json
|
||||
// @Param action query string true "permission key" Enums(question.add, question.edit, question.edit_without_review, question.delete, question.close, question.reopen, question.vote_up, question.vote_down, question.pin, question.unpin, question.hide, question.show, answer.add, answer.edit, answer.edit_without_review, answer.delete, answer.accept, answer.vote_up, answer.vote_down, answer.invite_someone_to_answer, comment.add, comment.edit, comment.delete, comment.vote_up, comment.vote_down, report.add, tag.add, tag.edit, tag.edit_slug_name, tag.edit_without_review, tag.delete, tag.synonym, link.url_limit, vote.detail, answer.audit, question.audit, tag.audit, tag.use_reserved_tag)
|
||||
// @Success 200 {object} handler.RespBody{data=map[string]bool}
|
||||
// @Router /answer/api/v1/permission [get]
|
||||
func (u *PermissionController) GetPermission(ctx *gin.Context) {
|
||||
req := &schema.GetPermissionReq{}
|
||||
if handler.BindAndCheck(ctx, req) {
|
||||
return
|
||||
}
|
||||
|
||||
userID := middleware.GetLoginUserIDFromContext(ctx)
|
||||
ops, requireRanks, err := u.rankService.CheckOperationPermissionsForRanks(ctx, userID, req.Actions)
|
||||
if err != nil {
|
||||
handler.HandleResponse(ctx, err, nil)
|
||||
return
|
||||
}
|
||||
|
||||
lang := handler.GetLangByCtx(ctx)
|
||||
mapping := make(map[string]*schema.GetPermissionResp, len(ops))
|
||||
for i, action := range req.Actions {
|
||||
t := &schema.GetPermissionResp{HasPermission: ops[i]}
|
||||
t.TrTip(lang, requireRanks[i])
|
||||
mapping[action] = t
|
||||
}
|
||||
handler.HandleResponse(ctx, err, mapping)
|
||||
}
|
|
@ -5,6 +5,7 @@ import (
|
|||
"github.com/answerdev/answer/internal/base/middleware"
|
||||
"github.com/answerdev/answer/internal/base/pager"
|
||||
"github.com/answerdev/answer/internal/base/reason"
|
||||
"github.com/answerdev/answer/internal/base/translator"
|
||||
"github.com/answerdev/answer/internal/base/validator"
|
||||
"github.com/answerdev/answer/internal/entity"
|
||||
"github.com/answerdev/answer/internal/schema"
|
||||
|
@ -306,13 +307,14 @@ func (qc *QuestionController) AddQuestion(ctx *gin.Context) {
|
|||
}
|
||||
req.UserID = middleware.GetLoginUserIDFromContext(ctx)
|
||||
|
||||
canList, err := qc.rankService.CheckOperationPermissions(ctx, req.UserID, []string{
|
||||
canList, requireRanks, err := qc.rankService.CheckOperationPermissionsForRanks(ctx, req.UserID, []string{
|
||||
permission.QuestionAdd,
|
||||
permission.QuestionEdit,
|
||||
permission.QuestionDelete,
|
||||
permission.QuestionClose,
|
||||
permission.QuestionReopen,
|
||||
permission.TagUseReservedTag,
|
||||
permission.TagAdd,
|
||||
})
|
||||
if err != nil {
|
||||
handler.HandleResponse(ctx, err, nil)
|
||||
|
@ -324,11 +326,25 @@ func (qc *QuestionController) AddQuestion(ctx *gin.Context) {
|
|||
req.CanClose = canList[3]
|
||||
req.CanReopen = canList[4]
|
||||
req.CanUseReservedTag = canList[5]
|
||||
req.CanAddTag = canList[6]
|
||||
if !req.CanAdd {
|
||||
handler.HandleResponse(ctx, errors.Forbidden(reason.RankFailToMeetTheCondition), nil)
|
||||
return
|
||||
}
|
||||
|
||||
// can add tag
|
||||
hasNewTag, err := qc.questionService.HasNewTag(ctx, req.Tags)
|
||||
if err != nil {
|
||||
handler.HandleResponse(ctx, err, nil)
|
||||
return
|
||||
}
|
||||
if !req.CanAddTag && hasNewTag {
|
||||
lang := handler.GetLang(ctx)
|
||||
msg := translator.TrWithData(lang, reason.NoEnoughRankToOperate, &schema.PermissionTrTplData{Rank: requireRanks[6]})
|
||||
handler.HandleResponse(ctx, errors.Forbidden(reason.NoEnoughRankToOperate).WithMsg(msg), nil)
|
||||
return
|
||||
}
|
||||
|
||||
errList, err := qc.questionService.CheckAddQuestion(ctx, req)
|
||||
if err != nil {
|
||||
errlist, ok := errList.([]*validator.FormErrorField)
|
||||
|
@ -480,11 +496,12 @@ func (qc *QuestionController) UpdateQuestion(ctx *gin.Context) {
|
|||
req.ID = uid.DeShortID(req.ID)
|
||||
req.UserID = middleware.GetLoginUserIDFromContext(ctx)
|
||||
|
||||
canList, err := qc.rankService.CheckOperationPermissions(ctx, req.UserID, []string{
|
||||
canList, requireRanks, err := qc.rankService.CheckOperationPermissionsForRanks(ctx, req.UserID, []string{
|
||||
permission.QuestionEdit,
|
||||
permission.QuestionDelete,
|
||||
permission.QuestionEditWithoutReview,
|
||||
permission.TagUseReservedTag,
|
||||
permission.TagAdd,
|
||||
})
|
||||
if err != nil {
|
||||
handler.HandleResponse(ctx, err, nil)
|
||||
|
@ -496,6 +513,7 @@ func (qc *QuestionController) UpdateQuestion(ctx *gin.Context) {
|
|||
req.CanDelete = canList[1]
|
||||
req.NoNeedReview = canList[2] || objectOwner
|
||||
req.CanUseReservedTag = canList[3]
|
||||
req.CanAddTag = canList[4]
|
||||
if !req.CanEdit {
|
||||
handler.HandleResponse(ctx, errors.Forbidden(reason.RankFailToMeetTheCondition), nil)
|
||||
return
|
||||
|
@ -511,6 +529,19 @@ func (qc *QuestionController) UpdateQuestion(ctx *gin.Context) {
|
|||
return
|
||||
}
|
||||
|
||||
// can add tag
|
||||
hasNewTag, err := qc.questionService.HasNewTag(ctx, req.Tags)
|
||||
if err != nil {
|
||||
handler.HandleResponse(ctx, err, nil)
|
||||
return
|
||||
}
|
||||
if !req.CanAddTag && hasNewTag {
|
||||
lang := handler.GetLang(ctx)
|
||||
msg := translator.TrWithData(lang, reason.NoEnoughRankToOperate, &schema.PermissionTrTplData{Rank: requireRanks[4]})
|
||||
handler.HandleResponse(ctx, errors.Forbidden(reason.NoEnoughRankToOperate).WithMsg(msg), nil)
|
||||
return
|
||||
}
|
||||
|
||||
resp, err := qc.questionService.UpdateQuestion(ctx, req)
|
||||
if err != nil {
|
||||
handler.HandleResponse(ctx, err, resp)
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
package controller
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/answerdev/answer/internal/base/handler"
|
||||
"github.com/answerdev/answer/internal/base/middleware"
|
||||
"github.com/answerdev/answer/internal/base/reason"
|
||||
|
@ -44,16 +42,15 @@ func (vc *VoteController) VoteUp(ctx *gin.Context) {
|
|||
}
|
||||
req.ObjectID = uid.DeShortID(req.ObjectID)
|
||||
req.UserID = middleware.GetLoginUserIDFromContext(ctx)
|
||||
can, rank, err := vc.rankService.CheckVotePermission(ctx, req.UserID, req.ObjectID, true)
|
||||
can, needRank, err := vc.rankService.CheckVotePermission(ctx, req.UserID, req.ObjectID, true)
|
||||
if err != nil {
|
||||
handler.HandleResponse(ctx, err, nil)
|
||||
return
|
||||
}
|
||||
if !can {
|
||||
lang := handler.GetLang(ctx)
|
||||
msg := translator.Tr(lang, reason.VoteRankFailToMeetTheCondition)
|
||||
msg = handler.MsgWithParameter(msg, map[string]string{"rank": fmt.Sprintf("%d", rank)})
|
||||
handler.HandleResponse(ctx, errors.Forbidden(reason.VoteRankFailToMeetTheCondition).WithMsg(msg), nil)
|
||||
msg := translator.TrWithData(lang, reason.NoEnoughRankToOperate, &schema.PermissionTrTplData{Rank: needRank})
|
||||
handler.HandleResponse(ctx, errors.Forbidden(reason.NoEnoughRankToOperate).WithMsg(msg), nil)
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -84,16 +81,15 @@ func (vc *VoteController) VoteDown(ctx *gin.Context) {
|
|||
}
|
||||
req.ObjectID = uid.DeShortID(req.ObjectID)
|
||||
req.UserID = middleware.GetLoginUserIDFromContext(ctx)
|
||||
can, rank, err := vc.rankService.CheckVotePermission(ctx, req.UserID, req.ObjectID, false)
|
||||
can, needRank, err := vc.rankService.CheckVotePermission(ctx, req.UserID, req.ObjectID, false)
|
||||
if err != nil {
|
||||
handler.HandleResponse(ctx, err, nil)
|
||||
return
|
||||
}
|
||||
if !can {
|
||||
lang := handler.GetLang(ctx)
|
||||
msg := translator.Tr(lang, reason.VoteRankFailToMeetTheCondition)
|
||||
msg = handler.MsgWithParameter(msg, map[string]string{"rank": fmt.Sprintf("%d", rank)})
|
||||
handler.HandleResponse(ctx, errors.Forbidden(reason.VoteRankFailToMeetTheCondition).WithMsg(msg), nil)
|
||||
msg := translator.TrWithData(lang, reason.NoEnoughRankToOperate, &schema.PermissionTrTplData{Rank: needRank})
|
||||
handler.HandleResponse(ctx, errors.Forbidden(reason.NoEnoughRankToOperate).WithMsg(msg), nil)
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
@ -11,6 +11,7 @@ type Notification struct {
|
|||
ObjectID string `xorm:"not null default 0 INDEX BIGINT(20) object_id"`
|
||||
Content string `xorm:"not null TEXT content"`
|
||||
Type int `xorm:"not null default 0 INT(11) type"`
|
||||
MsgType int `xorm:"not null default 0 INT(11) msg_type"`
|
||||
IsRead int `xorm:"not null default 1 INT(11) is_read"`
|
||||
Status int `xorm:"not null default 1 INT(11) status"`
|
||||
}
|
||||
|
|
|
@ -21,6 +21,7 @@ func updateCount(x *xorm.Engine) error {
|
|||
updateUserQuestionCount(x)
|
||||
updateUserAnswerCount(x)
|
||||
inviteAnswer(x)
|
||||
inBoxData(x)
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -337,3 +338,44 @@ func inviteAnswer(x *xorm.Engine) error {
|
|||
|
||||
return nil
|
||||
}
|
||||
|
||||
// inBoxData Classify messages
|
||||
func inBoxData(x *xorm.Engine) error {
|
||||
type Notification struct {
|
||||
ID string `xorm:"not null pk autoincr BIGINT(20) id"`
|
||||
CreatedAt time.Time `xorm:"created TIMESTAMP created_at"`
|
||||
UpdatedAt time.Time `xorm:"TIMESTAMP updated_at"`
|
||||
UserID string `xorm:"not null default 0 BIGINT(20) INDEX user_id"`
|
||||
ObjectID string `xorm:"not null default 0 INDEX BIGINT(20) object_id"`
|
||||
Content string `xorm:"not null TEXT content"`
|
||||
Type int `xorm:"not null default 0 INT(11) type"`
|
||||
MsgType int `xorm:"not null default 0 INT(11) msg_type"`
|
||||
IsRead int `xorm:"not null default 1 INT(11) is_read"`
|
||||
Status int `xorm:"not null default 1 INT(11) status"`
|
||||
}
|
||||
err := x.Sync(new(Notification))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
msglist := make([]entity.Notification, 0)
|
||||
err = x.Find(&msglist, &entity.Notification{})
|
||||
if err != nil {
|
||||
return fmt.Errorf("get Notification failed: %w", err)
|
||||
}
|
||||
for _, v := range msglist {
|
||||
Content := &schema.NotificationContent{}
|
||||
err := json.Unmarshal([]byte(v.Content), Content)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
_, ok := constant.NotificationMsgTypeMapping[Content.NotificationAction]
|
||||
if ok {
|
||||
v.MsgType = constant.NotificationMsgTypeMapping[Content.NotificationAction]
|
||||
if _, err = x.Update(v, &entity.Notification{ID: v.ID}); err != nil {
|
||||
log.Errorf("update %+v Notification failed: %s", v.ID, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -323,7 +323,7 @@ func (ar *answerRepo) AdminSearchList(ctx context.Context, search *entity.AdminA
|
|||
|
||||
offset := search.Page * search.PageSize
|
||||
session.
|
||||
OrderBy("a.updated_at desc").
|
||||
OrderBy("a.created_at desc").
|
||||
Limit(search.PageSize, offset)
|
||||
count, err = session.FindAndCount(&rows)
|
||||
if err != nil {
|
||||
|
|
|
@ -96,10 +96,14 @@ func (nr *notificationRepo) GetNotificationPage(ctx context.Context, searchCond
|
|||
|
||||
session := nr.data.DB.Context(ctx)
|
||||
session = session.Desc("updated_at")
|
||||
|
||||
cond := &entity.Notification{
|
||||
UserID: searchCond.UserID,
|
||||
Type: searchCond.Type,
|
||||
}
|
||||
if searchCond.InboxType > 0 {
|
||||
cond.MsgType = searchCond.InboxType
|
||||
}
|
||||
total, err = pager.Help(searchCond.Page, searchCond.PageSize, ¬ificationList, cond, session)
|
||||
if err != nil {
|
||||
err = errors.InternalServer(reason.DatabaseError).WithError(err).WithStack()
|
||||
|
|
|
@ -371,7 +371,7 @@ func (qr *questionRepo) AdminSearchList(ctx context.Context, search *schema.Admi
|
|||
|
||||
offset := search.Page * search.PageSize
|
||||
|
||||
session.OrderBy("updated_at desc").
|
||||
session.OrderBy("created_at desc").
|
||||
Limit(search.PageSize, offset)
|
||||
count, err = session.FindAndCount(&rows)
|
||||
if err != nil {
|
||||
|
|
|
@ -33,6 +33,7 @@ type AnswerAPIRouter struct {
|
|||
activityController *controller.ActivityController
|
||||
roleController *controller_admin.RoleController
|
||||
pluginController *controller_admin.PluginController
|
||||
permissionController *controller.PermissionController
|
||||
}
|
||||
|
||||
func NewAnswerAPIRouter(
|
||||
|
@ -61,6 +62,7 @@ func NewAnswerAPIRouter(
|
|||
activityController *controller.ActivityController,
|
||||
roleController *controller_admin.RoleController,
|
||||
pluginController *controller_admin.PluginController,
|
||||
permissionController *controller.PermissionController,
|
||||
) *AnswerAPIRouter {
|
||||
return &AnswerAPIRouter{
|
||||
langController: langController,
|
||||
|
@ -88,6 +90,7 @@ func NewAnswerAPIRouter(
|
|||
activityController: activityController,
|
||||
roleController: roleController,
|
||||
pluginController: pluginController,
|
||||
permissionController: permissionController,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -220,6 +223,9 @@ func (a *AnswerAPIRouter) RegisterAnswerAPIRouter(r *gin.RouterGroup) {
|
|||
// reason
|
||||
r.GET("/reasons", a.reasonController.Reasons)
|
||||
|
||||
// permission
|
||||
r.GET("/permission", a.permissionController.GetPermission)
|
||||
|
||||
// notification
|
||||
r.GET("/notification/status", a.notificationController.GetRedDot)
|
||||
r.PUT("/notification/status", a.notificationController.ClearRedDot)
|
||||
|
|
|
@ -7,10 +7,10 @@ const (
|
|||
NotificationRead = 2
|
||||
NotificationStatusNormal = 1
|
||||
NotificationStatusDelete = 10
|
||||
NotificationInboxTypeAll = 1
|
||||
NotificationInboxTypePosts = 2
|
||||
NotificationInboxTypeAll = 0
|
||||
NotificationInboxTypePosts = 1
|
||||
NotificationInboxTypeVotes = 2
|
||||
NotificationInboxTypeInvites = 3
|
||||
NotificationInboxTypeVotes = 4
|
||||
)
|
||||
|
||||
var NotificationType = map[string]int{
|
||||
|
|
|
@ -1,7 +1,18 @@
|
|||
package schema
|
||||
|
||||
const PermissionMemberActionTypeEdit = "edit"
|
||||
const PermissionMemberActionTypeReason = "reason"
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/answerdev/answer/internal/base/reason"
|
||||
"github.com/answerdev/answer/internal/base/translator"
|
||||
"github.com/answerdev/answer/internal/base/validator"
|
||||
"github.com/segmentfault/pacman/i18n"
|
||||
)
|
||||
|
||||
// PermissionTrTplData template data as for translate permission message
|
||||
type PermissionTrTplData struct {
|
||||
Rank int
|
||||
}
|
||||
|
||||
// PermissionMemberAction permission member action
|
||||
type PermissionMemberAction struct {
|
||||
|
@ -9,3 +20,35 @@ type PermissionMemberAction struct {
|
|||
Name string `json:"name"`
|
||||
Type string `json:"type"`
|
||||
}
|
||||
|
||||
// GetPermissionReq get permission request
|
||||
type GetPermissionReq struct {
|
||||
Action string `form:"action"`
|
||||
Actions []string `validate:"omitempty" form:"actions"`
|
||||
}
|
||||
|
||||
func (r *GetPermissionReq) Check() (errField []*validator.FormErrorField, err error) {
|
||||
if len(r.Action) > 0 {
|
||||
r.Actions = strings.Split(r.Action, ",")
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// GetPermissionResp get permission response
|
||||
type GetPermissionResp struct {
|
||||
HasPermission bool `json:"has_permission"`
|
||||
// only not allow, will return this tip
|
||||
NoPermissionTip string `json:"no_permission_tip"`
|
||||
}
|
||||
|
||||
func (r *GetPermissionResp) TrTip(lang i18n.Language, requireRank int) {
|
||||
if r.HasPermission {
|
||||
return
|
||||
}
|
||||
if requireRank <= 0 {
|
||||
r.NoPermissionTip = translator.Tr(lang, reason.RankFailToMeetTheCondition)
|
||||
} else {
|
||||
r.NoPermissionTip = translator.TrWithData(
|
||||
lang, reason.NoEnoughRankToOperate, &PermissionTrTplData{Rank: requireRank})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -124,6 +124,7 @@ type QuestionPermission struct {
|
|||
CanUseReservedTag bool `json:"-"`
|
||||
// whether user can invite other user to answer this question
|
||||
CanInviteOtherToAnswer bool `json:"-"`
|
||||
CanAddTag bool `json:"-"`
|
||||
}
|
||||
|
||||
type CheckCanQuestionUpdate struct {
|
||||
|
|
|
@ -100,13 +100,15 @@ func (r *GetUserToSetShowResp) GetFromUserEntity(userInfo *entity.User) {
|
|||
if ok {
|
||||
r.Status = statusShow
|
||||
}
|
||||
|
||||
avatarInfo := &AvatarInfo{}
|
||||
_ = json.Unmarshal([]byte(userInfo.Avatar), avatarInfo)
|
||||
if constant.DefaultAvatar == "gravatar" && avatarInfo.Type == "" {
|
||||
avatarInfo.Type = "gravatar"
|
||||
if len(avatarInfo.Type) == 0 && constant.DefaultAvatar == AvatarTypeGravatar {
|
||||
avatarInfo.Type = AvatarTypeGravatar
|
||||
avatarInfo.Gravatar = gravatar.GetAvatarURL(userInfo.EMail)
|
||||
} else if avatarInfo.Type == AvatarTypeGravatar {
|
||||
avatarInfo.Gravatar = gravatar.GetAvatarURL(userInfo.EMail)
|
||||
}
|
||||
// if json.Unmarshal Error avatarInfo.Type is Empty
|
||||
r.Avatar = avatarInfo
|
||||
}
|
||||
|
||||
|
@ -118,7 +120,7 @@ const (
|
|||
|
||||
func FormatAvatarInfo(avatarJson, email string) (res string) {
|
||||
defer func() {
|
||||
if constant.DefaultAvatar == "gravatar" && len(res) == 0 {
|
||||
if constant.DefaultAvatar == AvatarTypeGravatar && len(res) == 0 {
|
||||
res = gravatar.GetAvatarURL(email)
|
||||
}
|
||||
}()
|
||||
|
@ -133,7 +135,7 @@ func FormatAvatarInfo(avatarJson, email string) (res string) {
|
|||
}
|
||||
switch avatarInfo.Type {
|
||||
case AvatarTypeGravatar:
|
||||
return avatarInfo.Gravatar
|
||||
return gravatar.GetAvatarURL(email)
|
||||
case AvatarTypeCustom:
|
||||
return avatarInfo.Custom
|
||||
default:
|
||||
|
|
|
@ -125,9 +125,9 @@ func (ns *NotificationService) GetNotificationPage(ctx context.Context, searchCo
|
|||
}
|
||||
searchInboxType := schema.NotificationInboxTypeAll
|
||||
if searchType == schema.NotificationTypeInbox {
|
||||
searchInboxType, ok = schema.NotificationInboxType[searchCond.InboxTypeStr]
|
||||
if !ok {
|
||||
return pager.NewPageModel(0, resp), nil
|
||||
_, ok = schema.NotificationInboxType[searchCond.InboxTypeStr]
|
||||
if ok {
|
||||
searchInboxType = schema.NotificationInboxType[searchCond.InboxTypeStr]
|
||||
}
|
||||
}
|
||||
searchCond.Type = searchType
|
||||
|
|
|
@ -114,11 +114,11 @@ func (ns *NotificationCommon) AddNotification(ctx context.Context, msg *schema.N
|
|||
if msg.Type == schema.NotificationTypeAchievement {
|
||||
notificationInfo, exist, err := ns.notificationRepo.GetByUserIdObjectIdTypeId(ctx, req.ReceiverUserID, req.ObjectInfo.ObjectID, req.Type)
|
||||
if err != nil {
|
||||
return errors.InternalServer(reason.UnknownError).WithError(err).WithStack()
|
||||
return fmt.Errorf("get by user id object id type id error: %w", err)
|
||||
}
|
||||
rank, err := ns.activityRepo.GetUserIDObjectIDActivitySum(ctx, req.ReceiverUserID, req.ObjectInfo.ObjectID)
|
||||
if err != nil {
|
||||
return errors.InternalServer(reason.UnknownError).WithError(err).WithStack()
|
||||
return fmt.Errorf("get user id object id activity sum error: %w", err)
|
||||
}
|
||||
req.Rank = rank
|
||||
if exist {
|
||||
|
@ -126,17 +126,14 @@ func (ns *NotificationCommon) AddNotification(ctx context.Context, msg *schema.N
|
|||
updateContent := &schema.NotificationContent{}
|
||||
err := json.Unmarshal([]byte(notificationInfo.Content), updateContent)
|
||||
if err != nil {
|
||||
return errors.InternalServer(reason.UnknownError).WithError(err).WithStack()
|
||||
return fmt.Errorf("unmarshal notification content error: %w", err)
|
||||
}
|
||||
updateContent.Rank = rank
|
||||
content, err := json.Marshal(updateContent)
|
||||
if err != nil {
|
||||
return errors.InternalServer(reason.UnknownError).WithError(err).WithStack()
|
||||
}
|
||||
content, _ := json.Marshal(updateContent)
|
||||
notificationInfo.Content = string(content)
|
||||
err = ns.notificationRepo.UpdateNotificationContent(ctx, notificationInfo)
|
||||
if err != nil {
|
||||
return errors.InternalServer(reason.UnknownError).WithError(err).WithStack()
|
||||
return fmt.Errorf("update notification content error: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
@ -154,20 +151,21 @@ func (ns *NotificationCommon) AddNotification(ctx context.Context, msg *schema.N
|
|||
|
||||
userBasicInfo, exist, err := ns.userCommon.GetUserBasicInfoByID(ctx, req.TriggerUserID)
|
||||
if err != nil {
|
||||
return errors.InternalServer(reason.UnknownError).WithError(err).WithStack()
|
||||
return fmt.Errorf("get user basic info error: %w", err)
|
||||
}
|
||||
if !exist {
|
||||
return errors.InternalServer(reason.UserNotFound).WithError(err).WithStack()
|
||||
return fmt.Errorf("user not exist: %s", req.TriggerUserID)
|
||||
}
|
||||
req.UserInfo = userBasicInfo
|
||||
content, err := json.Marshal(req)
|
||||
if err != nil {
|
||||
return errors.InternalServer(reason.UnknownError).WithError(err).WithStack()
|
||||
content, _ := json.Marshal(req)
|
||||
_, ok := constant.NotificationMsgTypeMapping[req.NotificationAction]
|
||||
if ok {
|
||||
info.MsgType = constant.NotificationMsgTypeMapping[req.NotificationAction]
|
||||
}
|
||||
info.Content = string(content)
|
||||
err = ns.notificationRepo.AddNotification(ctx, info)
|
||||
if err != nil {
|
||||
return errors.InternalServer(reason.UnknownError).WithError(err).WithStack()
|
||||
return fmt.Errorf("add notification error: %w", err)
|
||||
}
|
||||
err = ns.addRedDot(ctx, info.UserID, info.Type)
|
||||
if err != nil {
|
||||
|
|
|
@ -200,6 +200,11 @@ func (qs *QuestionService) CheckAddQuestion(ctx context.Context, req *schema.Que
|
|||
return nil, nil
|
||||
}
|
||||
|
||||
// HasNewTag
|
||||
func (qs *QuestionService) HasNewTag(ctx context.Context, tags []*schema.TagItem) (bool, error) {
|
||||
return qs.tagCommon.HasNewTag(ctx, tags)
|
||||
}
|
||||
|
||||
// AddQuestion add question
|
||||
func (qs *QuestionService) AddQuestion(ctx context.Context, req *schema.QuestionAdd) (questionInfo any, err error) {
|
||||
if len(req.Tags) == 0 {
|
||||
|
|
|
@ -95,21 +95,22 @@ func (rs *RankService) CheckOperationPermission(ctx context.Context, userID stri
|
|||
return can, nil
|
||||
}
|
||||
|
||||
// CheckOperationPermissions verify that the user has permission
|
||||
func (rs *RankService) CheckOperationPermissions(ctx context.Context, userID string, actions []string) (
|
||||
can []bool, err error) {
|
||||
// CheckOperationPermissionsForRanks verify that the user has permission
|
||||
func (rs *RankService) CheckOperationPermissionsForRanks(ctx context.Context, userID string, actions []string) (
|
||||
can []bool, requireRanks []int, err error) {
|
||||
can = make([]bool, len(actions))
|
||||
requireRanks = make([]int, len(actions))
|
||||
if len(userID) == 0 {
|
||||
return can, nil
|
||||
return can, requireRanks, nil
|
||||
}
|
||||
|
||||
// get the rank of the current user
|
||||
userInfo, exist, err := rs.userCommon.GetUserBasicInfoByID(ctx, userID)
|
||||
if err != nil {
|
||||
return can, err
|
||||
return can, requireRanks, err
|
||||
}
|
||||
if !exist {
|
||||
return can, nil
|
||||
return can, requireRanks, nil
|
||||
}
|
||||
|
||||
powerMapping := rs.getUserPowerMapping(ctx, userID)
|
||||
|
@ -118,10 +119,18 @@ func (rs *RankService) CheckOperationPermissions(ctx context.Context, userID str
|
|||
can[idx] = true
|
||||
continue
|
||||
}
|
||||
meetRank, _ := rs.checkUserRank(ctx, userInfo.ID, userInfo.Rank, PermissionPrefix+action)
|
||||
meetRank, requireRank := rs.checkUserRank(ctx, userInfo.ID, userInfo.Rank, PermissionPrefix+action)
|
||||
can[idx] = meetRank
|
||||
requireRanks[idx] = requireRank
|
||||
}
|
||||
return can, nil
|
||||
return can, requireRanks, nil
|
||||
}
|
||||
|
||||
// CheckOperationPermissions verify that the user has permission
|
||||
func (rs *RankService) CheckOperationPermissions(ctx context.Context, userID string, actions []string) (
|
||||
can []bool, err error) {
|
||||
can, _, err = rs.CheckOperationPermissionsForRanks(ctx, userID, actions)
|
||||
return can, err
|
||||
}
|
||||
|
||||
// CheckOperationObjectOwner check operation object owner
|
||||
|
@ -142,7 +151,7 @@ func (rs *RankService) CheckOperationObjectOwner(ctx context.Context, userID, ob
|
|||
|
||||
// CheckVotePermission verify that the user has vote permission
|
||||
func (rs *RankService) CheckVotePermission(ctx context.Context, userID, objectID string, voteUp bool) (
|
||||
can bool, rank int, err error) {
|
||||
can bool, needRank int, err error) {
|
||||
if len(userID) == 0 || len(objectID) == 0 {
|
||||
return false, 0, nil
|
||||
}
|
||||
|
@ -180,13 +189,12 @@ func (rs *RankService) CheckVotePermission(ctx context.Context, userID, objectID
|
|||
action = permission.CommentVoteDown
|
||||
}
|
||||
}
|
||||
meetRank, rank := rs.checkUserRank(ctx, userInfo.ID, userInfo.Rank, PermissionPrefix+action)
|
||||
powerMapping := rs.getUserPowerMapping(ctx, userID)
|
||||
if powerMapping[action] {
|
||||
return true, rank, nil
|
||||
return true, 0, nil
|
||||
}
|
||||
|
||||
return meetRank, rank, nil
|
||||
can, needRank = rs.checkUserRank(ctx, userInfo.ID, userInfo.Rank, PermissionPrefix+action)
|
||||
return can, needRank, nil
|
||||
}
|
||||
|
||||
// getUserPowerMapping get user power mapping
|
||||
|
|
|
@ -247,6 +247,32 @@ func (ts *TagCommonService) ExistRecommend(ctx context.Context, tags []*schema.T
|
|||
return false, nil
|
||||
}
|
||||
|
||||
func (ts *TagCommonService) HasNewTag(ctx context.Context, tags []*schema.TagItem) (bool, error) {
|
||||
tagNames := make([]string, 0)
|
||||
tagMap := make(map[string]bool)
|
||||
for _, item := range tags {
|
||||
item.SlugName = strings.ReplaceAll(item.SlugName, " ", "-")
|
||||
tagNames = append(tagNames, item.SlugName)
|
||||
tagMap[item.SlugName] = false
|
||||
}
|
||||
list, err := ts.GetTagListByNames(ctx, tagNames)
|
||||
if err != nil {
|
||||
return true, err
|
||||
}
|
||||
for _, item := range list {
|
||||
_, ok := tagMap[item.SlugName]
|
||||
if ok {
|
||||
tagMap[item.SlugName] = true
|
||||
}
|
||||
}
|
||||
for _, has := range tagMap {
|
||||
if !has {
|
||||
return true, nil
|
||||
}
|
||||
}
|
||||
return false, nil
|
||||
}
|
||||
|
||||
// GetObjectTag get object tag
|
||||
func (ts *TagCommonService) GetObjectTag(ctx context.Context, objectId string) (objTags []*schema.TagResp, err error) {
|
||||
tagsInfoList, err := ts.GetObjectEntityTag(ctx, objectId)
|
||||
|
|
|
@ -49,6 +49,12 @@ func NewUserCenterLoginService(
|
|||
func (us *UserCenterLoginService) ExternalLogin(
|
||||
ctx context.Context, userCenter plugin.UserCenter, basicUserInfo *plugin.UserCenterBasicUserInfo) (
|
||||
resp *schema.UserExternalLoginResp, err error) {
|
||||
if len(basicUserInfo.ExternalID) == 0 {
|
||||
return &schema.UserExternalLoginResp{
|
||||
ErrTitle: translator.Tr(handler.GetLangByCtx(ctx), reason.UserAccessDenied),
|
||||
ErrMsg: translator.Tr(handler.GetLangByCtx(ctx), reason.UserExternalLoginMissingUserID),
|
||||
}, nil
|
||||
}
|
||||
|
||||
if len(basicUserInfo.Email) > 0 {
|
||||
// check whether site allow register or not
|
||||
|
|
|
@ -6,13 +6,16 @@ import (
|
|||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/answerdev/answer/internal/base/handler"
|
||||
"github.com/answerdev/answer/internal/base/reason"
|
||||
"github.com/answerdev/answer/internal/base/translator"
|
||||
"github.com/answerdev/answer/internal/entity"
|
||||
"github.com/answerdev/answer/internal/schema"
|
||||
"github.com/answerdev/answer/internal/service/activity"
|
||||
"github.com/answerdev/answer/internal/service/export"
|
||||
"github.com/answerdev/answer/internal/service/siteinfo_common"
|
||||
usercommon "github.com/answerdev/answer/internal/service/user_common"
|
||||
"github.com/answerdev/answer/pkg/checker"
|
||||
"github.com/answerdev/answer/pkg/random"
|
||||
"github.com/answerdev/answer/pkg/token"
|
||||
"github.com/answerdev/answer/plugin"
|
||||
|
@ -64,6 +67,13 @@ func NewUserExternalLoginService(
|
|||
func (us *UserExternalLoginService) ExternalLogin(
|
||||
ctx context.Context, externalUserInfo *schema.ExternalLoginUserInfoCache) (
|
||||
resp *schema.UserExternalLoginResp, err error) {
|
||||
if len(externalUserInfo.ExternalID) == 0 {
|
||||
return &schema.UserExternalLoginResp{
|
||||
ErrTitle: translator.Tr(handler.GetLangByCtx(ctx), reason.UserAccessDenied),
|
||||
ErrMsg: translator.Tr(handler.GetLangByCtx(ctx), reason.UserExternalLoginMissingUserID),
|
||||
}, nil
|
||||
}
|
||||
|
||||
oldExternalLoginUserInfo, exist, err := us.userExternalLoginRepo.GetByExternalID(ctx,
|
||||
externalUserInfo.Provider, externalUserInfo.ExternalID)
|
||||
if err != nil {
|
||||
|
@ -99,6 +109,19 @@ func (us *UserExternalLoginService) ExternalLogin(
|
|||
return &schema.UserExternalLoginResp{BindingKey: bindingKey}, nil
|
||||
}
|
||||
|
||||
// check whether site allow register or not
|
||||
siteInfo, err := us.siteInfoCommonService.GetSiteLogin(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !checker.EmailInAllowEmailDomain(externalUserInfo.Email, siteInfo.AllowEmailDomains) {
|
||||
log.Debugf("email domain not allowed: %s", externalUserInfo.Email)
|
||||
return &schema.UserExternalLoginResp{
|
||||
ErrTitle: translator.Tr(handler.GetLangByCtx(ctx), reason.UserAccessDenied),
|
||||
ErrMsg: translator.Tr(handler.GetLangByCtx(ctx), reason.EmailIllegalDomainError),
|
||||
}, nil
|
||||
}
|
||||
|
||||
oldUserInfo, exist, err := us.userRepo.GetByEmail(ctx, externalUserInfo.Email)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
Loading…
Reference in New Issue