Simplified emailing system and combined mailer and notifications packages

This commit is contained in:
Torkel Ödegaard 2015-06-08 16:51:25 +02:00
parent c8bc0b3bf8
commit 42fc68baa5
6 changed files with 54 additions and 66 deletions

View File

@ -15,7 +15,6 @@ import (
"github.com/grafana/grafana/pkg/metrics" "github.com/grafana/grafana/pkg/metrics"
"github.com/grafana/grafana/pkg/plugins" "github.com/grafana/grafana/pkg/plugins"
"github.com/grafana/grafana/pkg/services/eventpublisher" "github.com/grafana/grafana/pkg/services/eventpublisher"
"github.com/grafana/grafana/pkg/services/mailer"
"github.com/grafana/grafana/pkg/services/notifications" "github.com/grafana/grafana/pkg/services/notifications"
"github.com/grafana/grafana/pkg/services/search" "github.com/grafana/grafana/pkg/services/search"
"github.com/grafana/grafana/pkg/services/sqlstore" "github.com/grafana/grafana/pkg/services/sqlstore"
@ -58,7 +57,6 @@ func main() {
social.NewOAuthService() social.NewOAuthService()
eventpublisher.Init() eventpublisher.Init()
plugins.Init() plugins.Init()
mailer.Init()
if err := notifications.Init(); err != nil { if err := notifications.Init(); err != nil {
log.Fatal(3, "Notification service failed to initialize", err) log.Fatal(3, "Notification service failed to initialize", err)

View File

@ -5,12 +5,11 @@ import "errors"
var ErrInvalidEmailCode = errors.New("Invalid or expired email code") var ErrInvalidEmailCode = errors.New("Invalid or expired email code")
type SendEmailCommand struct { type SendEmailCommand struct {
To []string To []string
From string Template string
Subject string Data map[string]interface{}
Body string Massive bool
Massive bool Info string
Info string
} }
type SendResetPasswordEmailCommand struct { type SendResetPasswordEmailCommand struct {
@ -21,20 +20,3 @@ type ValidateResetPasswordCodeQuery struct {
Code string Code string
Result *User Result *User
} }
// create mail content
func (m *SendEmailCommand) Content() string {
contentType := "text/html; charset=UTF-8"
content := "From: " + m.From + "\r\nSubject: " + m.Subject + "\r\nContent-Type: " + contentType + "\r\n\r\n" + m.Body
return content
}
// Create html mail command
func NewSendEmailCommand(To []string, From, Subject, Body string) SendEmailCommand {
return SendEmailCommand{
To: To,
From: From,
Subject: Subject,
Body: Body,
}
}

View File

@ -5,18 +5,23 @@ import (
"github.com/grafana/grafana/pkg/setting" "github.com/grafana/grafana/pkg/setting"
) )
// Create New mail message use MailFrom and MailUser type Message struct {
func newMailMessageFrom(To []string, from, subject, body string) m.SendEmailCommand { To []string
return m.NewSendEmailCommand(To, from, subject, body) From string
Subject string
Body string
Massive bool
Info string
} }
// Create New mail message use MailFrom and MailUser // create mail content
func newMailMessage(To string, subject, body string) m.SendEmailCommand { func (m *Message) Content() string {
return newMailMessageFrom([]string{To}, setting.Smtp.FromAddress, subject, body) contentType := "text/html; charset=UTF-8"
content := "From: " + m.From + "\r\nSubject: " + m.Subject + "\r\nContent-Type: " + contentType + "\r\n\r\n" + m.Body
return content
} }
func getMailTmplData(u *m.User) map[interface{}]interface{} { func setDefaultTemplateData(data map[string]interface{}, u *m.User) {
data := make(map[interface{}]interface{}, 10)
data["AppUrl"] = setting.AppUrl data["AppUrl"] = setting.AppUrl
data["BuildVersion"] = setting.BuildVersion data["BuildVersion"] = setting.BuildVersion
data["BuildStamp"] = setting.BuildStamp data["BuildStamp"] = setting.BuildStamp
@ -25,5 +30,4 @@ func getMailTmplData(u *m.User) map[interface{}]interface{} {
if u != nil { if u != nil {
data["Name"] = u.NameOrFallback() data["Name"] = u.NameOrFallback()
} }
return data
} }

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a MIT-style // Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
package mailer package notifications
import ( import (
"crypto/tls" "crypto/tls"
@ -13,18 +13,14 @@ import (
"os" "os"
"strings" "strings"
"github.com/grafana/grafana/pkg/bus"
"github.com/grafana/grafana/pkg/log" "github.com/grafana/grafana/pkg/log"
m "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/setting" "github.com/grafana/grafana/pkg/setting"
) )
var mailQueue chan *m.SendEmailCommand var mailQueue chan *Message
func Init() { func initMailQueue() {
bus.AddHandler("email", handleEmailCommand) mailQueue = make(chan *Message, 10)
mailQueue = make(chan *m.SendEmailCommand, 10)
setting.Smtp = setting.SmtpSettings{ setting.Smtp = setting.SmtpSettings{
Host: "smtp.gmail.com:587", Host: "smtp.gmail.com:587",
@ -55,10 +51,8 @@ func processMailQueue() {
} }
} }
func handleEmailCommand(cmd *m.SendEmailCommand) error { var addToMailQueue = func(msg *Message) {
log.Info("Sending on queue") mailQueue <- msg
mailQueue <- cmd
return nil
} }
func sendToSmtpServer(recipients []string, msgContent []byte) error { func sendToSmtpServer(recipients []string, msgContent []byte) error {
@ -162,7 +156,7 @@ func sendToSmtpServer(recipients []string, msgContent []byte) error {
return client.Quit() return client.Quit()
} }
func buildAndSend(msg *m.SendEmailCommand) (int, error) { func buildAndSend(msg *Message) (int, error) {
log.Trace("Sending mails to: %s", strings.Join(msg.To, "; ")) log.Trace("Sending mails to: %s", strings.Join(msg.To, "; "))
// get message body // get message body

View File

@ -16,8 +16,11 @@ var mailTemplates *template.Template
var tmplResetPassword = "reset_password.html" var tmplResetPassword = "reset_password.html"
func Init() error { func Init() error {
initMailQueue()
bus.AddHandler("email", sendResetPasswordEmail) bus.AddHandler("email", sendResetPasswordEmail)
bus.AddHandler("email", validateResetPasswordCode) bus.AddHandler("email", validateResetPasswordCode)
bus.AddHandler("email", sendEmailCommandHandler)
mailTemplates = template.New("name") mailTemplates = template.New("name")
mailTemplates.Funcs(template.FuncMap{ mailTemplates.Funcs(template.FuncMap{
@ -41,26 +44,23 @@ func Init() error {
return nil return nil
} }
var dispatchMail = func(cmd *m.SendEmailCommand) error {
return bus.Dispatch(cmd)
}
func subjectTemplateFunc(obj map[string]interface{}, value string) string { func subjectTemplateFunc(obj map[string]interface{}, value string) string {
obj["value"] = value obj["value"] = value
return "" return ""
} }
func sendResetPasswordEmail(cmd *m.SendResetPasswordEmailCommand) error { func sendEmailCommandHandler(cmd *m.SendEmailCommand) error {
var buffer bytes.Buffer var buffer bytes.Buffer
data := cmd.Data
if data == nil {
data = make(map[string]interface{}, 10)
}
var data = getMailTmplData(cmd.User) setDefaultTemplateData(data, nil)
code := createUserEmailCode(cmd.User, nil) mailTemplates.ExecuteTemplate(&buffer, cmd.Template, data)
data["Code"] = code
mailTemplates.ExecuteTemplate(&buffer, tmplResetPassword, data) addToMailQueue(&Message{
To: cmd.To,
dispatchMail(&m.SendEmailCommand{
To: []string{cmd.User.Email},
From: setting.Smtp.FromAddress, From: setting.Smtp.FromAddress,
Subject: data["Subject"].(map[string]interface{})["value"].(string), Subject: data["Subject"].(map[string]interface{})["value"].(string),
Body: buffer.String(), Body: buffer.String(),
@ -69,6 +69,17 @@ func sendResetPasswordEmail(cmd *m.SendResetPasswordEmailCommand) error {
return nil return nil
} }
func sendResetPasswordEmail(cmd *m.SendResetPasswordEmailCommand) error {
return sendEmailCommandHandler(&m.SendEmailCommand{
To: []string{cmd.User.Email},
Template: tmplResetPassword,
Data: map[string]interface{}{
"Code": createUserEmailCode(cmd.User, nil),
"Name": cmd.User.NameOrFallback(),
},
})
}
func validateResetPasswordCode(query *m.ValidateResetPasswordCodeQuery) error { func validateResetPasswordCode(query *m.ValidateResetPasswordCodeQuery) error {
login := getLoginForEmailCode(query.Code) login := getLoginForEmailCode(query.Code)
if login == "" { if login == "" {

View File

@ -20,17 +20,16 @@ func TestNotifications(t *testing.T) {
err := Init() err := Init()
So(err, ShouldBeNil) So(err, ShouldBeNil)
var sentMail *m.SendEmailCommand var sentMsg *Message
dispatchMail = func(cmd *m.SendEmailCommand) error { addToMailQueue = func(msg *Message) {
sentMail = cmd sentMsg = msg
return nil
} }
Convey("When sending reset email password", func() { Convey("When sending reset email password", func() {
sendResetPasswordEmail(&m.SendResetPasswordEmailCommand{User: &m.User{Email: "asd@asd.com"}}) sendResetPasswordEmail(&m.SendResetPasswordEmailCommand{User: &m.User{Email: "asd@asd.com"}})
So(sentMail.Body, ShouldContainSubstring, "body") So(sentMsg.Body, ShouldContainSubstring, "body")
So(sentMail.Subject, ShouldEqual, "Reset your Grafana password") So(sentMsg.Subject, ShouldEqual, "Reset your Grafana password")
So(sentMail.Body, ShouldNotContainSubstring, "Subject") So(sentMsg.Body, ShouldNotContainSubstring, "Subject")
}) })
}) })