chore: move notifications models into notifications service (#61638)
This commit is contained in:
@@ -10,7 +10,6 @@ import (
|
||||
"html/template"
|
||||
"net/mail"
|
||||
|
||||
"github.com/grafana/grafana/pkg/models"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"github.com/prometheus/client_golang/prometheus/promauto"
|
||||
)
|
||||
@@ -54,9 +53,9 @@ func (ns *NotificationService) Send(msg *Message) (int, error) {
|
||||
return ns.mailer.Send(messages...)
|
||||
}
|
||||
|
||||
func (ns *NotificationService) buildEmailMessage(cmd *models.SendEmailCommand) (*Message, error) {
|
||||
func (ns *NotificationService) buildEmailMessage(cmd *SendEmailCommand) (*Message, error) {
|
||||
if !ns.Cfg.Smtp.Enabled {
|
||||
return nil, models.ErrSmtpNotEnabled
|
||||
return nil, ErrSmtpNotEnabled
|
||||
}
|
||||
|
||||
data := cmd.Data
|
||||
@@ -120,7 +119,7 @@ func (ns *NotificationService) buildEmailMessage(cmd *models.SendEmailCommand) (
|
||||
|
||||
// buildAttachedFiles build attached files
|
||||
func buildAttachedFiles(
|
||||
attached []*models.SendEmailAttachFile,
|
||||
attached []*SendEmailAttachFile,
|
||||
) []*AttachedFile {
|
||||
result := make([]*AttachedFile, 0)
|
||||
|
||||
|
||||
@@ -2,22 +2,20 @@ package notifications
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/grafana/grafana/pkg/models"
|
||||
)
|
||||
|
||||
type NotificationServiceMock struct {
|
||||
Webhook models.SendWebhookSync
|
||||
EmailSync models.SendEmailCommandSync
|
||||
Email models.SendEmailCommand
|
||||
Webhook SendWebhookSync
|
||||
EmailSync SendEmailCommandSync
|
||||
Email SendEmailCommand
|
||||
ShouldError error
|
||||
|
||||
WebhookHandler func(context.Context, *models.SendWebhookSync) error
|
||||
EmailHandlerSync func(context.Context, *models.SendEmailCommandSync) error
|
||||
EmailHandler func(context.Context, *models.SendEmailCommand) error
|
||||
WebhookHandler func(context.Context, *SendWebhookSync) error
|
||||
EmailHandlerSync func(context.Context, *SendEmailCommandSync) error
|
||||
EmailHandler func(context.Context, *SendEmailCommand) error
|
||||
}
|
||||
|
||||
func (ns *NotificationServiceMock) SendWebhookSync(ctx context.Context, cmd *models.SendWebhookSync) error {
|
||||
func (ns *NotificationServiceMock) SendWebhookSync(ctx context.Context, cmd *SendWebhookSync) error {
|
||||
ns.Webhook = *cmd
|
||||
if ns.WebhookHandler != nil {
|
||||
return ns.WebhookHandler(ctx, cmd)
|
||||
@@ -25,7 +23,7 @@ func (ns *NotificationServiceMock) SendWebhookSync(ctx context.Context, cmd *mod
|
||||
return ns.ShouldError
|
||||
}
|
||||
|
||||
func (ns *NotificationServiceMock) SendEmailCommandHandlerSync(ctx context.Context, cmd *models.SendEmailCommandSync) error {
|
||||
func (ns *NotificationServiceMock) SendEmailCommandHandlerSync(ctx context.Context, cmd *SendEmailCommandSync) error {
|
||||
ns.EmailSync = *cmd
|
||||
if ns.EmailHandlerSync != nil {
|
||||
return ns.EmailHandlerSync(ctx, cmd)
|
||||
@@ -33,7 +31,7 @@ func (ns *NotificationServiceMock) SendEmailCommandHandlerSync(ctx context.Conte
|
||||
return ns.ShouldError
|
||||
}
|
||||
|
||||
func (ns *NotificationServiceMock) SendEmailCommandHandler(ctx context.Context, cmd *models.SendEmailCommand) error {
|
||||
func (ns *NotificationServiceMock) SendEmailCommandHandler(ctx context.Context, cmd *SendEmailCommand) error {
|
||||
ns.Email = *cmd
|
||||
if ns.EmailHandler != nil {
|
||||
return ns.EmailHandler(ctx, cmd)
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
package notifications
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"github.com/grafana/grafana/pkg/services/user"
|
||||
)
|
||||
|
||||
var ErrInvalidEmailCode = errors.New("invalid or expired email code")
|
||||
var ErrSmtpNotEnabled = errors.New("SMTP not configured, check your grafana.ini config file's [smtp] section")
|
||||
|
||||
// SendEmailAttachFile is a definition of the attached files without path
|
||||
type SendEmailAttachFile struct {
|
||||
Name string
|
||||
Content []byte
|
||||
}
|
||||
|
||||
// SendEmailCommand is the command for sending emails
|
||||
type SendEmailCommand struct {
|
||||
To []string
|
||||
SingleEmail bool
|
||||
Template string
|
||||
Subject string
|
||||
Data map[string]interface{}
|
||||
Info string
|
||||
ReplyTo []string
|
||||
EmbeddedFiles []string
|
||||
AttachedFiles []*SendEmailAttachFile
|
||||
}
|
||||
|
||||
// SendEmailCommandSync is the command for sending emails synchronously
|
||||
type SendEmailCommandSync struct {
|
||||
SendEmailCommand
|
||||
}
|
||||
|
||||
type SendWebhookSync struct {
|
||||
Url string
|
||||
User string
|
||||
Password string
|
||||
Body string
|
||||
HttpMethod string
|
||||
HttpHeader map[string]string
|
||||
ContentType string
|
||||
Validation func(body []byte, statusCode int) error
|
||||
}
|
||||
|
||||
type SendResetPasswordEmailCommand struct {
|
||||
User *user.User
|
||||
}
|
||||
|
||||
type ValidateResetPasswordCodeQuery struct {
|
||||
Code string
|
||||
Result *user.User
|
||||
}
|
||||
@@ -10,10 +10,10 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/Masterminds/sprig/v3"
|
||||
|
||||
"github.com/grafana/grafana/pkg/bus"
|
||||
"github.com/grafana/grafana/pkg/events"
|
||||
"github.com/grafana/grafana/pkg/infra/log"
|
||||
"github.com/grafana/grafana/pkg/models"
|
||||
tempuser "github.com/grafana/grafana/pkg/services/temp_user"
|
||||
"github.com/grafana/grafana/pkg/services/user"
|
||||
"github.com/grafana/grafana/pkg/setting"
|
||||
@@ -21,11 +21,11 @@ import (
|
||||
)
|
||||
|
||||
type WebhookSender interface {
|
||||
SendWebhookSync(ctx context.Context, cmd *models.SendWebhookSync) error
|
||||
SendWebhookSync(ctx context.Context, cmd *SendWebhookSync) error
|
||||
}
|
||||
type EmailSender interface {
|
||||
SendEmailCommandHandlerSync(ctx context.Context, cmd *models.SendEmailCommandSync) error
|
||||
SendEmailCommandHandler(ctx context.Context, cmd *models.SendEmailCommand) error
|
||||
SendEmailCommandHandlerSync(ctx context.Context, cmd *SendEmailCommandSync) error
|
||||
SendEmailCommandHandler(ctx context.Context, cmd *SendEmailCommand) error
|
||||
}
|
||||
type Service interface {
|
||||
WebhookSender
|
||||
@@ -130,7 +130,7 @@ func (ns *NotificationService) GetMailer() Mailer {
|
||||
return ns.mailer
|
||||
}
|
||||
|
||||
func (ns *NotificationService) SendWebhookSync(ctx context.Context, cmd *models.SendWebhookSync) error {
|
||||
func (ns *NotificationService) SendWebhookSync(ctx context.Context, cmd *SendWebhookSync) error {
|
||||
return ns.sendWebRequestSync(ctx, &Webhook{
|
||||
Url: cmd.Url,
|
||||
User: cmd.User,
|
||||
@@ -148,8 +148,8 @@ func subjectTemplateFunc(obj map[string]interface{}, value string) string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (ns *NotificationService) SendEmailCommandHandlerSync(ctx context.Context, cmd *models.SendEmailCommandSync) error {
|
||||
message, err := ns.buildEmailMessage(&models.SendEmailCommand{
|
||||
func (ns *NotificationService) SendEmailCommandHandlerSync(ctx context.Context, cmd *SendEmailCommandSync) error {
|
||||
message, err := ns.buildEmailMessage(&SendEmailCommand{
|
||||
Data: cmd.Data,
|
||||
Info: cmd.Info,
|
||||
Template: cmd.Template,
|
||||
@@ -169,7 +169,7 @@ func (ns *NotificationService) SendEmailCommandHandlerSync(ctx context.Context,
|
||||
return err
|
||||
}
|
||||
|
||||
func (ns *NotificationService) SendEmailCommandHandler(ctx context.Context, cmd *models.SendEmailCommand) error {
|
||||
func (ns *NotificationService) SendEmailCommandHandler(ctx context.Context, cmd *SendEmailCommand) error {
|
||||
message, err := ns.buildEmailMessage(cmd)
|
||||
|
||||
if err != nil {
|
||||
@@ -180,12 +180,12 @@ func (ns *NotificationService) SendEmailCommandHandler(ctx context.Context, cmd
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ns *NotificationService) SendResetPasswordEmail(ctx context.Context, cmd *models.SendResetPasswordEmailCommand) error {
|
||||
func (ns *NotificationService) SendResetPasswordEmail(ctx context.Context, cmd *SendResetPasswordEmailCommand) error {
|
||||
code, err := createUserEmailCode(ns.Cfg, cmd.User, "")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return ns.SendEmailCommandHandler(ctx, &models.SendEmailCommand{
|
||||
return ns.SendEmailCommandHandler(ctx, &SendEmailCommand{
|
||||
To: []string{cmd.User.Email},
|
||||
Template: tmplResetPassword,
|
||||
Data: map[string]interface{}{
|
||||
@@ -197,10 +197,10 @@ func (ns *NotificationService) SendResetPasswordEmail(ctx context.Context, cmd *
|
||||
|
||||
type GetUserByLoginFunc = func(c context.Context, login string) (*user.User, error)
|
||||
|
||||
func (ns *NotificationService) ValidateResetPasswordCode(ctx context.Context, query *models.ValidateResetPasswordCodeQuery, userByLogin GetUserByLoginFunc) error {
|
||||
func (ns *NotificationService) ValidateResetPasswordCode(ctx context.Context, query *ValidateResetPasswordCodeQuery, userByLogin GetUserByLoginFunc) error {
|
||||
login := getLoginForEmailCode(query.Code)
|
||||
if login == "" {
|
||||
return models.ErrInvalidEmailCode
|
||||
return ErrInvalidEmailCode
|
||||
}
|
||||
|
||||
user, err := userByLogin(ctx, login)
|
||||
@@ -213,7 +213,7 @@ func (ns *NotificationService) ValidateResetPasswordCode(ctx context.Context, qu
|
||||
return err
|
||||
}
|
||||
if !validEmailCode {
|
||||
return models.ErrInvalidEmailCode
|
||||
return ErrInvalidEmailCode
|
||||
}
|
||||
|
||||
query.Result = user
|
||||
@@ -231,7 +231,7 @@ func (ns *NotificationService) signUpStartedHandler(ctx context.Context, evt *ev
|
||||
return nil
|
||||
}
|
||||
|
||||
err := ns.SendEmailCommandHandler(ctx, &models.SendEmailCommand{
|
||||
err := ns.SendEmailCommandHandler(ctx, &SendEmailCommand{
|
||||
To: []string{evt.Email},
|
||||
Template: tmplSignUpStarted,
|
||||
Data: map[string]interface{}{
|
||||
@@ -254,7 +254,7 @@ func (ns *NotificationService) signUpCompletedHandler(ctx context.Context, evt *
|
||||
return nil
|
||||
}
|
||||
|
||||
return ns.SendEmailCommandHandler(ctx, &models.SendEmailCommand{
|
||||
return ns.SendEmailCommandHandler(ctx, &SendEmailCommand{
|
||||
To: []string{evt.Email},
|
||||
Template: tmplWelcomeOnSignUp,
|
||||
Data: map[string]interface{}{
|
||||
|
||||
@@ -5,13 +5,13 @@ import (
|
||||
"regexp"
|
||||
"testing"
|
||||
|
||||
"github.com/grafana/grafana/pkg/bus"
|
||||
"github.com/grafana/grafana/pkg/infra/tracing"
|
||||
"github.com/grafana/grafana/pkg/models"
|
||||
"github.com/grafana/grafana/pkg/services/user"
|
||||
"github.com/grafana/grafana/pkg/setting"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/grafana/grafana/pkg/bus"
|
||||
"github.com/grafana/grafana/pkg/infra/tracing"
|
||||
"github.com/grafana/grafana/pkg/services/user"
|
||||
"github.com/grafana/grafana/pkg/setting"
|
||||
)
|
||||
|
||||
func newBus(t *testing.T) bus.Bus {
|
||||
@@ -53,8 +53,8 @@ func TestSendEmailSync(t *testing.T) {
|
||||
|
||||
t.Run("When sending emails synchronously", func(t *testing.T) {
|
||||
ns, mailer := createSut(t, bus)
|
||||
cmd := &models.SendEmailCommandSync{
|
||||
SendEmailCommand: models.SendEmailCommand{
|
||||
cmd := &SendEmailCommandSync{
|
||||
SendEmailCommand: SendEmailCommand{
|
||||
Subject: "subject",
|
||||
To: []string{"asdf@grafana.com"},
|
||||
SingleEmail: false,
|
||||
@@ -72,8 +72,8 @@ func TestSendEmailSync(t *testing.T) {
|
||||
|
||||
t.Run("When using Single Email mode with multiple recipients", func(t *testing.T) {
|
||||
ns, mailer := createSut(t, bus)
|
||||
cmd := &models.SendEmailCommandSync{
|
||||
SendEmailCommand: models.SendEmailCommand{
|
||||
cmd := &SendEmailCommandSync{
|
||||
SendEmailCommand: SendEmailCommand{
|
||||
Subject: "subject",
|
||||
To: []string{"1@grafana.com", "2@grafana.com", "3@grafana.com"},
|
||||
SingleEmail: true,
|
||||
@@ -89,8 +89,8 @@ func TestSendEmailSync(t *testing.T) {
|
||||
|
||||
t.Run("When using Multi Email mode with multiple recipients", func(t *testing.T) {
|
||||
ns, mailer := createSut(t, bus)
|
||||
cmd := &models.SendEmailCommandSync{
|
||||
SendEmailCommand: models.SendEmailCommand{
|
||||
cmd := &SendEmailCommandSync{
|
||||
SendEmailCommand: SendEmailCommand{
|
||||
Subject: "subject",
|
||||
To: []string{"1@grafana.com", "2@grafana.com", "3@grafana.com"},
|
||||
SingleEmail: false,
|
||||
@@ -106,13 +106,13 @@ func TestSendEmailSync(t *testing.T) {
|
||||
|
||||
t.Run("When attaching files to emails", func(t *testing.T) {
|
||||
ns, mailer := createSut(t, bus)
|
||||
cmd := &models.SendEmailCommandSync{
|
||||
SendEmailCommand: models.SendEmailCommand{
|
||||
cmd := &SendEmailCommandSync{
|
||||
SendEmailCommand: SendEmailCommand{
|
||||
Subject: "subject",
|
||||
To: []string{"asdf@grafana.com"},
|
||||
SingleEmail: true,
|
||||
Template: "welcome_on_signup",
|
||||
AttachedFiles: []*models.SendEmailAttachFile{
|
||||
AttachedFiles: []*SendEmailAttachFile{
|
||||
{
|
||||
Name: "attachment.txt",
|
||||
Content: []byte("text file content"),
|
||||
@@ -137,8 +137,8 @@ func TestSendEmailSync(t *testing.T) {
|
||||
cfg.Smtp.Enabled = false
|
||||
ns, mailer, err := createSutWithConfig(t, bus, cfg)
|
||||
require.NoError(t, err)
|
||||
cmd := &models.SendEmailCommandSync{
|
||||
SendEmailCommand: models.SendEmailCommand{
|
||||
cmd := &SendEmailCommandSync{
|
||||
SendEmailCommand: SendEmailCommand{
|
||||
Subject: "subject",
|
||||
To: []string{"1@grafana.com", "2@grafana.com", "3@grafana.com"},
|
||||
SingleEmail: true,
|
||||
@@ -148,7 +148,7 @@ func TestSendEmailSync(t *testing.T) {
|
||||
|
||||
err = ns.SendEmailCommandHandlerSync(context.Background(), cmd)
|
||||
|
||||
require.ErrorIs(t, err, models.ErrSmtpNotEnabled)
|
||||
require.ErrorIs(t, err, ErrSmtpNotEnabled)
|
||||
require.Empty(t, mailer.Sent)
|
||||
})
|
||||
|
||||
@@ -157,8 +157,8 @@ func TestSendEmailSync(t *testing.T) {
|
||||
cfg.Smtp.ContentTypes = append(cfg.Smtp.ContentTypes, "multipart/form-data")
|
||||
ns, mailer, err := createSutWithConfig(t, bus, cfg)
|
||||
require.NoError(t, err)
|
||||
cmd := &models.SendEmailCommandSync{
|
||||
SendEmailCommand: models.SendEmailCommand{
|
||||
cmd := &SendEmailCommandSync{
|
||||
SendEmailCommand: SendEmailCommand{
|
||||
Subject: "subject",
|
||||
To: []string{"1@grafana.com", "2@grafana.com", "3@grafana.com"},
|
||||
SingleEmail: false,
|
||||
@@ -174,8 +174,8 @@ func TestSendEmailSync(t *testing.T) {
|
||||
|
||||
t.Run("When SMTP dialer is disconnected", func(t *testing.T) {
|
||||
ns := createDisconnectedSut(t, bus)
|
||||
cmd := &models.SendEmailCommandSync{
|
||||
SendEmailCommand: models.SendEmailCommand{
|
||||
cmd := &SendEmailCommandSync{
|
||||
SendEmailCommand: SendEmailCommand{
|
||||
Subject: "subject",
|
||||
To: []string{"1@grafana.com", "2@grafana.com", "3@grafana.com"},
|
||||
SingleEmail: false,
|
||||
@@ -195,7 +195,7 @@ func TestSendEmailAsync(t *testing.T) {
|
||||
t.Run("When sending reset email password", func(t *testing.T) {
|
||||
sut, _ := createSut(t, bus)
|
||||
testuser := user.User{Email: "asd@asd.com", Login: "asd@asd.com"}
|
||||
err := sut.SendResetPasswordEmail(context.Background(), &models.SendResetPasswordEmailCommand{User: &testuser})
|
||||
err := sut.SendResetPasswordEmail(context.Background(), &SendResetPasswordEmailCommand{User: &testuser})
|
||||
|
||||
require.NoError(t, err)
|
||||
|
||||
@@ -212,7 +212,7 @@ func TestSendEmailAsync(t *testing.T) {
|
||||
code := match[len("code="):]
|
||||
|
||||
// verify code
|
||||
query := models.ValidateResetPasswordCodeQuery{Code: code}
|
||||
query := ValidateResetPasswordCodeQuery{Code: code}
|
||||
getUserByLogin := func(ctx context.Context, login string) (*user.User, error) {
|
||||
return &testuser, nil
|
||||
}
|
||||
@@ -225,7 +225,7 @@ func TestSendEmailAsync(t *testing.T) {
|
||||
cfg.Smtp.Enabled = false
|
||||
ns, mailer, err := createSutWithConfig(t, bus, cfg)
|
||||
require.NoError(t, err)
|
||||
cmd := &models.SendEmailCommand{
|
||||
cmd := &SendEmailCommand{
|
||||
Subject: "subject",
|
||||
To: []string{"1@grafana.com", "2@grafana.com", "3@grafana.com"},
|
||||
SingleEmail: true,
|
||||
@@ -234,7 +234,7 @@ func TestSendEmailAsync(t *testing.T) {
|
||||
|
||||
err = ns.SendEmailCommandHandler(context.Background(), cmd)
|
||||
|
||||
require.ErrorIs(t, err, models.ErrSmtpNotEnabled)
|
||||
require.ErrorIs(t, err, ErrSmtpNotEnabled)
|
||||
require.Empty(t, mailer.Sent)
|
||||
})
|
||||
|
||||
@@ -243,7 +243,7 @@ func TestSendEmailAsync(t *testing.T) {
|
||||
cfg.Smtp.ContentTypes = append(cfg.Smtp.ContentTypes, "multipart/form-data")
|
||||
ns, mailer, err := createSutWithConfig(t, bus, cfg)
|
||||
require.NoError(t, err)
|
||||
cmd := &models.SendEmailCommand{
|
||||
cmd := &SendEmailCommand{
|
||||
Subject: "subject",
|
||||
To: []string{"1@grafana.com", "2@grafana.com", "3@grafana.com"},
|
||||
SingleEmail: false,
|
||||
@@ -258,7 +258,7 @@ func TestSendEmailAsync(t *testing.T) {
|
||||
|
||||
t.Run("When SMTP dialer is disconnected", func(t *testing.T) {
|
||||
ns := createDisconnectedSut(t, bus)
|
||||
cmd := &models.SendEmailCommand{
|
||||
cmd := &SendEmailCommand{
|
||||
Subject: "subject",
|
||||
To: []string{"1@grafana.com", "2@grafana.com", "3@grafana.com"},
|
||||
SingleEmail: false,
|
||||
|
||||
@@ -5,7 +5,6 @@ import (
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/grafana/grafana/pkg/models"
|
||||
"github.com/grafana/grafana/pkg/setting"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
@@ -28,7 +27,7 @@ func TestEmailIntegrationTest(t *testing.T) {
|
||||
ns.Cfg.Smtp.ContentTypes = []string{"text/html", "text/plain"}
|
||||
|
||||
t.Run("When sending reset email password", func(t *testing.T) {
|
||||
cmd := &models.SendEmailCommand{
|
||||
cmd := &SendEmailCommand{
|
||||
|
||||
Data: map[string]interface{}{
|
||||
"Title": "[CRITICAL] Imaginary timeseries alert",
|
||||
|
||||
Reference in New Issue
Block a user