1
0
mirror of https://github.com/hrfee/jfa-go.git synced 2024-10-18 17:10:11 +00:00

Compare commits

..

No commits in common. "d772e43e44bd507e1f94d215b53425abdb7fd9a0" and "e8b1cca9cac4b2df19ac67066e04d3a8b224a7bb" have entirely different histories.

8 changed files with 88 additions and 234 deletions

12
api.go
View File

@ -1570,7 +1570,6 @@ func (app *appContext) GetEmail(gc *gin.Context) {
var err error
var msg *Email
var variables []string
var conditionals []string
var values map[string]interface{}
var writeVars func(variables []string)
newEmail := false
@ -1662,21 +1661,16 @@ func (app *appContext) GetEmail(gc *gin.Context) {
// app.storage.customEmails.InviteEmail = content
} else if id == "WelcomeEmail" {
content = app.storage.customEmails.WelcomeEmail.Content
conditionals = []string{"{yourAccountWillExpire}"}
app.storage.customEmails.WelcomeEmail.Conditionals = conditionals
if content == "" {
newEmail = true
msg, err = app.email.constructWelcome("", time.Time{}, app, true)
content = msg.Text
conditionals = []string{"{yourAccountWillExpire}"}
} else {
variables = app.storage.customEmails.WelcomeEmail.Variables
}
writeVars = func(variables []string) {
app.storage.customEmails.WelcomeEmail.Variables = variables
}
writeVars = func(variables []string) { app.storage.customEmails.WelcomeEmail.Variables = variables }
// app.storage.customEmails.WelcomeEmail = content
values = app.email.welcomeValues(username, time.Now(), app, false, true)
values = app.email.welcomeValues(username, time.Time{}, app, false, true)
} else if id == "EmailConfirmation" {
content = app.storage.customEmails.EmailConfirmation.Content
if content == "" {
@ -1740,7 +1734,7 @@ func (app *appContext) GetEmail(gc *gin.Context) {
respondBool(500, false, gc)
return
}
gc.JSON(200, customEmailDTO{Content: content, Variables: variables, Conditionals: conditionals, Values: values, HTML: email.HTML, Plaintext: email.Text})
gc.JSON(200, customEmailDTO{Content: content, Variables: variables, Values: values, HTML: email.HTML, Plaintext: email.Text})
}
// @Summary Returns whether there's a new update, and extra info if there is.

144
email.go
View File

@ -274,12 +274,13 @@ func (emailer *Emailer) constructConfirmation(code, username, key string, app *a
var err error
template := emailer.confirmationValues(code, username, key, app, noSub)
if app.storage.customEmails.EmailConfirmation.Enabled {
content := templateEmail(
app.storage.customEmails.EmailConfirmation.Content,
app.storage.customEmails.EmailConfirmation.Variables,
nil,
template,
)
content := app.storage.customEmails.EmailConfirmation.Content
for _, v := range app.storage.customEmails.EmailConfirmation.Variables {
replaceWith, ok := template[v[1:len(v)-1]]
if ok {
content = strings.ReplaceAll(content, v, replaceWith.(string))
}
}
email, err = emailer.constructTemplate(email.Subject, content, app)
} else {
email.HTML, email.Text, err = emailer.construct(app, "email_confirmation", "email_", template)
@ -345,12 +346,13 @@ func (emailer *Emailer) constructInvite(code string, invite Invite, app *appCont
template := emailer.inviteValues(code, invite, app, noSub)
var err error
if app.storage.customEmails.InviteEmail.Enabled {
content := templateEmail(
app.storage.customEmails.InviteEmail.Content,
app.storage.customEmails.InviteEmail.Variables,
nil,
template,
)
content := app.storage.customEmails.InviteEmail.Content
for _, v := range app.storage.customEmails.InviteEmail.Variables {
replaceWith, ok := template[v[1:len(v)-1]]
if ok {
content = strings.ReplaceAll(content, v, replaceWith.(string))
}
}
email, err = emailer.constructTemplate(email.Subject, content, app)
} else {
email.HTML, email.Text, err = emailer.construct(app, "invite_emails", "email_", template)
@ -384,12 +386,13 @@ func (emailer *Emailer) constructExpiry(code string, invite Invite, app *appCont
var err error
template := emailer.expiryValues(code, invite, app, noSub)
if app.storage.customEmails.InviteExpiry.Enabled {
content := templateEmail(
app.storage.customEmails.InviteExpiry.Content,
app.storage.customEmails.InviteExpiry.Variables,
nil,
template,
)
content := app.storage.customEmails.InviteExpiry.Content
for _, v := range app.storage.customEmails.InviteExpiry.Variables {
replaceWith, ok := template[v[1:len(v)-1]]
if ok {
content = strings.ReplaceAll(content, v, replaceWith.(string))
}
}
email, err = emailer.constructTemplate(email.Subject, content, app)
} else {
email.HTML, email.Text, err = emailer.construct(app, "notifications", "expiry_", template)
@ -438,12 +441,13 @@ func (emailer *Emailer) constructCreated(code, username, address string, invite
template := emailer.createdValues(code, username, address, invite, app, noSub)
var err error
if app.storage.customEmails.UserCreated.Enabled {
content := templateEmail(
app.storage.customEmails.UserCreated.Content,
app.storage.customEmails.UserCreated.Variables,
nil,
template,
)
content := app.storage.customEmails.UserCreated.Content
for _, v := range app.storage.customEmails.UserCreated.Variables {
replaceWith, ok := template[v[1:len(v)-1]]
if ok {
content = strings.ReplaceAll(content, v, replaceWith.(string))
}
}
email, err = emailer.constructTemplate(email.Subject, content, app)
} else {
email.HTML, email.Text, err = emailer.construct(app, "notifications", "created_", template)
@ -512,12 +516,13 @@ func (emailer *Emailer) constructReset(pwr PasswordReset, app *appContext, noSub
template := emailer.resetValues(pwr, app, noSub)
var err error
if app.storage.customEmails.PasswordReset.Enabled {
content := templateEmail(
app.storage.customEmails.PasswordReset.Content,
app.storage.customEmails.PasswordReset.Variables,
nil,
template,
)
content := app.storage.customEmails.PasswordReset.Content
for _, v := range app.storage.customEmails.PasswordReset.Variables {
replaceWith, ok := template[v[1:len(v)-1]]
if ok {
content = strings.ReplaceAll(content, v, replaceWith.(string))
}
}
email, err = emailer.constructTemplate(email.Subject, content, app)
} else {
email.HTML, email.Text, err = emailer.construct(app, "password_resets", "email_", template)
@ -553,12 +558,13 @@ func (emailer *Emailer) constructDeleted(reason string, app *appContext, noSub b
var err error
template := emailer.deletedValues(reason, app, noSub)
if app.storage.customEmails.UserDeleted.Enabled {
content := templateEmail(
app.storage.customEmails.UserDeleted.Content,
app.storage.customEmails.UserDeleted.Variables,
nil,
template,
)
content := app.storage.customEmails.UserDeleted.Content
for _, v := range app.storage.customEmails.UserDeleted.Variables {
replaceWith, ok := template[v[1:len(v)-1]]
if ok {
content = strings.ReplaceAll(content, v, replaceWith.(string))
}
}
email, err = emailer.constructTemplate(email.Subject, content, app)
} else {
email.HTML, email.Text, err = emailer.construct(app, "deletion", "email_", template)
@ -594,12 +600,13 @@ func (emailer *Emailer) constructDisabled(reason string, app *appContext, noSub
var err error
template := emailer.disabledValues(reason, app, noSub)
if app.storage.customEmails.UserDisabled.Enabled {
content := templateEmail(
app.storage.customEmails.UserDisabled.Content,
app.storage.customEmails.UserDisabled.Variables,
nil,
template,
)
content := app.storage.customEmails.UserDisabled.Content
for _, v := range app.storage.customEmails.UserDisabled.Variables {
replaceWith, ok := template[v[1:len(v)-1]]
if ok {
content = strings.ReplaceAll(content, v, replaceWith.(string))
}
}
email, err = emailer.constructTemplate(email.Subject, content, app)
} else {
email.HTML, email.Text, err = emailer.construct(app, "disable_enable", "disabled_", template)
@ -635,12 +642,13 @@ func (emailer *Emailer) constructEnabled(reason string, app *appContext, noSub b
var err error
template := emailer.enabledValues(reason, app, noSub)
if app.storage.customEmails.UserEnabled.Enabled {
content := templateEmail(
app.storage.customEmails.UserEnabled.Content,
app.storage.customEmails.UserEnabled.Variables,
nil,
template,
)
content := app.storage.customEmails.UserEnabled.Content
for _, v := range app.storage.customEmails.UserEnabled.Variables {
replaceWith, ok := template[v[1:len(v)-1]]
if ok {
content = strings.ReplaceAll(content, v, replaceWith.(string))
}
}
email, err = emailer.constructTemplate(email.Subject, content, app)
} else {
email.HTML, email.Text, err = emailer.construct(app, "disable_enable", "enabled_", template)
@ -669,14 +677,12 @@ func (emailer *Emailer) welcomeValues(username string, expiry time.Time, app *ap
template["username"] = username
template["message"] = app.config.Section("email").Key("message").String()
exp := app.formatDatetime(expiry)
if !expiry.IsZero() {
if custom {
template["yourAccountWillExpire"] = exp
} else if !expiry.IsZero() {
template["yourAccountWillExpire"] = emailer.lang.WelcomeEmail.template("yourAccountWillExpire", tmpl{
"date": exp,
})
}
if custom {
template["yourAccountWillExpire"] = exp
} else if !expiry.IsZero() {
template["yourAccountWillExpire"] = emailer.lang.WelcomeEmail.template("yourAccountWillExpire", tmpl{
"date": exp,
})
}
}
return template
@ -699,12 +705,13 @@ func (emailer *Emailer) constructWelcome(username string, expiry time.Time, app
})
}
if app.storage.customEmails.WelcomeEmail.Enabled {
content := templateEmail(
app.storage.customEmails.WelcomeEmail.Content,
app.storage.customEmails.WelcomeEmail.Variables,
app.storage.customEmails.WelcomeEmail.Conditionals,
template,
)
content := app.storage.customEmails.WelcomeEmail.Content
for _, v := range app.storage.customEmails.WelcomeEmail.Variables {
replaceWith, ok := template[v[1:len(v)-1]]
if ok {
content = strings.ReplaceAll(content, v, replaceWith.(string))
}
}
email, err = emailer.constructTemplate(email.Subject, content, app)
} else {
email.HTML, email.Text, err = emailer.construct(app, "welcome_email", "email_", template)
@ -734,12 +741,13 @@ func (emailer *Emailer) constructUserExpired(app *appContext, noSub bool) (*Emai
var err error
template := emailer.userExpiredValues(app, noSub)
if app.storage.customEmails.UserExpired.Enabled {
content := templateEmail(
app.storage.customEmails.UserExpired.Content,
app.storage.customEmails.UserExpired.Variables,
nil,
template,
)
content := app.storage.customEmails.UserExpired.Content
for _, v := range app.storage.customEmails.UserExpired.Variables {
replaceWith, ok := template[v[1:len(v)-1]]
if ok {
content = strings.ReplaceAll(content, v, replaceWith.(string))
}
}
email, err = emailer.constructTemplate(email.Subject, content, app)
} else {
email.HTML, email.Text, err = emailer.construct(app, "user_expiry", "email_", template)

View File

@ -183,8 +183,6 @@
<div class="col flex-col content mt-half">
<span class="label supra" for="editor-variables" id="label-editor-variables">{{ .strings.variables }}</span>
<div id="editor-variables"></div>
<span class="label supra" for="editor-conditionals" id="label-editor-conditionals">{{ .strings.conditionals }}</span>
<div id="editor-conditionals"></div>
<label class="label supra" for="textarea-editor">{{ .strings.message }}</label>
<textarea id="textarea-editor" class="textarea full-width flex-auto ~neutral !normal mt-half monospace"></textarea>
<p class="support mt-half mb-1">{{ .strings.markdownSupported }}</p>

View File

@ -49,7 +49,6 @@
"subject": "Email Subject",
"message": "Message",
"variables": "Variables",
"conditionals": "Conditionals",
"preview": "Preview",
"reset": "Reset",
"edit": "Edit",

View File

@ -214,12 +214,11 @@ type emailTestDTO struct {
}
type customEmailDTO struct {
Content string `json:"content"`
Variables []string `json:"variables"`
Conditionals []string `json:"conditionals"`
Values map[string]interface{} `json:"values"`
HTML string `json:"html"`
Plaintext string `json:"plaintext"`
Content string `json:"content"`
Variables []string `json:"variables"`
Values map[string]interface{} `json:"values"`
HTML string `json:"html"`
Plaintext string `json:"plaintext"`
}
type extendExpiryDTO struct {

View File

@ -43,10 +43,9 @@ type customEmails struct {
}
type customEmail struct {
Enabled bool `json:"enabled,omitempty"`
Content string `json:"content"`
Variables []string `json:"variables,omitempty"`
Conditionals []string `json:"conditionals,omitempty"`
Enabled bool `json:"enabled,omitempty"`
Content string `json:"content"`
Variables []string `json:"variables,omitempty"`
}
// timePattern: %Y-%m-%dT%H:%M:%S.%f

View File

@ -1,118 +0,0 @@
package main
import "fmt"
func truthy(val interface{}) bool {
switch v := val.(type) {
case string:
return v != ""
case bool:
return v
case int:
return v != 0
}
return false
}
// Templater for custom emails.
// Variables should be written as {varName}.
// If statements should be written as {if (!)varName}...{endif}.
// Strings are true if != "", ints are true if != 0.
func templateEmail(content string, variables []string, conditionals []string, values map[string]interface{}) string {
ifStart, ifEnd := -1, -1
ifTrue := false
invalidIf := false
previousEnd := -2
cStart, cEnd := -1, -1
varStart, varEnd := -1, -1
varName := ""
out := ""
for i, c := range content {
if c == '{' {
cStart = i + 1
for content[cStart] == ' ' {
cStart++
}
if content[cStart:cStart+3] == "if " {
varStart = cStart + 3
for content[varStart] == ' ' {
varStart++
}
}
if ifStart == -1 {
out += content[previousEnd+2 : i]
}
if content[cStart:cStart+5] != "endif" || invalidIf {
continue
}
ifEnd = i - 1
if ifTrue {
b := templateEmail(content[ifStart:ifEnd+1], variables, conditionals, values)
out += b
ifTrue = false
}
} else if c == '}' {
if varStart != -1 {
ifStart = i + 1
varEnd = i - 1
for content[varEnd] == ' ' {
varEnd--
}
varName = content[varStart : varEnd+1]
positive := true
if varName[0] == '!' {
positive = false
varName = varName[1:]
}
validVar := false
wrappedVarName := "{" + varName + "}"
for _, v := range conditionals {
if v == wrappedVarName {
validVar = true
break
}
}
if validVar {
ifTrue = positive == truthy(values[varName])
} else {
invalidIf = true
ifStart, ifEnd = -1, -1
}
varStart, varEnd = -1, -1
}
cEnd = i - 1
for content[cEnd] == ' ' {
cEnd--
}
previousEnd = i - 1
if content[cEnd-4:cEnd+1] == "endif" && !invalidIf {
continue
}
validVar := false
varName = content[cStart : cEnd+1]
cStart, cEnd = -1, -1
if ifStart != -1 {
continue
}
wrappedVarName := "{" + varName + "}"
for _, v := range variables {
if v == wrappedVarName {
validVar = true
break
}
}
if !validVar {
out += wrappedVarName
continue
}
out += fmt.Sprint(values[varName])
}
}
if previousEnd+1 != len(content)-1 {
out += content[previousEnd+2:]
}
if out == "" {
return content
}
return out
}

View File

@ -769,7 +769,6 @@ class ombiDefaults {
interface templateEmail {
content: string;
variables: string[];
conditionals: string[];
values: { [key: string]: string };
html: string;
plaintext: string;
@ -789,8 +788,6 @@ class EmailEditor {
private _header = document.getElementById("header-editor") as HTMLSpanElement;
private _variables = document.getElementById("editor-variables") as HTMLDivElement;
private _variablesLabel = document.getElementById("label-editor-variables") as HTMLElement;
private _conditionals = document.getElementById("editor-conditionals") as HTMLDivElement;
private _conditionalsLabel = document.getElementById("label-editor-conditionals") as HTMLElement;
private _textArea = document.getElementById("textarea-editor") as HTMLTextAreaElement;
private _preview = document.getElementById("editor-preview") as HTMLDivElement;
private _previewContent: HTMLElement;
@ -848,7 +845,7 @@ class EmailEditor {
this._variablesLabel.classList.remove("unfocused");
}
this._variables.innerHTML = innerHTML
let buttons = this._variables.querySelectorAll("span.button") as NodeListOf<HTMLSpanElement>;
const buttons = this._variables.querySelectorAll("span.button") as NodeListOf<HTMLSpanElement>;
for (let i = 0; i < this._templ.variables.length; i++) {
buttons[i].innerHTML = `<span class="monospace">` + this._templ.variables[i] + `</span>`;
buttons[i].onclick = () => {
@ -857,28 +854,6 @@ class EmailEditor {
// this._timeout = setTimeout(this.loadPreview, this._finishInterval);
}
}
innerHTML = '';
for (let i = this._templ.conditionals.length-1; i >= 0; i--) {
let ci = i % colors.length;
innerHTML += '<span class="button ~' + colors[ci] +' !normal mb-1" style="margin-left: 0.25rem; margin-right: 0.25rem;"></span>'
}
if (this._templ.conditionals.length == 0) {
this._conditionalsLabel.classList.add("unfocused");
} else {
this._conditionalsLabel.classList.remove("unfocused");
}
this._conditionals.innerHTML = innerHTML
buttons = this._conditionals.querySelectorAll("span.button") as NodeListOf<HTMLSpanElement>;
for (let i = 0; i < this._templ.conditionals.length; i++) {
buttons[i].innerHTML = `<span class="monospace">{if ` + this._templ.conditionals[i].slice(1) + `</span>`;
buttons[i].onclick = () => {
this.insert(this._textArea, "{if " + this._templ.conditionals[i].slice(1) + "{endif}");
this.loadPreview();
// this._timeout = setTimeout(this.loadPreview, this._finishInterval);
}
}
window.modals.editor.show();
}
})