|
|
|
@ -7,11 +7,13 @@ import ( |
|
|
|
|
"html/template" |
|
|
|
|
"net/url" |
|
|
|
|
"path/filepath" |
|
|
|
|
"strings" |
|
|
|
|
|
|
|
|
|
"github.com/grafana/grafana/pkg/bus" |
|
|
|
|
"github.com/grafana/grafana/pkg/events" |
|
|
|
|
"github.com/grafana/grafana/pkg/log" |
|
|
|
|
m "github.com/grafana/grafana/pkg/models" |
|
|
|
|
"github.com/grafana/grafana/pkg/registry" |
|
|
|
|
"github.com/grafana/grafana/pkg/setting" |
|
|
|
|
"github.com/grafana/grafana/pkg/util" |
|
|
|
|
) |
|
|
|
@ -21,20 +23,31 @@ var tmplResetPassword = "reset_password.html" |
|
|
|
|
var tmplSignUpStarted = "signup_started.html" |
|
|
|
|
var tmplWelcomeOnSignUp = "welcome_on_signup.html" |
|
|
|
|
|
|
|
|
|
func Init() error { |
|
|
|
|
initMailQueue() |
|
|
|
|
initWebhookQueue() |
|
|
|
|
func init() { |
|
|
|
|
registry.RegisterService(&NotificationService{}) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
type NotificationService struct { |
|
|
|
|
Bus bus.Bus `inject:""` |
|
|
|
|
mailQueue chan *Message |
|
|
|
|
webhookQueue chan *Webhook |
|
|
|
|
log log.Logger |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
bus.AddHandler("email", sendResetPasswordEmail) |
|
|
|
|
bus.AddHandler("email", validateResetPasswordCode) |
|
|
|
|
bus.AddHandler("email", sendEmailCommandHandler) |
|
|
|
|
func (ns *NotificationService) Init() error { |
|
|
|
|
ns.log = log.New("notifications") |
|
|
|
|
ns.mailQueue = make(chan *Message, 10) |
|
|
|
|
ns.webhookQueue = make(chan *Webhook, 10) |
|
|
|
|
|
|
|
|
|
bus.AddCtxHandler("email", sendEmailCommandHandlerSync) |
|
|
|
|
ns.Bus.AddHandler(ns.sendResetPasswordEmail) |
|
|
|
|
ns.Bus.AddHandler(ns.validateResetPasswordCode) |
|
|
|
|
ns.Bus.AddHandler(ns.sendEmailCommandHandler) |
|
|
|
|
|
|
|
|
|
bus.AddCtxHandler("webhook", SendWebhookSync) |
|
|
|
|
ns.Bus.AddCtxHandler(ns.sendEmailCommandHandlerSync) |
|
|
|
|
ns.Bus.AddCtxHandler(ns.SendWebhookSync) |
|
|
|
|
|
|
|
|
|
bus.AddEventListener(signUpStartedHandler) |
|
|
|
|
bus.AddEventListener(signUpCompletedHandler) |
|
|
|
|
ns.Bus.AddEventListener(ns.signUpStartedHandler) |
|
|
|
|
ns.Bus.AddEventListener(ns.signUpCompletedHandler) |
|
|
|
|
|
|
|
|
|
mailTemplates = template.New("name") |
|
|
|
|
mailTemplates.Funcs(template.FuncMap{ |
|
|
|
@ -58,8 +71,37 @@ func Init() error { |
|
|
|
|
return nil |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func SendWebhookSync(ctx context.Context, cmd *m.SendWebhookSync) error { |
|
|
|
|
return sendWebRequestSync(ctx, &Webhook{ |
|
|
|
|
func (ns *NotificationService) Run(ctx context.Context) error { |
|
|
|
|
for { |
|
|
|
|
select { |
|
|
|
|
case webhook := <-ns.webhookQueue: |
|
|
|
|
err := ns.sendWebRequestSync(context.Background(), webhook) |
|
|
|
|
|
|
|
|
|
if err != nil { |
|
|
|
|
ns.log.Error("Failed to send webrequest ", "error", err) |
|
|
|
|
} |
|
|
|
|
case msg := <-ns.mailQueue: |
|
|
|
|
num, err := send(msg) |
|
|
|
|
tos := strings.Join(msg.To, "; ") |
|
|
|
|
info := "" |
|
|
|
|
if err != nil { |
|
|
|
|
if len(msg.Info) > 0 { |
|
|
|
|
info = ", info: " + msg.Info |
|
|
|
|
} |
|
|
|
|
ns.log.Error(fmt.Sprintf("Async sent email %d succeed, not send emails: %s%s err: %s", num, tos, info, err)) |
|
|
|
|
} else { |
|
|
|
|
ns.log.Debug(fmt.Sprintf("Async sent email %d succeed, sent emails: %s%s", num, tos, info)) |
|
|
|
|
} |
|
|
|
|
case <-ctx.Done(): |
|
|
|
|
return ctx.Err() |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return nil |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func (ns *NotificationService) SendWebhookSync(ctx context.Context, cmd *m.SendWebhookSync) error { |
|
|
|
|
return ns.sendWebRequestSync(ctx, &Webhook{ |
|
|
|
|
Url: cmd.Url, |
|
|
|
|
User: cmd.User, |
|
|
|
|
Password: cmd.Password, |
|
|
|
@ -74,7 +116,7 @@ func subjectTemplateFunc(obj map[string]interface{}, value string) string { |
|
|
|
|
return "" |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func sendEmailCommandHandlerSync(ctx context.Context, cmd *m.SendEmailCommandSync) error { |
|
|
|
|
func (ns *NotificationService) sendEmailCommandHandlerSync(ctx context.Context, cmd *m.SendEmailCommandSync) error { |
|
|
|
|
message, err := buildEmailMessage(&m.SendEmailCommand{ |
|
|
|
|
Data: cmd.Data, |
|
|
|
|
Info: cmd.Info, |
|
|
|
@ -89,24 +131,22 @@ func sendEmailCommandHandlerSync(ctx context.Context, cmd *m.SendEmailCommandSyn |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
_, err = send(message) |
|
|
|
|
|
|
|
|
|
return err |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func sendEmailCommandHandler(cmd *m.SendEmailCommand) error { |
|
|
|
|
func (ns *NotificationService) sendEmailCommandHandler(cmd *m.SendEmailCommand) error { |
|
|
|
|
message, err := buildEmailMessage(cmd) |
|
|
|
|
|
|
|
|
|
if err != nil { |
|
|
|
|
return err |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
addToMailQueue(message) |
|
|
|
|
|
|
|
|
|
ns.mailQueue <- message |
|
|
|
|
return nil |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func sendResetPasswordEmail(cmd *m.SendResetPasswordEmailCommand) error { |
|
|
|
|
return sendEmailCommandHandler(&m.SendEmailCommand{ |
|
|
|
|
func (ns *NotificationService) sendResetPasswordEmail(cmd *m.SendResetPasswordEmailCommand) error { |
|
|
|
|
return ns.sendEmailCommandHandler(&m.SendEmailCommand{ |
|
|
|
|
To: []string{cmd.User.Email}, |
|
|
|
|
Template: tmplResetPassword, |
|
|
|
|
Data: map[string]interface{}{ |
|
|
|
@ -116,7 +156,7 @@ func sendResetPasswordEmail(cmd *m.SendResetPasswordEmailCommand) error { |
|
|
|
|
}) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func validateResetPasswordCode(query *m.ValidateResetPasswordCodeQuery) error { |
|
|
|
|
func (ns *NotificationService) validateResetPasswordCode(query *m.ValidateResetPasswordCodeQuery) error { |
|
|
|
|
login := getLoginForEmailCode(query.Code) |
|
|
|
|
if login == "" { |
|
|
|
|
return m.ErrInvalidEmailCode |
|
|
|
@ -135,18 +175,18 @@ func validateResetPasswordCode(query *m.ValidateResetPasswordCodeQuery) error { |
|
|
|
|
return nil |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func signUpStartedHandler(evt *events.SignUpStarted) error { |
|
|
|
|
func (ns *NotificationService) signUpStartedHandler(evt *events.SignUpStarted) error { |
|
|
|
|
if !setting.VerifyEmailEnabled { |
|
|
|
|
return nil |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
log.Info("User signup started: %s", evt.Email) |
|
|
|
|
ns.log.Info("User signup started", "email", evt.Email) |
|
|
|
|
|
|
|
|
|
if evt.Email == "" { |
|
|
|
|
return nil |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
err := sendEmailCommandHandler(&m.SendEmailCommand{ |
|
|
|
|
err := ns.sendEmailCommandHandler(&m.SendEmailCommand{ |
|
|
|
|
To: []string{evt.Email}, |
|
|
|
|
Template: tmplSignUpStarted, |
|
|
|
|
Data: map[string]interface{}{ |
|
|
|
@ -155,6 +195,7 @@ func signUpStartedHandler(evt *events.SignUpStarted) error { |
|
|
|
|
"SignUpUrl": setting.ToAbsUrl(fmt.Sprintf("signup/?email=%s&code=%s", url.QueryEscape(evt.Email), url.QueryEscape(evt.Code))), |
|
|
|
|
}, |
|
|
|
|
}) |
|
|
|
|
|
|
|
|
|
if err != nil { |
|
|
|
|
return err |
|
|
|
|
} |
|
|
|
@ -163,12 +204,12 @@ func signUpStartedHandler(evt *events.SignUpStarted) error { |
|
|
|
|
return bus.Dispatch(&emailSentCmd) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func signUpCompletedHandler(evt *events.SignUpCompleted) error { |
|
|
|
|
func (ns *NotificationService) signUpCompletedHandler(evt *events.SignUpCompleted) error { |
|
|
|
|
if evt.Email == "" || !setting.Smtp.SendWelcomeEmailOnSignUp { |
|
|
|
|
return nil |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return sendEmailCommandHandler(&m.SendEmailCommand{ |
|
|
|
|
return ns.sendEmailCommandHandler(&m.SendEmailCommand{ |
|
|
|
|
To: []string{evt.Email}, |
|
|
|
|
Template: tmplWelcomeOnSignUp, |
|
|
|
|
Data: map[string]interface{}{ |
|
|
|
|