diff --git a/internal/start/start.go b/internal/start/start.go index b19a54168..bdb0989aa 100644 --- a/internal/start/start.go +++ b/internal/start/start.go @@ -552,10 +552,10 @@ EOF id+filepath.Ext(tmpl.ContentPath), )) } - if len(tmpl.Subject) > 0 { + if tmpl.Subject != nil { env = append(env, fmt.Sprintf("GOTRUE_MAILER_SUBJECTS_%s=%s", strings.ToUpper(id), - tmpl.Subject, + *tmpl.Subject, )) } } diff --git a/pkg/config/auth.go b/pkg/config/auth.go index 2a71f2177..c7c4590c2 100644 --- a/pkg/config/auth.go +++ b/pkg/config/auth.go @@ -89,10 +89,10 @@ type ( } emailTemplate struct { - Subject string `toml:"subject"` - ContentPath string `toml:"content_path"` + Subject *string `toml:"subject"` + ContentPath string `toml:"content_path"` // Exposed for remote diff only, not valid in config.toml - Content string `toml:"content"` + Content *string `toml:"content"` } sms struct { @@ -332,49 +332,24 @@ func (e email) toAuthConfigBody(body *v1API.UpdateAuthConfigBody) { return } var tmpl *emailTemplate - // When local config is not set, we assume platform defaults should not change tmpl = cast.Ptr(e.Template["invite"]) - if len(tmpl.Subject) > 0 { - body.MailerSubjectsInvite = &tmpl.Subject - } - if len(tmpl.Content) > 0 { - body.MailerTemplatesInviteContent = &tmpl.Content - } + body.MailerSubjectsInvite = tmpl.Subject + body.MailerTemplatesInviteContent = tmpl.Content tmpl = cast.Ptr(e.Template["confirmation"]) - if len(tmpl.Subject) > 0 { - body.MailerSubjectsConfirmation = &tmpl.Subject - } - if len(tmpl.Content) > 0 { - body.MailerTemplatesConfirmationContent = &tmpl.Content - } + body.MailerSubjectsConfirmation = tmpl.Subject + body.MailerTemplatesConfirmationContent = tmpl.Content tmpl = cast.Ptr(e.Template["recovery"]) - if len(tmpl.Subject) > 0 { - body.MailerSubjectsRecovery = &tmpl.Subject - } - if len(tmpl.Content) > 0 { - body.MailerTemplatesRecoveryContent = &tmpl.Content - } + body.MailerSubjectsRecovery = tmpl.Subject + body.MailerTemplatesRecoveryContent = tmpl.Content tmpl = cast.Ptr(e.Template["magic_link"]) - if len(tmpl.Subject) > 0 { - body.MailerSubjectsMagicLink = &tmpl.Subject - } - if len(tmpl.Content) > 0 { - body.MailerTemplatesMagicLinkContent = &tmpl.Content - } + body.MailerSubjectsMagicLink = tmpl.Subject + body.MailerTemplatesMagicLinkContent = tmpl.Content tmpl = cast.Ptr(e.Template["email_change"]) - if len(tmpl.Subject) > 0 { - body.MailerSubjectsEmailChange = &tmpl.Subject - } - if len(tmpl.Content) > 0 { - body.MailerTemplatesEmailChangeContent = &tmpl.Content - } + body.MailerSubjectsEmailChange = tmpl.Subject + body.MailerTemplatesEmailChangeContent = tmpl.Content tmpl = cast.Ptr(e.Template["reauthentication"]) - if len(tmpl.Subject) > 0 { - body.MailerSubjectsReauthentication = &tmpl.Subject - } - if len(tmpl.Content) > 0 { - body.MailerTemplatesReauthenticationContent = &tmpl.Content - } + body.MailerSubjectsReauthentication = tmpl.Subject + body.MailerTemplatesReauthenticationContent = tmpl.Content } func (e *email) fromAuthConfig(remoteConfig v1API.AuthConfigResponse) { @@ -405,57 +380,58 @@ func (e *email) fromAuthConfig(remoteConfig v1API.AuthConfigResponse) { return } var tmpl emailTemplate + // When local config is not set, we assume platform defaults should not change tmpl = e.Template["invite"] - if len(tmpl.Subject) > 0 { - tmpl.Subject = cast.Val(remoteConfig.MailerSubjectsInvite, "") + if tmpl.Subject != nil { + tmpl.Subject = remoteConfig.MailerSubjectsInvite } - if len(tmpl.Content) > 0 { - tmpl.Content = cast.Val(remoteConfig.MailerTemplatesInviteContent, "") + if tmpl.Content != nil { + tmpl.Content = remoteConfig.MailerTemplatesInviteContent } e.Template["invite"] = tmpl tmpl = e.Template["confirmation"] - if len(tmpl.Subject) > 0 { - tmpl.Subject = cast.Val(remoteConfig.MailerSubjectsConfirmation, "") + if tmpl.Subject != nil { + tmpl.Subject = remoteConfig.MailerSubjectsConfirmation } - if len(tmpl.Content) > 0 { - tmpl.Content = cast.Val(remoteConfig.MailerTemplatesConfirmationContent, "") + if tmpl.Content != nil { + tmpl.Content = remoteConfig.MailerTemplatesConfirmationContent } e.Template["confirmation"] = tmpl tmpl = e.Template["recovery"] - if len(tmpl.Subject) > 0 { - tmpl.Subject = cast.Val(remoteConfig.MailerSubjectsRecovery, "") + if tmpl.Subject != nil { + tmpl.Subject = remoteConfig.MailerSubjectsRecovery } - if len(tmpl.Content) > 0 { - tmpl.Content = cast.Val(remoteConfig.MailerTemplatesRecoveryContent, "") + if tmpl.Content != nil { + tmpl.Content = remoteConfig.MailerTemplatesRecoveryContent } e.Template["recovery"] = tmpl tmpl = e.Template["magic_link"] - if len(tmpl.Subject) > 0 { - tmpl.Subject = cast.Val(remoteConfig.MailerSubjectsMagicLink, "") + if tmpl.Subject != nil { + tmpl.Subject = remoteConfig.MailerSubjectsMagicLink } - if len(tmpl.Content) > 0 { - tmpl.Content = cast.Val(remoteConfig.MailerTemplatesMagicLinkContent, "") + if tmpl.Content != nil { + tmpl.Content = remoteConfig.MailerTemplatesMagicLinkContent } e.Template["magic_link"] = tmpl tmpl = e.Template["email_change"] - if len(tmpl.Subject) > 0 { - tmpl.Subject = cast.Val(remoteConfig.MailerSubjectsEmailChange, "") + if tmpl.Subject != nil { + tmpl.Subject = remoteConfig.MailerSubjectsEmailChange } - if len(tmpl.Content) > 0 { - tmpl.Content = cast.Val(remoteConfig.MailerTemplatesEmailChangeContent, "") + if tmpl.Content != nil { + tmpl.Content = remoteConfig.MailerTemplatesEmailChangeContent } e.Template["email_change"] = tmpl tmpl = e.Template["reauthentication"] - if len(tmpl.Subject) > 0 { - tmpl.Subject = cast.Val(remoteConfig.MailerSubjectsReauthentication, "") + if tmpl.Subject != nil { + tmpl.Subject = remoteConfig.MailerSubjectsReauthentication } - if len(tmpl.Content) > 0 { - tmpl.Content = cast.Val(remoteConfig.MailerTemplatesReauthenticationContent, "") + if tmpl.Content != nil { + tmpl.Content = remoteConfig.MailerTemplatesReauthenticationContent } e.Template["reauthentication"] = tmpl } diff --git a/pkg/config/auth_test.go b/pkg/config/auth_test.go index 086c9107b..5a8973700 100644 --- a/pkg/config/auth_test.go +++ b/pkg/config/auth_test.go @@ -229,28 +229,28 @@ func TestEmailDiff(t *testing.T) { SecurePasswordChange: true, Template: map[string]emailTemplate{ "invite": { - Subject: "invite-subject", - Content: "invite-content", + Subject: cast.Ptr("invite-subject"), + Content: cast.Ptr("invite-content"), }, "confirmation": { - Subject: "confirmation-subject", - Content: "confirmation-content", + Subject: cast.Ptr("confirmation-subject"), + Content: cast.Ptr("confirmation-content"), }, "recovery": { - Subject: "recovery-subject", - Content: "recovery-content", + Subject: cast.Ptr("recovery-subject"), + Content: cast.Ptr("recovery-content"), }, "magic_link": { - Subject: "magic-link-subject", - Content: "magic-link-content", + Subject: cast.Ptr("magic-link-subject"), + Content: cast.Ptr("magic-link-content"), }, "email_change": { - Subject: "email-change-subject", - Content: "email-change-content", + Subject: cast.Ptr("email-change-subject"), + Content: cast.Ptr("email-change-content"), }, "reauthentication": { - Subject: "reauthentication-subject", - Content: "reauthentication-content", + Subject: cast.Ptr("reauthentication-subject"), + Content: cast.Ptr("reauthentication-content"), }, }, Smtp: &smtp{ @@ -308,26 +308,26 @@ func TestEmailDiff(t *testing.T) { SecurePasswordChange: true, Template: map[string]emailTemplate{ "invite": { - Subject: "invite-subject", - Content: "invite-content", + Subject: cast.Ptr("invite-subject"), + Content: cast.Ptr("invite-content"), }, "confirmation": { - Subject: "confirmation-subject", + Subject: cast.Ptr("confirmation-subject"), }, "recovery": { - Content: "recovery-content", + Content: cast.Ptr("recovery-content"), }, "magic_link": { - Subject: "magic-link-subject", - Content: "magic-link-content", + Subject: cast.Ptr("magic-link-subject"), + Content: cast.Ptr("magic-link-content"), }, "email_change": { - Subject: "email-change-subject", - Content: "email-change-content", + Subject: cast.Ptr("email-change-subject"), + Content: cast.Ptr("email-change-content"), }, "reauthentication": { - Subject: "reauthentication-subject", - Content: "reauthentication-content", + Subject: cast.Ptr(""), + Content: cast.Ptr(""), }, }, Smtp: &smtp{ @@ -359,6 +359,7 @@ func TestEmailDiff(t *testing.T) { }) // Check error assert.NoError(t, err) + assert.Empty(t, string(diff)) assert.Contains(t, string(diff), ` [email]`) assert.Contains(t, string(diff), `-enable_signup = false`) @@ -376,42 +377,39 @@ func TestEmailDiff(t *testing.T) { assert.Contains(t, string(diff), `+otp_length = 8`) assert.Contains(t, string(diff), `+otp_expiry = 86400`) - assert.Contains(t, string(diff), `+[email.smtp]`) - assert.Contains(t, string(diff), `+host = "smtp.sendgrid.net"`) - assert.Contains(t, string(diff), `+port = 587`) - assert.Contains(t, string(diff), `+user = "apikey"`) - assert.Contains(t, string(diff), `+pass = "hash:ed64b7695a606bc6ab4fcb41fe815b5ddf1063ccbc87afe1fa89756635db520e"`) - assert.Contains(t, string(diff), `+admin_email = "admin@email.com"`) - assert.Contains(t, string(diff), `+sender_name = "Admin"`) - assert.Contains(t, string(diff), ` [email.template]`) assert.Contains(t, string(diff), ` [email.template.confirmation]`) - assert.Contains(t, string(diff), `-subject = ""`) assert.Contains(t, string(diff), `+subject = "confirmation-subject"`) assert.Contains(t, string(diff), ` content_path = ""`) - assert.Contains(t, string(diff), ` content = ""`) assert.Contains(t, string(diff), ` [email.template.email_change]`) - assert.Contains(t, string(diff), `-subject = ""`) assert.Contains(t, string(diff), `+subject = "email-change-subject"`) assert.Contains(t, string(diff), ` content_path = ""`) assert.Contains(t, string(diff), ` content = "email-change-content"`) assert.Contains(t, string(diff), ` [email.template.invite]`) - assert.Contains(t, string(diff), `-subject = ""`) assert.Contains(t, string(diff), `-content_path = ""`) - assert.Contains(t, string(diff), `-content = ""`) assert.Contains(t, string(diff), `+subject = "invite-subject"`) assert.Contains(t, string(diff), `+content_path = ""`) assert.Contains(t, string(diff), `+content = "invite-content"`) assert.Contains(t, string(diff), ` [email.template.magic_link]`) assert.Contains(t, string(diff), ` subject = "magic-link-subject"`) assert.Contains(t, string(diff), ` content_path = ""`) - assert.Contains(t, string(diff), `-content = ""`) assert.Contains(t, string(diff), `+content = "magic-link-content"`) + assert.Contains(t, string(diff), ` [email.template.reauthentication]`) + assert.Contains(t, string(diff), `-content_path = ""`) + assert.Contains(t, string(diff), `+subject = ""`) + assert.Contains(t, string(diff), `+content_path = ""`) + assert.Contains(t, string(diff), `+content = ""`) assert.Contains(t, string(diff), ` [email.template.recovery]`) - assert.Contains(t, string(diff), ` subject = ""`) assert.Contains(t, string(diff), ` content_path = ""`) - assert.Contains(t, string(diff), `-content = ""`) assert.Contains(t, string(diff), `+content = "recovery-content"`) + + assert.Contains(t, string(diff), `+[email.smtp]`) + assert.Contains(t, string(diff), `+host = "smtp.sendgrid.net"`) + assert.Contains(t, string(diff), `+port = 587`) + assert.Contains(t, string(diff), `+user = "apikey"`) + assert.Contains(t, string(diff), `+pass = "hash:ed64b7695a606bc6ab4fcb41fe815b5ddf1063ccbc87afe1fa89756635db520e"`) + assert.Contains(t, string(diff), `+admin_email = "admin@email.com"`) + assert.Contains(t, string(diff), `+sender_name = "Admin"`) }) t.Run("local disabled remote enabled", func(t *testing.T) { diff --git a/pkg/config/config.go b/pkg/config/config.go index 3895ddb4c..b1e7ed570 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -30,6 +30,7 @@ import ( "github.com/joho/godotenv" "github.com/mitchellh/mapstructure" "github.com/spf13/viper" + "github.com/supabase/cli/pkg/cast" "github.com/supabase/cli/pkg/fetcher" "golang.org/x/mod/semver" ) @@ -819,16 +820,15 @@ func (c *seed) loadSeedPaths(basePath string, fsys fs.FS) error { func (e *email) validate(fsys fs.FS) (err error) { for name, tmpl := range e.Template { if len(tmpl.ContentPath) == 0 { - if len(tmpl.Content) > 0 { + if tmpl.Content != nil { return errors.Errorf("Invalid config for auth.email.%s.content: please use content_path instead", name) } continue } - // Load the file content of the template within the config if content, err := fs.ReadFile(fsys, filepath.Clean(tmpl.ContentPath)); err != nil { return errors.Errorf("Invalid config for auth.email.%s.content_path: %w", name, err) } else { - tmpl.Content = string(content) + tmpl.Content = cast.Ptr(string(content)) } e.Template[name] = tmpl }