mirror of https://gitee.com/answerdev/answer.git
Merge remote-tracking branch 'github/feat/1.1.2/user-center' into beta.2/1.1.0
# Conflicts: # docs/docs.go # docs/swagger.json # docs/swagger.yaml # go.mod # i18n/en_US.yaml # internal/base/reason/reason.go # internal/migrations/init.go # internal/migrations/migrations.go
This commit is contained in:
commit
b0a04bbf11
|
@ -193,7 +193,7 @@ func initApplication(debug bool, serverConf *conf.Server, dbConf *data.Database,
|
||||||
reasonService := reason2.NewReasonService(reasonRepo)
|
reasonService := reason2.NewReasonService(reasonRepo)
|
||||||
reasonController := controller.NewReasonController(reasonService)
|
reasonController := controller.NewReasonController(reasonService)
|
||||||
themeController := controller_admin.NewThemeController()
|
themeController := controller_admin.NewThemeController()
|
||||||
siteInfoService := siteinfo.NewSiteInfoService(siteInfoRepo, siteInfoCommonService, emailService, tagCommonService)
|
siteInfoService := siteinfo.NewSiteInfoService(siteInfoRepo, siteInfoCommonService, emailService, tagCommonService, configRepo)
|
||||||
siteInfoController := controller_admin.NewSiteInfoController(siteInfoService)
|
siteInfoController := controller_admin.NewSiteInfoController(siteInfoService)
|
||||||
siteinfoController := controller.NewSiteinfoController(siteInfoCommonService)
|
siteinfoController := controller.NewSiteinfoController(siteInfoCommonService)
|
||||||
notificationRepo := notification.NewNotificationRepo(dataData)
|
notificationRepo := notification.NewNotificationRepo(dataData)
|
||||||
|
@ -220,7 +220,7 @@ func initApplication(debug bool, serverConf *conf.Server, dbConf *data.Database,
|
||||||
templateController := controller.NewTemplateController(templateRenderController, siteInfoCommonService)
|
templateController := controller.NewTemplateController(templateRenderController, siteInfoCommonService)
|
||||||
templateRouter := router.NewTemplateRouter(templateController, templateRenderController, siteInfoController)
|
templateRouter := router.NewTemplateRouter(templateController, templateRenderController, siteInfoController)
|
||||||
connectorController := controller.NewConnectorController(siteInfoCommonService, emailService, userExternalLoginService)
|
connectorController := controller.NewConnectorController(siteInfoCommonService, emailService, userExternalLoginService)
|
||||||
userCenterLoginService := user_external_login2.NewUserCenterLoginService(userRepo, userCommon, userExternalLoginRepo, userActiveActivityRepo)
|
userCenterLoginService := user_external_login2.NewUserCenterLoginService(userRepo, userCommon, userExternalLoginRepo, userActiveActivityRepo, siteInfoCommonService)
|
||||||
userCenterController := controller.NewUserCenterController(userCenterLoginService, siteInfoCommonService)
|
userCenterController := controller.NewUserCenterController(userCenterLoginService, siteInfoCommonService)
|
||||||
pluginAPIRouter := router.NewPluginAPIRouter(connectorController, userCenterController)
|
pluginAPIRouter := router.NewPluginAPIRouter(connectorController, userCenterController)
|
||||||
ginEngine := server.NewHTTPServer(debug, staticRouter, answerAPIRouter, swaggerRouter, uiRouter, authUserMiddleware, avatarMiddleware, templateRouter, pluginAPIRouter)
|
ginEngine := server.NewHTTPServer(debug, staticRouter, answerAPIRouter, swaggerRouter, uiRouter, authUserMiddleware, avatarMiddleware, templateRouter, pluginAPIRouter)
|
||||||
|
|
360
docs/docs.go
360
docs/docs.go
|
@ -662,6 +662,77 @@ const docTemplate = `{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"/answer/admin/api/setting/privileges": {
|
||||||
|
"get": {
|
||||||
|
"security": [
|
||||||
|
{
|
||||||
|
"ApiKeyAuth": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "GetPrivilegesConfig get privileges config",
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"admin"
|
||||||
|
],
|
||||||
|
"summary": "GetPrivilegesConfig get privileges config",
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK",
|
||||||
|
"schema": {
|
||||||
|
"allOf": [
|
||||||
|
{
|
||||||
|
"$ref": "#/definitions/handler.RespBody"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"data": {
|
||||||
|
"$ref": "#/definitions/schema.GetPrivilegesConfigResp"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"put": {
|
||||||
|
"security": [
|
||||||
|
{
|
||||||
|
"ApiKeyAuth": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "update privileges config",
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"admin"
|
||||||
|
],
|
||||||
|
"summary": "update privileges config",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"description": "config",
|
||||||
|
"name": "data",
|
||||||
|
"in": "body",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/schema.UpdatePrivilegesConfigReq"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/handler.RespBody"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"/answer/admin/api/setting/smtp": {
|
"/answer/admin/api/setting/smtp": {
|
||||||
"get": {
|
"get": {
|
||||||
"security": [
|
"security": [
|
||||||
|
@ -1301,6 +1372,77 @@ const docTemplate = `{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"/answer/admin/api/siteinfo/users": {
|
||||||
|
"get": {
|
||||||
|
"security": [
|
||||||
|
{
|
||||||
|
"ApiKeyAuth": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "get site user config",
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"admin"
|
||||||
|
],
|
||||||
|
"summary": "get site user config",
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK",
|
||||||
|
"schema": {
|
||||||
|
"allOf": [
|
||||||
|
{
|
||||||
|
"$ref": "#/definitions/handler.RespBody"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"data": {
|
||||||
|
"$ref": "#/definitions/schema.SiteUsersResp"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"put": {
|
||||||
|
"security": [
|
||||||
|
{
|
||||||
|
"ApiKeyAuth": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "update site info config about users",
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"admin"
|
||||||
|
],
|
||||||
|
"summary": "update site info config about users",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"description": "users info",
|
||||||
|
"name": "data",
|
||||||
|
"in": "body",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/schema.SiteUsersReq"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/handler.RespBody"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"/answer/admin/api/siteinfo/write": {
|
"/answer/admin/api/siteinfo/write": {
|
||||||
"get": {
|
"get": {
|
||||||
"security": [
|
"security": [
|
||||||
|
@ -2861,7 +3003,7 @@ const docTemplate = `{
|
||||||
"ApiKeyAuth": []
|
"ApiKeyAuth": []
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"description": "list personal answers",
|
"description": "UserAnswerList",
|
||||||
"consumes": [
|
"consumes": [
|
||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
|
@ -2869,9 +3011,9 @@ const docTemplate = `{
|
||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
"tags": [
|
"tags": [
|
||||||
"Personal"
|
"api-answer"
|
||||||
],
|
],
|
||||||
"summary": "list personal answers",
|
"summary": "UserAnswerList",
|
||||||
"parameters": [
|
"parameters": [
|
||||||
{
|
{
|
||||||
"type": "string",
|
"type": "string",
|
||||||
|
@ -2903,8 +3045,8 @@ const docTemplate = `{
|
||||||
{
|
{
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"default": "20",
|
"default": "20",
|
||||||
"description": "page_size",
|
"description": "pagesize",
|
||||||
"name": "page_size",
|
"name": "pagesize",
|
||||||
"in": "query",
|
"in": "query",
|
||||||
"required": true
|
"required": true
|
||||||
}
|
}
|
||||||
|
@ -2926,7 +3068,7 @@ const docTemplate = `{
|
||||||
"ApiKeyAuth": []
|
"ApiKeyAuth": []
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"description": "list personal collections",
|
"description": "UserCollectionList",
|
||||||
"consumes": [
|
"consumes": [
|
||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
|
@ -2936,7 +3078,7 @@ const docTemplate = `{
|
||||||
"tags": [
|
"tags": [
|
||||||
"Collection"
|
"Collection"
|
||||||
],
|
],
|
||||||
"summary": "list personal collections",
|
"summary": "UserCollectionList",
|
||||||
"parameters": [
|
"parameters": [
|
||||||
{
|
{
|
||||||
"type": "string",
|
"type": "string",
|
||||||
|
@ -2949,8 +3091,8 @@ const docTemplate = `{
|
||||||
{
|
{
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"default": "20",
|
"default": "20",
|
||||||
"description": "page_size",
|
"description": "pagesize",
|
||||||
"name": "page_size",
|
"name": "pagesize",
|
||||||
"in": "query",
|
"in": "query",
|
||||||
"required": true
|
"required": true
|
||||||
}
|
}
|
||||||
|
@ -5668,7 +5810,7 @@ const docTemplate = `{
|
||||||
"ApiKeyAuth": []
|
"ApiKeyAuth": []
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"description": "list personal questions",
|
"description": "UserList",
|
||||||
"consumes": [
|
"consumes": [
|
||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
|
@ -5676,9 +5818,9 @@ const docTemplate = `{
|
||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
"tags": [
|
"tags": [
|
||||||
"Personal"
|
"Question"
|
||||||
],
|
],
|
||||||
"summary": "list personal questions",
|
"summary": "UserList",
|
||||||
"parameters": [
|
"parameters": [
|
||||||
{
|
{
|
||||||
"type": "string",
|
"type": "string",
|
||||||
|
@ -5710,8 +5852,8 @@ const docTemplate = `{
|
||||||
{
|
{
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"default": "20",
|
"default": "20",
|
||||||
"description": "page_size",
|
"description": "pagesize",
|
||||||
"name": "page_size",
|
"name": "pagesize",
|
||||||
"in": "query",
|
"in": "query",
|
||||||
"required": true
|
"required": true
|
||||||
}
|
}
|
||||||
|
@ -5748,6 +5890,20 @@ const docTemplate = `{
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"definitions": {
|
"definitions": {
|
||||||
|
"constant.Privilege": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"key": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"label": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"value": {
|
||||||
|
"type": "integer"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"handler.RespBody": {
|
"handler.RespBody": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
|
@ -6229,9 +6385,20 @@ const docTemplate = `{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"schema.ConfigFieldUIOptionAction": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"url": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"schema.ConfigFieldUIOptions": {
|
"schema.ConfigFieldUIOptions": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
|
"action": {
|
||||||
|
"$ref": "#/definitions/schema.ConfigFieldUIOptionAction"
|
||||||
|
},
|
||||||
"input_type": {
|
"input_type": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
|
@ -6243,6 +6410,12 @@ const docTemplate = `{
|
||||||
},
|
},
|
||||||
"rows": {
|
"rows": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
|
},
|
||||||
|
"text": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"variant": {
|
||||||
|
"type": "string"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -6649,6 +6822,20 @@ const docTemplate = `{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"schema.GetPrivilegesConfigResp": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"options": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/definitions/schema.PrivilegeOption"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"selected_level": {
|
||||||
|
"type": "integer"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"schema.GetRankPersonalWithPageResp": {
|
"schema.GetRankPersonalWithPageResp": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
|
@ -7351,6 +7538,23 @@ const docTemplate = `{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"schema.PrivilegeOption": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"level": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"level_desc": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"privileges": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/definitions/constant.Privilege"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"schema.QuestionAdd": {
|
"schema.QuestionAdd": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"required": [
|
"required": [
|
||||||
|
@ -7418,6 +7622,10 @@ const docTemplate = `{
|
||||||
"schema.QuestionPageReq": {
|
"schema.QuestionPageReq": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
|
"inDays": {
|
||||||
|
"type": "integer",
|
||||||
|
"minimum": 1
|
||||||
|
},
|
||||||
"orderCond": {
|
"orderCond": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": [
|
"enum": [
|
||||||
|
@ -7800,6 +8008,10 @@ const docTemplate = `{
|
||||||
"custom_header": {
|
"custom_header": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"maxLength": 65536
|
"maxLength": 65536
|
||||||
|
},
|
||||||
|
"custom_sidebar": {
|
||||||
|
"type": "string",
|
||||||
|
"maxLength": 65536
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -7821,6 +8033,10 @@ const docTemplate = `{
|
||||||
"custom_header": {
|
"custom_header": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"maxLength": 65536
|
"maxLength": 65536
|
||||||
|
},
|
||||||
|
"custom_sidebar": {
|
||||||
|
"type": "string",
|
||||||
|
"maxLength": 65536
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -7908,6 +8124,9 @@ const docTemplate = `{
|
||||||
"site_seo": {
|
"site_seo": {
|
||||||
"$ref": "#/definitions/schema.SiteSeoReq"
|
"$ref": "#/definitions/schema.SiteSeoReq"
|
||||||
},
|
},
|
||||||
|
"site_users": {
|
||||||
|
"$ref": "#/definitions/schema.SiteUsersResp"
|
||||||
|
},
|
||||||
"theme": {
|
"theme": {
|
||||||
"$ref": "#/definitions/schema.SiteThemeResp"
|
"$ref": "#/definitions/schema.SiteThemeResp"
|
||||||
},
|
},
|
||||||
|
@ -7919,18 +8138,10 @@ const docTemplate = `{
|
||||||
"schema.SiteInterfaceReq": {
|
"schema.SiteInterfaceReq": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"required": [
|
"required": [
|
||||||
"default_avatar",
|
|
||||||
"language",
|
"language",
|
||||||
"time_zone"
|
"time_zone"
|
||||||
],
|
],
|
||||||
"properties": {
|
"properties": {
|
||||||
"default_avatar": {
|
|
||||||
"type": "string",
|
|
||||||
"enum": [
|
|
||||||
"system",
|
|
||||||
"gravatar"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"language": {
|
"language": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"maxLength": 128
|
"maxLength": 128
|
||||||
|
@ -7944,18 +8155,10 @@ const docTemplate = `{
|
||||||
"schema.SiteInterfaceResp": {
|
"schema.SiteInterfaceResp": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"required": [
|
"required": [
|
||||||
"default_avatar",
|
|
||||||
"language",
|
"language",
|
||||||
"time_zone"
|
"time_zone"
|
||||||
],
|
],
|
||||||
"properties": {
|
"properties": {
|
||||||
"default_avatar": {
|
|
||||||
"type": "string",
|
|
||||||
"enum": [
|
|
||||||
"system",
|
|
||||||
"gravatar"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"language": {
|
"language": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"maxLength": 128
|
"maxLength": 128
|
||||||
|
@ -8003,6 +8206,15 @@ const docTemplate = `{
|
||||||
"schema.SiteLoginReq": {
|
"schema.SiteLoginReq": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
|
"allow_email_domains": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"allow_email_registrations": {
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
"allow_new_registrations": {
|
"allow_new_registrations": {
|
||||||
"type": "boolean"
|
"type": "boolean"
|
||||||
},
|
},
|
||||||
|
@ -8014,6 +8226,15 @@ const docTemplate = `{
|
||||||
"schema.SiteLoginResp": {
|
"schema.SiteLoginResp": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
|
"allow_email_domains": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"allow_email_registrations": {
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
"allow_new_registrations": {
|
"allow_new_registrations": {
|
||||||
"type": "boolean"
|
"type": "boolean"
|
||||||
},
|
},
|
||||||
|
@ -8090,6 +8311,72 @@ const docTemplate = `{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"schema.SiteUsersReq": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"default_avatar"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"allow_update_avatar": {
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"allow_update_bio": {
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"allow_update_display_name": {
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"allow_update_location": {
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"allow_update_username": {
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"allow_update_website": {
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"default_avatar": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"system",
|
||||||
|
"gravatar"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"schema.SiteUsersResp": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"default_avatar"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"allow_update_avatar": {
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"allow_update_bio": {
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"allow_update_display_name": {
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"allow_update_location": {
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"allow_update_username": {
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"allow_update_website": {
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"default_avatar": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"system",
|
||||||
|
"gravatar"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"schema.SiteWriteReq": {
|
"schema.SiteWriteReq": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
|
@ -8324,6 +8611,19 @@ const docTemplate = `{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"schema.UpdatePrivilegesConfigReq": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"level"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"level": {
|
||||||
|
"type": "integer",
|
||||||
|
"maximum": 3,
|
||||||
|
"minimum": 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"schema.UpdateSMTPConfigReq": {
|
"schema.UpdateSMTPConfigReq": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
|
|
47
go.sum
47
go.sum
|
@ -76,7 +76,6 @@ github.com/anargu/gin-brotli v0.0.0-20220116052358-12bf532d5267/go.mod h1:Yj3yPP
|
||||||
github.com/andybalholm/brotli v1.0.1/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y=
|
github.com/andybalholm/brotli v1.0.1/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y=
|
||||||
github.com/andybalholm/brotli v1.0.4 h1:V7DdXeJtZscaqfNuAdSRuRFzuiKlHSC/Zh3zl9qY3JY=
|
github.com/andybalholm/brotli v1.0.4 h1:V7DdXeJtZscaqfNuAdSRuRFzuiKlHSC/Zh3zl9qY3JY=
|
||||||
github.com/andybalholm/brotli v1.0.4/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
|
github.com/andybalholm/brotli v1.0.4/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
|
||||||
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
|
|
||||||
github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
|
github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
|
||||||
github.com/apache/thrift v0.13.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
|
github.com/apache/thrift v0.13.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
|
||||||
github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
|
github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
|
||||||
|
@ -113,10 +112,6 @@ github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDk
|
||||||
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
||||||
github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
|
github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
|
||||||
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
|
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
|
||||||
github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI=
|
|
||||||
github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
|
||||||
github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
|
||||||
github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
|
||||||
github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ=
|
github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ=
|
||||||
github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8=
|
github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8=
|
||||||
github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI=
|
github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI=
|
||||||
|
@ -172,7 +167,6 @@ github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.m
|
||||||
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
|
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
|
||||||
github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po=
|
github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po=
|
||||||
github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
|
github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
|
||||||
github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE=
|
|
||||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||||
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
||||||
github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4=
|
github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4=
|
||||||
|
@ -231,8 +225,6 @@ github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG
|
||||||
github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE=
|
github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE=
|
||||||
github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
|
github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
|
||||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||||
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 h1:p104kn46Q8WdvHunIJ9dAyjPVtrBPhSr3KT2yUst43I=
|
|
||||||
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
|
|
||||||
github.com/goccy/go-json v0.8.1/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
|
github.com/goccy/go-json v0.8.1/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
|
||||||
github.com/goccy/go-json v0.9.7/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
|
github.com/goccy/go-json v0.9.7/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
|
||||||
github.com/goccy/go-json v0.9.11 h1:/pAaQDLHEoCq/5FFmSKBswWmK6H0e8g4159Kc/X/nqk=
|
github.com/goccy/go-json v0.9.11 h1:/pAaQDLHEoCq/5FFmSKBswWmK6H0e8g4159Kc/X/nqk=
|
||||||
|
@ -281,8 +273,6 @@ github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QD
|
||||||
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||||
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||||
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
|
|
||||||
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
|
||||||
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||||
github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||||
github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
|
github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
|
||||||
|
@ -300,7 +290,6 @@ github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
|
||||||
github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
|
||||||
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
|
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
|
||||||
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||||
|
@ -317,8 +306,6 @@ github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hf
|
||||||
github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||||
github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||||
github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||||
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38 h1:yAJXTCF9TqKcTiHJAE8dj7HMvPfh66eeA2JYW7eFpSE=
|
|
||||||
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
|
||||||
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
||||||
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4=
|
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4=
|
||||||
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ=
|
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ=
|
||||||
|
@ -348,18 +335,13 @@ github.com/grokify/html-strip-tags-go v0.0.1/go.mod h1:2Su6romC5/1VXOQMaWL2yb618
|
||||||
github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
|
github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
|
||||||
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
|
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
|
||||||
github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
|
github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
|
||||||
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
|
|
||||||
github.com/hashicorp/consul/api v1.3.0/go.mod h1:MmDNSzIMUjNpY/mQ398R4bk2FnqQLoPndWW5VkKPlCE=
|
github.com/hashicorp/consul/api v1.3.0/go.mod h1:MmDNSzIMUjNpY/mQ398R4bk2FnqQLoPndWW5VkKPlCE=
|
||||||
github.com/hashicorp/consul/sdk v0.3.0/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8=
|
github.com/hashicorp/consul/sdk v0.3.0/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8=
|
||||||
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
||||||
github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I=
|
|
||||||
github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
|
||||||
github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
|
github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
|
||||||
github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
|
github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
|
||||||
github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=
|
github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=
|
||||||
github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
|
github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
|
||||||
github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo=
|
|
||||||
github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
|
|
||||||
github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU=
|
github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU=
|
||||||
github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU=
|
github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU=
|
||||||
github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
|
github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
|
||||||
|
@ -382,8 +364,6 @@ github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:
|
||||||
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||||
github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU=
|
github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU=
|
||||||
github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
|
github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
|
||||||
github.com/imroc/req/v3 v3.33.1 h1:BZnyl+K0hXcJlZBHY2CqbPgmVc1pPJDzjn6aJfB6shI=
|
|
||||||
github.com/imroc/req/v3 v3.33.1/go.mod h1:cZ+7C3L/AYOr4tLGG16hZF90F1WzAdAdzt1xFSlizXY=
|
|
||||||
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
||||||
github.com/inconshreveable/mousetrap v1.0.1 h1:U3uMjPSQEBMNp1lFxmllqCPM6P5u/Xq7Pgzkat/bFNc=
|
github.com/inconshreveable/mousetrap v1.0.1 h1:U3uMjPSQEBMNp1lFxmllqCPM6P5u/Xq7Pgzkat/bFNc=
|
||||||
github.com/inconshreveable/mousetrap v1.0.1/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
|
github.com/inconshreveable/mousetrap v1.0.1/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
|
||||||
|
@ -558,10 +538,9 @@ github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:v
|
||||||
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||||
github.com/onsi/ginkgo v1.7.0 h1:WSHQ+IS43OoUrWtD1/bbclrwK8TTH5hzp+umCiuxHgs=
|
github.com/onsi/ginkgo v1.7.0 h1:WSHQ+IS43OoUrWtD1/bbclrwK8TTH5hzp+umCiuxHgs=
|
||||||
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||||
github.com/onsi/ginkgo/v2 v2.2.0 h1:3ZNA3L1c5FYDFTTxbFeVGGD8jYvjYauHD30YgLxVsNI=
|
|
||||||
github.com/onsi/ginkgo/v2 v2.2.0/go.mod h1:MEH45j8TBi6u9BMogfbp0stKC5cdGjumZj5Y7AG4VIk=
|
|
||||||
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
||||||
github.com/onsi/gomega v1.20.1 h1:PA/3qinGoukvymdIDV8pii6tiZgC8kbmJO6Z5+b002Q=
|
github.com/onsi/gomega v1.20.1 h1:PA/3qinGoukvymdIDV8pii6tiZgC8kbmJO6Z5+b002Q=
|
||||||
|
github.com/onsi/gomega v1.20.1/go.mod h1:DtrZpjmvpn2mPm4YWQa0/ALMDj9v4YxLgojwPeREyVo=
|
||||||
github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk=
|
github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk=
|
||||||
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
|
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
|
||||||
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
|
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
|
||||||
|
@ -625,23 +604,12 @@ github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R
|
||||||
github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||||
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
|
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
|
||||||
github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A=
|
github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A=
|
||||||
github.com/quic-go/qpack v0.4.0 h1:Cr9BXA1sQS2SmDUWjSofMPNKmvF6IiIfDRmgU0w1ZCo=
|
|
||||||
github.com/quic-go/qpack v0.4.0/go.mod h1:UZVnYIfi5GRk+zI9UMaCPsmZ2xKJP7XBUvVyT1Knj9A=
|
|
||||||
github.com/quic-go/qtls-go1-18 v0.2.0 h1:5ViXqBZ90wpUcZS0ge79rf029yx0dYB0McyPJwqqj7U=
|
|
||||||
github.com/quic-go/qtls-go1-18 v0.2.0/go.mod h1:moGulGHK7o6O8lSPSZNoOwcLvJKJ85vVNc7oJFD65bc=
|
|
||||||
github.com/quic-go/qtls-go1-19 v0.2.0 h1:Cvn2WdhyViFUHoOqK52i51k4nDX8EwIh5VJiVM4nttk=
|
|
||||||
github.com/quic-go/qtls-go1-19 v0.2.0/go.mod h1:ySOI96ew8lnoKPtSqx2BlI5wCpUVPT05RMAlajtnyOI=
|
|
||||||
github.com/quic-go/qtls-go1-20 v0.1.0 h1:d1PK3ErFy9t7zxKsG3NXBJXZjp/kMLoIb3y/kV54oAI=
|
|
||||||
github.com/quic-go/qtls-go1-20 v0.1.0/go.mod h1:JKtK6mjbAVcUTN/9jZpvLbGxvdWIKS8uT7EiStoU1SM=
|
|
||||||
github.com/quic-go/quic-go v0.32.0 h1:lY02md31s1JgPiiyfqJijpu/UX/Iun304FI3yUqX7tA=
|
|
||||||
github.com/quic-go/quic-go v0.32.0/go.mod h1:/fCsKANhQIeD5l76c2JFU+07gVE3KaA0FP+0zMWwfwo=
|
|
||||||
github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
|
github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
|
||||||
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 h1:OdAsTTz6OkFY5QxjkYwrChwuRruF69c169dPK26NUlk=
|
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 h1:OdAsTTz6OkFY5QxjkYwrChwuRruF69c169dPK26NUlk=
|
||||||
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
|
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
|
||||||
github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs=
|
github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs=
|
||||||
github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=
|
github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=
|
||||||
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
|
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
|
||||||
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
|
|
||||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||||
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
|
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
|
||||||
github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8=
|
github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8=
|
||||||
|
@ -774,7 +742,6 @@ go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||||
go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||||
go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||||
go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk=
|
go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk=
|
||||||
go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
|
|
||||||
go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
||||||
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
||||||
go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
|
go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
|
||||||
|
@ -827,8 +794,6 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0
|
||||||
golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
|
golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
|
||||||
golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
|
golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
|
||||||
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
|
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
|
||||||
golang.org/x/exp v0.0.0-20221205204356-47842c84f3db h1:D/cFflL63o2KSLJIwjlcIt8PR064j/xsmdEJL/YvY/o=
|
|
||||||
golang.org/x/exp v0.0.0-20221205204356-47842c84f3db/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc=
|
|
||||||
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
||||||
golang.org/x/image v0.0.0-20190501045829-6d32002ffd75/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
golang.org/x/image v0.0.0-20190501045829-6d32002ffd75/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
||||||
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||||
|
@ -1014,7 +979,6 @@ golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3
|
||||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
|
||||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||||
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||||
|
@ -1148,7 +1112,6 @@ google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfG
|
||||||
google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||||
google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||||
google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||||
google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
|
||||||
google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U=
|
google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U=
|
||||||
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
|
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
|
||||||
google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA=
|
google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA=
|
||||||
|
@ -1162,8 +1125,6 @@ google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6D
|
||||||
google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||||
google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||||
google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||||
google.golang.org/genproto v0.0.0-20220519153652-3a47de7e79bd h1:e0TwkXOdbnH/1x5rc5MZ/VYyiZ4v+RdVfrGMqEwT68I=
|
|
||||||
google.golang.org/genproto v0.0.0-20220519153652-3a47de7e79bd/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4=
|
|
||||||
google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
|
google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
|
||||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||||
google.golang.org/grpc v1.20.0/go.mod h1:chYK+tFQF0nDUGJgXMSgLCQk3phJEuONr2DCgLDdAQM=
|
google.golang.org/grpc v1.20.0/go.mod h1:chYK+tFQF0nDUGJgXMSgLCQk3phJEuONr2DCgLDdAQM=
|
||||||
|
@ -1182,14 +1143,9 @@ google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3Iji
|
||||||
google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
||||||
google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
||||||
google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
||||||
google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0=
|
|
||||||
google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
|
google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
|
||||||
google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8=
|
google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8=
|
||||||
google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
|
google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
|
||||||
google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
|
|
||||||
google.golang.org/grpc v1.46.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk=
|
|
||||||
google.golang.org/grpc v1.46.2 h1:u+MLGgVf7vRdjEYZ8wDFhAVNmhkbJ5hmrA1LMWK1CAQ=
|
|
||||||
google.golang.org/grpc v1.46.2/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk=
|
|
||||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||||
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
||||||
|
@ -1201,7 +1157,6 @@ google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpAD
|
||||||
google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
|
google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
|
||||||
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
|
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
|
||||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||||
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
|
||||||
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||||
google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||||
google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w=
|
google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w=
|
||||||
|
|
|
@ -25,6 +25,8 @@ backend:
|
||||||
other: Close
|
other: Close
|
||||||
reopen:
|
reopen:
|
||||||
other: Reopen
|
other: Reopen
|
||||||
|
forbidden_error:
|
||||||
|
other: Forbidden.
|
||||||
pin:
|
pin:
|
||||||
other: Pin
|
other: Pin
|
||||||
hide:
|
hide:
|
||||||
|
@ -48,6 +50,58 @@ backend:
|
||||||
other: Have the full power to access the site.
|
other: Have the full power to access the site.
|
||||||
moderator:
|
moderator:
|
||||||
other: Has access to all posts except admin settings.
|
other: Has access to all posts except admin settings.
|
||||||
|
privilege:
|
||||||
|
level_1:
|
||||||
|
description:
|
||||||
|
other: Level 1 (less reputation required for private team, group)
|
||||||
|
level_2:
|
||||||
|
description:
|
||||||
|
other: Level 2 (low reputation required for startup community)
|
||||||
|
level_3:
|
||||||
|
description:
|
||||||
|
other: Level 3 (high reputation required for mature community)
|
||||||
|
rank_question_add_label:
|
||||||
|
other: Ask question
|
||||||
|
rank_answer_add_label:
|
||||||
|
other: Write answer
|
||||||
|
rank_comment_add_label:
|
||||||
|
other: Write comment
|
||||||
|
rank_report_add_label:
|
||||||
|
other: Flag
|
||||||
|
rank_comment_vote_up_label:
|
||||||
|
other: Upvote comment
|
||||||
|
rank_link_url_limit_label:
|
||||||
|
other: Post more than 2 links at a time
|
||||||
|
rank_question_vote_up_label:
|
||||||
|
other: Upvote question
|
||||||
|
rank_answer_vote_up_label:
|
||||||
|
other: Upvote answer
|
||||||
|
rank_question_vote_down_label:
|
||||||
|
other: Downvote question
|
||||||
|
rank_answer_vote_down_label:
|
||||||
|
other: Downvote answer
|
||||||
|
rank_tag_add_label:
|
||||||
|
other: Create new tag
|
||||||
|
rank_tag_edit_label:
|
||||||
|
other: Edit tag description (need to review)
|
||||||
|
rank_question_edit_label:
|
||||||
|
other: Edit other's question (need to review)
|
||||||
|
rank_answer_edit_label:
|
||||||
|
other: Edit other's answer (need to review)
|
||||||
|
rank_question_edit_without_review_label:
|
||||||
|
other: Edit other's question without review
|
||||||
|
rank_answer_edit_without_review_label:
|
||||||
|
other: Edit other's answer without review
|
||||||
|
rank_question_audit_label:
|
||||||
|
other: Review question edits
|
||||||
|
rank_answer_audit_label:
|
||||||
|
other: Review answer edits
|
||||||
|
rank_tag_audit_label:
|
||||||
|
other: Review tag edits
|
||||||
|
rank_tag_edit_without_review_label:
|
||||||
|
other: Edit tag description without review
|
||||||
|
rank_tag_synonym_label:
|
||||||
|
other: Manage tag synonyms
|
||||||
email:
|
email:
|
||||||
other: Email
|
other: Email
|
||||||
password:
|
password:
|
||||||
|
@ -85,6 +139,8 @@ backend:
|
||||||
other: Email should be verified.
|
other: Email should be verified.
|
||||||
verify_url_expired:
|
verify_url_expired:
|
||||||
other: Email verified URL has expired, please resend the email.
|
other: Email verified URL has expired, please resend the email.
|
||||||
|
illegal_email_domain_error:
|
||||||
|
other: Email is not allowed from that email domain. Please use another one.
|
||||||
lang:
|
lang:
|
||||||
not_found:
|
not_found:
|
||||||
other: Language file not found.
|
other: Language file not found.
|
||||||
|
@ -176,6 +232,10 @@ backend:
|
||||||
other: You cannot modify your role.
|
other: You cannot modify your role.
|
||||||
not_allowed_registration:
|
not_allowed_registration:
|
||||||
other: Currently the site is not open for registration
|
other: Currently the site is not open for registration
|
||||||
|
access_denied:
|
||||||
|
other: Access denied
|
||||||
|
page_access_denied:
|
||||||
|
other: You do not have access to this page.
|
||||||
config:
|
config:
|
||||||
read_config_failed:
|
read_config_failed:
|
||||||
other: Read config failed
|
other: Read config failed
|
||||||
|
@ -281,6 +341,16 @@ backend:
|
||||||
other: Your answer has been deleted
|
other: Your answer has been deleted
|
||||||
your_comment_was_deleted:
|
your_comment_was_deleted:
|
||||||
other: Your comment has been deleted
|
other: Your comment has been deleted
|
||||||
|
up_voted_question:
|
||||||
|
other: upvoted question
|
||||||
|
down_voted_question:
|
||||||
|
other: downvoted question
|
||||||
|
up_voted_answer:
|
||||||
|
other: upvoted answer
|
||||||
|
down_voted_answer:
|
||||||
|
other: downvoted answer
|
||||||
|
up_voted_comment:
|
||||||
|
other: upvoted comment
|
||||||
|
|
||||||
# The following fields are used for interface presentation(Front-end)
|
# The following fields are used for interface presentation(Front-end)
|
||||||
ui:
|
ui:
|
||||||
|
|
|
@ -45,6 +45,58 @@ backend:
|
||||||
other: 拥有管理网站的全部权限。
|
other: 拥有管理网站的全部权限。
|
||||||
moderator:
|
moderator:
|
||||||
other: 拥有访问除管理员设置以外的所有权限。
|
other: 拥有访问除管理员设置以外的所有权限。
|
||||||
|
privilege:
|
||||||
|
level_1:
|
||||||
|
description:
|
||||||
|
other: 等级1(创业社区所需的声望最低)
|
||||||
|
level_2:
|
||||||
|
description:
|
||||||
|
other: 等级2(创业社区所需的声望较低)
|
||||||
|
level_3:
|
||||||
|
description:
|
||||||
|
other: 等级3(成熟社区所需的声望较高)
|
||||||
|
rank_question_add_label:
|
||||||
|
other: 提问
|
||||||
|
rank_answer_add_label:
|
||||||
|
other: 回答问题
|
||||||
|
rank_comment_add_label:
|
||||||
|
other: 发表评论
|
||||||
|
rank_report_add_label:
|
||||||
|
other: 举报
|
||||||
|
rank_comment_vote_up_label:
|
||||||
|
other: 评论点赞
|
||||||
|
rank_link_url_limit_label:
|
||||||
|
other: 一次发布超过两个链接
|
||||||
|
rank_question_vote_up_label:
|
||||||
|
other: 问题点赞
|
||||||
|
rank_answer_vote_up_label:
|
||||||
|
other: 答案点赞
|
||||||
|
rank_question_vote_down_label:
|
||||||
|
other: 问题点踩
|
||||||
|
rank_answer_vote_down_label:
|
||||||
|
other: 答案点踩
|
||||||
|
rank_tag_add_label:
|
||||||
|
other: 创建新标签
|
||||||
|
rank_tag_edit_label:
|
||||||
|
other: 编辑标签描述(需要审核)
|
||||||
|
rank_question_edit_label:
|
||||||
|
other: 编辑他人提问(需要审核)
|
||||||
|
rank_answer_edit_label:
|
||||||
|
other: 编辑他人回答(需要审核)
|
||||||
|
rank_question_edit_without_review_label:
|
||||||
|
other: 编辑他人提问(无需审核)
|
||||||
|
rank_answer_edit_without_review_label:
|
||||||
|
other: 编辑他人回答(无需审核)
|
||||||
|
rank_question_audit_label:
|
||||||
|
other: 审核问题编辑
|
||||||
|
rank_answer_audit_label:
|
||||||
|
other: 审核答案编辑
|
||||||
|
rank_tag_audit_label:
|
||||||
|
other: 审核标签编辑
|
||||||
|
rank_tag_edit_without_review_label:
|
||||||
|
other: 编辑标签描述(无需审核)
|
||||||
|
rank_tag_synonym_label:
|
||||||
|
other: 管理标签同义词
|
||||||
email:
|
email:
|
||||||
other: 邮箱
|
other: 邮箱
|
||||||
password:
|
password:
|
||||||
|
@ -82,6 +134,8 @@ backend:
|
||||||
other: 邮箱需要验证。
|
other: 邮箱需要验证。
|
||||||
verify_url_expired:
|
verify_url_expired:
|
||||||
other: 邮箱验证的网址已过期,请重新发送邮件。
|
other: 邮箱验证的网址已过期,请重新发送邮件。
|
||||||
|
illegal_email_domain_error:
|
||||||
|
other: 该域名的邮箱无法使用。请尝试更换其他邮箱。
|
||||||
lang:
|
lang:
|
||||||
not_found:
|
not_found:
|
||||||
other: 语言未找到
|
other: 语言未找到
|
||||||
|
@ -171,6 +225,10 @@ backend:
|
||||||
other: 您不能修改自己的角色。
|
other: 您不能修改自己的角色。
|
||||||
not_allowed_registration:
|
not_allowed_registration:
|
||||||
other: 目前该站点未开放注册
|
other: 目前该站点未开放注册
|
||||||
|
access_denied:
|
||||||
|
other: 访问被拒绝
|
||||||
|
page_access_denied:
|
||||||
|
other: 你没有权限进入这个页面。
|
||||||
config:
|
config:
|
||||||
read_config_failed:
|
read_config_failed:
|
||||||
other: 读取配置失败
|
other: 读取配置失败
|
||||||
|
@ -271,6 +329,16 @@ backend:
|
||||||
other: 你的答案已被删除
|
other: 你的答案已被删除
|
||||||
your_comment_was_deleted:
|
your_comment_was_deleted:
|
||||||
other: 你的评论已被删除
|
other: 你的评论已被删除
|
||||||
|
up_voted_question:
|
||||||
|
other: 赞了问题
|
||||||
|
down_voted_question:
|
||||||
|
other: 踩了问题
|
||||||
|
up_voted_answer:
|
||||||
|
other: 赞了答案
|
||||||
|
down_voted_answer:
|
||||||
|
other: 踩了答案
|
||||||
|
up_voted_comment:
|
||||||
|
other: 赞了评论
|
||||||
#The following fields are used for interface presentation(Front-end)
|
#The following fields are used for interface presentation(Front-end)
|
||||||
ui:
|
ui:
|
||||||
how_to_format:
|
how_to_format:
|
||||||
|
@ -1063,6 +1131,9 @@ ui:
|
||||||
installed_plugins: 插件列表
|
installed_plugins: 插件列表
|
||||||
website_welcome: 欢迎来到 {{site_name}}
|
website_welcome: 欢迎来到 {{site_name}}
|
||||||
plugins:
|
plugins:
|
||||||
|
login: 登录
|
||||||
|
qrcode_login_tip: 请使用 {{ agentName }} 扫描二维码登录
|
||||||
|
login_failed_email_tip: 登录失败, 请允许该应用程序访问您的电子邮件信息,然后再试一次。
|
||||||
oauth:
|
oauth:
|
||||||
connect: 连接到 {{ auth_name }}
|
connect: 连接到 {{ auth_name }}
|
||||||
remove: 解绑 {{ auth_name }}
|
remove: 解绑 {{ auth_name }}
|
||||||
|
@ -1396,6 +1467,30 @@ ui:
|
||||||
deactivate: 停用
|
deactivate: 停用
|
||||||
activate: 启用
|
activate: 启用
|
||||||
settings: 设置
|
settings: 设置
|
||||||
|
settings_users:
|
||||||
|
title: 用户
|
||||||
|
avatar:
|
||||||
|
label: 默认头像
|
||||||
|
text: 未设置自定义头像的用户所展示的头像。
|
||||||
|
profile_editable:
|
||||||
|
title: 可编辑的个人资料
|
||||||
|
allow_update_display_name:
|
||||||
|
label: 允许用户更改显示名称
|
||||||
|
allow_update_username:
|
||||||
|
label: 允许用户更改用户名
|
||||||
|
allow_update_avatar:
|
||||||
|
label: 允许用户更改头像
|
||||||
|
allow_update_bio:
|
||||||
|
label: 允许用户更改自我介绍
|
||||||
|
allow_update_website:
|
||||||
|
label: 允许用户更改个人网站
|
||||||
|
allow_update_location:
|
||||||
|
label: 允许用户更改所在地
|
||||||
|
privilege:
|
||||||
|
title: 声望权限
|
||||||
|
level:
|
||||||
|
label: 所需声望等级
|
||||||
|
text: 选择所需的声望等级以获取权限
|
||||||
form:
|
form:
|
||||||
optional: (选填)
|
optional: (选填)
|
||||||
empty: 不能为空
|
empty: 不能为空
|
||||||
|
|
|
@ -66,6 +66,8 @@ const (
|
||||||
SiteTypeLogin = "login"
|
SiteTypeLogin = "login"
|
||||||
SiteTypeCustomCssHTML = "css-html"
|
SiteTypeCustomCssHTML = "css-html"
|
||||||
SiteTypeTheme = "theme"
|
SiteTypeTheme = "theme"
|
||||||
|
SiteTypePrivileges = "privileges"
|
||||||
|
SiteTypeUsers = "users"
|
||||||
)
|
)
|
||||||
|
|
||||||
func ExistInPathIgnore(name string) bool {
|
func ExistInPathIgnore(name string) bool {
|
||||||
|
|
|
@ -1,28 +1,38 @@
|
||||||
package constant
|
package constant
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// UpdateQuestion update question
|
// NotificationUpdateQuestion update question
|
||||||
UpdateQuestion = "notification.action.update_question"
|
NotificationUpdateQuestion = "notification.action.update_question"
|
||||||
// AnswerTheQuestion answer the question
|
// NotificationAnswerTheQuestion answer the question
|
||||||
AnswerTheQuestion = "notification.action.answer_the_question"
|
NotificationAnswerTheQuestion = "notification.action.answer_the_question"
|
||||||
// UpdateAnswer update answer
|
// NotificationUpVotedTheQuestion up voted the question
|
||||||
UpdateAnswer = "notification.action.update_answer"
|
NotificationUpVotedTheQuestion = "notification.action.up_voted_question"
|
||||||
// AcceptAnswer accept answer
|
// NotificationDownVotedTheQuestion down voted the question
|
||||||
AcceptAnswer = "notification.action.accept_answer"
|
NotificationDownVotedTheQuestion = "notification.action.down_voted_question"
|
||||||
// CommentQuestion comment question
|
// NotificationUpdateAnswer update answer
|
||||||
CommentQuestion = "notification.action.comment_question"
|
NotificationUpdateAnswer = "notification.action.update_answer"
|
||||||
// CommentAnswer comment answer
|
// NotificationAcceptAnswer accept answer
|
||||||
CommentAnswer = "notification.action.comment_answer"
|
NotificationAcceptAnswer = "notification.action.accept_answer"
|
||||||
// ReplyToYou reply to you
|
// NotificationUpVotedTheAnswer up voted the answer
|
||||||
ReplyToYou = "notification.action.reply_to_you"
|
NotificationUpVotedTheAnswer = "notification.action.up_voted_answer"
|
||||||
// MentionYou mention you
|
// NotificationDownVotedTheAnswer down voted the answer
|
||||||
MentionYou = "notification.action.mention_you"
|
NotificationDownVotedTheAnswer = "notification.action.down_voted_answer"
|
||||||
// YourQuestionIsClosed your question is closed
|
// NotificationCommentQuestion comment question
|
||||||
YourQuestionIsClosed = "notification.action.your_question_is_closed"
|
NotificationCommentQuestion = "notification.action.comment_question"
|
||||||
// YourQuestionWasDeleted your question was deleted
|
// NotificationCommentAnswer comment answer
|
||||||
YourQuestionWasDeleted = "notification.action.your_question_was_deleted"
|
NotificationCommentAnswer = "notification.action.comment_answer"
|
||||||
// YourAnswerWasDeleted your answer was deleted
|
// NotificationUpVotedTheComment up voted the comment
|
||||||
YourAnswerWasDeleted = "notification.action.your_answer_was_deleted"
|
NotificationUpVotedTheComment = "notification.action.up_voted_comment"
|
||||||
// YourCommentWasDeleted your comment was deleted
|
// NotificationReplyToYou reply to you
|
||||||
YourCommentWasDeleted = "notification.action.your_comment_was_deleted"
|
NotificationReplyToYou = "notification.action.reply_to_you"
|
||||||
|
// NotificationMentionYou mention you
|
||||||
|
NotificationMentionYou = "notification.action.mention_you"
|
||||||
|
// NotificationYourQuestionIsClosed your question is closed
|
||||||
|
NotificationYourQuestionIsClosed = "notification.action.your_question_is_closed"
|
||||||
|
// NotificationYourQuestionWasDeleted your question was deleted
|
||||||
|
NotificationYourQuestionWasDeleted = "notification.action.your_question_was_deleted"
|
||||||
|
// NotificationYourAnswerWasDeleted your answer was deleted
|
||||||
|
NotificationYourAnswerWasDeleted = "notification.action.your_answer_was_deleted"
|
||||||
|
// NotificationYourCommentWasDeleted your comment was deleted
|
||||||
|
NotificationYourCommentWasDeleted = "notification.action.your_comment_was_deleted"
|
||||||
)
|
)
|
||||||
|
|
|
@ -0,0 +1,70 @@
|
||||||
|
package constant
|
||||||
|
|
||||||
|
import "github.com/answerdev/answer/internal/base/reason"
|
||||||
|
|
||||||
|
type Privilege struct {
|
||||||
|
Key string `json:"key"`
|
||||||
|
Label string `json:"label"`
|
||||||
|
Value int `json:"value"`
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
RankQuestionAddKey = "rank.question.add"
|
||||||
|
RankQuestionEditKey = "rank.question.edit"
|
||||||
|
RankQuestionDeleteKey = "rank.question.delete"
|
||||||
|
RankQuestionVoteUpKey = "rank.question.vote_up"
|
||||||
|
RankQuestionVoteDownKey = "rank.question.vote_down"
|
||||||
|
RankAnswerAddKey = "rank.answer.add"
|
||||||
|
RankAnswerEditKey = "rank.answer.edit"
|
||||||
|
RankAnswerDeleteKey = "rank.answer.delete"
|
||||||
|
RankAnswerAcceptKey = "rank.answer.accept"
|
||||||
|
RankAnswerVoteUpKey = "rank.answer.vote_up"
|
||||||
|
RankAnswerVoteDownKey = "rank.answer.vote_down"
|
||||||
|
RankCommentAddKey = "rank.comment.add"
|
||||||
|
RankCommentEditKey = "rank.comment.edit"
|
||||||
|
RankCommentDeleteKey = "rank.comment.delete"
|
||||||
|
RankReportAddKey = "rank.report.add"
|
||||||
|
RankTagAddKey = "rank.tag.add"
|
||||||
|
RankTagEditKey = "rank.tag.edit"
|
||||||
|
RankTagDeleteKey = "rank.tag.delete"
|
||||||
|
RankTagSynonymKey = "rank.tag.synonym"
|
||||||
|
RankLinkUrlLimitKey = "rank.link.url_limit"
|
||||||
|
RankVoteDetailKey = "rank.vote.detail"
|
||||||
|
RankCommentVoteUpKey = "rank.comment.vote_up"
|
||||||
|
RankCommentVoteDownKey = "rank.comment.vote_down"
|
||||||
|
RankQuestionEditWithoutReviewKey = "rank.question.edit_without_review"
|
||||||
|
RankAnswerEditWithoutReviewKey = "rank.answer.edit_without_review"
|
||||||
|
RankTagEditWithoutReviewKey = "rank.tag.edit_without_review"
|
||||||
|
RankAnswerAuditKey = "rank.answer.audit"
|
||||||
|
RankQuestionAuditKey = "rank.question.audit"
|
||||||
|
RankTagAuditKey = "rank.tag.audit"
|
||||||
|
RankQuestionCloseKey = "rank.question.close"
|
||||||
|
RankQuestionReopenKey = "rank.question.reopen"
|
||||||
|
RankTagUseReservedTagKey = "rank.tag.use_reserved_tag"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
RankAllPrivileges = []*Privilege{
|
||||||
|
{Label: reason.RankQuestionAddLabel, Key: RankQuestionAddKey},
|
||||||
|
{Label: reason.RankAnswerAddLabel, Key: RankAnswerAddKey},
|
||||||
|
{Label: reason.RankCommentAddLabel, Key: RankCommentAddKey},
|
||||||
|
{Label: reason.RankReportAddLabel, Key: RankReportAddKey},
|
||||||
|
{Label: reason.RankCommentVoteUpLabel, Key: RankCommentVoteUpKey},
|
||||||
|
{Label: reason.RankLinkUrlLimitLabel, Key: RankLinkUrlLimitKey},
|
||||||
|
{Label: reason.RankQuestionVoteUpLabel, Key: RankQuestionVoteUpKey},
|
||||||
|
{Label: reason.RankAnswerVoteUpLabel, Key: RankAnswerVoteUpKey},
|
||||||
|
{Label: reason.RankQuestionVoteDownLabel, Key: RankQuestionVoteDownKey},
|
||||||
|
{Label: reason.RankAnswerVoteDownLabel, Key: RankAnswerVoteDownKey},
|
||||||
|
{Label: reason.RankTagAddLabel, Key: RankTagAddKey},
|
||||||
|
{Label: reason.RankTagEditLabel, Key: RankTagEditKey},
|
||||||
|
{Label: reason.RankQuestionEditLabel, Key: RankQuestionEditKey},
|
||||||
|
{Label: reason.RankAnswerEditLabel, Key: RankAnswerEditKey},
|
||||||
|
{Label: reason.RankQuestionEditWithoutReviewLabel, Key: RankQuestionEditWithoutReviewKey},
|
||||||
|
{Label: reason.RankAnswerEditWithoutReviewLabel, Key: RankAnswerEditWithoutReviewKey},
|
||||||
|
{Label: reason.RankQuestionAuditLabel, Key: RankQuestionAuditKey},
|
||||||
|
{Label: reason.RankAnswerAuditLabel, Key: RankAnswerAuditKey},
|
||||||
|
{Label: reason.RankTagAuditLabel, Key: RankTagAuditKey},
|
||||||
|
{Label: reason.RankTagEditWithoutReviewLabel, Key: RankTagEditWithoutReviewKey},
|
||||||
|
{Label: reason.RankTagSynonymLabel, Key: RankTagSynonymKey},
|
||||||
|
}
|
||||||
|
)
|
|
@ -1,5 +1,6 @@
|
||||||
package constant
|
package constant
|
||||||
|
|
||||||
var (
|
var (
|
||||||
DefaultAvatar = "system"
|
DefaultAvatar = "system"
|
||||||
|
DefaultSiteURL = ""
|
||||||
)
|
)
|
||||||
|
|
|
@ -8,9 +8,13 @@ import (
|
||||||
"github.com/segmentfault/pacman/errors"
|
"github.com/segmentfault/pacman/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
// BanAPIWhenUserCenterEnabled ban api when user center enabled
|
// BanAPIForUserCenter ban api for user center
|
||||||
func BanAPIWhenUserCenterEnabled(ctx *gin.Context) {
|
func BanAPIForUserCenter(ctx *gin.Context) {
|
||||||
if plugin.UserCenterEnabled() {
|
uc, ok := plugin.GetUserCenter()
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if !uc.Description().EnabledOriginalUserSystem {
|
||||||
handler.HandleResponse(ctx, errors.Forbidden(reason.ForbiddenError), nil)
|
handler.HandleResponse(ctx, errors.Forbidden(reason.ForbiddenError), nil)
|
||||||
ctx.Abort()
|
ctx.Abort()
|
||||||
return
|
return
|
||||||
|
|
|
@ -0,0 +1,29 @@
|
||||||
|
package reason
|
||||||
|
|
||||||
|
const (
|
||||||
|
PrivilegeLevel1Desc = "privilege.level_1.description"
|
||||||
|
PrivilegeLevel2Desc = "privilege.level_2.description"
|
||||||
|
PrivilegeLevel3Desc = "privilege.level_3.description"
|
||||||
|
|
||||||
|
RankQuestionAddLabel = "privilege.rank_question_add_label"
|
||||||
|
RankAnswerAddLabel = "privilege.rank_answer_add_label"
|
||||||
|
RankCommentAddLabel = "privilege.rank_comment_add_label"
|
||||||
|
RankReportAddLabel = "privilege.rank_report_add_label"
|
||||||
|
RankCommentVoteUpLabel = "privilege.rank_comment_vote_up_label"
|
||||||
|
RankLinkUrlLimitLabel = "privilege.rank_link_url_limit_label"
|
||||||
|
RankQuestionVoteUpLabel = "privilege.rank_question_vote_up_label"
|
||||||
|
RankAnswerVoteUpLabel = "privilege.rank_answer_vote_up_label"
|
||||||
|
RankQuestionVoteDownLabel = "privilege.rank_question_vote_down_label"
|
||||||
|
RankAnswerVoteDownLabel = "privilege.rank_answer_vote_down_label"
|
||||||
|
RankTagAddLabel = "privilege.rank_tag_add_label"
|
||||||
|
RankTagEditLabel = "privilege.rank_tag_edit_label"
|
||||||
|
RankQuestionEditLabel = "privilege.rank_question_edit_label"
|
||||||
|
RankAnswerEditLabel = "privilege.rank_answer_edit_label"
|
||||||
|
RankQuestionEditWithoutReviewLabel = "privilege.rank_question_edit_without_review_label"
|
||||||
|
RankAnswerEditWithoutReviewLabel = "privilege.rank_answer_edit_without_review_label"
|
||||||
|
RankQuestionAuditLabel = "privilege.rank_question_audit_label"
|
||||||
|
RankAnswerAuditLabel = "privilege.rank_answer_audit_label"
|
||||||
|
RankTagAuditLabel = "privilege.rank_tag_audit_label"
|
||||||
|
RankTagEditWithoutReviewLabel = "privilege.rank_tag_edit_without_review_label"
|
||||||
|
RankTagSynonymLabel = "privilege.rank_tag_synonym_label"
|
||||||
|
)
|
|
@ -42,6 +42,7 @@ const (
|
||||||
EmailDuplicate = "error.email.duplicate"
|
EmailDuplicate = "error.email.duplicate"
|
||||||
EmailVerifyURLExpired = "error.email.verify_url_expired"
|
EmailVerifyURLExpired = "error.email.verify_url_expired"
|
||||||
EmailNeedToBeVerified = "error.email.need_to_be_verified"
|
EmailNeedToBeVerified = "error.email.need_to_be_verified"
|
||||||
|
EmailIllegalDomainError = "error.email.illegal_email_domain_error"
|
||||||
UserSuspended = "error.user.suspended"
|
UserSuspended = "error.user.suspended"
|
||||||
ObjectNotFound = "error.object.not_found"
|
ObjectNotFound = "error.object.not_found"
|
||||||
TagNotFound = "error.tag.not_found"
|
TagNotFound = "error.tag.not_found"
|
||||||
|
@ -50,7 +51,7 @@ const (
|
||||||
TagIsUsedCannotDelete = "error.tag.is_used_cannot_delete"
|
TagIsUsedCannotDelete = "error.tag.is_used_cannot_delete"
|
||||||
TagAlreadyExist = "error.tag.already_exist"
|
TagAlreadyExist = "error.tag.already_exist"
|
||||||
RankFailToMeetTheCondition = "error.rank.fail_to_meet_the_condition"
|
RankFailToMeetTheCondition = "error.rank.fail_to_meet_the_condition"
|
||||||
VoteRankFailToMeetTheCondition = "error.rank.vote_fail_to_meet_the_condition"
|
VoteRankFailToMeetTheCondition = "error.rank.vote_fail_to_meet_the_condition"
|
||||||
ThemeNotFound = "error.theme.not_found"
|
ThemeNotFound = "error.theme.not_found"
|
||||||
LangNotFound = "error.lang.not_found"
|
LangNotFound = "error.lang.not_found"
|
||||||
ReportHandleFailed = "error.report.handle_failed"
|
ReportHandleFailed = "error.report.handle_failed"
|
||||||
|
@ -73,4 +74,6 @@ const (
|
||||||
AdminCannotUpdateTheirPassword = "error.admin.cannot_update_their_password"
|
AdminCannotUpdateTheirPassword = "error.admin.cannot_update_their_password"
|
||||||
AdminCannotModifySelfStatus = "error.admin.cannot_modify_self_status"
|
AdminCannotModifySelfStatus = "error.admin.cannot_modify_self_status"
|
||||||
UserExternalLoginUnbindingForbidden = "error.user.external_login_unbinding_forbidden"
|
UserExternalLoginUnbindingForbidden = "error.user.external_login_unbinding_forbidden"
|
||||||
|
UserAccessDenied = "error.user.access_denied"
|
||||||
|
UserPageAccessDenied = "error.user.page_access_denied"
|
||||||
)
|
)
|
||||||
|
|
|
@ -7,6 +7,7 @@ import (
|
||||||
brotli "github.com/anargu/gin-brotli"
|
brotli "github.com/anargu/gin-brotli"
|
||||||
"github.com/answerdev/answer/internal/base/middleware"
|
"github.com/answerdev/answer/internal/base/middleware"
|
||||||
"github.com/answerdev/answer/internal/router"
|
"github.com/answerdev/answer/internal/router"
|
||||||
|
"github.com/answerdev/answer/plugin"
|
||||||
"github.com/answerdev/answer/ui"
|
"github.com/answerdev/answer/ui"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
)
|
)
|
||||||
|
@ -66,6 +67,14 @@ func NewHTTPServer(debug bool,
|
||||||
|
|
||||||
// plugin routes
|
// plugin routes
|
||||||
pluginAPIRouter.RegisterUnAuthConnectorRouter(mustUnAuthV1)
|
pluginAPIRouter.RegisterUnAuthConnectorRouter(mustUnAuthV1)
|
||||||
pluginAPIRouter.RegisterAuthConnectorRouter(authV1)
|
pluginAPIRouter.RegisterAuthUserConnectorRouter(authV1)
|
||||||
|
pluginAPIRouter.RegisterAuthAdminConnectorRouter(adminauthV1)
|
||||||
|
|
||||||
|
_ = plugin.CallAgent(func(agent plugin.Agent) error {
|
||||||
|
agent.RegisterUnAuthRouter(mustUnAuthV1)
|
||||||
|
agent.RegisterAuthUserRouter(authV1)
|
||||||
|
agent.RegisterAuthAdminRouter(adminauthV1)
|
||||||
|
return nil
|
||||||
|
})
|
||||||
return r
|
return r
|
||||||
}
|
}
|
||||||
|
|
|
@ -130,7 +130,7 @@ func (cc *ConnectorController) ConnectorRedirect(connector plugin.Connector) (fn
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if len(resp.AccessToken) > 0 {
|
if len(resp.AccessToken) > 0 {
|
||||||
ctx.Redirect(http.StatusFound, fmt.Sprintf("%s/users/oauth?access_token=%s",
|
ctx.Redirect(http.StatusFound, fmt.Sprintf("%s/users/auth-landing?access_token=%s",
|
||||||
siteGeneral.SiteUrl, resp.AccessToken))
|
siteGeneral.SiteUrl, resp.AccessToken))
|
||||||
} else {
|
} else {
|
||||||
ctx.Redirect(http.StatusFound, fmt.Sprintf("%s/users/confirm-email?binding_key=%s",
|
ctx.Redirect(http.StatusFound, fmt.Sprintf("%s/users/confirm-email?binding_key=%s",
|
||||||
|
|
|
@ -60,9 +60,11 @@ func (uc *UserCenterController) UserCenterAgent(ctx *gin.Context) {
|
||||||
_ = plugin.CallUserCenter(func(uc plugin.UserCenter) error {
|
_ = plugin.CallUserCenter(func(uc plugin.UserCenter) error {
|
||||||
info := uc.Description()
|
info := uc.Description()
|
||||||
resp.AgentInfo.Name = info.Name
|
resp.AgentInfo.Name = info.Name
|
||||||
|
resp.AgentInfo.DisplayName = info.DisplayName.Translate(ctx)
|
||||||
resp.AgentInfo.Icon = info.Icon
|
resp.AgentInfo.Icon = info.Icon
|
||||||
resp.AgentInfo.Url = info.Url
|
resp.AgentInfo.Url = info.Url
|
||||||
resp.AgentInfo.ControlCenterItems = make([]*schema.ControlCenter, 0)
|
resp.AgentInfo.ControlCenterItems = make([]*schema.ControlCenter, 0)
|
||||||
|
resp.AgentInfo.EnabledOriginalUserSystem = info.EnabledOriginalUserSystem
|
||||||
items := uc.ControlCenterItems()
|
items := uc.ControlCenterItems()
|
||||||
for _, item := range items {
|
for _, item := range items {
|
||||||
resp.AgentInfo.ControlCenterItems = append(resp.AgentInfo.ControlCenterItems, &schema.ControlCenter{
|
resp.AgentInfo.ControlCenterItems = append(resp.AgentInfo.ControlCenterItems, &schema.ControlCenter{
|
||||||
|
@ -90,8 +92,8 @@ func (uc *UserCenterController) UserCenterPersonalBranding(ctx *gin.Context) {
|
||||||
|
|
||||||
func (uc *UserCenterController) UserCenterLoginRedirect(ctx *gin.Context) {
|
func (uc *UserCenterController) UserCenterLoginRedirect(ctx *gin.Context) {
|
||||||
var redirectURL string
|
var redirectURL string
|
||||||
_ = plugin.CallUserCenter(func(uc plugin.UserCenter) error {
|
_ = plugin.CallUserCenter(func(userCenter plugin.UserCenter) error {
|
||||||
info := uc.Description()
|
info := userCenter.Description()
|
||||||
redirectURL = info.LoginRedirectURL
|
redirectURL = info.LoginRedirectURL
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
|
@ -100,9 +102,9 @@ func (uc *UserCenterController) UserCenterLoginRedirect(ctx *gin.Context) {
|
||||||
|
|
||||||
func (uc *UserCenterController) UserCenterSignUpRedirect(ctx *gin.Context) {
|
func (uc *UserCenterController) UserCenterSignUpRedirect(ctx *gin.Context) {
|
||||||
var redirectURL string
|
var redirectURL string
|
||||||
_ = plugin.CallUserCenter(func(uc plugin.UserCenter) error {
|
_ = plugin.CallUserCenter(func(userCenter plugin.UserCenter) error {
|
||||||
info := uc.Description()
|
info := userCenter.Description()
|
||||||
redirectURL = info.SignUpRedirectURL
|
redirectURL = info.LoginRedirectURL
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
ctx.Redirect(http.StatusFound, redirectURL)
|
ctx.Redirect(http.StatusFound, redirectURL)
|
||||||
|
@ -124,17 +126,24 @@ func (uc *UserCenterController) UserCenterLoginCallback(ctx *gin.Context) {
|
||||||
userInfo, err := userCenter.LoginCallback(ctx)
|
userInfo, err := userCenter.LoginCallback(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error(err)
|
log.Error(err)
|
||||||
ctx.Redirect(http.StatusFound, "/50x")
|
if !ctx.IsAborted() {
|
||||||
|
ctx.Redirect(http.StatusFound, "/50x")
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
resp, err := uc.userCenterLoginService.ExternalLogin(ctx, userCenter.Info().SlugName, userInfo)
|
resp, err := uc.userCenterLoginService.ExternalLogin(ctx, userCenter, userInfo)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("external login failed: %v", err)
|
log.Errorf("external login failed: %v", err)
|
||||||
ctx.Redirect(http.StatusFound, "/50x")
|
ctx.Redirect(http.StatusFound, "/50x")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
ctx.Redirect(http.StatusFound, fmt.Sprintf("%s/users/oauth?access_token=%s",
|
if len(resp.ErrMsg) > 0 {
|
||||||
|
ctx.Redirect(http.StatusFound, fmt.Sprintf("/50x?title=%s&msg=%s", resp.ErrTitle, resp.ErrMsg))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
userCenter.AfterLogin(userInfo.ExternalID, resp.AccessToken)
|
||||||
|
ctx.Redirect(http.StatusFound, fmt.Sprintf("%s/users/auth-landing?access_token=%s",
|
||||||
siteGeneral.SiteUrl, resp.AccessToken))
|
siteGeneral.SiteUrl, resp.AccessToken))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -158,13 +167,18 @@ func (uc *UserCenterController) UserCenterSignUpCallback(ctx *gin.Context) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
resp, err := uc.userCenterLoginService.ExternalLogin(ctx, userCenter.Info().SlugName, userInfo)
|
resp, err := uc.userCenterLoginService.ExternalLogin(ctx, userCenter, userInfo)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("external login failed: %v", err)
|
log.Errorf("external login failed: %v", err)
|
||||||
ctx.Redirect(http.StatusFound, "/50x")
|
ctx.Redirect(http.StatusFound, "/50x")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
ctx.Redirect(http.StatusFound, fmt.Sprintf("%s/users/oauth?access_token=%s",
|
if len(resp.ErrMsg) > 0 {
|
||||||
|
ctx.Redirect(http.StatusFound, fmt.Sprintf("/50x?title=%s&msg=%s", resp.ErrTitle, resp.ErrMsg))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
userCenter.AfterLogin(userInfo.ExternalID, resp.AccessToken)
|
||||||
|
ctx.Redirect(http.StatusFound, fmt.Sprintf("%s/users/auth-landing?access_token=%s",
|
||||||
siteGeneral.SiteUrl, resp.AccessToken))
|
siteGeneral.SiteUrl, resp.AccessToken))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -174,3 +188,9 @@ func (uc *UserCenterController) UserCenterUserSettings(ctx *gin.Context) {
|
||||||
resp, err := uc.userCenterLoginService.UserCenterUserSettings(ctx, userID)
|
resp, err := uc.userCenterLoginService.UserCenterUserSettings(ctx, userID)
|
||||||
handler.HandleResponse(ctx, err, resp)
|
handler.HandleResponse(ctx, err, resp)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// UserCenterAdminFunctionAgent user center admin function agent
|
||||||
|
func (uc *UserCenterController) UserCenterAdminFunctionAgent(ctx *gin.Context) {
|
||||||
|
resp, err := uc.userCenterLoginService.UserCenterAdminFunctionAgent(ctx)
|
||||||
|
handler.HandleResponse(ctx, err, resp)
|
||||||
|
}
|
||||||
|
|
|
@ -64,6 +64,10 @@ func (sc *SiteinfoController) GetSiteInfo(ctx *gin.Context) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error(err)
|
log.Error(err)
|
||||||
}
|
}
|
||||||
|
resp.SiteUsers, err = sc.siteInfoService.GetSiteUsers(ctx)
|
||||||
|
if err != nil {
|
||||||
|
log.Error(err)
|
||||||
|
}
|
||||||
|
|
||||||
handler.HandleResponse(ctx, nil, resp)
|
handler.HandleResponse(ctx, nil, resp)
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,7 @@ import (
|
||||||
"github.com/answerdev/answer/internal/service/export"
|
"github.com/answerdev/answer/internal/service/export"
|
||||||
"github.com/answerdev/answer/internal/service/siteinfo_common"
|
"github.com/answerdev/answer/internal/service/siteinfo_common"
|
||||||
"github.com/answerdev/answer/internal/service/uploader"
|
"github.com/answerdev/answer/internal/service/uploader"
|
||||||
|
"github.com/answerdev/answer/pkg/checker"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/segmentfault/pacman/errors"
|
"github.com/segmentfault/pacman/errors"
|
||||||
"github.com/segmentfault/pacman/log"
|
"github.com/segmentfault/pacman/log"
|
||||||
|
@ -223,7 +224,7 @@ func (uc *UserController) UserRegisterByEmail(ctx *gin.Context) {
|
||||||
handler.HandleResponse(ctx, err, nil)
|
handler.HandleResponse(ctx, err, nil)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if !siteInfo.AllowNewRegistrations {
|
if !siteInfo.AllowNewRegistrations || !siteInfo.AllowEmailRegistrations {
|
||||||
handler.HandleResponse(ctx, errors.BadRequest(reason.NotAllowedRegistration), nil)
|
handler.HandleResponse(ctx, errors.BadRequest(reason.NotAllowedRegistration), nil)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -232,6 +233,10 @@ func (uc *UserController) UserRegisterByEmail(ctx *gin.Context) {
|
||||||
if handler.BindAndCheck(ctx, req) {
|
if handler.BindAndCheck(ctx, req) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
if !checker.EmailInAllowEmailDomain(req.Email, siteInfo.AllowEmailDomains) {
|
||||||
|
handler.HandleResponse(ctx, errors.BadRequest(reason.EmailIllegalDomainError), nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
req.IP = ctx.ClientIP()
|
req.IP = ctx.ClientIP()
|
||||||
captchaPass := uc.actionService.UserRegisterVerifyCaptcha(ctx, req.CaptchaID, req.CaptchaCode)
|
captchaPass := uc.actionService.UserRegisterVerifyCaptcha(ctx, req.CaptchaID, req.CaptchaCode)
|
||||||
if !captchaPass {
|
if !captchaPass {
|
||||||
|
@ -489,6 +494,16 @@ func (uc *UserController) UserChangeEmailSendCode(ctx *gin.Context) {
|
||||||
handler.HandleResponse(ctx, errors.Unauthorized(reason.UnauthorizedError), nil)
|
handler.HandleResponse(ctx, errors.Unauthorized(reason.UnauthorizedError), nil)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
// check whether email allow register or not
|
||||||
|
siteInfo, err := uc.siteInfoCommonService.GetSiteLogin(ctx)
|
||||||
|
if err != nil {
|
||||||
|
handler.HandleResponse(ctx, err, nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if !checker.EmailInAllowEmailDomain(req.Email, siteInfo.AllowEmailDomains) {
|
||||||
|
handler.HandleResponse(ctx, errors.BadRequest(reason.EmailIllegalDomainError), nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
captchaPass := uc.actionService.ActionRecordVerifyCaptcha(ctx, schema.ActionRecordTypeEmail, ctx.ClientIP(), req.CaptchaID, req.CaptchaCode)
|
captchaPass := uc.actionService.ActionRecordVerifyCaptcha(ctx, schema.ActionRecordTypeEmail, ctx.ClientIP(), req.CaptchaID, req.CaptchaCode)
|
||||||
if !captchaPass {
|
if !captchaPass {
|
||||||
|
|
|
@ -139,6 +139,19 @@ func (sc *SiteInfoController) GetSiteTheme(ctx *gin.Context) {
|
||||||
handler.HandleResponse(ctx, err, resp)
|
handler.HandleResponse(ctx, err, resp)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetSiteUsers get site user config
|
||||||
|
// @Summary get site user config
|
||||||
|
// @Description get site user config
|
||||||
|
// @Security ApiKeyAuth
|
||||||
|
// @Tags admin
|
||||||
|
// @Produce json
|
||||||
|
// @Success 200 {object} handler.RespBody{data=schema.SiteUsersResp}
|
||||||
|
// @Router /answer/admin/api/siteinfo/users [get]
|
||||||
|
func (sc *SiteInfoController) GetSiteUsers(ctx *gin.Context) {
|
||||||
|
resp, err := sc.siteInfoService.GetSiteUsers(ctx)
|
||||||
|
handler.HandleResponse(ctx, err, resp)
|
||||||
|
}
|
||||||
|
|
||||||
// GetRobots get site robots information
|
// GetRobots get site robots information
|
||||||
// @Summary get site robots information
|
// @Summary get site robots information
|
||||||
// @Description get site robots information
|
// @Description get site robots information
|
||||||
|
@ -336,6 +349,24 @@ func (sc *SiteInfoController) SaveSiteTheme(ctx *gin.Context) {
|
||||||
handler.HandleResponse(ctx, err, nil)
|
handler.HandleResponse(ctx, err, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// UpdateSiteUsers update site config about users
|
||||||
|
// @Summary update site info config about users
|
||||||
|
// @Description update site info config about users
|
||||||
|
// @Security ApiKeyAuth
|
||||||
|
// @Tags admin
|
||||||
|
// @Produce json
|
||||||
|
// @Param data body schema.SiteUsersReq true "users info"
|
||||||
|
// @Success 200 {object} handler.RespBody{}
|
||||||
|
// @Router /answer/admin/api/siteinfo/users [put]
|
||||||
|
func (sc *SiteInfoController) UpdateSiteUsers(ctx *gin.Context) {
|
||||||
|
req := &schema.SiteUsersReq{}
|
||||||
|
if handler.BindAndCheck(ctx, req) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err := sc.siteInfoService.SaveSiteUsers(ctx, req)
|
||||||
|
handler.HandleResponse(ctx, err, nil)
|
||||||
|
}
|
||||||
|
|
||||||
// GetSMTPConfig get smtp config
|
// GetSMTPConfig get smtp config
|
||||||
// @Summary GetSMTPConfig get smtp config
|
// @Summary GetSMTPConfig get smtp config
|
||||||
// @Description GetSMTPConfig get smtp config
|
// @Description GetSMTPConfig get smtp config
|
||||||
|
@ -366,3 +397,34 @@ func (sc *SiteInfoController) UpdateSMTPConfig(ctx *gin.Context) {
|
||||||
err := sc.siteInfoService.UpdateSMTPConfig(ctx, req)
|
err := sc.siteInfoService.UpdateSMTPConfig(ctx, req)
|
||||||
handler.HandleResponse(ctx, err, nil)
|
handler.HandleResponse(ctx, err, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetPrivilegesConfig get privileges config
|
||||||
|
// @Summary GetPrivilegesConfig get privileges config
|
||||||
|
// @Description GetPrivilegesConfig get privileges config
|
||||||
|
// @Security ApiKeyAuth
|
||||||
|
// @Tags admin
|
||||||
|
// @Produce json
|
||||||
|
// @Success 200 {object} handler.RespBody{data=schema.GetPrivilegesConfigResp}
|
||||||
|
// @Router /answer/admin/api/setting/privileges [get]
|
||||||
|
func (sc *SiteInfoController) GetPrivilegesConfig(ctx *gin.Context) {
|
||||||
|
resp, err := sc.siteInfoService.GetPrivilegesConfig(ctx)
|
||||||
|
handler.HandleResponse(ctx, err, resp)
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdatePrivilegesConfig update privileges config
|
||||||
|
// @Summary update privileges config
|
||||||
|
// @Description update privileges config
|
||||||
|
// @Security ApiKeyAuth
|
||||||
|
// @Tags admin
|
||||||
|
// @Produce json
|
||||||
|
// @Param data body schema.UpdatePrivilegesConfigReq true "config"
|
||||||
|
// @Success 200 {object} handler.RespBody{}
|
||||||
|
// @Router /answer/admin/api/setting/privileges [put]
|
||||||
|
func (sc *SiteInfoController) UpdatePrivilegesConfig(ctx *gin.Context) {
|
||||||
|
req := &schema.UpdatePrivilegesConfigReq{}
|
||||||
|
if handler.BindAndCheck(ctx, req) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err := sc.siteInfoService.UpdatePrivilegesConfig(ctx, req)
|
||||||
|
handler.HandleResponse(ctx, err, nil)
|
||||||
|
}
|
||||||
|
|
|
@ -32,7 +32,7 @@ func NewUserAdminController(userService *user_admin.UserAdminService) *UserAdmin
|
||||||
// @Success 200 {object} handler.RespBody
|
// @Success 200 {object} handler.RespBody
|
||||||
// @Router /answer/admin/api/user/status [put]
|
// @Router /answer/admin/api/user/status [put]
|
||||||
func (uc *UserAdminController) UpdateUserStatus(ctx *gin.Context) {
|
func (uc *UserAdminController) UpdateUserStatus(ctx *gin.Context) {
|
||||||
if plugin.UserCenterEnabled() {
|
if u, ok := plugin.GetUserCenter(); ok && u.Description().UserStatusAgentEnabled {
|
||||||
handler.HandleResponse(ctx, errors.Forbidden(reason.ForbiddenError), nil)
|
handler.HandleResponse(ctx, errors.Forbidden(reason.ForbiddenError), nil)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -80,10 +80,6 @@ func (uc *UserAdminController) UpdateUserRole(ctx *gin.Context) {
|
||||||
// @Success 200 {object} handler.RespBody
|
// @Success 200 {object} handler.RespBody
|
||||||
// @Router /answer/admin/api/user [post]
|
// @Router /answer/admin/api/user [post]
|
||||||
func (uc *UserAdminController) AddUser(ctx *gin.Context) {
|
func (uc *UserAdminController) AddUser(ctx *gin.Context) {
|
||||||
if plugin.UserCenterEnabled() {
|
|
||||||
handler.HandleResponse(ctx, errors.Forbidden(reason.ForbiddenError), nil)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
req := &schema.AddUserReq{}
|
req := &schema.AddUserReq{}
|
||||||
if handler.BindAndCheck(ctx, req) {
|
if handler.BindAndCheck(ctx, req) {
|
||||||
return
|
return
|
||||||
|
@ -106,10 +102,6 @@ func (uc *UserAdminController) AddUser(ctx *gin.Context) {
|
||||||
// @Success 200 {object} handler.RespBody
|
// @Success 200 {object} handler.RespBody
|
||||||
// @Router /answer/admin/api/user/password [put]
|
// @Router /answer/admin/api/user/password [put]
|
||||||
func (uc *UserAdminController) UpdateUserPassword(ctx *gin.Context) {
|
func (uc *UserAdminController) UpdateUserPassword(ctx *gin.Context) {
|
||||||
if plugin.UserCenterEnabled() {
|
|
||||||
handler.HandleResponse(ctx, errors.Forbidden(reason.ForbiddenError), nil)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
req := &schema.UpdateUserPasswordReq{}
|
req := &schema.UpdateUserPasswordReq{}
|
||||||
if handler.BindAndCheck(ctx, req) {
|
if handler.BindAndCheck(ctx, req) {
|
||||||
return
|
return
|
||||||
|
|
|
@ -6,4 +6,5 @@ type UserCacheInfo struct {
|
||||||
UserStatus int `json:"user_status"`
|
UserStatus int `json:"user_status"`
|
||||||
EmailStatus int `json:"email_status"`
|
EmailStatus int `json:"email_status"`
|
||||||
RoleID int `json:"role_id"`
|
RoleID int `json:"role_id"`
|
||||||
|
ExternalID string `json:"external_id"`
|
||||||
}
|
}
|
||||||
|
|
|
@ -143,8 +143,9 @@ func initSiteInfo(engine *xorm.Engine, language, siteName, siteURL, contactEmail
|
||||||
}
|
}
|
||||||
|
|
||||||
loginConfig := map[string]bool{
|
loginConfig := map[string]bool{
|
||||||
"allow_new_registrations": true,
|
"allow_new_registrations": true,
|
||||||
"login_required": false,
|
"allow_email_registrations": true,
|
||||||
|
"login_required": false,
|
||||||
}
|
}
|
||||||
loginConfigDataBytes, _ := json.Marshal(loginConfig)
|
loginConfigDataBytes, _ := json.Marshal(loginConfig)
|
||||||
_, err = engine.InsertOne(&entity.SiteInfo{
|
_, err = engine.InsertOne(&entity.SiteInfo{
|
||||||
|
@ -178,6 +179,25 @@ func initSiteInfo(engine *xorm.Engine, language, siteName, siteURL, contactEmail
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
usersData := map[string]any{
|
||||||
|
"default_avatar": "gravatar",
|
||||||
|
"allow_update_display_name": true,
|
||||||
|
"allow_update_username": true,
|
||||||
|
"allow_update_avatar": true,
|
||||||
|
"allow_update_bio": true,
|
||||||
|
"allow_update_website": true,
|
||||||
|
"allow_update_location": true,
|
||||||
|
}
|
||||||
|
usersDataBytes, _ := json.Marshal(usersData)
|
||||||
|
_, err = engine.InsertOne(&entity.SiteInfo{
|
||||||
|
Type: "users",
|
||||||
|
Content: string(usersDataBytes),
|
||||||
|
Status: 1,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -346,10 +366,14 @@ func initConfigTable(engine *xorm.Engine) error {
|
||||||
{ID: 116, Key: "rank.question.reopen", Value: `-1`},
|
{ID: 116, Key: "rank.question.reopen", Value: `-1`},
|
||||||
{ID: 117, Key: "rank.tag.use_reserved_tag", Value: `-1`},
|
{ID: 117, Key: "rank.tag.use_reserved_tag", Value: `-1`},
|
||||||
{ID: 118, Key: "plugin.status", Value: `{}`},
|
{ID: 118, Key: "plugin.status", Value: `{}`},
|
||||||
{ID: 119, Key: "question.pin", Value: `-1`},
|
{ID: 119, Key: "question.pin", Value: `0`},
|
||||||
{ID: 120, Key: "question.unpin", Value: `-1`},
|
{ID: 120, Key: "question.unpin", Value: `0`},
|
||||||
{ID: 121, Key: "question.show", Value: `-1`},
|
{ID: 121, Key: "question.show", Value: `0`},
|
||||||
{ID: 122, Key: "question.hide", Value: `-1`},
|
{ID: 122, Key: "question.hide", Value: `0`},
|
||||||
|
{ID: 123, Key: "rank.question.pin", Value: `-1`},
|
||||||
|
{ID: 124, Key: "rank.question.unpin", Value: `-1`},
|
||||||
|
{ID: 125, Key: "rank.question.show", Value: `-1`},
|
||||||
|
{ID: 126, Key: "rank.question.hide", Value: `-1`},
|
||||||
}
|
}
|
||||||
_, err := engine.Insert(defaultConfigTable)
|
_, err := engine.Insert(defaultConfigTable)
|
||||||
return err
|
return err
|
||||||
|
|
|
@ -61,6 +61,7 @@ var migrations = []Migration{
|
||||||
NewMigration("add plugin", addPlugin, false),
|
NewMigration("add plugin", addPlugin, false),
|
||||||
NewMigration("update user pin hide features", updateRolePinAndHideFeatures, true),
|
NewMigration("update user pin hide features", updateRolePinAndHideFeatures, true),
|
||||||
NewMigration("update question post time", updateQuestionPostTime, true),
|
NewMigration("update question post time", updateQuestionPostTime, true),
|
||||||
|
NewMigration("add login limitations", addLoginLimitations, true),
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetCurrentDBVersion returns the current db version
|
// GetCurrentDBVersion returns the current db version
|
||||||
|
|
|
@ -0,0 +1,69 @@
|
||||||
|
package migrations
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/answerdev/answer/internal/base/constant"
|
||||||
|
"github.com/answerdev/answer/internal/entity"
|
||||||
|
"github.com/answerdev/answer/internal/schema"
|
||||||
|
"github.com/tidwall/gjson"
|
||||||
|
"xorm.io/xorm"
|
||||||
|
)
|
||||||
|
|
||||||
|
func addLoginLimitations(x *xorm.Engine) error {
|
||||||
|
loginSiteInfo := &entity.SiteInfo{
|
||||||
|
Type: constant.SiteTypeLogin,
|
||||||
|
}
|
||||||
|
exist, err := x.Get(loginSiteInfo)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("get config failed: %w", err)
|
||||||
|
}
|
||||||
|
if exist {
|
||||||
|
content := &schema.SiteLoginReq{}
|
||||||
|
_ = json.Unmarshal([]byte(loginSiteInfo.Content), content)
|
||||||
|
content.AllowEmailRegistrations = true
|
||||||
|
content.AllowEmailDomains = make([]string, 0)
|
||||||
|
_, err = x.ID(loginSiteInfo.ID).Cols("content").Update(loginSiteInfo)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("update site info failed: %w", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
interfaceSiteInfo := &entity.SiteInfo{
|
||||||
|
Type: constant.SiteTypeInterface,
|
||||||
|
}
|
||||||
|
exist, err = x.Get(interfaceSiteInfo)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("get config failed: %w", err)
|
||||||
|
}
|
||||||
|
siteUsers := &schema.SiteUsersReq{
|
||||||
|
AllowUpdateDisplayName: true,
|
||||||
|
AllowUpdateUsername: true,
|
||||||
|
AllowUpdateAvatar: true,
|
||||||
|
AllowUpdateBio: true,
|
||||||
|
AllowUpdateWebsite: true,
|
||||||
|
AllowUpdateLocation: true,
|
||||||
|
}
|
||||||
|
if exist {
|
||||||
|
siteUsers.DefaultAvatar = gjson.Get(interfaceSiteInfo.Content, "default_avatar").String()
|
||||||
|
}
|
||||||
|
data, _ := json.Marshal(siteUsers)
|
||||||
|
|
||||||
|
exist, err = x.Get(&entity.SiteInfo{Type: constant.SiteTypeUsers})
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("get config failed: %w", err)
|
||||||
|
}
|
||||||
|
if !exist {
|
||||||
|
usersSiteInfo := &entity.SiteInfo{
|
||||||
|
Type: constant.SiteTypeUsers,
|
||||||
|
Content: string(data),
|
||||||
|
Status: 1,
|
||||||
|
}
|
||||||
|
_, err = x.InsertOne(usersSiteInfo)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("insert site info failed: %w", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
|
@ -18,10 +18,6 @@ func addPlugin(x *xorm.Engine) error {
|
||||||
return fmt.Errorf("get config failed: %w", err)
|
return fmt.Errorf("get config failed: %w", err)
|
||||||
}
|
}
|
||||||
if exist {
|
if exist {
|
||||||
if _, err = x.Update(c, &entity.Config{ID: c.ID, Key: c.Key}); err != nil {
|
|
||||||
log.Errorf("update %+v config failed: %s", c, err)
|
|
||||||
return fmt.Errorf("update config failed: %w", err)
|
|
||||||
}
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if _, err = x.Insert(&entity.Config{ID: c.ID, Key: c.Key, Value: c.Value}); err != nil {
|
if _, err = x.Insert(&entity.Config{ID: c.ID, Key: c.Key, Value: c.Value}); err != nil {
|
||||||
|
|
|
@ -202,7 +202,9 @@ func (ar *AnswerActivityRepo) AcceptAnswer(ctx context.Context,
|
||||||
msg.TriggerUserID = questionUserID
|
msg.TriggerUserID = questionUserID
|
||||||
msg.ObjectType = constant.AnswerObjectType
|
msg.ObjectType = constant.AnswerObjectType
|
||||||
}
|
}
|
||||||
notice_queue.AddNotification(msg)
|
if msg.TriggerUserID != msg.ReceiverUserID {
|
||||||
|
notice_queue.AddNotification(msg)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, act := range addActivityList {
|
for _, act := range addActivityList {
|
||||||
|
@ -214,7 +216,7 @@ func (ar *AnswerActivityRepo) AcceptAnswer(ctx context.Context,
|
||||||
if act.UserID != questionUserID {
|
if act.UserID != questionUserID {
|
||||||
msg.TriggerUserID = questionUserID
|
msg.TriggerUserID = questionUserID
|
||||||
msg.ObjectType = constant.AnswerObjectType
|
msg.ObjectType = constant.AnswerObjectType
|
||||||
msg.NotificationAction = constant.AcceptAnswer
|
msg.NotificationAction = constant.NotificationAcceptAnswer
|
||||||
notice_queue.AddNotification(msg)
|
notice_queue.AddNotification(msg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,7 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/answerdev/answer/internal/base/constant"
|
||||||
"github.com/answerdev/answer/pkg/converter"
|
"github.com/answerdev/answer/pkg/converter"
|
||||||
|
|
||||||
"github.com/answerdev/answer/internal/base/pager"
|
"github.com/answerdev/answer/internal/base/pager"
|
||||||
|
@ -70,7 +71,9 @@ var LimitDownActions = map[string][]string{
|
||||||
|
|
||||||
func (vr *VoteRepo) vote(ctx context.Context, objectID string, userID, objectUserID string, actions []string) (resp *schema.VoteResp, err error) {
|
func (vr *VoteRepo) vote(ctx context.Context, objectID string, userID, objectUserID string, actions []string) (resp *schema.VoteResp, err error) {
|
||||||
resp = &schema.VoteResp{}
|
resp = &schema.VoteResp{}
|
||||||
notificationUserIDs := make([]string, 0)
|
achievementNotificationUserIDs := make([]string, 0)
|
||||||
|
sendInboxNotification := false
|
||||||
|
upVote := false
|
||||||
_, err = vr.data.DB.Transaction(func(session *xorm.Session) (result any, err error) {
|
_, err = vr.data.DB.Transaction(func(session *xorm.Session) (result any, err error) {
|
||||||
result = nil
|
result = nil
|
||||||
for _, action := range actions {
|
for _, action := range actions {
|
||||||
|
@ -127,7 +130,7 @@ func (vr *VoteRepo) vote(ctx context.Context, objectID string, userID, objectUse
|
||||||
if isReachStandard {
|
if isReachStandard {
|
||||||
insertActivity.Rank = 0
|
insertActivity.Rank = 0
|
||||||
}
|
}
|
||||||
notificationUserIDs = append(notificationUserIDs, activityUserID)
|
achievementNotificationUserIDs = append(achievementNotificationUserIDs, activityUserID)
|
||||||
}
|
}
|
||||||
|
|
||||||
if has {
|
if has {
|
||||||
|
@ -142,13 +145,17 @@ func (vr *VoteRepo) vote(ctx context.Context, objectID string, userID, objectUse
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
sendInboxNotification = true
|
||||||
}
|
}
|
||||||
|
|
||||||
// update votes
|
// update votes
|
||||||
if action == "vote_down" || action == "vote_up" {
|
if action == constant.ActVoteDown || action == constant.ActVoteUp {
|
||||||
votes := 1
|
votes := 1
|
||||||
if action == "vote_down" {
|
if action == constant.ActVoteDown {
|
||||||
|
upVote = false
|
||||||
votes = -1
|
votes = -1
|
||||||
|
} else {
|
||||||
|
upVote = true
|
||||||
}
|
}
|
||||||
err = vr.updateVotes(ctx, session, objectID, votes)
|
err = vr.updateVotes(ctx, session, objectID, votes)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -165,9 +172,12 @@ func (vr *VoteRepo) vote(ctx context.Context, objectID string, userID, objectUse
|
||||||
resp, err = vr.GetVoteResultByObjectId(ctx, objectID)
|
resp, err = vr.GetVoteResultByObjectId(ctx, objectID)
|
||||||
resp.VoteStatus = vr.voteCommon.GetVoteStatus(ctx, objectID, userID)
|
resp.VoteStatus = vr.voteCommon.GetVoteStatus(ctx, objectID, userID)
|
||||||
|
|
||||||
for _, activityUserID := range notificationUserIDs {
|
for _, activityUserID := range achievementNotificationUserIDs {
|
||||||
vr.sendNotification(ctx, activityUserID, objectUserID, objectID)
|
vr.sendNotification(ctx, activityUserID, objectUserID, objectID)
|
||||||
}
|
}
|
||||||
|
if sendInboxNotification {
|
||||||
|
vr.sendVoteInboxNotification(userID, objectUserID, objectID, upVote)
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -441,3 +451,40 @@ func (vr *VoteRepo) sendNotification(ctx context.Context, activityUserID, object
|
||||||
}
|
}
|
||||||
notice_queue.AddNotification(msg)
|
notice_queue.AddNotification(msg)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (vr *VoteRepo) sendVoteInboxNotification(triggerUserID, receiverUserID, objectID string, upvote bool) {
|
||||||
|
if triggerUserID == receiverUserID {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
objectType, _ := obj.GetObjectTypeStrByObjectID(objectID)
|
||||||
|
|
||||||
|
msg := &schema.NotificationMsg{
|
||||||
|
TriggerUserID: triggerUserID,
|
||||||
|
ReceiverUserID: receiverUserID,
|
||||||
|
Type: schema.NotificationTypeInbox,
|
||||||
|
ObjectID: objectID,
|
||||||
|
ObjectType: objectType,
|
||||||
|
}
|
||||||
|
if objectType == constant.QuestionObjectType {
|
||||||
|
if upvote {
|
||||||
|
msg.NotificationAction = constant.NotificationUpVotedTheQuestion
|
||||||
|
} else {
|
||||||
|
msg.NotificationAction = constant.NotificationDownVotedTheQuestion
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if objectType == constant.AnswerObjectType {
|
||||||
|
if upvote {
|
||||||
|
msg.NotificationAction = constant.NotificationUpVotedTheAnswer
|
||||||
|
} else {
|
||||||
|
msg.NotificationAction = constant.NotificationDownVotedTheAnswer
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if objectType == constant.CommentObjectType {
|
||||||
|
if upvote {
|
||||||
|
msg.NotificationAction = constant.NotificationUpVotedTheComment
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(msg.NotificationAction) > 0 {
|
||||||
|
notice_queue.AddNotification(msg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -255,7 +255,7 @@ func (qr *questionRepo) GetQuestionIDsPage(ctx context.Context, page, pageSize i
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetQuestionPage query question page
|
// GetQuestionPage query question page
|
||||||
func (qr *questionRepo) GetQuestionPage(ctx context.Context, page, pageSize int, userID, tagID, orderCond string) (
|
func (qr *questionRepo) GetQuestionPage(ctx context.Context, page, pageSize int, userID, tagID, orderCond string, inDays int) (
|
||||||
questionList []*entity.Question, total int64, err error) {
|
questionList []*entity.Question, total int64, err error) {
|
||||||
questionList = make([]*entity.Question, 0)
|
questionList = make([]*entity.Question, 0)
|
||||||
|
|
||||||
|
@ -271,6 +271,9 @@ func (qr *questionRepo) GetQuestionPage(ctx context.Context, page, pageSize int,
|
||||||
} else {
|
} else {
|
||||||
session.And("question.show = ?", entity.QuestionShow)
|
session.And("question.show = ?", entity.QuestionShow)
|
||||||
}
|
}
|
||||||
|
if inDays > 0 {
|
||||||
|
session.And("question.created_at > ?", time.Now().AddDate(0, 0, -inDays))
|
||||||
|
}
|
||||||
|
|
||||||
switch orderCond {
|
switch orderCond {
|
||||||
case "newest":
|
case "newest":
|
||||||
|
|
|
@ -86,6 +86,9 @@ func (ur *userAdminRepo) GetUserInfo(ctx context.Context, userID string) (user *
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, false, errors.InternalServer(reason.DatabaseError).WithError(err).WithStack()
|
return nil, false, errors.InternalServer(reason.DatabaseError).WithError(err).WithStack()
|
||||||
}
|
}
|
||||||
|
if !exist {
|
||||||
|
return
|
||||||
|
}
|
||||||
err = tryToDecorateUserInfoFromUserCenter(ctx, ur.data, user)
|
err = tryToDecorateUserInfoFromUserCenter(ctx, ur.data, user)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, false, err
|
return nil, false, err
|
||||||
|
@ -102,6 +105,9 @@ func (ur *userAdminRepo) GetUserInfoByEmail(ctx context.Context, email string) (
|
||||||
err = errors.InternalServer(reason.DatabaseError).WithError(err).WithStack()
|
err = errors.InternalServer(reason.DatabaseError).WithError(err).WithStack()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
if !exist {
|
||||||
|
return
|
||||||
|
}
|
||||||
err = tryToDecorateUserInfoFromUserCenter(ctx, ur.data, user)
|
err = tryToDecorateUserInfoFromUserCenter(ctx, ur.data, user)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, false, err
|
return nil, false, err
|
||||||
|
|
|
@ -10,6 +10,7 @@ import (
|
||||||
"github.com/answerdev/answer/internal/schema"
|
"github.com/answerdev/answer/internal/schema"
|
||||||
"github.com/answerdev/answer/internal/service/config"
|
"github.com/answerdev/answer/internal/service/config"
|
||||||
usercommon "github.com/answerdev/answer/internal/service/user_common"
|
usercommon "github.com/answerdev/answer/internal/service/user_common"
|
||||||
|
"github.com/answerdev/answer/pkg/converter"
|
||||||
"github.com/answerdev/answer/plugin"
|
"github.com/answerdev/answer/plugin"
|
||||||
"github.com/segmentfault/pacman/errors"
|
"github.com/segmentfault/pacman/errors"
|
||||||
"github.com/segmentfault/pacman/log"
|
"github.com/segmentfault/pacman/log"
|
||||||
|
@ -195,6 +196,9 @@ func (ur *userRepo) GetUserCount(ctx context.Context) (count int64, err error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func tryToDecorateUserInfoFromUserCenter(ctx context.Context, data *data.Data, original *entity.User) (err error) {
|
func tryToDecorateUserInfoFromUserCenter(ctx context.Context, data *data.Data, original *entity.User) (err error) {
|
||||||
|
if original == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
uc, ok := plugin.GetUserCenter()
|
uc, ok := plugin.GetUserCenter()
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil
|
return nil
|
||||||
|
@ -276,14 +280,27 @@ func decorateByUserCenterUser(original *entity.User, ucUser *plugin.UserCenterBa
|
||||||
if original.Username != ucUser.Username {
|
if original.Username != ucUser.Username {
|
||||||
log.Warnf("user %s username is inconsistent with user center", original.ID)
|
log.Warnf("user %s username is inconsistent with user center", original.ID)
|
||||||
}
|
}
|
||||||
original.DisplayName = ucUser.DisplayName
|
if len(ucUser.DisplayName) > 0 {
|
||||||
original.EMail = ucUser.Email
|
original.DisplayName = ucUser.DisplayName
|
||||||
original.Avatar = schema.CustomAvatar(ucUser.Avatar).ToJsonString()
|
}
|
||||||
original.Mobile = ucUser.Mobile
|
if len(ucUser.Email) > 0 {
|
||||||
|
original.EMail = ucUser.Email
|
||||||
|
}
|
||||||
|
if len(ucUser.Avatar) > 0 {
|
||||||
|
original.Avatar = schema.CustomAvatar(ucUser.Avatar).ToJsonString()
|
||||||
|
}
|
||||||
|
if len(ucUser.Mobile) > 0 {
|
||||||
|
original.Mobile = ucUser.Mobile
|
||||||
|
}
|
||||||
|
if len(ucUser.Bio) > 0 {
|
||||||
|
original.BioHTML = converter.Markdown2HTML(ucUser.Bio) + original.BioHTML
|
||||||
|
}
|
||||||
|
|
||||||
// If plugin enable rank agent, use rank from user center.
|
// If plugin enable rank agent, use rank from user center.
|
||||||
if plugin.RankAgentEnabled() {
|
if plugin.RankAgentEnabled() {
|
||||||
original.Rank = ucUser.Rank
|
original.Rank = ucUser.Rank
|
||||||
}
|
}
|
||||||
original.Status = int(ucUser.Status)
|
if ucUser.Status != plugin.UserStatusAvailable {
|
||||||
|
original.Status = int(ucUser.Status)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -102,7 +102,7 @@ func (a *AnswerAPIRouter) RegisterMustUnAuthAnswerAPIRouter(r *gin.RouterGroup)
|
||||||
|
|
||||||
// user
|
// user
|
||||||
r.GET("/user/info", a.userController.GetUserInfoByUserID)
|
r.GET("/user/info", a.userController.GetUserInfoByUserID)
|
||||||
routerGroup := r.Group("", middleware.BanAPIWhenUserCenterEnabled)
|
routerGroup := r.Group("", middleware.BanAPIForUserCenter)
|
||||||
routerGroup.POST("/user/login/email", a.userController.UserEmailLogin)
|
routerGroup.POST("/user/login/email", a.userController.UserEmailLogin)
|
||||||
routerGroup.POST("/user/register/email", a.userController.UserRegisterByEmail)
|
routerGroup.POST("/user/register/email", a.userController.UserRegisterByEmail)
|
||||||
routerGroup.GET("/user/register/captcha", a.userController.UserRegisterCaptcha)
|
routerGroup.GET("/user/register/captcha", a.userController.UserRegisterCaptcha)
|
||||||
|
@ -117,8 +117,8 @@ func (a *AnswerAPIRouter) RegisterMustUnAuthAnswerAPIRouter(r *gin.RouterGroup)
|
||||||
func (a *AnswerAPIRouter) RegisterUnAuthAnswerAPIRouter(r *gin.RouterGroup) {
|
func (a *AnswerAPIRouter) RegisterUnAuthAnswerAPIRouter(r *gin.RouterGroup) {
|
||||||
// user
|
// user
|
||||||
r.GET("/user/logout", a.userController.UserLogout)
|
r.GET("/user/logout", a.userController.UserLogout)
|
||||||
r.POST("/user/email/change/code", middleware.BanAPIWhenUserCenterEnabled, a.userController.UserChangeEmailSendCode)
|
r.POST("/user/email/change/code", middleware.BanAPIForUserCenter, a.userController.UserChangeEmailSendCode)
|
||||||
r.POST("/user/email/verification/send", middleware.BanAPIWhenUserCenterEnabled, a.userController.UserVerifyEmailSend)
|
r.POST("/user/email/verification/send", middleware.BanAPIForUserCenter, a.userController.UserVerifyEmailSend)
|
||||||
r.GET("/personal/user/info", a.userController.GetOtherUserInfoByUsername)
|
r.GET("/personal/user/info", a.userController.GetOtherUserInfoByUsername)
|
||||||
r.GET("/user/ranking", a.userController.UserRanking)
|
r.GET("/user/ranking", a.userController.UserRanking)
|
||||||
|
|
||||||
|
@ -206,8 +206,8 @@ func (a *AnswerAPIRouter) RegisterAnswerAPIRouter(r *gin.RouterGroup) {
|
||||||
r.DELETE("/answer", a.answerController.RemoveAnswer)
|
r.DELETE("/answer", a.answerController.RemoveAnswer)
|
||||||
|
|
||||||
// user
|
// user
|
||||||
r.PUT("/user/password", middleware.BanAPIWhenUserCenterEnabled, a.userController.UserModifyPassWord)
|
r.PUT("/user/password", middleware.BanAPIForUserCenter, a.userController.UserModifyPassWord)
|
||||||
r.PUT("/user/info", middleware.BanAPIWhenUserCenterEnabled, a.userController.UserUpdateInfo)
|
r.PUT("/user/info", a.userController.UserUpdateInfo)
|
||||||
r.PUT("/user/interface", a.userController.UserUpdateInterface)
|
r.PUT("/user/interface", a.userController.UserUpdateInterface)
|
||||||
r.POST("/user/notice/set", a.userController.UserNoticeSet)
|
r.POST("/user/notice/set", a.userController.UserNoticeSet)
|
||||||
|
|
||||||
|
@ -246,10 +246,10 @@ func (a *AnswerAPIRouter) RegisterAnswerAdminAPIRouter(r *gin.RouterGroup) {
|
||||||
|
|
||||||
// user
|
// user
|
||||||
r.GET("/users/page", a.adminUserController.GetUserPage)
|
r.GET("/users/page", a.adminUserController.GetUserPage)
|
||||||
r.PUT("/user/status", middleware.BanAPIWhenUserCenterEnabled, a.adminUserController.UpdateUserStatus)
|
r.PUT("/user/status", a.adminUserController.UpdateUserStatus)
|
||||||
r.PUT("/user/role", a.adminUserController.UpdateUserRole)
|
r.PUT("/user/role", a.adminUserController.UpdateUserRole)
|
||||||
r.POST("/user", middleware.BanAPIWhenUserCenterEnabled, a.adminUserController.AddUser)
|
r.POST("/user", a.adminUserController.AddUser)
|
||||||
r.PUT("/user/password", middleware.BanAPIWhenUserCenterEnabled, a.adminUserController.UpdateUserPassword)
|
r.PUT("/user/password", a.adminUserController.UpdateUserPassword)
|
||||||
|
|
||||||
// reason
|
// reason
|
||||||
r.GET("/reasons", a.reasonController.Reasons)
|
r.GET("/reasons", a.reasonController.Reasons)
|
||||||
|
@ -262,25 +262,29 @@ func (a *AnswerAPIRouter) RegisterAnswerAdminAPIRouter(r *gin.RouterGroup) {
|
||||||
|
|
||||||
// siteinfo
|
// siteinfo
|
||||||
r.GET("/siteinfo/general", a.siteInfoController.GetGeneral)
|
r.GET("/siteinfo/general", a.siteInfoController.GetGeneral)
|
||||||
r.GET("/siteinfo/interface", a.siteInfoController.GetInterface)
|
|
||||||
r.GET("/siteinfo/branding", a.siteInfoController.GetSiteBranding)
|
|
||||||
r.GET("/siteinfo/write", a.siteInfoController.GetSiteWrite)
|
|
||||||
r.GET("/siteinfo/legal", a.siteInfoController.GetSiteLegal)
|
|
||||||
r.GET("/siteinfo/seo", a.siteInfoController.GetSeo)
|
|
||||||
r.GET("/siteinfo/login", a.siteInfoController.GetSiteLogin)
|
|
||||||
r.GET("/siteinfo/custom-css-html", a.siteInfoController.GetSiteCustomCssHTML)
|
|
||||||
r.GET("/siteinfo/theme", a.siteInfoController.GetSiteTheme)
|
|
||||||
r.PUT("/siteinfo/general", a.siteInfoController.UpdateGeneral)
|
r.PUT("/siteinfo/general", a.siteInfoController.UpdateGeneral)
|
||||||
|
r.GET("/siteinfo/interface", a.siteInfoController.GetInterface)
|
||||||
r.PUT("/siteinfo/interface", a.siteInfoController.UpdateInterface)
|
r.PUT("/siteinfo/interface", a.siteInfoController.UpdateInterface)
|
||||||
|
r.GET("/siteinfo/branding", a.siteInfoController.GetSiteBranding)
|
||||||
r.PUT("/siteinfo/branding", a.siteInfoController.UpdateBranding)
|
r.PUT("/siteinfo/branding", a.siteInfoController.UpdateBranding)
|
||||||
|
r.GET("/siteinfo/write", a.siteInfoController.GetSiteWrite)
|
||||||
r.PUT("/siteinfo/write", a.siteInfoController.UpdateSiteWrite)
|
r.PUT("/siteinfo/write", a.siteInfoController.UpdateSiteWrite)
|
||||||
|
r.GET("/siteinfo/legal", a.siteInfoController.GetSiteLegal)
|
||||||
r.PUT("/siteinfo/legal", a.siteInfoController.UpdateSiteLegal)
|
r.PUT("/siteinfo/legal", a.siteInfoController.UpdateSiteLegal)
|
||||||
r.PUT("/siteinfo/login", a.siteInfoController.UpdateSiteLogin)
|
r.GET("/siteinfo/seo", a.siteInfoController.GetSeo)
|
||||||
r.PUT("/siteinfo/custom-css-html", a.siteInfoController.UpdateSiteCustomCssHTML)
|
|
||||||
r.PUT("/siteinfo/theme", a.siteInfoController.SaveSiteTheme)
|
|
||||||
r.PUT("/siteinfo/seo", a.siteInfoController.UpdateSeo)
|
r.PUT("/siteinfo/seo", a.siteInfoController.UpdateSeo)
|
||||||
|
r.GET("/siteinfo/login", a.siteInfoController.GetSiteLogin)
|
||||||
|
r.PUT("/siteinfo/login", a.siteInfoController.UpdateSiteLogin)
|
||||||
|
r.GET("/siteinfo/custom-css-html", a.siteInfoController.GetSiteCustomCssHTML)
|
||||||
|
r.PUT("/siteinfo/custom-css-html", a.siteInfoController.UpdateSiteCustomCssHTML)
|
||||||
|
r.GET("/siteinfo/theme", a.siteInfoController.GetSiteTheme)
|
||||||
|
r.PUT("/siteinfo/theme", a.siteInfoController.SaveSiteTheme)
|
||||||
|
r.GET("/siteinfo/users", a.siteInfoController.GetSiteUsers)
|
||||||
|
r.PUT("/siteinfo/users", a.siteInfoController.UpdateSiteUsers)
|
||||||
r.GET("/setting/smtp", a.siteInfoController.GetSMTPConfig)
|
r.GET("/setting/smtp", a.siteInfoController.GetSMTPConfig)
|
||||||
r.PUT("/setting/smtp", a.siteInfoController.UpdateSMTPConfig)
|
r.PUT("/setting/smtp", a.siteInfoController.UpdateSMTPConfig)
|
||||||
|
r.GET("/setting/privileges", a.siteInfoController.GetPrivilegesConfig)
|
||||||
|
r.PUT("/setting/privileges", a.siteInfoController.UpdatePrivilegesConfig)
|
||||||
|
|
||||||
// dashboard
|
// dashboard
|
||||||
r.GET("/dashboard", a.dashboardController.DashboardInfo)
|
r.GET("/dashboard", a.dashboardController.DashboardInfo)
|
||||||
|
|
|
@ -37,10 +37,14 @@ func (pr *PluginAPIRouter) RegisterUnAuthConnectorRouter(r *gin.RouterGroup) {
|
||||||
r.GET("/user-center/sign-up/callback", pr.userCenterController.UserCenterSignUpCallback)
|
r.GET("/user-center/sign-up/callback", pr.userCenterController.UserCenterSignUpCallback)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pr *PluginAPIRouter) RegisterAuthConnectorRouter(r *gin.RouterGroup) {
|
func (pr *PluginAPIRouter) RegisterAuthUserConnectorRouter(r *gin.RouterGroup) {
|
||||||
connectorController := pr.connectorController
|
connectorController := pr.connectorController
|
||||||
r.GET("/connector/user/info", connectorController.ConnectorsUserInfo)
|
r.GET("/connector/user/info", connectorController.ConnectorsUserInfo)
|
||||||
r.DELETE("/connector/user/unbinding", connectorController.ExternalLoginUnbinding)
|
r.DELETE("/connector/user/unbinding", connectorController.ExternalLoginUnbinding)
|
||||||
|
|
||||||
r.GET("/user-center/user/settings", pr.userCenterController.UserCenterUserSettings)
|
r.GET("/user-center/user/settings", pr.userCenterController.UserCenterUserSettings)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (pr *PluginAPIRouter) RegisterAuthAdminConnectorRouter(r *gin.RouterGroup) {
|
||||||
|
r.GET("/user-center/agent", pr.userCenterController.UserCenterAdminFunctionAgent)
|
||||||
|
}
|
||||||
|
|
|
@ -56,10 +56,31 @@ func (g *GetPluginConfigResp) SetConfigFields(ctx *gin.Context, fields []plugin.
|
||||||
UIOptions: ConfigFieldUIOptions{
|
UIOptions: ConfigFieldUIOptions{
|
||||||
Rows: field.UIOptions.Rows,
|
Rows: field.UIOptions.Rows,
|
||||||
InputType: string(field.UIOptions.InputType),
|
InputType: string(field.UIOptions.InputType),
|
||||||
|
Variant: field.UIOptions.Variant,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
configField.UIOptions.Placeholder = field.UIOptions.Placeholder.Translate(ctx)
|
configField.UIOptions.Placeholder = field.UIOptions.Placeholder.Translate(ctx)
|
||||||
configField.UIOptions.Label = field.UIOptions.Label.Translate(ctx)
|
configField.UIOptions.Label = field.UIOptions.Label.Translate(ctx)
|
||||||
|
configField.UIOptions.Text = field.UIOptions.Text.Translate(ctx)
|
||||||
|
if field.UIOptions.Action != nil {
|
||||||
|
uiOptionAction := &UIOptionAction{
|
||||||
|
Url: field.UIOptions.Action.Url,
|
||||||
|
Method: field.UIOptions.Action.Method,
|
||||||
|
}
|
||||||
|
if field.UIOptions.Action.Loading != nil {
|
||||||
|
uiOptionAction.Loading = &LoadingAction{
|
||||||
|
Text: field.UIOptions.Action.Loading.Text.Translate(ctx),
|
||||||
|
State: string(field.UIOptions.Action.Loading.State),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if field.UIOptions.Action.OnComplete != nil {
|
||||||
|
uiOptionAction.OnCompleteAction = &OnCompleteAction{
|
||||||
|
ToastReturnMessage: field.UIOptions.Action.OnComplete.ToastReturnMessage,
|
||||||
|
RefreshFormConfig: field.UIOptions.Action.OnComplete.RefreshFormConfig,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
configField.UIOptions.Action = uiOptionAction
|
||||||
|
}
|
||||||
|
|
||||||
for _, option := range field.Options {
|
for _, option := range field.Options {
|
||||||
configField.Options = append(configField.Options, ConfigFieldOption{
|
configField.Options = append(configField.Options, ConfigFieldOption{
|
||||||
|
@ -83,10 +104,13 @@ type ConfigField struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type ConfigFieldUIOptions struct {
|
type ConfigFieldUIOptions struct {
|
||||||
Placeholder string `json:"placeholder,omitempty"`
|
Placeholder string `json:"placeholder,omitempty"`
|
||||||
Rows string `json:"rows,omitempty"`
|
Rows string `json:"rows,omitempty"`
|
||||||
InputType string `json:"input_type,omitempty"`
|
InputType string `json:"input_type,omitempty"`
|
||||||
Label string `json:"label,omitempty"`
|
Label string `json:"label,omitempty"`
|
||||||
|
Action *UIOptionAction `json:"action,omitempty"`
|
||||||
|
Variant string `json:"variant,omitempty"`
|
||||||
|
Text string `json:"text,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type ConfigFieldOption struct {
|
type ConfigFieldOption struct {
|
||||||
|
@ -94,6 +118,23 @@ type ConfigFieldOption struct {
|
||||||
Value string `json:"value"`
|
Value string `json:"value"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type UIOptionAction struct {
|
||||||
|
Url string `json:"url"`
|
||||||
|
Method string `json:"method,omitempty"`
|
||||||
|
Loading *LoadingAction `json:"loading,omitempty"`
|
||||||
|
OnCompleteAction *OnCompleteAction `json:"on_complete,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type LoadingAction struct {
|
||||||
|
Text string `json:"text"`
|
||||||
|
State string `json:"state"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type OnCompleteAction struct {
|
||||||
|
ToastReturnMessage bool `json:"toast_return_message"`
|
||||||
|
RefreshFormConfig bool `json:"refresh_form_config"`
|
||||||
|
}
|
||||||
|
|
||||||
type UpdatePluginConfigReq struct {
|
type UpdatePluginConfigReq struct {
|
||||||
PluginSlugName string `validate:"required,gt=1,lte=100" json:"plugin_slug_name"`
|
PluginSlugName string `validate:"required,gt=1,lte=100" json:"plugin_slug_name"`
|
||||||
ConfigFields map[string]any `json:"config_fields"`
|
ConfigFields map[string]any `json:"config_fields"`
|
||||||
|
|
|
@ -6,12 +6,14 @@ type UserCenterAgentResp struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type AgentInfo struct {
|
type AgentInfo struct {
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Icon string `json:"icon"`
|
DisplayName string `json:"display_name"`
|
||||||
Url string `json:"url"`
|
Icon string `json:"icon"`
|
||||||
LoginRedirectURL string `json:"login_redirect_url"`
|
Url string `json:"url"`
|
||||||
SignUpRedirectURL string `json:"sign_up_redirect_url"`
|
LoginRedirectURL string `json:"login_redirect_url"`
|
||||||
ControlCenterItems []*ControlCenter `json:"control_center"`
|
SignUpRedirectURL string `json:"sign_up_redirect_url"`
|
||||||
|
ControlCenterItems []*ControlCenter `json:"control_center"`
|
||||||
|
EnabledOriginalUserSystem bool `json:"enabled_original_user_system"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type ControlCenter struct {
|
type ControlCenter struct {
|
||||||
|
|
|
@ -297,6 +297,7 @@ type QuestionPageReq struct {
|
||||||
OrderCond string `validate:"omitempty,oneof=newest active frequent score unanswered" form:"order"`
|
OrderCond string `validate:"omitempty,oneof=newest active frequent score unanswered" form:"order"`
|
||||||
Tag string `validate:"omitempty,gt=0,lte=100" form:"tag"`
|
Tag string `validate:"omitempty,gt=0,lte=100" form:"tag"`
|
||||||
Username string `validate:"omitempty,gt=0,lte=100" form:"username"`
|
Username string `validate:"omitempty,gt=0,lte=100" form:"username"`
|
||||||
|
InDays int `validate:"omitempty,min=1" form:"in_days"`
|
||||||
|
|
||||||
LoginUserID string `json:"-"`
|
LoginUserID string `json:"-"`
|
||||||
UserIDBeSearched string `json:"-"`
|
UserIDBeSearched string `json:"-"`
|
||||||
|
|
|
@ -6,6 +6,7 @@ import (
|
||||||
"net/mail"
|
"net/mail"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
|
||||||
|
"github.com/answerdev/answer/internal/base/constant"
|
||||||
"github.com/answerdev/answer/internal/base/handler"
|
"github.com/answerdev/answer/internal/base/handler"
|
||||||
"github.com/answerdev/answer/internal/base/reason"
|
"github.com/answerdev/answer/internal/base/reason"
|
||||||
"github.com/answerdev/answer/internal/base/translator"
|
"github.com/answerdev/answer/internal/base/translator"
|
||||||
|
@ -42,9 +43,8 @@ func (r *SiteGeneralReq) FormatSiteUrl() {
|
||||||
|
|
||||||
// SiteInterfaceReq site interface request
|
// SiteInterfaceReq site interface request
|
||||||
type SiteInterfaceReq struct {
|
type SiteInterfaceReq struct {
|
||||||
Language string `validate:"required,gt=1,lte=128" form:"language" json:"language"`
|
Language string `validate:"required,gt=1,lte=128" form:"language" json:"language"`
|
||||||
TimeZone string `validate:"required,gt=1,lte=128" form:"time_zone" json:"time_zone"`
|
TimeZone string `validate:"required,gt=1,lte=128" form:"time_zone" json:"time_zone"`
|
||||||
DefaultAvatar string `validate:"required,oneof=system gravatar" form:"default_avatar" json:"default_avatar"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// SiteBrandingReq site branding request
|
// SiteBrandingReq site branding request
|
||||||
|
@ -92,18 +92,32 @@ type GetSiteLegalInfoResp struct {
|
||||||
PrivacyPolicyParsedText string `json:"privacy_policy_parsed_text,omitempty"`
|
PrivacyPolicyParsedText string `json:"privacy_policy_parsed_text,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SiteUsersReq site users config request
|
||||||
|
type SiteUsersReq struct {
|
||||||
|
DefaultAvatar string `validate:"required,oneof=system gravatar" form:"default_avatar" json:"default_avatar"`
|
||||||
|
AllowUpdateDisplayName bool `form:"allow_update_display_name" json:"allow_update_display_name"`
|
||||||
|
AllowUpdateUsername bool `form:"allow_update_username" json:"allow_update_username"`
|
||||||
|
AllowUpdateAvatar bool `form:"allow_update_avatar" json:"allow_update_avatar"`
|
||||||
|
AllowUpdateBio bool `form:"allow_update_bio" json:"allow_update_bio"`
|
||||||
|
AllowUpdateWebsite bool `form:"allow_update_website" json:"allow_update_website"`
|
||||||
|
AllowUpdateLocation bool `form:"allow_update_location" json:"allow_update_location"`
|
||||||
|
}
|
||||||
|
|
||||||
// SiteLoginReq site login request
|
// SiteLoginReq site login request
|
||||||
type SiteLoginReq struct {
|
type SiteLoginReq struct {
|
||||||
AllowNewRegistrations bool `json:"allow_new_registrations"`
|
AllowNewRegistrations bool `json:"allow_new_registrations"`
|
||||||
LoginRequired bool `json:"login_required"`
|
AllowEmailRegistrations bool `json:"allow_email_registrations"`
|
||||||
|
LoginRequired bool `json:"login_required"`
|
||||||
|
AllowEmailDomains []string `json:"allow_email_domains"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// SiteCustomCssHTMLReq site custom css html
|
// SiteCustomCssHTMLReq site custom css html
|
||||||
type SiteCustomCssHTMLReq struct {
|
type SiteCustomCssHTMLReq struct {
|
||||||
CustomHead string `validate:"omitempty,gt=0,lte=65536" json:"custom_head"`
|
CustomHead string `validate:"omitempty,gt=0,lte=65536" json:"custom_head"`
|
||||||
CustomCss string `validate:"omitempty,gt=0,lte=65536" json:"custom_css"`
|
CustomCss string `validate:"omitempty,gt=0,lte=65536" json:"custom_css"`
|
||||||
CustomHeader string `validate:"omitempty,gt=0,lte=65536" json:"custom_header"`
|
CustomHeader string `validate:"omitempty,gt=0,lte=65536" json:"custom_header"`
|
||||||
CustomFooter string `validate:"omitempty,gt=0,lte=65536" json:"custom_footer"`
|
CustomFooter string `validate:"omitempty,gt=0,lte=65536" json:"custom_footer"`
|
||||||
|
CustomSideBar string `validate:"omitempty,gt=0,lte=65536" json:"custom_sidebar"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// SiteThemeReq site theme config
|
// SiteThemeReq site theme config
|
||||||
|
@ -127,6 +141,9 @@ type SiteLoginResp SiteLoginReq
|
||||||
// SiteCustomCssHTMLResp site custom css html response
|
// SiteCustomCssHTMLResp site custom css html response
|
||||||
type SiteCustomCssHTMLResp SiteCustomCssHTMLReq
|
type SiteCustomCssHTMLResp SiteCustomCssHTMLReq
|
||||||
|
|
||||||
|
// SiteUsersResp site users response
|
||||||
|
type SiteUsersResp SiteUsersReq
|
||||||
|
|
||||||
// SiteThemeResp site theme response
|
// SiteThemeResp site theme response
|
||||||
type SiteThemeResp struct {
|
type SiteThemeResp struct {
|
||||||
ThemeOptions []*ThemeOption `json:"theme_options"`
|
ThemeOptions []*ThemeOption `json:"theme_options"`
|
||||||
|
@ -169,6 +186,7 @@ type SiteInfoResp struct {
|
||||||
Theme *SiteThemeResp `json:"theme"`
|
Theme *SiteThemeResp `json:"theme"`
|
||||||
CustomCssHtml *SiteCustomCssHTMLResp `json:"custom_css_html"`
|
CustomCssHtml *SiteCustomCssHTMLResp `json:"custom_css_html"`
|
||||||
SiteSeo *SiteSeoReq `json:"site_seo"`
|
SiteSeo *SiteSeoReq `json:"site_seo"`
|
||||||
|
SiteUsers *SiteUsersResp `json:"site_users"`
|
||||||
Version string `json:"version"`
|
Version string `json:"version"`
|
||||||
Revision string `json:"revision"`
|
Revision string `json:"revision"`
|
||||||
}
|
}
|
||||||
|
@ -235,3 +253,85 @@ type GetManifestJsonResp struct {
|
||||||
ThemeColor string `json:"theme_color"`
|
ThemeColor string `json:"theme_color"`
|
||||||
BackgroundColor string `json:"background_color"`
|
BackgroundColor string `json:"background_color"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
// PrivilegeLevel1 low
|
||||||
|
PrivilegeLevel1 PrivilegeLevel = 1
|
||||||
|
// PrivilegeLevel2 medium
|
||||||
|
PrivilegeLevel2 PrivilegeLevel = 2
|
||||||
|
// PrivilegeLevel3 high
|
||||||
|
PrivilegeLevel3 PrivilegeLevel = 3
|
||||||
|
)
|
||||||
|
|
||||||
|
type PrivilegeLevel int
|
||||||
|
|
||||||
|
// GetPrivilegesConfigResp get privileges config response
|
||||||
|
type GetPrivilegesConfigResp struct {
|
||||||
|
Options []*PrivilegeOption `json:"options"`
|
||||||
|
SelectedLevel PrivilegeLevel `json:"selected_level"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// PrivilegeOption privilege option
|
||||||
|
type PrivilegeOption struct {
|
||||||
|
Level PrivilegeLevel `json:"level"`
|
||||||
|
LevelDesc string `json:"level_desc"`
|
||||||
|
Privileges []*constant.Privilege `json:"privileges"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdatePrivilegesConfigReq update privileges config request
|
||||||
|
type UpdatePrivilegesConfigReq struct {
|
||||||
|
Level PrivilegeLevel `validate:"required,min=1,max=3" json:"level"`
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
DefaultPrivilegeOptions []*PrivilegeOption
|
||||||
|
privilegeOptionsLevelMapping = map[string][]int{
|
||||||
|
constant.RankQuestionAddKey: {1, 1, 1},
|
||||||
|
constant.RankAnswerAddKey: {1, 1, 1},
|
||||||
|
constant.RankCommentAddKey: {1, 1, 1},
|
||||||
|
constant.RankReportAddKey: {1, 1, 1},
|
||||||
|
constant.RankCommentVoteUpKey: {1, 1, 1},
|
||||||
|
constant.RankLinkUrlLimitKey: {1, 10, 10},
|
||||||
|
constant.RankQuestionVoteUpKey: {1, 1, 15},
|
||||||
|
constant.RankAnswerVoteUpKey: {1, 1, 15},
|
||||||
|
constant.RankQuestionVoteDownKey: {125, 125, 125},
|
||||||
|
constant.RankAnswerVoteDownKey: {125, 125, 125},
|
||||||
|
constant.RankTagAddKey: {1, 750, 1500},
|
||||||
|
constant.RankTagEditKey: {1, 50, 100},
|
||||||
|
constant.RankQuestionEditKey: {1, 100, 200},
|
||||||
|
constant.RankAnswerEditKey: {1, 100, 200},
|
||||||
|
constant.RankQuestionEditWithoutReviewKey: {1, 1000, 2000},
|
||||||
|
constant.RankAnswerEditWithoutReviewKey: {1, 1000, 2000},
|
||||||
|
constant.RankQuestionAuditKey: {1, 1000, 2000},
|
||||||
|
constant.RankAnswerAuditKey: {1, 1000, 2000},
|
||||||
|
constant.RankTagAuditKey: {1, 2500, 5000},
|
||||||
|
constant.RankTagEditWithoutReviewKey: {1, 10000, 20000},
|
||||||
|
constant.RankTagSynonymKey: {1, 10000, 20000},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
DefaultPrivilegeOptions = append(DefaultPrivilegeOptions, &PrivilegeOption{
|
||||||
|
Level: PrivilegeLevel1,
|
||||||
|
LevelDesc: reason.PrivilegeLevel1Desc,
|
||||||
|
}, &PrivilegeOption{
|
||||||
|
Level: PrivilegeLevel2,
|
||||||
|
LevelDesc: reason.PrivilegeLevel2Desc,
|
||||||
|
}, &PrivilegeOption{
|
||||||
|
Level: PrivilegeLevel3,
|
||||||
|
LevelDesc: reason.PrivilegeLevel3Desc,
|
||||||
|
})
|
||||||
|
|
||||||
|
for _, option := range DefaultPrivilegeOptions {
|
||||||
|
for _, privilege := range constant.RankAllPrivileges {
|
||||||
|
if len(privilegeOptionsLevelMapping[privilege.Key]) == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
option.Privileges = append(option.Privileges, &constant.Privilege{
|
||||||
|
Label: privilege.Label,
|
||||||
|
Value: privilegeOptionsLevelMapping[privilege.Key][option.Level-1],
|
||||||
|
Key: privilege.Key,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -4,6 +4,9 @@ package schema
|
||||||
type UserExternalLoginResp struct {
|
type UserExternalLoginResp struct {
|
||||||
BindingKey string `json:"binding_key"`
|
BindingKey string `json:"binding_key"`
|
||||||
AccessToken string `json:"access_token"`
|
AccessToken string `json:"access_token"`
|
||||||
|
// ErrMsg error message, if not empty, means login failed and this message should be displayed.
|
||||||
|
ErrMsg string `json:"-"`
|
||||||
|
ErrTitle string `json:"-"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// ExternalLoginBindingUserSendEmailReq external login binding user request
|
// ExternalLoginBindingUserSendEmailReq external login binding user request
|
||||||
|
@ -49,6 +52,8 @@ type ExternalLoginUserInfoCache struct {
|
||||||
Avatar string
|
Avatar string
|
||||||
// optional. The original user information provided by the third-party login platform
|
// optional. The original user information provided by the third-party login platform
|
||||||
MetaInfo string
|
MetaInfo string
|
||||||
|
// optional. The bio provided by the third-party login platform
|
||||||
|
Bio string
|
||||||
}
|
}
|
||||||
|
|
||||||
// ExternalLoginUnbindingReq external login unbinding user
|
// ExternalLoginUnbindingReq external login unbinding user
|
||||||
|
@ -63,6 +68,13 @@ type UserCenterUserSettingsResp struct {
|
||||||
AccountSettingAgent UserSettingAgent `json:"account_setting_agent"`
|
AccountSettingAgent UserSettingAgent `json:"account_setting_agent"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type UserCenterAdminFunctionAgentResp struct {
|
||||||
|
AllowCreateUser bool `json:"allow_create_user"`
|
||||||
|
AllowUpdateUserStatus bool `json:"allow_update_user_status"`
|
||||||
|
AllowUpdateUserPassword bool `json:"allow_update_user_password"`
|
||||||
|
AllowUpdateUserRole bool `json:"allow_update_user_role"`
|
||||||
|
}
|
||||||
|
|
||||||
type UserSettingAgent struct {
|
type UserSettingAgent struct {
|
||||||
Enabled bool `json:"enabled"`
|
Enabled bool `json:"enabled"`
|
||||||
RedirectURL string `json:"redirect_url"`
|
RedirectURL string `json:"redirect_url"`
|
||||||
|
|
|
@ -4,14 +4,12 @@ import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
|
||||||
"github.com/answerdev/answer/internal/base/constant"
|
"github.com/answerdev/answer/internal/base/constant"
|
||||||
"github.com/answerdev/answer/internal/base/reason"
|
|
||||||
"github.com/answerdev/answer/internal/base/validator"
|
"github.com/answerdev/answer/internal/base/validator"
|
||||||
"github.com/answerdev/answer/internal/entity"
|
"github.com/answerdev/answer/internal/entity"
|
||||||
"github.com/answerdev/answer/pkg/checker"
|
"github.com/answerdev/answer/pkg/checker"
|
||||||
"github.com/answerdev/answer/pkg/converter"
|
"github.com/answerdev/answer/pkg/converter"
|
||||||
"github.com/answerdev/answer/pkg/gravatar"
|
"github.com/answerdev/answer/pkg/gravatar"
|
||||||
"github.com/jinzhu/copier"
|
"github.com/jinzhu/copier"
|
||||||
"github.com/segmentfault/pacman/errors"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// UserVerifyEmailReq user verify email request
|
// UserVerifyEmailReq user verify email request
|
||||||
|
@ -300,7 +298,7 @@ func (u *UserModifyPasswordReq) Check() (errFields []*validator.FormErrorField,
|
||||||
|
|
||||||
type UpdateInfoRequest struct {
|
type UpdateInfoRequest struct {
|
||||||
// display_name
|
// display_name
|
||||||
DisplayName string `validate:"required,gt=0,lte=30" json:"display_name"`
|
DisplayName string `validate:"omitempty,gt=0,lte=30" json:"display_name"`
|
||||||
// username
|
// username
|
||||||
Username string `validate:"omitempty,gt=3,lte=30" json:"username"`
|
Username string `validate:"omitempty,gt=3,lte=30" json:"username"`
|
||||||
// avatar
|
// avatar
|
||||||
|
@ -329,16 +327,6 @@ func (a *AvatarInfo) ToJsonString() string {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (req *UpdateInfoRequest) Check() (errFields []*validator.FormErrorField, err error) {
|
func (req *UpdateInfoRequest) Check() (errFields []*validator.FormErrorField, err error) {
|
||||||
if len(req.Username) > 0 {
|
|
||||||
if checker.IsInvalidUsername(req.Username) {
|
|
||||||
errField := &validator.FormErrorField{
|
|
||||||
ErrorField: "username",
|
|
||||||
ErrorMsg: reason.UsernameInvalid,
|
|
||||||
}
|
|
||||||
errFields = append(errFields, errField)
|
|
||||||
return errFields, errors.BadRequest(reason.UsernameInvalid)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
req.BioHTML = converter.Markdown2BasicHTML(req.Bio)
|
req.BioHTML = converter.Markdown2BasicHTML(req.Bio)
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -476,7 +476,7 @@ func (as *AnswerService) AdminSetAnswerStatus(ctx context.Context, req *schema.A
|
||||||
msg.ReceiverUserID = answerInfo.UserID
|
msg.ReceiverUserID = answerInfo.UserID
|
||||||
msg.TriggerUserID = answerInfo.UserID
|
msg.TriggerUserID = answerInfo.UserID
|
||||||
msg.ObjectType = constant.AnswerObjectType
|
msg.ObjectType = constant.AnswerObjectType
|
||||||
msg.NotificationAction = constant.YourAnswerWasDeleted
|
msg.NotificationAction = constant.NotificationYourAnswerWasDeleted
|
||||||
notice_queue.AddNotification(msg)
|
notice_queue.AddNotification(msg)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
@ -566,7 +566,7 @@ func (as *AnswerService) notificationUpdateAnswer(ctx context.Context, questionU
|
||||||
ObjectID: answerID,
|
ObjectID: answerID,
|
||||||
}
|
}
|
||||||
msg.ObjectType = constant.AnswerObjectType
|
msg.ObjectType = constant.AnswerObjectType
|
||||||
msg.NotificationAction = constant.UpdateAnswer
|
msg.NotificationAction = constant.NotificationUpdateAnswer
|
||||||
notice_queue.AddNotification(msg)
|
notice_queue.AddNotification(msg)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -583,7 +583,7 @@ func (as *AnswerService) notificationAnswerTheQuestion(ctx context.Context,
|
||||||
ObjectID: answerID,
|
ObjectID: answerID,
|
||||||
}
|
}
|
||||||
msg.ObjectType = constant.AnswerObjectType
|
msg.ObjectType = constant.AnswerObjectType
|
||||||
msg.NotificationAction = constant.AnswerTheQuestion
|
msg.NotificationAction = constant.NotificationAnswerTheQuestion
|
||||||
notice_queue.AddNotification(msg)
|
notice_queue.AddNotification(msg)
|
||||||
|
|
||||||
userInfo, exist, err := as.userRepo.GetByUserID(ctx, questionUserID)
|
userInfo, exist, err := as.userRepo.GetByUserID(ctx, questionUserID)
|
||||||
|
|
|
@ -5,6 +5,7 @@ import (
|
||||||
|
|
||||||
"github.com/answerdev/answer/internal/entity"
|
"github.com/answerdev/answer/internal/entity"
|
||||||
"github.com/answerdev/answer/pkg/token"
|
"github.com/answerdev/answer/pkg/token"
|
||||||
|
"github.com/answerdev/answer/plugin"
|
||||||
"github.com/segmentfault/pacman/log"
|
"github.com/segmentfault/pacman/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -42,7 +43,6 @@ func (as *AuthService) GetUserCacheInfo(ctx context.Context, accessToken string)
|
||||||
}
|
}
|
||||||
cacheInfo, _ := as.authRepo.GetUserStatus(ctx, userCacheInfo.UserID)
|
cacheInfo, _ := as.authRepo.GetUserStatus(ctx, userCacheInfo.UserID)
|
||||||
if cacheInfo != nil {
|
if cacheInfo != nil {
|
||||||
log.Debugf("user status updated: %+v", cacheInfo)
|
|
||||||
userCacheInfo.UserStatus = cacheInfo.UserStatus
|
userCacheInfo.UserStatus = cacheInfo.UserStatus
|
||||||
userCacheInfo.EmailStatus = cacheInfo.EmailStatus
|
userCacheInfo.EmailStatus = cacheInfo.EmailStatus
|
||||||
userCacheInfo.RoleID = cacheInfo.RoleID
|
userCacheInfo.RoleID = cacheInfo.RoleID
|
||||||
|
@ -52,6 +52,14 @@ func (as *AuthService) GetUserCacheInfo(ctx context.Context, accessToken string)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// try to get user status from user center
|
||||||
|
uc, ok := plugin.GetUserCenter()
|
||||||
|
if ok && len(userCacheInfo.ExternalID) > 0 {
|
||||||
|
if userStatus := uc.UserStatus(userCacheInfo.ExternalID); userStatus != plugin.UserStatusAvailable {
|
||||||
|
userCacheInfo.UserStatus = int(userStatus)
|
||||||
|
}
|
||||||
|
}
|
||||||
return userCacheInfo, nil
|
return userCacheInfo, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -471,7 +471,7 @@ func (cs *CommentService) notificationQuestionComment(ctx context.Context, quest
|
||||||
ObjectID: commentID,
|
ObjectID: commentID,
|
||||||
}
|
}
|
||||||
msg.ObjectType = constant.CommentObjectType
|
msg.ObjectType = constant.CommentObjectType
|
||||||
msg.NotificationAction = constant.CommentQuestion
|
msg.NotificationAction = constant.NotificationCommentQuestion
|
||||||
notice_queue.AddNotification(msg)
|
notice_queue.AddNotification(msg)
|
||||||
|
|
||||||
receiverUserInfo, exist, err := cs.userRepo.GetByUserID(ctx, questionUserID)
|
receiverUserInfo, exist, err := cs.userRepo.GetByUserID(ctx, questionUserID)
|
||||||
|
@ -526,7 +526,7 @@ func (cs *CommentService) notificationAnswerComment(ctx context.Context,
|
||||||
ObjectID: commentID,
|
ObjectID: commentID,
|
||||||
}
|
}
|
||||||
msg.ObjectType = constant.CommentObjectType
|
msg.ObjectType = constant.CommentObjectType
|
||||||
msg.NotificationAction = constant.CommentAnswer
|
msg.NotificationAction = constant.NotificationCommentAnswer
|
||||||
notice_queue.AddNotification(msg)
|
notice_queue.AddNotification(msg)
|
||||||
|
|
||||||
receiverUserInfo, exist, err := cs.userRepo.GetByUserID(ctx, answerUserID)
|
receiverUserInfo, exist, err := cs.userRepo.GetByUserID(ctx, answerUserID)
|
||||||
|
@ -578,7 +578,7 @@ func (cs *CommentService) notificationCommentReply(ctx context.Context, replyUse
|
||||||
ObjectID: commentID,
|
ObjectID: commentID,
|
||||||
}
|
}
|
||||||
msg.ObjectType = constant.CommentObjectType
|
msg.ObjectType = constant.CommentObjectType
|
||||||
msg.NotificationAction = constant.ReplyToYou
|
msg.NotificationAction = constant.NotificationReplyToYou
|
||||||
notice_queue.AddNotification(msg)
|
notice_queue.AddNotification(msg)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -599,7 +599,7 @@ func (cs *CommentService) notificationMention(
|
||||||
ObjectID: commentID,
|
ObjectID: commentID,
|
||||||
}
|
}
|
||||||
msg.ObjectType = constant.CommentObjectType
|
msg.ObjectType = constant.CommentObjectType
|
||||||
msg.NotificationAction = constant.MentionYou
|
msg.NotificationAction = constant.NotificationMentionYou
|
||||||
notice_queue.AddNotification(msg)
|
notice_queue.AddNotification(msg)
|
||||||
alreadyNotifiedUserIDs = append(alreadyNotifiedUserIDs, userInfo.ID)
|
alreadyNotifiedUserIDs = append(alreadyNotifiedUserIDs, userInfo.ID)
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,14 +7,15 @@ import (
|
||||||
|
|
||||||
"github.com/answerdev/answer/internal/base/constant"
|
"github.com/answerdev/answer/internal/base/constant"
|
||||||
"github.com/answerdev/answer/internal/base/data"
|
"github.com/answerdev/answer/internal/base/data"
|
||||||
|
"github.com/answerdev/answer/internal/base/handler"
|
||||||
"github.com/answerdev/answer/internal/base/pager"
|
"github.com/answerdev/answer/internal/base/pager"
|
||||||
"github.com/answerdev/answer/internal/base/translator"
|
"github.com/answerdev/answer/internal/base/translator"
|
||||||
|
"github.com/answerdev/answer/internal/entity"
|
||||||
"github.com/answerdev/answer/internal/schema"
|
"github.com/answerdev/answer/internal/schema"
|
||||||
notficationcommon "github.com/answerdev/answer/internal/service/notification_common"
|
notficationcommon "github.com/answerdev/answer/internal/service/notification_common"
|
||||||
"github.com/answerdev/answer/internal/service/revision_common"
|
"github.com/answerdev/answer/internal/service/revision_common"
|
||||||
"github.com/answerdev/answer/pkg/uid"
|
"github.com/answerdev/answer/pkg/uid"
|
||||||
"github.com/jinzhu/copier"
|
"github.com/jinzhu/copier"
|
||||||
"github.com/segmentfault/pacman/i18n"
|
|
||||||
"github.com/segmentfault/pacman/log"
|
"github.com/segmentfault/pacman/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -127,35 +128,47 @@ func (ns *NotificationService) GetNotificationPage(ctx context.Context, searchCo
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
resp, err = ns.formatNotificationPage(ctx, notifications)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return pager.NewPageModel(total, resp), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ns *NotificationService) formatNotificationPage(ctx context.Context, notifications []*entity.Notification) (
|
||||||
|
resp []*schema.NotificationContent, err error) {
|
||||||
|
lang := handler.GetLangByCtx(ctx)
|
||||||
for _, notificationInfo := range notifications {
|
for _, notificationInfo := range notifications {
|
||||||
item := &schema.NotificationContent{}
|
item := &schema.NotificationContent{}
|
||||||
err := json.Unmarshal([]byte(notificationInfo.Content), item)
|
if err := json.Unmarshal([]byte(notificationInfo.Content), item); err != nil {
|
||||||
if err != nil {
|
|
||||||
log.Error("NotificationContent Unmarshal Error", err.Error())
|
log.Error("NotificationContent Unmarshal Error", err.Error())
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
lang, _ := ctx.Value(constant.AcceptLanguageFlag).(i18n.Language)
|
// If notification is downvote, the user info is not needed.
|
||||||
item.NotificationAction = translator.Tr(lang, item.NotificationAction)
|
if item.NotificationAction == constant.NotificationDownVotedTheQuestion ||
|
||||||
item.ID = notificationInfo.ID
|
item.NotificationAction == constant.NotificationDownVotedTheAnswer {
|
||||||
item.UpdateTime = notificationInfo.UpdatedAt.Unix()
|
item.UserInfo = nil
|
||||||
if notificationInfo.IsRead == schema.NotificationRead {
|
|
||||||
item.IsRead = true
|
|
||||||
}
|
}
|
||||||
answerID, ok := item.ObjectInfo.ObjectMap["answer"]
|
|
||||||
if ok {
|
item.ID = notificationInfo.ID
|
||||||
|
item.NotificationAction = translator.Tr(lang, item.NotificationAction)
|
||||||
|
item.UpdateTime = notificationInfo.UpdatedAt.Unix()
|
||||||
|
item.IsRead = notificationInfo.IsRead == schema.NotificationRead
|
||||||
|
|
||||||
|
if answerID, ok := item.ObjectInfo.ObjectMap["answer"]; ok {
|
||||||
if item.ObjectInfo.ObjectID == answerID {
|
if item.ObjectInfo.ObjectID == answerID {
|
||||||
item.ObjectInfo.ObjectID = uid.EnShortID(item.ObjectInfo.ObjectMap["answer"])
|
item.ObjectInfo.ObjectID = uid.EnShortID(item.ObjectInfo.ObjectMap["answer"])
|
||||||
}
|
}
|
||||||
item.ObjectInfo.ObjectMap["answer"] = uid.EnShortID(item.ObjectInfo.ObjectMap["answer"])
|
item.ObjectInfo.ObjectMap["answer"] = uid.EnShortID(item.ObjectInfo.ObjectMap["answer"])
|
||||||
}
|
}
|
||||||
questionID, ok := item.ObjectInfo.ObjectMap["question"]
|
if questionID, ok := item.ObjectInfo.ObjectMap["question"]; ok {
|
||||||
if ok {
|
|
||||||
if item.ObjectInfo.ObjectID == questionID {
|
if item.ObjectInfo.ObjectID == questionID {
|
||||||
item.ObjectInfo.ObjectID = uid.EnShortID(item.ObjectInfo.ObjectMap["question"])
|
item.ObjectInfo.ObjectID = uid.EnShortID(item.ObjectInfo.ObjectMap["question"])
|
||||||
}
|
}
|
||||||
item.ObjectInfo.ObjectMap["question"] = uid.EnShortID(item.ObjectInfo.ObjectMap["question"])
|
item.ObjectInfo.ObjectMap["question"] = uid.EnShortID(item.ObjectInfo.ObjectMap["question"])
|
||||||
}
|
}
|
||||||
|
|
||||||
resp = append(resp, item)
|
resp = append(resp, item)
|
||||||
}
|
}
|
||||||
return pager.NewPageModel(total, resp), nil
|
return resp, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -193,10 +193,10 @@ func (ns *NotificationCommon) SendNotificationToAllFollower(ctx context.Context,
|
||||||
if msg.NoNeedPushAllFollow {
|
if msg.NoNeedPushAllFollow {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if msg.NotificationAction != constant.UpdateQuestion &&
|
if msg.NotificationAction != constant.NotificationUpdateQuestion &&
|
||||||
msg.NotificationAction != constant.AnswerTheQuestion &&
|
msg.NotificationAction != constant.NotificationAnswerTheQuestion &&
|
||||||
msg.NotificationAction != constant.UpdateAnswer &&
|
msg.NotificationAction != constant.NotificationUpdateAnswer &&
|
||||||
msg.NotificationAction != constant.AcceptAnswer {
|
msg.NotificationAction != constant.NotificationAcceptAnswer {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
condObjectID := msg.ObjectID
|
condObjectID := msg.ObjectID
|
||||||
|
|
|
@ -10,10 +10,10 @@ const (
|
||||||
QuestionReopen = "question.reopen"
|
QuestionReopen = "question.reopen"
|
||||||
QuestionVoteUp = "question.vote_up"
|
QuestionVoteUp = "question.vote_up"
|
||||||
QuestionVoteDown = "question.vote_down"
|
QuestionVoteDown = "question.vote_down"
|
||||||
QuestionPin = "question.pin" //Top the question
|
QuestionPin = "question.pin"
|
||||||
QuestionUnPin = "question.unpin" //untop the question
|
QuestionUnPin = "question.unpin"
|
||||||
QuestionHide = "question.hide" //hide the question
|
QuestionHide = "question.hide"
|
||||||
QuestionShow = "question.show" //show the question
|
QuestionShow = "question.show"
|
||||||
AnswerAdd = "answer.add"
|
AnswerAdd = "answer.add"
|
||||||
AnswerEdit = "answer.edit"
|
AnswerEdit = "answer.edit"
|
||||||
AnswerEditWithoutReview = "answer.edit_without_review"
|
AnswerEditWithoutReview = "answer.edit_without_review"
|
||||||
|
|
|
@ -32,7 +32,7 @@ type QuestionRepo interface {
|
||||||
UpdateQuestion(ctx context.Context, question *entity.Question, Cols []string) (err error)
|
UpdateQuestion(ctx context.Context, question *entity.Question, Cols []string) (err error)
|
||||||
GetQuestion(ctx context.Context, id string) (question *entity.Question, exist bool, err error)
|
GetQuestion(ctx context.Context, id string) (question *entity.Question, exist bool, err error)
|
||||||
GetQuestionList(ctx context.Context, question *entity.Question) (questions []*entity.Question, err error)
|
GetQuestionList(ctx context.Context, question *entity.Question) (questions []*entity.Question, err error)
|
||||||
GetQuestionPage(ctx context.Context, page, pageSize int, userID, tagID, orderCond string) (
|
GetQuestionPage(ctx context.Context, page, pageSize int, userID, tagID, orderCond string, inDays int) (
|
||||||
questionList []*entity.Question, total int64, err error)
|
questionList []*entity.Question, total int64, err error)
|
||||||
UpdateQuestionStatus(ctx context.Context, question *entity.Question) (err error)
|
UpdateQuestionStatus(ctx context.Context, question *entity.Question) (err error)
|
||||||
UpdateQuestionStatusWithOutUpdateTime(ctx context.Context, question *entity.Question) (err error)
|
UpdateQuestionStatusWithOutUpdateTime(ctx context.Context, question *entity.Question) (err error)
|
||||||
|
|
|
@ -1002,7 +1002,7 @@ func (qs *QuestionService) GetQuestionPage(ctx context.Context, req *schema.Ques
|
||||||
}
|
}
|
||||||
|
|
||||||
questionList, total, err := qs.questionRepo.GetQuestionPage(ctx, req.Page, req.PageSize,
|
questionList, total, err := qs.questionRepo.GetQuestionPage(ctx, req.Page, req.PageSize,
|
||||||
req.UserIDBeSearched, req.TagID, req.OrderCond)
|
req.UserIDBeSearched, req.TagID, req.OrderCond, req.InDays)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, 0, err
|
return nil, 0, err
|
||||||
}
|
}
|
||||||
|
@ -1064,7 +1064,7 @@ func (qs *QuestionService) AdminSetQuestionStatus(ctx context.Context, questionI
|
||||||
msg.ReceiverUserID = questionInfo.UserID
|
msg.ReceiverUserID = questionInfo.UserID
|
||||||
msg.TriggerUserID = questionInfo.UserID
|
msg.TriggerUserID = questionInfo.UserID
|
||||||
msg.ObjectType = constant.QuestionObjectType
|
msg.ObjectType = constant.QuestionObjectType
|
||||||
msg.NotificationAction = constant.YourQuestionWasDeleted
|
msg.NotificationAction = constant.NotificationYourQuestionWasDeleted
|
||||||
notice_queue.AddNotification(msg)
|
notice_queue.AddNotification(msg)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -66,7 +66,7 @@ func (rh *ReportHandle) HandleObject(ctx context.Context, reported *entity.Repor
|
||||||
switch req.FlaggedType {
|
switch req.FlaggedType {
|
||||||
case reasonDelete:
|
case reasonDelete:
|
||||||
err = rh.commentRepo.RemoveComment(ctx, objectID)
|
err = rh.commentRepo.RemoveComment(ctx, objectID)
|
||||||
rh.sendNotification(ctx, reportedUserID, objectID, constant.YourCommentWasDeleted)
|
rh.sendNotification(ctx, reportedUserID, objectID, constant.NotificationYourCommentWasDeleted)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
|
|
|
@ -209,7 +209,7 @@ func (rs *RevisionService) revisionAuditAnswer(ctx context.Context, revisionitem
|
||||||
ObjectID: answerinfo.ID,
|
ObjectID: answerinfo.ID,
|
||||||
}
|
}
|
||||||
msg.ObjectType = constant.AnswerObjectType
|
msg.ObjectType = constant.AnswerObjectType
|
||||||
msg.NotificationAction = constant.UpdateAnswer
|
msg.NotificationAction = constant.NotificationUpdateAnswer
|
||||||
notice_queue.AddNotification(msg)
|
notice_queue.AddNotification(msg)
|
||||||
|
|
||||||
activity_queue.AddActivity(&schema.ActivityMsg{
|
activity_queue.AddActivity(&schema.ActivityMsg{
|
||||||
|
|
|
@ -3,12 +3,15 @@ package siteinfo
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
"github.com/answerdev/answer/internal/base/constant"
|
"github.com/answerdev/answer/internal/base/constant"
|
||||||
|
"github.com/answerdev/answer/internal/base/handler"
|
||||||
"github.com/answerdev/answer/internal/base/reason"
|
"github.com/answerdev/answer/internal/base/reason"
|
||||||
"github.com/answerdev/answer/internal/base/translator"
|
"github.com/answerdev/answer/internal/base/translator"
|
||||||
"github.com/answerdev/answer/internal/entity"
|
"github.com/answerdev/answer/internal/entity"
|
||||||
"github.com/answerdev/answer/internal/schema"
|
"github.com/answerdev/answer/internal/schema"
|
||||||
|
"github.com/answerdev/answer/internal/service/config"
|
||||||
"github.com/answerdev/answer/internal/service/export"
|
"github.com/answerdev/answer/internal/service/export"
|
||||||
"github.com/answerdev/answer/internal/service/siteinfo_common"
|
"github.com/answerdev/answer/internal/service/siteinfo_common"
|
||||||
tagcommon "github.com/answerdev/answer/internal/service/tag_common"
|
tagcommon "github.com/answerdev/answer/internal/service/tag_common"
|
||||||
|
@ -23,19 +26,23 @@ type SiteInfoService struct {
|
||||||
siteInfoCommonService *siteinfo_common.SiteInfoCommonService
|
siteInfoCommonService *siteinfo_common.SiteInfoCommonService
|
||||||
emailService *export.EmailService
|
emailService *export.EmailService
|
||||||
tagCommonService *tagcommon.TagCommonService
|
tagCommonService *tagcommon.TagCommonService
|
||||||
|
configRepo config.ConfigRepo
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewSiteInfoService(
|
func NewSiteInfoService(
|
||||||
siteInfoRepo siteinfo_common.SiteInfoRepo,
|
siteInfoRepo siteinfo_common.SiteInfoRepo,
|
||||||
siteInfoCommonService *siteinfo_common.SiteInfoCommonService,
|
siteInfoCommonService *siteinfo_common.SiteInfoCommonService,
|
||||||
emailService *export.EmailService,
|
emailService *export.EmailService,
|
||||||
tagCommonService *tagcommon.TagCommonService) *SiteInfoService {
|
tagCommonService *tagcommon.TagCommonService,
|
||||||
|
configRepo config.ConfigRepo,
|
||||||
resp, err := siteInfoCommonService.GetSiteInterface(context.Background())
|
) *SiteInfoService {
|
||||||
if err != nil {
|
usersSiteInfo, _ := siteInfoCommonService.GetSiteUsers(context.Background())
|
||||||
log.Error(err)
|
if usersSiteInfo != nil {
|
||||||
} else {
|
constant.DefaultAvatar = usersSiteInfo.DefaultAvatar
|
||||||
constant.DefaultAvatar = resp.DefaultAvatar
|
}
|
||||||
|
generalSiteInfo, _ := siteInfoCommonService.GetSiteGeneral(context.Background())
|
||||||
|
if generalSiteInfo != nil {
|
||||||
|
constant.DefaultSiteURL = generalSiteInfo.SiteUrl
|
||||||
}
|
}
|
||||||
|
|
||||||
return &SiteInfoService{
|
return &SiteInfoService{
|
||||||
|
@ -43,6 +50,7 @@ func NewSiteInfoService(
|
||||||
siteInfoCommonService: siteInfoCommonService,
|
siteInfoCommonService: siteInfoCommonService,
|
||||||
emailService: emailService,
|
emailService: emailService,
|
||||||
tagCommonService: tagCommonService,
|
tagCommonService: tagCommonService,
|
||||||
|
configRepo: configRepo,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -61,6 +69,11 @@ func (s *SiteInfoService) GetSiteBranding(ctx context.Context) (resp *schema.Sit
|
||||||
return s.siteInfoCommonService.GetSiteBranding(ctx)
|
return s.siteInfoCommonService.GetSiteBranding(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetSiteUsers get site info about users
|
||||||
|
func (s *SiteInfoService) GetSiteUsers(ctx context.Context) (resp *schema.SiteUsersResp, err error) {
|
||||||
|
return s.siteInfoCommonService.GetSiteUsers(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
// GetSiteWrite get site info write
|
// GetSiteWrite get site info write
|
||||||
func (s *SiteInfoService) GetSiteWrite(ctx context.Context) (resp *schema.SiteWriteResp, err error) {
|
func (s *SiteInfoService) GetSiteWrite(ctx context.Context) (resp *schema.SiteWriteResp, err error) {
|
||||||
resp = &schema.SiteWriteResp{}
|
resp = &schema.SiteWriteResp{}
|
||||||
|
@ -106,45 +119,32 @@ func (s *SiteInfoService) GetSiteTheme(ctx context.Context) (resp *schema.SiteTh
|
||||||
|
|
||||||
func (s *SiteInfoService) SaveSiteGeneral(ctx context.Context, req schema.SiteGeneralReq) (err error) {
|
func (s *SiteInfoService) SaveSiteGeneral(ctx context.Context, req schema.SiteGeneralReq) (err error) {
|
||||||
req.FormatSiteUrl()
|
req.FormatSiteUrl()
|
||||||
var (
|
content, _ := json.Marshal(req)
|
||||||
siteType = "general"
|
data := &entity.SiteInfo{
|
||||||
content []byte
|
Type: constant.SiteTypeGeneral,
|
||||||
)
|
|
||||||
content, _ = json.Marshal(req)
|
|
||||||
|
|
||||||
data := entity.SiteInfo{
|
|
||||||
Type: siteType,
|
|
||||||
Content: string(content),
|
Content: string(content),
|
||||||
|
Status: 1,
|
||||||
|
}
|
||||||
|
err = s.siteInfoRepo.SaveByType(ctx, constant.SiteTypeGeneral, data)
|
||||||
|
if err == nil {
|
||||||
|
constant.DefaultSiteURL = req.SiteUrl
|
||||||
}
|
}
|
||||||
|
|
||||||
err = s.siteInfoRepo.SaveByType(ctx, siteType, &data)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *SiteInfoService) SaveSiteInterface(ctx context.Context, req schema.SiteInterfaceReq) (err error) {
|
func (s *SiteInfoService) SaveSiteInterface(ctx context.Context, req schema.SiteInterfaceReq) (err error) {
|
||||||
var (
|
|
||||||
siteType = "interface"
|
|
||||||
content []byte
|
|
||||||
)
|
|
||||||
|
|
||||||
// check language
|
// check language
|
||||||
if !translator.CheckLanguageIsValid(req.Language) {
|
if !translator.CheckLanguageIsValid(req.Language) {
|
||||||
err = errors.BadRequest(reason.LangNotFound)
|
err = errors.BadRequest(reason.LangNotFound)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
content, _ = json.Marshal(req)
|
content, _ := json.Marshal(req)
|
||||||
|
|
||||||
data := entity.SiteInfo{
|
data := entity.SiteInfo{
|
||||||
Type: siteType,
|
Type: constant.SiteTypeInterface,
|
||||||
Content: string(content),
|
Content: string(content),
|
||||||
}
|
}
|
||||||
|
return s.siteInfoRepo.SaveByType(ctx, constant.SiteTypeInterface, &data)
|
||||||
err = s.siteInfoRepo.SaveByType(ctx, siteType, &data)
|
|
||||||
if err == nil {
|
|
||||||
constant.DefaultAvatar = req.DefaultAvatar
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// SaveSiteBranding save site branding information
|
// SaveSiteBranding save site branding information
|
||||||
|
@ -218,6 +218,21 @@ func (s *SiteInfoService) SaveSiteTheme(ctx context.Context, req *schema.SiteThe
|
||||||
return s.siteInfoRepo.SaveByType(ctx, constant.SiteTypeTheme, data)
|
return s.siteInfoRepo.SaveByType(ctx, constant.SiteTypeTheme, data)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SaveSiteUsers save site users
|
||||||
|
func (s *SiteInfoService) SaveSiteUsers(ctx context.Context, req *schema.SiteUsersReq) (err error) {
|
||||||
|
content, _ := json.Marshal(req)
|
||||||
|
data := &entity.SiteInfo{
|
||||||
|
Type: constant.SiteTypeUsers,
|
||||||
|
Content: string(content),
|
||||||
|
Status: 1,
|
||||||
|
}
|
||||||
|
err = s.siteInfoRepo.SaveByType(ctx, constant.SiteTypeUsers, data)
|
||||||
|
if err == nil {
|
||||||
|
constant.DefaultAvatar = req.DefaultAvatar
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
// GetSMTPConfig get smtp config
|
// GetSMTPConfig get smtp config
|
||||||
func (s *SiteInfoService) GetSMTPConfig(ctx context.Context) (
|
func (s *SiteInfoService) GetSMTPConfig(ctx context.Context) (
|
||||||
resp *schema.GetSMTPConfigResp, err error,
|
resp *schema.GetSMTPConfigResp, err error,
|
||||||
|
@ -253,8 +268,11 @@ func (s *SiteInfoService) UpdateSMTPConfig(ctx context.Context, req *schema.Upda
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *SiteInfoService) GetSeo(ctx context.Context) (resp *schema.SiteSeoResp, err error) {
|
func (s *SiteInfoService) GetSeo(ctx context.Context) (resp *schema.SiteSeoReq, err error) {
|
||||||
resp = &schema.SiteSeoResp{}
|
resp = &schema.SiteSeoReq{}
|
||||||
|
if err = s.siteInfoCommonService.GetSiteInfoByType(ctx, constant.SiteTypeSeo, resp); err != nil {
|
||||||
|
return resp, err
|
||||||
|
}
|
||||||
loginConfig, err := s.GetSiteLogin(ctx)
|
loginConfig, err := s.GetSiteLogin(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error(err)
|
log.Error(err)
|
||||||
|
@ -265,17 +283,6 @@ func (s *SiteInfoService) GetSeo(ctx context.Context) (resp *schema.SiteSeoResp,
|
||||||
resp.Robots = "User-agent: *\nDisallow: /"
|
resp.Robots = "User-agent: *\nDisallow: /"
|
||||||
return resp, nil
|
return resp, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
resp = &schema.SiteSeoResp{}
|
|
||||||
siteInfo, exist, err := s.siteInfoRepo.GetByType(ctx, constant.SiteTypeSeo)
|
|
||||||
if err != nil {
|
|
||||||
log.Error(err)
|
|
||||||
return resp, nil
|
|
||||||
}
|
|
||||||
if !exist {
|
|
||||||
return resp, nil
|
|
||||||
}
|
|
||||||
_ = json.Unmarshal([]byte(siteInfo.Content), resp)
|
|
||||||
return resp, nil
|
return resp, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -302,3 +309,71 @@ func (s *SiteInfoService) SaveSeo(ctx context.Context, req schema.SiteSeoReq) (e
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *SiteInfoService) GetPrivilegesConfig(ctx context.Context) (resp *schema.GetPrivilegesConfigResp, err error) {
|
||||||
|
privilege := &schema.UpdatePrivilegesConfigReq{}
|
||||||
|
if err = s.siteInfoCommonService.GetSiteInfoByType(ctx, constant.SiteTypePrivileges, privilege); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
resp = &schema.GetPrivilegesConfigResp{
|
||||||
|
Options: s.translatePrivilegeOptions(ctx),
|
||||||
|
SelectedLevel: schema.PrivilegeLevel3,
|
||||||
|
}
|
||||||
|
if privilege != nil && privilege.Level > 0 {
|
||||||
|
resp.SelectedLevel = privilege.Level
|
||||||
|
}
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *SiteInfoService) translatePrivilegeOptions(ctx context.Context) (options []*schema.PrivilegeOption) {
|
||||||
|
la := handler.GetLangByCtx(ctx)
|
||||||
|
for _, option := range schema.DefaultPrivilegeOptions {
|
||||||
|
op := &schema.PrivilegeOption{
|
||||||
|
Level: option.Level,
|
||||||
|
LevelDesc: translator.Tr(la, option.LevelDesc),
|
||||||
|
}
|
||||||
|
for _, privilege := range option.Privileges {
|
||||||
|
op.Privileges = append(op.Privileges, &constant.Privilege{
|
||||||
|
Key: privilege.Key,
|
||||||
|
Label: translator.Tr(la, privilege.Label),
|
||||||
|
Value: privilege.Value,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
options = append(options, op)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *SiteInfoService) UpdatePrivilegesConfig(ctx context.Context, req *schema.UpdatePrivilegesConfigReq) (err error) {
|
||||||
|
var chooseOption *schema.PrivilegeOption
|
||||||
|
for _, option := range schema.DefaultPrivilegeOptions {
|
||||||
|
if option.Level == req.Level {
|
||||||
|
chooseOption = option
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if chooseOption == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// update site info that user choose which privilege level
|
||||||
|
content, _ := json.Marshal(req)
|
||||||
|
data := &entity.SiteInfo{
|
||||||
|
Type: constant.SiteTypePrivileges,
|
||||||
|
Content: string(content),
|
||||||
|
Status: 1,
|
||||||
|
}
|
||||||
|
err = s.siteInfoRepo.SaveByType(ctx, constant.SiteTypePrivileges, data)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// update privilege in config
|
||||||
|
for _, privilege := range chooseOption.Privileges {
|
||||||
|
err = s.configRepo.SetConfig(privilege.Key, fmt.Sprintf("%d", privilege.Value))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
|
@ -43,7 +43,7 @@ func NewSiteInfoCommonService(siteInfoRepo SiteInfoRepo) *SiteInfoCommonService
|
||||||
// GetSiteGeneral get site info general
|
// GetSiteGeneral get site info general
|
||||||
func (s *SiteInfoCommonService) GetSiteGeneral(ctx context.Context) (resp *schema.SiteGeneralResp, err error) {
|
func (s *SiteInfoCommonService) GetSiteGeneral(ctx context.Context) (resp *schema.SiteGeneralResp, err error) {
|
||||||
resp = &schema.SiteGeneralResp{}
|
resp = &schema.SiteGeneralResp{}
|
||||||
if err = s.getSiteInfoByType(ctx, constant.SiteTypeGeneral, resp); err != nil {
|
if err = s.GetSiteInfoByType(ctx, constant.SiteTypeGeneral, resp); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return resp, nil
|
return resp, nil
|
||||||
|
@ -52,7 +52,7 @@ func (s *SiteInfoCommonService) GetSiteGeneral(ctx context.Context) (resp *schem
|
||||||
// GetSiteInterface get site info interface
|
// GetSiteInterface get site info interface
|
||||||
func (s *SiteInfoCommonService) GetSiteInterface(ctx context.Context) (resp *schema.SiteInterfaceResp, err error) {
|
func (s *SiteInfoCommonService) GetSiteInterface(ctx context.Context) (resp *schema.SiteInterfaceResp, err error) {
|
||||||
resp = &schema.SiteInterfaceResp{}
|
resp = &schema.SiteInterfaceResp{}
|
||||||
if err = s.getSiteInfoByType(ctx, constant.SiteTypeInterface, resp); err != nil {
|
if err = s.GetSiteInfoByType(ctx, constant.SiteTypeInterface, resp); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return resp, nil
|
return resp, nil
|
||||||
|
@ -61,7 +61,16 @@ func (s *SiteInfoCommonService) GetSiteInterface(ctx context.Context) (resp *sch
|
||||||
// GetSiteBranding get site info branding
|
// GetSiteBranding get site info branding
|
||||||
func (s *SiteInfoCommonService) GetSiteBranding(ctx context.Context) (resp *schema.SiteBrandingResp, err error) {
|
func (s *SiteInfoCommonService) GetSiteBranding(ctx context.Context) (resp *schema.SiteBrandingResp, err error) {
|
||||||
resp = &schema.SiteBrandingResp{}
|
resp = &schema.SiteBrandingResp{}
|
||||||
if err = s.getSiteInfoByType(ctx, constant.SiteTypeBranding, resp); err != nil {
|
if err = s.GetSiteInfoByType(ctx, constant.SiteTypeBranding, resp); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetSiteUsers get site info about users
|
||||||
|
func (s *SiteInfoCommonService) GetSiteUsers(ctx context.Context) (resp *schema.SiteUsersResp, err error) {
|
||||||
|
resp = &schema.SiteUsersResp{}
|
||||||
|
if err = s.GetSiteInfoByType(ctx, constant.SiteTypeUsers, resp); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return resp, nil
|
return resp, nil
|
||||||
|
@ -70,7 +79,7 @@ func (s *SiteInfoCommonService) GetSiteBranding(ctx context.Context) (resp *sche
|
||||||
// GetSiteWrite get site info write
|
// GetSiteWrite get site info write
|
||||||
func (s *SiteInfoCommonService) GetSiteWrite(ctx context.Context) (resp *schema.SiteWriteResp, err error) {
|
func (s *SiteInfoCommonService) GetSiteWrite(ctx context.Context) (resp *schema.SiteWriteResp, err error) {
|
||||||
resp = &schema.SiteWriteResp{}
|
resp = &schema.SiteWriteResp{}
|
||||||
if err = s.getSiteInfoByType(ctx, constant.SiteTypeWrite, resp); err != nil {
|
if err = s.GetSiteInfoByType(ctx, constant.SiteTypeWrite, resp); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return resp, nil
|
return resp, nil
|
||||||
|
@ -79,7 +88,7 @@ func (s *SiteInfoCommonService) GetSiteWrite(ctx context.Context) (resp *schema.
|
||||||
// GetSiteLegal get site info write
|
// GetSiteLegal get site info write
|
||||||
func (s *SiteInfoCommonService) GetSiteLegal(ctx context.Context) (resp *schema.SiteLegalResp, err error) {
|
func (s *SiteInfoCommonService) GetSiteLegal(ctx context.Context) (resp *schema.SiteLegalResp, err error) {
|
||||||
resp = &schema.SiteLegalResp{}
|
resp = &schema.SiteLegalResp{}
|
||||||
if err = s.getSiteInfoByType(ctx, constant.SiteTypeLegal, resp); err != nil {
|
if err = s.GetSiteInfoByType(ctx, constant.SiteTypeLegal, resp); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return resp, nil
|
return resp, nil
|
||||||
|
@ -88,7 +97,7 @@ func (s *SiteInfoCommonService) GetSiteLegal(ctx context.Context) (resp *schema.
|
||||||
// GetSiteLogin get site login config
|
// GetSiteLogin get site login config
|
||||||
func (s *SiteInfoCommonService) GetSiteLogin(ctx context.Context) (resp *schema.SiteLoginResp, err error) {
|
func (s *SiteInfoCommonService) GetSiteLogin(ctx context.Context) (resp *schema.SiteLoginResp, err error) {
|
||||||
resp = &schema.SiteLoginResp{}
|
resp = &schema.SiteLoginResp{}
|
||||||
if err = s.getSiteInfoByType(ctx, constant.SiteTypeLogin, resp); err != nil {
|
if err = s.GetSiteInfoByType(ctx, constant.SiteTypeLogin, resp); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return resp, nil
|
return resp, nil
|
||||||
|
@ -97,7 +106,7 @@ func (s *SiteInfoCommonService) GetSiteLogin(ctx context.Context) (resp *schema.
|
||||||
// GetSiteCustomCssHTML get site custom css html config
|
// GetSiteCustomCssHTML get site custom css html config
|
||||||
func (s *SiteInfoCommonService) GetSiteCustomCssHTML(ctx context.Context) (resp *schema.SiteCustomCssHTMLResp, err error) {
|
func (s *SiteInfoCommonService) GetSiteCustomCssHTML(ctx context.Context) (resp *schema.SiteCustomCssHTMLResp, err error) {
|
||||||
resp = &schema.SiteCustomCssHTMLResp{}
|
resp = &schema.SiteCustomCssHTMLResp{}
|
||||||
if err = s.getSiteInfoByType(ctx, constant.SiteTypeCustomCssHTML, resp); err != nil {
|
if err = s.GetSiteInfoByType(ctx, constant.SiteTypeCustomCssHTML, resp); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return resp, nil
|
return resp, nil
|
||||||
|
@ -108,7 +117,7 @@ func (s *SiteInfoCommonService) GetSiteTheme(ctx context.Context) (resp *schema.
|
||||||
resp = &schema.SiteThemeResp{
|
resp = &schema.SiteThemeResp{
|
||||||
ThemeOptions: schema.GetThemeOptions,
|
ThemeOptions: schema.GetThemeOptions,
|
||||||
}
|
}
|
||||||
if err = s.getSiteInfoByType(ctx, constant.SiteTypeTheme, resp); err != nil {
|
if err = s.GetSiteInfoByType(ctx, constant.SiteTypeTheme, resp); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
resp.TrTheme(ctx)
|
resp.TrTheme(ctx)
|
||||||
|
@ -118,13 +127,13 @@ func (s *SiteInfoCommonService) GetSiteTheme(ctx context.Context) (resp *schema.
|
||||||
// GetSiteSeo get site seo
|
// GetSiteSeo get site seo
|
||||||
func (s *SiteInfoCommonService) GetSiteSeo(ctx context.Context) (resp *schema.SiteSeoReq, err error) {
|
func (s *SiteInfoCommonService) GetSiteSeo(ctx context.Context) (resp *schema.SiteSeoReq, err error) {
|
||||||
resp = &schema.SiteSeoReq{}
|
resp = &schema.SiteSeoReq{}
|
||||||
if err = s.getSiteInfoByType(ctx, constant.SiteTypeSeo, resp); err != nil {
|
if err = s.GetSiteInfoByType(ctx, constant.SiteTypeSeo, resp); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return resp, nil
|
return resp, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *SiteInfoCommonService) getSiteInfoByType(ctx context.Context, siteType string, resp interface{}) (err error) {
|
func (s *SiteInfoCommonService) GetSiteInfoByType(ctx context.Context, siteType string, resp interface{}) (err error) {
|
||||||
siteInfo, exist, err := s.siteInfoRepo.GetByType(ctx, siteType)
|
siteInfo, exist, err := s.siteInfoRepo.GetByType(ctx, siteType)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
|
@ -150,7 +150,7 @@ func (us *UserCommon) MakeUsername(ctx context.Context, displayName string) (use
|
||||||
return username + suffix, nil
|
return username + suffix, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (us *UserCommon) CacheLoginUserInfo(ctx context.Context, userID string, userStatus, emailStatus int) (
|
func (us *UserCommon) CacheLoginUserInfo(ctx context.Context, userID string, userStatus, emailStatus int, externalID string) (
|
||||||
accessToken string, userCacheInfo *entity.UserCacheInfo, err error) {
|
accessToken string, userCacheInfo *entity.UserCacheInfo, err error) {
|
||||||
roleID, err := us.userRoleService.GetUserRole(ctx, userID)
|
roleID, err := us.userRoleService.GetUserRole(ctx, userID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -162,6 +162,7 @@ func (us *UserCommon) CacheLoginUserInfo(ctx context.Context, userID string, use
|
||||||
EmailStatus: emailStatus,
|
EmailStatus: emailStatus,
|
||||||
UserStatus: userStatus,
|
UserStatus: userStatus,
|
||||||
RoleID: roleID,
|
RoleID: roleID,
|
||||||
|
ExternalID: externalID,
|
||||||
}
|
}
|
||||||
|
|
||||||
accessToken, err = us.authService.SetUserCacheInfo(ctx, userCacheInfo)
|
accessToken, err = us.authService.SetUserCacheInfo(ctx, userCacheInfo)
|
||||||
|
|
|
@ -5,10 +5,16 @@ import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"time"
|
"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/entity"
|
||||||
"github.com/answerdev/answer/internal/schema"
|
"github.com/answerdev/answer/internal/schema"
|
||||||
"github.com/answerdev/answer/internal/service/activity"
|
"github.com/answerdev/answer/internal/service/activity"
|
||||||
|
"github.com/answerdev/answer/internal/service/siteinfo_common"
|
||||||
usercommon "github.com/answerdev/answer/internal/service/user_common"
|
usercommon "github.com/answerdev/answer/internal/service/user_common"
|
||||||
|
"github.com/answerdev/answer/pkg/checker"
|
||||||
|
"github.com/answerdev/answer/pkg/converter"
|
||||||
"github.com/answerdev/answer/pkg/random"
|
"github.com/answerdev/answer/pkg/random"
|
||||||
"github.com/answerdev/answer/plugin"
|
"github.com/answerdev/answer/plugin"
|
||||||
"github.com/segmentfault/pacman/log"
|
"github.com/segmentfault/pacman/log"
|
||||||
|
@ -20,6 +26,7 @@ type UserCenterLoginService struct {
|
||||||
userExternalLoginRepo UserExternalLoginRepo
|
userExternalLoginRepo UserExternalLoginRepo
|
||||||
userCommonService *usercommon.UserCommon
|
userCommonService *usercommon.UserCommon
|
||||||
userActivity activity.UserActiveActivityRepo
|
userActivity activity.UserActiveActivityRepo
|
||||||
|
siteInfoCommonService *siteinfo_common.SiteInfoCommonService
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewUserCenterLoginService new user external login service
|
// NewUserCenterLoginService new user external login service
|
||||||
|
@ -28,21 +35,38 @@ func NewUserCenterLoginService(
|
||||||
userCommonService *usercommon.UserCommon,
|
userCommonService *usercommon.UserCommon,
|
||||||
userExternalLoginRepo UserExternalLoginRepo,
|
userExternalLoginRepo UserExternalLoginRepo,
|
||||||
userActivity activity.UserActiveActivityRepo,
|
userActivity activity.UserActiveActivityRepo,
|
||||||
|
siteInfoCommonService *siteinfo_common.SiteInfoCommonService,
|
||||||
) *UserCenterLoginService {
|
) *UserCenterLoginService {
|
||||||
return &UserCenterLoginService{
|
return &UserCenterLoginService{
|
||||||
userRepo: userRepo,
|
userRepo: userRepo,
|
||||||
userCommonService: userCommonService,
|
userCommonService: userCommonService,
|
||||||
userExternalLoginRepo: userExternalLoginRepo,
|
userExternalLoginRepo: userExternalLoginRepo,
|
||||||
userActivity: userActivity,
|
userActivity: userActivity,
|
||||||
|
siteInfoCommonService: siteInfoCommonService,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (us *UserCenterLoginService) ExternalLogin(
|
func (us *UserCenterLoginService) ExternalLogin(
|
||||||
ctx context.Context, provider string, basicUserInfo *plugin.UserCenterBasicUserInfo) (
|
ctx context.Context, userCenter plugin.UserCenter, basicUserInfo *plugin.UserCenterBasicUserInfo) (
|
||||||
resp *schema.UserExternalLoginResp, err error) {
|
resp *schema.UserExternalLoginResp, err error) {
|
||||||
|
|
||||||
|
if len(basicUserInfo.Email) > 0 {
|
||||||
|
// check whether site allow register or not
|
||||||
|
siteInfo, err := us.siteInfoCommonService.GetSiteLogin(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if !checker.EmailInAllowEmailDomain(basicUserInfo.Email, siteInfo.AllowEmailDomains) {
|
||||||
|
log.Debugf("email domain not allowed: %s", basicUserInfo.Email)
|
||||||
|
return &schema.UserExternalLoginResp{
|
||||||
|
ErrTitle: translator.Tr(handler.GetLangByCtx(ctx), reason.UserAccessDenied),
|
||||||
|
ErrMsg: translator.Tr(handler.GetLangByCtx(ctx), reason.EmailIllegalDomainError),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
oldExternalLoginUserInfo, exist, err := us.userExternalLoginRepo.GetByExternalID(ctx,
|
oldExternalLoginUserInfo, exist, err := us.userExternalLoginRepo.GetByExternalID(ctx,
|
||||||
provider, basicUserInfo.ExternalID)
|
userCenter.Info().SlugName, basicUserInfo.ExternalID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -53,16 +77,28 @@ func (us *UserCenterLoginService) ExternalLogin(
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if exist {
|
if exist {
|
||||||
|
// if user is deleted, do not allow login
|
||||||
|
if oldUserInfo.Status == entity.UserStatusDeleted {
|
||||||
|
return &schema.UserExternalLoginResp{
|
||||||
|
ErrTitle: translator.Tr(handler.GetLangByCtx(ctx), reason.UserAccessDenied),
|
||||||
|
ErrMsg: translator.Tr(handler.GetLangByCtx(ctx), reason.UserPageAccessDenied),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
if err := us.userRepo.UpdateLastLoginDate(ctx, oldUserInfo.ID); err != nil {
|
if err := us.userRepo.UpdateLastLoginDate(ctx, oldUserInfo.ID); err != nil {
|
||||||
log.Errorf("update user last login date failed: %v", err)
|
log.Errorf("update user last login date failed: %v", err)
|
||||||
}
|
}
|
||||||
accessToken, _, err := us.userCommonService.CacheLoginUserInfo(
|
accessToken, _, err := us.userCommonService.CacheLoginUserInfo(
|
||||||
ctx, oldUserInfo.ID, oldUserInfo.MailStatus, oldUserInfo.Status)
|
ctx, oldUserInfo.ID, oldUserInfo.MailStatus, oldUserInfo.Status, oldExternalLoginUserInfo.ExternalID)
|
||||||
return &schema.UserExternalLoginResp{AccessToken: accessToken}, err
|
return &schema.UserExternalLoginResp{AccessToken: accessToken}, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
oldUserInfo, err := us.registerNewUser(ctx, provider, basicUserInfo)
|
// cache external user info, waiting for user enter email address.
|
||||||
|
if userCenter.Description().MustAuthEmailEnabled && len(basicUserInfo.Email) == 0 {
|
||||||
|
return &schema.UserExternalLoginResp{ErrMsg: "Requires authorized email to login"}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
oldUserInfo, err := us.registerNewUser(ctx, userCenter.Info().SlugName, basicUserInfo)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -70,7 +106,7 @@ func (us *UserCenterLoginService) ExternalLogin(
|
||||||
us.activeUser(ctx, oldUserInfo)
|
us.activeUser(ctx, oldUserInfo)
|
||||||
|
|
||||||
accessToken, _, err := us.userCommonService.CacheLoginUserInfo(
|
accessToken, _, err := us.userCommonService.CacheLoginUserInfo(
|
||||||
ctx, oldUserInfo.ID, oldUserInfo.MailStatus, oldUserInfo.Status)
|
ctx, oldUserInfo.ID, oldUserInfo.MailStatus, oldUserInfo.Status, oldExternalLoginUserInfo.ExternalID)
|
||||||
return &schema.UserExternalLoginResp{AccessToken: accessToken}, err
|
return &schema.UserExternalLoginResp{AccessToken: accessToken}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -98,6 +134,8 @@ func (us *UserCenterLoginService) registerNewUser(ctx context.Context, provider
|
||||||
userInfo.MailStatus = entity.EmailStatusAvailable
|
userInfo.MailStatus = entity.EmailStatusAvailable
|
||||||
userInfo.Status = entity.UserStatusAvailable
|
userInfo.Status = entity.UserStatusAvailable
|
||||||
userInfo.LastLoginDate = time.Now()
|
userInfo.LastLoginDate = time.Now()
|
||||||
|
userInfo.Bio = basicUserInfo.Bio
|
||||||
|
userInfo.BioHTML = converter.Markdown2HTML(basicUserInfo.Bio)
|
||||||
err = us.userRepo.AddUser(ctx, userInfo)
|
err = us.userRepo.AddUser(ctx, userInfo)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -166,6 +204,31 @@ func (us *UserCenterLoginService) UserCenterUserSettings(ctx context.Context, us
|
||||||
return resp, nil
|
return resp, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// UserCenterAdminFunctionAgent Check in the backend administration interface if the user-related functions
|
||||||
|
// are turned off due to turning on the User Center plugin.
|
||||||
|
func (us *UserCenterLoginService) UserCenterAdminFunctionAgent(ctx context.Context) (
|
||||||
|
resp *schema.UserCenterAdminFunctionAgentResp, err error) {
|
||||||
|
resp = &schema.UserCenterAdminFunctionAgentResp{
|
||||||
|
AllowCreateUser: true,
|
||||||
|
AllowUpdateUserStatus: true,
|
||||||
|
AllowUpdateUserPassword: true,
|
||||||
|
AllowUpdateUserRole: true,
|
||||||
|
}
|
||||||
|
userCenter, ok := plugin.GetUserCenter()
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
desc := userCenter.Description()
|
||||||
|
// If user status agent is enabled, admin can not update user status in answer.
|
||||||
|
resp.AllowUpdateUserStatus = !desc.UserStatusAgentEnabled
|
||||||
|
|
||||||
|
// If original user system is enabled, admin can update user password and role in answer.
|
||||||
|
resp.AllowUpdateUserPassword = desc.EnabledOriginalUserSystem
|
||||||
|
resp.AllowUpdateUserRole = desc.EnabledOriginalUserSystem
|
||||||
|
resp.AllowCreateUser = desc.EnabledOriginalUserSystem
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (us *UserCenterLoginService) UserCenterPersonalBranding(ctx context.Context, username string) (
|
func (us *UserCenterLoginService) UserCenterPersonalBranding(ctx context.Context, username string) (
|
||||||
resp *schema.UserCenterPersonalBranding, err error) {
|
resp *schema.UserCenterPersonalBranding, err error) {
|
||||||
resp = &schema.UserCenterPersonalBranding{
|
resp = &schema.UserCenterPersonalBranding{
|
||||||
|
|
|
@ -15,6 +15,7 @@ import (
|
||||||
usercommon "github.com/answerdev/answer/internal/service/user_common"
|
usercommon "github.com/answerdev/answer/internal/service/user_common"
|
||||||
"github.com/answerdev/answer/pkg/random"
|
"github.com/answerdev/answer/pkg/random"
|
||||||
"github.com/answerdev/answer/pkg/token"
|
"github.com/answerdev/answer/pkg/token"
|
||||||
|
"github.com/answerdev/answer/plugin"
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
"github.com/segmentfault/pacman/errors"
|
"github.com/segmentfault/pacman/errors"
|
||||||
"github.com/segmentfault/pacman/log"
|
"github.com/segmentfault/pacman/log"
|
||||||
|
@ -83,7 +84,7 @@ func (us *UserExternalLoginService) ExternalLogin(
|
||||||
log.Error(err)
|
log.Error(err)
|
||||||
}
|
}
|
||||||
accessToken, _, err := us.userCommonService.CacheLoginUserInfo(
|
accessToken, _, err := us.userCommonService.CacheLoginUserInfo(
|
||||||
ctx, oldUserInfo.ID, newMailStatus, oldUserInfo.Status)
|
ctx, oldUserInfo.ID, newMailStatus, oldUserInfo.Status, oldExternalLoginUserInfo.ExternalID)
|
||||||
return &schema.UserExternalLoginResp{AccessToken: accessToken}, err
|
return &schema.UserExternalLoginResp{AccessToken: accessToken}, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -122,7 +123,7 @@ func (us *UserExternalLoginService) ExternalLogin(
|
||||||
}
|
}
|
||||||
|
|
||||||
accessToken, _, err := us.userCommonService.CacheLoginUserInfo(
|
accessToken, _, err := us.userCommonService.CacheLoginUserInfo(
|
||||||
ctx, oldUserInfo.ID, newMailStatus, oldUserInfo.Status)
|
ctx, oldUserInfo.ID, newMailStatus, oldUserInfo.Status, oldExternalLoginUserInfo.ExternalID)
|
||||||
return &schema.UserExternalLoginResp{AccessToken: accessToken}, err
|
return &schema.UserExternalLoginResp{AccessToken: accessToken}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -150,6 +151,8 @@ func (us *UserExternalLoginService) registerNewUser(ctx context.Context,
|
||||||
userInfo.MailStatus = entity.EmailStatusToBeVerified
|
userInfo.MailStatus = entity.EmailStatusToBeVerified
|
||||||
userInfo.Status = entity.UserStatusAvailable
|
userInfo.Status = entity.UserStatusAvailable
|
||||||
userInfo.LastLoginDate = time.Now()
|
userInfo.LastLoginDate = time.Now()
|
||||||
|
userInfo.Bio = externalUserInfo.Bio
|
||||||
|
userInfo.BioHTML = externalUserInfo.Bio
|
||||||
err = us.userRepo.AddUser(ctx, userInfo)
|
err = us.userRepo.AddUser(ctx, userInfo)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -249,7 +252,7 @@ func (us *UserExternalLoginService) ExternalLoginBindingUserSendEmail(
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
resp.AccessToken, _, err = us.userCommonService.CacheLoginUserInfo(
|
resp.AccessToken, _, err = us.userCommonService.CacheLoginUserInfo(
|
||||||
ctx, userInfo.ID, userInfo.MailStatus, userInfo.Status)
|
ctx, userInfo.ID, userInfo.MailStatus, userInfo.Status, externalLoginInfo.ExternalID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error(err)
|
log.Error(err)
|
||||||
}
|
}
|
||||||
|
@ -316,3 +319,33 @@ func (us *UserExternalLoginService) ExternalLoginUnbinding(
|
||||||
|
|
||||||
return nil, us.userExternalLoginRepo.DeleteUserExternalLogin(ctx, req.UserID, req.ExternalID)
|
return nil, us.userExternalLoginRepo.DeleteUserExternalLogin(ctx, req.UserID, req.ExternalID)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CheckUserStatusInUserCenter check user status in user center
|
||||||
|
func (us *UserExternalLoginService) CheckUserStatusInUserCenter(ctx context.Context, userID string) (
|
||||||
|
valid bool, externalID string, err error) {
|
||||||
|
// If enable user center plugin, user status should be checked by user center
|
||||||
|
userCenter, ok := plugin.GetUserCenter()
|
||||||
|
if !ok {
|
||||||
|
return true, "", nil
|
||||||
|
}
|
||||||
|
userInfoList, err := us.GetExternalLoginUserInfoList(ctx, userID)
|
||||||
|
if err != nil {
|
||||||
|
return false, "", err
|
||||||
|
}
|
||||||
|
var thisUcUserInfo *entity.UserExternalLogin
|
||||||
|
for _, t := range userInfoList {
|
||||||
|
if t.Provider == userCenter.Info().SlugName {
|
||||||
|
thisUcUserInfo = t
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// If this user not login by user center, no need to check user status
|
||||||
|
if thisUcUserInfo == nil {
|
||||||
|
return true, "", nil
|
||||||
|
}
|
||||||
|
userStatus := userCenter.UserStatus(thisUcUserInfo.ExternalID)
|
||||||
|
if userStatus == plugin.UserStatusDeleted {
|
||||||
|
return false, thisUcUserInfo.ExternalID, nil
|
||||||
|
}
|
||||||
|
return true, thisUcUserInfo.ExternalID, nil
|
||||||
|
}
|
||||||
|
|
|
@ -80,6 +80,9 @@ func (us *UserService) GetUserInfoByUserID(ctx context.Context, token, userID st
|
||||||
if !exist {
|
if !exist {
|
||||||
return nil, errors.BadRequest(reason.UserNotFound)
|
return nil, errors.BadRequest(reason.UserNotFound)
|
||||||
}
|
}
|
||||||
|
if userInfo.Status == entity.UserStatusDeleted {
|
||||||
|
return nil, errors.Unauthorized(reason.UnauthorizedError)
|
||||||
|
}
|
||||||
roleID, err := us.userRoleService.GetUserRole(ctx, userInfo.ID)
|
roleID, err := us.userRoleService.GetUserRole(ctx, userInfo.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error(err)
|
log.Error(err)
|
||||||
|
@ -119,10 +122,17 @@ func (us *UserService) EmailLogin(ctx context.Context, req *schema.UserEmailLogi
|
||||||
if !us.verifyPassword(ctx, req.Pass, userInfo.Pass) {
|
if !us.verifyPassword(ctx, req.Pass, userInfo.Pass) {
|
||||||
return nil, errors.BadRequest(reason.EmailOrPasswordWrong)
|
return nil, errors.BadRequest(reason.EmailOrPasswordWrong)
|
||||||
}
|
}
|
||||||
|
ok, externalID, err := us.userExternalLoginService.CheckUserStatusInUserCenter(ctx, userInfo.ID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if !ok {
|
||||||
|
return nil, errors.BadRequest(reason.EmailOrPasswordWrong)
|
||||||
|
}
|
||||||
|
|
||||||
err = us.userRepo.UpdateLastLoginDate(ctx, userInfo.ID)
|
err = us.userRepo.UpdateLastLoginDate(ctx, userInfo.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("UpdateLastLoginDate", err.Error())
|
log.Errorf("update last login data failed, err: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
roleID, err := us.userRoleService.GetUserRole(ctx, userInfo.ID)
|
roleID, err := us.userRoleService.GetUserRole(ctx, userInfo.ID)
|
||||||
|
@ -137,6 +147,7 @@ func (us *UserService) EmailLogin(ctx context.Context, req *schema.UserEmailLogi
|
||||||
EmailStatus: userInfo.MailStatus,
|
EmailStatus: userInfo.MailStatus,
|
||||||
UserStatus: userInfo.Status,
|
UserStatus: userInfo.Status,
|
||||||
RoleID: roleID,
|
RoleID: roleID,
|
||||||
|
ExternalID: externalID,
|
||||||
}
|
}
|
||||||
resp.AccessToken, err = us.authService.SetUserCacheInfo(ctx, userCacheInfo)
|
resp.AccessToken, err = us.authService.SetUserCacheInfo(ctx, userCacheInfo)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -252,7 +263,27 @@ func (us *UserService) UserModifyPassword(ctx context.Context, req *schema.UserM
|
||||||
// UpdateInfo update user info
|
// UpdateInfo update user info
|
||||||
func (us *UserService) UpdateInfo(ctx context.Context, req *schema.UpdateInfoRequest) (
|
func (us *UserService) UpdateInfo(ctx context.Context, req *schema.UpdateInfoRequest) (
|
||||||
errFields []*validator.FormErrorField, err error) {
|
errFields []*validator.FormErrorField, err error) {
|
||||||
if len(req.Username) > 0 {
|
siteUsers, err := us.siteInfoService.GetSiteUsers(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if siteUsers.AllowUpdateUsername && len(req.Username) > 0 {
|
||||||
|
if checker.IsInvalidUsername(req.Username) {
|
||||||
|
errFields = append(errFields, &validator.FormErrorField{
|
||||||
|
ErrorField: "username",
|
||||||
|
ErrorMsg: reason.UsernameInvalid,
|
||||||
|
})
|
||||||
|
return errFields, errors.BadRequest(reason.UsernameInvalid)
|
||||||
|
}
|
||||||
|
if checker.IsReservedUsername(req.Username) {
|
||||||
|
errFields = append(errFields, &validator.FormErrorField{
|
||||||
|
ErrorField: "username",
|
||||||
|
ErrorMsg: reason.UsernameInvalid,
|
||||||
|
})
|
||||||
|
return errFields, errors.BadRequest(reason.UsernameInvalid)
|
||||||
|
}
|
||||||
|
|
||||||
userInfo, exist, err := us.userRepo.GetByUsername(ctx, req.Username)
|
userInfo, exist, err := us.userRepo.GetByUsername(ctx, req.Username)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -264,31 +295,57 @@ func (us *UserService) UpdateInfo(ctx context.Context, req *schema.UpdateInfoReq
|
||||||
})
|
})
|
||||||
return errFields, errors.BadRequest(reason.UsernameDuplicate)
|
return errFields, errors.BadRequest(reason.UsernameDuplicate)
|
||||||
}
|
}
|
||||||
if checker.IsReservedUsername(req.Username) {
|
|
||||||
errFields = append(errFields, &validator.FormErrorField{
|
|
||||||
ErrorField: "username",
|
|
||||||
ErrorMsg: reason.UsernameInvalid,
|
|
||||||
})
|
|
||||||
return errFields, errors.BadRequest(reason.UsernameInvalid)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
avatar, err := json.Marshal(req.Avatar)
|
|
||||||
|
oldUserInfo, exist, err := us.userRepo.GetByUserID(ctx, req.UserID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.BadRequest(reason.UserSetAvatar).WithError(err).WithStack()
|
return nil, err
|
||||||
}
|
}
|
||||||
userInfo := entity.User{}
|
if !exist {
|
||||||
userInfo.ID = req.UserID
|
return nil, errors.BadRequest(reason.UserNotFound)
|
||||||
userInfo.Avatar = string(avatar)
|
}
|
||||||
userInfo.DisplayName = req.DisplayName
|
|
||||||
userInfo.Bio = req.Bio
|
cond := us.formatUserInfoForUpdateInfo(oldUserInfo, req, siteUsers)
|
||||||
userInfo.BioHTML = req.BioHTML
|
err = us.userRepo.UpdateInfo(ctx, cond)
|
||||||
userInfo.Location = req.Location
|
|
||||||
userInfo.Website = req.Website
|
|
||||||
userInfo.Username = req.Username
|
|
||||||
err = us.userRepo.UpdateInfo(ctx, &userInfo)
|
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (us *UserService) formatUserInfoForUpdateInfo(
|
||||||
|
oldUserInfo *entity.User, req *schema.UpdateInfoRequest, siteUsersConf *schema.SiteUsersResp) *entity.User {
|
||||||
|
avatar, _ := json.Marshal(req.Avatar)
|
||||||
|
|
||||||
|
userInfo := &entity.User{}
|
||||||
|
userInfo.DisplayName = oldUserInfo.DisplayName
|
||||||
|
userInfo.Username = oldUserInfo.Username
|
||||||
|
userInfo.Avatar = oldUserInfo.Avatar
|
||||||
|
userInfo.Bio = oldUserInfo.Bio
|
||||||
|
userInfo.BioHTML = oldUserInfo.BioHTML
|
||||||
|
userInfo.Website = oldUserInfo.Website
|
||||||
|
userInfo.Location = oldUserInfo.Location
|
||||||
|
userInfo.ID = req.UserID
|
||||||
|
|
||||||
|
if len(req.DisplayName) > 0 && siteUsersConf.AllowUpdateDisplayName {
|
||||||
|
userInfo.DisplayName = req.DisplayName
|
||||||
|
}
|
||||||
|
if len(req.Username) > 0 && siteUsersConf.AllowUpdateUsername {
|
||||||
|
userInfo.Username = req.Username
|
||||||
|
}
|
||||||
|
if len(avatar) > 0 && siteUsersConf.AllowUpdateAvatar {
|
||||||
|
userInfo.Avatar = string(avatar)
|
||||||
|
}
|
||||||
|
if siteUsersConf.AllowUpdateBio {
|
||||||
|
userInfo.Bio = req.Bio
|
||||||
|
userInfo.BioHTML = req.BioHTML
|
||||||
|
}
|
||||||
|
if siteUsersConf.AllowUpdateWebsite {
|
||||||
|
userInfo.Website = req.Website
|
||||||
|
}
|
||||||
|
if siteUsersConf.AllowUpdateLocation {
|
||||||
|
userInfo.Location = req.Location
|
||||||
|
}
|
||||||
|
return userInfo
|
||||||
|
}
|
||||||
|
|
||||||
func (us *UserService) UserEmailHas(ctx context.Context, email string) (bool, error) {
|
func (us *UserService) UserEmailHas(ctx context.Context, email string) (bool, error) {
|
||||||
_, has, err := us.userRepo.GetByEmail(ctx, email)
|
_, has, err := us.userRepo.GetByEmail(ctx, email)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -466,7 +523,7 @@ func (us *UserService) UserVerifyEmail(ctx context.Context, req *schema.UserVeri
|
||||||
}
|
}
|
||||||
|
|
||||||
accessToken, userCacheInfo, err := us.userCommonService.CacheLoginUserInfo(
|
accessToken, userCacheInfo, err := us.userCommonService.CacheLoginUserInfo(
|
||||||
ctx, userInfo.ID, userInfo.MailStatus, userInfo.Status)
|
ctx, userInfo.ID, userInfo.MailStatus, userInfo.Status, "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -63,12 +63,12 @@ func NewVoteService(
|
||||||
}
|
}
|
||||||
|
|
||||||
// VoteUp vote up
|
// VoteUp vote up
|
||||||
func (as *VoteService) VoteUp(ctx context.Context, dto *schema.VoteDTO) (voteResp *schema.VoteResp, err error) {
|
func (vs *VoteService) VoteUp(ctx context.Context, dto *schema.VoteDTO) (voteResp *schema.VoteResp, err error) {
|
||||||
voteResp = &schema.VoteResp{}
|
voteResp = &schema.VoteResp{}
|
||||||
|
|
||||||
var objectUserID string
|
var objectUserID string
|
||||||
|
|
||||||
objectUserID, err = as.GetObjectUserID(ctx, dto.ObjectID)
|
objectUserID, err = vs.GetObjectUserID(ctx, dto.ObjectID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -80,19 +80,19 @@ func (as *VoteService) VoteUp(ctx context.Context, dto *schema.VoteDTO) (voteRes
|
||||||
}
|
}
|
||||||
|
|
||||||
if dto.IsCancel {
|
if dto.IsCancel {
|
||||||
return as.voteRepo.VoteUpCancel(ctx, dto.ObjectID, dto.UserID, objectUserID)
|
return vs.voteRepo.VoteUpCancel(ctx, dto.ObjectID, dto.UserID, objectUserID)
|
||||||
} else {
|
} else {
|
||||||
return as.voteRepo.VoteUp(ctx, dto.ObjectID, dto.UserID, objectUserID)
|
return vs.voteRepo.VoteUp(ctx, dto.ObjectID, dto.UserID, objectUserID)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// VoteDown vote down
|
// VoteDown vote down
|
||||||
func (as *VoteService) VoteDown(ctx context.Context, dto *schema.VoteDTO) (voteResp *schema.VoteResp, err error) {
|
func (vs *VoteService) VoteDown(ctx context.Context, dto *schema.VoteDTO) (voteResp *schema.VoteResp, err error) {
|
||||||
voteResp = &schema.VoteResp{}
|
voteResp = &schema.VoteResp{}
|
||||||
|
|
||||||
var objectUserID string
|
var objectUserID string
|
||||||
|
|
||||||
objectUserID, err = as.GetObjectUserID(ctx, dto.ObjectID)
|
objectUserID, err = vs.GetObjectUserID(ctx, dto.ObjectID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -104,9 +104,9 @@ func (as *VoteService) VoteDown(ctx context.Context, dto *schema.VoteDTO) (voteR
|
||||||
}
|
}
|
||||||
|
|
||||||
if dto.IsCancel {
|
if dto.IsCancel {
|
||||||
return as.voteRepo.VoteDownCancel(ctx, dto.ObjectID, dto.UserID, objectUserID)
|
return vs.voteRepo.VoteDownCancel(ctx, dto.ObjectID, dto.UserID, objectUserID)
|
||||||
} else {
|
} else {
|
||||||
return as.voteRepo.VoteDown(ctx, dto.ObjectID, dto.UserID, objectUserID)
|
return vs.voteRepo.VoteDown(ctx, dto.ObjectID, dto.UserID, objectUserID)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
package checker
|
||||||
|
|
||||||
|
import "strings"
|
||||||
|
|
||||||
|
func EmailInAllowEmailDomain(email string, allowEmailDomains []string) bool {
|
||||||
|
if len(allowEmailDomains) == 0 {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, domain := range allowEmailDomains {
|
||||||
|
if strings.HasSuffix(email, domain) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
|
@ -0,0 +1,24 @@
|
||||||
|
package plugin
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/answerdev/answer/internal/base/constant"
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Agent interface {
|
||||||
|
Base
|
||||||
|
RegisterUnAuthRouter(r *gin.RouterGroup)
|
||||||
|
RegisterAuthUserRouter(r *gin.RouterGroup)
|
||||||
|
RegisterAuthAdminRouter(r *gin.RouterGroup)
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
CallAgent,
|
||||||
|
registerAgent = MakePlugin[Agent](true)
|
||||||
|
)
|
||||||
|
|
||||||
|
// SiteURL The site url is the domain address of the current site. e.g. http://localhost:8080
|
||||||
|
// When some Agent plugins want to redirect to the origin site, it can use this function to get the site url.
|
||||||
|
func SiteURL() string {
|
||||||
|
return constant.DefaultSiteURL
|
||||||
|
}
|
|
@ -12,6 +12,7 @@ const (
|
||||||
ConfigTypeUpload ConfigType = "upload"
|
ConfigTypeUpload ConfigType = "upload"
|
||||||
ConfigTypeTimezone ConfigType = "timezone"
|
ConfigTypeTimezone ConfigType = "timezone"
|
||||||
ConfigTypeSwitch ConfigType = "switch"
|
ConfigTypeSwitch ConfigType = "switch"
|
||||||
|
ConfigTypeButton ConfigType = "button"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -43,10 +44,13 @@ type ConfigField struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type ConfigFieldUIOptions struct {
|
type ConfigFieldUIOptions struct {
|
||||||
Placeholder Translator `json:"placeholder,omitempty"`
|
Placeholder Translator `json:"placeholder,omitempty"`
|
||||||
Rows string `json:"rows,omitempty"`
|
Rows string `json:"rows,omitempty"`
|
||||||
InputType InputType `json:"input_type,omitempty"`
|
InputType InputType `json:"input_type,omitempty"`
|
||||||
Label Translator `json:"label,omitempty"`
|
Label Translator `json:"label,omitempty"`
|
||||||
|
Action *UIOptionAction `json:"action,omitempty"`
|
||||||
|
Variant string `json:"variant,omitempty"`
|
||||||
|
Text Translator `json:"text,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type ConfigFieldOption struct {
|
type ConfigFieldOption struct {
|
||||||
|
@ -54,6 +58,31 @@ type ConfigFieldOption struct {
|
||||||
Value string `json:"value"`
|
Value string `json:"value"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type UIOptionAction struct {
|
||||||
|
Url string `json:"url"`
|
||||||
|
Method string `json:"method,omitempty"`
|
||||||
|
Loading *LoadingAction `json:"loading,omitempty"`
|
||||||
|
OnComplete *OnCompleteAction `json:"on_complete,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
LoadingActionStateNone LoadingActionType = "none"
|
||||||
|
LoadingActionStatePending LoadingActionType = "pending"
|
||||||
|
LoadingActionStateComplete LoadingActionType = "completed"
|
||||||
|
)
|
||||||
|
|
||||||
|
type LoadingActionType string
|
||||||
|
|
||||||
|
type LoadingAction struct {
|
||||||
|
Text Translator `json:"text"`
|
||||||
|
State LoadingActionType `json:"state"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type OnCompleteAction struct {
|
||||||
|
ToastReturnMessage bool `json:"toast_return_message"`
|
||||||
|
RefreshFormConfig bool `json:"refresh_form_config"`
|
||||||
|
}
|
||||||
|
|
||||||
type Config interface {
|
type Config interface {
|
||||||
Base
|
Base
|
||||||
|
|
||||||
|
|
|
@ -52,6 +52,10 @@ func Register(p Base) {
|
||||||
if _, ok := p.(UserCenter); ok {
|
if _, ok := p.(UserCenter); ok {
|
||||||
registerUserCenter(p.(UserCenter))
|
registerUserCenter(p.(UserCenter))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if _, ok := p.(Agent); ok {
|
||||||
|
registerAgent(p.(Agent))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type Stack[T Base] struct {
|
type Stack[T Base] struct {
|
||||||
|
@ -132,7 +136,7 @@ type TranslateFn func(ctx *GinContext) string
|
||||||
|
|
||||||
// Translator contains a function that translates the key to the current language of the context
|
// Translator contains a function that translates the key to the current language of the context
|
||||||
type Translator struct {
|
type Translator struct {
|
||||||
fn TranslateFn
|
Fn TranslateFn
|
||||||
}
|
}
|
||||||
|
|
||||||
// MakeTranslator generates a translator from the key
|
// MakeTranslator generates a translator from the key
|
||||||
|
@ -140,13 +144,13 @@ func MakeTranslator(key string) Translator {
|
||||||
t := func(ctx *GinContext) string {
|
t := func(ctx *GinContext) string {
|
||||||
return Translate(ctx, key)
|
return Translate(ctx, key)
|
||||||
}
|
}
|
||||||
return Translator{fn: t}
|
return Translator{Fn: t}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Translate translates the key to the current language of the context
|
// Translate translates the key to the current language of the context
|
||||||
func (t Translator) Translate(ctx *GinContext) string {
|
func (t Translator) Translate(ctx *GinContext) string {
|
||||||
if &t == nil || t.fn == nil {
|
if &t == nil || t.Fn == nil {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
return t.fn(ctx)
|
return t.Fn(ctx)
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,21 +12,29 @@ type UserCenter interface {
|
||||||
SignUpCallback(ctx *GinContext) (userInfo *UserCenterBasicUserInfo, err error)
|
SignUpCallback(ctx *GinContext) (userInfo *UserCenterBasicUserInfo, err error)
|
||||||
// UserInfo returns the user information
|
// UserInfo returns the user information
|
||||||
UserInfo(externalID string) (userInfo *UserCenterBasicUserInfo, err error)
|
UserInfo(externalID string) (userInfo *UserCenterBasicUserInfo, err error)
|
||||||
|
// UserStatus returns the latest user status
|
||||||
|
UserStatus(externalID string) (userStatus UserStatus)
|
||||||
// UserList returns the user list information
|
// UserList returns the user list information
|
||||||
UserList(externalIDs []string) (userInfo []*UserCenterBasicUserInfo, err error)
|
UserList(externalIDs []string) (userInfo []*UserCenterBasicUserInfo, err error)
|
||||||
// UserSettings returns the user settings
|
// UserSettings returns the user settings
|
||||||
UserSettings(externalID string) (userSettings *SettingInfo, err error)
|
UserSettings(externalID string) (userSettings *SettingInfo, err error)
|
||||||
// PersonalBranding returns the personal branding information
|
// PersonalBranding returns the personal branding information
|
||||||
PersonalBranding(externalID string) (branding []*PersonalBranding)
|
PersonalBranding(externalID string) (branding []*PersonalBranding)
|
||||||
|
// AfterLogin is called after the user logs in
|
||||||
|
AfterLogin(externalID, accessToken string)
|
||||||
}
|
}
|
||||||
|
|
||||||
type UserCenterDesc struct {
|
type UserCenterDesc struct {
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Icon string `json:"icon"`
|
DisplayName Translator `json:"display_name"`
|
||||||
Url string `json:"url"`
|
Icon string `json:"icon"`
|
||||||
LoginRedirectURL string `json:"login_redirect_url"`
|
Url string `json:"url"`
|
||||||
SignUpRedirectURL string `json:"sign_up_redirect_url"`
|
LoginRedirectURL string `json:"login_redirect_url"`
|
||||||
RankAgentEnabled bool `json:"rank_agent_enabled"`
|
SignUpRedirectURL string `json:"sign_up_redirect_url"`
|
||||||
|
RankAgentEnabled bool `json:"rank_agent_enabled"`
|
||||||
|
UserStatusAgentEnabled bool `json:"user_status_agent_enabled"`
|
||||||
|
MustAuthEmailEnabled bool `json:"must_auth_email_enabled"`
|
||||||
|
EnabledOriginalUserSystem bool `json:"enabled_original_user_system"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type UserStatus int
|
type UserStatus int
|
||||||
|
@ -45,6 +53,7 @@ type UserCenterBasicUserInfo struct {
|
||||||
Rank int `json:"rank"`
|
Rank int `json:"rank"`
|
||||||
Avatar string `json:"avatar"`
|
Avatar string `json:"avatar"`
|
||||||
Mobile string `json:"mobile"`
|
Mobile string `json:"mobile"`
|
||||||
|
Bio string `json:"bio"`
|
||||||
Status UserStatus `json:"status"`
|
Status UserStatus `json:"status"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,26 +1,21 @@
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
set -e
|
||||||
|
echo "begin build plugin"
|
||||||
plugin_file=./script/plugin_list
|
plugin_file=./script/plugin_list
|
||||||
if [ ! -f "$plugin_file" ]; then
|
if [ ! -f "$plugin_file" ]; then
|
||||||
echo "plugin_list is not exist"
|
echo "plugin_list is not exist"
|
||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
num=0
|
|
||||||
for line in `cat $plugin_file`
|
echo "plugin_list exist"
|
||||||
do
|
|
||||||
account=$line
|
|
||||||
accounts[$num]=$account
|
|
||||||
((num++))
|
|
||||||
done
|
|
||||||
if [ $num -eq 0 ]; then
|
|
||||||
echo "plugin_list is null"
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
cmd="./answer build "
|
cmd="./answer build "
|
||||||
for repo in ${accounts[@]}
|
for repo in `cat $plugin_file`
|
||||||
do
|
do
|
||||||
echo ${repo}
|
echo ${repo}
|
||||||
cmd=$cmd" --with "${repo}
|
cmd=$cmd" --with "${repo}
|
||||||
done
|
done
|
||||||
|
|
||||||
|
echo "cmd is "$cmd
|
||||||
$cmd
|
$cmd
|
||||||
if [ ! -f "./new_answer" ]; then
|
if [ ! -f "./new_answer" ]; then
|
||||||
echo "new_answer is not exist build failed"
|
echo "new_answer is not exist build failed"
|
||||||
|
|
Loading…
Reference in New Issue