mirror of
https://github.com/teamhanko/hanko.git
synced 2025-10-27 22:27:23 +08:00
[FEAT] disable email delivery (#1419)
* feat: add config to disable email delivery * chore: update config schema * docs: add new config parameter * test: fix test * fix: rename email webhook event * docs: Update backend/docs/Config.md Co-authored-by: Lennart Fleischmann <67686424+lfleischmann@users.noreply.github.com> --------- Co-authored-by: Lennart Fleischmann <67686424+lfleischmann@users.noreply.github.com>
This commit is contained in:
@ -23,6 +23,7 @@ type Config struct {
|
|||||||
Server Server `yaml:"server" json:"server,omitempty" koanf:"server"`
|
Server Server `yaml:"server" json:"server,omitempty" koanf:"server"`
|
||||||
Webauthn WebauthnSettings `yaml:"webauthn" json:"webauthn,omitempty" koanf:"webauthn"`
|
Webauthn WebauthnSettings `yaml:"webauthn" json:"webauthn,omitempty" koanf:"webauthn"`
|
||||||
Smtp SMTP `yaml:"smtp" json:"smtp,omitempty" koanf:"smtp"`
|
Smtp SMTP `yaml:"smtp" json:"smtp,omitempty" koanf:"smtp"`
|
||||||
|
EmailDelivery EmailDelivery `yaml:"email_delivery" json:"email_delivery,omitempty" koanf:"email_delivery" split_words:"true"`
|
||||||
Passcode Passcode `yaml:"passcode" json:"passcode" koanf:"passcode"`
|
Passcode Passcode `yaml:"passcode" json:"passcode" koanf:"passcode"`
|
||||||
Password Password `yaml:"password" json:"password,omitempty" koanf:"password"`
|
Password Password `yaml:"password" json:"password,omitempty" koanf:"password"`
|
||||||
Database Database `yaml:"database" json:"database" koanf:"database"`
|
Database Database `yaml:"database" json:"database" koanf:"database"`
|
||||||
@ -118,6 +119,9 @@ func DefaultConfig() *Config {
|
|||||||
Smtp: SMTP{
|
Smtp: SMTP{
|
||||||
Port: "465",
|
Port: "465",
|
||||||
},
|
},
|
||||||
|
EmailDelivery: EmailDelivery{
|
||||||
|
Enabled: true,
|
||||||
|
},
|
||||||
Passcode: Passcode{
|
Passcode: Passcode{
|
||||||
TTL: 300,
|
TTL: 300,
|
||||||
Email: Email{
|
Email: Email{
|
||||||
@ -203,10 +207,12 @@ func (c *Config) Validate() error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to validate webauthn settings: %w", err)
|
return fmt.Errorf("failed to validate webauthn settings: %w", err)
|
||||||
}
|
}
|
||||||
|
if c.EmailDelivery.Enabled {
|
||||||
err = c.Smtp.Validate()
|
err = c.Smtp.Validate()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to validate smtp settings: %w", err)
|
return fmt.Errorf("failed to validate smtp settings: %w", err)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
err = c.Passcode.Validate()
|
err = c.Passcode.Validate()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to validate passcode settings: %w", err)
|
return fmt.Errorf("failed to validate passcode settings: %w", err)
|
||||||
@ -382,6 +388,10 @@ func (s *SMTP) Validate() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type EmailDelivery struct {
|
||||||
|
Enabled bool `yaml:"enabled" json:"enabled" koanf:"enabled" jsonschema:"default=true"`
|
||||||
|
}
|
||||||
|
|
||||||
type Email struct {
|
type Email struct {
|
||||||
FromAddress string `yaml:"from_address" json:"from_address,omitempty" koanf:"from_address" split_words:"true" jsonschema:"default=passcode@hanko.io"`
|
FromAddress string `yaml:"from_address" json:"from_address,omitempty" koanf:"from_address" split_words:"true" jsonschema:"default=passcode@hanko.io"`
|
||||||
FromName string `yaml:"from_name" json:"from_name,omitempty" koanf:"from_name" split_words:"true" jsonschema:"default=Hanko"`
|
FromName string `yaml:"from_name" json:"from_name,omitempty" koanf:"from_name" split_words:"true" jsonschema:"default=Hanko"`
|
||||||
@ -688,6 +698,9 @@ func (c *Config) PostProcess() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *Config) arrangeSmtpSettings() {
|
func (c *Config) arrangeSmtpSettings() {
|
||||||
|
if !c.EmailDelivery.Enabled {
|
||||||
|
return
|
||||||
|
}
|
||||||
if c.Passcode.Smtp.Validate() == nil {
|
if c.Passcode.Smtp.Validate() == nil {
|
||||||
if c.Smtp.Validate() == nil {
|
if c.Smtp.Validate() == nil {
|
||||||
zeroLogger.Warn().Msg("Both root smtp and passcode.smtp are set. Using smtp settings from root configuration")
|
zeroLogger.Warn().Msg("Both root smtp and passcode.smtp are set. Using smtp settings from root configuration")
|
||||||
|
|||||||
@ -300,6 +300,18 @@ webauthn:
|
|||||||
origins:
|
origins:
|
||||||
- "android:apk-key-hash:nLSu7wVTbnMOxLgC52f2faTnv..."
|
- "android:apk-key-hash:nLSu7wVTbnMOxLgC52f2faTnv..."
|
||||||
- "https://login.example.com"
|
- "https://login.example.com"
|
||||||
|
## email_delivery ##
|
||||||
|
#
|
||||||
|
# Settings needed for email delivery.
|
||||||
|
#
|
||||||
|
email_delivery:
|
||||||
|
## enabled ##
|
||||||
|
#
|
||||||
|
# Enable or disable email delivery by hanko. Disable if you want to send the emails yourself. To send emails yourself you must subscribe to the `email.create` webhook event.
|
||||||
|
#
|
||||||
|
# Default: true
|
||||||
|
#
|
||||||
|
enabled: true
|
||||||
## audit_log ##
|
## audit_log ##
|
||||||
#
|
#
|
||||||
# Configures audit logging
|
# Configures audit logging
|
||||||
@ -1011,4 +1023,10 @@ webhooks:
|
|||||||
# Email - Triggers on: change of primary email
|
# Email - Triggers on: change of primary email
|
||||||
#
|
#
|
||||||
- user.update.email.primary
|
- user.update.email.primary
|
||||||
|
##
|
||||||
|
#
|
||||||
|
# Triggers on: an email was sent or should be sent
|
||||||
|
#
|
||||||
|
- email.send
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|||||||
26
backend/dto/webhook/email.go
Normal file
26
backend/dto/webhook/email.go
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
package webhook
|
||||||
|
|
||||||
|
type EmailSend struct {
|
||||||
|
Subject string `json:"subject"` // subject
|
||||||
|
BodyPlain string `json:"body_plain"` // used for string templates
|
||||||
|
Body string `json:"body,omitempty"` // used for html templates
|
||||||
|
ToEmailAddress string `json:"to_email_address"`
|
||||||
|
DeliveredByHanko bool `json:"delivered_by_hanko"`
|
||||||
|
AcceptLanguage string `json:"accept_language"` // accept_language header from http request
|
||||||
|
Type EmailType `json:"type"` // type of the email, currently only "passcode", but other could be added later
|
||||||
|
|
||||||
|
Data interface{} `json:"data"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type PasscodeData struct {
|
||||||
|
ServiceName string `json:"service_name"`
|
||||||
|
OtpCode string `json:"otp_code"`
|
||||||
|
TTL int `json:"ttl"`
|
||||||
|
ValidUntil int64 `json:"valid_until"` // UnixTimestamp
|
||||||
|
}
|
||||||
|
|
||||||
|
type EmailType string
|
||||||
|
|
||||||
|
var (
|
||||||
|
EmailTypePasscode EmailType = "passcode"
|
||||||
|
)
|
||||||
@ -144,7 +144,7 @@ func (h *EmailHandler) Create(c echo.Context) error {
|
|||||||
var evt events.Event
|
var evt events.Event
|
||||||
|
|
||||||
if len(user.Emails) >= 1 {
|
if len(user.Emails) >= 1 {
|
||||||
evt = events.EmailCreate
|
evt = events.UserEmailCreate
|
||||||
} else {
|
} else {
|
||||||
evt = events.UserCreate
|
evt = events.UserCreate
|
||||||
}
|
}
|
||||||
@ -212,7 +212,7 @@ func (h *EmailHandler) SetPrimaryEmail(c echo.Context) error {
|
|||||||
return fmt.Errorf("failed to create audit log: %w", err)
|
return fmt.Errorf("failed to create audit log: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
utils.NotifyUserChange(c, tx, h.persister, events.EmailPrimary, userId)
|
utils.NotifyUserChange(c, tx, h.persister, events.UserEmailPrimary, userId)
|
||||||
|
|
||||||
return c.NoContent(http.StatusNoContent)
|
return c.NoContent(http.StatusNoContent)
|
||||||
})
|
})
|
||||||
@ -256,7 +256,7 @@ func (h *EmailHandler) Delete(c echo.Context) error {
|
|||||||
return fmt.Errorf("failed to create audit log: %w", err)
|
return fmt.Errorf("failed to create audit log: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
utils.NotifyUserChange(c, tx, h.persister, events.EmailDelete, userId)
|
utils.NotifyUserChange(c, tx, h.persister, events.UserEmailDelete, userId)
|
||||||
|
|
||||||
return c.NoContent(http.StatusNoContent)
|
return c.NoContent(http.StatusNoContent)
|
||||||
})
|
})
|
||||||
|
|||||||
@ -150,7 +150,7 @@ func (h *emailAdminHandler) Create(ctx echo.Context) error {
|
|||||||
err = h.persister.GetPrimaryEmailPersisterWithConnection(tx).Create(*primaryEmail)
|
err = h.persister.GetPrimaryEmailPersisterWithConnection(tx).Create(*primaryEmail)
|
||||||
}
|
}
|
||||||
|
|
||||||
utils.NotifyUserChange(ctx, tx, h.persister, events.EmailCreate, userId)
|
utils.NotifyUserChange(ctx, tx, h.persister, events.UserEmailCreate, userId)
|
||||||
|
|
||||||
return ctx.JSON(http.StatusCreated, admin.FromEmailModel(email))
|
return ctx.JSON(http.StatusCreated, admin.FromEmailModel(email))
|
||||||
})
|
})
|
||||||
@ -229,7 +229,7 @@ func (h *emailAdminHandler) Delete(ctx echo.Context) error {
|
|||||||
return fmt.Errorf("failed to delete email from db: %w", err)
|
return fmt.Errorf("failed to delete email from db: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
utils.NotifyUserChange(ctx, tx, h.persister, events.EmailDelete, userId)
|
utils.NotifyUserChange(ctx, tx, h.persister, events.UserEmailDelete, userId)
|
||||||
|
|
||||||
return ctx.NoContent(http.StatusNoContent)
|
return ctx.NoContent(http.StatusNoContent)
|
||||||
})
|
})
|
||||||
@ -275,7 +275,7 @@ func (h *emailAdminHandler) SetPrimaryEmail(ctx echo.Context) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
utils.NotifyUserChange(ctx, tx, h.persister, events.EmailPrimary, userId)
|
utils.NotifyUserChange(ctx, tx, h.persister, events.UserEmailPrimary, userId)
|
||||||
|
|
||||||
return ctx.NoContent(http.StatusNoContent)
|
return ctx.NoContent(http.StatusNoContent)
|
||||||
})
|
})
|
||||||
|
|||||||
@ -7,11 +7,13 @@ import (
|
|||||||
"github.com/gofrs/uuid"
|
"github.com/gofrs/uuid"
|
||||||
"github.com/labstack/echo/v4"
|
"github.com/labstack/echo/v4"
|
||||||
"github.com/lestrrat-go/jwx/v2/jwt"
|
"github.com/lestrrat-go/jwx/v2/jwt"
|
||||||
|
zeroLogger "github.com/rs/zerolog/log"
|
||||||
"github.com/sethvargo/go-limiter"
|
"github.com/sethvargo/go-limiter"
|
||||||
"github.com/teamhanko/hanko/backend/audit_log"
|
"github.com/teamhanko/hanko/backend/audit_log"
|
||||||
"github.com/teamhanko/hanko/backend/config"
|
"github.com/teamhanko/hanko/backend/config"
|
||||||
"github.com/teamhanko/hanko/backend/crypto"
|
"github.com/teamhanko/hanko/backend/crypto"
|
||||||
"github.com/teamhanko/hanko/backend/dto"
|
"github.com/teamhanko/hanko/backend/dto"
|
||||||
|
"github.com/teamhanko/hanko/backend/dto/webhook"
|
||||||
"github.com/teamhanko/hanko/backend/mail"
|
"github.com/teamhanko/hanko/backend/mail"
|
||||||
"github.com/teamhanko/hanko/backend/persistence"
|
"github.com/teamhanko/hanko/backend/persistence"
|
||||||
"github.com/teamhanko/hanko/backend/persistence/models"
|
"github.com/teamhanko/hanko/backend/persistence/models"
|
||||||
@ -189,24 +191,55 @@ func (h *PasscodeHandler) Init(c echo.Context) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
lang := c.Request().Header.Get("Accept-Language")
|
lang := c.Request().Header.Get("Accept-Language")
|
||||||
str, err := h.renderer.Render("loginTextMail", lang, data)
|
subject := h.renderer.Translate(lang, "email_subject_login", data)
|
||||||
|
bodyPlain, err := h.renderer.Render("loginTextMail", lang, data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to render email template: %w", err)
|
return fmt.Errorf("failed to render email template: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
webhookData := webhook.EmailSend{
|
||||||
|
Subject: subject,
|
||||||
|
BodyPlain: bodyPlain,
|
||||||
|
ToEmailAddress: email.Address,
|
||||||
|
DeliveredByHanko: true,
|
||||||
|
AcceptLanguage: lang,
|
||||||
|
Type: webhook.EmailTypePasscode,
|
||||||
|
Data: webhook.PasscodeData{
|
||||||
|
ServiceName: h.cfg.Service.Name,
|
||||||
|
OtpCode: passcode,
|
||||||
|
TTL: h.TTL,
|
||||||
|
ValidUntil: passcodeModel.CreatedAt.Add(time.Duration(h.TTL) * time.Second).UTC().Unix(),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
if h.cfg.EmailDelivery.Enabled {
|
||||||
message := gomail.NewMessage()
|
message := gomail.NewMessage()
|
||||||
message.SetAddressHeader("To", email.Address, "")
|
message.SetAddressHeader("To", email.Address, "")
|
||||||
message.SetAddressHeader("From", h.emailConfig.FromAddress, h.emailConfig.FromName)
|
message.SetAddressHeader("From", h.emailConfig.FromAddress, h.emailConfig.FromName)
|
||||||
|
|
||||||
message.SetHeader("Subject", h.renderer.Translate(lang, "email_subject_login", data))
|
message.SetHeader("Subject", subject)
|
||||||
|
|
||||||
message.SetBody("text/plain", str)
|
message.SetBody("text/plain", bodyPlain)
|
||||||
|
|
||||||
err = h.mailer.Send(message)
|
err = h.mailer.Send(message)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to send passcode: %w", err)
|
return fmt.Errorf("failed to send passcode: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
err = utils.TriggerWebhooks(c, events.EmailSend, webhookData)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
zeroLogger.Warn().Err(err).Msg("failed to trigger webhook")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
webhookData.DeliveredByHanko = false
|
||||||
|
err = utils.TriggerWebhooks(c, events.EmailSend, webhookData)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf(fmt.Sprintf("failed to trigger webhook: %s", err))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
err = h.auditLogger.Create(c, models.AuditLogPasscodeLoginInitSucceeded, user, nil)
|
err = h.auditLogger.Create(c, models.AuditLogPasscodeLoginInitSucceeded, user, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to create audit log: %w", err)
|
return fmt.Errorf("failed to create audit log: %w", err)
|
||||||
@ -326,7 +359,7 @@ func (h *PasscodeHandler) Finish(c echo.Context) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
wasUnverified := false
|
wasUnverified := false
|
||||||
hasEmails := len(user.Emails) >= 1 // check if we need to trigger a UserCreate webhook or a EmailCreate one
|
hasEmails := len(user.Emails) >= 1 // check if we need to trigger a UserCreate webhook or a UserEmailCreate one
|
||||||
|
|
||||||
if !passcode.Email.Verified {
|
if !passcode.Email.Verified {
|
||||||
wasUnverified = true
|
wasUnverified = true
|
||||||
@ -394,7 +427,7 @@ func (h *PasscodeHandler) Finish(c echo.Context) error {
|
|||||||
var evt events.Event
|
var evt events.Event
|
||||||
|
|
||||||
if hasEmails {
|
if hasEmails {
|
||||||
evt = events.EmailCreate
|
evt = events.UserEmailCreate
|
||||||
} else {
|
} else {
|
||||||
evt = events.UserCreate
|
evt = events.UserCreate
|
||||||
}
|
}
|
||||||
|
|||||||
@ -143,9 +143,9 @@ func NewPublicRouter(cfg *config.Config, persister persistence.Persister, promet
|
|||||||
webauthnCredentials.DELETE("/:id", webauthnHandler.DeleteCredential)
|
webauthnCredentials.DELETE("/:id", webauthnHandler.DeleteCredential)
|
||||||
|
|
||||||
passcode := g.Group("/passcode")
|
passcode := g.Group("/passcode")
|
||||||
passcodeLogin := passcode.Group("/login")
|
passcodeLogin := passcode.Group("/login", webhookMiddlware)
|
||||||
passcodeLogin.POST("/initialize", passcodeHandler.Init)
|
passcodeLogin.POST("/initialize", passcodeHandler.Init)
|
||||||
passcodeLogin.POST("/finalize", passcodeHandler.Finish, webhookMiddlware)
|
passcodeLogin.POST("/finalize", passcodeHandler.Finish)
|
||||||
|
|
||||||
email := g.Group("/emails", sessionMiddleware, webhookMiddlware)
|
email := g.Group("/emails", sessionMiddleware, webhookMiddlware)
|
||||||
email.GET("", emailHandler.List)
|
email.GET("", emailHandler.List)
|
||||||
|
|||||||
@ -133,6 +133,9 @@
|
|||||||
"smtp": {
|
"smtp": {
|
||||||
"$ref": "#/$defs/SMTP"
|
"$ref": "#/$defs/SMTP"
|
||||||
},
|
},
|
||||||
|
"email_delivery": {
|
||||||
|
"$ref": "#/$defs/EmailDelivery"
|
||||||
|
},
|
||||||
"passcode": {
|
"passcode": {
|
||||||
"$ref": "#/$defs/Passcode"
|
"$ref": "#/$defs/Passcode"
|
||||||
},
|
},
|
||||||
@ -302,6 +305,19 @@
|
|||||||
"additionalProperties": false,
|
"additionalProperties": false,
|
||||||
"type": "object"
|
"type": "object"
|
||||||
},
|
},
|
||||||
|
"EmailDelivery": {
|
||||||
|
"properties": {
|
||||||
|
"enabled": {
|
||||||
|
"type": "boolean",
|
||||||
|
"default": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": false,
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"enabled"
|
||||||
|
]
|
||||||
|
},
|
||||||
"Emails": {
|
"Emails": {
|
||||||
"properties": {
|
"properties": {
|
||||||
"require_verification": {
|
"require_verification": {
|
||||||
|
|||||||
@ -53,7 +53,6 @@ func Limit(store limiter.Store, userId uuid.UUID, c echo.Context) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
resetTime := int(math.Floor(time.Unix(0, int64(reset)).UTC().Sub(time.Now().UTC()).Seconds()))
|
resetTime := int(math.Floor(time.Unix(0, int64(reset)).UTC().Sub(time.Now().UTC()).Seconds()))
|
||||||
log.Println(resetTime)
|
|
||||||
|
|
||||||
// Set headers (we do this regardless of whether the request is permitted).
|
// Set headers (we do this regardless of whether the request is permitted).
|
||||||
c.Response().Header().Set(httplimit.HeaderRateLimitLimit, strconv.FormatUint(limit, 10))
|
c.Response().Header().Set(httplimit.HeaderRateLimitLimit, strconv.FormatUint(limit, 10))
|
||||||
|
|||||||
@ -20,6 +20,9 @@ var DefaultConfig = config.Config{
|
|||||||
Host: "localhost",
|
Host: "localhost",
|
||||||
Port: "2500",
|
Port: "2500",
|
||||||
},
|
},
|
||||||
|
EmailDelivery: config.EmailDelivery{
|
||||||
|
Enabled: true,
|
||||||
|
},
|
||||||
Passcode: config.Passcode{
|
Passcode: config.Passcode{
|
||||||
Email: config.Email{
|
Email: config.Email{
|
||||||
FromAddress: "test@hanko.io",
|
FromAddress: "test@hanko.io",
|
||||||
|
|||||||
2
backend/thirdparty/linking.go
vendored
2
backend/thirdparty/linking.go
vendored
@ -128,7 +128,7 @@ func signIn(tx *pop.Connection, cfg *config.Config, p persistence.Persister, use
|
|||||||
}
|
}
|
||||||
|
|
||||||
identity.EmailID = email.ID
|
identity.EmailID = email.ID
|
||||||
webhookEvent = events.EmailCreate
|
webhookEvent = events.UserEmailCreate
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -9,10 +9,12 @@ const (
|
|||||||
UserCreate Event = "user.create"
|
UserCreate Event = "user.create"
|
||||||
UserUpdate Event = "user.update"
|
UserUpdate Event = "user.update"
|
||||||
UserDelete Event = "user.delete"
|
UserDelete Event = "user.delete"
|
||||||
Email Event = "user.update.email"
|
UserEmail Event = "user.update.email"
|
||||||
EmailCreate Event = "user.update.email.create"
|
UserEmailCreate Event = "user.update.email.create"
|
||||||
EmailPrimary Event = "user.update.email.primary"
|
UserEmailPrimary Event = "user.update.email.primary"
|
||||||
EmailDelete Event = "user.update.email.delete"
|
UserEmailDelete Event = "user.update.email.delete"
|
||||||
|
|
||||||
|
EmailSend Event = "email.send"
|
||||||
)
|
)
|
||||||
|
|
||||||
func StringIsValidEvent(value string) bool {
|
func StringIsValidEvent(value string) bool {
|
||||||
@ -23,7 +25,7 @@ func StringIsValidEvent(value string) bool {
|
|||||||
func IsValidEvent(evt Event) bool {
|
func IsValidEvent(evt Event) bool {
|
||||||
var isValid bool
|
var isValid bool
|
||||||
switch evt {
|
switch evt {
|
||||||
case User, UserCreate, UserUpdate, UserDelete, Email, EmailCreate, EmailPrimary, EmailDelete:
|
case User, UserCreate, UserUpdate, UserDelete, UserEmail, UserEmailCreate, UserEmailPrimary, UserEmailDelete, EmailSend:
|
||||||
isValid = true
|
isValid = true
|
||||||
default:
|
default:
|
||||||
isValid = false
|
isValid = false
|
||||||
|
|||||||
@ -17,7 +17,7 @@ func TestBaseWebhook_HasEvent(t *testing.T) {
|
|||||||
Events: events.Events{events.UserUpdate},
|
Events: events.Events{events.UserUpdate},
|
||||||
}
|
}
|
||||||
|
|
||||||
require.True(t, baseHook.HasEvent(events.EmailCreate))
|
require.True(t, baseHook.HasEvent(events.UserEmailCreate))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestWebhooks_HasEvent_WithMultipleEvents(t *testing.T) {
|
func TestWebhooks_HasEvent_WithMultipleEvents(t *testing.T) {
|
||||||
@ -37,7 +37,7 @@ func TestWebhooks_HasSubEvent_WithMultipleEvents(t *testing.T) {
|
|||||||
Events: events.Events{events.UserCreate, events.UserUpdate},
|
Events: events.Events{events.UserCreate, events.UserUpdate},
|
||||||
}
|
}
|
||||||
|
|
||||||
require.True(t, baseHook.HasEvent(events.EmailCreate))
|
require.True(t, baseHook.HasEvent(events.UserEmailCreate))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestBaseWebhook_HasSubEvent(t *testing.T) {
|
func TestBaseWebhook_HasSubEvent(t *testing.T) {
|
||||||
|
|||||||
Reference in New Issue
Block a user