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)
|
||||
reasonController := controller.NewReasonController(reasonService)
|
||||
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.NewSiteinfoController(siteInfoCommonService)
|
||||
notificationRepo := notification.NewNotificationRepo(dataData)
|
||||
|
@ -220,7 +220,7 @@ func initApplication(debug bool, serverConf *conf.Server, dbConf *data.Database,
|
|||
templateController := controller.NewTemplateController(templateRenderController, siteInfoCommonService)
|
||||
templateRouter := router.NewTemplateRouter(templateController, templateRenderController, siteInfoController)
|
||||
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)
|
||||
pluginAPIRouter := router.NewPluginAPIRouter(connectorController, userCenterController)
|
||||
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": {
|
||||
"get": {
|
||||
"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": {
|
||||
"get": {
|
||||
"security": [
|
||||
|
@ -2861,7 +3003,7 @@ const docTemplate = `{
|
|||
"ApiKeyAuth": []
|
||||
}
|
||||
],
|
||||
"description": "list personal answers",
|
||||
"description": "UserAnswerList",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
|
@ -2869,9 +3011,9 @@ const docTemplate = `{
|
|||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Personal"
|
||||
"api-answer"
|
||||
],
|
||||
"summary": "list personal answers",
|
||||
"summary": "UserAnswerList",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
|
@ -2903,8 +3045,8 @@ const docTemplate = `{
|
|||
{
|
||||
"type": "string",
|
||||
"default": "20",
|
||||
"description": "page_size",
|
||||
"name": "page_size",
|
||||
"description": "pagesize",
|
||||
"name": "pagesize",
|
||||
"in": "query",
|
||||
"required": true
|
||||
}
|
||||
|
@ -2926,7 +3068,7 @@ const docTemplate = `{
|
|||
"ApiKeyAuth": []
|
||||
}
|
||||
],
|
||||
"description": "list personal collections",
|
||||
"description": "UserCollectionList",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
|
@ -2936,7 +3078,7 @@ const docTemplate = `{
|
|||
"tags": [
|
||||
"Collection"
|
||||
],
|
||||
"summary": "list personal collections",
|
||||
"summary": "UserCollectionList",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
|
@ -2949,8 +3091,8 @@ const docTemplate = `{
|
|||
{
|
||||
"type": "string",
|
||||
"default": "20",
|
||||
"description": "page_size",
|
||||
"name": "page_size",
|
||||
"description": "pagesize",
|
||||
"name": "pagesize",
|
||||
"in": "query",
|
||||
"required": true
|
||||
}
|
||||
|
@ -5668,7 +5810,7 @@ const docTemplate = `{
|
|||
"ApiKeyAuth": []
|
||||
}
|
||||
],
|
||||
"description": "list personal questions",
|
||||
"description": "UserList",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
|
@ -5676,9 +5818,9 @@ const docTemplate = `{
|
|||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Personal"
|
||||
"Question"
|
||||
],
|
||||
"summary": "list personal questions",
|
||||
"summary": "UserList",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
|
@ -5710,8 +5852,8 @@ const docTemplate = `{
|
|||
{
|
||||
"type": "string",
|
||||
"default": "20",
|
||||
"description": "page_size",
|
||||
"name": "page_size",
|
||||
"description": "pagesize",
|
||||
"name": "pagesize",
|
||||
"in": "query",
|
||||
"required": true
|
||||
}
|
||||
|
@ -5748,6 +5890,20 @@ const docTemplate = `{
|
|||
}
|
||||
},
|
||||
"definitions": {
|
||||
"constant.Privilege": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"key": {
|
||||
"type": "string"
|
||||
},
|
||||
"label": {
|
||||
"type": "string"
|
||||
},
|
||||
"value": {
|
||||
"type": "integer"
|
||||
}
|
||||
}
|
||||
},
|
||||
"handler.RespBody": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
|
@ -6229,9 +6385,20 @@ const docTemplate = `{
|
|||
}
|
||||
}
|
||||
},
|
||||
"schema.ConfigFieldUIOptionAction": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"url": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"schema.ConfigFieldUIOptions": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"action": {
|
||||
"$ref": "#/definitions/schema.ConfigFieldUIOptionAction"
|
||||
},
|
||||
"input_type": {
|
||||
"type": "string"
|
||||
},
|
||||
|
@ -6243,6 +6410,12 @@ const docTemplate = `{
|
|||
},
|
||||
"rows": {
|
||||
"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": {
|
||||
"type": "object",
|
||||
"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": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
|
@ -7418,6 +7622,10 @@ const docTemplate = `{
|
|||
"schema.QuestionPageReq": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"inDays": {
|
||||
"type": "integer",
|
||||
"minimum": 1
|
||||
},
|
||||
"orderCond": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
|
@ -7800,6 +8008,10 @@ const docTemplate = `{
|
|||
"custom_header": {
|
||||
"type": "string",
|
||||
"maxLength": 65536
|
||||
},
|
||||
"custom_sidebar": {
|
||||
"type": "string",
|
||||
"maxLength": 65536
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -7821,6 +8033,10 @@ const docTemplate = `{
|
|||
"custom_header": {
|
||||
"type": "string",
|
||||
"maxLength": 65536
|
||||
},
|
||||
"custom_sidebar": {
|
||||
"type": "string",
|
||||
"maxLength": 65536
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -7908,6 +8124,9 @@ const docTemplate = `{
|
|||
"site_seo": {
|
||||
"$ref": "#/definitions/schema.SiteSeoReq"
|
||||
},
|
||||
"site_users": {
|
||||
"$ref": "#/definitions/schema.SiteUsersResp"
|
||||
},
|
||||
"theme": {
|
||||
"$ref": "#/definitions/schema.SiteThemeResp"
|
||||
},
|
||||
|
@ -7919,18 +8138,10 @@ const docTemplate = `{
|
|||
"schema.SiteInterfaceReq": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"default_avatar",
|
||||
"language",
|
||||
"time_zone"
|
||||
],
|
||||
"properties": {
|
||||
"default_avatar": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"system",
|
||||
"gravatar"
|
||||
]
|
||||
},
|
||||
"language": {
|
||||
"type": "string",
|
||||
"maxLength": 128
|
||||
|
@ -7944,18 +8155,10 @@ const docTemplate = `{
|
|||
"schema.SiteInterfaceResp": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"default_avatar",
|
||||
"language",
|
||||
"time_zone"
|
||||
],
|
||||
"properties": {
|
||||
"default_avatar": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"system",
|
||||
"gravatar"
|
||||
]
|
||||
},
|
||||
"language": {
|
||||
"type": "string",
|
||||
"maxLength": 128
|
||||
|
@ -8003,6 +8206,15 @@ const docTemplate = `{
|
|||
"schema.SiteLoginReq": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"allow_email_domains": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"allow_email_registrations": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"allow_new_registrations": {
|
||||
"type": "boolean"
|
||||
},
|
||||
|
@ -8014,6 +8226,15 @@ const docTemplate = `{
|
|||
"schema.SiteLoginResp": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"allow_email_domains": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"allow_email_registrations": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"allow_new_registrations": {
|
||||
"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": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
|
@ -8324,6 +8611,19 @@ const docTemplate = `{
|
|||
}
|
||||
}
|
||||
},
|
||||
"schema.UpdatePrivilegesConfigReq": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"level"
|
||||
],
|
||||
"properties": {
|
||||
"level": {
|
||||
"type": "integer",
|
||||
"maximum": 3,
|
||||
"minimum": 1
|
||||
}
|
||||
}
|
||||
},
|
||||
"schema.UpdateSMTPConfigReq": {
|
||||
"type": "object",
|
||||
"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.4 h1:V7DdXeJtZscaqfNuAdSRuRFzuiKlHSC/Zh3zl9qY3JY=
|
||||
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.13.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
|
||||
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-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-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/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=
|
||||
|
@ -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.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.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/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
||||
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/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
|
||||
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.9.7/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
|
||||
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.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||
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.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
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.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.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/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
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-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-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/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4=
|
||||
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-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.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
|
||||
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/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-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-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-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU=
|
||||
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/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU=
|
||||
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.1 h1:U3uMjPSQEBMNp1lFxmllqCPM6P5u/Xq7Pgzkat/bFNc=
|
||||
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.7.0 h1:WSHQ+IS43OoUrWtD1/bbclrwK8TTH5hzp+umCiuxHgs=
|
||||
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.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/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
|
||||
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.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
|
||||
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/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 h1:OdAsTTz6OkFY5QxjkYwrChwuRruF69c169dPK26NUlk=
|
||||
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/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=
|
||||
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.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
|
||||
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.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
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.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
||||
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-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-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-20190501045829-6d32002ffd75/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
||||
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.3/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.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
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-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-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-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
|
||||
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-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-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.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
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.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.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0=
|
||||
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.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-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||
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.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/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.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w=
|
||||
|
|
|
@ -25,6 +25,8 @@ backend:
|
|||
other: Close
|
||||
reopen:
|
||||
other: Reopen
|
||||
forbidden_error:
|
||||
other: Forbidden.
|
||||
pin:
|
||||
other: Pin
|
||||
hide:
|
||||
|
@ -48,6 +50,58 @@ backend:
|
|||
other: Have the full power to access the site.
|
||||
moderator:
|
||||
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:
|
||||
other: Email
|
||||
password:
|
||||
|
@ -85,6 +139,8 @@ backend:
|
|||
other: Email should be verified.
|
||||
verify_url_expired:
|
||||
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:
|
||||
not_found:
|
||||
other: Language file not found.
|
||||
|
@ -176,6 +232,10 @@ backend:
|
|||
other: You cannot modify your role.
|
||||
not_allowed_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:
|
||||
read_config_failed:
|
||||
other: Read config failed
|
||||
|
@ -281,6 +341,16 @@ backend:
|
|||
other: Your answer has been deleted
|
||||
your_comment_was_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)
|
||||
ui:
|
||||
|
|
|
@ -45,6 +45,58 @@ backend:
|
|||
other: 拥有管理网站的全部权限。
|
||||
moderator:
|
||||
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:
|
||||
other: 邮箱
|
||||
password:
|
||||
|
@ -82,6 +134,8 @@ backend:
|
|||
other: 邮箱需要验证。
|
||||
verify_url_expired:
|
||||
other: 邮箱验证的网址已过期,请重新发送邮件。
|
||||
illegal_email_domain_error:
|
||||
other: 该域名的邮箱无法使用。请尝试更换其他邮箱。
|
||||
lang:
|
||||
not_found:
|
||||
other: 语言未找到
|
||||
|
@ -171,6 +225,10 @@ backend:
|
|||
other: 您不能修改自己的角色。
|
||||
not_allowed_registration:
|
||||
other: 目前该站点未开放注册
|
||||
access_denied:
|
||||
other: 访问被拒绝
|
||||
page_access_denied:
|
||||
other: 你没有权限进入这个页面。
|
||||
config:
|
||||
read_config_failed:
|
||||
other: 读取配置失败
|
||||
|
@ -271,6 +329,16 @@ backend:
|
|||
other: 你的答案已被删除
|
||||
your_comment_was_deleted:
|
||||
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)
|
||||
ui:
|
||||
how_to_format:
|
||||
|
@ -1063,6 +1131,9 @@ ui:
|
|||
installed_plugins: 插件列表
|
||||
website_welcome: 欢迎来到 {{site_name}}
|
||||
plugins:
|
||||
login: 登录
|
||||
qrcode_login_tip: 请使用 {{ agentName }} 扫描二维码登录
|
||||
login_failed_email_tip: 登录失败, 请允许该应用程序访问您的电子邮件信息,然后再试一次。
|
||||
oauth:
|
||||
connect: 连接到 {{ auth_name }}
|
||||
remove: 解绑 {{ auth_name }}
|
||||
|
@ -1396,6 +1467,30 @@ ui:
|
|||
deactivate: 停用
|
||||
activate: 启用
|
||||
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:
|
||||
optional: (选填)
|
||||
empty: 不能为空
|
||||
|
|
|
@ -66,6 +66,8 @@ const (
|
|||
SiteTypeLogin = "login"
|
||||
SiteTypeCustomCssHTML = "css-html"
|
||||
SiteTypeTheme = "theme"
|
||||
SiteTypePrivileges = "privileges"
|
||||
SiteTypeUsers = "users"
|
||||
)
|
||||
|
||||
func ExistInPathIgnore(name string) bool {
|
||||
|
|
|
@ -1,28 +1,38 @@
|
|||
package constant
|
||||
|
||||
const (
|
||||
// UpdateQuestion update question
|
||||
UpdateQuestion = "notification.action.update_question"
|
||||
// AnswerTheQuestion answer the question
|
||||
AnswerTheQuestion = "notification.action.answer_the_question"
|
||||
// UpdateAnswer update answer
|
||||
UpdateAnswer = "notification.action.update_answer"
|
||||
// AcceptAnswer accept answer
|
||||
AcceptAnswer = "notification.action.accept_answer"
|
||||
// CommentQuestion comment question
|
||||
CommentQuestion = "notification.action.comment_question"
|
||||
// CommentAnswer comment answer
|
||||
CommentAnswer = "notification.action.comment_answer"
|
||||
// ReplyToYou reply to you
|
||||
ReplyToYou = "notification.action.reply_to_you"
|
||||
// MentionYou mention you
|
||||
MentionYou = "notification.action.mention_you"
|
||||
// YourQuestionIsClosed your question is closed
|
||||
YourQuestionIsClosed = "notification.action.your_question_is_closed"
|
||||
// YourQuestionWasDeleted your question was deleted
|
||||
YourQuestionWasDeleted = "notification.action.your_question_was_deleted"
|
||||
// YourAnswerWasDeleted your answer was deleted
|
||||
YourAnswerWasDeleted = "notification.action.your_answer_was_deleted"
|
||||
// YourCommentWasDeleted your comment was deleted
|
||||
YourCommentWasDeleted = "notification.action.your_comment_was_deleted"
|
||||
// NotificationUpdateQuestion update question
|
||||
NotificationUpdateQuestion = "notification.action.update_question"
|
||||
// NotificationAnswerTheQuestion answer the question
|
||||
NotificationAnswerTheQuestion = "notification.action.answer_the_question"
|
||||
// NotificationUpVotedTheQuestion up voted the question
|
||||
NotificationUpVotedTheQuestion = "notification.action.up_voted_question"
|
||||
// NotificationDownVotedTheQuestion down voted the question
|
||||
NotificationDownVotedTheQuestion = "notification.action.down_voted_question"
|
||||
// NotificationUpdateAnswer update answer
|
||||
NotificationUpdateAnswer = "notification.action.update_answer"
|
||||
// NotificationAcceptAnswer accept answer
|
||||
NotificationAcceptAnswer = "notification.action.accept_answer"
|
||||
// NotificationUpVotedTheAnswer up voted the answer
|
||||
NotificationUpVotedTheAnswer = "notification.action.up_voted_answer"
|
||||
// NotificationDownVotedTheAnswer down voted the answer
|
||||
NotificationDownVotedTheAnswer = "notification.action.down_voted_answer"
|
||||
// NotificationCommentQuestion comment question
|
||||
NotificationCommentQuestion = "notification.action.comment_question"
|
||||
// NotificationCommentAnswer comment answer
|
||||
NotificationCommentAnswer = "notification.action.comment_answer"
|
||||
// NotificationUpVotedTheComment up voted the comment
|
||||
NotificationUpVotedTheComment = "notification.action.up_voted_comment"
|
||||
// NotificationReplyToYou reply to you
|
||||
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},
|
||||
}
|
||||
)
|
|
@ -2,4 +2,5 @@ package constant
|
|||
|
||||
var (
|
||||
DefaultAvatar = "system"
|
||||
DefaultSiteURL = ""
|
||||
)
|
||||
|
|
|
@ -8,9 +8,13 @@ import (
|
|||
"github.com/segmentfault/pacman/errors"
|
||||
)
|
||||
|
||||
// BanAPIWhenUserCenterEnabled ban api when user center enabled
|
||||
func BanAPIWhenUserCenterEnabled(ctx *gin.Context) {
|
||||
if plugin.UserCenterEnabled() {
|
||||
// BanAPIForUserCenter ban api for user center
|
||||
func BanAPIForUserCenter(ctx *gin.Context) {
|
||||
uc, ok := plugin.GetUserCenter()
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
if !uc.Description().EnabledOriginalUserSystem {
|
||||
handler.HandleResponse(ctx, errors.Forbidden(reason.ForbiddenError), nil)
|
||||
ctx.Abort()
|
||||
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"
|
||||
EmailVerifyURLExpired = "error.email.verify_url_expired"
|
||||
EmailNeedToBeVerified = "error.email.need_to_be_verified"
|
||||
EmailIllegalDomainError = "error.email.illegal_email_domain_error"
|
||||
UserSuspended = "error.user.suspended"
|
||||
ObjectNotFound = "error.object.not_found"
|
||||
TagNotFound = "error.tag.not_found"
|
||||
|
@ -73,4 +74,6 @@ const (
|
|||
AdminCannotUpdateTheirPassword = "error.admin.cannot_update_their_password"
|
||||
AdminCannotModifySelfStatus = "error.admin.cannot_modify_self_status"
|
||||
UserExternalLoginUnbindingForbidden = "error.user.external_login_unbinding_forbidden"
|
||||
UserAccessDenied = "error.user.access_denied"
|
||||
UserPageAccessDenied = "error.user.page_access_denied"
|
||||
)
|
||||
|
|
|
@ -7,6 +7,7 @@ import (
|
|||
brotli "github.com/anargu/gin-brotli"
|
||||
"github.com/answerdev/answer/internal/base/middleware"
|
||||
"github.com/answerdev/answer/internal/router"
|
||||
"github.com/answerdev/answer/plugin"
|
||||
"github.com/answerdev/answer/ui"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
@ -66,6 +67,14 @@ func NewHTTPServer(debug bool,
|
|||
|
||||
// plugin routes
|
||||
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
|
||||
}
|
||||
|
|
|
@ -130,7 +130,7 @@ func (cc *ConnectorController) ConnectorRedirect(connector plugin.Connector) (fn
|
|||
return
|
||||
}
|
||||
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))
|
||||
} else {
|
||||
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 {
|
||||
info := uc.Description()
|
||||
resp.AgentInfo.Name = info.Name
|
||||
resp.AgentInfo.DisplayName = info.DisplayName.Translate(ctx)
|
||||
resp.AgentInfo.Icon = info.Icon
|
||||
resp.AgentInfo.Url = info.Url
|
||||
resp.AgentInfo.ControlCenterItems = make([]*schema.ControlCenter, 0)
|
||||
resp.AgentInfo.EnabledOriginalUserSystem = info.EnabledOriginalUserSystem
|
||||
items := uc.ControlCenterItems()
|
||||
for _, item := range items {
|
||||
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) {
|
||||
var redirectURL string
|
||||
_ = plugin.CallUserCenter(func(uc plugin.UserCenter) error {
|
||||
info := uc.Description()
|
||||
_ = plugin.CallUserCenter(func(userCenter plugin.UserCenter) error {
|
||||
info := userCenter.Description()
|
||||
redirectURL = info.LoginRedirectURL
|
||||
return nil
|
||||
})
|
||||
|
@ -100,9 +102,9 @@ func (uc *UserCenterController) UserCenterLoginRedirect(ctx *gin.Context) {
|
|||
|
||||
func (uc *UserCenterController) UserCenterSignUpRedirect(ctx *gin.Context) {
|
||||
var redirectURL string
|
||||
_ = plugin.CallUserCenter(func(uc plugin.UserCenter) error {
|
||||
info := uc.Description()
|
||||
redirectURL = info.SignUpRedirectURL
|
||||
_ = plugin.CallUserCenter(func(userCenter plugin.UserCenter) error {
|
||||
info := userCenter.Description()
|
||||
redirectURL = info.LoginRedirectURL
|
||||
return nil
|
||||
})
|
||||
ctx.Redirect(http.StatusFound, redirectURL)
|
||||
|
@ -124,17 +126,24 @@ func (uc *UserCenterController) UserCenterLoginCallback(ctx *gin.Context) {
|
|||
userInfo, err := userCenter.LoginCallback(ctx)
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
if !ctx.IsAborted() {
|
||||
ctx.Redirect(http.StatusFound, "/50x")
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
resp, err := uc.userCenterLoginService.ExternalLogin(ctx, userCenter.Info().SlugName, userInfo)
|
||||
resp, err := uc.userCenterLoginService.ExternalLogin(ctx, userCenter, userInfo)
|
||||
if err != nil {
|
||||
log.Errorf("external login failed: %v", err)
|
||||
ctx.Redirect(http.StatusFound, "/50x")
|
||||
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))
|
||||
}
|
||||
|
||||
|
@ -158,13 +167,18 @@ func (uc *UserCenterController) UserCenterSignUpCallback(ctx *gin.Context) {
|
|||
return
|
||||
}
|
||||
|
||||
resp, err := uc.userCenterLoginService.ExternalLogin(ctx, userCenter.Info().SlugName, userInfo)
|
||||
resp, err := uc.userCenterLoginService.ExternalLogin(ctx, userCenter, userInfo)
|
||||
if err != nil {
|
||||
log.Errorf("external login failed: %v", err)
|
||||
ctx.Redirect(http.StatusFound, "/50x")
|
||||
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))
|
||||
}
|
||||
|
||||
|
@ -174,3 +188,9 @@ func (uc *UserCenterController) UserCenterUserSettings(ctx *gin.Context) {
|
|||
resp, err := uc.userCenterLoginService.UserCenterUserSettings(ctx, userID)
|
||||
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 {
|
||||
log.Error(err)
|
||||
}
|
||||
resp.SiteUsers, err = sc.siteInfoService.GetSiteUsers(ctx)
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
}
|
||||
|
||||
handler.HandleResponse(ctx, nil, resp)
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@ import (
|
|||
"github.com/answerdev/answer/internal/service/export"
|
||||
"github.com/answerdev/answer/internal/service/siteinfo_common"
|
||||
"github.com/answerdev/answer/internal/service/uploader"
|
||||
"github.com/answerdev/answer/pkg/checker"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/segmentfault/pacman/errors"
|
||||
"github.com/segmentfault/pacman/log"
|
||||
|
@ -223,7 +224,7 @@ func (uc *UserController) UserRegisterByEmail(ctx *gin.Context) {
|
|||
handler.HandleResponse(ctx, err, nil)
|
||||
return
|
||||
}
|
||||
if !siteInfo.AllowNewRegistrations {
|
||||
if !siteInfo.AllowNewRegistrations || !siteInfo.AllowEmailRegistrations {
|
||||
handler.HandleResponse(ctx, errors.BadRequest(reason.NotAllowedRegistration), nil)
|
||||
return
|
||||
}
|
||||
|
@ -232,6 +233,10 @@ func (uc *UserController) UserRegisterByEmail(ctx *gin.Context) {
|
|||
if handler.BindAndCheck(ctx, req) {
|
||||
return
|
||||
}
|
||||
if !checker.EmailInAllowEmailDomain(req.Email, siteInfo.AllowEmailDomains) {
|
||||
handler.HandleResponse(ctx, errors.BadRequest(reason.EmailIllegalDomainError), nil)
|
||||
return
|
||||
}
|
||||
req.IP = ctx.ClientIP()
|
||||
captchaPass := uc.actionService.UserRegisterVerifyCaptcha(ctx, req.CaptchaID, req.CaptchaCode)
|
||||
if !captchaPass {
|
||||
|
@ -489,6 +494,16 @@ func (uc *UserController) UserChangeEmailSendCode(ctx *gin.Context) {
|
|||
handler.HandleResponse(ctx, errors.Unauthorized(reason.UnauthorizedError), nil)
|
||||
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)
|
||||
if !captchaPass {
|
||||
|
|
|
@ -139,6 +139,19 @@ func (sc *SiteInfoController) GetSiteTheme(ctx *gin.Context) {
|
|||
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
|
||||
// @Summary 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)
|
||||
}
|
||||
|
||||
// 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
|
||||
// @Summary 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)
|
||||
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
|
||||
// @Router /answer/admin/api/user/status [put]
|
||||
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)
|
||||
return
|
||||
}
|
||||
|
@ -80,10 +80,6 @@ func (uc *UserAdminController) UpdateUserRole(ctx *gin.Context) {
|
|||
// @Success 200 {object} handler.RespBody
|
||||
// @Router /answer/admin/api/user [post]
|
||||
func (uc *UserAdminController) AddUser(ctx *gin.Context) {
|
||||
if plugin.UserCenterEnabled() {
|
||||
handler.HandleResponse(ctx, errors.Forbidden(reason.ForbiddenError), nil)
|
||||
return
|
||||
}
|
||||
req := &schema.AddUserReq{}
|
||||
if handler.BindAndCheck(ctx, req) {
|
||||
return
|
||||
|
@ -106,10 +102,6 @@ func (uc *UserAdminController) AddUser(ctx *gin.Context) {
|
|||
// @Success 200 {object} handler.RespBody
|
||||
// @Router /answer/admin/api/user/password [put]
|
||||
func (uc *UserAdminController) UpdateUserPassword(ctx *gin.Context) {
|
||||
if plugin.UserCenterEnabled() {
|
||||
handler.HandleResponse(ctx, errors.Forbidden(reason.ForbiddenError), nil)
|
||||
return
|
||||
}
|
||||
req := &schema.UpdateUserPasswordReq{}
|
||||
if handler.BindAndCheck(ctx, req) {
|
||||
return
|
||||
|
|
|
@ -6,4 +6,5 @@ type UserCacheInfo struct {
|
|||
UserStatus int `json:"user_status"`
|
||||
EmailStatus int `json:"email_status"`
|
||||
RoleID int `json:"role_id"`
|
||||
ExternalID string `json:"external_id"`
|
||||
}
|
||||
|
|
|
@ -144,6 +144,7 @@ func initSiteInfo(engine *xorm.Engine, language, siteName, siteURL, contactEmail
|
|||
|
||||
loginConfig := map[string]bool{
|
||||
"allow_new_registrations": true,
|
||||
"allow_email_registrations": true,
|
||||
"login_required": false,
|
||||
}
|
||||
loginConfigDataBytes, _ := json.Marshal(loginConfig)
|
||||
|
@ -178,6 +179,25 @@ func initSiteInfo(engine *xorm.Engine, language, siteName, siteURL, contactEmail
|
|||
if err != nil {
|
||||
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
|
||||
}
|
||||
|
||||
|
@ -346,10 +366,14 @@ func initConfigTable(engine *xorm.Engine) error {
|
|||
{ID: 116, Key: "rank.question.reopen", Value: `-1`},
|
||||
{ID: 117, Key: "rank.tag.use_reserved_tag", Value: `-1`},
|
||||
{ID: 118, Key: "plugin.status", Value: `{}`},
|
||||
{ID: 119, Key: "question.pin", Value: `-1`},
|
||||
{ID: 120, Key: "question.unpin", Value: `-1`},
|
||||
{ID: 121, Key: "question.show", Value: `-1`},
|
||||
{ID: 122, Key: "question.hide", Value: `-1`},
|
||||
{ID: 119, Key: "question.pin", Value: `0`},
|
||||
{ID: 120, Key: "question.unpin", Value: `0`},
|
||||
{ID: 121, Key: "question.show", Value: `0`},
|
||||
{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)
|
||||
return err
|
||||
|
|
|
@ -61,6 +61,7 @@ var migrations = []Migration{
|
|||
NewMigration("add plugin", addPlugin, false),
|
||||
NewMigration("update user pin hide features", updateRolePinAndHideFeatures, true),
|
||||
NewMigration("update question post time", updateQuestionPostTime, true),
|
||||
NewMigration("add login limitations", addLoginLimitations, true),
|
||||
}
|
||||
|
||||
// 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)
|
||||
}
|
||||
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
|
||||
}
|
||||
if _, err = x.Insert(&entity.Config{ID: c.ID, Key: c.Key, Value: c.Value}); err != nil {
|
||||
|
|
|
@ -202,8 +202,10 @@ func (ar *AnswerActivityRepo) AcceptAnswer(ctx context.Context,
|
|||
msg.TriggerUserID = questionUserID
|
||||
msg.ObjectType = constant.AnswerObjectType
|
||||
}
|
||||
if msg.TriggerUserID != msg.ReceiverUserID {
|
||||
notice_queue.AddNotification(msg)
|
||||
}
|
||||
}
|
||||
|
||||
for _, act := range addActivityList {
|
||||
msg := &schema.NotificationMsg{
|
||||
|
@ -214,7 +216,7 @@ func (ar *AnswerActivityRepo) AcceptAnswer(ctx context.Context,
|
|||
if act.UserID != questionUserID {
|
||||
msg.TriggerUserID = questionUserID
|
||||
msg.ObjectType = constant.AnswerObjectType
|
||||
msg.NotificationAction = constant.AcceptAnswer
|
||||
msg.NotificationAction = constant.NotificationAcceptAnswer
|
||||
notice_queue.AddNotification(msg)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@ import (
|
|||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/answerdev/answer/internal/base/constant"
|
||||
"github.com/answerdev/answer/pkg/converter"
|
||||
|
||||
"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) {
|
||||
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) {
|
||||
result = nil
|
||||
for _, action := range actions {
|
||||
|
@ -127,7 +130,7 @@ func (vr *VoteRepo) vote(ctx context.Context, objectID string, userID, objectUse
|
|||
if isReachStandard {
|
||||
insertActivity.Rank = 0
|
||||
}
|
||||
notificationUserIDs = append(notificationUserIDs, activityUserID)
|
||||
achievementNotificationUserIDs = append(achievementNotificationUserIDs, activityUserID)
|
||||
}
|
||||
|
||||
if has {
|
||||
|
@ -142,13 +145,17 @@ func (vr *VoteRepo) vote(ctx context.Context, objectID string, userID, objectUse
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
sendInboxNotification = true
|
||||
}
|
||||
|
||||
// update votes
|
||||
if action == "vote_down" || action == "vote_up" {
|
||||
if action == constant.ActVoteDown || action == constant.ActVoteUp {
|
||||
votes := 1
|
||||
if action == "vote_down" {
|
||||
if action == constant.ActVoteDown {
|
||||
upVote = false
|
||||
votes = -1
|
||||
} else {
|
||||
upVote = true
|
||||
}
|
||||
err = vr.updateVotes(ctx, session, objectID, votes)
|
||||
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.VoteStatus = vr.voteCommon.GetVoteStatus(ctx, objectID, userID)
|
||||
|
||||
for _, activityUserID := range notificationUserIDs {
|
||||
for _, activityUserID := range achievementNotificationUserIDs {
|
||||
vr.sendNotification(ctx, activityUserID, objectUserID, objectID)
|
||||
}
|
||||
if sendInboxNotification {
|
||||
vr.sendVoteInboxNotification(userID, objectUserID, objectID, upVote)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -441,3 +451,40 @@ func (vr *VoteRepo) sendNotification(ctx context.Context, activityUserID, object
|
|||
}
|
||||
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
|
||||
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 = make([]*entity.Question, 0)
|
||||
|
||||
|
@ -271,6 +271,9 @@ func (qr *questionRepo) GetQuestionPage(ctx context.Context, page, pageSize int,
|
|||
} else {
|
||||
session.And("question.show = ?", entity.QuestionShow)
|
||||
}
|
||||
if inDays > 0 {
|
||||
session.And("question.created_at > ?", time.Now().AddDate(0, 0, -inDays))
|
||||
}
|
||||
|
||||
switch orderCond {
|
||||
case "newest":
|
||||
|
|
|
@ -86,6 +86,9 @@ func (ur *userAdminRepo) GetUserInfo(ctx context.Context, userID string) (user *
|
|||
if err != nil {
|
||||
return nil, false, errors.InternalServer(reason.DatabaseError).WithError(err).WithStack()
|
||||
}
|
||||
if !exist {
|
||||
return
|
||||
}
|
||||
err = tryToDecorateUserInfoFromUserCenter(ctx, ur.data, user)
|
||||
if err != nil {
|
||||
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()
|
||||
return
|
||||
}
|
||||
if !exist {
|
||||
return
|
||||
}
|
||||
err = tryToDecorateUserInfoFromUserCenter(ctx, ur.data, user)
|
||||
if err != nil {
|
||||
return nil, false, err
|
||||
|
|
|
@ -10,6 +10,7 @@ import (
|
|||
"github.com/answerdev/answer/internal/schema"
|
||||
"github.com/answerdev/answer/internal/service/config"
|
||||
usercommon "github.com/answerdev/answer/internal/service/user_common"
|
||||
"github.com/answerdev/answer/pkg/converter"
|
||||
"github.com/answerdev/answer/plugin"
|
||||
"github.com/segmentfault/pacman/errors"
|
||||
"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) {
|
||||
if original == nil {
|
||||
return nil
|
||||
}
|
||||
uc, ok := plugin.GetUserCenter()
|
||||
if !ok {
|
||||
return nil
|
||||
|
@ -276,14 +280,27 @@ func decorateByUserCenterUser(original *entity.User, ucUser *plugin.UserCenterBa
|
|||
if original.Username != ucUser.Username {
|
||||
log.Warnf("user %s username is inconsistent with user center", original.ID)
|
||||
}
|
||||
if len(ucUser.DisplayName) > 0 {
|
||||
original.DisplayName = ucUser.DisplayName
|
||||
}
|
||||
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.RankAgentEnabled() {
|
||||
original.Rank = ucUser.Rank
|
||||
}
|
||||
if ucUser.Status != plugin.UserStatusAvailable {
|
||||
original.Status = int(ucUser.Status)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -102,7 +102,7 @@ func (a *AnswerAPIRouter) RegisterMustUnAuthAnswerAPIRouter(r *gin.RouterGroup)
|
|||
|
||||
// user
|
||||
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/register/email", a.userController.UserRegisterByEmail)
|
||||
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) {
|
||||
// user
|
||||
r.GET("/user/logout", a.userController.UserLogout)
|
||||
r.POST("/user/email/change/code", middleware.BanAPIWhenUserCenterEnabled, a.userController.UserChangeEmailSendCode)
|
||||
r.POST("/user/email/verification/send", middleware.BanAPIWhenUserCenterEnabled, a.userController.UserVerifyEmailSend)
|
||||
r.POST("/user/email/change/code", middleware.BanAPIForUserCenter, a.userController.UserChangeEmailSendCode)
|
||||
r.POST("/user/email/verification/send", middleware.BanAPIForUserCenter, a.userController.UserVerifyEmailSend)
|
||||
r.GET("/personal/user/info", a.userController.GetOtherUserInfoByUsername)
|
||||
r.GET("/user/ranking", a.userController.UserRanking)
|
||||
|
||||
|
@ -206,8 +206,8 @@ func (a *AnswerAPIRouter) RegisterAnswerAPIRouter(r *gin.RouterGroup) {
|
|||
r.DELETE("/answer", a.answerController.RemoveAnswer)
|
||||
|
||||
// user
|
||||
r.PUT("/user/password", middleware.BanAPIWhenUserCenterEnabled, a.userController.UserModifyPassWord)
|
||||
r.PUT("/user/info", middleware.BanAPIWhenUserCenterEnabled, a.userController.UserUpdateInfo)
|
||||
r.PUT("/user/password", middleware.BanAPIForUserCenter, a.userController.UserModifyPassWord)
|
||||
r.PUT("/user/info", a.userController.UserUpdateInfo)
|
||||
r.PUT("/user/interface", a.userController.UserUpdateInterface)
|
||||
r.POST("/user/notice/set", a.userController.UserNoticeSet)
|
||||
|
||||
|
@ -246,10 +246,10 @@ func (a *AnswerAPIRouter) RegisterAnswerAdminAPIRouter(r *gin.RouterGroup) {
|
|||
|
||||
// user
|
||||
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.POST("/user", middleware.BanAPIWhenUserCenterEnabled, a.adminUserController.AddUser)
|
||||
r.PUT("/user/password", middleware.BanAPIWhenUserCenterEnabled, a.adminUserController.UpdateUserPassword)
|
||||
r.POST("/user", a.adminUserController.AddUser)
|
||||
r.PUT("/user/password", a.adminUserController.UpdateUserPassword)
|
||||
|
||||
// reason
|
||||
r.GET("/reasons", a.reasonController.Reasons)
|
||||
|
@ -262,25 +262,29 @@ func (a *AnswerAPIRouter) RegisterAnswerAdminAPIRouter(r *gin.RouterGroup) {
|
|||
|
||||
// siteinfo
|
||||
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.GET("/siteinfo/interface", a.siteInfoController.GetInterface)
|
||||
r.PUT("/siteinfo/interface", a.siteInfoController.UpdateInterface)
|
||||
r.GET("/siteinfo/branding", a.siteInfoController.GetSiteBranding)
|
||||
r.PUT("/siteinfo/branding", a.siteInfoController.UpdateBranding)
|
||||
r.GET("/siteinfo/write", a.siteInfoController.GetSiteWrite)
|
||||
r.PUT("/siteinfo/write", a.siteInfoController.UpdateSiteWrite)
|
||||
r.GET("/siteinfo/legal", a.siteInfoController.GetSiteLegal)
|
||||
r.PUT("/siteinfo/legal", a.siteInfoController.UpdateSiteLegal)
|
||||
r.PUT("/siteinfo/login", a.siteInfoController.UpdateSiteLogin)
|
||||
r.PUT("/siteinfo/custom-css-html", a.siteInfoController.UpdateSiteCustomCssHTML)
|
||||
r.PUT("/siteinfo/theme", a.siteInfoController.SaveSiteTheme)
|
||||
r.GET("/siteinfo/seo", a.siteInfoController.GetSeo)
|
||||
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.PUT("/setting/smtp", a.siteInfoController.UpdateSMTPConfig)
|
||||
r.GET("/setting/privileges", a.siteInfoController.GetPrivilegesConfig)
|
||||
r.PUT("/setting/privileges", a.siteInfoController.UpdatePrivilegesConfig)
|
||||
|
||||
// dashboard
|
||||
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)
|
||||
}
|
||||
|
||||
func (pr *PluginAPIRouter) RegisterAuthConnectorRouter(r *gin.RouterGroup) {
|
||||
func (pr *PluginAPIRouter) RegisterAuthUserConnectorRouter(r *gin.RouterGroup) {
|
||||
connectorController := pr.connectorController
|
||||
r.GET("/connector/user/info", connectorController.ConnectorsUserInfo)
|
||||
r.DELETE("/connector/user/unbinding", connectorController.ExternalLoginUnbinding)
|
||||
|
||||
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{
|
||||
Rows: field.UIOptions.Rows,
|
||||
InputType: string(field.UIOptions.InputType),
|
||||
Variant: field.UIOptions.Variant,
|
||||
},
|
||||
}
|
||||
configField.UIOptions.Placeholder = field.UIOptions.Placeholder.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 {
|
||||
configField.Options = append(configField.Options, ConfigFieldOption{
|
||||
|
@ -87,6 +108,9 @@ type ConfigFieldUIOptions struct {
|
|||
Rows string `json:"rows,omitempty"`
|
||||
InputType string `json:"input_type,omitempty"`
|
||||
Label string `json:"label,omitempty"`
|
||||
Action *UIOptionAction `json:"action,omitempty"`
|
||||
Variant string `json:"variant,omitempty"`
|
||||
Text string `json:"text,omitempty"`
|
||||
}
|
||||
|
||||
type ConfigFieldOption struct {
|
||||
|
@ -94,6 +118,23 @@ type ConfigFieldOption struct {
|
|||
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 {
|
||||
PluginSlugName string `validate:"required,gt=1,lte=100" json:"plugin_slug_name"`
|
||||
ConfigFields map[string]any `json:"config_fields"`
|
||||
|
|
|
@ -7,11 +7,13 @@ type UserCenterAgentResp struct {
|
|||
|
||||
type AgentInfo struct {
|
||||
Name string `json:"name"`
|
||||
DisplayName string `json:"display_name"`
|
||||
Icon string `json:"icon"`
|
||||
Url string `json:"url"`
|
||||
LoginRedirectURL string `json:"login_redirect_url"`
|
||||
SignUpRedirectURL string `json:"sign_up_redirect_url"`
|
||||
ControlCenterItems []*ControlCenter `json:"control_center"`
|
||||
EnabledOriginalUserSystem bool `json:"enabled_original_user_system"`
|
||||
}
|
||||
|
||||
type ControlCenter struct {
|
||||
|
|
|
@ -297,6 +297,7 @@ type QuestionPageReq struct {
|
|||
OrderCond string `validate:"omitempty,oneof=newest active frequent score unanswered" form:"order"`
|
||||
Tag string `validate:"omitempty,gt=0,lte=100" form:"tag"`
|
||||
Username string `validate:"omitempty,gt=0,lte=100" form:"username"`
|
||||
InDays int `validate:"omitempty,min=1" form:"in_days"`
|
||||
|
||||
LoginUserID string `json:"-"`
|
||||
UserIDBeSearched string `json:"-"`
|
||||
|
|
|
@ -6,6 +6,7 @@ import (
|
|||
"net/mail"
|
||||
"net/url"
|
||||
|
||||
"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/translator"
|
||||
|
@ -44,7 +45,6 @@ func (r *SiteGeneralReq) FormatSiteUrl() {
|
|||
type SiteInterfaceReq struct {
|
||||
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"`
|
||||
DefaultAvatar string `validate:"required,oneof=system gravatar" form:"default_avatar" json:"default_avatar"`
|
||||
}
|
||||
|
||||
// SiteBrandingReq site branding request
|
||||
|
@ -92,10 +92,23 @@ type GetSiteLegalInfoResp struct {
|
|||
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
|
||||
type SiteLoginReq struct {
|
||||
AllowNewRegistrations bool `json:"allow_new_registrations"`
|
||||
AllowEmailRegistrations bool `json:"allow_email_registrations"`
|
||||
LoginRequired bool `json:"login_required"`
|
||||
AllowEmailDomains []string `json:"allow_email_domains"`
|
||||
}
|
||||
|
||||
// SiteCustomCssHTMLReq site custom css html
|
||||
|
@ -104,6 +117,7 @@ type SiteCustomCssHTMLReq struct {
|
|||
CustomCss string `validate:"omitempty,gt=0,lte=65536" json:"custom_css"`
|
||||
CustomHeader string `validate:"omitempty,gt=0,lte=65536" json:"custom_header"`
|
||||
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
|
||||
|
@ -127,6 +141,9 @@ type SiteLoginResp SiteLoginReq
|
|||
// SiteCustomCssHTMLResp site custom css html response
|
||||
type SiteCustomCssHTMLResp SiteCustomCssHTMLReq
|
||||
|
||||
// SiteUsersResp site users response
|
||||
type SiteUsersResp SiteUsersReq
|
||||
|
||||
// SiteThemeResp site theme response
|
||||
type SiteThemeResp struct {
|
||||
ThemeOptions []*ThemeOption `json:"theme_options"`
|
||||
|
@ -169,6 +186,7 @@ type SiteInfoResp struct {
|
|||
Theme *SiteThemeResp `json:"theme"`
|
||||
CustomCssHtml *SiteCustomCssHTMLResp `json:"custom_css_html"`
|
||||
SiteSeo *SiteSeoReq `json:"site_seo"`
|
||||
SiteUsers *SiteUsersResp `json:"site_users"`
|
||||
Version string `json:"version"`
|
||||
Revision string `json:"revision"`
|
||||
}
|
||||
|
@ -235,3 +253,85 @@ type GetManifestJsonResp struct {
|
|||
ThemeColor string `json:"theme_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 {
|
||||
BindingKey string `json:"binding_key"`
|
||||
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
|
||||
|
@ -49,6 +52,8 @@ type ExternalLoginUserInfoCache struct {
|
|||
Avatar string
|
||||
// optional. The original user information provided by the third-party login platform
|
||||
MetaInfo string
|
||||
// optional. The bio provided by the third-party login platform
|
||||
Bio string
|
||||
}
|
||||
|
||||
// ExternalLoginUnbindingReq external login unbinding user
|
||||
|
@ -63,6 +68,13 @@ type UserCenterUserSettingsResp struct {
|
|||
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 {
|
||||
Enabled bool `json:"enabled"`
|
||||
RedirectURL string `json:"redirect_url"`
|
||||
|
|
|
@ -4,14 +4,12 @@ import (
|
|||
"encoding/json"
|
||||
|
||||
"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/entity"
|
||||
"github.com/answerdev/answer/pkg/checker"
|
||||
"github.com/answerdev/answer/pkg/converter"
|
||||
"github.com/answerdev/answer/pkg/gravatar"
|
||||
"github.com/jinzhu/copier"
|
||||
"github.com/segmentfault/pacman/errors"
|
||||
)
|
||||
|
||||
// UserVerifyEmailReq user verify email request
|
||||
|
@ -300,7 +298,7 @@ func (u *UserModifyPasswordReq) Check() (errFields []*validator.FormErrorField,
|
|||
|
||||
type UpdateInfoRequest struct {
|
||||
// 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 string `validate:"omitempty,gt=3,lte=30" json:"username"`
|
||||
// avatar
|
||||
|
@ -329,16 +327,6 @@ func (a *AvatarInfo) ToJsonString() string {
|
|||
}
|
||||
|
||||
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)
|
||||
return nil, nil
|
||||
}
|
||||
|
|
|
@ -476,7 +476,7 @@ func (as *AnswerService) AdminSetAnswerStatus(ctx context.Context, req *schema.A
|
|||
msg.ReceiverUserID = answerInfo.UserID
|
||||
msg.TriggerUserID = answerInfo.UserID
|
||||
msg.ObjectType = constant.AnswerObjectType
|
||||
msg.NotificationAction = constant.YourAnswerWasDeleted
|
||||
msg.NotificationAction = constant.NotificationYourAnswerWasDeleted
|
||||
notice_queue.AddNotification(msg)
|
||||
|
||||
return nil
|
||||
|
@ -566,7 +566,7 @@ func (as *AnswerService) notificationUpdateAnswer(ctx context.Context, questionU
|
|||
ObjectID: answerID,
|
||||
}
|
||||
msg.ObjectType = constant.AnswerObjectType
|
||||
msg.NotificationAction = constant.UpdateAnswer
|
||||
msg.NotificationAction = constant.NotificationUpdateAnswer
|
||||
notice_queue.AddNotification(msg)
|
||||
}
|
||||
|
||||
|
@ -583,7 +583,7 @@ func (as *AnswerService) notificationAnswerTheQuestion(ctx context.Context,
|
|||
ObjectID: answerID,
|
||||
}
|
||||
msg.ObjectType = constant.AnswerObjectType
|
||||
msg.NotificationAction = constant.AnswerTheQuestion
|
||||
msg.NotificationAction = constant.NotificationAnswerTheQuestion
|
||||
notice_queue.AddNotification(msg)
|
||||
|
||||
userInfo, exist, err := as.userRepo.GetByUserID(ctx, questionUserID)
|
||||
|
|
|
@ -5,6 +5,7 @@ import (
|
|||
|
||||
"github.com/answerdev/answer/internal/entity"
|
||||
"github.com/answerdev/answer/pkg/token"
|
||||
"github.com/answerdev/answer/plugin"
|
||||
"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)
|
||||
if cacheInfo != nil {
|
||||
log.Debugf("user status updated: %+v", cacheInfo)
|
||||
userCacheInfo.UserStatus = cacheInfo.UserStatus
|
||||
userCacheInfo.EmailStatus = cacheInfo.EmailStatus
|
||||
userCacheInfo.RoleID = cacheInfo.RoleID
|
||||
|
@ -52,6 +52,14 @@ func (as *AuthService) GetUserCacheInfo(ctx context.Context, accessToken string)
|
|||
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
|
||||
}
|
||||
|
||||
|
|
|
@ -471,7 +471,7 @@ func (cs *CommentService) notificationQuestionComment(ctx context.Context, quest
|
|||
ObjectID: commentID,
|
||||
}
|
||||
msg.ObjectType = constant.CommentObjectType
|
||||
msg.NotificationAction = constant.CommentQuestion
|
||||
msg.NotificationAction = constant.NotificationCommentQuestion
|
||||
notice_queue.AddNotification(msg)
|
||||
|
||||
receiverUserInfo, exist, err := cs.userRepo.GetByUserID(ctx, questionUserID)
|
||||
|
@ -526,7 +526,7 @@ func (cs *CommentService) notificationAnswerComment(ctx context.Context,
|
|||
ObjectID: commentID,
|
||||
}
|
||||
msg.ObjectType = constant.CommentObjectType
|
||||
msg.NotificationAction = constant.CommentAnswer
|
||||
msg.NotificationAction = constant.NotificationCommentAnswer
|
||||
notice_queue.AddNotification(msg)
|
||||
|
||||
receiverUserInfo, exist, err := cs.userRepo.GetByUserID(ctx, answerUserID)
|
||||
|
@ -578,7 +578,7 @@ func (cs *CommentService) notificationCommentReply(ctx context.Context, replyUse
|
|||
ObjectID: commentID,
|
||||
}
|
||||
msg.ObjectType = constant.CommentObjectType
|
||||
msg.NotificationAction = constant.ReplyToYou
|
||||
msg.NotificationAction = constant.NotificationReplyToYou
|
||||
notice_queue.AddNotification(msg)
|
||||
}
|
||||
|
||||
|
@ -599,7 +599,7 @@ func (cs *CommentService) notificationMention(
|
|||
ObjectID: commentID,
|
||||
}
|
||||
msg.ObjectType = constant.CommentObjectType
|
||||
msg.NotificationAction = constant.MentionYou
|
||||
msg.NotificationAction = constant.NotificationMentionYou
|
||||
notice_queue.AddNotification(msg)
|
||||
alreadyNotifiedUserIDs = append(alreadyNotifiedUserIDs, userInfo.ID)
|
||||
}
|
||||
|
|
|
@ -7,14 +7,15 @@ import (
|
|||
|
||||
"github.com/answerdev/answer/internal/base/constant"
|
||||
"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/translator"
|
||||
"github.com/answerdev/answer/internal/entity"
|
||||
"github.com/answerdev/answer/internal/schema"
|
||||
notficationcommon "github.com/answerdev/answer/internal/service/notification_common"
|
||||
"github.com/answerdev/answer/internal/service/revision_common"
|
||||
"github.com/answerdev/answer/pkg/uid"
|
||||
"github.com/jinzhu/copier"
|
||||
"github.com/segmentfault/pacman/i18n"
|
||||
"github.com/segmentfault/pacman/log"
|
||||
)
|
||||
|
||||
|
@ -127,35 +128,47 @@ func (ns *NotificationService) GetNotificationPage(ctx context.Context, searchCo
|
|||
if err != nil {
|
||||
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 {
|
||||
item := &schema.NotificationContent{}
|
||||
err := json.Unmarshal([]byte(notificationInfo.Content), item)
|
||||
if err != nil {
|
||||
if err := json.Unmarshal([]byte(notificationInfo.Content), item); err != nil {
|
||||
log.Error("NotificationContent Unmarshal Error", err.Error())
|
||||
continue
|
||||
}
|
||||
lang, _ := ctx.Value(constant.AcceptLanguageFlag).(i18n.Language)
|
||||
item.NotificationAction = translator.Tr(lang, item.NotificationAction)
|
||||
item.ID = notificationInfo.ID
|
||||
item.UpdateTime = notificationInfo.UpdatedAt.Unix()
|
||||
if notificationInfo.IsRead == schema.NotificationRead {
|
||||
item.IsRead = true
|
||||
// If notification is downvote, the user info is not needed.
|
||||
if item.NotificationAction == constant.NotificationDownVotedTheQuestion ||
|
||||
item.NotificationAction == constant.NotificationDownVotedTheAnswer {
|
||||
item.UserInfo = nil
|
||||
}
|
||||
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 {
|
||||
item.ObjectInfo.ObjectID = uid.EnShortID(item.ObjectInfo.ObjectMap["answer"])
|
||||
}
|
||||
item.ObjectInfo.ObjectMap["answer"] = uid.EnShortID(item.ObjectInfo.ObjectMap["answer"])
|
||||
}
|
||||
questionID, ok := item.ObjectInfo.ObjectMap["question"]
|
||||
if ok {
|
||||
if questionID, ok := item.ObjectInfo.ObjectMap["question"]; ok {
|
||||
if item.ObjectInfo.ObjectID == questionID {
|
||||
item.ObjectInfo.ObjectID = uid.EnShortID(item.ObjectInfo.ObjectMap["question"])
|
||||
}
|
||||
item.ObjectInfo.ObjectMap["question"] = uid.EnShortID(item.ObjectInfo.ObjectMap["question"])
|
||||
}
|
||||
|
||||
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 {
|
||||
return
|
||||
}
|
||||
if msg.NotificationAction != constant.UpdateQuestion &&
|
||||
msg.NotificationAction != constant.AnswerTheQuestion &&
|
||||
msg.NotificationAction != constant.UpdateAnswer &&
|
||||
msg.NotificationAction != constant.AcceptAnswer {
|
||||
if msg.NotificationAction != constant.NotificationUpdateQuestion &&
|
||||
msg.NotificationAction != constant.NotificationAnswerTheQuestion &&
|
||||
msg.NotificationAction != constant.NotificationUpdateAnswer &&
|
||||
msg.NotificationAction != constant.NotificationAcceptAnswer {
|
||||
return
|
||||
}
|
||||
condObjectID := msg.ObjectID
|
||||
|
|
|
@ -10,10 +10,10 @@ const (
|
|||
QuestionReopen = "question.reopen"
|
||||
QuestionVoteUp = "question.vote_up"
|
||||
QuestionVoteDown = "question.vote_down"
|
||||
QuestionPin = "question.pin" //Top the question
|
||||
QuestionUnPin = "question.unpin" //untop the question
|
||||
QuestionHide = "question.hide" //hide the question
|
||||
QuestionShow = "question.show" //show the question
|
||||
QuestionPin = "question.pin"
|
||||
QuestionUnPin = "question.unpin"
|
||||
QuestionHide = "question.hide"
|
||||
QuestionShow = "question.show"
|
||||
AnswerAdd = "answer.add"
|
||||
AnswerEdit = "answer.edit"
|
||||
AnswerEditWithoutReview = "answer.edit_without_review"
|
||||
|
|
|
@ -32,7 +32,7 @@ type QuestionRepo interface {
|
|||
UpdateQuestion(ctx context.Context, question *entity.Question, Cols []string) (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)
|
||||
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)
|
||||
UpdateQuestionStatus(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,
|
||||
req.UserIDBeSearched, req.TagID, req.OrderCond)
|
||||
req.UserIDBeSearched, req.TagID, req.OrderCond, req.InDays)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
@ -1064,7 +1064,7 @@ func (qs *QuestionService) AdminSetQuestionStatus(ctx context.Context, questionI
|
|||
msg.ReceiverUserID = questionInfo.UserID
|
||||
msg.TriggerUserID = questionInfo.UserID
|
||||
msg.ObjectType = constant.QuestionObjectType
|
||||
msg.NotificationAction = constant.YourQuestionWasDeleted
|
||||
msg.NotificationAction = constant.NotificationYourQuestionWasDeleted
|
||||
notice_queue.AddNotification(msg)
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -66,7 +66,7 @@ func (rh *ReportHandle) HandleObject(ctx context.Context, reported *entity.Repor
|
|||
switch req.FlaggedType {
|
||||
case reasonDelete:
|
||||
err = rh.commentRepo.RemoveComment(ctx, objectID)
|
||||
rh.sendNotification(ctx, reportedUserID, objectID, constant.YourCommentWasDeleted)
|
||||
rh.sendNotification(ctx, reportedUserID, objectID, constant.NotificationYourCommentWasDeleted)
|
||||
}
|
||||
}
|
||||
return
|
||||
|
|
|
@ -209,7 +209,7 @@ func (rs *RevisionService) revisionAuditAnswer(ctx context.Context, revisionitem
|
|||
ObjectID: answerinfo.ID,
|
||||
}
|
||||
msg.ObjectType = constant.AnswerObjectType
|
||||
msg.NotificationAction = constant.UpdateAnswer
|
||||
msg.NotificationAction = constant.NotificationUpdateAnswer
|
||||
notice_queue.AddNotification(msg)
|
||||
|
||||
activity_queue.AddActivity(&schema.ActivityMsg{
|
||||
|
|
|
@ -3,12 +3,15 @@ package siteinfo
|
|||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"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/translator"
|
||||
"github.com/answerdev/answer/internal/entity"
|
||||
"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/siteinfo_common"
|
||||
tagcommon "github.com/answerdev/answer/internal/service/tag_common"
|
||||
|
@ -23,19 +26,23 @@ type SiteInfoService struct {
|
|||
siteInfoCommonService *siteinfo_common.SiteInfoCommonService
|
||||
emailService *export.EmailService
|
||||
tagCommonService *tagcommon.TagCommonService
|
||||
configRepo config.ConfigRepo
|
||||
}
|
||||
|
||||
func NewSiteInfoService(
|
||||
siteInfoRepo siteinfo_common.SiteInfoRepo,
|
||||
siteInfoCommonService *siteinfo_common.SiteInfoCommonService,
|
||||
emailService *export.EmailService,
|
||||
tagCommonService *tagcommon.TagCommonService) *SiteInfoService {
|
||||
|
||||
resp, err := siteInfoCommonService.GetSiteInterface(context.Background())
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
} else {
|
||||
constant.DefaultAvatar = resp.DefaultAvatar
|
||||
tagCommonService *tagcommon.TagCommonService,
|
||||
configRepo config.ConfigRepo,
|
||||
) *SiteInfoService {
|
||||
usersSiteInfo, _ := siteInfoCommonService.GetSiteUsers(context.Background())
|
||||
if usersSiteInfo != nil {
|
||||
constant.DefaultAvatar = usersSiteInfo.DefaultAvatar
|
||||
}
|
||||
generalSiteInfo, _ := siteInfoCommonService.GetSiteGeneral(context.Background())
|
||||
if generalSiteInfo != nil {
|
||||
constant.DefaultSiteURL = generalSiteInfo.SiteUrl
|
||||
}
|
||||
|
||||
return &SiteInfoService{
|
||||
|
@ -43,6 +50,7 @@ func NewSiteInfoService(
|
|||
siteInfoCommonService: siteInfoCommonService,
|
||||
emailService: emailService,
|
||||
tagCommonService: tagCommonService,
|
||||
configRepo: configRepo,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -61,6 +69,11 @@ func (s *SiteInfoService) GetSiteBranding(ctx context.Context) (resp *schema.Sit
|
|||
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
|
||||
func (s *SiteInfoService) GetSiteWrite(ctx context.Context) (resp *schema.SiteWriteResp, err error) {
|
||||
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) {
|
||||
req.FormatSiteUrl()
|
||||
var (
|
||||
siteType = "general"
|
||||
content []byte
|
||||
)
|
||||
content, _ = json.Marshal(req)
|
||||
|
||||
data := entity.SiteInfo{
|
||||
Type: siteType,
|
||||
content, _ := json.Marshal(req)
|
||||
data := &entity.SiteInfo{
|
||||
Type: constant.SiteTypeGeneral,
|
||||
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
|
||||
}
|
||||
|
||||
func (s *SiteInfoService) SaveSiteInterface(ctx context.Context, req schema.SiteInterfaceReq) (err error) {
|
||||
var (
|
||||
siteType = "interface"
|
||||
content []byte
|
||||
)
|
||||
|
||||
// check language
|
||||
if !translator.CheckLanguageIsValid(req.Language) {
|
||||
err = errors.BadRequest(reason.LangNotFound)
|
||||
return
|
||||
}
|
||||
|
||||
content, _ = json.Marshal(req)
|
||||
|
||||
content, _ := json.Marshal(req)
|
||||
data := entity.SiteInfo{
|
||||
Type: siteType,
|
||||
Type: constant.SiteTypeInterface,
|
||||
Content: string(content),
|
||||
}
|
||||
|
||||
err = s.siteInfoRepo.SaveByType(ctx, siteType, &data)
|
||||
if err == nil {
|
||||
constant.DefaultAvatar = req.DefaultAvatar
|
||||
}
|
||||
return
|
||||
return s.siteInfoRepo.SaveByType(ctx, constant.SiteTypeInterface, &data)
|
||||
}
|
||||
|
||||
// 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)
|
||||
}
|
||||
|
||||
// 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
|
||||
func (s *SiteInfoService) GetSMTPConfig(ctx context.Context) (
|
||||
resp *schema.GetSMTPConfigResp, err error,
|
||||
|
@ -253,8 +268,11 @@ func (s *SiteInfoService) UpdateSMTPConfig(ctx context.Context, req *schema.Upda
|
|||
return
|
||||
}
|
||||
|
||||
func (s *SiteInfoService) GetSeo(ctx context.Context) (resp *schema.SiteSeoResp, err error) {
|
||||
resp = &schema.SiteSeoResp{}
|
||||
func (s *SiteInfoService) GetSeo(ctx context.Context) (resp *schema.SiteSeoReq, err error) {
|
||||
resp = &schema.SiteSeoReq{}
|
||||
if err = s.siteInfoCommonService.GetSiteInfoByType(ctx, constant.SiteTypeSeo, resp); err != nil {
|
||||
return resp, err
|
||||
}
|
||||
loginConfig, err := s.GetSiteLogin(ctx)
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
|
@ -265,17 +283,6 @@ func (s *SiteInfoService) GetSeo(ctx context.Context) (resp *schema.SiteSeoResp,
|
|||
resp.Robots = "User-agent: *\nDisallow: /"
|
||||
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
|
||||
}
|
||||
|
||||
|
@ -302,3 +309,71 @@ func (s *SiteInfoService) SaveSeo(ctx context.Context, req schema.SiteSeoReq) (e
|
|||
}
|
||||
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
|
||||
func (s *SiteInfoCommonService) GetSiteGeneral(ctx context.Context) (resp *schema.SiteGeneralResp, err error) {
|
||||
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 resp, nil
|
||||
|
@ -52,7 +52,7 @@ func (s *SiteInfoCommonService) GetSiteGeneral(ctx context.Context) (resp *schem
|
|||
// GetSiteInterface get site info interface
|
||||
func (s *SiteInfoCommonService) GetSiteInterface(ctx context.Context) (resp *schema.SiteInterfaceResp, err error) {
|
||||
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 resp, nil
|
||||
|
@ -61,7 +61,16 @@ func (s *SiteInfoCommonService) GetSiteInterface(ctx context.Context) (resp *sch
|
|||
// GetSiteBranding get site info branding
|
||||
func (s *SiteInfoCommonService) GetSiteBranding(ctx context.Context) (resp *schema.SiteBrandingResp, err error) {
|
||||
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 resp, nil
|
||||
|
@ -70,7 +79,7 @@ func (s *SiteInfoCommonService) GetSiteBranding(ctx context.Context) (resp *sche
|
|||
// GetSiteWrite get site info write
|
||||
func (s *SiteInfoCommonService) GetSiteWrite(ctx context.Context) (resp *schema.SiteWriteResp, err error) {
|
||||
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 resp, nil
|
||||
|
@ -79,7 +88,7 @@ func (s *SiteInfoCommonService) GetSiteWrite(ctx context.Context) (resp *schema.
|
|||
// GetSiteLegal get site info write
|
||||
func (s *SiteInfoCommonService) GetSiteLegal(ctx context.Context) (resp *schema.SiteLegalResp, err error) {
|
||||
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 resp, nil
|
||||
|
@ -88,7 +97,7 @@ func (s *SiteInfoCommonService) GetSiteLegal(ctx context.Context) (resp *schema.
|
|||
// GetSiteLogin get site login config
|
||||
func (s *SiteInfoCommonService) GetSiteLogin(ctx context.Context) (resp *schema.SiteLoginResp, err error) {
|
||||
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 resp, nil
|
||||
|
@ -97,7 +106,7 @@ func (s *SiteInfoCommonService) GetSiteLogin(ctx context.Context) (resp *schema.
|
|||
// GetSiteCustomCssHTML get site custom css html config
|
||||
func (s *SiteInfoCommonService) GetSiteCustomCssHTML(ctx context.Context) (resp *schema.SiteCustomCssHTMLResp, err error) {
|
||||
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 resp, nil
|
||||
|
@ -108,7 +117,7 @@ func (s *SiteInfoCommonService) GetSiteTheme(ctx context.Context) (resp *schema.
|
|||
resp = &schema.SiteThemeResp{
|
||||
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
|
||||
}
|
||||
resp.TrTheme(ctx)
|
||||
|
@ -118,13 +127,13 @@ func (s *SiteInfoCommonService) GetSiteTheme(ctx context.Context) (resp *schema.
|
|||
// GetSiteSeo get site seo
|
||||
func (s *SiteInfoCommonService) GetSiteSeo(ctx context.Context) (resp *schema.SiteSeoReq, err error) {
|
||||
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 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)
|
||||
if err != nil {
|
||||
return err
|
||||
|
|
|
@ -150,7 +150,7 @@ func (us *UserCommon) MakeUsername(ctx context.Context, displayName string) (use
|
|||
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) {
|
||||
roleID, err := us.userRoleService.GetUserRole(ctx, userID)
|
||||
if err != nil {
|
||||
|
@ -162,6 +162,7 @@ func (us *UserCommon) CacheLoginUserInfo(ctx context.Context, userID string, use
|
|||
EmailStatus: emailStatus,
|
||||
UserStatus: userStatus,
|
||||
RoleID: roleID,
|
||||
ExternalID: externalID,
|
||||
}
|
||||
|
||||
accessToken, err = us.authService.SetUserCacheInfo(ctx, userCacheInfo)
|
||||
|
|
|
@ -5,10 +5,16 @@ import (
|
|||
"encoding/json"
|
||||
"time"
|
||||
|
||||
"github.com/answerdev/answer/internal/base/handler"
|
||||
"github.com/answerdev/answer/internal/base/reason"
|
||||
"github.com/answerdev/answer/internal/base/translator"
|
||||
"github.com/answerdev/answer/internal/entity"
|
||||
"github.com/answerdev/answer/internal/schema"
|
||||
"github.com/answerdev/answer/internal/service/activity"
|
||||
"github.com/answerdev/answer/internal/service/siteinfo_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/plugin"
|
||||
"github.com/segmentfault/pacman/log"
|
||||
|
@ -20,6 +26,7 @@ type UserCenterLoginService struct {
|
|||
userExternalLoginRepo UserExternalLoginRepo
|
||||
userCommonService *usercommon.UserCommon
|
||||
userActivity activity.UserActiveActivityRepo
|
||||
siteInfoCommonService *siteinfo_common.SiteInfoCommonService
|
||||
}
|
||||
|
||||
// NewUserCenterLoginService new user external login service
|
||||
|
@ -28,21 +35,38 @@ func NewUserCenterLoginService(
|
|||
userCommonService *usercommon.UserCommon,
|
||||
userExternalLoginRepo UserExternalLoginRepo,
|
||||
userActivity activity.UserActiveActivityRepo,
|
||||
siteInfoCommonService *siteinfo_common.SiteInfoCommonService,
|
||||
) *UserCenterLoginService {
|
||||
return &UserCenterLoginService{
|
||||
userRepo: userRepo,
|
||||
userCommonService: userCommonService,
|
||||
userExternalLoginRepo: userExternalLoginRepo,
|
||||
userActivity: userActivity,
|
||||
siteInfoCommonService: siteInfoCommonService,
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
|
||||
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,
|
||||
provider, basicUserInfo.ExternalID)
|
||||
userCenter.Info().SlugName, basicUserInfo.ExternalID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -53,16 +77,28 @@ func (us *UserCenterLoginService) ExternalLogin(
|
|||
return nil, err
|
||||
}
|
||||
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 {
|
||||
log.Errorf("update user last login date failed: %v", err)
|
||||
}
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
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 {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -70,7 +106,7 @@ func (us *UserCenterLoginService) ExternalLogin(
|
|||
us.activeUser(ctx, oldUserInfo)
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
|
@ -98,6 +134,8 @@ func (us *UserCenterLoginService) registerNewUser(ctx context.Context, provider
|
|||
userInfo.MailStatus = entity.EmailStatusAvailable
|
||||
userInfo.Status = entity.UserStatusAvailable
|
||||
userInfo.LastLoginDate = time.Now()
|
||||
userInfo.Bio = basicUserInfo.Bio
|
||||
userInfo.BioHTML = converter.Markdown2HTML(basicUserInfo.Bio)
|
||||
err = us.userRepo.AddUser(ctx, userInfo)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -166,6 +204,31 @@ func (us *UserCenterLoginService) UserCenterUserSettings(ctx context.Context, us
|
|||
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) (
|
||||
resp *schema.UserCenterPersonalBranding, err error) {
|
||||
resp = &schema.UserCenterPersonalBranding{
|
||||
|
|
|
@ -15,6 +15,7 @@ import (
|
|||
usercommon "github.com/answerdev/answer/internal/service/user_common"
|
||||
"github.com/answerdev/answer/pkg/random"
|
||||
"github.com/answerdev/answer/pkg/token"
|
||||
"github.com/answerdev/answer/plugin"
|
||||
"github.com/google/uuid"
|
||||
"github.com/segmentfault/pacman/errors"
|
||||
"github.com/segmentfault/pacman/log"
|
||||
|
@ -83,7 +84,7 @@ func (us *UserExternalLoginService) ExternalLogin(
|
|||
log.Error(err)
|
||||
}
|
||||
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
|
||||
}
|
||||
}
|
||||
|
@ -122,7 +123,7 @@ func (us *UserExternalLoginService) ExternalLogin(
|
|||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
|
@ -150,6 +151,8 @@ func (us *UserExternalLoginService) registerNewUser(ctx context.Context,
|
|||
userInfo.MailStatus = entity.EmailStatusToBeVerified
|
||||
userInfo.Status = entity.UserStatusAvailable
|
||||
userInfo.LastLoginDate = time.Now()
|
||||
userInfo.Bio = externalUserInfo.Bio
|
||||
userInfo.BioHTML = externalUserInfo.Bio
|
||||
err = us.userRepo.AddUser(ctx, userInfo)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -249,7 +252,7 @@ func (us *UserExternalLoginService) ExternalLoginBindingUserSendEmail(
|
|||
return nil, err
|
||||
}
|
||||
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 {
|
||||
log.Error(err)
|
||||
}
|
||||
|
@ -316,3 +319,33 @@ func (us *UserExternalLoginService) ExternalLoginUnbinding(
|
|||
|
||||
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 {
|
||||
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)
|
||||
if err != nil {
|
||||
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) {
|
||||
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)
|
||||
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)
|
||||
|
@ -137,6 +147,7 @@ func (us *UserService) EmailLogin(ctx context.Context, req *schema.UserEmailLogi
|
|||
EmailStatus: userInfo.MailStatus,
|
||||
UserStatus: userInfo.Status,
|
||||
RoleID: roleID,
|
||||
ExternalID: externalID,
|
||||
}
|
||||
resp.AccessToken, err = us.authService.SetUserCacheInfo(ctx, userCacheInfo)
|
||||
if err != nil {
|
||||
|
@ -252,7 +263,27 @@ func (us *UserService) UserModifyPassword(ctx context.Context, req *schema.UserM
|
|||
// UpdateInfo update user info
|
||||
func (us *UserService) UpdateInfo(ctx context.Context, req *schema.UpdateInfoRequest) (
|
||||
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)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -264,29 +295,55 @@ func (us *UserService) UpdateInfo(ctx context.Context, req *schema.UpdateInfoReq
|
|||
})
|
||||
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 {
|
||||
return nil, errors.BadRequest(reason.UserSetAvatar).WithError(err).WithStack()
|
||||
return nil, err
|
||||
}
|
||||
userInfo := entity.User{}
|
||||
if !exist {
|
||||
return nil, errors.BadRequest(reason.UserNotFound)
|
||||
}
|
||||
|
||||
cond := us.formatUserInfoForUpdateInfo(oldUserInfo, req, siteUsers)
|
||||
err = us.userRepo.UpdateInfo(ctx, cond)
|
||||
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
|
||||
userInfo.Avatar = string(avatar)
|
||||
|
||||
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
|
||||
userInfo.Location = req.Location
|
||||
}
|
||||
if siteUsersConf.AllowUpdateWebsite {
|
||||
userInfo.Website = req.Website
|
||||
userInfo.Username = req.Username
|
||||
err = us.userRepo.UpdateInfo(ctx, &userInfo)
|
||||
return nil, err
|
||||
}
|
||||
if siteUsersConf.AllowUpdateLocation {
|
||||
userInfo.Location = req.Location
|
||||
}
|
||||
return userInfo
|
||||
}
|
||||
|
||||
func (us *UserService) UserEmailHas(ctx context.Context, email string) (bool, error) {
|
||||
|
@ -466,7 +523,7 @@ func (us *UserService) UserVerifyEmail(ctx context.Context, req *schema.UserVeri
|
|||
}
|
||||
|
||||
accessToken, userCacheInfo, err := us.userCommonService.CacheLoginUserInfo(
|
||||
ctx, userInfo.ID, userInfo.MailStatus, userInfo.Status)
|
||||
ctx, userInfo.ID, userInfo.MailStatus, userInfo.Status, "")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -63,12 +63,12 @@ func NewVoteService(
|
|||
}
|
||||
|
||||
// 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{}
|
||||
|
||||
var objectUserID string
|
||||
|
||||
objectUserID, err = as.GetObjectUserID(ctx, dto.ObjectID)
|
||||
objectUserID, err = vs.GetObjectUserID(ctx, dto.ObjectID)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
@ -80,19 +80,19 @@ func (as *VoteService) VoteUp(ctx context.Context, dto *schema.VoteDTO) (voteRes
|
|||
}
|
||||
|
||||
if dto.IsCancel {
|
||||
return as.voteRepo.VoteUpCancel(ctx, dto.ObjectID, dto.UserID, objectUserID)
|
||||
return vs.voteRepo.VoteUpCancel(ctx, dto.ObjectID, dto.UserID, objectUserID)
|
||||
} else {
|
||||
return as.voteRepo.VoteUp(ctx, dto.ObjectID, dto.UserID, objectUserID)
|
||||
return vs.voteRepo.VoteUp(ctx, dto.ObjectID, dto.UserID, objectUserID)
|
||||
}
|
||||
}
|
||||
|
||||
// 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{}
|
||||
|
||||
var objectUserID string
|
||||
|
||||
objectUserID, err = as.GetObjectUserID(ctx, dto.ObjectID)
|
||||
objectUserID, err = vs.GetObjectUserID(ctx, dto.ObjectID)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
@ -104,9 +104,9 @@ func (as *VoteService) VoteDown(ctx context.Context, dto *schema.VoteDTO) (voteR
|
|||
}
|
||||
|
||||
if dto.IsCancel {
|
||||
return as.voteRepo.VoteDownCancel(ctx, dto.ObjectID, dto.UserID, objectUserID)
|
||||
return vs.voteRepo.VoteDownCancel(ctx, dto.ObjectID, dto.UserID, objectUserID)
|
||||
} 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"
|
||||
ConfigTypeTimezone ConfigType = "timezone"
|
||||
ConfigTypeSwitch ConfigType = "switch"
|
||||
ConfigTypeButton ConfigType = "button"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -47,6 +48,9 @@ type ConfigFieldUIOptions struct {
|
|||
Rows string `json:"rows,omitempty"`
|
||||
InputType InputType `json:"input_type,omitempty"`
|
||||
Label Translator `json:"label,omitempty"`
|
||||
Action *UIOptionAction `json:"action,omitempty"`
|
||||
Variant string `json:"variant,omitempty"`
|
||||
Text Translator `json:"text,omitempty"`
|
||||
}
|
||||
|
||||
type ConfigFieldOption struct {
|
||||
|
@ -54,6 +58,31 @@ type ConfigFieldOption struct {
|
|||
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 {
|
||||
Base
|
||||
|
||||
|
|
|
@ -52,6 +52,10 @@ func Register(p Base) {
|
|||
if _, ok := p.(UserCenter); ok {
|
||||
registerUserCenter(p.(UserCenter))
|
||||
}
|
||||
|
||||
if _, ok := p.(Agent); ok {
|
||||
registerAgent(p.(Agent))
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
type Translator struct {
|
||||
fn TranslateFn
|
||||
Fn TranslateFn
|
||||
}
|
||||
|
||||
// MakeTranslator generates a translator from the key
|
||||
|
@ -140,13 +144,13 @@ func MakeTranslator(key string) Translator {
|
|||
t := func(ctx *GinContext) string {
|
||||
return Translate(ctx, key)
|
||||
}
|
||||
return Translator{fn: t}
|
||||
return Translator{Fn: t}
|
||||
}
|
||||
|
||||
// Translate translates the key to the current language of the context
|
||||
func (t Translator) Translate(ctx *GinContext) string {
|
||||
if &t == nil || t.fn == nil {
|
||||
if &t == nil || t.Fn == nil {
|
||||
return ""
|
||||
}
|
||||
return t.fn(ctx)
|
||||
return t.Fn(ctx)
|
||||
}
|
||||
|
|
|
@ -12,21 +12,29 @@ type UserCenter interface {
|
|||
SignUpCallback(ctx *GinContext) (userInfo *UserCenterBasicUserInfo, err error)
|
||||
// UserInfo returns the user information
|
||||
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(externalIDs []string) (userInfo []*UserCenterBasicUserInfo, err error)
|
||||
// UserSettings returns the user settings
|
||||
UserSettings(externalID string) (userSettings *SettingInfo, err error)
|
||||
// PersonalBranding returns the personal branding information
|
||||
PersonalBranding(externalID string) (branding []*PersonalBranding)
|
||||
// AfterLogin is called after the user logs in
|
||||
AfterLogin(externalID, accessToken string)
|
||||
}
|
||||
|
||||
type UserCenterDesc struct {
|
||||
Name string `json:"name"`
|
||||
DisplayName Translator `json:"display_name"`
|
||||
Icon string `json:"icon"`
|
||||
Url string `json:"url"`
|
||||
LoginRedirectURL string `json:"login_redirect_url"`
|
||||
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
|
||||
|
@ -45,6 +53,7 @@ type UserCenterBasicUserInfo struct {
|
|||
Rank int `json:"rank"`
|
||||
Avatar string `json:"avatar"`
|
||||
Mobile string `json:"mobile"`
|
||||
Bio string `json:"bio"`
|
||||
Status UserStatus `json:"status"`
|
||||
}
|
||||
|
||||
|
|
|
@ -1,26 +1,21 @@
|
|||
#!/bin/bash
|
||||
set -e
|
||||
echo "begin build plugin"
|
||||
plugin_file=./script/plugin_list
|
||||
if [ ! -f "$plugin_file" ]; then
|
||||
echo "plugin_list is not exist"
|
||||
exit 0
|
||||
fi
|
||||
num=0
|
||||
for line in `cat $plugin_file`
|
||||
do
|
||||
account=$line
|
||||
accounts[$num]=$account
|
||||
((num++))
|
||||
done
|
||||
if [ $num -eq 0 ]; then
|
||||
echo "plugin_list is null"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo "plugin_list exist"
|
||||
cmd="./answer build "
|
||||
for repo in ${accounts[@]}
|
||||
for repo in `cat $plugin_file`
|
||||
do
|
||||
echo ${repo}
|
||||
cmd=$cmd" --with "${repo}
|
||||
echo ${repo}
|
||||
cmd=$cmd" --with "${repo}
|
||||
done
|
||||
|
||||
echo "cmd is "$cmd
|
||||
$cmd
|
||||
if [ ! -f "./new_answer" ]; then
|
||||
echo "new_answer is not exist build failed"
|
||||
|
|
Loading…
Reference in New Issue