Compare commits

...

5 Commits

Author SHA1 Message Date
Cornichon420 9ae16163bb Translated using Weblate (French)
Currently translated at 100.0% (109 of 109 strings)

Translation: jfa-go/Setup
Translate-URL: https://weblate.jfa-go.com/projects/jfa-go/setup/fr/
2021-10-07 17:19:30 +02:00
Sundune c5ce66bd4d translation from Weblate (German)
Currently translated at 98.2% (165 of 168 strings)

Translation: jfa-go/Admin Page
Translate-URL: https://weblate.jfa-go.com/projects/jfa-go/admin/de/
2021-10-07 17:19:30 +02:00
Cornichon420 da8dd7def8 translation from Weblate (French)
Currently translated at 100.0% (37 of 37 strings)

Translation: jfa-go/Account Creation Form
Translate-URL: https://weblate.jfa-go.com/projects/jfa-go/form/fr/
2021-10-07 17:19:29 +02:00
Cornichon420 a4b5d6dea8 translation from Weblate (French)
Currently translated at 100.0% (168 of 168 strings)

Translation: jfa-go/Admin Page
Translate-URL: https://weblate.jfa-go.com/projects/jfa-go/admin/fr/
2021-10-07 17:19:29 +02:00
Harvey Tindall 77799b2917
smtp: only construct email once
also switch layout in email file to group each driver and its methods
together.
2021-10-07 16:19:06 +01:00
5 changed files with 101 additions and 105 deletions

161
email.go
View File

