mirror of https://github.com/hrfee/jfa-go
Fixed password validation for new users, add invite route, couple other fixes.pull/20/head
parent
d8fb6e5613
commit
961b9afa75
@ -1,7 +1,7 @@
|
||||
A user was created using code {{ code }}.
|
||||
A user was created using code {{ .code }}.
|
||||
|
||||
Name: {{ username }}
|
||||
Address: {{ address }}
|
||||
Time: {{ time }}
|
||||
Name: {{ .username }}
|
||||
Address: {{ .address }}
|
||||
Time: {{ .time }}
|
||||
|
||||
Note: Notification emails can be toggled on the admin dashboard.
|
||||
|
@ -1,10 +1,10 @@
|
||||
Hi {{ username }},
|
||||
Hi {{ .username }},
|
||||
|
||||
Someone has recently requests a password reset on Jellyfin.
|
||||
If this was you, enter the below pin into the prompt.
|
||||
This code will expire on {{ expiry_date }}, at {{ expiry_time }} UTC, which is in {{ expires_in }}.
|
||||
This code will expire on {{ .expiry_date }}, at {{ .expiry_time }} UTC, which is in {{ .expires_in }}.
|
||||
If this wasn't you, please ignore this email.
|
||||
|
||||
PIN: {{ pin }}
|
||||
PIN: {{ .pin }}
|
||||
|
||||
{{ message }}
|
||||
{{ .message }}
|
||||
|
@ -1,5 +1,5 @@
|
||||
Invite expired.
|
||||
|
||||
Code {{ code }} expired at {{ expiry }}.
|
||||
Code {{ .code }} expired at {{ .expiry }}.
|
||||
|
||||
Note: Notification emails can be toggled on the admin dashboard.
|
||||
|
@ -1,8 +1,8 @@
|
||||
Hi,
|
||||
You've been invited to Jellyfin.
|
||||
To join, follow the below link.
|
||||
This invite will expire on {{ expiry_date }}, at {{ expiry_time }}, which is in {{ expires_in }}, so act quick.
|
||||
This invite will expire on {{ .expiry_date }}, at {{ .expiry_time }}, which is in {{ .expires_in }}, so act quick.
|
||||
|
||||
{{ invite_link }}
|
||||
{{ .invite_link }}
|
||||
|
||||
{{ message }}
|
||||
{{ .message }}
|
||||
|
@ -0,0 +1,209 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
// "context"
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/knz/strtime"
|
||||
"github.com/mailgun/mailgun-go/v4"
|
||||
"html/template"
|
||||
"net/smtp"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Emailer struct {
|
||||
smtpAuth smtp.Auth
|
||||
sendType, sendMethod, fromAddr, fromName string
|
||||
content Email
|
||||
mg *mailgun.MailgunImpl
|
||||
}
|
||||
|
||||
type Email struct {
|
||||
subject string
|
||||
html, text string
|
||||
}
|
||||
|
||||
func (email *Emailer) formatExpiry(expiry time.Time, tzaware bool, datePattern, timePattern string) (d, t, expires_in string) {
|
||||
d, _ = strtime.Strftime(expiry, datePattern)
|
||||
t, _ = strtime.Strftime(expiry, timePattern)
|
||||
current_time := time.Now()
|
||||
if tzaware {
|
||||
current_time = current_time.UTC()
|
||||
}
|
||||
_, _, days, hours, minutes, _ := timeDiff(expiry, current_time)
|
||||
if days != 0 {
|
||||
expires_in += fmt.Sprintf("%dd ", days)
|
||||
}
|
||||
if hours != 0 {
|
||||
expires_in += fmt.Sprintf("%dh ", hours)
|
||||
}
|
||||
if minutes != 0 {
|
||||
expires_in += fmt.Sprintf("%dm ", minutes)
|
||||
}
|
||||
expires_in = strings.TrimSuffix(expires_in, " ")
|
||||
return
|
||||
}
|
||||
|
||||
func (email *Emailer) init(ctx *appContext) {
|
||||
email.fromAddr = ctx.config.Section("email").Key("address").String()
|
||||
email.fromName = ctx.config.Section("email").Key("from").String()
|
||||
email.sendMethod = ctx.config.Section("email").Key("method").String()
|
||||
if email.sendMethod == "mailgun" {
|
||||
email.mg = mailgun.NewMailgun(strings.Split(email.fromAddr, "@")[1], ctx.config.Section("mailgun").Key("api_key").String())
|
||||
api_url := ctx.config.Section("mailgun").Key("api_url").String()
|
||||
if strings.Contains(api_url, "messages") {
|
||||
api_url = api_url[0:strings.LastIndex(api_url, "/")]
|
||||
api_url = api_url[0:strings.LastIndex(api_url, "/")]
|
||||
}
|
||||
email.mg.SetAPIBase(api_url)
|
||||
}
|
||||
}
|
||||
|
||||
func (email *Emailer) constructInvite(code string, invite Invite, ctx *appContext) error {
|
||||
email.content.subject = ctx.config.Section("invite_emails").Key("subject").String()
|
||||
expiry := invite.ValidTill
|
||||
d, t, expires_in := email.formatExpiry(expiry, false, ctx.datePattern, ctx.timePattern)
|
||||
message := ctx.config.Section("email").Key("message").String()
|
||||
invite_link := ctx.config.Section("invite_emails").Key("url_base").String()
|
||||
invite_link = fmt.Sprintf("%s/%s", invite_link, code)
|
||||
|
||||
for _, key := range []string{"html", "text"} {
|
||||
fpath := ctx.config.Section("invite_emails").Key("email_" + key).String()
|
||||
tpl, err := template.ParseFiles(fpath)
|
||||
if err != nil {
|
||||
fmt.Println("failed email", err)
|
||||
return err
|
||||
}
|
||||
var tplData bytes.Buffer
|
||||
err = tpl.Execute(&tplData, map[string]string{
|
||||
"expiry_date": d,
|
||||
"expiry_time": t,
|
||||
"expires_in": expires_in,
|
||||
"invite_link": invite_link,
|
||||
"message": message,
|
||||
})
|
||||
if err != nil {
|
||||
fmt.Println("failed email", err)
|
||||
return err
|
||||
}
|
||||
if key == "html" {
|
||||
email.content.html = tplData.String()
|
||||
} else {
|
||||
email.content.text = tplData.String()
|
||||
}
|
||||
}
|
||||
email.sendType = "invite"
|
||||
return nil
|
||||
}
|
||||
|
||||
func (email *Emailer) constructExpiry(code string, invite Invite, ctx *appContext) error {
|
||||
email.content.subject = "Notice: Invite expired"
|
||||
expiry := ctx.formatDatetime(invite.ValidTill)
|
||||
for _, key := range []string{"html", "text"} {
|
||||
fpath := ctx.config.Section("notifications").Key("expiry_" + key).String()
|
||||
tpl, err := template.ParseFiles(fpath)
|
||||
if err != nil {
|
||||
fmt.Println("failed email", err)
|
||||
return err
|
||||
}
|
||||
var tplData bytes.Buffer
|
||||
err = tpl.Execute(&tplData, map[string]string{
|
||||
"code": code,
|
||||
"expiry": expiry,
|
||||
})
|
||||
if err != nil {
|
||||
fmt.Println("failed email", err)
|
||||
return err
|
||||
}
|
||||
if key == "html" {
|
||||
email.content.html = tplData.String()
|
||||
} else {
|
||||
email.content.text = tplData.String()
|
||||
}
|
||||
}
|
||||
email.sendType = "expiry"
|
||||
return nil
|
||||
}
|
||||
|
||||
func (email *Emailer) constructCreated(code, username, address string, invite Invite, ctx *appContext) error {
|
||||
email.content.subject = "Notice: User created"
|
||||
created := ctx.formatDatetime(invite.Created)
|
||||
var tplAddress string
|
||||
if ctx.config.Section("email").Key("no_username").MustBool(false) {
|
||||
tplAddress = "n/a"
|
||||
} else {
|
||||
tplAddress = address
|
||||
}
|
||||
for _, key := range []string{"html", "text"} {
|
||||
fpath := ctx.config.Section("notifications").Key("created_" + key).String()
|
||||
tpl, err := template.ParseFiles(fpath)
|
||||
if err != nil {
|
||||
fmt.Println("failed email", err)
|
||||
return err
|
||||
}
|
||||
var tplData bytes.Buffer
|
||||
err = tpl.Execute(&tplData, map[string]string{
|
||||
"code": code,
|
||||
"username": username,
|
||||
"address": tplAddress,
|
||||
"time": created,
|
||||
})
|
||||
if err != nil {
|
||||
fmt.Println("failed email", err)
|
||||
return err
|
||||
}
|
||||
if key == "html" {
|
||||
email.content.html = tplData.String()
|
||||
} else {
|
||||
email.content.text = tplData.String()
|
||||
}
|
||||
}
|
||||
email.sendType = "created"
|
||||
return nil
|
||||
}
|
||||
|
||||
func (email *Emailer) send(address string, ctx *appContext) error {
|
||||
if email.sendMethod == "mailgun" {
|
||||
// reqData := map[string]string{
|
||||
// "to": fmt.Sprintf("%s <%s>", "test", email.to),
|
||||
// "from": email.fromAddr,
|
||||
// "subject": email.subject,
|
||||
// }
|
||||
// if email.sendType == "invite" {
|
||||
// reqData["text"] = email.invite.text
|
||||
// reqData["html"] = email.invite.html
|
||||
// }
|
||||
// data := &bytes.Buffer{}
|
||||
// encoder := json.NewEncoder(data)
|
||||
// encoder.SetEscapeHTML(false)
|
||||
// err := encoder.Encode(reqData)
|
||||
// fmt.Println("marshaled:", data)
|
||||
// if err != nil {
|
||||
// fmt.Println("Failed marshal:", err, ">", data)
|
||||
// return err
|
||||
// }
|
||||
// var req *http.Request
|
||||
// req, err = http.NewRequest("POST", ctx.config.Section("mailgun").Key("api_url").String(), data)
|
||||
// req.SetBasicAuth("api", ctx.config.Section("mailgun").Key("api_key").String())
|
||||
// var resp *http.Response
|
||||
// resp, err = email.httpClient.Do(req)
|
||||
// if err != nil || !(resp.StatusCode == 200 || resp.StatusCode == 204) {
|
||||
// fmt.Println("failed send:", err, resp.StatusCode)
|
||||
// fmt.Println("resp:", resp.Header.Get("Content-Encoding"), resp.Body)
|
||||
// }
|
||||
message := email.mg.NewMessage(
|
||||
fmt.Sprintf("%s <%s>", email.fromName, email.fromAddr),
|
||||
email.content.subject,
|
||||
email.content.text,
|
||||
address)
|
||||
message.SetHtml(email.content.html)
|
||||
mgctx, cancel := context.WithTimeout(context.Background(), time.Second*30)
|
||||
defer cancel()
|
||||
_, id, err := email.mg.Send(mgctx, message)
|
||||
fmt.Println("mailgun:", id, err)
|
||||
|
||||
}
|
||||
return nil
|
||||
}
|
Loading…
Reference in new issue