mirror of https://gitee.com/answerdev/answer.git
Merge branch 'feat/1.1.2/notification' into test
This commit is contained in:
commit
7a036f2118
|
@ -26,7 +26,7 @@ import (
|
|||
"github.com/answerdev/answer/internal/repo/config"
|
||||
"github.com/answerdev/answer/internal/repo/export"
|
||||
"github.com/answerdev/answer/internal/repo/meta"
|
||||
"github.com/answerdev/answer/internal/repo/notification"
|
||||
notification2 "github.com/answerdev/answer/internal/repo/notification"
|
||||
"github.com/answerdev/answer/internal/repo/plugin_config"
|
||||
"github.com/answerdev/answer/internal/repo/question"
|
||||
"github.com/answerdev/answer/internal/repo/rank"
|
||||
|
@ -41,6 +41,7 @@ import (
|
|||
"github.com/answerdev/answer/internal/repo/unique"
|
||||
"github.com/answerdev/answer/internal/repo/user"
|
||||
"github.com/answerdev/answer/internal/repo/user_external_login"
|
||||
"github.com/answerdev/answer/internal/repo/user_notification_config"
|
||||
"github.com/answerdev/answer/internal/router"
|
||||
"github.com/answerdev/answer/internal/service"
|
||||
"github.com/answerdev/answer/internal/service/action"
|
||||
|
@ -58,7 +59,7 @@ import (
|
|||
"github.com/answerdev/answer/internal/service/follow"
|
||||
meta2 "github.com/answerdev/answer/internal/service/meta"
|
||||
"github.com/answerdev/answer/internal/service/notice_queue"
|
||||
notification2 "github.com/answerdev/answer/internal/service/notification"
|
||||
"github.com/answerdev/answer/internal/service/notification"
|
||||
"github.com/answerdev/answer/internal/service/notification_common"
|
||||
"github.com/answerdev/answer/internal/service/object_info"
|
||||
"github.com/answerdev/answer/internal/service/plugin_common"
|
||||
|
@ -80,6 +81,7 @@ import (
|
|||
"github.com/answerdev/answer/internal/service/user_admin"
|
||||
"github.com/answerdev/answer/internal/service/user_common"
|
||||
user_external_login2 "github.com/answerdev/answer/internal/service/user_external_login"
|
||||
user_notification_config2 "github.com/answerdev/answer/internal/service/user_notification_config"
|
||||
"github.com/segmentfault/pacman"
|
||||
"github.com/segmentfault/pacman/log"
|
||||
)
|
||||
|
@ -127,10 +129,12 @@ func initApplication(debug bool, serverConf *conf.Server, dbConf *data.Database,
|
|||
userCommon := usercommon.NewUserCommon(userRepo, userRoleRelService, authService, siteInfoCommonService)
|
||||
userExternalLoginRepo := user_external_login.NewUserExternalLoginRepo(dataData)
|
||||
userExternalLoginService := user_external_login2.NewUserExternalLoginService(userRepo, userCommon, userExternalLoginRepo, emailService, siteInfoCommonService, userActiveActivityRepo)
|
||||
userService := service.NewUserService(userRepo, userActiveActivityRepo, activityRepo, emailService, authService, siteInfoCommonService, userRoleRelService, userCommon, userExternalLoginService)
|
||||
userNotificationConfigRepo := user_notification_config.NewUserNotificationConfigRepo(dataData)
|
||||
userService := service.NewUserService(userRepo, userActiveActivityRepo, activityRepo, emailService, authService, siteInfoCommonService, userRoleRelService, userCommon, userExternalLoginService, userNotificationConfigRepo)
|
||||
captchaRepo := captcha.NewCaptchaRepo(dataData)
|
||||
captchaService := action.NewCaptchaService(captchaRepo)
|
||||
userController := controller.NewUserController(authService, userService, captchaService, emailService, siteInfoCommonService)
|
||||
userNotificationConfigService := user_notification_config2.NewUserNotificationConfigService(userRepo, userNotificationConfigRepo)
|
||||
userController := controller.NewUserController(authService, userService, captchaService, emailService, siteInfoCommonService, userNotificationConfigService)
|
||||
commentRepo := comment.NewCommentRepo(dataData, uniqueIDRepo)
|
||||
commentCommonRepo := comment.NewCommentCommonRepo(dataData, uniqueIDRepo)
|
||||
answerRepo := answer.NewAnswerRepo(dataData, uniqueIDRepo, userRankRepo, activityRepo)
|
||||
|
@ -145,7 +149,8 @@ func initApplication(debug bool, serverConf *conf.Server, dbConf *data.Database,
|
|||
objService := object_info.NewObjService(answerRepo, questionRepo, commentCommonRepo, tagCommonRepo, tagCommonService)
|
||||
voteRepo := activity_common.NewVoteRepo(dataData, activityRepo)
|
||||
notificationQueueService := notice_queue.NewNotificationQueueService()
|
||||
commentService := comment2.NewCommentService(commentRepo, commentCommonRepo, userCommon, objService, voteRepo, emailService, userRepo, notificationQueueService, activityQueueService)
|
||||
externalNotificationQueueService := notice_queue.NewNewQuestionNotificationQueueService()
|
||||
commentService := comment2.NewCommentService(commentRepo, commentCommonRepo, userCommon, objService, voteRepo, emailService, userRepo, notificationQueueService, externalNotificationQueueService, activityQueueService)
|
||||
rolePowerRelRepo := role.NewRolePowerRelRepo(dataData)
|
||||
rolePowerRelService := role2.NewRolePowerRelService(rolePowerRelRepo, userRoleRelService)
|
||||
rankService := rank2.NewRankService(userCommon, userRankRepo, objService, userRoleRelService, rolePowerRelService, configService)
|
||||
|
@ -173,8 +178,9 @@ func initApplication(debug bool, serverConf *conf.Server, dbConf *data.Database,
|
|||
collectionController := controller.NewCollectionController(collectionService)
|
||||
answerActivityRepo := activity.NewAnswerActivityRepo(dataData, activityRepo, userRankRepo, notificationQueueService)
|
||||
answerActivityService := activity2.NewAnswerActivityService(answerActivityRepo, configService)
|
||||
questionService := service.NewQuestionService(questionRepo, tagCommonService, questionCommon, userCommon, userRepo, revisionService, metaService, collectionCommon, answerActivityService, emailService, notificationQueueService, activityQueueService, siteInfoCommonService)
|
||||
answerService := service.NewAnswerService(answerRepo, questionRepo, questionCommon, userCommon, collectionCommon, userRepo, revisionService, answerActivityService, answerCommon, voteRepo, emailService, userRoleRelService, notificationQueueService, activityQueueService)
|
||||
externalNotificationService := notification.NewExternalNotificationService(userNotificationConfigRepo, followRepo, emailService, userRepo, externalNotificationQueueService)
|
||||
questionService := service.NewQuestionService(questionRepo, tagCommonService, questionCommon, userCommon, userRepo, revisionService, metaService, collectionCommon, answerActivityService, emailService, notificationQueueService, externalNotificationQueueService, activityQueueService, siteInfoCommonService, externalNotificationService)
|
||||
answerService := service.NewAnswerService(answerRepo, questionRepo, questionCommon, userCommon, collectionCommon, userRepo, revisionService, answerActivityService, answerCommon, voteRepo, emailService, userRoleRelService, notificationQueueService, externalNotificationQueueService, activityQueueService)
|
||||
questionController := controller.NewQuestionController(questionService, answerService, rankService, siteInfoCommonService, captchaService)
|
||||
answerController := controller.NewAnswerController(answerService, rankService, captchaService)
|
||||
searchParser := search_parser.NewSearchParser(tagCommonService, userCommon)
|
||||
|
@ -197,9 +203,9 @@ func initApplication(debug bool, serverConf *conf.Server, dbConf *data.Database,
|
|||
siteInfoService := siteinfo.NewSiteInfoService(siteInfoRepo, siteInfoCommonService, emailService, tagCommonService, configService, questionCommon)
|
||||
siteInfoController := controller_admin.NewSiteInfoController(siteInfoService)
|
||||
controllerSiteInfoController := controller.NewSiteInfoController(siteInfoCommonService)
|
||||
notificationRepo := notification.NewNotificationRepo(dataData)
|
||||
notificationRepo := notification2.NewNotificationRepo(dataData)
|
||||
notificationCommon := notificationcommon.NewNotificationCommon(dataData, notificationRepo, userCommon, activityRepo, followRepo, objService, notificationQueueService)
|
||||
notificationService := notification2.NewNotificationService(dataData, notificationRepo, notificationCommon, revisionService)
|
||||
notificationService := notification.NewNotificationService(dataData, notificationRepo, notificationCommon, revisionService)
|
||||
notificationController := controller.NewNotificationController(notificationService, rankService)
|
||||
dashboardService := dashboard.NewDashboardService(questionRepo, answerRepo, commentCommonRepo, voteRepo, userRepo, reportRepo, configService, siteInfoCommonService, serviceConf, dataData)
|
||||
dashboardController := controller.NewDashboardController(dashboardService)
|
||||
|
|
194
docs/docs.go
194
docs/docs.go
|
@ -5166,29 +5166,6 @@ const docTemplate = `{
|
|||
}
|
||||
}
|
||||
},
|
||||
"/answer/api/v1/user/email/notification": {
|
||||
"put": {
|
||||
"description": "unsubscribe email notification",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"User"
|
||||
],
|
||||
"summary": "unsubscribe email notification",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/handler.RespBody"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/answer/api/v1/user/email/verification": {
|
||||
"post": {
|
||||
"description": "UserVerifyEmail",
|
||||
|
@ -5526,14 +5503,14 @@ const docTemplate = `{
|
|||
}
|
||||
}
|
||||
},
|
||||
"/answer/api/v1/user/notice/set": {
|
||||
"post": {
|
||||
"/answer/api/v1/user/notification/config": {
|
||||
"put": {
|
||||
"security": [
|
||||
{
|
||||
"ApiKeyAuth": []
|
||||
}
|
||||
],
|
||||
"description": "UserNoticeSet",
|
||||
"description": "update user's notification config",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
|
@ -5543,18 +5520,44 @@ const docTemplate = `{
|
|||
"tags": [
|
||||
"User"
|
||||
],
|
||||
"summary": "UserNoticeSet",
|
||||
"summary": "update user's notification config",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "UserNoticeSetRequest",
|
||||
"description": "UpdateUserNotificationConfigReq",
|
||||
"name": "data",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/schema.UserNoticeSetRequest"
|
||||
"$ref": "#/definitions/schema.UpdateUserNotificationConfigReq"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/handler.RespBody"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"ApiKeyAuth": []
|
||||
}
|
||||
],
|
||||
"description": "get user's notification config",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"User"
|
||||
],
|
||||
"summary": "get user's notification config",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
|
@ -5567,7 +5570,7 @@ const docTemplate = `{
|
|||
"type": "object",
|
||||
"properties": {
|
||||
"data": {
|
||||
"$ref": "#/definitions/schema.UserNoticeSetResp"
|
||||
"$ref": "#/definitions/schema.GetUserNotificationConfigResp"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -5577,6 +5580,40 @@ const docTemplate = `{
|
|||
}
|
||||
}
|
||||
},
|
||||
"/answer/api/v1/user/notification/unsubscribe": {
|
||||
"put": {
|
||||
"description": "unsubscribe notification",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"User"
|
||||
],
|
||||
"summary": "unsubscribe notification",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "UserUnsubscribeNotificationReq",
|
||||
"name": "data",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/schema.UserUnsubscribeNotificationReq"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/handler.RespBody"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/answer/api/v1/user/password": {
|
||||
"put": {
|
||||
"security": [
|
||||
|
@ -6198,6 +6235,15 @@ const docTemplate = `{
|
|||
}
|
||||
},
|
||||
"definitions": {
|
||||
"constant.NotificationChannelKey": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"email"
|
||||
],
|
||||
"x-enum-varnames": [
|
||||
"EmailChannel"
|
||||
]
|
||||
},
|
||||
"constant.Privilege": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
|
@ -6301,6 +6347,9 @@ const docTemplate = `{
|
|||
"type": "string",
|
||||
"maxLength": 30
|
||||
},
|
||||
"login_required": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"name": {
|
||||
"type": "string",
|
||||
"maxLength": 30
|
||||
|
@ -7595,6 +7644,29 @@ const docTemplate = `{
|
|||
}
|
||||
}
|
||||
},
|
||||
"schema.GetUserNotificationConfigResp": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"all_new_question": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/schema.NotificationChannelConfig"
|
||||
}
|
||||
},
|
||||
"all_new_question_for_following_tags": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/schema.NotificationChannelConfig"
|
||||
}
|
||||
},
|
||||
"inbox": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/schema.NotificationChannelConfig"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"schema.GetUserPageResp": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
|
@ -7706,6 +7778,17 @@ const docTemplate = `{
|
|||
}
|
||||
}
|
||||
},
|
||||
"schema.NotificationChannelConfig": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"enable": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"key": {
|
||||
"$ref": "#/definitions/constant.NotificationChannelKey"
|
||||
}
|
||||
}
|
||||
},
|
||||
"schema.NotificationClearIDRequest": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
|
@ -9103,6 +9186,29 @@ const docTemplate = `{
|
|||
}
|
||||
}
|
||||
},
|
||||
"schema.UpdateUserNotificationConfigReq": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"all_new_question": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/schema.NotificationChannelConfig"
|
||||
}
|
||||
},
|
||||
"all_new_question_for_following_tags": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/schema.NotificationChannelConfig"
|
||||
}
|
||||
},
|
||||
"inbox": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/schema.NotificationChannelConfig"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"schema.UpdateUserPasswordReq": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
|
@ -9382,22 +9488,6 @@ const docTemplate = `{
|
|||
}
|
||||
}
|
||||
},
|
||||
"schema.UserNoticeSetRequest": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"notice_switch": {
|
||||
"type": "boolean"
|
||||
}
|
||||
}
|
||||
},
|
||||
"schema.UserNoticeSetResp": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"notice_switch": {
|
||||
"type": "boolean"
|
||||
}
|
||||
}
|
||||
},
|
||||
"schema.UserRankingResp": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
|
@ -9510,6 +9600,18 @@ const docTemplate = `{
|
|||
}
|
||||
}
|
||||
},
|
||||
"schema.UserUnsubscribeNotificationReq": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"code"
|
||||
],
|
||||
"properties": {
|
||||
"code": {
|
||||
"type": "string",
|
||||
"maxLength": 500
|
||||
}
|
||||
}
|
||||
},
|
||||
"schema.VoteReq": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
|
|
|
@ -5154,29 +5154,6 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"/answer/api/v1/user/email/notification": {
|
||||
"put": {
|
||||
"description": "unsubscribe email notification",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"User"
|
||||
],
|
||||
"summary": "unsubscribe email notification",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/handler.RespBody"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/answer/api/v1/user/email/verification": {
|
||||
"post": {
|
||||
"description": "UserVerifyEmail",
|
||||
|
@ -5514,14 +5491,14 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"/answer/api/v1/user/notice/set": {
|
||||
"post": {
|
||||
"/answer/api/v1/user/notification/config": {
|
||||
"put": {
|
||||
"security": [
|
||||
{
|
||||
"ApiKeyAuth": []
|
||||
}
|
||||
],
|
||||
"description": "UserNoticeSet",
|
||||
"description": "update user's notification config",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
|
@ -5531,18 +5508,44 @@
|
|||
"tags": [
|
||||
"User"
|
||||
],
|
||||
"summary": "UserNoticeSet",
|
||||
"summary": "update user's notification config",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "UserNoticeSetRequest",
|
||||
"description": "UpdateUserNotificationConfigReq",
|
||||
"name": "data",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/schema.UserNoticeSetRequest"
|
||||
"$ref": "#/definitions/schema.UpdateUserNotificationConfigReq"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/handler.RespBody"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"ApiKeyAuth": []
|
||||
}
|
||||
],
|
||||
"description": "get user's notification config",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"User"
|
||||
],
|
||||
"summary": "get user's notification config",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
|
@ -5555,7 +5558,7 @@
|
|||
"type": "object",
|
||||
"properties": {
|
||||
"data": {
|
||||
"$ref": "#/definitions/schema.UserNoticeSetResp"
|
||||
"$ref": "#/definitions/schema.GetUserNotificationConfigResp"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -5565,6 +5568,40 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"/answer/api/v1/user/notification/unsubscribe": {
|
||||
"put": {
|
||||
"description": "unsubscribe notification",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"User"
|
||||
],
|
||||
"summary": "unsubscribe notification",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "UserUnsubscribeNotificationReq",
|
||||
"name": "data",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/schema.UserUnsubscribeNotificationReq"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/handler.RespBody"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/answer/api/v1/user/password": {
|
||||
"put": {
|
||||
"security": [
|
||||
|
@ -6186,6 +6223,15 @@
|
|||
}
|
||||
},
|
||||
"definitions": {
|
||||
"constant.NotificationChannelKey": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"email"
|
||||
],
|
||||
"x-enum-varnames": [
|
||||
"EmailChannel"
|
||||
]
|
||||
},
|
||||
"constant.Privilege": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
|
@ -6289,6 +6335,9 @@
|
|||
"type": "string",
|
||||
"maxLength": 30
|
||||
},
|
||||
"login_required": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"name": {
|
||||
"type": "string",
|
||||
"maxLength": 30
|
||||
|
@ -7583,6 +7632,29 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"schema.GetUserNotificationConfigResp": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"all_new_question": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/schema.NotificationChannelConfig"
|
||||
}
|
||||
},
|
||||
"all_new_question_for_following_tags": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/schema.NotificationChannelConfig"
|
||||
}
|
||||
},
|
||||
"inbox": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/schema.NotificationChannelConfig"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"schema.GetUserPageResp": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
|
@ -7694,6 +7766,17 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"schema.NotificationChannelConfig": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"enable": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"key": {
|
||||
"$ref": "#/definitions/constant.NotificationChannelKey"
|
||||
}
|
||||
}
|
||||
},
|
||||
"schema.NotificationClearIDRequest": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
|
@ -9091,6 +9174,29 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"schema.UpdateUserNotificationConfigReq": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"all_new_question": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/schema.NotificationChannelConfig"
|
||||
}
|
||||
},
|
||||
"all_new_question_for_following_tags": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/schema.NotificationChannelConfig"
|
||||
}
|
||||
},
|
||||
"inbox": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/schema.NotificationChannelConfig"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"schema.UpdateUserPasswordReq": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
|
@ -9370,22 +9476,6 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"schema.UserNoticeSetRequest": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"notice_switch": {
|
||||
"type": "boolean"
|
||||
}
|
||||
}
|
||||
},
|
||||
"schema.UserNoticeSetResp": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"notice_switch": {
|
||||
"type": "boolean"
|
||||
}
|
||||
}
|
||||
},
|
||||
"schema.UserRankingResp": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
|
@ -9498,6 +9588,18 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"schema.UserUnsubscribeNotificationReq": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"code"
|
||||
],
|
||||
"properties": {
|
||||
"code": {
|
||||
"type": "string",
|
||||
"maxLength": 500
|
||||
}
|
||||
}
|
||||
},
|
||||
"schema.VoteReq": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
|
|
|
@ -1,4 +1,10 @@
|
|||
definitions:
|
||||
constant.NotificationChannelKey:
|
||||
enum:
|
||||
- email
|
||||
type: string
|
||||
x-enum-varnames:
|
||||
- EmailChannel
|
||||
constant.Privilege:
|
||||
properties:
|
||||
key:
|
||||
|
@ -63,6 +69,8 @@ definitions:
|
|||
lang:
|
||||
maxLength: 30
|
||||
type: string
|
||||
login_required:
|
||||
type: boolean
|
||||
name:
|
||||
maxLength: 30
|
||||
type: string
|
||||
|
@ -983,6 +991,21 @@ definitions:
|
|||
activation_url:
|
||||
type: string
|
||||
type: object
|
||||
schema.GetUserNotificationConfigResp:
|
||||
properties:
|
||||
all_new_question:
|
||||
items:
|
||||
$ref: '#/definitions/schema.NotificationChannelConfig'
|
||||
type: array
|
||||
all_new_question_for_following_tags:
|
||||
items:
|
||||
$ref: '#/definitions/schema.NotificationChannelConfig'
|
||||
type: array
|
||||
inbox:
|
||||
items:
|
||||
$ref: '#/definitions/schema.NotificationChannelConfig'
|
||||
type: array
|
||||
type: object
|
||||
schema.GetUserPageResp:
|
||||
properties:
|
||||
avatar:
|
||||
|
@ -1064,6 +1087,13 @@ definitions:
|
|||
text:
|
||||
type: string
|
||||
type: object
|
||||
schema.NotificationChannelConfig:
|
||||
properties:
|
||||
enable:
|
||||
type: boolean
|
||||
key:
|
||||
$ref: '#/definitions/constant.NotificationChannelKey'
|
||||
type: object
|
||||
schema.NotificationClearIDRequest:
|
||||
properties:
|
||||
id:
|
||||
|
@ -2028,6 +2058,21 @@ definitions:
|
|||
required:
|
||||
- language
|
||||
type: object
|
||||
schema.UpdateUserNotificationConfigReq:
|
||||
properties:
|
||||
all_new_question:
|
||||
items:
|
||||
$ref: '#/definitions/schema.NotificationChannelConfig'
|
||||
type: array
|
||||
all_new_question_for_following_tags:
|
||||
items:
|
||||
$ref: '#/definitions/schema.NotificationChannelConfig'
|
||||
type: array
|
||||
inbox:
|
||||
items:
|
||||
$ref: '#/definitions/schema.NotificationChannelConfig'
|
||||
type: array
|
||||
type: object
|
||||
schema.UpdateUserPasswordReq:
|
||||
properties:
|
||||
password:
|
||||
|
@ -2228,16 +2273,6 @@ definitions:
|
|||
required:
|
||||
- pass
|
||||
type: object
|
||||
schema.UserNoticeSetRequest:
|
||||
properties:
|
||||
notice_switch:
|
||||
type: boolean
|
||||
type: object
|
||||
schema.UserNoticeSetResp:
|
||||
properties:
|
||||
notice_switch:
|
||||
type: boolean
|
||||
type: object
|
||||
schema.UserRankingResp:
|
||||
properties:
|
||||
staffs:
|
||||
|
@ -2316,6 +2351,14 @@ definitions:
|
|||
required:
|
||||
- e_mail
|
||||
type: object
|
||||
schema.UserUnsubscribeNotificationReq:
|
||||
properties:
|
||||
code:
|
||||
maxLength: 500
|
||||
type: string
|
||||
required:
|
||||
- code
|
||||
type: object
|
||||
schema.VoteReq:
|
||||
properties:
|
||||
captcha_code:
|
||||
|
@ -5478,21 +5521,6 @@ paths:
|
|||
summary: send email to the user email then change their email
|
||||
tags:
|
||||
- User
|
||||
/answer/api/v1/user/email/notification:
|
||||
put:
|
||||
consumes:
|
||||
- application/json
|
||||
description: unsubscribe email notification
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
$ref: '#/definitions/handler.RespBody'
|
||||
summary: unsubscribe email notification
|
||||
tags:
|
||||
- User
|
||||
/answer/api/v1/user/email/verification:
|
||||
post:
|
||||
consumes:
|
||||
|
@ -5698,18 +5726,11 @@ paths:
|
|||
summary: user logout
|
||||
tags:
|
||||
- User
|
||||
/answer/api/v1/user/notice/set:
|
||||
/answer/api/v1/user/notification/config:
|
||||
post:
|
||||
consumes:
|
||||
- application/json
|
||||
description: UserNoticeSet
|
||||
parameters:
|
||||
- description: UserNoticeSetRequest
|
||||
in: body
|
||||
name: data
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/schema.UserNoticeSetRequest'
|
||||
description: get user's notification config
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
|
@ -5720,11 +5741,56 @@ paths:
|
|||
- $ref: '#/definitions/handler.RespBody'
|
||||
- properties:
|
||||
data:
|
||||
$ref: '#/definitions/schema.UserNoticeSetResp'
|
||||
$ref: '#/definitions/schema.GetUserNotificationConfigResp'
|
||||
type: object
|
||||
security:
|
||||
- ApiKeyAuth: []
|
||||
summary: UserNoticeSet
|
||||
summary: get user's notification config
|
||||
tags:
|
||||
- User
|
||||
put:
|
||||
consumes:
|
||||
- application/json
|
||||
description: update user's notification config
|
||||
parameters:
|
||||
- description: UpdateUserNotificationConfigReq
|
||||
in: body
|
||||
name: data
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/schema.UpdateUserNotificationConfigReq'
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
$ref: '#/definitions/handler.RespBody'
|
||||
security:
|
||||
- ApiKeyAuth: []
|
||||
summary: update user's notification config
|
||||
tags:
|
||||
- User
|
||||
/answer/api/v1/user/notification/unsubscribe:
|
||||
put:
|
||||
consumes:
|
||||
- application/json
|
||||
description: unsubscribe notification
|
||||
parameters:
|
||||
- description: UserUnsubscribeNotificationReq
|
||||
in: body
|
||||
name: data
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/schema.UserUnsubscribeNotificationReq'
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
$ref: '#/definitions/handler.RespBody'
|
||||
summary: unsubscribe notification
|
||||
tags:
|
||||
- User
|
||||
/answer/api/v1/user/password:
|
||||
|
|
|
@ -431,6 +431,11 @@ backend:
|
|||
other: "[{{.SiteName}}] {{.DisplayName}} commented on your post"
|
||||
body:
|
||||
other: "<strong><a href='{{.CommentUrl}}'>{{.QuestionTitle}}</a></strong><br><br>\n\n<small>{{.DisplayName}}:</small><br>\n<blockquote>{{.CommentSummary}}</blockquote><br>\n<a href='{{.CommentUrl}}'>View it on {{.SiteName}}</a><br><br>\n\n<small>You are receiving this because you authored the thread. <a href='{{.UnsubscribeUrl}}'>Unsubscribe</a></small>"
|
||||
new_question:
|
||||
title:
|
||||
other: "[{{.SiteName}}] New question: {{.QuestionTitle}}"
|
||||
body:
|
||||
other: "<strong><a href='{{.QuestionUrl}}'>{{.QuestionTitle}}</a></strong><br><br>\n\n<small>{{.Tags}}</small><br><br>\n\n<small><a href='{{.UnsubscribeUrl}}'>Unsubscribe</a></small>"
|
||||
pass_reset:
|
||||
title:
|
||||
other: "[{{.SiteName }}] Password reset"
|
||||
|
|
|
@ -21,4 +21,7 @@ const (
|
|||
|
||||
EmailTplKeyInvitedAnswerTitle = "email_tpl.invited_you_to_answer.title"
|
||||
EmailTplKeyInvitedAnswerBody = "email_tpl.invited_you_to_answer.body"
|
||||
|
||||
EmailTplKeyNewQuestionTitle = "email_tpl.new_question.title"
|
||||
EmailTplKeyNewQuestionBody = "email_tpl.new_question.body"
|
||||
)
|
||||
|
|
|
@ -39,6 +39,19 @@ const (
|
|||
NotificationInvitedYouToAnswer = "notification.action.invited_you_to_answer"
|
||||
)
|
||||
|
||||
type NotificationChannelKey string
|
||||
type NotificationSource string
|
||||
|
||||
const (
|
||||
InboxSource NotificationSource = "inbox"
|
||||
AllNewQuestionSource NotificationSource = "all_new_question"
|
||||
AllNewQuestionForFollowingTagsSource NotificationSource = "all_new_question_for_following_tags"
|
||||
)
|
||||
|
||||
const (
|
||||
EmailChannel NotificationChannelKey = "email"
|
||||
)
|
||||
|
||||
var (
|
||||
NotificationMsgTypeMapping = map[string]int{
|
||||
NotificationUpdateQuestion: 1,
|
||||
|
|
|
@ -13,6 +13,7 @@ import (
|
|||
"github.com/answerdev/answer/internal/service/auth"
|
||||
"github.com/answerdev/answer/internal/service/export"
|
||||
"github.com/answerdev/answer/internal/service/siteinfo_common"
|
||||
"github.com/answerdev/answer/internal/service/user_notification_config"
|
||||
"github.com/answerdev/answer/pkg/checker"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/segmentfault/pacman/errors"
|
||||
|
@ -21,11 +22,12 @@ import (
|
|||
|
||||
// UserController user controller
|
||||
type UserController struct {
|
||||
userService *service.UserService
|
||||
authService *auth.AuthService
|
||||
actionService *action.CaptchaService
|
||||
emailService *export.EmailService
|
||||
siteInfoCommonService siteinfo_common.SiteInfoCommonService
|
||||
userService *service.UserService
|
||||
authService *auth.AuthService
|
||||
actionService *action.CaptchaService
|
||||
emailService *export.EmailService
|
||||
siteInfoCommonService siteinfo_common.SiteInfoCommonService
|
||||
userNotificationConfigService *user_notification_config.UserNotificationConfigService
|
||||
}
|
||||
|
||||
// NewUserController new controller
|
||||
|
@ -35,13 +37,15 @@ func NewUserController(
|
|||
actionService *action.CaptchaService,
|
||||
emailService *export.EmailService,
|
||||
siteInfoCommonService siteinfo_common.SiteInfoCommonService,
|
||||
userNotificationConfigService *user_notification_config.UserNotificationConfigService,
|
||||
) *UserController {
|
||||
return &UserController{
|
||||
authService: authService,
|
||||
userService: userService,
|
||||
actionService: actionService,
|
||||
emailService: emailService,
|
||||
siteInfoCommonService: siteInfoCommonService,
|
||||
authService: authService,
|
||||
userService: userService,
|
||||
actionService: actionService,
|
||||
emailService: emailService,
|
||||
siteInfoCommonService: siteInfoCommonService,
|
||||
userNotificationConfigService: userNotificationConfigService,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -488,25 +492,40 @@ func (uc *UserController) UserRegisterCaptcha(ctx *gin.Context) {
|
|||
handler.HandleResponse(ctx, err, resp)
|
||||
}
|
||||
|
||||
// UserNoticeSet godoc
|
||||
// @Summary UserNoticeSet
|
||||
// @Description UserNoticeSet
|
||||
// GetUserNotificationConfig get user's notification config
|
||||
// @Summary get user's notification config
|
||||
// @Description get user's notification config
|
||||
// @Tags User
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Security ApiKeyAuth
|
||||
// @Param data body schema.UserNoticeSetRequest true "UserNoticeSetRequest"
|
||||
// @Success 200 {object} handler.RespBody{data=schema.UserNoticeSetResp}
|
||||
// @Router /answer/api/v1/user/notice/set [post]
|
||||
func (uc *UserController) UserNoticeSet(ctx *gin.Context) {
|
||||
req := &schema.UserNoticeSetRequest{}
|
||||
// @Success 200 {object} handler.RespBody{data=schema.GetUserNotificationConfigResp}
|
||||
// @Router /answer/api/v1/user/notification/config [post]
|
||||
func (uc *UserController) GetUserNotificationConfig(ctx *gin.Context) {
|
||||
userID := middleware.GetLoginUserIDFromContext(ctx)
|
||||
resp, err := uc.userNotificationConfigService.GetUserNotificationConfig(ctx, userID)
|
||||
handler.HandleResponse(ctx, err, resp)
|
||||
}
|
||||
|
||||
// UpdateUserNotificationConfig update user's notification config
|
||||
// @Summary update user's notification config
|
||||
// @Description update user's notification config
|
||||
// @Tags User
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Security ApiKeyAuth
|
||||
// @Param data body schema.UpdateUserNotificationConfigReq true "UpdateUserNotificationConfigReq"
|
||||
// @Success 200 {object} handler.RespBody{}
|
||||
// @Router /answer/api/v1/user/notification/config [put]
|
||||
func (uc *UserController) UpdateUserNotificationConfig(ctx *gin.Context) {
|
||||
req := &schema.UpdateUserNotificationConfigReq{}
|
||||
if handler.BindAndCheck(ctx, req) {
|
||||
return
|
||||
}
|
||||
|
||||
req.UserID = middleware.GetLoginUserIDFromContext(ctx)
|
||||
resp, err := uc.userService.UserNoticeSet(ctx, req.UserID, req.NoticeSwitch)
|
||||
handler.HandleResponse(ctx, err, resp)
|
||||
err := uc.userNotificationConfigService.UpdateUserNotificationConfig(ctx, req)
|
||||
handler.HandleResponse(ctx, err, nil)
|
||||
}
|
||||
|
||||
// UserChangeEmailSendCode send email to the user email then change their email
|
||||
|
@ -608,16 +627,17 @@ func (uc *UserController) UserRanking(ctx *gin.Context) {
|
|||
handler.HandleResponse(ctx, err, resp)
|
||||
}
|
||||
|
||||
// UserUnsubscribeEmailNotification unsubscribe email notification
|
||||
// @Summary unsubscribe email notification
|
||||
// @Description unsubscribe email notification
|
||||
// UserUnsubscribeNotification unsubscribe notification
|
||||
// @Summary unsubscribe notification
|
||||
// @Description unsubscribe notification
|
||||
// @Tags User
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param data body schema.UserUnsubscribeNotificationReq true "UserUnsubscribeNotificationReq"
|
||||
// @Success 200 {object} handler.RespBody{}
|
||||
// @Router /answer/api/v1/user/email/notification [put]
|
||||
func (uc *UserController) UserUnsubscribeEmailNotification(ctx *gin.Context) {
|
||||
req := &schema.UserUnsubscribeEmailNotificationReq{}
|
||||
// @Router /answer/api/v1/user/notification/unsubscribe [put]
|
||||
func (uc *UserController) UserUnsubscribeNotification(ctx *gin.Context) {
|
||||
req := &schema.UserUnsubscribeNotificationReq{}
|
||||
if handler.BindAndCheck(ctx, req) {
|
||||
return
|
||||
}
|
||||
|
@ -629,7 +649,7 @@ func (uc *UserController) UserUnsubscribeEmailNotification(ctx *gin.Context) {
|
|||
return
|
||||
}
|
||||
|
||||
err := uc.userService.UserUnsubscribeEmailNotification(ctx, req)
|
||||
err := uc.userService.UserUnsubscribeNotification(ctx, req)
|
||||
handler.HandleResponse(ctx, err, nil)
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
package entity
|
||||
|
||||
import "time"
|
||||
|
||||
// UserNotificationConfig user notification config
|
||||
type UserNotificationConfig struct {
|
||||
ID string `xorm:"not null pk autoincr BIGINT(20) id"`
|
||||
CreatedAt time.Time `xorm:"created TIMESTAMP created_at"`
|
||||
UpdatedAt time.Time `xorm:"updated TIMESTAMP updated_at"`
|
||||
UserID string `xorm:"not null default 0 INDEX UNIQUE(uk_us) BIGINT(20) INDEX user_id"`
|
||||
Source string `xorm:"not null default '' INDEX UNIQUE(uk_us) VARCHAR(64) source"`
|
||||
Channels string `xorm:"not null TEXT channels"`
|
||||
Enabled bool `xorm:"not null default false BOOL enabled"`
|
||||
}
|
||||
|
||||
// TableName notification table name
|
||||
func (UserNotificationConfig) TableName() string {
|
||||
return "user_notification_config"
|
||||
}
|
|
@ -71,6 +71,7 @@ var migrations = []Migration{
|
|||
NewMigration("v1.1.0-beta.2", "update question post time", updateQuestionPostTime, true),
|
||||
NewMigration("v1.1.0", "add gravatar base url", updateCount, true),
|
||||
NewMigration("v1.1.1", "update the length of revision content", updateTheLengthOfRevisionContent, false),
|
||||
NewMigration("v1.1.2", "add notification config", addNoticeConfig, false),
|
||||
}
|
||||
|
||||
func GetMigrations() []Migration {
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
package migrations
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/answerdev/answer/internal/entity"
|
||||
"xorm.io/xorm"
|
||||
)
|
||||
|
||||
func addNoticeConfig(ctx context.Context, x *xorm.Engine) error {
|
||||
return x.Context(ctx).Sync(new(entity.UserNotificationConfig))
|
||||
}
|
|
@ -27,6 +27,7 @@ import (
|
|||
"github.com/answerdev/answer/internal/repo/unique"
|
||||
"github.com/answerdev/answer/internal/repo/user"
|
||||
"github.com/answerdev/answer/internal/repo/user_external_login"
|
||||
"github.com/answerdev/answer/internal/repo/user_notification_config"
|
||||
"github.com/google/wire"
|
||||
)
|
||||
|
||||
|
@ -73,4 +74,5 @@ var ProviderSetRepo = wire.NewSet(
|
|||
role.NewPowerRepo,
|
||||
user_external_login.NewUserExternalLoginRepo,
|
||||
plugin_config.NewPluginConfigRepo,
|
||||
user_notification_config.NewUserNotificationConfigRepo,
|
||||
)
|
||||
|
|
|
@ -0,0 +1,90 @@
|
|||
package user_notification_config
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/answerdev/answer/internal/base/constant"
|
||||
"github.com/answerdev/answer/internal/base/data"
|
||||
"github.com/answerdev/answer/internal/base/reason"
|
||||
"github.com/answerdev/answer/internal/entity"
|
||||
"github.com/answerdev/answer/internal/service/user_notification_config"
|
||||
"github.com/segmentfault/pacman/errors"
|
||||
)
|
||||
|
||||
// userNotificationConfigRepo notification repository
|
||||
type userNotificationConfigRepo struct {
|
||||
data *data.Data
|
||||
}
|
||||
|
||||
// NewUserNotificationConfigRepo new repository
|
||||
func NewUserNotificationConfigRepo(data *data.Data) user_notification_config.UserNotificationConfigRepo {
|
||||
return &userNotificationConfigRepo{
|
||||
data: data,
|
||||
}
|
||||
}
|
||||
|
||||
// Save save notification config, if existed, update, if not exist, insert
|
||||
func (ur *userNotificationConfigRepo) Save(ctx context.Context, uc *entity.UserNotificationConfig) (err error) {
|
||||
old := &entity.UserNotificationConfig{UserID: uc.UserID, Source: uc.Source}
|
||||
exist, err := ur.data.DB.Context(ctx).Get(old)
|
||||
if err != nil {
|
||||
return errors.InternalServer(reason.DatabaseError).WithError(err).WithStack()
|
||||
}
|
||||
if exist {
|
||||
old.Channels = uc.Channels
|
||||
old.Enabled = uc.Enabled
|
||||
_, err = ur.data.DB.Context(ctx).ID(old.ID).UseBool("enabled").Cols("channels", "enabled").Update(old)
|
||||
} else {
|
||||
_, err = ur.data.DB.Context(ctx).Insert(uc)
|
||||
}
|
||||
if err != nil {
|
||||
return errors.InternalServer(reason.DatabaseError).WithError(err).WithStack()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetByUserID get notification config by user id
|
||||
func (ur *userNotificationConfigRepo) GetByUserID(ctx context.Context, userID string) (
|
||||
[]*entity.UserNotificationConfig, error) {
|
||||
var configs []*entity.UserNotificationConfig
|
||||
err := ur.data.DB.Context(ctx).Where("user_id = ?", userID).Find(&configs)
|
||||
if err != nil {
|
||||
return nil, errors.InternalServer(reason.DatabaseError).WithError(err).WithStack()
|
||||
}
|
||||
return configs, nil
|
||||
}
|
||||
|
||||
// GetBySource get notification config by source
|
||||
func (ur *userNotificationConfigRepo) GetBySource(ctx context.Context, source constant.NotificationSource) (
|
||||
[]*entity.UserNotificationConfig, error) {
|
||||
var configs []*entity.UserNotificationConfig
|
||||
err := ur.data.DB.Context(ctx).UseBool("enabled").
|
||||
Find(&configs, &entity.UserNotificationConfig{Source: string(source), Enabled: true})
|
||||
if err != nil {
|
||||
return nil, errors.InternalServer(reason.DatabaseError).WithError(err).WithStack()
|
||||
}
|
||||
return configs, nil
|
||||
}
|
||||
|
||||
// GetByUserIDAndSource get notification config by user id and source
|
||||
func (ur *userNotificationConfigRepo) GetByUserIDAndSource(ctx context.Context, userID string, source constant.NotificationSource) (
|
||||
conf *entity.UserNotificationConfig, exist bool, err error) {
|
||||
config := &entity.UserNotificationConfig{UserID: userID, Source: string(source)}
|
||||
exist, err = ur.data.DB.Context(ctx).Get(config)
|
||||
if err != nil {
|
||||
return nil, false, errors.InternalServer(reason.DatabaseError).WithError(err).WithStack()
|
||||
}
|
||||
return config, exist, nil
|
||||
}
|
||||
|
||||
// GetByUsersAndSource get notification config by user ids and source
|
||||
func (ur *userNotificationConfigRepo) GetByUsersAndSource(
|
||||
ctx context.Context, userIDs []string, source constant.NotificationSource) (
|
||||
[]*entity.UserNotificationConfig, error) {
|
||||
var configs []*entity.UserNotificationConfig
|
||||
err := ur.data.DB.Context(ctx).UseBool("enabled").In("user_id", userIDs).
|
||||
Find(&configs, &entity.UserNotificationConfig{Source: string(source), Enabled: true})
|
||||
if err != nil {
|
||||
return nil, errors.InternalServer(reason.DatabaseError).WithError(err).WithStack()
|
||||
}
|
||||
return configs, nil
|
||||
}
|
|
@ -114,7 +114,7 @@ func (a *AnswerAPIRouter) RegisterMustUnAuthAnswerAPIRouter(authUserMiddleware *
|
|||
routerGroup.PUT("/user/email", a.userController.UserChangeEmailVerify)
|
||||
routerGroup.POST("/user/password/reset", a.userController.RetrievePassWord)
|
||||
routerGroup.POST("/user/password/replacement", a.userController.UseRePassWord)
|
||||
routerGroup.PUT("/user/email/notification", a.userController.UserUnsubscribeEmailNotification)
|
||||
routerGroup.PUT("/user/notification/unsubscribe", a.userController.UserUnsubscribeNotification)
|
||||
}
|
||||
|
||||
func (a *AnswerAPIRouter) RegisterUnAuthAnswerAPIRouter(r *gin.RouterGroup) {
|
||||
|
@ -215,7 +215,8 @@ func (a *AnswerAPIRouter) RegisterAnswerAPIRouter(r *gin.RouterGroup) {
|
|||
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)
|
||||
r.GET("/user/notification/config", a.userController.GetUserNotificationConfig)
|
||||
r.PUT("/user/notification/config", a.userController.UpdateUserNotificationConfig)
|
||||
r.GET("/user/info/search", a.userController.SearchUserListByName)
|
||||
|
||||
// vote
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
package schema
|
||||
|
||||
import "encoding/json"
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/answerdev/answer/internal/base/constant"
|
||||
)
|
||||
|
||||
const (
|
||||
AccountActivationSourceType EmailSourceType = "account-activation"
|
||||
|
@ -16,8 +19,10 @@ type EmailCodeContent struct {
|
|||
SourceType EmailSourceType `json:"source_type"`
|
||||
Email string `json:"e_mail"`
|
||||
UserID string `json:"user_id"`
|
||||
// Used for unsubscribe notification
|
||||
NotificationSources []constant.NotificationSource `json:"notification_source,omitempty"`
|
||||
// Used for third-party login account binding
|
||||
BindingKey string `json:"binding_key"`
|
||||
BindingKey string `json:"binding_key,omitempty"`
|
||||
}
|
||||
|
||||
func (r *EmailCodeContent) ToJSONString() string {
|
||||
|
@ -80,3 +85,19 @@ type NewCommentTemplateData struct {
|
|||
CommentSummary string
|
||||
UnsubscribeUrl string
|
||||
}
|
||||
|
||||
type NewQuestionTemplateRawData struct {
|
||||
QuestionTitle string
|
||||
QuestionID string
|
||||
UnsubscribeCode string
|
||||
Tags []string
|
||||
TagIDs []string
|
||||
}
|
||||
|
||||
type NewQuestionTemplateData struct {
|
||||
SiteName string
|
||||
QuestionTitle string
|
||||
QuestionUrl string
|
||||
Tags string
|
||||
UnsubscribeUrl string
|
||||
}
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
package schema
|
||||
|
||||
import (
|
||||
"github.com/answerdev/answer/internal/entity"
|
||||
"github.com/answerdev/answer/pkg/uid"
|
||||
)
|
||||
|
||||
type ExternalNotificationMsg struct {
|
||||
ReceiverUserID string `json:"receiver_user_id"`
|
||||
ReceiverEmail string `json:"receiver_email"`
|
||||
ReceiverLang string `json:"receiver_lang"`
|
||||
|
||||
NewAnswerTemplateRawData *NewAnswerTemplateRawData `json:"new_answer_template_raw_data,omitempty"`
|
||||
NewInviteAnswerTemplateRawData *NewInviteAnswerTemplateRawData `json:"new_invite_answer_template_raw_data,omitempty"`
|
||||
NewCommentTemplateRawData *NewCommentTemplateRawData `json:"new_comment_template_raw_data,omitempty"`
|
||||
NewQuestionTemplateRawData *NewQuestionTemplateRawData `json:"new_question_template_raw_data,omitempty"`
|
||||
}
|
||||
|
||||
func CreateNewQuestionNotificationMsg(questionID, questionTitle string, tags []*entity.Tag) *ExternalNotificationMsg {
|
||||
questionID = uid.DeShortID(questionID)
|
||||
msg := &ExternalNotificationMsg{
|
||||
NewQuestionTemplateRawData: &NewQuestionTemplateRawData{
|
||||
QuestionID: questionID,
|
||||
QuestionTitle: questionTitle,
|
||||
},
|
||||
}
|
||||
for _, tag := range tags {
|
||||
msg.NewQuestionTemplateRawData.Tags = append(msg.NewQuestionTemplateRawData.Tags, tag.SlugName)
|
||||
msg.NewQuestionTemplateRawData.TagIDs = append(msg.NewQuestionTemplateRawData.TagIDs, tag.ID)
|
||||
}
|
||||
return msg
|
||||
}
|
|
@ -0,0 +1,132 @@
|
|||
package schema
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/answerdev/answer/internal/base/constant"
|
||||
"github.com/answerdev/answer/internal/entity"
|
||||
)
|
||||
|
||||
type NotificationChannelConfig struct {
|
||||
Key constant.NotificationChannelKey `json:"key"`
|
||||
Enable bool `json:"enable"`
|
||||
}
|
||||
|
||||
type NotificationChannels []*NotificationChannelConfig
|
||||
|
||||
func NewNotificationChannelsFormJson(jsonStr string) NotificationChannels {
|
||||
var list NotificationChannels
|
||||
_ = json.Unmarshal([]byte(jsonStr), &list)
|
||||
return list
|
||||
}
|
||||
|
||||
func (n *NotificationChannels) Format(sequences []constant.NotificationChannelKey) {
|
||||
if n == nil {
|
||||
*n = make([]*NotificationChannelConfig, 0)
|
||||
return
|
||||
}
|
||||
mapping := make(map[constant.NotificationChannelKey]*NotificationChannelConfig)
|
||||
for _, item := range *n {
|
||||
mapping[item.Key] = &NotificationChannelConfig{
|
||||
Key: item.Key,
|
||||
Enable: item.Enable,
|
||||
}
|
||||
}
|
||||
newList := make([]*NotificationChannelConfig, 0)
|
||||
for _, ch := range sequences {
|
||||
if c, ok := mapping[ch]; ok {
|
||||
newList = append(newList, c)
|
||||
} else {
|
||||
newList = append(newList, &NotificationChannelConfig{
|
||||
Key: ch,
|
||||
})
|
||||
}
|
||||
}
|
||||
*n = newList
|
||||
}
|
||||
|
||||
func (n *NotificationChannels) CheckEnable(ch constant.NotificationChannelKey) bool {
|
||||
if n == nil {
|
||||
return false
|
||||
}
|
||||
for _, item := range *n {
|
||||
if item.Key == ch {
|
||||
return item.Enable
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (n *NotificationChannels) ToJsonString() string {
|
||||
data, _ := json.Marshal(n)
|
||||
return string(data)
|
||||
}
|
||||
|
||||
type NotificationConfig struct {
|
||||
Inbox NotificationChannels `json:"inbox"`
|
||||
AllNewQuestion NotificationChannels `json:"all_new_question"`
|
||||
AllNewQuestionForFollowingTags NotificationChannels `json:"all_new_question_for_following_tags"`
|
||||
}
|
||||
|
||||
func (n *NotificationConfig) ToJsonString() string {
|
||||
data, _ := json.Marshal(n)
|
||||
return string(data)
|
||||
}
|
||||
|
||||
func NewNotificationConfig(configs []*entity.UserNotificationConfig) NotificationConfig {
|
||||
nc := NotificationConfig{}
|
||||
nc.Inbox = make([]*NotificationChannelConfig, 0)
|
||||
nc.AllNewQuestion = make([]*NotificationChannelConfig, 0)
|
||||
nc.AllNewQuestionForFollowingTags = make([]*NotificationChannelConfig, 0)
|
||||
for _, item := range configs {
|
||||
switch item.Source {
|
||||
case string(constant.InboxSource):
|
||||
nc.Inbox = NewNotificationChannelsFormJson(item.Channels)
|
||||
case string(constant.AllNewQuestionSource):
|
||||
nc.AllNewQuestion = NewNotificationChannelsFormJson(item.Channels)
|
||||
case string(constant.AllNewQuestionForFollowingTagsSource):
|
||||
nc.AllNewQuestionForFollowingTags = NewNotificationChannelsFormJson(item.Channels)
|
||||
}
|
||||
}
|
||||
return nc
|
||||
}
|
||||
|
||||
func (n *NotificationConfig) FromJsonString(data string) {
|
||||
if len(data) > 0 {
|
||||
_ = json.Unmarshal([]byte(data), n)
|
||||
return
|
||||
}
|
||||
n.Inbox = make([]*NotificationChannelConfig, 0)
|
||||
n.AllNewQuestion = make([]*NotificationChannelConfig, 0)
|
||||
n.AllNewQuestionForFollowingTags = make([]*NotificationChannelConfig, 0)
|
||||
return
|
||||
}
|
||||
|
||||
func (n *NotificationConfig) Format() {
|
||||
n.Inbox.Format([]constant.NotificationChannelKey{constant.EmailChannel})
|
||||
n.AllNewQuestion.Format([]constant.NotificationChannelKey{constant.EmailChannel})
|
||||
n.AllNewQuestionForFollowingTags.Format([]constant.NotificationChannelKey{constant.EmailChannel})
|
||||
}
|
||||
|
||||
func (n *NotificationConfig) CheckEnable(
|
||||
source constant.NotificationSource, channel constant.NotificationChannelKey) bool {
|
||||
switch source {
|
||||
case constant.InboxSource:
|
||||
return n.Inbox.CheckEnable(channel)
|
||||
case constant.AllNewQuestionSource:
|
||||
return n.AllNewQuestion.CheckEnable(channel)
|
||||
case constant.AllNewQuestionForFollowingTagsSource:
|
||||
return n.AllNewQuestionForFollowingTags.CheckEnable(channel)
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// UpdateUserNotificationConfigReq update user notification config request
|
||||
type UpdateUserNotificationConfigReq struct {
|
||||
NotificationConfig
|
||||
UserID string `json:"-"`
|
||||
}
|
||||
|
||||
// GetUserNotificationConfigResp get user notification config response
|
||||
type GetUserNotificationConfigResp struct {
|
||||
NotificationConfig
|
||||
}
|
|
@ -293,15 +293,6 @@ func (u *UserRePassWordRequest) Check() (errFields []*validator.FormErrorField,
|
|||
return nil, nil
|
||||
}
|
||||
|
||||
type UserNoticeSetRequest struct {
|
||||
NoticeSwitch bool `json:"notice_switch"`
|
||||
UserID string `json:"-"`
|
||||
}
|
||||
|
||||
type UserNoticeSetResp struct {
|
||||
NoticeSwitch bool `json:"notice_switch"`
|
||||
}
|
||||
|
||||
type ActionRecordReq struct {
|
||||
Action string `validate:"required,oneof=email password edit_userinfo question answer comment edit invitation_answer search report delete vote" form:"action"`
|
||||
IP string `json:"-"`
|
||||
|
@ -373,8 +364,8 @@ type UserRankingSimpleInfo struct {
|
|||
Avatar string `json:"avatar"`
|
||||
}
|
||||
|
||||
// UserUnsubscribeEmailNotificationReq user unsubscribe email notification request
|
||||
type UserUnsubscribeEmailNotificationReq struct {
|
||||
// UserUnsubscribeNotificationReq user unsubscribe email notification request
|
||||
type UserUnsubscribeNotificationReq struct {
|
||||
Code string `validate:"required,gt=0,lte=500" json:"code"`
|
||||
Content string `json:"-"`
|
||||
}
|
||||
|
|
|
@ -25,26 +25,26 @@ import (
|
|||
"github.com/answerdev/answer/pkg/encryption"
|
||||
"github.com/answerdev/answer/pkg/uid"
|
||||
"github.com/segmentfault/pacman/errors"
|
||||
"github.com/segmentfault/pacman/i18n"
|
||||
"github.com/segmentfault/pacman/log"
|
||||
)
|
||||
|
||||
// AnswerService user service
|
||||
type AnswerService struct {
|
||||
answerRepo answercommon.AnswerRepo
|
||||
questionRepo questioncommon.QuestionRepo
|
||||
questionCommon *questioncommon.QuestionCommon
|
||||
answerActivityService *activity.AnswerActivityService
|
||||
userCommon *usercommon.UserCommon
|
||||
collectionCommon *collectioncommon.CollectionCommon
|
||||
userRepo usercommon.UserRepo
|
||||
revisionService *revision_common.RevisionService
|
||||
AnswerCommon *answercommon.AnswerCommon
|
||||
voteRepo activity_common.VoteRepo
|
||||
emailService *export.EmailService
|
||||
roleService *role.UserRoleRelService
|
||||
notificationQueueService notice_queue.NotificationQueueService
|
||||
activityQueueService activity_queue.ActivityQueueService
|
||||
answerRepo answercommon.AnswerRepo
|
||||
questionRepo questioncommon.QuestionRepo
|
||||
questionCommon *questioncommon.QuestionCommon
|
||||
answerActivityService *activity.AnswerActivityService
|
||||
userCommon *usercommon.UserCommon
|
||||
collectionCommon *collectioncommon.CollectionCommon
|
||||
userRepo usercommon.UserRepo
|
||||
revisionService *revision_common.RevisionService
|
||||
AnswerCommon *answercommon.AnswerCommon
|
||||
voteRepo activity_common.VoteRepo
|
||||
emailService *export.EmailService
|
||||
roleService *role.UserRoleRelService
|
||||
notificationQueueService notice_queue.NotificationQueueService
|
||||
externalNotificationQueueService notice_queue.ExternalNotificationQueueService
|
||||
activityQueueService activity_queue.ActivityQueueService
|
||||
}
|
||||
|
||||
func NewAnswerService(
|
||||
|
@ -61,23 +61,25 @@ func NewAnswerService(
|
|||
emailService *export.EmailService,
|
||||
roleService *role.UserRoleRelService,
|
||||
notificationQueueService notice_queue.NotificationQueueService,
|
||||
externalNotificationQueueService notice_queue.ExternalNotificationQueueService,
|
||||
activityQueueService activity_queue.ActivityQueueService,
|
||||
) *AnswerService {
|
||||
return &AnswerService{
|
||||
answerRepo: answerRepo,
|
||||
questionRepo: questionRepo,
|
||||
userCommon: userCommon,
|
||||
collectionCommon: collectionCommon,
|
||||
questionCommon: questionCommon,
|
||||
userRepo: userRepo,
|
||||
revisionService: revisionService,
|
||||
answerActivityService: answerAcceptActivityRepo,
|
||||
AnswerCommon: answerCommon,
|
||||
voteRepo: voteRepo,
|
||||
emailService: emailService,
|
||||
roleService: roleService,
|
||||
notificationQueueService: notificationQueueService,
|
||||
activityQueueService: activityQueueService,
|
||||
answerRepo: answerRepo,
|
||||
questionRepo: questionRepo,
|
||||
userCommon: userCommon,
|
||||
collectionCommon: collectionCommon,
|
||||
questionCommon: questionCommon,
|
||||
userRepo: userRepo,
|
||||
revisionService: revisionService,
|
||||
answerActivityService: answerAcceptActivityRepo,
|
||||
AnswerCommon: answerCommon,
|
||||
voteRepo: voteRepo,
|
||||
emailService: emailService,
|
||||
roleService: roleService,
|
||||
notificationQueueService: notificationQueueService,
|
||||
externalNotificationQueueService: externalNotificationQueueService,
|
||||
activityQueueService: activityQueueService,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -604,7 +606,7 @@ func (as *AnswerService) notificationAnswerTheQuestion(ctx context.Context,
|
|||
msg.NotificationAction = constant.NotificationAnswerTheQuestion
|
||||
as.notificationQueueService.Send(ctx, msg)
|
||||
|
||||
userInfo, exist, err := as.userRepo.GetByUserID(ctx, questionUserID)
|
||||
receiverUserInfo, exist, err := as.userRepo.GetByUserID(ctx, questionUserID)
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
return
|
||||
|
@ -613,37 +615,23 @@ func (as *AnswerService) notificationAnswerTheQuestion(ctx context.Context,
|
|||
log.Warnf("user %s not found", questionUserID)
|
||||
return
|
||||
}
|
||||
if userInfo.NoticeStatus == schema.NoticeStatusOff || len(userInfo.EMail) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
externalNotificationMsg := &schema.ExternalNotificationMsg{
|
||||
ReceiverUserID: receiverUserInfo.ID,
|
||||
ReceiverEmail: receiverUserInfo.EMail,
|
||||
ReceiverLang: receiverUserInfo.Language,
|
||||
}
|
||||
rawData := &schema.NewAnswerTemplateRawData{
|
||||
QuestionTitle: questionTitle,
|
||||
QuestionID: questionID,
|
||||
AnswerID: answerID,
|
||||
AnswerSummary: answerSummary,
|
||||
UnsubscribeCode: encryption.MD5(userInfo.Pass),
|
||||
UnsubscribeCode: encryption.MD5(receiverUserInfo.Pass),
|
||||
}
|
||||
answerUser, _, _ := as.userCommon.GetUserBasicInfoByID(ctx, answerUserID)
|
||||
if answerUser != nil {
|
||||
rawData.AnswerUserDisplayName = answerUser.DisplayName
|
||||
}
|
||||
codeContent := &schema.EmailCodeContent{
|
||||
SourceType: schema.UnsubscribeSourceType,
|
||||
Email: userInfo.EMail,
|
||||
UserID: userInfo.ID,
|
||||
}
|
||||
|
||||
// If receiver has set language, use it to send email.
|
||||
if len(userInfo.Language) > 0 {
|
||||
ctx = context.WithValue(ctx, constant.AcceptLanguageFlag, i18n.Language(userInfo.Language))
|
||||
}
|
||||
title, body, err := as.emailService.NewAnswerTemplate(ctx, rawData)
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
go as.emailService.SendAndSaveCodeWithTime(
|
||||
ctx, userInfo.EMail, title, body, rawData.UnsubscribeCode, codeContent.ToJSONString(), 7*24*time.Hour)
|
||||
externalNotificationMsg.NewAnswerTemplateRawData = rawData
|
||||
as.externalNotificationQueueService.Send(ctx, externalNotificationMsg)
|
||||
}
|
||||
|
|
|
@ -22,7 +22,6 @@ import (
|
|||
"github.com/answerdev/answer/pkg/uid"
|
||||
"github.com/jinzhu/copier"
|
||||
"github.com/segmentfault/pacman/errors"
|
||||
"github.com/segmentfault/pacman/i18n"
|
||||
"github.com/segmentfault/pacman/log"
|
||||
)
|
||||
|
||||
|
@ -58,15 +57,16 @@ func (c *CommentQuery) GetOrderBy() string {
|
|||
|
||||
// CommentService user service
|
||||
type CommentService struct {
|
||||
commentRepo CommentRepo
|
||||
commentCommonRepo comment_common.CommentCommonRepo
|
||||
userCommon *usercommon.UserCommon
|
||||
voteCommon activity_common.VoteRepo
|
||||
objectInfoService *object_info.ObjService
|
||||
emailService *export.EmailService
|
||||
userRepo usercommon.UserRepo
|
||||
notificationQueueService notice_queue.NotificationQueueService
|
||||
activityQueueService activity_queue.ActivityQueueService
|
||||
commentRepo CommentRepo
|
||||
commentCommonRepo comment_common.CommentCommonRepo
|
||||
userCommon *usercommon.UserCommon
|
||||
voteCommon activity_common.VoteRepo
|
||||
objectInfoService *object_info.ObjService
|
||||
emailService *export.EmailService
|
||||
userRepo usercommon.UserRepo
|
||||
notificationQueueService notice_queue.NotificationQueueService
|
||||
externalNotificationQueueService notice_queue.ExternalNotificationQueueService
|
||||
activityQueueService activity_queue.ActivityQueueService
|
||||
}
|
||||
|
||||
// NewCommentService new comment service
|
||||
|
@ -79,18 +79,20 @@ func NewCommentService(
|
|||
emailService *export.EmailService,
|
||||
userRepo usercommon.UserRepo,
|
||||
notificationQueueService notice_queue.NotificationQueueService,
|
||||
externalNotificationQueueService notice_queue.ExternalNotificationQueueService,
|
||||
activityQueueService activity_queue.ActivityQueueService,
|
||||
) *CommentService {
|
||||
return &CommentService{
|
||||
commentRepo: commentRepo,
|
||||
commentCommonRepo: commentCommonRepo,
|
||||
userCommon: userCommon,
|
||||
voteCommon: voteCommon,
|
||||
objectInfoService: objectInfoService,
|
||||
emailService: emailService,
|
||||
userRepo: userRepo,
|
||||
notificationQueueService: notificationQueueService,
|
||||
activityQueueService: activityQueueService,
|
||||
commentRepo: commentRepo,
|
||||
commentCommonRepo: commentCommonRepo,
|
||||
userCommon: userCommon,
|
||||
voteCommon: voteCommon,
|
||||
objectInfoService: objectInfoService,
|
||||
emailService: emailService,
|
||||
userRepo: userRepo,
|
||||
notificationQueueService: notificationQueueService,
|
||||
externalNotificationQueueService: externalNotificationQueueService,
|
||||
activityQueueService: activityQueueService,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -474,6 +476,7 @@ func (cs *CommentService) notificationQuestionComment(ctx context.Context, quest
|
|||
if questionUserID == commentUserID {
|
||||
return
|
||||
}
|
||||
// send internal notification
|
||||
msg := &schema.NotificationMsg{
|
||||
ReceiverUserID: questionUserID,
|
||||
TriggerUserID: commentUserID,
|
||||
|
@ -484,6 +487,7 @@ func (cs *CommentService) notificationQuestionComment(ctx context.Context, quest
|
|||
msg.NotificationAction = constant.NotificationCommentQuestion
|
||||
cs.notificationQueueService.Send(ctx, msg)
|
||||
|
||||
// send external notification
|
||||
receiverUserInfo, exist, err := cs.userRepo.GetByUserID(ctx, questionUserID)
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
|
@ -493,10 +497,12 @@ func (cs *CommentService) notificationQuestionComment(ctx context.Context, quest
|
|||
log.Warnf("user %s not found", questionUserID)
|
||||
return
|
||||
}
|
||||
if receiverUserInfo.NoticeStatus == schema.NoticeStatusOff || len(receiverUserInfo.EMail) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
externalNotificationMsg := &schema.ExternalNotificationMsg{
|
||||
ReceiverUserID: receiverUserInfo.ID,
|
||||
ReceiverEmail: receiverUserInfo.EMail,
|
||||
ReceiverLang: receiverUserInfo.Language,
|
||||
}
|
||||
rawData := &schema.NewCommentTemplateRawData{
|
||||
QuestionTitle: questionTitle,
|
||||
QuestionID: questionID,
|
||||
|
@ -508,24 +514,8 @@ func (cs *CommentService) notificationQuestionComment(ctx context.Context, quest
|
|||
if commentUser != nil {
|
||||
rawData.CommentUserDisplayName = commentUser.DisplayName
|
||||
}
|
||||
codeContent := &schema.EmailCodeContent{
|
||||
SourceType: schema.UnsubscribeSourceType,
|
||||
Email: receiverUserInfo.EMail,
|
||||
UserID: receiverUserInfo.ID,
|
||||
}
|
||||
|
||||
// If receiver has set language, use it to send email.
|
||||
if len(receiverUserInfo.Language) > 0 {
|
||||
ctx = context.WithValue(ctx, constant.AcceptLanguageFlag, i18n.Language(receiverUserInfo.Language))
|
||||
}
|
||||
title, body, err := cs.emailService.NewCommentTemplate(ctx, rawData)
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
go cs.emailService.SendAndSaveCodeWithTime(
|
||||
ctx, receiverUserInfo.EMail, title, body, rawData.UnsubscribeCode, codeContent.ToJSONString(), 7*24*time.Hour)
|
||||
externalNotificationMsg.NewCommentTemplateRawData = rawData
|
||||
cs.externalNotificationQueueService.Send(ctx, externalNotificationMsg)
|
||||
}
|
||||
|
||||
func (cs *CommentService) notificationAnswerComment(ctx context.Context,
|
||||
|
@ -533,6 +523,8 @@ func (cs *CommentService) notificationAnswerComment(ctx context.Context,
|
|||
if answerUserID == commentUserID {
|
||||
return
|
||||
}
|
||||
|
||||
// Send internal notification.
|
||||
msg := &schema.NotificationMsg{
|
||||
ReceiverUserID: answerUserID,
|
||||
TriggerUserID: commentUserID,
|
||||
|
@ -543,6 +535,7 @@ func (cs *CommentService) notificationAnswerComment(ctx context.Context,
|
|||
msg.NotificationAction = constant.NotificationCommentAnswer
|
||||
cs.notificationQueueService.Send(ctx, msg)
|
||||
|
||||
// Send external notification.
|
||||
receiverUserInfo, exist, err := cs.userRepo.GetByUserID(ctx, answerUserID)
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
|
@ -552,10 +545,11 @@ func (cs *CommentService) notificationAnswerComment(ctx context.Context,
|
|||
log.Warnf("user %s not found", answerUserID)
|
||||
return
|
||||
}
|
||||
if receiverUserInfo.NoticeStatus == schema.NoticeStatusOff || len(receiverUserInfo.EMail) == 0 {
|
||||
return
|
||||
externalNotificationMsg := &schema.ExternalNotificationMsg{
|
||||
ReceiverUserID: receiverUserInfo.ID,
|
||||
ReceiverEmail: receiverUserInfo.EMail,
|
||||
ReceiverLang: receiverUserInfo.Language,
|
||||
}
|
||||
|
||||
rawData := &schema.NewCommentTemplateRawData{
|
||||
QuestionTitle: questionTitle,
|
||||
QuestionID: questionID,
|
||||
|
@ -568,24 +562,8 @@ func (cs *CommentService) notificationAnswerComment(ctx context.Context,
|
|||
if commentUser != nil {
|
||||
rawData.CommentUserDisplayName = commentUser.DisplayName
|
||||
}
|
||||
codeContent := &schema.EmailCodeContent{
|
||||
SourceType: schema.UnsubscribeSourceType,
|
||||
Email: receiverUserInfo.EMail,
|
||||
UserID: receiverUserInfo.ID,
|
||||
}
|
||||
|
||||
// If receiver has set language, use it to send email.
|
||||
if len(receiverUserInfo.Language) > 0 {
|
||||
ctx = context.WithValue(ctx, constant.AcceptLanguageFlag, i18n.Language(receiverUserInfo.Language))
|
||||
}
|
||||
title, body, err := cs.emailService.NewCommentTemplate(ctx, rawData)
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
go cs.emailService.SendAndSaveCodeWithTime(
|
||||
ctx, receiverUserInfo.EMail, title, body, rawData.UnsubscribeCode, codeContent.ToJSONString(), 7*24*time.Hour)
|
||||
externalNotificationMsg.NewCommentTemplateRawData = rawData
|
||||
cs.externalNotificationQueueService.Send(ctx, externalNotificationMsg)
|
||||
}
|
||||
|
||||
func (cs *CommentService) notificationCommentReply(ctx context.Context, replyUserID, commentID, commentUserID string) {
|
||||
|
|
|
@ -6,6 +6,7 @@ import (
|
|||
"fmt"
|
||||
"mime"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/answerdev/answer/internal/base/constant"
|
||||
|
@ -149,7 +150,7 @@ func (es *EmailService) VerifyUrlExpired(ctx context.Context, code string) (cont
|
|||
return content
|
||||
}
|
||||
|
||||
func (es *EmailService) GetSiteGeneral(ctx context.Context) (resp schema.SiteGeneralResp, err error) {
|
||||
func (es *EmailService) getSiteGeneral(ctx context.Context) (resp schema.SiteGeneralResp, err error) {
|
||||
var (
|
||||
siteType = "general"
|
||||
siteInfo *entity.SiteInfo
|
||||
|
@ -167,7 +168,7 @@ func (es *EmailService) GetSiteGeneral(ctx context.Context) (resp schema.SiteGen
|
|||
}
|
||||
|
||||
func (es *EmailService) RegisterTemplate(ctx context.Context, registerUrl string) (title, body string, err error) {
|
||||
siteInfo, err := es.GetSiteGeneral(ctx)
|
||||
siteInfo, err := es.getSiteGeneral(ctx)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
@ -183,7 +184,7 @@ func (es *EmailService) RegisterTemplate(ctx context.Context, registerUrl string
|
|||
}
|
||||
|
||||
func (es *EmailService) PassResetTemplate(ctx context.Context, passResetUrl string) (title, body string, err error) {
|
||||
siteInfo, err := es.GetSiteGeneral(ctx)
|
||||
siteInfo, err := es.getSiteGeneral(ctx)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
@ -197,7 +198,7 @@ func (es *EmailService) PassResetTemplate(ctx context.Context, passResetUrl stri
|
|||
}
|
||||
|
||||
func (es *EmailService) ChangeEmailTemplate(ctx context.Context, changeEmailUrl string) (title, body string, err error) {
|
||||
siteInfo, err := es.GetSiteGeneral(ctx)
|
||||
siteInfo, err := es.getSiteGeneral(ctx)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
@ -214,7 +215,7 @@ func (es *EmailService) ChangeEmailTemplate(ctx context.Context, changeEmailUrl
|
|||
|
||||
// TestTemplate send test email template parse
|
||||
func (es *EmailService) TestTemplate(ctx context.Context) (title, body string, err error) {
|
||||
siteInfo, err := es.GetSiteGeneral(ctx)
|
||||
siteInfo, err := es.getSiteGeneral(ctx)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
@ -229,7 +230,7 @@ func (es *EmailService) TestTemplate(ctx context.Context) (title, body string, e
|
|||
// NewAnswerTemplate new answer template
|
||||
func (es *EmailService) NewAnswerTemplate(ctx context.Context, raw *schema.NewAnswerTemplateRawData) (
|
||||
title, body string, err error) {
|
||||
siteInfo, err := es.GetSiteGeneral(ctx)
|
||||
siteInfo, err := es.getSiteGeneral(ctx)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
@ -251,7 +252,7 @@ func (es *EmailService) NewAnswerTemplate(ctx context.Context, raw *schema.NewAn
|
|||
// NewInviteAnswerTemplate new invite answer template
|
||||
func (es *EmailService) NewInviteAnswerTemplate(ctx context.Context, raw *schema.NewInviteAnswerTemplateRawData) (
|
||||
title, body string, err error) {
|
||||
siteInfo, err := es.GetSiteGeneral(ctx)
|
||||
siteInfo, err := es.getSiteGeneral(ctx)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
@ -272,7 +273,7 @@ func (es *EmailService) NewInviteAnswerTemplate(ctx context.Context, raw *schema
|
|||
// NewCommentTemplate new comment template
|
||||
func (es *EmailService) NewCommentTemplate(ctx context.Context, raw *schema.NewCommentTemplateRawData) (
|
||||
title, body string, err error) {
|
||||
siteInfo, err := es.GetSiteGeneral(ctx)
|
||||
siteInfo, err := es.getSiteGeneral(ctx)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
@ -297,6 +298,27 @@ func (es *EmailService) NewCommentTemplate(ctx context.Context, raw *schema.NewC
|
|||
return title, body, nil
|
||||
}
|
||||
|
||||
// NewQuestionTemplate new question template
|
||||
func (es *EmailService) NewQuestionTemplate(ctx context.Context, raw *schema.NewQuestionTemplateRawData) (
|
||||
title, body string, err error) {
|
||||
siteInfo, err := es.getSiteGeneral(ctx)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
templateData := &schema.NewQuestionTemplateData{
|
||||
SiteName: siteInfo.Name,
|
||||
QuestionTitle: raw.QuestionTitle,
|
||||
Tags: strings.Join(raw.Tags, ", "),
|
||||
UnsubscribeUrl: fmt.Sprintf("%s/users/unsubscribe?code=%s", siteInfo.SiteUrl, raw.UnsubscribeCode),
|
||||
}
|
||||
templateData.QuestionUrl = fmt.Sprintf("%s/questions/%s", siteInfo.SiteUrl, raw.QuestionID)
|
||||
|
||||
lang := handler.GetLangByCtx(ctx)
|
||||
title = translator.TrWithData(lang, constant.EmailTplKeyNewQuestionTitle, templateData)
|
||||
body = translator.TrWithData(lang, constant.EmailTplKeyNewQuestionBody, templateData)
|
||||
return title, body, nil
|
||||
}
|
||||
|
||||
func (es *EmailService) GetEmailConfig(ctx context.Context) (ec *EmailConfig, err error) {
|
||||
emailConf, err := es.configService.GetStringValue(ctx, "email.config")
|
||||
if err != nil {
|
||||
|
|
|
@ -0,0 +1,50 @@
|
|||
package notice_queue
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/answerdev/answer/internal/schema"
|
||||
"github.com/segmentfault/pacman/log"
|
||||
)
|
||||
|
||||
type ExternalNotificationQueueService interface {
|
||||
Send(ctx context.Context, msg *schema.ExternalNotificationMsg)
|
||||
RegisterHandler(handler func(ctx context.Context, msg *schema.ExternalNotificationMsg) error)
|
||||
}
|
||||
|
||||
type externalNotificationQueueService struct {
|
||||
Queue chan *schema.ExternalNotificationMsg
|
||||
Handler func(ctx context.Context, msg *schema.ExternalNotificationMsg) error
|
||||
}
|
||||
|
||||
func (ns *externalNotificationQueueService) Send(ctx context.Context, msg *schema.ExternalNotificationMsg) {
|
||||
ns.Queue <- msg
|
||||
}
|
||||
|
||||
func (ns *externalNotificationQueueService) RegisterHandler(
|
||||
handler func(ctx context.Context, msg *schema.ExternalNotificationMsg) error) {
|
||||
ns.Handler = handler
|
||||
}
|
||||
|
||||
func (ns *externalNotificationQueueService) working() {
|
||||
go func() {
|
||||
for msg := range ns.Queue {
|
||||
log.Debugf("received notification %+v", msg)
|
||||
if ns.Handler == nil {
|
||||
log.Warnf("no handler for notification")
|
||||
continue
|
||||
}
|
||||
if err := ns.Handler(context.Background(), msg); err != nil {
|
||||
log.Error(err)
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
// NewNewQuestionNotificationQueueService create a new notification queue service
|
||||
func NewNewQuestionNotificationQueueService() ExternalNotificationQueueService {
|
||||
ns := &externalNotificationQueueService{}
|
||||
ns.Queue = make(chan *schema.ExternalNotificationMsg, 128)
|
||||
ns.working()
|
||||
return ns
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
package notification
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/answerdev/answer/internal/base/data"
|
||||
"github.com/answerdev/answer/internal/schema"
|
||||
"github.com/answerdev/answer/internal/service/activity_common"
|
||||
"github.com/answerdev/answer/internal/service/export"
|
||||
"github.com/answerdev/answer/internal/service/notice_queue"
|
||||
usercommon "github.com/answerdev/answer/internal/service/user_common"
|
||||
"github.com/answerdev/answer/internal/service/user_notification_config"
|
||||
"github.com/segmentfault/pacman/log"
|
||||
)
|
||||
|
||||
type ExternalNotificationService struct {
|
||||
data *data.Data
|
||||
userNotificationConfigRepo user_notification_config.UserNotificationConfigRepo
|
||||
followRepo activity_common.FollowRepo
|
||||
emailService *export.EmailService
|
||||
userRepo usercommon.UserRepo
|
||||
notificationQueueService notice_queue.ExternalNotificationQueueService
|
||||
}
|
||||
|
||||
func NewExternalNotificationService(
|
||||
userNotificationConfigRepo user_notification_config.UserNotificationConfigRepo,
|
||||
followRepo activity_common.FollowRepo,
|
||||
emailService *export.EmailService,
|
||||
userRepo usercommon.UserRepo,
|
||||
notificationQueueService notice_queue.ExternalNotificationQueueService,
|
||||
) *ExternalNotificationService {
|
||||
n := &ExternalNotificationService{
|
||||
userNotificationConfigRepo: userNotificationConfigRepo,
|
||||
followRepo: followRepo,
|
||||
emailService: emailService,
|
||||
userRepo: userRepo,
|
||||
notificationQueueService: notificationQueueService,
|
||||
}
|
||||
notificationQueueService.RegisterHandler(n.Handler)
|
||||
return n
|
||||
}
|
||||
|
||||
func (ns *ExternalNotificationService) Handler(ctx context.Context, msg *schema.ExternalNotificationMsg) error {
|
||||
log.Debugf("try to send external notification %+v", msg)
|
||||
|
||||
if msg.NewQuestionTemplateRawData != nil {
|
||||
return ns.handleNewQuestionNotification(ctx, msg)
|
||||
}
|
||||
if msg.NewCommentTemplateRawData != nil {
|
||||
return ns.handleNewCommentNotification(ctx, msg)
|
||||
}
|
||||
if msg.NewAnswerTemplateRawData != nil {
|
||||
return ns.handleNewAnswerNotification(ctx, msg)
|
||||
}
|
||||
if msg.NewInviteAnswerTemplateRawData != nil {
|
||||
return ns.handleInviteAnswerNotification(ctx, msg)
|
||||
}
|
||||
log.Errorf("unknown notification message: %+v", msg)
|
||||
return nil
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
package notification
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/answerdev/answer/internal/base/constant"
|
||||
"github.com/answerdev/answer/internal/schema"
|
||||
"github.com/segmentfault/pacman/i18n"
|
||||
"github.com/segmentfault/pacman/log"
|
||||
"time"
|
||||
)
|
||||
|
||||
func (ns *ExternalNotificationService) handleInviteAnswerNotification(ctx context.Context,
|
||||
msg *schema.ExternalNotificationMsg) error {
|
||||
log.Debugf("try to send invite answer notification %+v", msg)
|
||||
|
||||
notificationConfig, exist, err := ns.userNotificationConfigRepo.GetByUserIDAndSource(ctx, msg.ReceiverUserID, constant.InboxSource)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !exist {
|
||||
return nil
|
||||
}
|
||||
channels := schema.NewNotificationChannelsFormJson(notificationConfig.Channels)
|
||||
for _, channel := range channels {
|
||||
if !channel.Enable {
|
||||
continue
|
||||
}
|
||||
switch channel.Key {
|
||||
case constant.EmailChannel:
|
||||
ns.sendInviteAnswerNotificationEmail(ctx, msg.ReceiverUserID, msg.ReceiverEmail, msg.ReceiverLang, msg.NewInviteAnswerTemplateRawData)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ns *ExternalNotificationService) sendInviteAnswerNotificationEmail(ctx context.Context,
|
||||
userID, email, lang string, rawData *schema.NewInviteAnswerTemplateRawData) {
|
||||
codeContent := &schema.EmailCodeContent{
|
||||
SourceType: schema.UnsubscribeSourceType,
|
||||
NotificationSources: []constant.NotificationSource{
|
||||
constant.InboxSource,
|
||||
},
|
||||
Email: email,
|
||||
UserID: userID,
|
||||
}
|
||||
|
||||
// If receiver has set language, use it to send email.
|
||||
if len(lang) > 0 {
|
||||
ctx = context.WithValue(ctx, constant.AcceptLanguageFlag, i18n.Language(lang))
|
||||
}
|
||||
title, body, err := ns.emailService.NewInviteAnswerTemplate(ctx, rawData)
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
ns.emailService.SendAndSaveCodeWithTime(
|
||||
ctx, email, title, body, rawData.UnsubscribeCode, codeContent.ToJSONString(), 1*24*time.Hour)
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
package notification
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/answerdev/answer/internal/base/constant"
|
||||
"github.com/answerdev/answer/internal/schema"
|
||||
"github.com/segmentfault/pacman/i18n"
|
||||
"github.com/segmentfault/pacman/log"
|
||||
"time"
|
||||
)
|
||||
|
||||
func (ns *ExternalNotificationService) handleNewAnswerNotification(ctx context.Context,
|
||||
msg *schema.ExternalNotificationMsg) error {
|
||||
log.Debugf("try to send new comment notification %+v", msg)
|
||||
|
||||
notificationConfig, exist, err := ns.userNotificationConfigRepo.GetByUserIDAndSource(ctx, msg.ReceiverUserID, constant.InboxSource)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !exist {
|
||||
return nil
|
||||
}
|
||||
channels := schema.NewNotificationChannelsFormJson(notificationConfig.Channels)
|
||||
for _, channel := range channels {
|
||||
if !channel.Enable {
|
||||
continue
|
||||
}
|
||||
switch channel.Key {
|
||||
case constant.EmailChannel:
|
||||
ns.sendNewAnswerNotificationEmail(ctx, msg.ReceiverUserID, msg.ReceiverEmail, msg.ReceiverLang, msg.NewAnswerTemplateRawData)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ns *ExternalNotificationService) sendNewAnswerNotificationEmail(ctx context.Context,
|
||||
userID, email, lang string, rawData *schema.NewAnswerTemplateRawData) {
|
||||
codeContent := &schema.EmailCodeContent{
|
||||
SourceType: schema.UnsubscribeSourceType,
|
||||
NotificationSources: []constant.NotificationSource{
|
||||
constant.InboxSource,
|
||||
},
|
||||
Email: email,
|
||||
UserID: userID,
|
||||
}
|
||||
|
||||
// If receiver has set language, use it to send email.
|
||||
if len(lang) > 0 {
|
||||
ctx = context.WithValue(ctx, constant.AcceptLanguageFlag, i18n.Language(lang))
|
||||
}
|
||||
title, body, err := ns.emailService.NewAnswerTemplate(ctx, rawData)
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
ns.emailService.SendAndSaveCodeWithTime(
|
||||
ctx, email, title, body, rawData.UnsubscribeCode, codeContent.ToJSONString(), 1*24*time.Hour)
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
package notification
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/answerdev/answer/internal/base/constant"
|
||||
"github.com/answerdev/answer/internal/schema"
|
||||
"github.com/segmentfault/pacman/i18n"
|
||||
"github.com/segmentfault/pacman/log"
|
||||
"time"
|
||||
)
|
||||
|
||||
func (ns *ExternalNotificationService) handleNewCommentNotification(ctx context.Context,
|
||||
msg *schema.ExternalNotificationMsg) error {
|
||||
log.Debugf("try to send new comment notification %+v", msg)
|
||||
|
||||
notificationConfig, exist, err := ns.userNotificationConfigRepo.GetByUserIDAndSource(ctx, msg.ReceiverUserID, constant.InboxSource)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !exist {
|
||||
return nil
|
||||
}
|
||||
channels := schema.NewNotificationChannelsFormJson(notificationConfig.Channels)
|
||||
for _, channel := range channels {
|
||||
if !channel.Enable {
|
||||
continue
|
||||
}
|
||||
switch channel.Key {
|
||||
case constant.EmailChannel:
|
||||
ns.sendNewCommentNotificationEmail(ctx, msg.ReceiverUserID, msg.ReceiverEmail, msg.ReceiverLang, msg.NewCommentTemplateRawData)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ns *ExternalNotificationService) sendNewCommentNotificationEmail(ctx context.Context,
|
||||
userID, email, lang string, rawData *schema.NewCommentTemplateRawData) {
|
||||
codeContent := &schema.EmailCodeContent{
|
||||
SourceType: schema.UnsubscribeSourceType,
|
||||
NotificationSources: []constant.NotificationSource{
|
||||
constant.InboxSource,
|
||||
},
|
||||
Email: email,
|
||||
UserID: userID,
|
||||
}
|
||||
// If receiver has set language, use it to send email.
|
||||
if len(lang) > 0 {
|
||||
ctx = context.WithValue(ctx, constant.AcceptLanguageFlag, i18n.Language(lang))
|
||||
}
|
||||
title, body, err := ns.emailService.NewCommentTemplate(ctx, rawData)
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
ns.emailService.SendAndSaveCodeWithTime(
|
||||
ctx, email, title, body, rawData.UnsubscribeCode, codeContent.ToJSONString(), 1*24*time.Hour)
|
||||
}
|
|
@ -0,0 +1,141 @@
|
|||
package notification
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/answerdev/answer/internal/base/constant"
|
||||
"github.com/answerdev/answer/internal/schema"
|
||||
"github.com/segmentfault/pacman/i18n"
|
||||
"github.com/segmentfault/pacman/log"
|
||||
"time"
|
||||
)
|
||||
|
||||
type NewQuestionSubscriber struct {
|
||||
UserID string `json:"user_id"`
|
||||
Channels schema.NotificationChannels `json:"channels"`
|
||||
}
|
||||
|
||||
func (ns *ExternalNotificationService) handleNewQuestionNotification(ctx context.Context,
|
||||
msg *schema.ExternalNotificationMsg) error {
|
||||
log.Debugf("try to send new question notification %+v", msg)
|
||||
subscribers, err := ns.getNewQuestionSubscribers(ctx, msg)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
log.Debugf("get subscribers %d for question %s", len(subscribers), msg.NewQuestionTemplateRawData.QuestionID)
|
||||
|
||||
for _, subscriber := range subscribers {
|
||||
for _, channel := range subscriber.Channels {
|
||||
if !channel.Enable {
|
||||
continue
|
||||
}
|
||||
switch channel.Key {
|
||||
case constant.EmailChannel:
|
||||
ns.sendNewQuestionNotificationEmail(ctx, subscriber.UserID, &schema.NewQuestionTemplateRawData{
|
||||
QuestionTitle: msg.NewQuestionTemplateRawData.QuestionTitle,
|
||||
QuestionID: msg.NewQuestionTemplateRawData.QuestionID,
|
||||
Tags: msg.NewQuestionTemplateRawData.Tags,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ns *ExternalNotificationService) getNewQuestionSubscribers(ctx context.Context, msg *schema.ExternalNotificationMsg) (
|
||||
subscribers []*NewQuestionSubscriber, err error) {
|
||||
subscribersMapping := make(map[string]*NewQuestionSubscriber)
|
||||
|
||||
// 1. get all this new question's tags followers
|
||||
tagsFollowerIDs := make([]string, 0)
|
||||
followerMapping := make(map[string]bool)
|
||||
for _, tagID := range msg.NewQuestionTemplateRawData.TagIDs {
|
||||
userIDs, err := ns.followRepo.GetFollowUserIDs(ctx, tagID)
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
continue
|
||||
}
|
||||
for _, userID := range userIDs {
|
||||
if _, ok := followerMapping[userID]; ok {
|
||||
continue
|
||||
}
|
||||
followerMapping[userID] = true
|
||||
tagsFollowerIDs = append(tagsFollowerIDs, userID)
|
||||
}
|
||||
}
|
||||
userNotificationConfigs, err := ns.userNotificationConfigRepo.GetByUsersAndSource(
|
||||
ctx, tagsFollowerIDs, constant.AllNewQuestionForFollowingTagsSource)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, userNotificationConfig := range userNotificationConfigs {
|
||||
if _, ok := subscribersMapping[userNotificationConfig.UserID]; ok {
|
||||
continue
|
||||
}
|
||||
subscribersMapping[userNotificationConfig.UserID] = &NewQuestionSubscriber{
|
||||
UserID: userNotificationConfig.UserID,
|
||||
Channels: schema.NewNotificationChannelsFormJson(userNotificationConfig.Channels),
|
||||
}
|
||||
subscribers = append(subscribers, subscribersMapping[userNotificationConfig.UserID])
|
||||
}
|
||||
log.Debugf("get %d subscribers from tags", len(subscribersMapping))
|
||||
|
||||
// 2. get all new question's followers
|
||||
notificationConfigs, err := ns.userNotificationConfigRepo.GetBySource(ctx, constant.AllNewQuestionSource)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, notificationConfig := range notificationConfigs {
|
||||
if _, ok := subscribersMapping[notificationConfig.UserID]; ok {
|
||||
continue
|
||||
}
|
||||
if ns.checkSendNewQuestionNotificationEmailLimit(ctx, notificationConfig.UserID) {
|
||||
continue
|
||||
}
|
||||
subscribersMapping[notificationConfig.UserID] = &NewQuestionSubscriber{
|
||||
UserID: notificationConfig.UserID,
|
||||
Channels: schema.NewNotificationChannelsFormJson(notificationConfig.Channels),
|
||||
}
|
||||
subscribers = append(subscribers, subscribersMapping[notificationConfig.UserID])
|
||||
}
|
||||
log.Debugf("get %d subscribers from all new question config", len(subscribers))
|
||||
return subscribers, nil
|
||||
}
|
||||
|
||||
func (ns *ExternalNotificationService) checkSendNewQuestionNotificationEmailLimit(ctx context.Context, userID string) bool {
|
||||
// TODO: check if reach send limit
|
||||
return false
|
||||
}
|
||||
|
||||
func (ns *ExternalNotificationService) sendNewQuestionNotificationEmail(ctx context.Context,
|
||||
userID string, rawData *schema.NewQuestionTemplateRawData) {
|
||||
userInfo, exist, err := ns.userRepo.GetByUserID(ctx, userID)
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
return
|
||||
}
|
||||
if !exist {
|
||||
log.Errorf("user %s not exist", userID)
|
||||
return
|
||||
}
|
||||
// If receiver has set language, use it to send email.
|
||||
if len(userInfo.Language) > 0 {
|
||||
ctx = context.WithValue(ctx, constant.AcceptLanguageFlag, i18n.Language(userInfo.Language))
|
||||
}
|
||||
title, body, err := ns.emailService.NewQuestionTemplate(ctx, rawData)
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
codeContent := &schema.EmailCodeContent{
|
||||
SourceType: schema.UnsubscribeSourceType,
|
||||
Email: userInfo.EMail,
|
||||
UserID: userID,
|
||||
NotificationSources: []constant.NotificationSource{
|
||||
constant.AllNewQuestionSource,
|
||||
constant.AllNewQuestionForFollowingTagsSource,
|
||||
},
|
||||
}
|
||||
ns.emailService.SendAndSaveCodeWithTime(
|
||||
ctx, userInfo.EMail, title, body, rawData.UnsubscribeCode, codeContent.ToJSONString(), 1*24*time.Hour)
|
||||
}
|
|
@ -37,6 +37,7 @@ import (
|
|||
"github.com/answerdev/answer/internal/service/user_admin"
|
||||
usercommon "github.com/answerdev/answer/internal/service/user_common"
|
||||
"github.com/answerdev/answer/internal/service/user_external_login"
|
||||
"github.com/answerdev/answer/internal/service/user_notification_config"
|
||||
"github.com/google/wire"
|
||||
)
|
||||
|
||||
|
@ -90,4 +91,7 @@ var ProviderSetService = wire.NewSet(
|
|||
config.NewConfigService,
|
||||
notice_queue.NewNotificationQueueService,
|
||||
activity_queue.NewActivityQueueService,
|
||||
user_notification_config.NewUserNotificationConfigService,
|
||||
notification.NewExternalNotificationService,
|
||||
notice_queue.NewNewQuestionNotificationQueueService,
|
||||
)
|
||||
|
|
|
@ -3,6 +3,7 @@ package service
|
|||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/answerdev/answer/internal/service/notification"
|
||||
"github.com/answerdev/answer/internal/service/siteinfo_common"
|
||||
"strings"
|
||||
"time"
|
||||
|
@ -32,7 +33,6 @@ import (
|
|||
"github.com/answerdev/answer/pkg/uid"
|
||||
"github.com/jinzhu/copier"
|
||||
"github.com/segmentfault/pacman/errors"
|
||||
"github.com/segmentfault/pacman/i18n"
|
||||
"github.com/segmentfault/pacman/log"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
@ -41,19 +41,21 @@ import (
|
|||
|
||||
// QuestionService user service
|
||||
type QuestionService struct {
|
||||
questionRepo questioncommon.QuestionRepo
|
||||
tagCommon *tagcommon.TagCommonService
|
||||
questioncommon *questioncommon.QuestionCommon
|
||||
userCommon *usercommon.UserCommon
|
||||
userRepo usercommon.UserRepo
|
||||
revisionService *revision_common.RevisionService
|
||||
metaService *meta.MetaService
|
||||
collectionCommon *collectioncommon.CollectionCommon
|
||||
answerActivityService *activity.AnswerActivityService
|
||||
emailService *export.EmailService
|
||||
notificationQueueService notice_queue.NotificationQueueService
|
||||
activityQueueService activity_queue.ActivityQueueService
|
||||
siteInfoService siteinfo_common.SiteInfoCommonService
|
||||
questionRepo questioncommon.QuestionRepo
|
||||
tagCommon *tagcommon.TagCommonService
|
||||
questioncommon *questioncommon.QuestionCommon
|
||||
userCommon *usercommon.UserCommon
|
||||
userRepo usercommon.UserRepo
|
||||
revisionService *revision_common.RevisionService
|
||||
metaService *meta.MetaService
|
||||
collectionCommon *collectioncommon.CollectionCommon
|
||||
answerActivityService *activity.AnswerActivityService
|
||||
emailService *export.EmailService
|
||||
notificationQueueService notice_queue.NotificationQueueService
|
||||
externalNotificationQueueService notice_queue.ExternalNotificationQueueService
|
||||
activityQueueService activity_queue.ActivityQueueService
|
||||
siteInfoService siteinfo_common.SiteInfoCommonService
|
||||
newQuestionNotificationService *notification.ExternalNotificationService
|
||||
}
|
||||
|
||||
func NewQuestionService(
|
||||
|
@ -68,23 +70,27 @@ func NewQuestionService(
|
|||
answerActivityService *activity.AnswerActivityService,
|
||||
emailService *export.EmailService,
|
||||
notificationQueueService notice_queue.NotificationQueueService,
|
||||
externalNotificationQueueService notice_queue.ExternalNotificationQueueService,
|
||||
activityQueueService activity_queue.ActivityQueueService,
|
||||
siteInfoService siteinfo_common.SiteInfoCommonService,
|
||||
newQuestionNotificationService *notification.ExternalNotificationService,
|
||||
) *QuestionService {
|
||||
return &QuestionService{
|
||||
questionRepo: questionRepo,
|
||||
tagCommon: tagCommon,
|
||||
questioncommon: questioncommon,
|
||||
userCommon: userCommon,
|
||||
userRepo: userRepo,
|
||||
revisionService: revisionService,
|
||||
metaService: metaService,
|
||||
collectionCommon: collectionCommon,
|
||||
answerActivityService: answerActivityService,
|
||||
emailService: emailService,
|
||||
notificationQueueService: notificationQueueService,
|
||||
activityQueueService: activityQueueService,
|
||||
siteInfoService: siteInfoService,
|
||||
questionRepo: questionRepo,
|
||||
tagCommon: tagCommon,
|
||||
questioncommon: questioncommon,
|
||||
userCommon: userCommon,
|
||||
userRepo: userRepo,
|
||||
revisionService: revisionService,
|
||||
metaService: metaService,
|
||||
collectionCommon: collectionCommon,
|
||||
answerActivityService: answerActivityService,
|
||||
emailService: emailService,
|
||||
notificationQueueService: notificationQueueService,
|
||||
externalNotificationQueueService: externalNotificationQueueService,
|
||||
activityQueueService: activityQueueService,
|
||||
siteInfoService: siteInfoService,
|
||||
newQuestionNotificationService: newQuestionNotificationService,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -241,12 +247,12 @@ func (qs *QuestionService) AddQuestion(ctx context.Context, req *schema.Question
|
|||
tag.SlugName = strings.ReplaceAll(tag.SlugName, " ", "-")
|
||||
tagNameList = append(tagNameList, tag.SlugName)
|
||||
}
|
||||
Tags, tagerr := qs.tagCommon.GetTagListByNames(ctx, tagNameList)
|
||||
tags, tagerr := qs.tagCommon.GetTagListByNames(ctx, tagNameList)
|
||||
if tagerr != nil {
|
||||
return questionInfo, tagerr
|
||||
}
|
||||
if !req.QuestionPermission.CanUseReservedTag {
|
||||
taglist, err := qs.AddQuestionCheckTags(ctx, Tags)
|
||||
taglist, err := qs.AddQuestionCheckTags(ctx, tags)
|
||||
errMsg := fmt.Sprintf(`"%s" can only be used by moderators.`,
|
||||
strings.Join(taglist, ","))
|
||||
if err != nil {
|
||||
|
@ -296,7 +302,7 @@ func (qs *QuestionService) AddQuestion(ctx context.Context, req *schema.Question
|
|||
Title: question.Title,
|
||||
}
|
||||
|
||||
questionWithTagsRevision, err := qs.changeQuestionToRevision(ctx, question, Tags)
|
||||
questionWithTagsRevision, err := qs.changeQuestionToRevision(ctx, question, tags)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -326,6 +332,9 @@ func (qs *QuestionService) AddQuestion(ctx context.Context, req *schema.Question
|
|||
RevisionID: revisionID,
|
||||
})
|
||||
|
||||
qs.externalNotificationQueueService.Send(ctx,
|
||||
schema.CreateNewQuestionNotificationMsg(question.ID, question.Title, tags))
|
||||
|
||||
questionInfo, err = qs.GetQuestion(ctx, question.ID, question.UserID, req.QuestionPermission)
|
||||
return
|
||||
}
|
||||
|
@ -640,39 +649,24 @@ func (qs *QuestionService) notificationInviteUser(
|
|||
msg.NotificationAction = constant.NotificationInvitedYouToAnswer
|
||||
qs.notificationQueueService.Send(ctx, msg)
|
||||
|
||||
userInfo, ok := invitee[userID]
|
||||
receiverUserInfo, ok := invitee[userID]
|
||||
if !ok {
|
||||
log.Warnf("user %s not found", userID)
|
||||
return
|
||||
}
|
||||
if userInfo.NoticeStatus == schema.NoticeStatusOff || len(userInfo.EMail) == 0 {
|
||||
return
|
||||
externalNotificationMsg := &schema.ExternalNotificationMsg{
|
||||
ReceiverUserID: receiverUserInfo.ID,
|
||||
ReceiverEmail: receiverUserInfo.EMail,
|
||||
ReceiverLang: receiverUserInfo.Language,
|
||||
}
|
||||
|
||||
rawData := &schema.NewInviteAnswerTemplateRawData{
|
||||
InviterDisplayName: inviter.DisplayName,
|
||||
QuestionTitle: questionTitle,
|
||||
QuestionID: questionID,
|
||||
UnsubscribeCode: encryption.MD5(userInfo.Pass),
|
||||
UnsubscribeCode: encryption.MD5(receiverUserInfo.Pass),
|
||||
}
|
||||
codeContent := &schema.EmailCodeContent{
|
||||
SourceType: schema.UnsubscribeSourceType,
|
||||
Email: userInfo.EMail,
|
||||
UserID: userInfo.ID,
|
||||
}
|
||||
|
||||
// If receiver has set language, use it to send email.
|
||||
if len(userInfo.Language) > 0 {
|
||||
ctx = context.WithValue(ctx, constant.AcceptLanguageFlag, i18n.Language(userInfo.Language))
|
||||
}
|
||||
title, body, err := qs.emailService.NewInviteAnswerTemplate(ctx, rawData)
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
go qs.emailService.SendAndSaveCodeWithTime(
|
||||
ctx, userInfo.EMail, title, body, rawData.UnsubscribeCode, codeContent.ToJSONString(), 7*24*time.Hour)
|
||||
externalNotificationMsg.NewInviteAnswerTemplateRawData = rawData
|
||||
qs.externalNotificationQueueService.Send(ctx, externalNotificationMsg)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,99 @@
|
|||
package user_notification_config
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/answerdev/answer/internal/base/constant"
|
||||
"github.com/answerdev/answer/internal/entity"
|
||||
"github.com/answerdev/answer/internal/schema"
|
||||
usercommon "github.com/answerdev/answer/internal/service/user_common"
|
||||
)
|
||||
|
||||
type UserNotificationConfigRepo interface {
|
||||
Save(ctx context.Context, uc *entity.UserNotificationConfig) (err error)
|
||||
GetByUserID(ctx context.Context, userID string) ([]*entity.UserNotificationConfig, error)
|
||||
GetBySource(ctx context.Context, source constant.NotificationSource) ([]*entity.UserNotificationConfig, error)
|
||||
GetByUserIDAndSource(ctx context.Context, userID string, source constant.NotificationSource) (
|
||||
conf *entity.UserNotificationConfig, exist bool, err error)
|
||||
GetByUsersAndSource(ctx context.Context, userIDs []string, source constant.NotificationSource) (
|
||||
[]*entity.UserNotificationConfig, error)
|
||||
}
|
||||
|
||||
type UserNotificationConfigService struct {
|
||||
userRepo usercommon.UserRepo
|
||||
userNotificationConfigRepo UserNotificationConfigRepo
|
||||
}
|
||||
|
||||
func NewUserNotificationConfigService(
|
||||
userRepo usercommon.UserRepo,
|
||||
userNotificationConfigRepo UserNotificationConfigRepo,
|
||||
) *UserNotificationConfigService {
|
||||
return &UserNotificationConfigService{
|
||||
userRepo: userRepo,
|
||||
userNotificationConfigRepo: userNotificationConfigRepo,
|
||||
}
|
||||
}
|
||||
|
||||
func (us *UserNotificationConfigService) GetUserNotificationConfig(ctx context.Context, userID string) (
|
||||
resp *schema.GetUserNotificationConfigResp, err error) {
|
||||
notificationConfigs, err := us.userNotificationConfigRepo.GetByUserID(ctx, userID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp = &schema.GetUserNotificationConfigResp{}
|
||||
resp.NotificationConfig = schema.NewNotificationConfig(notificationConfigs)
|
||||
resp.Format()
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
func (us *UserNotificationConfigService) UpdateUserNotificationConfig(
|
||||
ctx context.Context, req *schema.UpdateUserNotificationConfigReq) (err error) {
|
||||
req.NotificationConfig.Format()
|
||||
|
||||
err = us.userNotificationConfigRepo.Save(ctx,
|
||||
us.convertToEntity(ctx, req.UserID, constant.InboxSource, req.NotificationConfig.Inbox))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = us.userNotificationConfigRepo.Save(ctx,
|
||||
us.convertToEntity(ctx, req.UserID, constant.AllNewQuestionSource, req.NotificationConfig.AllNewQuestion))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = us.userNotificationConfigRepo.Save(ctx,
|
||||
us.convertToEntity(ctx, req.UserID, constant.AllNewQuestionForFollowingTagsSource,
|
||||
req.NotificationConfig.AllNewQuestionForFollowingTags))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (us *UserNotificationConfigService) convertToEntity(ctx context.Context, userID string,
|
||||
source constant.NotificationSource, channels schema.NotificationChannels) (c *entity.UserNotificationConfig) {
|
||||
c = &entity.UserNotificationConfig{
|
||||
UserID: userID,
|
||||
Source: string(source),
|
||||
Channels: channels.ToJsonString(),
|
||||
}
|
||||
for _, ch := range channels {
|
||||
if ch.Enable {
|
||||
c.Enabled = true
|
||||
break
|
||||
}
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
func (us *UserNotificationConfigService) CheckEnable(
|
||||
ctx context.Context, userID string, source constant.NotificationSource,
|
||||
channel constant.NotificationChannelKey) (enable bool, err error) {
|
||||
conf, exist, err := us.userNotificationConfigRepo.GetByUserIDAndSource(ctx, userID, source)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if !exist {
|
||||
return false, nil
|
||||
}
|
||||
notificationChannels := schema.NewNotificationChannelsFormJson(conf.Channels)
|
||||
return notificationChannels.CheckEnable(channel), nil
|
||||
}
|
|
@ -4,6 +4,8 @@ import (
|
|||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/answerdev/answer/internal/base/constant"
|
||||
"github.com/answerdev/answer/internal/service/user_notification_config"
|
||||
"time"
|
||||
|
||||
"github.com/answerdev/answer/internal/base/handler"
|
||||
|
@ -28,19 +30,18 @@ import (
|
|||
"golang.org/x/crypto/bcrypt"
|
||||
)
|
||||
|
||||
// UserRepo user repository
|
||||
|
||||
// UserService user service
|
||||
type UserService struct {
|
||||
userCommonService *usercommon.UserCommon
|
||||
userRepo usercommon.UserRepo
|
||||
userActivity activity.UserActiveActivityRepo
|
||||
activityRepo activity_common.ActivityRepo
|
||||
emailService *export.EmailService
|
||||
authService *auth.AuthService
|
||||
siteInfoService siteinfo_common.SiteInfoCommonService
|
||||
userRoleService *role.UserRoleRelService
|
||||
userExternalLoginService *user_external_login.UserExternalLoginService
|
||||
userCommonService *usercommon.UserCommon
|
||||
userRepo usercommon.UserRepo
|
||||
userActivity activity.UserActiveActivityRepo
|
||||
activityRepo activity_common.ActivityRepo
|
||||
emailService *export.EmailService
|
||||
authService *auth.AuthService
|
||||
siteInfoService siteinfo_common.SiteInfoCommonService
|
||||
userRoleService *role.UserRoleRelService
|
||||
userExternalLoginService *user_external_login.UserExternalLoginService
|
||||
userNotificationConfigRepo user_notification_config.UserNotificationConfigRepo
|
||||
}
|
||||
|
||||
func NewUserService(userRepo usercommon.UserRepo,
|
||||
|
@ -52,17 +53,19 @@ func NewUserService(userRepo usercommon.UserRepo,
|
|||
userRoleService *role.UserRoleRelService,
|
||||
userCommonService *usercommon.UserCommon,
|
||||
userExternalLoginService *user_external_login.UserExternalLoginService,
|
||||
userNotificationConfigRepo user_notification_config.UserNotificationConfigRepo,
|
||||
) *UserService {
|
||||
return &UserService{
|
||||
userCommonService: userCommonService,
|
||||
userRepo: userRepo,
|
||||
userActivity: userActivity,
|
||||
activityRepo: activityRepo,
|
||||
emailService: emailService,
|
||||
authService: authService,
|
||||
siteInfoService: siteInfoService,
|
||||
userRoleService: userRoleService,
|
||||
userExternalLoginService: userExternalLoginService,
|
||||
userCommonService: userCommonService,
|
||||
userRepo: userRepo,
|
||||
userActivity: userActivity,
|
||||
activityRepo: activityRepo,
|
||||
emailService: emailService,
|
||||
authService: authService,
|
||||
siteInfoService: siteInfoService,
|
||||
userRoleService: userRoleService,
|
||||
userExternalLoginService: userExternalLoginService,
|
||||
userNotificationConfigRepo: userNotificationConfigRepo,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -93,8 +96,7 @@ func (us *UserService) GetUserInfoByUserID(ctx context.Context, token, userID st
|
|||
}
|
||||
|
||||
func (us *UserService) GetOtherUserInfoByUsername(ctx context.Context, username string) (
|
||||
resp *schema.GetOtherUserInfoByUsernameResp, err error,
|
||||
) {
|
||||
resp *schema.GetOtherUserInfoByUsernameResp, err error) {
|
||||
userInfo, exist, err := us.userRepo.GetByUsername(ctx, username)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -345,14 +347,6 @@ func (us *UserService) formatUserInfoForUpdateInfo(
|
|||
return userInfo
|
||||
}
|
||||
|
||||
func (us *UserService) UserEmailHas(ctx context.Context, email string) (bool, error) {
|
||||
_, has, err := us.userRepo.GetByEmail(ctx, email)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
return has, nil
|
||||
}
|
||||
|
||||
// UserUpdateInterface update user interface
|
||||
func (us *UserService) UserUpdateInterface(ctx context.Context, req *schema.UpdateUserInterfaceRequest) (err error) {
|
||||
if !translator.CheckLanguageIsValid(req.Language) {
|
||||
|
@ -470,25 +464,6 @@ func (us *UserService) UserVerifyEmailSend(ctx context.Context, userID string) e
|
|||
return nil
|
||||
}
|
||||
|
||||
func (us *UserService) UserNoticeSet(ctx context.Context, userID string, noticeSwitch bool) (
|
||||
resp *schema.UserNoticeSetResp, err error,
|
||||
) {
|
||||
userInfo, has, err := us.userRepo.GetByUserID(ctx, userID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !has {
|
||||
return nil, errors.BadRequest(reason.UserNotFound)
|
||||
}
|
||||
if noticeSwitch {
|
||||
userInfo.NoticeStatus = schema.NoticeStatusOn
|
||||
} else {
|
||||
userInfo.NoticeStatus = schema.NoticeStatusOff
|
||||
}
|
||||
err = us.userRepo.UpdateNoticeStatus(ctx, userInfo.ID, userInfo.NoticeStatus)
|
||||
return &schema.UserNoticeSetResp{NoticeSwitch: noticeSwitch}, err
|
||||
}
|
||||
|
||||
func (us *UserService) UserVerifyEmail(ctx context.Context, req *schema.UserVerifyEmailReq) (resp *schema.UserLoginResp, err error) {
|
||||
data := &schema.EmailCodeContent{}
|
||||
err = data.FromJSONString(req.Content)
|
||||
|
@ -720,23 +695,37 @@ func (us *UserService) UserRanking(ctx context.Context) (resp *schema.UserRankin
|
|||
return us.warpStatRankingResp(userInfoMapping, rankStat, voteStat, userRoleRels), nil
|
||||
}
|
||||
|
||||
// UserUnsubscribeEmailNotification user unsubscribe email notification
|
||||
func (us *UserService) UserUnsubscribeEmailNotification(
|
||||
ctx context.Context, req *schema.UserUnsubscribeEmailNotificationReq) (err error) {
|
||||
// UserUnsubscribeNotification user unsubscribe email notification
|
||||
func (us *UserService) UserUnsubscribeNotification(
|
||||
ctx context.Context, req *schema.UserUnsubscribeNotificationReq) (err error) {
|
||||
data := &schema.EmailCodeContent{}
|
||||
err = data.FromJSONString(req.Content)
|
||||
if err != nil || len(data.UserID) == 0 {
|
||||
return errors.BadRequest(reason.EmailVerifyURLExpired)
|
||||
}
|
||||
|
||||
userInfo, exist, err := us.userRepo.GetByUserID(ctx, data.UserID)
|
||||
if err != nil {
|
||||
return err
|
||||
for _, source := range data.NotificationSources {
|
||||
notificationConfig, exist, err := us.userNotificationConfigRepo.GetByUserIDAndSource(
|
||||
ctx, data.UserID, source)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !exist {
|
||||
continue
|
||||
}
|
||||
channels := schema.NewNotificationChannelsFormJson(notificationConfig.Channels)
|
||||
// unsubscribe email notification
|
||||
for _, channel := range channels {
|
||||
if channel.Key == constant.EmailChannel {
|
||||
channel.Enable = false
|
||||
}
|
||||
}
|
||||
notificationConfig.Channels = channels.ToJsonString()
|
||||
if err = us.userNotificationConfigRepo.Save(ctx, notificationConfig); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if !exist {
|
||||
return errors.BadRequest(reason.UserNotFound)
|
||||
}
|
||||
return us.userRepo.UpdateNoticeStatus(ctx, userInfo.ID, schema.NoticeStatusOff)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (us *UserService) getActivityUserRankStat(ctx context.Context, startTime, endTime time.Time, limit int,
|
||||
|
|
Loading…
Reference in New Issue