diff --git a/api.go b/api.go index 6a4e38f..b473c38 100644 --- a/api.go +++ b/api.go @@ -39,9 +39,9 @@ func respondBool(code int, val bool, gc *gin.Context) { } func (app *appContext) loadStrftime() { - app.datePattern = app.config.Section("email").Key("date_format").String() + app.datePattern = app.config.Section("messages").Key("date_format").String() app.timePattern = `%H:%M` - if val, _ := app.config.Section("email").Key("use_24h").Bool(); !val { + if val, _ := app.config.Section("messages").Key("use_24h").Bool(); !val { app.timePattern = `%I:%M %p` } return @@ -331,7 +331,7 @@ func (app *appContext) newUser(req newUserDTO, confirmed bool) (f errorFunc, suc return } telegramTokenIndex := -1 - if app.config.Section("telegram").Key("enabled").MustBool(false) { + if telegramEnabled { if req.TelegramPIN == "" { if app.config.Section("telegram").Key("required").MustBool(false) { f = func(gc *gin.Context) { @@ -480,7 +480,7 @@ func (app *appContext) newUser(req newUserDTO, confirmed bool) (f errorFunc, suc } } - if app.config.Section("telegram").Key("enabled").MustBool(false) && telegramTokenIndex != -1 { + if telegramEnabled && telegramTokenIndex != -1 { tgToken := app.telegram.verifiedTokens[telegramTokenIndex] tgUser := TelegramUser{ ChatID: tgToken.ChatID, @@ -579,7 +579,7 @@ func (app *appContext) EnableDisableUsers(gc *gin.Context) { "GetUser": map[string]string{}, "SetPolicy": map[string]string{}, } - sendMail := emailEnabled || app.config.Section("telegram").Key("enabled").MustBool(false) + sendMail := messagesEnabled var msg *Message var err error if sendMail { @@ -636,7 +636,7 @@ func (app *appContext) DeleteUsers(gc *gin.Context) { gc.BindJSON(&req) errors := map[string]string{} ombiEnabled := app.config.Section("ombi").Key("enabled").MustBool(false) - sendMail := emailEnabled || app.config.Section("telegram").Key("enabled").MustBool(false) + sendMail := messagesEnabled var msg *Message var err error if sendMail { @@ -730,7 +730,7 @@ func (app *appContext) ExtendExpiry(gc *gin.Context) { func (app *appContext) Announce(gc *gin.Context) { var req announcementDTO gc.BindJSON(&req) - if !(emailEnabled || app.config.Section("telegram").Key("enabled").MustBool(false)) { + if !messagesEnabled { respondBool(400, false, gc) return } @@ -1384,6 +1384,10 @@ func (app *appContext) GetConfig(gc *gin.Context) { el := resp.Sections["email"].Settings["language"] el.Options = emailOptions el.Value = app.config.Section("email").Key("language").MustString("en-us") + telegramOptions := app.storage.lang.Email.getOptions() + tl := resp.Sections["telegram"].Settings["language"] + tl.Options = telegramOptions + tl.Value = app.config.Section("telegram").Key("language").MustString("en-us") if updater == "" { delete(resp.Sections, "updates") for i, v := range resp.Order { @@ -1412,6 +1416,7 @@ func (app *appContext) GetConfig(gc *gin.Context) { resp.Sections["ui"].Settings["language-admin"] = al resp.Sections["email"].Settings["language"] = el resp.Sections["password_resets"].Settings["language"] = pl + resp.Sections["telegram"].Settings["language"] = tl gc.JSON(200, resp) } @@ -1436,6 +1441,9 @@ func (app *appContext) ModifyConfig(gc *gin.Context) { tempConfig.NewSection(section) } for setting, value := range settings.(map[string]interface{}) { + if section == "email" && setting == "method" && value == "disabled" { + value = "" + } if value.(string) != app.config.Section(section).Key(setting).MustString("") { tempConfig.Section(section).Key(setting).SetValue(value.(string)) } diff --git a/config.go b/config.go index 9ef527f..9c60efc 100644 --- a/config.go +++ b/config.go @@ -12,6 +12,8 @@ import ( ) var emailEnabled = false +var messagesEnabled = false +var telegramEnabled = false func (app *appContext) GetPath(sect, key string) (fs.FS, string) { val := app.config.Section(sect).Key(key).MustString("") @@ -83,12 +85,19 @@ func (app *appContext) loadConfig() error { app.config.Section("jellyfin").Key("version").SetValue(version) app.config.Section("jellyfin").Key("device").SetValue("jfa-go") app.config.Section("jellyfin").Key("device_id").SetValue(fmt.Sprintf("jfa-go-%s-%s", version, commit)) - - if app.config.Section("email").Key("method").MustString("") == "" { + messagesEnabled = app.config.Section("messages").Key("enabled").MustBool(false) + telegramEnabled = app.config.Section("telegram").Key("enabled").MustBool(false) + if !messagesEnabled { + emailEnabled = false + telegramEnabled = false + } else if app.config.Section("email").Key("method").MustString("") == "" { emailEnabled = false } else { emailEnabled = true } + if !emailEnabled && !telegramEnabled { + messagesEnabled = false + } app.MustSetValue("updates", "enabled", "true") releaseChannel := app.config.Section("updates").Key("channel").String() @@ -134,3 +143,28 @@ func (app *appContext) loadConfig() error { return nil } + +func (app *appContext) migrateEmailConfig() { + tempConfig, _ := ini.Load(app.configPath) + fmt.Println(warning("Part of your email configuration will be migrated to the new \"messages\" section.\nA backup will be made.")) + err := tempConfig.SaveTo(app.configPath + "_" + commit + ".bak") + if err != nil { + app.err.Fatalf("Failed to backup config: %v", err) + return + } + for _, setting := range []string{"use_24h", "date_format", "message"} { + if val := app.config.Section("email").Key(setting).Value(); val != "" { + tempConfig.Section("email").Key(setting).SetValue("") + tempConfig.Section("messages").Key(setting).SetValue(val) + } + } + if app.config.Section("messages").Key("enabled").MustBool(false) || app.config.Section("telegram").Key("enabled").MustBool(false) { + tempConfig.Section("messages").Key("enabled").SetValue("true") + } + err = tempConfig.SaveTo(app.configPath) + if err != nil { + app.err.Fatalf("Failed to save config: %v", err) + return + } + app.loadConfig() +} diff --git a/config/config-base.json b/config/config-base.json index 61be322..c572d09 100644 --- a/config/config-base.json +++ b/config/config-base.json @@ -345,33 +345,20 @@ } } }, - "email": { + "messages": { "order": [], "meta": { - "name": "Email", - "description": "General email settings." + "name": "Messages/Notifications", + "description": "General settings for emails/messages." }, "settings": { - "language": { - "name": "Email Language", - "required": false, - "requires_restart": false, - "depends_true": "method", - "type": "select", - "options": [ - ["en-us", "English (US)"] - ], - "value": "en-us", - "description": "Default email language. Submit a PR on github if you'd like to translate." - }, - "no_username": { - "name": "Use email addresses as username", - "required": false, - "requires_restart": false, - "depends_true": "method", + "enabled": { + "name": "Enabled", + "required": true, + "requires_restart": true, "type": "bool", - "value": false, - "description": "Use email address from invite form as username on Jellyfin." + "value": true, + "description": "Enable the sending of emails/messages such as password resets, announcements, etc." }, "use_24h": { "name": "Use 24h time", @@ -399,6 +386,37 @@ "type": "text", "value": "Need help? contact me.", "description": "Message displayed at bottom of emails." + } + } + }, + "email": { + "order": [], + "meta": { + "name": "Email", + "description": "General email settings.", + "depends_true": "messages|enabled" + }, + "settings": { + "language": { + "name": "Email Language", + "required": false, + "requires_restart": false, + "depends_true": "method", + "type": "select", + "options": [ + ["en-us", "English (US)"] + ], + "value": "en-us", + "description": "Default email language. Submit a PR on github if you'd like to translate." + }, + "no_username": { + "name": "Use email addresses as username", + "required": false, + "requires_restart": false, + "depends_true": "method", + "type": "bool", + "value": false, + "description": "Use email address from invite form as username on Jellyfin." }, "method": { "name": "Email method", @@ -443,12 +461,143 @@ } } }, + "mailgun": { + "order": [], + "meta": { + "name": "Mailgun (Email)", + "description": "Mailgun API connection settings", + "depends_true": "email|method" + }, + "settings": { + "api_url": { + "name": "API URL", + "required": false, + "requires_restart": false, + "type": "text", + "value": "https://api.mailgun.net..." + }, + "api_key": { + "name": "API Key", + "required": false, + "requires_restart": false, + "type": "text", + "value": "your api key" + } + } + }, + "smtp": { + "order": [], + "meta": { + "name": "SMTP (Email)", + "description": "SMTP Server connection settings.", + "depends_true": "email|method" + }, + "settings": { + "username": { + "name": "Username", + "required": false, + "requires_restart": false, + "type": "text", + "value": "", + "description": "Username for SMTP. Leave blank to user send from address as username." + }, + "encryption": { + "name": "Encryption Method", + "required": false, + "requires_restart": false, + "type": "select", + "options": [ + ["ssl_tls", "SSL/TLS"], + ["starttls", "STARTTLS"] + ], + "value": "starttls", + "description": "Your email provider should provide different ports for each encryption method. Generally 465 for ssl_tls, 587 for starttls." + }, + "server": { + "name": "Server address", + "required": false, + "requires_restart": false, + "type": "text", + "value": "smtp.jellyf.in", + "description": "SMTP Server address." + }, + "port": { + "name": "Port", + "required": false, + "requires_restart": false, + "type": "number", + "value": 465 + }, + "password": { + "name": "Password", + "required": false, + "requires_restart": false, + "type": "password", + "value": "smtp password" + }, + "ssl_cert": { + "name": "Path to custom SSL certificate", + "required": false, + "requires_restart": false, + "advanced": true, + "type": "text", + "value": "", + "description": "Use if your SMTP server's SSL Certificate is not trusted by the system." + } + } + }, + "telegram": { + "order": [], + "meta": { + "name": "Telegram", + "description": "Settings for Telegram signup/notifications" + }, + "settings": { + "enabled": { + "name": "Enabled", + "required": false, + "requires_restart": true, + "type": "bool", + "value": false, + "description": "Enable signup verification through Telegram and the sending of notifications through it." + }, + "required": { + "name": "Require on sign-up", + "required": false, + "required_restart": true, + "type": "bool", + "value": false, + "description": "Require telegram connection on sign-up." + }, + "token": { + "name": "API Token", + "required": false, + "requires_restart": true, + "depends_true": "enabled", + "type": "text", + "value": "", + "description": "Telegram Bot API Token." + }, + "language": { + "name": "Language", + "required": false, + "requires_restart": false, + "depends_true": "enabled", + "type": "select", + "options": [ + ["en-us", "English (US)"] + ], + "value": "en-us", + "description": "Default telegram message language. Visit weblate if you'd like to translate." + } + } + }, "password_resets": { "order": [], "meta": { "name": "Password Resets", "description": "Settings for the password reset handler.", - "depends_true": "email|method" + "depends_true": "messages|enabled" }, "settings": { "enabled": { @@ -580,7 +729,7 @@ "meta": { "name": "Notifications", "description": "Notification related settings.", - "depends_true": "email|method" + "depends_true": "messages|enabled" }, "settings": { "enabled": { @@ -633,91 +782,6 @@ } } }, - "mailgun": { - "order": [], - "meta": { - "name": "Mailgun (Email)", - "description": "Mailgun API connection settings", - "depends_true": "email|method" - }, - "settings": { - "api_url": { - "name": "API URL", - "required": false, - "requires_restart": false, - "type": "text", - "value": "https://api.mailgun.net..." - }, - "api_key": { - "name": "API Key", - "required": false, - "requires_restart": false, - "type": "text", - "value": "your api key" - } - } - }, - "smtp": { - "order": [], - "meta": { - "name": "SMTP (Email)", - "description": "SMTP Server connection settings.", - "depends_true": "email|method" - }, - "settings": { - "username": { - "name": "Username", - "required": false, - "requires_restart": false, - "type": "text", - "value": "", - "description": "Username for SMTP. Leave blank to user send from address as username." - }, - "encryption": { - "name": "Encryption Method", - "required": false, - "requires_restart": false, - "type": "select", - "options": [ - ["ssl_tls", "SSL/TLS"], - ["starttls", "STARTTLS"] - ], - "value": "starttls", - "description": "Your email provider should provide different ports for each encryption method. Generally 465 for ssl_tls, 587 for starttls." - }, - "server": { - "name": "Server address", - "required": false, - "requires_restart": false, - "type": "text", - "value": "smtp.jellyf.in", - "description": "SMTP Server address." - }, - "port": { - "name": "Port", - "required": false, - "requires_restart": false, - "type": "number", - "value": 465 - }, - "password": { - "name": "Password", - "required": false, - "requires_restart": false, - "type": "password", - "value": "smtp password" - }, - "ssl_cert": { - "name": "Path to custom SSL certificate", - "required": false, - "requires_restart": false, - "advanced": true, - "type": "text", - "value": "", - "description": "Use if your SMTP server's SSL Certificate is not trusted by the system." - } - } - }, "ombi": { "order": [], "meta": { @@ -756,9 +820,9 @@ "welcome_email": { "order": [], "meta": { - "name": "Welcome Emails", - "description": "Optionally send a welcome email to new users with the Jellyfin URL and their username.", - "depends_true": "email|method" + "name": "Welcome Message", + "description": "Optionally send a welcome message to new users with the Jellyfin URL and their username.", + "depends_true": "messages|enabled" }, "settings": { "enabled": { @@ -865,14 +929,14 @@ "requires_restart": false, "type": "bool", "value": true, - "depends_true": "email|method", + "depends_true": "messages|enabled", "description": "Send an email when a user's account expires." }, "subject": { "name": "Email subject", "required": false, "requires_restart": false, - "depends_true": "email|method", + "depends_true": "messages|enabled", "type": "text", "value": "", "description": "Subject of user expiry emails." @@ -882,7 +946,7 @@ "required": false, "requires_restart": false, "advanced": true, - "depends_true": "email|method", + "depends_true": "messages|enabled", "type": "text", "value": "", "description": "Path to custom email html" @@ -892,7 +956,7 @@ "required": false, "requires_restart": false, "advanced": true, - "depends_true": "email|method", + "depends_true": "messages|enabled", "type": "text", "value": "", "description": "Path to custom email in plain text" @@ -904,7 +968,7 @@ "meta": { "name": "Account Disabling/Enabling", "description": "Subject/email files for account disabling/enabling emails.", - "depends_true": "email|method" + "depends_true": "messages|enabled" }, "settings": { "subject_disabled": { @@ -966,7 +1030,7 @@ "meta": { "name": "Account Deletion", "description": "Subject/email files for account deletion emails.", - "depends_true": "email|method" + "depends_true": "messages|enabled" }, "settings": { "subject": { @@ -997,53 +1061,6 @@ } } }, - "telegram": { - "order": [], - "meta": { - "name": "Telegram", - "description": "Settings for Telegram signup/notifications" - }, - "settings": { - "enabled": { - "name": "Enabled", - "required": false, - "requires_restart": true, - "type": "bool", - "value": false, - "description": "Enable signup verification through Telegram and the sending of notifications through it." - }, - "required": { - "name": "Require on sign-up", - "required": false, - "required_restart": true, - "type": "bool", - "value": false, - "description": "Require telegram connection on sign-up." - }, - "token": { - "name": "API Token", - "required": false, - "requires_restart": true, - "depends_true": "enabled", - "type": "text", - "value": "", - "description": "Telegram Bot API Token." - }, - "language": { - "name": "Language", - "required": false, - "requires_restart": false, - "depends_true": "enabled", - "type": "select", - "options": [ - ["en-us", "English (US)"] - ], - "value": "en-us", - "description": "Default telegram message language. Visit weblate if you'd like to translate." - } - } - - }, "files": { "order": [], "meta": { diff --git a/email.go b/email.go index ef9a846..5a7f6bd 100644 --- a/email.go +++ b/email.go @@ -289,7 +289,7 @@ func (emailer *Emailer) confirmationValues(code, username, key string, app *appC template[v] = "{" + v + "}" } } else { - message := app.config.Section("email").Key("message").String() + message := app.config.Section("messages").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}) @@ -327,7 +327,7 @@ func (emailer *Emailer) constructTemplate(subject, md string, app *appContext) ( renderer := html.NewRenderer(html.RendererOptions{Flags: html.Smartypants}) html := markdown.ToHTML([]byte(md), nil, renderer) text := stripMarkdown(md) - message := app.config.Section("email").Key("message").String() + message := app.config.Section("messages").Key("message").String() var err error email.HTML, email.Text, email.Markdown, err = emailer.construct(app, "template_email", "email_", map[string]interface{}{ "text": template.HTML(html), @@ -344,7 +344,7 @@ func (emailer *Emailer) constructTemplate(subject, md string, app *appContext) ( func (emailer *Emailer) inviteValues(code string, invite Invite, app *appContext, noSub bool) map[string]interface{} { expiry := invite.ValidTill d, t, expiresIn := emailer.formatExpiry(expiry, false, app.datePattern, app.timePattern) - message := app.config.Section("email").Key("message").String() + message := app.config.Section("messages").Key("message").String() inviteLink := app.config.Section("invite_emails").Key("url_base").String() inviteLink = fmt.Sprintf("%s/%s", inviteLink, code) template := map[string]interface{}{ @@ -489,7 +489,7 @@ func (emailer *Emailer) constructCreated(code, username, address string, invite func (emailer *Emailer) resetValues(pwr PasswordReset, app *appContext, noSub bool) map[string]interface{} { d, t, expiresIn := emailer.formatExpiry(pwr.Expiry, true, app.datePattern, app.timePattern) - message := app.config.Section("email").Key("message").String() + message := app.config.Section("messages").Key("message").String() template := map[string]interface{}{ "someoneHasRequestedReset": emailer.lang.PasswordReset.get("someoneHasRequestedReset"), "ifItWasNotYou": emailer.lang.Strings.get("ifItWasNotYou"), @@ -574,7 +574,7 @@ func (emailer *Emailer) deletedValues(reason string, app *appContext, noSub bool } } else { template["reason"] = reason - template["message"] = app.config.Section("email").Key("message").String() + template["message"] = app.config.Section("messages").Key("message").String() } return template } @@ -615,7 +615,7 @@ func (emailer *Emailer) disabledValues(reason string, app *appContext, noSub boo } } else { template["reason"] = reason - template["message"] = app.config.Section("email").Key("message").String() + template["message"] = app.config.Section("messages").Key("message").String() } return template } @@ -656,7 +656,7 @@ func (emailer *Emailer) enabledValues(reason string, app *appContext, noSub bool } } else { template["reason"] = reason - template["message"] = app.config.Section("email").Key("message").String() + template["message"] = app.config.Section("messages").Key("message").String() } return template } @@ -701,7 +701,7 @@ func (emailer *Emailer) welcomeValues(username string, expiry time.Time, app *ap } else { template["jellyfinURL"] = app.config.Section("jellyfin").Key("public_server").String() template["username"] = username - template["message"] = app.config.Section("email").Key("message").String() + template["message"] = app.config.Section("messages").Key("message").String() exp := app.formatDatetime(expiry) if !expiry.IsZero() { if custom { @@ -756,7 +756,7 @@ func (emailer *Emailer) userExpiredValues(app *appContext, noSub bool) map[strin "message": "", } if !noSub { - template["message"] = app.config.Section("email").Key("message").String() + template["message"] = app.config.Section("messages").Key("message").String() } return template } @@ -790,10 +790,9 @@ func (emailer *Emailer) send(email *Message, address ...string) error { } func (app *appContext) sendByID(email *Message, ID ...string) error { - tgEnabled := app.config.Section("telegram").Key("enabled").MustBool(false) for _, id := range ID { var err error - if tgChat, ok := app.storage.telegram[id]; ok && tgChat.Contact && tgEnabled { + if tgChat, ok := app.storage.telegram[id]; ok && tgChat.Contact && telegramEnabled { err = app.telegram.Send(email, tgChat.ChatID) } else if address, ok := app.storage.emails[id]; ok { err = app.email.send(email, address.(string)) @@ -806,8 +805,7 @@ func (app *appContext) sendByID(email *Message, ID ...string) error { } func (app *appContext) getAddressOrName(jfID string) string { - tgEnabled := app.config.Section("telegram").Key("enabled").MustBool(false) - if tgChat, ok := app.storage.telegram[jfID]; ok && tgChat.Contact && tgEnabled { + if tgChat, ok := app.storage.telegram[jfID]; ok && tgChat.Contact && telegramEnabled { return "@" + tgChat.Username } if addr, ok := app.storage.emails[jfID]; ok { diff --git a/html/admin.html b/html/admin.html index a074ec3..a5b784f 100644 --- a/html/admin.html +++ b/html/admin.html @@ -180,8 +180,8 @@