@ -13,7 +13,6 @@ import (
"os"
"strconv"
"strings"
"sync"
textTemplate "text/template"
"time"
@ -31,84 +30,6 @@ type EmailClient interface {
Send(fromName, fromAddr string, message *Message, address ...string) error
}
type DummyClient struct{}
func (dc *DummyClient) Send(fromName, fromAddr string, email *Message, 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
}
func (mg *Mailgun) Send(fromName, fromAddr string, email *Message, address ...string) error {
message := mg.client.NewMessage(
fmt.Sprintf("%s <%s>", fromName, fromAddr),
email.Subject,
email.Text,
)
for _, a := range address {
// Adding variable tells mailgun to do a batch send, so users don't see other recipients.
message.AddRecipientAndVariables(a, map[string]interface{}{"unique_id": a})
}
message.SetHtml(email.HTML)
ctx, cancel := context.WithTimeout(context.Background(), time.Second*10)
defer cancel()
_, _, err := mg.client.Send(ctx, message)
return err
}
// SMTP supports SSL/TLS and STARTTLS; implements EmailClient.
type SMTP struct {
Client *sMail.SMTPServer
}
func (sm *SMTP) Send(fromName, fromAddr string, email *Message, address ...string) error {
from := fmt.Sprintf("%s <%s>", fromName, fromAddr)
var cli *sMail.SMTPClient
var err error
cli, err = sm.Client.Connect()
if err != nil {
return err
}
defer cli.Close()
var wg sync.WaitGroup
for _, addr := range address {
wg.Add(1)
go func(addr string) {
defer wg.Done()
e := sMail.NewMSG()
e.SetFrom(from)
e.SetSubject(email.Subject)
e.AddTo(addr)
if email.HTML == "" {
e.SetBody(sMail.TextPlain, email.Text)
} else {
e.SetBody(sMail.TextHTML, email.HTML)
e.AddAlternative(sMail.TextPlain, email.Text)
}
err = e.Send(cli)
// e := jEmail.NewEmail()
// e.Subject = email.Subject
// e.From = from
// e.Text = []byte(email.Text)
// e.HTML = []byte(email.HTML)
// e.To = []string{addr}
// err = sm.Pool.Send(e, 15*time.Second)
// if sm.sslTLS {
// err = sm.Pool.S
// err = e.SendWithTLS(server, sm.auth, sm.tlsConfig)
// } else {
// err = e.SendWithStartTLS(server, sm.auth, sm.tlsConfig)
// }
}(addr)
}
wg.Wait()
return err
}
// Emailer contains the email sender, translations, and methods to construct messages.
type Emailer struct {
fromAddr, fromName string
@ -175,18 +96,17 @@ func NewEmailer(app *appContext) *Emailer {
return emailer
}
// NewMailgun returns a Mailgun emailClient.
func (emailer *Emailer) NewMailgun(url, key string) {
sender := &Mailgun{
client: mailgun.NewMailgun(strings.Split(emailer.fromAddr, "@")[1], key),
}
// Mailgun client takes the base url, so we need to trim off the end (e.g 'v3/messages')
if strings.Contains(url, "messages") {
url = url[0:strings.LastIndex(url, "/")]
url = url[0:strings.LastIndex(url, "/")]
}
sender.client.SetAPIBase(url)
emailer.sender = sender
// DummyClient just logs the email to the console for debugging purposes. It can be used by settings [email]/method to "dummy".
type DummyClient struct{}
func (dc *DummyClient) Send(fromName, fromAddr string, email *Message, address ...string) error {
fmt.Printf("FROM: %s <%s>\nTO: %s\nTEXT: %s\n", fromName, fromAddr, strings.Join(address, ", "), email.Text)
return nil
}
// SMTP supports SSL/TLS and STARTTLS; implements EmailClient.
type SMTP struct {
Client *sMail.SMTPServer
}
// NewSMTP returns an SMTP emailClient.
@ -237,6 +157,65 @@ func (emailer *Emailer) NewSMTP(server string, port int, username, password stri
return
}
func (sm *SMTP) Send(fromName, fromAddr string, email *Message, address ...string) error {
from := fmt.Sprintf("%s <%s>", fromName, fromAddr)
var cli *sMail.SMTPClient
var err error
cli, err = sm.Client.Connect()
if err != nil {
return err
}
defer cli.Close()
e := sMail.NewMSG()
e.SetFrom(from)
e.SetSubject(email.Subject)
e.AddTo(address...)
if email.HTML == "" {
e.SetBody(sMail.TextPlain, email.Text)
} else {
e.SetBody(sMail.TextHTML, email.HTML)
e.AddAlternative(sMail.TextPlain, email.Text)
}
err = e.Send(cli)
return err
}
// Mailgun client implements EmailClient.
type Mailgun struct {
client *mailgun.MailgunImpl
}
// NewMailgun returns a Mailgun emailClient.
func (emailer *Emailer) NewMailgun(url, key string) {
sender := &Mailgun{
client: mailgun.NewMailgun(strings.Split(emailer.fromAddr, "@")[1], key),
}
// Mailgun client takes the base url, so we need to trim off the end (e.g 'v3/messages')
if strings.Contains(url, "messages") {
url = url[0:strings.LastIndex(url, "/")]
url = url[0:strings.LastIndex(url, "/")]
}
sender.client.SetAPIBase(url)
emailer.sender = sender
}
func (mg *Mailgun) Send(fromName, fromAddr string, email *Message, address ...string) error {
message := mg.client.NewMessage(
fmt.Sprintf("%s <%s>", fromName, fromAddr),
email.Subject,
email.Text,
)
for _, a := range address {
// Adding variable tells mailgun to do a batch send, so users don't see other recipients.
message.AddRecipientAndVariables(a, map[string]interface{}{"unique_id": a})
}
message.SetHtml(email.HTML)
ctx, cancel := context.WithTimeout(context.Background(), time.Second*10)
defer cancel()
_, _, err := mg.client.Send(ctx, message)
return err
}
type templ interface {
Execute(wr io.Writer, data interface{}) error
}

View File

@ -100,7 +100,8 @@
"searchDiscordUser": "Gib den Discord-Benutzername ein, um den Benutzer zu finden.",
"findDiscordUser": "Suche Discord-Benutzer",
"linkMatrixDescription": "Gib den Benutzernamen und das Passwort des Benutzers ein, der als Bot verwendet werden soll. Nach dem Absenden wird die App neu gestartet.",
"matrixHomeServer": "Adresse des Homeservers"
"matrixHomeServer": "Adresse des Homeservers",
"templates": "Vorlagen"
},
"notifications": {
"changedEmailAddress": "E-Mail-Adresse von {n} geändert.",
@ -140,7 +141,8 @@
"noUpdatesAvailable": "Keinen neuen Aktualisierungen verfügbar.",
"updateAppliedRefresh": "Update angewendet, bitte aktualisieren.",
"telegramVerified": "Telegram-Konto verifiziert.",
"accountConnected": "Konto verbunden."
"accountConnected": "Konto verbunden.",
"savedAnnouncement": "Ankündigung gespeichert."
},
"quantityStrings": {
"modifySettingsFor": {

View File

@ -101,7 +101,11 @@
"findDiscordUser": "Trouver l'utilisateur Discord",
"linkMatrixDescription": "Entrez le nom d'utilisateur et le mot de passe de l'utilisateur pour lutilisateur comme bot. Une fois soumis, l'application va redémarrer.",
"searchDiscordUser": "Commencez à taper le nom d'utilisateur Discord pour trouver l'utilisateur.",
"matrixHomeServer": "Adresse du serveur"
"matrixHomeServer": "Adresse du serveur domestique",
"saveAsTemplate": "Sauvegarder comme modèle",
"templateEnterName": "Entrez un nom pour sauvegarder ce modèle.",
"deleteTemplate": "Supprimer le modèle",
"templates": "Modèles"
},
"notifications": {
"changedEmailAddress": "Adresse e-mail modifiée de {n}.",
@ -141,7 +145,8 @@
"noUpdatesAvailable": "Aucune nouvelle mise à jour disponible.",
"telegramVerified": "Compte Telegram vérifié.",
"updateAppliedRefresh": "Mise à jour appliquée, veuillez actualiser.",
"accountConnected": "Compte connecté."
"accountConnected": "Compte connecté.",
"savedAnnouncement": "Annonce enregistrée."
},
"quantityStrings": {
"modifySettingsFor": {

View File

@ -7,7 +7,7 @@
"pageTitle": "Créer un compte Jellyfin",
"createAccountHeader": "Création du compte",
"accountDetails": "Détails",
"emailAddress": "Email",
"emailAddress": "E-mail",
"username": "Nom d'utilisateur",
"password": "Mot de passe",
"reEnterPassword": "Confirmez mot de passe",

View File

@ -15,7 +15,11 @@
"serverAddress": "Adresse du serveur",
"emailSubject": "Objet de l'e-mail",
"URL": "URL",
"apiKey": "Clé API"
"apiKey": "Clé API",
"errorUserDisabled": "L'utilisateur est peut-être désactivé.",
"error404": "404, vérifiez l'URL interne.",
"errorInvalidUserPass": "Nom d'utilisateur/mot de passe invalide.",
"errorNotAdmin": "L'utilisateur n'est pas autorisé à gérer le serveur."
},
"startPage": {
"welcome": "Bienvenue !",
@ -25,7 +29,7 @@
},
"endPage": {
"finished": "Terminé !",
"restartMessage": "Il y a d'autres paramètres que vous pouvez configurer sur la page administrateur. Cliquez en dessous pour redémarrer, rafraichissez ensuite la page.",
"restartMessage": "Vous pouvez configurer les bots Discord/Telegram/Matrix, personnaliser vos messages et plus encore dans Paramètres. Cliquez ci-dessous pour redémarrer, puis actualisez la page.",
"refreshPage": "Rafraichir"
},
"language": {
@ -86,16 +90,16 @@
"mailgunApiURL": "URL de l'API"
},
"notifications": {
"title": "Notifications",
"description": "Si activé, vous pouvez choisir (par invitation) de recevoir un e-mail lorsque l'invitation expire, ou lorsque l'utilisateur est créé. Si vous ne choisissez pas la méthode de connexion par Jellyfin, assurez-vous d'avoir fourni votre adresse e-mail."
"title": "Notifications d'administrateur",
"description": "Si activé, vous pouvez choisir (par invitation) de recevoir un message lorsque l'invitation expire, ou lorsque l'utilisateur est créé. Si vous ne choisissez pas la méthode de connexion par Jellyfin, assurez-vous d'avoir fourni votre adresse e-mail ou un autre moyen de contact."
},
"welcomeEmails": {
"title": "E-mails de bienvenue",
"description": "Si activé, un e-mail sera envoyé aux nouveaux utilisateurs avec l'URL de Jellyfin/Emby et leur nom d'utilisateur."
"title": "Messages de bienvenue",
"description": "Si activé, un message sera envoyé aux nouveaux utilisateurs avec l'URL de Jellyfin/Emby et leur nom d'utilisateur."
},
"inviteEmails": {
"title": "E-mails d'invitation",
"description": "Si activé, vous pouvez envoyer une invitation directement à l'adresse e-mail de l'utilisateur. Parce que vous pourriez utiliser un reverse proxy, vous devez renseigner l'URL d'accès aux invitations. Renseignez votre Base URL et ajoutez '/invite'."
"title": "Messages d'invitation",
"description": "Si activé, vous pouvez envoyer une invitation directement à l'adresse e-mail, le Discord ou Matrix de l'utilisateur. Parce que vous pourriez utiliser un reverse proxy, vous devez renseigner l'URL d'accès aux invitations. Renseignez votre Base URL et ajoutez '/invite'."
},
"passwordResets": {
"title": "Réinitialisation de mot de passe",
@ -104,7 +108,9 @@
"pathToJellyfinNotice": "Si vous ne savez pas où c'est, essayez de réinitialiser votre mot de passe dans Jellyfin. Une popup avec '<path to jellyfin>/passwordreset-*.json' apparaitra.",
"resetLinks": "Envoyer un lien plutôt qu'un PIN",
"resetLinksNotice": "Si l'intégration est activée, utilisez ceci pour synchroniser les réinitialisations de mots de passe Jellyfin avec Ombi.",
"resetLinksLanguage": "Langue du lien de réinitialisation par défaut"
"resetLinksLanguage": "Langue du lien de réinitialisation par défaut",
"setPassword": "Définir le mot de passe via le lien",
"setPasswordNotice": "L'activation de cette option signifie que l'utilisateur n'a pas à modifier son mot de passe à partir du code PIN après la réinitialisation. La validation du mot de passe sera également appliquée."
},
"passwordValidation": {
"title": "Validation du mot de passe",
@ -133,5 +139,9 @@
"updateChannel": "Mettre à jour la chaîne",
"stable": "Stable",
"unstable": "Instable"
},
"messages": {
"title": "Messages",
"description": "jfa-go peut envoyer des réinitialisations de mot de passe et divers messages par e-mail, Discord, Telegram et/ou Matrix. Vous pouvez configurer l'e-mail ci-dessous, et les autres peuvent être configurés dans les paramètres plus tard. Les instructions se trouvent sur le {n}. Si vous n'en avez pas besoin, vous pouvez désactiver ces fonctionnalités ici."
}
}