mirror of
https://github.com/hrfee/jfa-go.git
synced 2024-12-22 17:10:10 +00:00
userpage: change email (+ confirmation)
edit/add button added for email address. Confirmation works too.
This commit is contained in:
parent
03f1a3dbc0
commit
609039baeb
156
api-userpage.go
156
api-userpage.go
@ -1,6 +1,14 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import "github.com/gin-gonic/gin"
|
import (
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/golang-jwt/jwt"
|
||||||
|
)
|
||||||
|
|
||||||
// @Summary Returns the logged-in user's Jellyfin ID & Username.
|
// @Summary Returns the logged-in user's Jellyfin ID & Username.
|
||||||
// @Produce json
|
// @Produce json
|
||||||
@ -104,3 +112,149 @@ func (app *appContext) LogoutUser(gc *gin.Context) {
|
|||||||
gc.SetCookie("refresh", "invalid", -1, "/my", gc.Request.URL.Hostname(), true, true)
|
gc.SetCookie("refresh", "invalid", -1, "/my", gc.Request.URL.Hostname(), true, true)
|
||||||
respondBool(200, true, gc)
|
respondBool(200, true, gc)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// @Summary confirm an action (e.g. changing an email address.)
|
||||||
|
// @Produce json
|
||||||
|
// @Param jwt path string true "jwt confirmation code"
|
||||||
|
// @Router /my/confirm/{jwt} [post]
|
||||||
|
// @Success 200 {object} boolResponse
|
||||||
|
// @Failure 400 {object} stringResponse
|
||||||
|
// @Failure 404
|
||||||
|
// @Success 303
|
||||||
|
// @Failure 500 {object} stringResponse
|
||||||
|
// @tags User Page
|
||||||
|
func (app *appContext) ConfirmMyAction(gc *gin.Context) {
|
||||||
|
app.confirmMyAction(gc, "")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (app *appContext) confirmMyAction(gc *gin.Context, key string) {
|
||||||
|
var claims jwt.MapClaims
|
||||||
|
var target ConfirmationTarget
|
||||||
|
var id string
|
||||||
|
fail := func() {
|
||||||
|
gcHTML(gc, 404, "404.html", gin.H{
|
||||||
|
"cssClass": app.cssClass,
|
||||||
|
"cssVersion": cssVersion,
|
||||||
|
"contactMessage": app.config.Section("ui").Key("contact_message").String(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate key
|
||||||
|
if key == "" {
|
||||||
|
key = gc.Param("jwt")
|
||||||
|
}
|
||||||
|
token, err := jwt.Parse(key, checkToken)
|
||||||
|
if err != nil {
|
||||||
|
app.err.Printf("Failed to parse key: %s", err)
|
||||||
|
fail()
|
||||||
|
// respond(500, "unknownError", gc)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
claims, ok := token.Claims.(jwt.MapClaims)
|
||||||
|
if !ok {
|
||||||
|
app.err.Printf("Failed to parse key: %s", err)
|
||||||
|
fail()
|
||||||
|
// respond(500, "unknownError", gc)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
expiry := time.Unix(int64(claims["exp"].(float64)), 0)
|
||||||
|
if !(ok && token.Valid && claims["type"].(string) == "confirmation" && expiry.After(time.Now())) {
|
||||||
|
app.err.Printf("Invalid key")
|
||||||
|
fail()
|
||||||
|
// respond(400, "invalidKey", gc)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
target = ConfirmationTarget(int(claims["target"].(float64)))
|
||||||
|
id = claims["id"].(string)
|
||||||
|
|
||||||
|
// Perform an Action
|
||||||
|
if target == NoOp {
|
||||||
|
gc.Redirect(http.StatusSeeOther, "/my/account")
|
||||||
|
return
|
||||||
|
} else if target == UserEmailChange {
|
||||||
|
emailStore, ok := app.storage.emails[id]
|
||||||
|
if !ok {
|
||||||
|
emailStore = EmailAddress{
|
||||||
|
Contact: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
emailStore.Addr = claims["email"].(string)
|
||||||
|
app.storage.emails[id] = emailStore
|
||||||
|
if app.config.Section("ombi").Key("enabled").MustBool(false) {
|
||||||
|
ombiUser, code, err := app.getOmbiUser(id)
|
||||||
|
if code == 200 && err == nil {
|
||||||
|
ombiUser["emailAddress"] = claims["email"].(string)
|
||||||
|
code, err = app.ombi.ModifyUser(ombiUser)
|
||||||
|
if code != 200 || err != nil {
|
||||||
|
app.err.Printf("%s: Failed to change ombi email address (%d): %v", ombiUser["userName"].(string), code, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
app.storage.storeEmails()
|
||||||
|
app.info.Println("Email list modified")
|
||||||
|
gc.Redirect(http.StatusSeeOther, "/my/account")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Summary Modify your email address.
|
||||||
|
// @Produce json
|
||||||
|
// @Param ModifyMyEmailDTO body ModifyMyEmailDTO true "New email address."
|
||||||
|
// @Success 200 {object} boolResponse
|
||||||
|
// @Failure 400 {object} stringResponse
|
||||||
|
// @Failure 401 {object} stringResponse
|
||||||
|
// @Failure 500 {object} stringResponse
|
||||||
|
// @Router /my/email [post]
|
||||||
|
// @Security Bearer
|
||||||
|
// @tags Users
|
||||||
|
func (app *appContext) ModifyMyEmail(gc *gin.Context) {
|
||||||
|
var req ModifyMyEmailDTO
|
||||||
|
gc.BindJSON(&req)
|
||||||
|
app.debug.Println("Email modification requested")
|
||||||
|
if !strings.ContainsRune(req.Email, '@') {
|
||||||
|
respond(400, "Invalid Email Address", gc)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
id := gc.GetString("jfId")
|
||||||
|
|
||||||
|
// We'll use the ConfirmMyAction route to do the work, even if we don't need to confirm the address.
|
||||||
|
claims := jwt.MapClaims{
|
||||||
|
"valid": true,
|
||||||
|
"id": id,
|
||||||
|
"email": req.Email,
|
||||||
|
"type": "confirmation",
|
||||||
|
"target": UserEmailChange,
|
||||||
|
"exp": time.Now().Add(time.Hour).Unix(),
|
||||||
|
}
|
||||||
|
tk := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
|
||||||
|
key, err := tk.SignedString([]byte(os.Getenv("JFA_SECRET")))
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
app.err.Printf("Failed to generate confirmation token: %v", err)
|
||||||
|
respond(500, "errorUnknown", gc)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if emailEnabled && app.config.Section("email_confirmation").Key("enabled").MustBool(false) {
|
||||||
|
user, status, err := app.jf.UserByID(id, false)
|
||||||
|
name := ""
|
||||||
|
if status == 200 && err == nil {
|
||||||
|
name = user.Name
|
||||||
|
}
|
||||||
|
app.debug.Printf("%s: Email confirmation required", id)
|
||||||
|
respond(401, "confirmEmail", gc)
|
||||||
|
msg, err := app.email.constructConfirmation("", name, key, app, false)
|
||||||
|
if err != nil {
|
||||||
|
app.err.Printf("%s: Failed to construct confirmation email: %v", name, err)
|
||||||
|
} else if err := app.email.send(msg, req.Email); err != nil {
|
||||||
|
app.err.Printf("%s: Failed to send user confirmation email: %v", name, err)
|
||||||
|
} else {
|
||||||
|
app.info.Printf("%s: Sent user confirmation email to \"%s\"", name, req.Email)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
app.confirmMyAction(gc, key)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
14
email.go
14
email.go
@ -10,6 +10,7 @@ import (
|
|||||||
"html/template"
|
"html/template"
|
||||||
"io"
|
"io"
|
||||||
"io/fs"
|
"io/fs"
|
||||||
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
@ -304,10 +305,17 @@ func (emailer *Emailer) confirmationValues(code, username, key string, app *appC
|
|||||||
} else {
|
} else {
|
||||||
message := app.config.Section("messages").Key("message").String()
|
message := app.config.Section("messages").Key("message").String()
|
||||||
inviteLink := app.config.Section("invite_emails").Key("url_base").String()
|
inviteLink := app.config.Section("invite_emails").Key("url_base").String()
|
||||||
if !strings.HasSuffix(inviteLink, "/invite") {
|
if code == "" { // Personal email change
|
||||||
inviteLink += "/invite"
|
if strings.HasSuffix(inviteLink, "/invite") {
|
||||||
|
inviteLink = strings.TrimSuffix(inviteLink, "/invite")
|
||||||
|
}
|
||||||
|
inviteLink = fmt.Sprintf("%s/my/confirm/%s", inviteLink, url.PathEscape(key))
|
||||||
|
} else { // Invite email confirmation
|
||||||
|
if !strings.HasSuffix(inviteLink, "/invite") {
|
||||||
|
inviteLink += "/invite"
|
||||||
|
}
|
||||||
|
inviteLink = fmt.Sprintf("%s/%s?key=%s", inviteLink, code, url.PathEscape(key))
|
||||||
}
|
}
|
||||||
inviteLink = fmt.Sprintf("%s/%s?key=%s", inviteLink, code, key)
|
|
||||||
template["helloUser"] = emailer.lang.Strings.template("helloUser", tmpl{"username": username})
|
template["helloUser"] = emailer.lang.Strings.template("helloUser", tmpl{"username": username})
|
||||||
template["confirmationURL"] = inviteLink
|
template["confirmationURL"] = inviteLink
|
||||||
template["message"] = message
|
template["message"] = message
|
||||||
|
@ -17,6 +17,22 @@
|
|||||||
<title>{{ .lang.Strings.pageTitle }}</title>
|
<title>{{ .lang.Strings.pageTitle }}</title>
|
||||||
</head>
|
</head>
|
||||||
<body class="max-w-full overflow-x-hidden section">
|
<body class="max-w-full overflow-x-hidden section">
|
||||||
|
<div id="modal-email" class="modal">
|
||||||
|
<div class="card relative mx-auto my-[10%] w-4/5 lg:w-1/3">
|
||||||
|
<div class="content">
|
||||||
|
<span class="heading mb-4 my-2"></span>
|
||||||
|
<label class="label supra row m-1" for="modal-email-input">{{ .strings.emailAddress }}</label>
|
||||||
|
<div class="row">
|
||||||
|
<input type="email" class="col sm field ~neutral @low input" id="modal-email-input" placeholder="{{ .strings.emailAddress }}">
|
||||||
|
</div>
|
||||||
|
<button class="button ~urge @low supra full-width center lg my-2 modal-submit">{{ .strings.submit }}</button>
|
||||||
|
</div>
|
||||||
|
<div class="confirmation-required unfocused">
|
||||||
|
<span class="heading mb-4">{{ .strings.confirmationRequired }} <span class="modal-close">×</span></span>
|
||||||
|
<p class="content mb-4">{{ .strings.confirmationRequiredMessage }}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div id="notification-box"></div>
|
<div id="notification-box"></div>
|
||||||
<div class="top-4 left-4 absolute">
|
<div class="top-4 left-4 absolute">
|
||||||
<span class="dropdown" tabindex="0" id="lang-dropdown">
|
<span class="dropdown" tabindex="0" id="lang-dropdown">
|
||||||
@ -54,7 +70,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="card @low dark:~d_neutral flex-col" id="card-contact">
|
<div class="card @low dark:~d_neutral flex-col" id="card-contact">
|
||||||
<span class="heading mb-2">{{ .strings.contactMethods }}</span>
|
<span class="heading mb-2">{{ .strings.contactMethods }}</span>
|
||||||
<div class="content flex justify-between flex-col"></div>
|
<div class="content flex justify-between flex-col h-100"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -18,7 +18,6 @@
|
|||||||
"create": "Opret",
|
"create": "Opret",
|
||||||
"apply": "Anvend",
|
"apply": "Anvend",
|
||||||
"delete": "Slet",
|
"delete": "Slet",
|
||||||
"add": "Tilføj",
|
|
||||||
"select": "Vælg",
|
"select": "Vælg",
|
||||||
"name": "Navn",
|
"name": "Navn",
|
||||||
"date": "Dato",
|
"date": "Dato",
|
||||||
@ -46,7 +45,6 @@
|
|||||||
"conditionals": "Betingelser",
|
"conditionals": "Betingelser",
|
||||||
"preview": "Eksempel",
|
"preview": "Eksempel",
|
||||||
"reset": "Nulstil",
|
"reset": "Nulstil",
|
||||||
"edit": "Rediger",
|
|
||||||
"donate": "Doner",
|
"donate": "Doner",
|
||||||
"contactThrough": "Kontakt gennem:",
|
"contactThrough": "Kontakt gennem:",
|
||||||
"extendExpiry": "Forlæng udløb",
|
"extendExpiry": "Forlæng udløb",
|
||||||
|
@ -66,7 +66,6 @@
|
|||||||
"variables": "Variablen",
|
"variables": "Variablen",
|
||||||
"preview": "Vorschau",
|
"preview": "Vorschau",
|
||||||
"reset": "Zurücksetzen",
|
"reset": "Zurücksetzen",
|
||||||
"edit": "Bearbeiten",
|
|
||||||
"customizeMessages": "Benachrichtigungen anpassen",
|
"customizeMessages": "Benachrichtigungen anpassen",
|
||||||
"customizeMessagesDescription": "Wenn du jfa-go's E-Mail-Vorlagen nicht benutzen willst, kannst du deinen eigenen unter Verwendung von Markdown erstellen.",
|
"customizeMessagesDescription": "Wenn du jfa-go's E-Mail-Vorlagen nicht benutzen willst, kannst du deinen eigenen unter Verwendung von Markdown erstellen.",
|
||||||
"announce": "Ankündigen",
|
"announce": "Ankündigen",
|
||||||
@ -87,7 +86,6 @@
|
|||||||
"contactThrough": "Kontakt über:",
|
"contactThrough": "Kontakt über:",
|
||||||
"sendPIN": "Bitte den Benutzer, die unten stehende PIN an den Bot zu senden.",
|
"sendPIN": "Bitte den Benutzer, die unten stehende PIN an den Bot zu senden.",
|
||||||
"inviteMonths": "Monate",
|
"inviteMonths": "Monate",
|
||||||
"add": "Hinzufügen",
|
|
||||||
"select": "Auswählen",
|
"select": "Auswählen",
|
||||||
"searchDiscordUser": "Gib den Discord-Benutzername ein, um den Benutzer zu finden.",
|
"searchDiscordUser": "Gib den Discord-Benutzername ein, um den Benutzer zu finden.",
|
||||||
"findDiscordUser": "Suche Discord-Benutzer",
|
"findDiscordUser": "Suche Discord-Benutzer",
|
||||||
|
@ -66,7 +66,6 @@
|
|||||||
"variables": "Μεταβλητές",
|
"variables": "Μεταβλητές",
|
||||||
"preview": "Προεπισκόπηση",
|
"preview": "Προεπισκόπηση",
|
||||||
"reset": "Επαναφορά",
|
"reset": "Επαναφορά",
|
||||||
"edit": "Επεξεργασία",
|
|
||||||
"customizeMessages": "Παραμετροποίηση Emails",
|
"customizeMessages": "Παραμετροποίηση Emails",
|
||||||
"advancedSettings": "Προχωρημένες Ρυθμίσεις",
|
"advancedSettings": "Προχωρημένες Ρυθμίσεις",
|
||||||
"customizeMessagesDescription": "Αν δεν θέλετε να ζρησιμοποιήσετε τα πρότυπα email του jfa-go, μπορείτε να δημιουργήσετε τα δικά σας με χρήση Markdown.",
|
"customizeMessagesDescription": "Αν δεν θέλετε να ζρησιμοποιήσετε τα πρότυπα email του jfa-go, μπορείτε να δημιουργήσετε τα δικά σας με χρήση Markdown.",
|
||||||
|
@ -93,12 +93,10 @@
|
|||||||
"contactThrough": "Contact through:",
|
"contactThrough": "Contact through:",
|
||||||
"select": "Select",
|
"select": "Select",
|
||||||
"date": "Date",
|
"date": "Date",
|
||||||
"edit": "Edit",
|
|
||||||
"extendExpiry": "Extend expiry",
|
"extendExpiry": "Extend expiry",
|
||||||
"sendPWR": "Send Password Reset",
|
"sendPWR": "Send Password Reset",
|
||||||
"inviteMonths": "Months",
|
"inviteMonths": "Months",
|
||||||
"inviteDuration": "Invite Duration",
|
"inviteDuration": "Invite Duration",
|
||||||
"add": "Add",
|
|
||||||
"update": "Update",
|
"update": "Update",
|
||||||
"user": "User",
|
"user": "User",
|
||||||
"userExpiryDescription": "A specified amount of time after each signup, jfa-go will delete/disable the account. You can change this behaviour in settings.",
|
"userExpiryDescription": "A specified amount of time after each signup, jfa-go will delete/disable the account. You can change this behaviour in settings.",
|
||||||
|
@ -18,7 +18,6 @@
|
|||||||
"create": "Create",
|
"create": "Create",
|
||||||
"apply": "Apply",
|
"apply": "Apply",
|
||||||
"delete": "Delete",
|
"delete": "Delete",
|
||||||
"add": "Add",
|
|
||||||
"select": "Select",
|
"select": "Select",
|
||||||
"name": "Name",
|
"name": "Name",
|
||||||
"date": "Date",
|
"date": "Date",
|
||||||
@ -51,7 +50,6 @@
|
|||||||
"conditionals": "Conditionals",
|
"conditionals": "Conditionals",
|
||||||
"preview": "Preview",
|
"preview": "Preview",
|
||||||
"reset": "Reset",
|
"reset": "Reset",
|
||||||
"edit": "Edit",
|
|
||||||
"donate": "Donate",
|
"donate": "Donate",
|
||||||
"unlink": "Unlink Account",
|
"unlink": "Unlink Account",
|
||||||
"sendPWR": "Send Password Reset",
|
"sendPWR": "Send Password Reset",
|
||||||
|
@ -43,7 +43,6 @@
|
|||||||
"variables": "Variables",
|
"variables": "Variables",
|
||||||
"preview": "Vista previa",
|
"preview": "Vista previa",
|
||||||
"reset": "Reiniciar",
|
"reset": "Reiniciar",
|
||||||
"edit": "Editar",
|
|
||||||
"extendExpiry": "Extender el vencimiento",
|
"extendExpiry": "Extender el vencimiento",
|
||||||
"customizeMessages": "Personalizar mensajes",
|
"customizeMessages": "Personalizar mensajes",
|
||||||
"customizeMessagesDescription": "Si no desea utilizar las plantillas de mensajes de jfa-go, puede crear las suyas con Markdown.",
|
"customizeMessagesDescription": "Si no desea utilizar las plantillas de mensajes de jfa-go, puede crear las suyas con Markdown.",
|
||||||
@ -85,7 +84,6 @@
|
|||||||
"notifyUserCreation": "Sobre la creación de usuarios",
|
"notifyUserCreation": "Sobre la creación de usuarios",
|
||||||
"conditionals": "Condicionales",
|
"conditionals": "Condicionales",
|
||||||
"donate": "Donar",
|
"donate": "Donar",
|
||||||
"add": "Agregar",
|
|
||||||
"templates": "Plantillas",
|
"templates": "Plantillas",
|
||||||
"contactThrough": "Contactar a través de:",
|
"contactThrough": "Contactar a través de:",
|
||||||
"select": "Seleccionar",
|
"select": "Seleccionar",
|
||||||
|
@ -73,7 +73,6 @@
|
|||||||
"variables": "Variables",
|
"variables": "Variables",
|
||||||
"preview": "Aperçu",
|
"preview": "Aperçu",
|
||||||
"reset": "Réinitialisation",
|
"reset": "Réinitialisation",
|
||||||
"edit": "Éditer",
|
|
||||||
"customizeMessages": "Personnaliser les e-mails",
|
"customizeMessages": "Personnaliser les e-mails",
|
||||||
"inviteDuration": "Durée de l'invitation",
|
"inviteDuration": "Durée de l'invitation",
|
||||||
"advancedSettings": "Paramètres avancés",
|
"advancedSettings": "Paramètres avancés",
|
||||||
@ -88,7 +87,6 @@
|
|||||||
"extendExpiry": "Prolonger l'expiration",
|
"extendExpiry": "Prolonger l'expiration",
|
||||||
"contactThrough": "Contacté par :",
|
"contactThrough": "Contacté par :",
|
||||||
"sendPIN": "Demandez à l'utilisateur d'envoyer le code PIN ci-dessous au bot.",
|
"sendPIN": "Demandez à l'utilisateur d'envoyer le code PIN ci-dessous au bot.",
|
||||||
"add": "Ajouter",
|
|
||||||
"select": "Sélectionner",
|
"select": "Sélectionner",
|
||||||
"findDiscordUser": "Trouver l'utilisateur Discord",
|
"findDiscordUser": "Trouver l'utilisateur Discord",
|
||||||
"linkMatrixDescription": "Entrez le nom d'utilisateur et le mot de passe de l'utilisateur pour l’utilisateur comme bot. Une fois soumis, l'application va redémarrer.",
|
"linkMatrixDescription": "Entrez le nom d'utilisateur et le mot de passe de l'utilisateur pour l’utilisateur comme bot. Une fois soumis, l'application va redémarrer.",
|
||||||
|
@ -18,7 +18,6 @@
|
|||||||
"create": "Létrehozás",
|
"create": "Létrehozás",
|
||||||
"apply": "Alkalmaz",
|
"apply": "Alkalmaz",
|
||||||
"delete": "Törlés",
|
"delete": "Törlés",
|
||||||
"add": "Hozzáadás",
|
|
||||||
"select": "Kiválasztás",
|
"select": "Kiválasztás",
|
||||||
"name": "Név",
|
"name": "Név",
|
||||||
"date": "Dátum",
|
"date": "Dátum",
|
||||||
@ -49,7 +48,6 @@
|
|||||||
"conditionals": "Feltételek",
|
"conditionals": "Feltételek",
|
||||||
"preview": "Előnézet",
|
"preview": "Előnézet",
|
||||||
"reset": "Visszaállítás",
|
"reset": "Visszaállítás",
|
||||||
"edit": "Szerkesztés",
|
|
||||||
"donate": "Támogatás",
|
"donate": "Támogatás",
|
||||||
"sendPWR": "Jelszó visszaállítás küldése",
|
"sendPWR": "Jelszó visszaállítás küldése",
|
||||||
"contactThrough": "",
|
"contactThrough": "",
|
||||||
|
@ -66,7 +66,6 @@
|
|||||||
"variables": "Variabel",
|
"variables": "Variabel",
|
||||||
"preview": "Pratinjau",
|
"preview": "Pratinjau",
|
||||||
"reset": "Setel ulang",
|
"reset": "Setel ulang",
|
||||||
"edit": "Edit",
|
|
||||||
"customizeMessages": "Sesuaikan Email",
|
"customizeMessages": "Sesuaikan Email",
|
||||||
"customizeMessagesDescription": "Jika Anda tidak ingin menggunakan templat email jfa-go, Anda dapat membuatnya sendiri menggunakan Markdown.",
|
"customizeMessagesDescription": "Jika Anda tidak ingin menggunakan templat email jfa-go, Anda dapat membuatnya sendiri menggunakan Markdown.",
|
||||||
"announce": "Mengumumkan",
|
"announce": "Mengumumkan",
|
||||||
|
@ -71,7 +71,6 @@
|
|||||||
"customizeMessagesDescription": "Als je de e-mailsjablonen van jfa-go niet wilt gebruiken, kun je met gebruik van Markdown je eigen aanmaken.",
|
"customizeMessagesDescription": "Als je de e-mailsjablonen van jfa-go niet wilt gebruiken, kun je met gebruik van Markdown je eigen aanmaken.",
|
||||||
"preview": "Voorbeeld",
|
"preview": "Voorbeeld",
|
||||||
"reset": "Reset",
|
"reset": "Reset",
|
||||||
"edit": "Bewerken",
|
|
||||||
"customizeMessages": "E-mails aanpassen",
|
"customizeMessages": "E-mails aanpassen",
|
||||||
"inviteDuration": "Geldigheidsduur uitnodiging",
|
"inviteDuration": "Geldigheidsduur uitnodiging",
|
||||||
"userExpiryDescription": "Een bepaalde tijd na elke aanmelding, wordt de account verwijderd/uitgeschakeld door jfa-go. Dit kan aangepast worden in de instellingen.",
|
"userExpiryDescription": "Een bepaalde tijd na elke aanmelding, wordt de account verwijderd/uitgeschakeld door jfa-go. Dit kan aangepast worden in de instellingen.",
|
||||||
@ -87,7 +86,6 @@
|
|||||||
"donate": "Doneer",
|
"donate": "Doneer",
|
||||||
"contactThrough": "Stuur bericht via:",
|
"contactThrough": "Stuur bericht via:",
|
||||||
"sendPIN": "Vraag de gebruiker om onderstaande pincode naar de bot te sturen.",
|
"sendPIN": "Vraag de gebruiker om onderstaande pincode naar de bot te sturen.",
|
||||||
"add": "Voeg toe",
|
|
||||||
"searchDiscordUser": "Begin de Discord gebruikersnaam te typen om de gebruiker te vinden.",
|
"searchDiscordUser": "Begin de Discord gebruikersnaam te typen om de gebruiker te vinden.",
|
||||||
"linkMatrixDescription": "Vul de gebruikersnaam en wachtwoord in van de gebruiker om als bot te gebruiken. De app start zodra ze zijn verstuurd.",
|
"linkMatrixDescription": "Vul de gebruikersnaam en wachtwoord in van de gebruiker om als bot te gebruiken. De app start zodra ze zijn verstuurd.",
|
||||||
"select": "Selecteer",
|
"select": "Selecteer",
|
||||||
|
@ -18,7 +18,6 @@
|
|||||||
"create": "",
|
"create": "",
|
||||||
"apply": "",
|
"apply": "",
|
||||||
"delete": "",
|
"delete": "",
|
||||||
"add": "",
|
|
||||||
"select": "",
|
"select": "",
|
||||||
"name": "Imię",
|
"name": "Imię",
|
||||||
"date": "Data",
|
"date": "Data",
|
||||||
@ -49,7 +48,6 @@
|
|||||||
"conditionals": "",
|
"conditionals": "",
|
||||||
"preview": "",
|
"preview": "",
|
||||||
"reset": "Zresetuj",
|
"reset": "Zresetuj",
|
||||||
"edit": "Edytuj",
|
|
||||||
"donate": "",
|
"donate": "",
|
||||||
"sendPWR": "",
|
"sendPWR": "",
|
||||||
"contactThrough": "",
|
"contactThrough": "",
|
||||||
|
@ -71,7 +71,6 @@
|
|||||||
"variables": "Variáveis",
|
"variables": "Variáveis",
|
||||||
"preview": "Pre-visualizar",
|
"preview": "Pre-visualizar",
|
||||||
"reset": "Redefinir",
|
"reset": "Redefinir",
|
||||||
"edit": "Editar",
|
|
||||||
"customizeMessages": "Customizar Emails",
|
"customizeMessages": "Customizar Emails",
|
||||||
"userExpiryDescription": "Após um determinado período de tempo de cada inscrição, o jfa-go apagará/desabilitará a conta. Você pode alterar essa opção nas configurações.",
|
"userExpiryDescription": "Após um determinado período de tempo de cada inscrição, o jfa-go apagará/desabilitará a conta. Você pode alterar essa opção nas configurações.",
|
||||||
"inviteDuration": "Duração do Convite",
|
"inviteDuration": "Duração do Convite",
|
||||||
@ -89,7 +88,6 @@
|
|||||||
"sendPIN": "Peça que o usuário envie o PIN abaixo para o bot.",
|
"sendPIN": "Peça que o usuário envie o PIN abaixo para o bot.",
|
||||||
"searchDiscordUser": "Digite o nome de usuário do Discord.",
|
"searchDiscordUser": "Digite o nome de usuário do Discord.",
|
||||||
"findDiscordUser": "Encontrar usuário Discord",
|
"findDiscordUser": "Encontrar usuário Discord",
|
||||||
"add": "Adicionar",
|
|
||||||
"linkMatrixDescription": "Digite o nome de usuário e a senha para usar como bot. Depois de enviado, o aplicativo será reiniciado.",
|
"linkMatrixDescription": "Digite o nome de usuário e a senha para usar como bot. Depois de enviado, o aplicativo será reiniciado.",
|
||||||
"select": "Selecionar",
|
"select": "Selecionar",
|
||||||
"templates": "Modelos",
|
"templates": "Modelos",
|
||||||
|
@ -34,7 +34,6 @@
|
|||||||
"variables": "Variabler",
|
"variables": "Variabler",
|
||||||
"preview": "Förhandsvisning",
|
"preview": "Förhandsvisning",
|
||||||
"reset": "Återställ",
|
"reset": "Återställ",
|
||||||
"edit": "Redigera",
|
|
||||||
"customizeMessages": "Anpassa e-post",
|
"customizeMessages": "Anpassa e-post",
|
||||||
"customizeMessagesDescription": "Om du inte vill använda jfa-go's e-postmallar, så kan du skapa dina egna med Markdown.",
|
"customizeMessagesDescription": "Om du inte vill använda jfa-go's e-postmallar, så kan du skapa dina egna med Markdown.",
|
||||||
"markdownSupported": "Markdown stöds.",
|
"markdownSupported": "Markdown stöds.",
|
||||||
|
@ -18,7 +18,6 @@
|
|||||||
"create": "Tạo mới",
|
"create": "Tạo mới",
|
||||||
"apply": "Áp dụng",
|
"apply": "Áp dụng",
|
||||||
"delete": "Xóa",
|
"delete": "Xóa",
|
||||||
"add": "Thêm",
|
|
||||||
"select": "Chọn",
|
"select": "Chọn",
|
||||||
"name": "Tên",
|
"name": "Tên",
|
||||||
"date": "Ngày",
|
"date": "Ngày",
|
||||||
@ -48,7 +47,6 @@
|
|||||||
"conditionals": "Điều kiện",
|
"conditionals": "Điều kiện",
|
||||||
"preview": "Xem trước",
|
"preview": "Xem trước",
|
||||||
"reset": "Đặt lại",
|
"reset": "Đặt lại",
|
||||||
"edit": "Chỉnh sửa",
|
|
||||||
"donate": "Đóng góp",
|
"donate": "Đóng góp",
|
||||||
"sendPWR": "Gửi Đặt lại Mật khẩu",
|
"sendPWR": "Gửi Đặt lại Mật khẩu",
|
||||||
"contactThrough": "Liên lạc qua:",
|
"contactThrough": "Liên lạc qua:",
|
||||||
|
@ -18,7 +18,6 @@
|
|||||||
"create": "创建",
|
"create": "创建",
|
||||||
"apply": "申请",
|
"apply": "申请",
|
||||||
"delete": "删除",
|
"delete": "删除",
|
||||||
"add": "添加",
|
|
||||||
"select": "选择",
|
"select": "选择",
|
||||||
"name": "名称",
|
"name": "名称",
|
||||||
"date": "日期",
|
"date": "日期",
|
||||||
@ -47,7 +46,6 @@
|
|||||||
"conditionals": "条件性条款",
|
"conditionals": "条件性条款",
|
||||||
"preview": "预览",
|
"preview": "预览",
|
||||||
"reset": "重设",
|
"reset": "重设",
|
||||||
"edit": "编辑",
|
|
||||||
"donate": "捐助",
|
"donate": "捐助",
|
||||||
"contactThrough": "联系方式:",
|
"contactThrough": "联系方式:",
|
||||||
"extendExpiry": "延长有效期",
|
"extendExpiry": "延长有效期",
|
||||||
|
@ -18,7 +18,6 @@
|
|||||||
"create": "創建",
|
"create": "創建",
|
||||||
"apply": "應用",
|
"apply": "應用",
|
||||||
"delete": "刪除",
|
"delete": "刪除",
|
||||||
"add": "添加",
|
|
||||||
"select": "選擇",
|
"select": "選擇",
|
||||||
"name": "帳戶名稱",
|
"name": "帳戶名稱",
|
||||||
"date": "日期",
|
"date": "日期",
|
||||||
@ -49,7 +48,6 @@
|
|||||||
"conditionals": "條件",
|
"conditionals": "條件",
|
||||||
"preview": "預覽",
|
"preview": "預覽",
|
||||||
"reset": "重設",
|
"reset": "重設",
|
||||||
"edit": "編輯",
|
|
||||||
"donate": "捐贈",
|
"donate": "捐贈",
|
||||||
"sendPWR": "發送密碼重置",
|
"sendPWR": "發送密碼重置",
|
||||||
"contactThrough": "聯繫方式:",
|
"contactThrough": "聯繫方式:",
|
||||||
|
@ -32,7 +32,9 @@
|
|||||||
"disabled": "Deaktiveret",
|
"disabled": "Deaktiveret",
|
||||||
"reEnable": "Genaktiver",
|
"reEnable": "Genaktiver",
|
||||||
"disable": "Deaktiver",
|
"disable": "Deaktiver",
|
||||||
"expiry": "Udløb"
|
"expiry": "Udløb",
|
||||||
|
"add": "Tilføj",
|
||||||
|
"edit": "Rediger"
|
||||||
},
|
},
|
||||||
"notifications": {
|
"notifications": {
|
||||||
"errorLoginBlank": "Brugernavnet og/eller adgangskoden blev efterladt tomme.",
|
"errorLoginBlank": "Brugernavnet og/eller adgangskoden blev efterladt tomme.",
|
||||||
|
@ -32,7 +32,9 @@
|
|||||||
"disabled": "Deaktiviert",
|
"disabled": "Deaktiviert",
|
||||||
"reEnable": "Wieder aktivieren",
|
"reEnable": "Wieder aktivieren",
|
||||||
"disable": "Deaktivieren",
|
"disable": "Deaktivieren",
|
||||||
"expiry": "Ablaufdatum"
|
"expiry": "Ablaufdatum",
|
||||||
|
"add": "Hinzufügen",
|
||||||
|
"edit": "Bearbeiten"
|
||||||
},
|
},
|
||||||
"notifications": {
|
"notifications": {
|
||||||
"errorLoginBlank": "Der Benutzername und/oder das Passwort wurden nicht ausgefüllt.",
|
"errorLoginBlank": "Der Benutzername und/oder das Passwort wurden nicht ausgefüllt.",
|
||||||
|
@ -23,7 +23,8 @@
|
|||||||
"disabled": "Απενεργοποιημένο",
|
"disabled": "Απενεργοποιημένο",
|
||||||
"reEnable": "Επανα-ενεργοποίηση",
|
"reEnable": "Επανα-ενεργοποίηση",
|
||||||
"disable": "Απενεργοποίηση",
|
"disable": "Απενεργοποίηση",
|
||||||
"expiry": "Λήξη"
|
"expiry": "Λήξη",
|
||||||
|
"edit": "Επεξεργασία"
|
||||||
},
|
},
|
||||||
"notifications": {
|
"notifications": {
|
||||||
"errorLoginBlank": "Το όνομα χρήστη και/ή ο κωδικός ήταν κενά.",
|
"errorLoginBlank": "Το όνομα χρήστη και/ή ο κωδικός ήταν κενά.",
|
||||||
|
@ -32,7 +32,9 @@
|
|||||||
"disabled": "Disabled",
|
"disabled": "Disabled",
|
||||||
"reEnable": "Re-enable",
|
"reEnable": "Re-enable",
|
||||||
"disable": "Disable",
|
"disable": "Disable",
|
||||||
"expiry": "Expiry"
|
"expiry": "Expiry",
|
||||||
|
"add": "Add",
|
||||||
|
"edit": "Edit"
|
||||||
},
|
},
|
||||||
"notifications": {
|
"notifications": {
|
||||||
"errorLoginBlank": "The username and/or password was left blank.",
|
"errorLoginBlank": "The username and/or password was left blank.",
|
||||||
|
@ -33,9 +33,13 @@
|
|||||||
"reEnable": "Re-enable",
|
"reEnable": "Re-enable",
|
||||||
"disable": "Disable",
|
"disable": "Disable",
|
||||||
"contactMethods": "Contact Methods",
|
"contactMethods": "Contact Methods",
|
||||||
|
"addContactMethod": "Add Contact Method",
|
||||||
|
"editContactMethod": "Edit Contact Method",
|
||||||
"accountStatus": "Account Status",
|
"accountStatus": "Account Status",
|
||||||
"notSet": "Not set",
|
"notSet": "Not set",
|
||||||
"expiry": "Expiry"
|
"expiry": "Expiry",
|
||||||
|
"add": "Add",
|
||||||
|
"edit": "Edit"
|
||||||
},
|
},
|
||||||
"notifications": {
|
"notifications": {
|
||||||
"errorLoginBlank": "The username and/or password were left blank.",
|
"errorLoginBlank": "The username and/or password were left blank.",
|
||||||
|
@ -32,7 +32,9 @@
|
|||||||
"disabled": "Desactivado",
|
"disabled": "Desactivado",
|
||||||
"reEnable": "Reactivar",
|
"reEnable": "Reactivar",
|
||||||
"disable": "Desactivar",
|
"disable": "Desactivar",
|
||||||
"expiry": "Expiración"
|
"expiry": "Expiración",
|
||||||
|
"add": "Agregar",
|
||||||
|
"edit": "Editar"
|
||||||
},
|
},
|
||||||
"notifications": {
|
"notifications": {
|
||||||
"errorLoginBlank": "El nombre de usuario y/o la contraseña se dejaron en blanco.",
|
"errorLoginBlank": "El nombre de usuario y/o la contraseña se dejaron en blanco.",
|
||||||
|
@ -32,7 +32,9 @@
|
|||||||
"disabled": "Désactivé",
|
"disabled": "Désactivé",
|
||||||
"reEnable": "Ré-activé",
|
"reEnable": "Ré-activé",
|
||||||
"disable": "Désactivé",
|
"disable": "Désactivé",
|
||||||
"expiry": "Expiration"
|
"expiry": "Expiration",
|
||||||
|
"add": "Ajouter",
|
||||||
|
"edit": "Éditer"
|
||||||
},
|
},
|
||||||
"notifications": {
|
"notifications": {
|
||||||
"errorLoginBlank": "Le nom d'utilisateur et/ou le mot de passe sont vides.",
|
"errorLoginBlank": "Le nom d'utilisateur et/ou le mot de passe sont vides.",
|
||||||
|
@ -10,7 +10,9 @@
|
|||||||
"disabled": "Tiltva",
|
"disabled": "Tiltva",
|
||||||
"reEnable": "Újra engedélyezés",
|
"reEnable": "Újra engedélyezés",
|
||||||
"disable": "Letiltás",
|
"disable": "Letiltás",
|
||||||
"expiry": "Lejárat"
|
"expiry": "Lejárat",
|
||||||
|
"add": "Hozzáadás",
|
||||||
|
"edit": "Szerkesztés"
|
||||||
},
|
},
|
||||||
"notifications": {},
|
"notifications": {},
|
||||||
"quantityStrings": {}
|
"quantityStrings": {}
|
||||||
|
@ -17,7 +17,8 @@
|
|||||||
"time12h": "Waktu 12 jam",
|
"time12h": "Waktu 12 jam",
|
||||||
"theme": "Tema",
|
"theme": "Tema",
|
||||||
"login": "Masuk",
|
"login": "Masuk",
|
||||||
"logout": "Keluar"
|
"logout": "Keluar",
|
||||||
|
"edit": "Edit"
|
||||||
},
|
},
|
||||||
"notifications": {
|
"notifications": {
|
||||||
"errorLoginBlank": "Nama pengguna dan / atau sandi kosong.",
|
"errorLoginBlank": "Nama pengguna dan / atau sandi kosong.",
|
||||||
|
@ -32,7 +32,9 @@
|
|||||||
"disabled": "Uitgeschakeld",
|
"disabled": "Uitgeschakeld",
|
||||||
"reEnable": "Opnieuw inschakelen",
|
"reEnable": "Opnieuw inschakelen",
|
||||||
"disable": "Uitschakelen",
|
"disable": "Uitschakelen",
|
||||||
"expiry": "Verloop"
|
"expiry": "Verloop",
|
||||||
|
"add": "Voeg toe",
|
||||||
|
"edit": "Bewerken"
|
||||||
},
|
},
|
||||||
"notifications": {
|
"notifications": {
|
||||||
"errorLoginBlank": "De gebruikersnaam en/of wachtwoord is leeg.",
|
"errorLoginBlank": "De gebruikersnaam en/of wachtwoord is leeg.",
|
||||||
|
@ -29,7 +29,8 @@
|
|||||||
"enabled": "Włączone",
|
"enabled": "Włączone",
|
||||||
"disabled": "Wyłączone",
|
"disabled": "Wyłączone",
|
||||||
"disable": "Wyłączone",
|
"disable": "Wyłączone",
|
||||||
"expiry": "Wygasa"
|
"expiry": "Wygasa",
|
||||||
|
"edit": "Edytuj"
|
||||||
},
|
},
|
||||||
"notifications": {
|
"notifications": {
|
||||||
"errorConnection": "Nie udało się połączyć z jfa-go.",
|
"errorConnection": "Nie udało się połączyć z jfa-go.",
|
||||||
|
@ -32,7 +32,9 @@
|
|||||||
"disabled": "Desativado",
|
"disabled": "Desativado",
|
||||||
"reEnable": "Reativar",
|
"reEnable": "Reativar",
|
||||||
"disable": "Desativar",
|
"disable": "Desativar",
|
||||||
"expiry": "Expira"
|
"expiry": "Expira",
|
||||||
|
"add": "Adicionar",
|
||||||
|
"edit": "Editar"
|
||||||
},
|
},
|
||||||
"notifications": {
|
"notifications": {
|
||||||
"errorLoginBlank": "O nome de usuário e/ou senha foram deixados em branco.",
|
"errorLoginBlank": "O nome de usuário e/ou senha foram deixados em branco.",
|
||||||
|
@ -20,7 +20,8 @@
|
|||||||
"admin": "Admin",
|
"admin": "Admin",
|
||||||
"enabled": "Aktiverad",
|
"enabled": "Aktiverad",
|
||||||
"disabled": "Inaktiverad",
|
"disabled": "Inaktiverad",
|
||||||
"expiry": "Löper ut"
|
"expiry": "Löper ut",
|
||||||
|
"edit": "Redigera"
|
||||||
},
|
},
|
||||||
"notifications": {
|
"notifications": {
|
||||||
"errorLoginBlank": "Användarnamnet och/eller lösenordet lämnades tomt.",
|
"errorLoginBlank": "Användarnamnet och/eller lösenordet lämnades tomt.",
|
||||||
|
@ -10,7 +10,9 @@
|
|||||||
"disabled": "Tắt",
|
"disabled": "Tắt",
|
||||||
"reEnable": "Mở lại",
|
"reEnable": "Mở lại",
|
||||||
"disable": "Tắt",
|
"disable": "Tắt",
|
||||||
"expiry": "Hết hạn"
|
"expiry": "Hết hạn",
|
||||||
|
"add": "Thêm",
|
||||||
|
"edit": "Chỉnh sửa"
|
||||||
},
|
},
|
||||||
"notifications": {
|
"notifications": {
|
||||||
"errorConnection": "Không thể kết nối với jfa-go.",
|
"errorConnection": "Không thể kết nối với jfa-go.",
|
||||||
|
@ -32,7 +32,9 @@
|
|||||||
"disabled": "已禁用",
|
"disabled": "已禁用",
|
||||||
"reEnable": "重新启用",
|
"reEnable": "重新启用",
|
||||||
"disable": "禁用",
|
"disable": "禁用",
|
||||||
"expiry": "到期"
|
"expiry": "到期",
|
||||||
|
"add": "添加",
|
||||||
|
"edit": "编辑"
|
||||||
},
|
},
|
||||||
"notifications": {
|
"notifications": {
|
||||||
"errorLoginBlank": "用户名/密码留空。",
|
"errorLoginBlank": "用户名/密码留空。",
|
||||||
|
@ -32,7 +32,9 @@
|
|||||||
"disabled": "已禁用",
|
"disabled": "已禁用",
|
||||||
"reEnable": "重新啟用",
|
"reEnable": "重新啟用",
|
||||||
"disable": "禁用",
|
"disable": "禁用",
|
||||||
"expiry": "到期"
|
"expiry": "到期",
|
||||||
|
"add": "添加",
|
||||||
|
"edit": "編輯"
|
||||||
},
|
},
|
||||||
"notifications": {
|
"notifications": {
|
||||||
"errorLoginBlank": "帳戶名稱和/或密碼留空。",
|
"errorLoginBlank": "帳戶名稱和/或密碼留空。",
|
||||||
|
11
models.go
11
models.go
@ -391,3 +391,14 @@ type MyDetailsContactMethodsDTO struct {
|
|||||||
Value string `json:"value"`
|
Value string `json:"value"`
|
||||||
Enabled bool `json:"enabled"`
|
Enabled bool `json:"enabled"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ModifyMyEmailDTO struct {
|
||||||
|
Email string `json:"email"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ConfirmationTarget int
|
||||||
|
|
||||||
|
const (
|
||||||
|
UserEmailChange ConfirmationTarget = iota
|
||||||
|
NoOp
|
||||||
|
)
|
||||||
|
@ -147,6 +147,7 @@ func (app *appContext) loadRoutes(router *gin.Engine) {
|
|||||||
router.GET(p+"/my/account", app.MyUserPage)
|
router.GET(p+"/my/account", app.MyUserPage)
|
||||||
router.GET(p+"/my/token/login", app.getUserTokenLogin)
|
router.GET(p+"/my/token/login", app.getUserTokenLogin)
|
||||||
router.GET(p+"/my/token/refresh", app.getUserTokenRefresh)
|
router.GET(p+"/my/token/refresh", app.getUserTokenRefresh)
|
||||||
|
router.GET(p+"/my/confirm/:jwt", app.ConfirmMyAction)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if *SWAGGER {
|
if *SWAGGER {
|
||||||
@ -229,6 +230,7 @@ func (app *appContext) loadRoutes(router *gin.Engine) {
|
|||||||
user.GET(p+"/details", app.MyDetails)
|
user.GET(p+"/details", app.MyDetails)
|
||||||
user.POST(p+"/contact", app.SetMyContactMethods)
|
user.POST(p+"/contact", app.SetMyContactMethods)
|
||||||
user.POST(p+"/logout", app.LogoutUser)
|
user.POST(p+"/logout", app.LogoutUser)
|
||||||
|
user.POST(p+"/email", app.ModifyMyEmail)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -35,7 +35,9 @@
|
|||||||
"contactMethods": "common",
|
"contactMethods": "common",
|
||||||
"accountStatus": "common",
|
"accountStatus": "common",
|
||||||
"notSet": "common",
|
"notSet": "common",
|
||||||
"expiry": "admin"
|
"expiry": "common",
|
||||||
|
"add": "admin",
|
||||||
|
"edit": "admin"
|
||||||
},
|
},
|
||||||
"notifications": {
|
"notifications": {
|
||||||
"errorLoginBlank": "common",
|
"errorLoginBlank": "common",
|
||||||
|
@ -111,6 +111,7 @@ declare interface Modals {
|
|||||||
matrix: Modal;
|
matrix: Modal;
|
||||||
sendPWR?: Modal;
|
sendPWR?: Modal;
|
||||||
logs: Modal;
|
logs: Modal;
|
||||||
|
email?: Modal;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Invite {
|
interface Invite {
|
||||||
|
76
ts/user.ts
76
ts/user.ts
@ -1,7 +1,7 @@
|
|||||||
import { ThemeManager } from "./modules/theme.js";
|
import { ThemeManager } from "./modules/theme.js";
|
||||||
import { lang, LangFile, loadLangSelector } from "./modules/lang.js";
|
import { lang, LangFile, loadLangSelector } from "./modules/lang.js";
|
||||||
import { Modal } from "./modules/modal.js";
|
import { Modal } from "./modules/modal.js";
|
||||||
import { _get, _post, notificationBox, whichAnimationEvent, toDateString } from "./modules/common.js";
|
import { _get, _post, notificationBox, whichAnimationEvent, toDateString, toggleLoader } from "./modules/common.js";
|
||||||
import { Login } from "./modules/login.js";
|
import { Login } from "./modules/login.js";
|
||||||
|
|
||||||
interface userWindow extends Window {
|
interface userWindow extends Window {
|
||||||
@ -25,6 +25,7 @@ window.modals = {} as Modals;
|
|||||||
|
|
||||||
(() => {
|
(() => {
|
||||||
window.modals.login = new Modal(document.getElementById("modal-login"), true);
|
window.modals.login = new Modal(document.getElementById("modal-login"), true);
|
||||||
|
window.modals.email = new Modal(document.getElementById("modal-email"), false);
|
||||||
})();
|
})();
|
||||||
|
|
||||||
window.notifications = new notificationBox(document.getElementById('notification-box') as HTMLDivElement, 5);
|
window.notifications = new notificationBox(document.getElementById('notification-box') as HTMLDivElement, 5);
|
||||||
@ -73,12 +74,12 @@ class ContactMethods {
|
|||||||
this._buttons = {};
|
this._buttons = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
append = (name: string, details: MyDetailsContactMethod, icon: string) => {
|
append = (name: string, details: MyDetailsContactMethod, icon: string, addEditFunc?: (add: boolean) => void) => {
|
||||||
const row = document.createElement("div");
|
const row = document.createElement("div");
|
||||||
row.classList.add("row", "flex-expand", "my-2");
|
row.classList.add("row", "flex-expand", "my-2");
|
||||||
row.innerHTML = `
|
let innerHTML = `
|
||||||
<div class="inline align-middle">
|
<div class="inline align-middle">
|
||||||
<span class="shield ~info" alt="${name}">
|
<span class="shield ~urge" alt="${name}">
|
||||||
<span class="icon">
|
<span class="icon">
|
||||||
${icon}
|
${icon}
|
||||||
</span>
|
</span>
|
||||||
@ -86,13 +87,25 @@ class ContactMethods {
|
|||||||
<span class="ml-2 font-bold">${(details.value == "") ? window.lang.strings("notSet") : details.value}</span>
|
<span class="ml-2 font-bold">${(details.value == "") ? window.lang.strings("notSet") : details.value}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex items-center">
|
<div class="flex items-center">
|
||||||
<button class="user-contact-enabled-disabled button ~neutral">
|
<button class="user-contact-enabled-disabled button ~neutral" ${details.value =="" ? "disabled" : ""}>
|
||||||
<input type="checkbox" class="mr-2">
|
<input type="checkbox" class="mr-2">
|
||||||
<span>${window.lang.strings("enabled")}</span>
|
<span>${window.lang.strings("enabled")}</span>
|
||||||
</button>
|
</button>
|
||||||
|
`;
|
||||||
|
if (addEditFunc) {
|
||||||
|
innerHTML += `
|
||||||
|
<button class="user-contact-edit button ~info ml-2">
|
||||||
|
<i class="ri-${details.value == "" ? "add" : "edit"}-fill mr-2"></i>
|
||||||
|
<span>${details.value == "" ? window.lang.strings("add") : window.lang.strings("edit")}</span>
|
||||||
|
</button>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
innerHTML += `
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
row.innerHTML = innerHTML;
|
||||||
|
|
||||||
this._buttons[name] = {
|
this._buttons[name] = {
|
||||||
element: row,
|
element: row,
|
||||||
details: details
|
details: details
|
||||||
@ -102,11 +115,11 @@ class ContactMethods {
|
|||||||
const checkbox = button.querySelector("input[type=checkbox]") as HTMLInputElement;
|
const checkbox = button.querySelector("input[type=checkbox]") as HTMLInputElement;
|
||||||
const setButtonAppearance = () => {
|
const setButtonAppearance = () => {
|
||||||
if (checkbox.checked) {
|
if (checkbox.checked) {
|
||||||
button.classList.add("~info");
|
button.classList.add("~urge");
|
||||||
button.classList.remove("~neutral");
|
button.classList.remove("~neutral");
|
||||||
} else {
|
} else {
|
||||||
button.classList.add("~neutral");
|
button.classList.add("~neutral");
|
||||||
button.classList.remove("~info");
|
button.classList.remove("~urge");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
const onPress = () => {
|
const onPress = () => {
|
||||||
@ -124,6 +137,11 @@ class ContactMethods {
|
|||||||
checkbox.checked = details.enabled;
|
checkbox.checked = details.enabled;
|
||||||
setButtonAppearance();
|
setButtonAppearance();
|
||||||
|
|
||||||
|
if (addEditFunc) {
|
||||||
|
const addEditButton = row.querySelector(".user-contact-edit") as HTMLButtonElement;
|
||||||
|
addEditButton.onclick = () => addEditFunc(details.value == "");
|
||||||
|
}
|
||||||
|
|
||||||
this._content.appendChild(row);
|
this._content.appendChild(row);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -220,6 +238,36 @@ var expiryCard = new ExpiryCard(statusCard);
|
|||||||
|
|
||||||
var contactMethodList = new ContactMethods(contactCard);
|
var contactMethodList = new ContactMethods(contactCard);
|
||||||
|
|
||||||
|
const addEditEmail = (add: boolean): void => {
|
||||||
|
console.log("call");
|
||||||
|
const heading = window.modals.email.modal.querySelector(".heading");
|
||||||
|
heading.innerHTML = (add ? window.lang.strings("addContactMethod") : window.lang.strings("editContactMethod")) + `<span class="modal-close">×</span>`;
|
||||||
|
const input = document.getElementById("modal-email-input") as HTMLInputElement;
|
||||||
|
input.value = "";
|
||||||
|
const confirmationRequired = window.modals.email.modal.querySelector(".confirmation-required");
|
||||||
|
confirmationRequired.classList.add("unfocused");
|
||||||
|
|
||||||
|
const content = window.modals.email.modal.querySelector(".content");
|
||||||
|
content.classList.remove("unfocused");
|
||||||
|
|
||||||
|
const submit = window.modals.email.modal.querySelector(".modal-submit") as HTMLButtonElement;
|
||||||
|
submit.onclick = () => {
|
||||||
|
toggleLoader(submit);
|
||||||
|
_post("/my/email", {"email": input.value}, (req: XMLHttpRequest) => {
|
||||||
|
if (req.readyState == 4 && (req.status == 303 || req.status == 200)) {
|
||||||
|
window.location.reload();
|
||||||
|
}
|
||||||
|
}, true, (req: XMLHttpRequest) => {
|
||||||
|
if (req.readyState == 4 && req.status == 401) {
|
||||||
|
content.classList.add("unfocused");
|
||||||
|
confirmationRequired.classList.remove("unfocused");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
window.modals.email.show();
|
||||||
|
}
|
||||||
|
|
||||||
document.addEventListener("details-reload", () => {
|
document.addEventListener("details-reload", () => {
|
||||||
_get("/my/details", null, (req: XMLHttpRequest) => {
|
_get("/my/details", null, (req: XMLHttpRequest) => {
|
||||||
if (req.readyState == 4) {
|
if (req.readyState == 4) {
|
||||||
@ -244,16 +292,16 @@ document.addEventListener("details-reload", () => {
|
|||||||
|
|
||||||
contactMethodList.clear();
|
contactMethodList.clear();
|
||||||
|
|
||||||
const contactMethods = [
|
const contactMethods: { name: string, icon: string, f: (add: boolean) => void }[] = [
|
||||||
["email", `<i class="ri-mail-fill"></i>`],
|
{name: "email", icon: `<i class="ri-mail-fill ri-lg"></i>`, f: addEditEmail},
|
||||||
["discord", `<i class="ri-discord-fill"></i>`],
|
{name: "discord", icon: `<i class="ri-discord-fill ri-lg"></i>`, f: null},
|
||||||
["telegram", `<i class="ri-telegram-fill"></i>`],
|
{name: "telegram", icon: `<i class="ri-telegram-fill ri-lg"></i>`, f: null},
|
||||||
["matrix", `[m]`]
|
{name: "matrix", icon: `<span class="font-bold">[m]</span>`, f: null}
|
||||||
];
|
];
|
||||||
|
|
||||||
for (let method of contactMethods) {
|
for (let method of contactMethods) {
|
||||||
if (method[0] in details) {
|
if (method.name in details) {
|
||||||
contactMethodList.append(method[0], details[method[0]], method[1]);
|
contactMethodList.append(method.name, details[method.name], method.icon, method.f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user