From 7a3e0d60f95e5718109da36781de79128f04ab96 Mon Sep 17 00:00:00 2001 From: Harvey Tindall Date: Thu, 8 Apr 2021 14:20:13 +0100 Subject: [PATCH] add expiry to welcome email, add dummy emailer for debugging the "yourAccountWillExpire" has also been added to the editor for #81. To use the dummy emailer, set [email]/method to "dummy". --- api.go | 27 ++++++++++++++------------- email.go | 35 +++++++++++++++++++++++++++++++---- lang/email/en-us.json | 1 + mail/welcome.mjml | 1 + mail/welcome.txt | 1 + 5 files changed, 48 insertions(+), 17 deletions(-) diff --git a/api.go b/api.go index d823c2a..ebbde07 100644 --- a/api.go +++ b/api.go @@ -295,7 +295,7 @@ func (app *appContext) NewUserAdmin(gc *gin.Context) { } if emailEnabled && app.config.Section("welcome_email").Key("enabled").MustBool(false) && req.Email != "" { app.debug.Printf("%s: Sending welcome email to %s", req.Username, req.Email) - msg, err := app.email.constructWelcome(req.Username, app, false) + msg, err := app.email.constructWelcome(req.Username, time.Time{}, app, false) if err != nil { app.err.Printf("%s: Failed to construct welcome email: %v", req.Username, err) respondUser(500, true, false, err.Error(), gc) @@ -434,9 +434,19 @@ func (app *appContext) newUser(req newUserDTO, confirmed bool) (f errorFunc, suc } } } + expiry := time.Time{} + if invite.UserExpiry { + app.storage.usersLock.Lock() + defer app.storage.usersLock.Unlock() + expiry = time.Now().Add(time.Duration(60*(invite.UserDays*24+invite.UserHours)+invite.UserMinutes) * time.Minute) + app.storage.users[id] = expiry + if err := app.storage.storeUsers(); err != nil { + app.err.Printf("Failed to store user duration: %v", err) + } + } if emailEnabled && app.config.Section("welcome_email").Key("enabled").MustBool(false) && req.Email != "" { app.debug.Printf("%s: Sending welcome email to %s", req.Username, req.Email) - msg, err := app.email.constructWelcome(req.Username, app, false) + msg, err := app.email.constructWelcome(req.Username, expiry, app, false) if err != nil { app.err.Printf("%s: Failed to construct welcome email: %v", req.Username, err) } else if err := app.email.send(msg, req.Email); err != nil { @@ -445,15 +455,6 @@ func (app *appContext) newUser(req newUserDTO, confirmed bool) (f errorFunc, suc app.info.Printf("%s: Sent welcome email to \"%s\"", req.Username, req.Email) } } - if invite.UserExpiry { - app.storage.usersLock.Lock() - defer app.storage.usersLock.Unlock() - expiry := time.Now().Add(time.Duration(60*(invite.UserDays*24+invite.UserHours)+invite.UserMinutes) * time.Minute) - app.storage.users[id] = expiry - if err := app.storage.storeUsers(); err != nil { - app.err.Printf("Failed to store user duration: %v", err) - } - } app.jf.CacheExpiry = time.Now() success = true return @@ -1592,14 +1593,14 @@ func (app *appContext) GetEmail(gc *gin.Context) { content = app.storage.customEmails.WelcomeEmail.Content if content == "" { newEmail = true - msg, err = app.email.constructWelcome("", app, true) + msg, err = app.email.constructWelcome("", time.Time{}, app, true) content = msg.Text } else { variables = app.storage.customEmails.WelcomeEmail.Variables } writeVars = func(variables []string) { app.storage.customEmails.WelcomeEmail.Variables = variables } // app.storage.customEmails.WelcomeEmail = content - values = app.email.welcomeValues(username, app, false) + values = app.email.welcomeValues(username, time.Time{}, app, false, true) } else if id == "EmailConfirmation" { content = app.storage.customEmails.EmailConfirmation.Content if content == "" { diff --git a/email.go b/email.go index 9dbffba..68dc90b 100644 --- a/email.go +++ b/email.go @@ -29,6 +29,13 @@ type emailClient interface { send(fromName, fromAddr string, email *Email, address ...string) error } +type dummyClient struct{} + +func (dc *dummyClient) send(fromName, fromAddr string, email *Email, address ...string) error { + fmt.Printf("FROM: %s <%s>\nTO: %s\nTEXT: %s\n", fromName, fromAddr, strings.Join(address, ", "), email.Text) + return nil +} + // Mailgun client implements emailClient. type Mailgun struct { client *mailgun.MailgunImpl @@ -146,6 +153,8 @@ func NewEmailer(app *appContext) *Emailer { } } else if method == "mailgun" { emailer.NewMailgun(app.config.Section("mailgun").Key("api_url").String(), app.config.Section("mailgun").Key("api_key").String()) + } else if method == "dummy" { + emailer.sender = &dummyClient{} } return emailer } @@ -566,7 +575,7 @@ func (emailer *Emailer) constructDeleted(reason string, app *appContext, noSub b return email, nil } -func (emailer *Emailer) welcomeValues(username string, app *appContext, noSub bool) map[string]interface{} { +func (emailer *Emailer) welcomeValues(username string, expiry time.Time, app *appContext, noSub bool, custom bool) map[string]interface{} { template := map[string]interface{}{ "welcome": emailer.lang.WelcomeEmail.get("welcome"), "youCanLoginWith": emailer.lang.WelcomeEmail.get("youCanLoginWith"), @@ -575,7 +584,7 @@ func (emailer *Emailer) welcomeValues(username string, app *appContext, noSub bo "message": "", } if noSub { - empty := []string{"jellyfinURL", "username"} + empty := []string{"jellyfinURL", "username", "yourAccountWillExpire"} for _, v := range empty { template[v] = "{" + v + "}" } @@ -583,16 +592,34 @@ func (emailer *Emailer) welcomeValues(username string, app *appContext, noSub bo template["jellyfinURL"] = app.config.Section("jellyfin").Key("public_server").String() template["username"] = username template["message"] = app.config.Section("email").Key("message").String() + exp := app.formatDatetime(expiry) + if custom { + template["yourAccountWillExpire"] = exp + } else if !expiry.IsZero() { + template["yourAccountWillExpire"] = emailer.lang.WelcomeEmail.template("yourAccountWillExpire", tmpl{ + "date": exp, + }) + } } return template } -func (emailer *Emailer) constructWelcome(username string, app *appContext, noSub bool) (*Email, error) { +func (emailer *Emailer) constructWelcome(username string, expiry time.Time, app *appContext, noSub bool) (*Email, error) { email := &Email{ Subject: app.config.Section("welcome_email").Key("subject").MustString(emailer.lang.WelcomeEmail.get("title")), } var err error - template := emailer.welcomeValues(username, app, noSub) + var template map[string]interface{} + if app.storage.customEmails.WelcomeEmail.Enabled { + template = emailer.welcomeValues(username, expiry, app, noSub, true) + } else { + template = emailer.welcomeValues(username, expiry, app, noSub, false) + } + if noSub { + template["yourAccountWillExpire"] = emailer.lang.WelcomeEmail.template("yourAccountWillExpire", tmpl{ + "date": "{yourAccountWillExpire}", + }) + } if app.storage.customEmails.WelcomeEmail.Enabled { content := app.storage.customEmails.WelcomeEmail.Content for _, v := range app.storage.customEmails.WelcomeEmail.Variables { diff --git a/lang/email/en-us.json b/lang/email/en-us.json index c54a404..c2d6285 100644 --- a/lang/email/en-us.json +++ b/lang/email/en-us.json @@ -49,6 +49,7 @@ "title": "Welcome to Jellyfin", "welcome": "Welcome to Jellyfin!", "youCanLoginWith": "You can login with the details below", + "yourAccountWillExpire": "Your account will expire on {date}.", "jellyfinURL": "URL" }, "emailConfirmation": { diff --git a/mail/welcome.mjml b/mail/welcome.mjml index 90d828a..cc92c40 100644 --- a/mail/welcome.mjml +++ b/mail/welcome.mjml @@ -64,6 +64,7 @@

{{ .youCanLoginWith }}:

{{ .jellyfinURLString }}: {{ .jellyfinURL }}

{{ .usernameString }}: {{ .username }}

+

{{ .yourAccountWillExpire }}

diff --git a/mail/welcome.txt b/mail/welcome.txt index 52f5f4b..9344210 100644 --- a/mail/welcome.txt +++ b/mail/welcome.txt @@ -6,5 +6,6 @@ {{ .usernameString }}: {{ .username }} +{{ .yourAccountWillExpire }} {{ .message }}