mirror of
https://github.com/hrfee/jfa-go.git
synced 2024-12-22 09:00:10 +00:00
Implement email template generation
Variables are surrounded by {}, and initial (default) templates are generated on demand from the plaintext version of emails. The custom emails are intended to only be used if the user actually changes them, as they lose the features of the default ones, such as tables.
This commit is contained in:
parent
5c87d109a3
commit
eb406ef951
120
api.go
120
api.go
@ -126,7 +126,7 @@ func (app *appContext) checkInvites() {
|
|||||||
wait.Add(1)
|
wait.Add(1)
|
||||||
go func(addr string) {
|
go func(addr string) {
|
||||||
defer wait.Done()
|
defer wait.Done()
|
||||||
msg, err := app.email.constructExpiry(code, data, app)
|
msg, err := app.email.constructExpiry(code, data, app, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
app.err.Printf("%s: Failed to construct expiry notification: %s", code, err)
|
app.err.Printf("%s: Failed to construct expiry notification: %s", code, err)
|
||||||
} else if err := app.email.send(msg, addr); err != nil {
|
} else if err := app.email.send(msg, addr); err != nil {
|
||||||
@ -163,7 +163,7 @@ func (app *appContext) checkInvite(code string, used bool, username string) bool
|
|||||||
for address, settings := range notify {
|
for address, settings := range notify {
|
||||||
if settings["notify-expiry"] {
|
if settings["notify-expiry"] {
|
||||||
go func() {
|
go func() {
|
||||||
msg, err := app.email.constructExpiry(code, inv, app)
|
msg, err := app.email.constructExpiry(code, inv, app, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
app.err.Printf("%s: Failed to construct expiry notification: %s", code, err)
|
app.err.Printf("%s: Failed to construct expiry notification: %s", code, err)
|
||||||
} else if err := app.email.send(msg, address); err != nil {
|
} else if err := app.email.send(msg, address); err != nil {
|
||||||
@ -295,7 +295,7 @@ func (app *appContext) NewUserAdmin(gc *gin.Context) {
|
|||||||
}
|
}
|
||||||
if emailEnabled && app.config.Section("welcome_email").Key("enabled").MustBool(false) && req.Email != "" {
|
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)
|
app.debug.Printf("%s: Sending welcome email to %s", req.Username, req.Email)
|
||||||
msg, err := app.email.constructWelcome(req.Username, app)
|
msg, err := app.email.constructWelcome(req.Username, app, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
app.err.Printf("%s: Failed to construct welcome email: %s", req.Username, err)
|
app.err.Printf("%s: Failed to construct welcome email: %s", req.Username, err)
|
||||||
respondUser(500, true, false, err.Error(), gc)
|
respondUser(500, true, false, err.Error(), gc)
|
||||||
@ -351,7 +351,7 @@ func (app *appContext) newUser(req newUserDTO, confirmed bool) (f errorFunc, suc
|
|||||||
f = func(gc *gin.Context) {
|
f = func(gc *gin.Context) {
|
||||||
app.debug.Printf("%s: Email confirmation required", req.Code)
|
app.debug.Printf("%s: Email confirmation required", req.Code)
|
||||||
respond(401, "confirmEmail", gc)
|
respond(401, "confirmEmail", gc)
|
||||||
msg, err := app.email.constructConfirmation(req.Code, req.Username, key, app)
|
msg, err := app.email.constructConfirmation(req.Code, req.Username, key, app, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
app.err.Printf("%s: Failed to construct confirmation email: %s", req.Code, err)
|
app.err.Printf("%s: Failed to construct confirmation email: %s", req.Code, err)
|
||||||
} else if err := app.email.send(msg, req.Email); err != nil {
|
} else if err := app.email.send(msg, req.Email); err != nil {
|
||||||
@ -380,7 +380,7 @@ func (app *appContext) newUser(req newUserDTO, confirmed bool) (f errorFunc, suc
|
|||||||
for address, settings := range invite.Notify {
|
for address, settings := range invite.Notify {
|
||||||
if settings["notify-creation"] {
|
if settings["notify-creation"] {
|
||||||
go func() {
|
go func() {
|
||||||
msg, err := app.email.constructCreated(req.Code, req.Username, req.Email, invite, app)
|
msg, err := app.email.constructCreated(req.Code, req.Username, req.Email, invite, app, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
app.err.Printf("%s: Failed to construct user creation notification: %s", req.Code, err)
|
app.err.Printf("%s: Failed to construct user creation notification: %s", req.Code, err)
|
||||||
} else if err := app.email.send(msg, address); err != nil {
|
} else if err := app.email.send(msg, address); err != nil {
|
||||||
@ -436,7 +436,7 @@ func (app *appContext) newUser(req newUserDTO, confirmed bool) (f errorFunc, suc
|
|||||||
}
|
}
|
||||||
if emailEnabled && app.config.Section("welcome_email").Key("enabled").MustBool(false) && req.Email != "" {
|
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)
|
app.debug.Printf("%s: Sending welcome email to %s", req.Username, req.Email)
|
||||||
msg, err := app.email.constructWelcome(req.Username, app)
|
msg, err := app.email.constructWelcome(req.Username, app, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
app.err.Printf("%s: Failed to construct welcome email: %s", req.Username, err)
|
app.err.Printf("%s: Failed to construct welcome email: %s", req.Username, err)
|
||||||
} else if err := app.email.send(msg, req.Email); err != nil {
|
} else if err := app.email.send(msg, req.Email); err != nil {
|
||||||
@ -576,7 +576,7 @@ func (app *appContext) DeleteUsers(gc *gin.Context) {
|
|||||||
}
|
}
|
||||||
if len(addresses) != 0 {
|
if len(addresses) != 0 {
|
||||||
go func(reason string, addresses []string) {
|
go func(reason string, addresses []string) {
|
||||||
msg, err := app.email.constructDeleted(reason, app)
|
msg, err := app.email.constructDeleted(reason, app, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
app.err.Printf("Failed to construct account deletion emails: %s", err)
|
app.err.Printf("Failed to construct account deletion emails: %s", err)
|
||||||
} else if err := app.email.send(msg, addresses...); err != nil {
|
} else if err := app.email.send(msg, addresses...); err != nil {
|
||||||
@ -638,7 +638,7 @@ func (app *appContext) GenerateInvite(gc *gin.Context) {
|
|||||||
if emailEnabled && req.Email != "" && app.config.Section("invite_emails").Key("enabled").MustBool(false) {
|
if emailEnabled && req.Email != "" && app.config.Section("invite_emails").Key("enabled").MustBool(false) {
|
||||||
app.debug.Printf("%s: Sending invite email", inviteCode)
|
app.debug.Printf("%s: Sending invite email", inviteCode)
|
||||||
invite.Email = req.Email
|
invite.Email = req.Email
|
||||||
msg, err := app.email.constructInvite(inviteCode, invite, app)
|
msg, err := app.email.constructInvite(inviteCode, invite, app, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
invite.Email = fmt.Sprintf("Failed to send to %s", req.Email)
|
invite.Email = fmt.Sprintf("Failed to send to %s", req.Email)
|
||||||
app.err.Printf("%s: Failed to construct invite email: %s", inviteCode, err)
|
app.err.Printf("%s: Failed to construct invite email: %s", inviteCode, err)
|
||||||
@ -1269,6 +1269,108 @@ func (app *appContext) ModifyConfig(gc *gin.Context) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// @Summary Get a list of email names and IDs.
|
||||||
|
// @Produce json
|
||||||
|
// @Success 200 {object} emailListDTO
|
||||||
|
// @Router /config/emails [get]
|
||||||
|
// @tags Configuration
|
||||||
|
func (app *appContext) GetEmails(gc *gin.Context) {
|
||||||
|
gc.JSON(200, emailListDTO{
|
||||||
|
"UserCreated": app.storage.lang.Email["en-us"].UserCreated["name"],
|
||||||
|
"InviteExpiry": app.storage.lang.Email["en-us"].InviteExpiry["name"],
|
||||||
|
"PasswordReset": app.storage.lang.Email["en-us"].PasswordReset["name"],
|
||||||
|
"UserDeleted": app.storage.lang.Email["en-us"].UserDeleted["name"],
|
||||||
|
"InviteEmail": app.storage.lang.Email["en-us"].InviteEmail["name"],
|
||||||
|
"WelcomeEmail": app.storage.lang.Email["en-us"].WelcomeEmail["name"],
|
||||||
|
"EmailConfirmation": app.storage.lang.Email["en-us"].EmailConfirmation["name"],
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Summary Returns the boilerplate email and list of used variables in it.
|
||||||
|
// @Produce json
|
||||||
|
// @Success 200 {object} emailDTO
|
||||||
|
// @Failure 500 {object} boolResponse
|
||||||
|
// @Router /config/emails/{id} [get]
|
||||||
|
// @tags Configuration
|
||||||
|
func (app *appContext) GetEmail(gc *gin.Context) {
|
||||||
|
id := gc.Param("id")
|
||||||
|
var content string
|
||||||
|
var err error
|
||||||
|
var msg *Email
|
||||||
|
if id == "UserCreated" {
|
||||||
|
content = app.storage.customEmails.UserCreated
|
||||||
|
if content == "" {
|
||||||
|
msg, err = app.email.constructCreated("", "", "", Invite{}, app, true)
|
||||||
|
content = msg.text
|
||||||
|
}
|
||||||
|
// app.storage.customEmails.UserCreated = content
|
||||||
|
} else if id == "InviteExpiry" {
|
||||||
|
content = app.storage.customEmails.InviteExpiry
|
||||||
|
if content == "" {
|
||||||
|
msg, err = app.email.constructExpiry("", Invite{}, app, true)
|
||||||
|
content = msg.text
|
||||||
|
}
|
||||||
|
// app.storage.customEmails.InviteExpiry = content
|
||||||
|
} else if id == "PasswordReset" {
|
||||||
|
content = app.storage.customEmails.PasswordReset
|
||||||
|
if content == "" {
|
||||||
|
msg, err = app.email.constructReset(PasswordReset{}, app, true)
|
||||||
|
content = msg.text
|
||||||
|
}
|
||||||
|
// app.storage.customEmails.PasswordReset = content
|
||||||
|
} else if id == "UserDeleted" {
|
||||||
|
content = app.storage.customEmails.UserDeleted
|
||||||
|
if content == "" {
|
||||||
|
msg, err = app.email.constructDeleted("", app, true)
|
||||||
|
content = msg.text
|
||||||
|
}
|
||||||
|
// app.storage.customEmails.UserDeleted = content
|
||||||
|
} else if id == "InviteEmail" {
|
||||||
|
content = app.storage.customEmails.InviteEmail
|
||||||
|
if content == "" {
|
||||||
|
msg, err = app.email.constructInvite("", Invite{}, app, true)
|
||||||
|
content = msg.text
|
||||||
|
}
|
||||||
|
// app.storage.customEmails.InviteEmail = content
|
||||||
|
} else if id == "WelcomeEmail" {
|
||||||
|
content = app.storage.customEmails.WelcomeEmail
|
||||||
|
if content == "" {
|
||||||
|
msg, err = app.email.constructWelcome("", app, true)
|
||||||
|
content = msg.text
|
||||||
|
}
|
||||||
|
// app.storage.customEmails.WelcomeEmail = content
|
||||||
|
} else if id == "EmailConfirmation" {
|
||||||
|
content = app.storage.customEmails.EmailConfirmation
|
||||||
|
if content == "" {
|
||||||
|
msg, err = app.email.constructConfirmation("", "", "", app, true)
|
||||||
|
content = msg.text
|
||||||
|
}
|
||||||
|
// app.storage.customEmails.EmailConfirmation = content
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
respondBool(500, false, gc)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
variables := make([]string, strings.Count(content, "{"))
|
||||||
|
i := 0
|
||||||
|
found := false
|
||||||
|
buf := ""
|
||||||
|
for _, c := range content {
|
||||||
|
if !found && c != '{' && c != '}' {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
found = true
|
||||||
|
buf += string(c)
|
||||||
|
if c == '}' {
|
||||||
|
found = false
|
||||||
|
variables[i] = buf
|
||||||
|
buf = ""
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
gc.JSON(200, emailDTO{Content: content, Variables: variables})
|
||||||
|
}
|
||||||
|
|
||||||
// @Summary Logout by deleting refresh token from cookies.
|
// @Summary Logout by deleting refresh token from cookies.
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Success 200 {object} boolResponse
|
// @Success 200 {object} boolResponse
|
||||||
@ -1291,7 +1393,7 @@ func (app *appContext) Logout(gc *gin.Context) {
|
|||||||
// @Produce json
|
// @Produce json
|
||||||
// @Success 200 {object} langDTO
|
// @Success 200 {object} langDTO
|
||||||
// @Failure 500 {object} stringResponse
|
// @Failure 500 {object} stringResponse
|
||||||
// @Router /lang [get]
|
// @Router /lang/{page} [get]
|
||||||
// @tags Other
|
// @tags Other
|
||||||
func (app *appContext) GetLanguages(gc *gin.Context) {
|
func (app *appContext) GetLanguages(gc *gin.Context) {
|
||||||
page := gc.Param("page")
|
page := gc.Param("page")
|
||||||
|
@ -32,7 +32,7 @@ func (app *appContext) loadConfig() error {
|
|||||||
app.config.Section("jellyfin").Key("public_server").SetValue(app.config.Section("jellyfin").Key("public_server").MustString(app.config.Section("jellyfin").Key("server").String()))
|
app.config.Section("jellyfin").Key("public_server").SetValue(app.config.Section("jellyfin").Key("public_server").MustString(app.config.Section("jellyfin").Key("server").String()))
|
||||||
|
|
||||||
for _, key := range app.config.Section("files").Keys() {
|
for _, key := range app.config.Section("files").Keys() {
|
||||||
if key.Name() != "html_templates" {
|
if name := key.Name(); name != "html_templates" && name != "lang_files" {
|
||||||
key.SetValue(key.MustString(filepath.Join(app.dataPath, (key.Name() + ".json"))))
|
key.SetValue(key.MustString(filepath.Join(app.dataPath, (key.Name() + ".json"))))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -63,8 +63,8 @@ func (app *appContext) loadConfig() error {
|
|||||||
app.config.Section("welcome_email").Key("email_html").SetValue(app.config.Section("welcome_email").Key("email_html").MustString("jfa-go:" + "welcome.html"))
|
app.config.Section("welcome_email").Key("email_html").SetValue(app.config.Section("welcome_email").Key("email_html").MustString("jfa-go:" + "welcome.html"))
|
||||||
app.config.Section("welcome_email").Key("email_text").SetValue(app.config.Section("welcome_email").Key("email_text").MustString("jfa-go:" + "welcome.txt"))
|
app.config.Section("welcome_email").Key("email_text").SetValue(app.config.Section("welcome_email").Key("email_text").MustString("jfa-go:" + "welcome.txt"))
|
||||||
|
|
||||||
app.config.Section("announcement_email").Key("email_html").SetValue(app.config.Section("announcement_email").Key("email_html").MustString("jfa-go:" + "announcement.html"))
|
app.config.Section("template_email").Key("email_html").SetValue(app.config.Section("template_email").Key("email_html").MustString("jfa-go:" + "template.html"))
|
||||||
app.config.Section("announcement_email").Key("email_text").SetValue(app.config.Section("announcement_email").Key("email_text").MustString("jfa-go:" + "announcement.txt"))
|
app.config.Section("template_email").Key("email_text").SetValue(app.config.Section("template_email").Key("email_text").MustString("jfa-go:" + "template.txt"))
|
||||||
|
|
||||||
app.config.Section("jellyfin").Key("version").SetValue(VERSION)
|
app.config.Section("jellyfin").Key("version").SetValue(VERSION)
|
||||||
app.config.Section("jellyfin").Key("device").SetValue("jfa-go")
|
app.config.Section("jellyfin").Key("device").SetValue("jfa-go")
|
||||||
@ -76,6 +76,9 @@ func (app *appContext) loadConfig() error {
|
|||||||
emailEnabled = true
|
emailEnabled = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
app.storage.customEmails_path = app.config.Section("files").Key("custom_emails").String()
|
||||||
|
app.storage.loadCustomEmails()
|
||||||
|
|
||||||
substituteStrings = app.config.Section("jellyfin").Key("substitute_jellyfin_strings").MustString("")
|
substituteStrings = app.config.Section("jellyfin").Key("substitute_jellyfin_strings").MustString("")
|
||||||
|
|
||||||
oldFormLang := app.config.Section("ui").Key("language").MustString("")
|
oldFormLang := app.config.Section("ui").Key("language").MustString("")
|
||||||
|
@ -853,6 +853,14 @@
|
|||||||
"type": "text",
|
"type": "text",
|
||||||
"value": "",
|
"value": "",
|
||||||
"description": "The path to a directory which following the same form as the internal 'lang/' directory. See GitHub for more info."
|
"description": "The path to a directory which following the same form as the internal 'lang/' directory. See GitHub for more info."
|
||||||
|
},
|
||||||
|
"custom_emails": {
|
||||||
|
"name": "Custom email content",
|
||||||
|
"required": false,
|
||||||
|
"requires_restart": false,
|
||||||
|
"type": "text",
|
||||||
|
"value": "",
|
||||||
|
"description": "JSON file generated by program in settings, different from email_html/email_text. See wiki for more info."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
191
email.go
191
email.go
@ -212,22 +212,32 @@ func (emailer *Emailer) construct(app *appContext, section, keyFragment string,
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (emailer *Emailer) constructConfirmation(code, username, key string, app *appContext) (*Email, error) {
|
func (emailer *Emailer) constructConfirmation(code, username, key string, app *appContext, noSub bool) (*Email, error) {
|
||||||
email := &Email{
|
email := &Email{
|
||||||
subject: app.config.Section("email_confirmation").Key("subject").MustString(emailer.lang.EmailConfirmation.get("title")),
|
subject: app.config.Section("email_confirmation").Key("subject").MustString(emailer.lang.EmailConfirmation.get("title")),
|
||||||
}
|
}
|
||||||
message := app.config.Section("email").Key("message").String()
|
|
||||||
inviteLink := app.config.Section("invite_emails").Key("url_base").String()
|
|
||||||
inviteLink = fmt.Sprintf("%s/%s?key=%s", inviteLink, code, key)
|
|
||||||
var err error
|
var err error
|
||||||
email.html, email.text, err = emailer.construct(app, "email_confirmation", "email_", map[string]interface{}{
|
template := map[string]interface{}{
|
||||||
"helloUser": emailer.lang.Strings.template("helloUser", tmpl{"username": username}),
|
|
||||||
"clickBelow": emailer.lang.EmailConfirmation.get("clickBelow"),
|
"clickBelow": emailer.lang.EmailConfirmation.get("clickBelow"),
|
||||||
"ifItWasNotYou": emailer.lang.Strings.get("ifItWasNotYou"),
|
"ifItWasNotYou": emailer.lang.Strings.get("ifItWasNotYou"),
|
||||||
"urlVal": inviteLink,
|
|
||||||
"confirmEmail": emailer.lang.EmailConfirmation.get("confirmEmail"),
|
"confirmEmail": emailer.lang.EmailConfirmation.get("confirmEmail"),
|
||||||
"message": message,
|
"message": "",
|
||||||
})
|
}
|
||||||
|
if noSub {
|
||||||
|
template["helloUser"] = emailer.lang.Strings.get("helloUser")
|
||||||
|
empty := []string{"confirmationURL"}
|
||||||
|
for _, v := range empty {
|
||||||
|
template[v] = "{" + v + "}"
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
message := app.config.Section("email").Key("message").String()
|
||||||
|
inviteLink := app.config.Section("invite_emails").Key("url_base").String()
|
||||||
|
inviteLink = fmt.Sprintf("%s/%s?key=%s", inviteLink, code, key)
|
||||||
|
template["helloUser"] = emailer.lang.Strings.template("helloUser", tmpl{"username": username})
|
||||||
|
template["confirmationURL"] = inviteLink
|
||||||
|
template["message"] = message
|
||||||
|
}
|
||||||
|
email.html, email.text, err = emailer.construct(app, "email_confirmation", "email_", template)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -241,7 +251,7 @@ func (emailer *Emailer) constructAnnouncement(subject, md string, app *appContex
|
|||||||
text := strings.TrimPrefix(strings.TrimSuffix(stripmd.Strip(md), "</p>"), "<p>")
|
text := strings.TrimPrefix(strings.TrimSuffix(stripmd.Strip(md), "</p>"), "<p>")
|
||||||
message := app.config.Section("email").Key("message").String()
|
message := app.config.Section("email").Key("message").String()
|
||||||
var err error
|
var err error
|
||||||
email.html, email.text, err = emailer.construct(app, "announcement_email", "email_", map[string]interface{}{
|
email.html, email.text, err = emailer.construct(app, "template_email", "email_", map[string]interface{}{
|
||||||
"text": template.HTML(html),
|
"text": template.HTML(html),
|
||||||
"plaintext": text,
|
"plaintext": text,
|
||||||
"message": message,
|
"message": message,
|
||||||
@ -252,7 +262,7 @@ func (emailer *Emailer) constructAnnouncement(subject, md string, app *appContex
|
|||||||
return email, nil
|
return email, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (emailer *Emailer) constructInvite(code string, invite Invite, app *appContext) (*Email, error) {
|
func (emailer *Emailer) constructInvite(code string, invite Invite, app *appContext, noSub bool) (*Email, error) {
|
||||||
email := &Email{
|
email := &Email{
|
||||||
subject: app.config.Section("email_confirmation").Key("subject").MustString(emailer.lang.InviteEmail.get("title")),
|
subject: app.config.Section("email_confirmation").Key("subject").MustString(emailer.lang.InviteEmail.get("title")),
|
||||||
}
|
}
|
||||||
@ -261,120 +271,175 @@ func (emailer *Emailer) constructInvite(code string, invite Invite, app *appCont
|
|||||||
message := app.config.Section("email").Key("message").String()
|
message := app.config.Section("email").Key("message").String()
|
||||||
inviteLink := app.config.Section("invite_emails").Key("url_base").String()
|
inviteLink := app.config.Section("invite_emails").Key("url_base").String()
|
||||||
inviteLink = fmt.Sprintf("%s/%s", inviteLink, code)
|
inviteLink = fmt.Sprintf("%s/%s", inviteLink, code)
|
||||||
var err error
|
template := map[string]interface{}{
|
||||||
email.html, email.text, err = emailer.construct(app, "invite_emails", "email_", map[string]interface{}{
|
|
||||||
"hello": emailer.lang.InviteEmail.get("hello"),
|
"hello": emailer.lang.InviteEmail.get("hello"),
|
||||||
"youHaveBeenInvited": emailer.lang.InviteEmail.get("youHaveBeenInvited"),
|
"youHaveBeenInvited": emailer.lang.InviteEmail.get("youHaveBeenInvited"),
|
||||||
"toJoin": emailer.lang.InviteEmail.get("toJoin"),
|
"toJoin": emailer.lang.InviteEmail.get("toJoin"),
|
||||||
"inviteExpiry": emailer.lang.InviteEmail.template("inviteExpiry", tmpl{"date": d, "time": t, "expiresInMinutes": expiresIn}),
|
|
||||||
"linkButton": emailer.lang.InviteEmail.get("linkButton"),
|
"linkButton": emailer.lang.InviteEmail.get("linkButton"),
|
||||||
"invite_link": inviteLink,
|
"message": "",
|
||||||
"message": message,
|
}
|
||||||
})
|
if noSub {
|
||||||
|
template["inviteExpiry"] = emailer.lang.InviteEmail.get("inviteExpiry")
|
||||||
|
empty := []string{"inviteURL"}
|
||||||
|
for _, v := range empty {
|
||||||
|
template[v] = "{" + v + "}"
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
template["inviteExpiry"] = emailer.lang.InviteEmail.template("inviteExpiry", tmpl{"date": d, "time": t, "expiresInMinutes": expiresIn})
|
||||||
|
template["inviteURL"] = inviteLink
|
||||||
|
template["message"] = message
|
||||||
|
}
|
||||||
|
var err error
|
||||||
|
email.html, email.text, err = emailer.construct(app, "invite_emails", "email_", template)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return email, nil
|
return email, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (emailer *Emailer) constructExpiry(code string, invite Invite, app *appContext) (*Email, error) {
|
func (emailer *Emailer) constructExpiry(code string, invite Invite, app *appContext, noSub bool) (*Email, error) {
|
||||||
email := &Email{
|
email := &Email{
|
||||||
subject: emailer.lang.InviteExpiry.get("title"),
|
subject: emailer.lang.InviteExpiry.get("title"),
|
||||||
}
|
}
|
||||||
expiry := app.formatDatetime(invite.ValidTill)
|
expiry := app.formatDatetime(invite.ValidTill)
|
||||||
var err error
|
template := map[string]interface{}{
|
||||||
email.html, email.text, err = emailer.construct(app, "notifications", "expiry_", map[string]interface{}{
|
|
||||||
"inviteExpired": emailer.lang.InviteExpiry.get("inviteExpired"),
|
"inviteExpired": emailer.lang.InviteExpiry.get("inviteExpired"),
|
||||||
"expiredAt": emailer.lang.InviteExpiry.template("expiredAt", tmpl{"code": "\"" + code + "\"", "time": expiry}),
|
|
||||||
"notificationNotice": emailer.lang.InviteExpiry.get("notificationNotice"),
|
"notificationNotice": emailer.lang.InviteExpiry.get("notificationNotice"),
|
||||||
})
|
}
|
||||||
|
if noSub {
|
||||||
|
template["expiredAt"] = emailer.lang.InviteExpiry.get("expiredAt")
|
||||||
|
} else {
|
||||||
|
template["expiredAt"] = emailer.lang.InviteExpiry.template("expiredAt", tmpl{"code": "\"" + code + "\"", "time": expiry})
|
||||||
|
}
|
||||||
|
var err error
|
||||||
|
email.html, email.text, err = emailer.construct(app, "notifications", "expiry_", template)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return email, nil
|
return email, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (emailer *Emailer) constructCreated(code, username, address string, invite Invite, app *appContext) (*Email, error) {
|
func (emailer *Emailer) constructCreated(code, username, address string, invite Invite, app *appContext, noSub bool) (*Email, error) {
|
||||||
email := &Email{
|
email := &Email{
|
||||||
subject: emailer.lang.UserCreated.get("title"),
|
subject: emailer.lang.UserCreated.get("title"),
|
||||||
}
|
}
|
||||||
created := app.formatDatetime(invite.Created)
|
template := map[string]interface{}{
|
||||||
var tplAddress string
|
"nameString": emailer.lang.Strings.get("name"),
|
||||||
if app.config.Section("email").Key("no_username").MustBool(false) {
|
"addressString": emailer.lang.Strings.get("emailAddress"),
|
||||||
tplAddress = "n/a"
|
"timeString": emailer.lang.UserCreated.get("time"),
|
||||||
|
"notificationNotice": "",
|
||||||
|
}
|
||||||
|
if noSub {
|
||||||
|
template["aUserWasCreated"] = emailer.lang.UserCreated.get("aUserWasCreated")
|
||||||
|
empty := []string{"name", "address", "time"}
|
||||||
|
for _, v := range empty {
|
||||||
|
template[v] = "{" + v + "}"
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
tplAddress = address
|
created := app.formatDatetime(invite.Created)
|
||||||
|
var tplAddress string
|
||||||
|
if app.config.Section("email").Key("no_username").MustBool(false) {
|
||||||
|
tplAddress = "n/a"
|
||||||
|
} else {
|
||||||
|
tplAddress = address
|
||||||
|
}
|
||||||
|
template["aUserWasCreated"] = emailer.lang.UserCreated.template("aUserWasCreated", tmpl{"code": "\"" + code + "\""})
|
||||||
|
template["name"] = username
|
||||||
|
template["address"] = tplAddress
|
||||||
|
template["time"] = created
|
||||||
|
template["notificationNotice"] = emailer.lang.UserCreated.get("notificationNotice")
|
||||||
}
|
}
|
||||||
var err error
|
var err error
|
||||||
email.html, email.text, err = emailer.construct(app, "notifications", "created_", map[string]interface{}{
|
email.html, email.text, err = emailer.construct(app, "notifications", "created_", template)
|
||||||
"aUserWasCreated": emailer.lang.UserCreated.template("aUserWasCreated", tmpl{"code": "\"" + code + "\""}),
|
|
||||||
"name": emailer.lang.Strings.get("name"),
|
|
||||||
"address": emailer.lang.Strings.get("emailAddress"),
|
|
||||||
"time": emailer.lang.UserCreated.get("time"),
|
|
||||||
"nameVal": username,
|
|
||||||
"addressVal": tplAddress,
|
|
||||||
"timeVal": created,
|
|
||||||
"notificationNotice": emailer.lang.UserCreated.get("notificationNotice"),
|
|
||||||
})
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return email, nil
|
return email, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (emailer *Emailer) constructReset(pwr PasswordReset, app *appContext) (*Email, error) {
|
func (emailer *Emailer) constructReset(pwr PasswordReset, app *appContext, noSub bool) (*Email, error) {
|
||||||
email := &Email{
|
email := &Email{
|
||||||
subject: app.config.Section("password_resets").Key("subject").MustString(emailer.lang.PasswordReset.get("title")),
|
subject: app.config.Section("password_resets").Key("subject").MustString(emailer.lang.PasswordReset.get("title")),
|
||||||
}
|
}
|
||||||
d, t, expiresIn := emailer.formatExpiry(pwr.Expiry, true, app.datePattern, app.timePattern)
|
d, t, expiresIn := emailer.formatExpiry(pwr.Expiry, true, app.datePattern, app.timePattern)
|
||||||
message := app.config.Section("email").Key("message").String()
|
message := app.config.Section("email").Key("message").String()
|
||||||
var err error
|
template := map[string]interface{}{
|
||||||
email.html, email.text, err = emailer.construct(app, "password_resets", "email_", map[string]interface{}{
|
|
||||||
"helloUser": emailer.lang.Strings.template("helloUser", tmpl{"username": pwr.Username}),
|
|
||||||
"someoneHasRequestedReset": emailer.lang.PasswordReset.get("someoneHasRequestedReset"),
|
"someoneHasRequestedReset": emailer.lang.PasswordReset.get("someoneHasRequestedReset"),
|
||||||
"ifItWasYou": emailer.lang.PasswordReset.get("ifItWasYou"),
|
"ifItWasYou": emailer.lang.PasswordReset.get("ifItWasYou"),
|
||||||
"codeExpiry": emailer.lang.PasswordReset.template("codeExpiry", tmpl{"date": d, "time": t, "expiresInMinutes": expiresIn}),
|
|
||||||
"ifItWasNotYou": emailer.lang.Strings.get("ifItWasNotYou"),
|
"ifItWasNotYou": emailer.lang.Strings.get("ifItWasNotYou"),
|
||||||
"pin": emailer.lang.PasswordReset.get("pin"),
|
"pinString": emailer.lang.PasswordReset.get("pin"),
|
||||||
"pinVal": pwr.Pin,
|
"message": "",
|
||||||
"message": message,
|
}
|
||||||
})
|
if noSub {
|
||||||
|
template["helloUser"] = emailer.lang.Strings.get("helloUser")
|
||||||
|
template["codeExpiry"] = emailer.lang.PasswordReset.get("codeExpiry")
|
||||||
|
empty := []string{"pin"}
|
||||||
|
for _, v := range empty {
|
||||||
|
template[v] = "{" + v + "}"
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
template["helloUser"] = emailer.lang.Strings.template("helloUser", tmpl{"username": pwr.Username})
|
||||||
|
template["codeExpiry"] = emailer.lang.PasswordReset.template("codeExpiry", tmpl{"date": d, "time": t, "expiresInMinutes": expiresIn})
|
||||||
|
template["pin"] = pwr.Pin
|
||||||
|
template["message"] = message
|
||||||
|
}
|
||||||
|
var err error
|
||||||
|
email.html, email.text, err = emailer.construct(app, "password_resets", "email_", template)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return email, nil
|
return email, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (emailer *Emailer) constructDeleted(reason string, app *appContext) (*Email, error) {
|
func (emailer *Emailer) constructDeleted(reason string, app *appContext, noSub bool) (*Email, error) {
|
||||||
email := &Email{
|
email := &Email{
|
||||||
subject: app.config.Section("deletion").Key("subject").MustString(emailer.lang.UserDeleted.get("title")),
|
subject: app.config.Section("deletion").Key("subject").MustString(emailer.lang.UserDeleted.get("title")),
|
||||||
}
|
}
|
||||||
var err error
|
template := map[string]interface{}{
|
||||||
email.html, email.text, err = emailer.construct(app, "deletion", "email_", map[string]interface{}{
|
|
||||||
"yourAccountWasDeleted": emailer.lang.UserDeleted.get("yourAccountWasDeleted"),
|
"yourAccountWasDeleted": emailer.lang.UserDeleted.get("yourAccountWasDeleted"),
|
||||||
"reason": emailer.lang.UserDeleted.get("reason"),
|
"reasonString": emailer.lang.UserDeleted.get("reason"),
|
||||||
"reasonVal": reason,
|
"message": "",
|
||||||
})
|
}
|
||||||
|
if noSub {
|
||||||
|
empty := []string{"reason"}
|
||||||
|
for _, v := range empty {
|
||||||
|
template[v] = "{" + v + "}"
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
template["reason"] = reason
|
||||||
|
template["message"] = app.config.Section("email").Key("message").String()
|
||||||
|
}
|
||||||
|
var err error
|
||||||
|
email.html, email.text, err = emailer.construct(app, "deletion", "email_", template)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return email, nil
|
return email, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (emailer *Emailer) constructWelcome(username string, app *appContext) (*Email, error) {
|
func (emailer *Emailer) constructWelcome(username string, app *appContext, noSub bool) (*Email, error) {
|
||||||
email := &Email{
|
email := &Email{
|
||||||
subject: app.config.Section("welcome_email").Key("subject").MustString(emailer.lang.WelcomeEmail.get("title")),
|
subject: app.config.Section("welcome_email").Key("subject").MustString(emailer.lang.WelcomeEmail.get("title")),
|
||||||
}
|
}
|
||||||
|
template := map[string]interface{}{
|
||||||
|
"welcome": emailer.lang.WelcomeEmail.get("welcome"),
|
||||||
|
"youCanLoginWith": emailer.lang.WelcomeEmail.get("youCanLoginWith"),
|
||||||
|
"jellyfinURLString": emailer.lang.WelcomeEmail.get("jellyfinURL"),
|
||||||
|
"usernameString": emailer.lang.Strings.get("username"),
|
||||||
|
"message": "",
|
||||||
|
}
|
||||||
|
if noSub {
|
||||||
|
empty := []string{"jellyfinURL", "username"}
|
||||||
|
for _, v := range empty {
|
||||||
|
template[v] = "{" + v + "}"
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
template["jellyfinURL"] = app.config.Section("jellyfin").Key("public_server").String()
|
||||||
|
template["username"] = username
|
||||||
|
template["message"] = app.config.Section("email").Key("message").String()
|
||||||
|
}
|
||||||
var err error
|
var err error
|
||||||
email.html, email.text, err = emailer.construct(app, "welcome_email", "email_", map[string]interface{}{
|
email.html, email.text, err = emailer.construct(app, "welcome_email", "email_", template)
|
||||||
"welcome": emailer.lang.WelcomeEmail.get("welcome"),
|
|
||||||
"youCanLoginWith": emailer.lang.WelcomeEmail.get("youCanLoginWith"),
|
|
||||||
"jellyfinURL": emailer.lang.WelcomeEmail.get("jellyfinURL"),
|
|
||||||
"jellyfinURLVal": app.config.Section("jellyfin").Key("public_server").String(),
|
|
||||||
"username": emailer.lang.Strings.get("username"),
|
|
||||||
"usernameVal": username,
|
|
||||||
"message": app.config.Section("email").Key("message").String(),
|
|
||||||
})
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -7,18 +7,21 @@
|
|||||||
"helloUser": "Hi {username},"
|
"helloUser": "Hi {username},"
|
||||||
},
|
},
|
||||||
"userCreated": {
|
"userCreated": {
|
||||||
|
"name": "User creation",
|
||||||
"title": "Notice: User created",
|
"title": "Notice: User created",
|
||||||
"aUserWasCreated": "A user was created using code {code}.",
|
"aUserWasCreated": "A user was created using code {code}.",
|
||||||
"time": "Time",
|
"time": "Time",
|
||||||
"notificationNotice": "Note: Notification emails can be toggled on the admin dashboard."
|
"notificationNotice": "Note: Notification emails can be toggled on the admin dashboard."
|
||||||
},
|
},
|
||||||
"inviteExpiry": {
|
"inviteExpiry": {
|
||||||
|
"name": "Invite expiry",
|
||||||
"title": "Notice: Invite expired",
|
"title": "Notice: Invite expired",
|
||||||
"inviteExpired": "Invite expired.",
|
"inviteExpired": "Invite expired.",
|
||||||
"expiredAt": "Code {code} expired at {time}.",
|
"expiredAt": "Code {code} expired at {time}.",
|
||||||
"notificationNotice": "Note: Notification emails can be toggled on the admin dashboard."
|
"notificationNotice": "Note: Notification emails can be toggled on the admin dashboard."
|
||||||
},
|
},
|
||||||
"passwordReset": {
|
"passwordReset": {
|
||||||
|
"name": "Password reset",
|
||||||
"title": "Password reset requested - Jellyfin",
|
"title": "Password reset requested - Jellyfin",
|
||||||
"someoneHasRequestedReset": "Someone has recently requested a password reset on Jellyfin.",
|
"someoneHasRequestedReset": "Someone has recently requested a password reset on Jellyfin.",
|
||||||
"ifItWasYou": "If this was you, enter the pin below into the prompt.",
|
"ifItWasYou": "If this was you, enter the pin below into the prompt.",
|
||||||
@ -26,11 +29,13 @@
|
|||||||
"pin": "PIN"
|
"pin": "PIN"
|
||||||
},
|
},
|
||||||
"userDeleted": {
|
"userDeleted": {
|
||||||
|
"name": "User deletion",
|
||||||
"title": "Your account was deleted - Jellyfin",
|
"title": "Your account was deleted - Jellyfin",
|
||||||
"yourAccountWasDeleted": "Your Jellyfin account was deleted.",
|
"yourAccountWasDeleted": "Your Jellyfin account was deleted.",
|
||||||
"reason": "Reason"
|
"reason": "Reason"
|
||||||
},
|
},
|
||||||
"inviteEmail": {
|
"inviteEmail": {
|
||||||
|
"name": "Invite email",
|
||||||
"title": "Invite - Jellyfin",
|
"title": "Invite - Jellyfin",
|
||||||
"hello": "Hi",
|
"hello": "Hi",
|
||||||
"youHaveBeenInvited": "You've been invited to Jellyfin.",
|
"youHaveBeenInvited": "You've been invited to Jellyfin.",
|
||||||
@ -39,12 +44,14 @@
|
|||||||
"linkButton": "Setup your account"
|
"linkButton": "Setup your account"
|
||||||
},
|
},
|
||||||
"welcomeEmail": {
|
"welcomeEmail": {
|
||||||
|
"name": "Welcome email",
|
||||||
"title": "Welcome to Jellyfin",
|
"title": "Welcome to Jellyfin",
|
||||||
"welcome": "Welcome to Jellyfin!",
|
"welcome": "Welcome to Jellyfin!",
|
||||||
"youCanLoginWith": "You can login with the details below",
|
"youCanLoginWith": "You can login with the details below",
|
||||||
"jellyfinURL": "URL"
|
"jellyfinURL": "URL"
|
||||||
},
|
},
|
||||||
"emailConfirmation": {
|
"emailConfirmation": {
|
||||||
|
"name": "Confirmation email",
|
||||||
"title": "Confirm your email - Jellyfin",
|
"title": "Confirm your email - Jellyfin",
|
||||||
"clickBelow": "Click the link below to confirm your email address and start using Jellyfin.",
|
"clickBelow": "Click the link below to confirm your email address and start using Jellyfin.",
|
||||||
"confirmEmail": "Confirm Email"
|
"confirmEmail": "Confirm Email"
|
||||||
|
@ -64,7 +64,7 @@
|
|||||||
<p>{{ .clickBelow }}</p>
|
<p>{{ .clickBelow }}</p>
|
||||||
<p>{{ .ifItWasNotYou }}</p>
|
<p>{{ .ifItWasNotYou }}</p>
|
||||||
</mj-text>
|
</mj-text>
|
||||||
<mj-button mj-class="blue bold" href="{{ .urlVal }}">{{ .confirmEmail }}</mj-button>
|
<mj-button mj-class="blue bold" href="{{ .confirmationURL }}">{{ .confirmEmail }}</mj-button>
|
||||||
</mj-column>
|
</mj-column>
|
||||||
</mj-section>
|
</mj-section>
|
||||||
<mj-section mj-class="bg2">
|
<mj-section mj-class="bg2">
|
||||||
|
@ -3,6 +3,6 @@
|
|||||||
{{ .clickBelow }}
|
{{ .clickBelow }}
|
||||||
{{ .ifItWasNotYou }}
|
{{ .ifItWasNotYou }}
|
||||||
|
|
||||||
{{ .urlVal }}
|
{{ .confirmationURL }}
|
||||||
|
|
||||||
{{ .message }}
|
{{ .message }}
|
||||||
|
@ -64,14 +64,14 @@
|
|||||||
</mj-text>
|
</mj-text>
|
||||||
<mj-table mj-class="text" container-background-color="#242424">
|
<mj-table mj-class="text" container-background-color="#242424">
|
||||||
<tr style="text-align: left;">
|
<tr style="text-align: left;">
|
||||||
<th>{{ .name }}</th>
|
<th>{{ .nameString }}</th>
|
||||||
<th>{{ .address }}</th>
|
<th>{{ .addressString }}</th>
|
||||||
<th>{{ .time }}</th>
|
<th>{{ .timeString }}</th>
|
||||||
</tr>
|
</tr>
|
||||||
<tr style="font-style: italic; text-align: left; color: rgb(153,153,153);">
|
<tr style="font-style: italic; text-align: left; color: rgb(153,153,153);">
|
||||||
<th>{{ .nameVal }}</th>
|
<th>{{ .name }}</th>
|
||||||
<th>{{ .addressVal }}</th>
|
<th>{{ .address }}</th>
|
||||||
<th>{{ .timeVal }}</th>
|
<th>{{ .time }}</th>
|
||||||
</mj-table>
|
</mj-table>
|
||||||
</mj-column>
|
</mj-column>
|
||||||
</mj-section>
|
</mj-section>
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
{{ .aUserWasCreated }}
|
{{ .aUserWasCreated }}
|
||||||
|
|
||||||
{{ .name }}: {{ .nameVal }}
|
{{ .nameString }}: {{ .name }}
|
||||||
{{ .address }}: {{ .addressVal }}
|
{{ .addressString }}: {{ .address }}
|
||||||
{{ .time }}: {{ .timeVal }}
|
{{ .timeString }}: {{ .time }}
|
||||||
|
|
||||||
{{ .notificationNotice }}
|
{{ .notificationNotice }}
|
||||||
|
@ -61,7 +61,7 @@
|
|||||||
<mj-column>
|
<mj-column>
|
||||||
<mj-text mj-class="text" font-size="16px" font-family="Noto Sans, Helvetica, Arial, sans-serif">
|
<mj-text mj-class="text" font-size="16px" font-family="Noto Sans, Helvetica, Arial, sans-serif">
|
||||||
<h3>{{ .yourAccountWasDeleted }}</h3>
|
<h3>{{ .yourAccountWasDeleted }}</h3>
|
||||||
<p>{{ .reason }}: <i>{{ .reasonVal }}</i></p>
|
<p>{{ .reasonString }}: <i>{{ .reason }}</i></p>
|
||||||
</mj-text>
|
</mj-text>
|
||||||
</mj-column>
|
</mj-column>
|
||||||
</mj-section>
|
</mj-section>
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
{{ .yourAccountWasDeleted }}
|
{{ .yourAccountWasDeleted }}
|
||||||
{{ .reason }}: {{ .reasonVal }}
|
{{ .reasonString }}: {{ .reason }}
|
||||||
|
|
||||||
{{ .message }}
|
{{ .message }}
|
||||||
|
@ -66,7 +66,7 @@
|
|||||||
<p>{{ .codeExpiry }}</p>
|
<p>{{ .codeExpiry }}</p>
|
||||||
<p>{{ .ifItWasNotYou }}</p>
|
<p>{{ .ifItWasNotYou }}</p>
|
||||||
</mj-text>
|
</mj-text>
|
||||||
<mj-button mj-class="blue bold"><mj-raw>{{ .pinVal }}</mj-raw></mj-button>
|
<mj-button mj-class="blue bold"><mj-raw>{{ .pin }}</mj-raw></mj-button>
|
||||||
</mj-column>
|
</mj-column>
|
||||||
</mj-section>
|
</mj-section>
|
||||||
<mj-section mj-class="bg2">
|
<mj-section mj-class="bg2">
|
||||||
|
@ -5,6 +5,6 @@
|
|||||||
{{ .codeExpiry }}
|
{{ .codeExpiry }}
|
||||||
{{ .ifItWasNotYou }}
|
{{ .ifItWasNotYou }}
|
||||||
|
|
||||||
{{ .pin }}: {{ .pinVal }}
|
{{ .pinString }}: {{ .pin }}
|
||||||
|
|
||||||
{{ .message }}
|
{{ .message }}
|
||||||
|
@ -65,7 +65,7 @@
|
|||||||
<p>{{ .toJoin }}</p>
|
<p>{{ .toJoin }}</p>
|
||||||
<p>{{ .inviteExpiry }}</p>
|
<p>{{ .inviteExpiry }}</p>
|
||||||
</mj-text>
|
</mj-text>
|
||||||
<mj-button mj-class="blue bold" href="{{ .invite_link }}">{{ .linkButton }}</mj-button>
|
<mj-button mj-class="blue bold" href="{{ .inviteURL }}">{{ .linkButton }}</mj-button>
|
||||||
</mj-column>
|
</mj-column>
|
||||||
</mj-section>
|
</mj-section>
|
||||||
<mj-section mj-class="bg2">
|
<mj-section mj-class="bg2">
|
||||||
|
@ -3,6 +3,6 @@
|
|||||||
{{ .toJoin }}
|
{{ .toJoin }}
|
||||||
{{ .inviteExpiry }}
|
{{ .inviteExpiry }}
|
||||||
|
|
||||||
{{ .invite_link }}
|
{{ .inviteURL }}
|
||||||
|
|
||||||
{{ .message }}
|
{{ .message }}
|
||||||
|
@ -62,8 +62,8 @@
|
|||||||
<mj-text mj-class="text" font-size="16px" font-family="Noto Sans, Helvetica, Arial, sans-serif">
|
<mj-text mj-class="text" font-size="16px" font-family="Noto Sans, Helvetica, Arial, sans-serif">
|
||||||
<h3>{{ .welcome }}</h3>
|
<h3>{{ .welcome }}</h3>
|
||||||
<p>{{ .youCanLoginWith }}:</p>
|
<p>{{ .youCanLoginWith }}:</p>
|
||||||
{{ .jellyfinURL }}: <a href="{{ .jellyfinURLVal }}">{{ .jellyfinURLVal }}</a>
|
{{ .jellyfinURLString }}: <a href="{{ .jellyfinURLVal }}">{{ .jellyfinURL }}</a>
|
||||||
<p>{{ .username }}: <i>{{ .usernameVal }}</i></p>
|
<p>{{ .usernameString }}: <i>{{ .username }}</i></p>
|
||||||
</mj-text>
|
</mj-text>
|
||||||
</mj-column>
|
</mj-column>
|
||||||
</mj-section>
|
</mj-section>
|
||||||
|
@ -2,8 +2,8 @@
|
|||||||
|
|
||||||
{{ .youCanLoginWith }}:
|
{{ .youCanLoginWith }}:
|
||||||
|
|
||||||
{{ .jellyfinURL }}: {{ .jellyfinURLVal }}
|
{{ .jellyfinURLString }}: {{ .jellyfinURL }}
|
||||||
{{ .username }}: {{ .usernameVal }}
|
{{ .usernameString }}: {{ .username }}
|
||||||
|
|
||||||
|
|
||||||
{{ .message }}
|
{{ .message }}
|
||||||
|
10
models.go
10
models.go
@ -174,3 +174,13 @@ type settings struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type langDTO map[string]string
|
type langDTO map[string]string
|
||||||
|
|
||||||
|
type emailListDTO map[string]string
|
||||||
|
type emailDTO struct {
|
||||||
|
Content string `json:"content"`
|
||||||
|
Variables []string `json:"Variables"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type emailSetDTO struct {
|
||||||
|
Content string `json:"content"`
|
||||||
|
}
|
||||||
|
@ -81,7 +81,7 @@ func pwrMonitor(app *appContext, watcher *fsnotify.Watcher) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
address = addr.(string)
|
address = addr.(string)
|
||||||
msg, err := app.email.constructReset(pwr, app)
|
msg, err := app.email.constructReset(pwr, app, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
app.err.Printf("Failed to construct password reset email for %s", pwr.Username)
|
app.err.Printf("Failed to construct password reset email for %s", pwr.Username)
|
||||||
app.debug.Printf("%s: Error: %s", pwr.Username, err)
|
app.debug.Printf("%s: Error: %s", pwr.Username, err)
|
||||||
|
@ -139,6 +139,8 @@ func (app *appContext) loadRoutes(router *gin.Engine) {
|
|||||||
// api.POST(p + "/setDefaults", app.SetDefaults)
|
// api.POST(p + "/setDefaults", app.SetDefaults)
|
||||||
api.POST(p+"/users/settings", app.ApplySettings)
|
api.POST(p+"/users/settings", app.ApplySettings)
|
||||||
api.POST(p+"/users/announce", app.Announce)
|
api.POST(p+"/users/announce", app.Announce)
|
||||||
|
api.GET(p+"/config/emails", app.GetEmails)
|
||||||
|
api.GET(p+"/config/emails/:id", app.GetEmail)
|
||||||
api.GET(p+"/config", app.GetConfig)
|
api.GET(p+"/config", app.GetConfig)
|
||||||
api.POST(p+"/config", app.ModifyConfig)
|
api.POST(p+"/config", app.ModifyConfig)
|
||||||
api.POST(p+"/restart", app.restart)
|
api.POST(p+"/restart", app.restart)
|
||||||
|
37
storage.go
37
storage.go
@ -14,15 +14,26 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type Storage struct {
|
type Storage struct {
|
||||||
timePattern string
|
timePattern string
|
||||||
invite_path, emails_path, policy_path, configuration_path, displayprefs_path, ombi_path, profiles_path string
|
invite_path, emails_path, policy_path, configuration_path, displayprefs_path, ombi_path, profiles_path, customEmails_path string
|
||||||
invites Invites
|
invites Invites
|
||||||
profiles map[string]Profile
|
profiles map[string]Profile
|
||||||
defaultProfile string
|
defaultProfile string
|
||||||
emails, displayprefs, ombi_template map[string]interface{}
|
emails, displayprefs, ombi_template map[string]interface{}
|
||||||
policy mediabrowser.Policy
|
customEmails customEmails
|
||||||
configuration mediabrowser.Configuration
|
policy mediabrowser.Policy
|
||||||
lang Lang
|
configuration mediabrowser.Configuration
|
||||||
|
lang Lang
|
||||||
|
}
|
||||||
|
|
||||||
|
type customEmails struct {
|
||||||
|
UserCreated string `json:"userCreated"`
|
||||||
|
InviteExpiry string `json:"inviteExpiry"`
|
||||||
|
PasswordReset string `json:"passwordReset"`
|
||||||
|
UserDeleted string `json:"userDeleted"`
|
||||||
|
InviteEmail string `json:"inviteEmail"`
|
||||||
|
WelcomeEmail string `json:"welcomeEmail"`
|
||||||
|
EmailConfirmation string `json:"emailConfirmation"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// timePattern: %Y-%m-%dT%H:%M:%S.%f
|
// timePattern: %Y-%m-%dT%H:%M:%S.%f
|
||||||
@ -394,6 +405,14 @@ func (st *Storage) storeEmails() error {
|
|||||||
return storeJSON(st.emails_path, st.emails)
|
return storeJSON(st.emails_path, st.emails)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (st *Storage) loadCustomEmails() error {
|
||||||
|
return loadJSON(st.customEmails_path, &st.customEmails)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (st *Storage) storeCustomEmails() error {
|
||||||
|
return storeJSON(st.customEmails_path, st.customEmails)
|
||||||
|
}
|
||||||
|
|
||||||
func (st *Storage) loadPolicy() error {
|
func (st *Storage) loadPolicy() error {
|
||||||
return loadJSON(st.policy_path, &st.policy)
|
return loadJSON(st.policy_path, &st.policy)
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user