1
0
mirror of https://github.com/hrfee/jfa-go.git synced 2025-01-01 05:50:12 +00:00

Compare commits

...

2 Commits

Author SHA1 Message Date
a8f71c83da
store language preference as cookie 2021-04-08 16:03:46 +01:00
7a3e0d60f9
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".
2021-04-08 14:20:13 +01:00
6 changed files with 94 additions and 26 deletions

27
api.go
View File

@ -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 == "" {

View File

@ -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 {

View File

@ -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": {

View File

@ -64,6 +64,7 @@
<p>{{ .youCanLoginWith }}:</p>
{{ .jellyfinURLString }}: <a href="{{ .jellyfinURLVal }}">{{ .jellyfinURL }}</a>
<p>{{ .usernameString }}: <i>{{ .username }}</i></p>
<p>{{ .yourAccountWillExpire }}</p>
</mj-text>
</mj-column>
</mj-section>

View File

@ -6,5 +6,6 @@
{{ .usernameString }}: {{ .username }}
{{ .yourAccountWillExpire }}
{{ .message }}

View File

@ -53,19 +53,56 @@ func (app *appContext) pushResources(gc *gin.Context, admin bool) {
gc.Header("Link", cssHeader)
}
func (app *appContext) getLang(gc *gin.Context, chosen string) string {
const (
AdminPage = iota + 1
FormPage
PWRPage
)
func (app *appContext) getLang(gc *gin.Context, page int, chosen string) string {
lang := gc.Query("lang")
if lang == "" {
lang = chosen
} else if _, ok := app.storage.lang.Admin[lang]; !ok {
lang = chosen
cookie, err := gc.Cookie("lang")
if lang != "" {
switch page {
case AdminPage:
if _, ok := app.storage.lang.Admin[lang]; ok {
gc.SetCookie("lang", lang, (365 * 3600), "/", gc.Request.URL.Hostname(), true, true)
return lang
}
case FormPage:
if _, ok := app.storage.lang.Form[lang]; ok {
gc.SetCookie("lang", lang, (365 * 3600), "/", gc.Request.URL.Hostname(), true, true)
return lang
}
case PWRPage:
if _, ok := app.storage.lang.PasswordReset[lang]; ok {
gc.SetCookie("lang", lang, (365 * 3600), "/", gc.Request.URL.Hostname(), true, true)
return lang
}
}
}
return lang
if cookie != "" && err == nil {
switch page {
case AdminPage:
if _, ok := app.storage.lang.Admin[cookie]; ok {
return cookie
}
case FormPage:
if _, ok := app.storage.lang.Form[cookie]; ok {
return cookie
}
case PWRPage:
if _, ok := app.storage.lang.PasswordReset[cookie]; ok {
return cookie
}
}
}
return chosen
}
func (app *appContext) AdminPage(gc *gin.Context) {
app.pushResources(gc, true)
lang := app.getLang(gc, app.storage.lang.chosenAdminLang)
lang := app.getLang(gc, AdminPage, app.storage.lang.chosenAdminLang)
emailEnabled, _ := app.config.Section("invite_emails").Key("enabled").Bool()
notificationsEnabled, _ := app.config.Section("notifications").Key("enabled").Bool()
ombiEnabled := app.config.Section("ombi").Key("enabled").MustBool(false)
@ -101,7 +138,7 @@ func (app *appContext) ResetPassword(gc *gin.Context) {
return
}
app.pushResources(gc, false)
lang := app.getLang(gc, app.storage.lang.chosenPWRLang)
lang := app.getLang(gc, PWRPage, app.storage.lang.chosenPWRLang)
data := gin.H{
"urlBase": app.getURLBase(gc),
"contactMessage": app.config.Section("ui").Key("contact_message").String(),
@ -121,7 +158,7 @@ func (app *appContext) ResetPassword(gc *gin.Context) {
func (app *appContext) InviteProxy(gc *gin.Context) {
app.pushResources(gc, false)
code := gc.Param("invCode")
lang := app.getLang(gc, app.storage.lang.chosenFormLang)
lang := app.getLang(gc, FormPage, app.storage.lang.chosenFormLang)
/* Don't actually check if the invite is valid, just if it exists, just so the page loads quicker. Invite is actually checked on submit anyway. */
// if app.checkInvite(code, false, "") {
inv, ok := app.storage.invites[code]