mirror of
https://github.com/hrfee/jfa-go.git
synced 2025-04-20 01:52:53 +00:00
Compare commits
No commits in common. "8eed4b012783f4cf78fcba7635265fc0d95efd48" and "46fe3a7f5d4105348cff2e8471f03fdce16a2d87" have entirely different histories.
8eed4b0127
...
46fe3a7f5d
@ -1,7 +1,7 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="en" class="{{ .cssClass }}">
|
<html lang="en" class="{{ .cssClass }}">
|
||||||
<head>
|
<head>
|
||||||
<link rel="stylesheet" type="text/css" href="{{ .urlBase }}/css/bundle.css">
|
<link rel="stylesheet" type="text/css" href="css/bundle.css">
|
||||||
<script>
|
<script>
|
||||||
window.URLBase = "{{ .urlBase }}";
|
window.URLBase = "{{ .urlBase }}";
|
||||||
window.notificationsEnabled = {{ .notifications }};
|
window.notificationsEnabled = {{ .notifications }};
|
||||||
@ -40,7 +40,7 @@
|
|||||||
<div id="modal-about" class="modal">
|
<div id="modal-about" class="modal">
|
||||||
<div class="modal-content content card">
|
<div class="modal-content content card">
|
||||||
<span class="heading">{{ .strings.aboutProgram }} <span class="modal-close">×</span></span>
|
<span class="heading">{{ .strings.aboutProgram }} <span class="modal-close">×</span></span>
|
||||||
<img src="{{ .urlBase }}/banner.svg" class="mt-1" alt="jfa-go banner">
|
<img src="/banner.svg" class="mt-1" alt="jfa-go banner">
|
||||||
<p><i class="icon ri-github-fill"></i><a href="https://github.com/hrfee/jfa-go">jfa-go</a></p>
|
<p><i class="icon ri-github-fill"></i><a href="https://github.com/hrfee/jfa-go">jfa-go</a></p>
|
||||||
<p>{{ .strings.version }} <span class="code monospace">{{ .version }}</span></p>
|
<p>{{ .strings.version }} <span class="code monospace">{{ .version }}</span></p>
|
||||||
<p>{{ .strings.commitNoun }} <span class="code monospace">{{ .commit }}</span></p>
|
<p>{{ .strings.commitNoun }} <span class="code monospace">{{ .commit }}</span></p>
|
||||||
@ -292,6 +292,6 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<script src="{{ .urlBase }}/js/admin.js" type="module"></script>
|
<script src="js/admin.js" type="module"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
@ -36,7 +36,7 @@
|
|||||||
"sendDeleteNotificationEmail": "Send notification email",
|
"sendDeleteNotificationEmail": "Send notification email",
|
||||||
"sendDeleteNotifiationExample": "Your account has been deleted.",
|
"sendDeleteNotifiationExample": "Your account has been deleted.",
|
||||||
"settingsRestart": "Restart",
|
"settingsRestart": "Restart",
|
||||||
"settingsRestarting": "Restarting…",
|
"settingsRestarting": "Restarting...",
|
||||||
"settingsRestartRequired": "Restart needed",
|
"settingsRestartRequired": "Restart needed",
|
||||||
"settingsRestartRequiredDescription": "A restart is necessary to apply some settings you changed. Restart now or later?",
|
"settingsRestartRequiredDescription": "A restart is necessary to apply some settings you changed. Restart now or later?",
|
||||||
"settingsApplyRestartLater": "Apply, restart later",
|
"settingsApplyRestartLater": "Apply, restart later",
|
||||||
@ -55,6 +55,7 @@
|
|||||||
"addProfileDescription": "Create a Jellyfin user and configure it, then select it below. When this profile is applied to an invite, new users will be created with the settings.",
|
"addProfileDescription": "Create a Jellyfin user and configure it, then select it below. When this profile is applied to an invite, new users will be created with the settings.",
|
||||||
"addProfileNameOf": "Profile Name",
|
"addProfileNameOf": "Profile Name",
|
||||||
"addProfileStoreHomescreenLayout": "Store homescreen layout",
|
"addProfileStoreHomescreenLayout": "Store homescreen layout",
|
||||||
|
|
||||||
"inviteNoUsersCreated": "None yet!",
|
"inviteNoUsersCreated": "None yet!",
|
||||||
"inviteUsersCreated": "Created users",
|
"inviteUsersCreated": "Created users",
|
||||||
"inviteNoProfile": "No Profile",
|
"inviteNoProfile": "No Profile",
|
||||||
@ -63,6 +64,7 @@
|
|||||||
"inviteRemainingUses": "Remaining uses",
|
"inviteRemainingUses": "Remaining uses",
|
||||||
"inviteNoInvites": "None",
|
"inviteNoInvites": "None",
|
||||||
"inviteExpiresInTime": "Expires in {n}",
|
"inviteExpiresInTime": "Expires in {n}",
|
||||||
|
|
||||||
"notifyEvent": "Notify on:",
|
"notifyEvent": "Notify on:",
|
||||||
"notifyInviteExpiry": "On expiry",
|
"notifyInviteExpiry": "On expiry",
|
||||||
"notifyUserCreation": "On user creation"
|
"notifyUserCreation": "On user creation"
|
||||||
@ -96,6 +98,7 @@
|
|||||||
"errorUserCreated": "Failed to create user {n}.",
|
"errorUserCreated": "Failed to create user {n}.",
|
||||||
"errorSendWelcomeEmail": "Failed to send welcome email (check console/logs)"
|
"errorSendWelcomeEmail": "Failed to send welcome email (check console/logs)"
|
||||||
},
|
},
|
||||||
|
|
||||||
"quantityStrings": {
|
"quantityStrings": {
|
||||||
"modifySettingsFor": {
|
"modifySettingsFor": {
|
||||||
"singular": "Modify Settings for {n} user",
|
"singular": "Modify Settings for {n} user",
|
||||||
|
@ -40,7 +40,7 @@
|
|||||||
"settingsApplyRestartLater": "Appliquer, redémarrer plus tard",
|
"settingsApplyRestartLater": "Appliquer, redémarrer plus tard",
|
||||||
"settingsApplyRestartNow": "Appliquer et redémarrer",
|
"settingsApplyRestartNow": "Appliquer et redémarrer",
|
||||||
"settingsApplied": "Paramètres appliqués.",
|
"settingsApplied": "Paramètres appliqués.",
|
||||||
"settingsRefreshPage": "Actualisez la page dans quelques secondes.",
|
"settingsRefreshPage": "Actualisez la page dans quelques secondes",
|
||||||
"settingsRequiredOrRestartMessage": "Remarque : {n} indique un champ obligatoire, {n} indique que les modifications nécessitent un redémarrage.",
|
"settingsRequiredOrRestartMessage": "Remarque : {n} indique un champ obligatoire, {n} indique que les modifications nécessitent un redémarrage.",
|
||||||
"settingsSave": "Sauver",
|
"settingsSave": "Sauver",
|
||||||
"ombiUserDefaults": "Paramètres par défaut de l'utilisateur Ombi",
|
"ombiUserDefaults": "Paramètres par défaut de l'utilisateur Ombi",
|
||||||
@ -64,9 +64,7 @@
|
|||||||
"notifyEvent": "Notifier sur :",
|
"notifyEvent": "Notifier sur :",
|
||||||
"notifyInviteExpiry": "À l'expiration",
|
"notifyInviteExpiry": "À l'expiration",
|
||||||
"notifyUserCreation": "à la création de l'utilisateur",
|
"notifyUserCreation": "à la création de l'utilisateur",
|
||||||
"label": "Etiquette",
|
"label": "Etiquette"
|
||||||
"settingsRestarting": "Redémarrage…",
|
|
||||||
"settingsRestart": "Redémarrer"
|
|
||||||
},
|
},
|
||||||
"notifications": {
|
"notifications": {
|
||||||
"changedEmailAddress": "Adresse e-mail modifiée de {n}.",
|
"changedEmailAddress": "Adresse e-mail modifiée de {n}.",
|
||||||
|
@ -39,7 +39,7 @@
|
|||||||
"settingsApplyRestartLater": "Sla op, herstart later",
|
"settingsApplyRestartLater": "Sla op, herstart later",
|
||||||
"settingsApplyRestartNow": "Sla op & herstart",
|
"settingsApplyRestartNow": "Sla op & herstart",
|
||||||
"settingsApplied": "Wijzigingen doorgevoerd.",
|
"settingsApplied": "Wijzigingen doorgevoerd.",
|
||||||
"settingsRefreshPage": "Ververs de pagina over enkele seconden.",
|
"settingsRefreshPage": "Ververs de pagina over enkele seconden",
|
||||||
"settingsRequiredOrRestartMessage": "Opmerking: {n} is een verplicht veld, {n} geeft aan dat na wijzigen een herstart nodig is.",
|
"settingsRequiredOrRestartMessage": "Opmerking: {n} is een verplicht veld, {n} geeft aan dat na wijzigen een herstart nodig is.",
|
||||||
"settingsSave": "Opslaan",
|
"settingsSave": "Opslaan",
|
||||||
"ombiUserDefaults": "Ombi gebruiker standaardinstellingen",
|
"ombiUserDefaults": "Ombi gebruiker standaardinstellingen",
|
||||||
@ -63,9 +63,7 @@
|
|||||||
"notifyEvent": "Meldingen:",
|
"notifyEvent": "Meldingen:",
|
||||||
"notifyInviteExpiry": "Bij verloop",
|
"notifyInviteExpiry": "Bij verloop",
|
||||||
"notifyUserCreation": "Bij aanmaken gebruiker",
|
"notifyUserCreation": "Bij aanmaken gebruiker",
|
||||||
"label": "Label",
|
"label": "Label"
|
||||||
"settingsRestart": "Herstart",
|
|
||||||
"settingsRestarting": "Aan het herstarten…"
|
|
||||||
},
|
},
|
||||||
"notifications": {
|
"notifications": {
|
||||||
"changedEmailAddress": "E-mailadres van {n} gewijzigd.",
|
"changedEmailAddress": "E-mailadres van {n} gewijzigd.",
|
||||||
|
@ -40,7 +40,7 @@
|
|||||||
"settingsApplyRestartLater": "Aplicar, reiniciar mais tarde",
|
"settingsApplyRestartLater": "Aplicar, reiniciar mais tarde",
|
||||||
"settingsApplyRestartNow": "Aplicar e reiniciar",
|
"settingsApplyRestartNow": "Aplicar e reiniciar",
|
||||||
"settingsApplied": "Configurações aplicada.",
|
"settingsApplied": "Configurações aplicada.",
|
||||||
"settingsRefreshPage": "Atualize a página em alguns segundos.",
|
"settingsRefreshPage": "Atualize a página em alguns segundos",
|
||||||
"settingsRequiredOrRestartMessage": "Nota: {n} indica campo obrigatório, {n} indica que as alterações requer um reinício.",
|
"settingsRequiredOrRestartMessage": "Nota: {n} indica campo obrigatório, {n} indica que as alterações requer um reinício.",
|
||||||
"settingsSave": "Salve",
|
"settingsSave": "Salve",
|
||||||
"ombiUserDefaults": "Padrões do usuário Ombi",
|
"ombiUserDefaults": "Padrões do usuário Ombi",
|
||||||
@ -63,9 +63,7 @@
|
|||||||
"inviteExpiresInTime": "Expira em {n}",
|
"inviteExpiresInTime": "Expira em {n}",
|
||||||
"notifyEvent": "Notificar em:",
|
"notifyEvent": "Notificar em:",
|
||||||
"notifyInviteExpiry": "No vencimento",
|
"notifyInviteExpiry": "No vencimento",
|
||||||
"notifyUserCreation": "Na criação do usuário",
|
"notifyUserCreation": "Na criação do usuário"
|
||||||
"settingsRestart": "Reiniciar",
|
|
||||||
"settingsRestarting": "Reiniciando…"
|
|
||||||
},
|
},
|
||||||
"notifications": {
|
"notifications": {
|
||||||
"changedEmailAddress": "Endereço de e-mail alterado de {n}.",
|
"changedEmailAddress": "Endereço de e-mail alterado de {n}.",
|
||||||
|
2
main.go
2
main.go
@ -567,8 +567,6 @@ func start(asDaemon, firstCall bool) {
|
|||||||
app.info.Fatalf("Failed to load language files: %+v\n", err)
|
app.info.Fatalf("Failed to load language files: %+v\n", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
cssHeader = app.loadCSSHeader()
|
|
||||||
|
|
||||||
app.info.Println("Loading routes")
|
app.info.Println("Loading routes")
|
||||||
if debugMode {
|
if debugMode {
|
||||||
gin.SetMode(gin.DebugMode)
|
gin.SetMode(gin.DebugMode)
|
||||||
|
15
ts/admin.ts
15
ts/admin.ts
@ -84,24 +84,23 @@ window.tabs.addTab("accounts", null, accounts.reload);
|
|||||||
window.tabs.addTab("settings", null, settings.reload);
|
window.tabs.addTab("settings", null, settings.reload);
|
||||||
|
|
||||||
for (let tab of ["invites", "accounts", "settings"]) {
|
for (let tab of ["invites", "accounts", "settings"]) {
|
||||||
if (window.location.pathname == window.URLBase + "/" + tab) {
|
if (window.location.pathname == "/" + tab) {
|
||||||
window.tabs.switch(tab, true);
|
window.tabs.switch(tab, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (window.location.pathname == window.URLBase + "/") {
|
if (window.location.pathname == "/") {
|
||||||
window.tabs.switch("invites", true);
|
window.tabs.switch("invites", true);
|
||||||
}
|
}
|
||||||
|
|
||||||
document.addEventListener("tab-change", (event: CustomEvent) => {
|
document.addEventListener("tab-change", (event: CustomEvent) => {
|
||||||
const urlParams = new URLSearchParams(window.location.search);
|
const urlParams = new URLSearchParams(window.location.search);
|
||||||
const lang = urlParams.get('lang');
|
const lang = urlParams.get('lang');
|
||||||
let tab = window.URLBase + "/" + event.detail;
|
let tab = "/" + event.detail;
|
||||||
if (tab == window.URLBase + "/invites") {
|
if (tab == "/invites") {
|
||||||
if (window.location.pathname == window.URLBase + "/") {
|
if (window.location.pathname == "/") {
|
||||||
tab = window.URLBase + "/";
|
tab = "/";
|
||||||
} else if (window.URLBase) { tab = window.URLBase; }
|
} else { tab = "../"; }
|
||||||
else { tab = "../"; }
|
|
||||||
}
|
}
|
||||||
if (lang) {
|
if (lang) {
|
||||||
tab += "?lang=" + lang
|
tab += "?lang=" + lang
|
||||||
|
@ -42,15 +42,7 @@ class user implements User {
|
|||||||
}
|
}
|
||||||
|
|
||||||
get email(): string { return this._emailAddress; }
|
get email(): string { return this._emailAddress; }
|
||||||
set email(value: string) {
|
set email(value: string) { this._email.value = value; this._emailAddress = value; }
|
||||||
this._emailAddress = value;
|
|
||||||
const input = this._email.querySelector("input");
|
|
||||||
if (input) {
|
|
||||||
input.value = value;
|
|
||||||
} else {
|
|
||||||
this._email.textContent = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
get last_active(): string { return this._lastActive.textContent; }
|
get last_active(): string { return this._lastActive.textContent; }
|
||||||
set last_active(value: string) { this._lastActive.textContent = value; }
|
set last_active(value: string) { this._lastActive.textContent = value; }
|
||||||
@ -63,27 +55,20 @@ class user implements User {
|
|||||||
this._row.innerHTML = `
|
this._row.innerHTML = `
|
||||||
<td><input type="checkbox" value=""></td>
|
<td><input type="checkbox" value=""></td>
|
||||||
<td><span class="accounts-username"></span> <span class="accounts-admin"></span></td>
|
<td><span class="accounts-username"></span> <span class="accounts-admin"></span></td>
|
||||||
<td><i class="icon ri-edit-line accounts-email-edit"></i><span class="accounts-email-container ml-half"></span></td>
|
<td><i class="icon ri-edit-line accounts-email-edit"></i><input type="email" class="input ~neutral !normal stealth-input stealth-input-hidden accounts-email" readonly></td>
|
||||||
<td class="accounts-last-active"></td>
|
<td class="accounts-last-active"></td>
|
||||||
`;
|
`;
|
||||||
const emailEditor = `<input type="email" class="input ~neutral !normal stealth-input">`;
|
|
||||||
this._check = this._row.querySelector("input[type=checkbox]") as HTMLInputElement;
|
this._check = this._row.querySelector("input[type=checkbox]") as HTMLInputElement;
|
||||||
this._username = this._row.querySelector(".accounts-username") as HTMLSpanElement;
|
this._username = this._row.querySelector(".accounts-username") as HTMLSpanElement;
|
||||||
this._admin = this._row.querySelector(".accounts-admin") as HTMLSpanElement;
|
this._admin = this._row.querySelector(".accounts-admin") as HTMLSpanElement;
|
||||||
this._email = this._row.querySelector(".accounts-email-container") as HTMLInputElement;
|
this._email = this._row.querySelector(".accounts-email") as HTMLInputElement;
|
||||||
this._emailEditButton = this._row.querySelector(".accounts-email-edit") as HTMLElement;
|
this._emailEditButton = this._row.querySelector(".accounts-email-edit") as HTMLElement;
|
||||||
this._lastActive = this._row.querySelector(".accounts-last-active") as HTMLTableDataCellElement;
|
this._lastActive = this._row.querySelector(".accounts-last-active") as HTMLTableDataCellElement;
|
||||||
this._check.onchange = () => { this.selected = this._check.checked; }
|
this._check.onchange = () => { this.selected = this._check.checked; }
|
||||||
|
|
||||||
const toggleStealthInput = () => {
|
const toggleStealthInput = () => {
|
||||||
if (this._emailEditButton.classList.contains("ri-edit-line")) {
|
this._email.classList.toggle("stealth-input-hidden");
|
||||||
this._email.innerHTML = emailEditor;
|
this._email.readOnly = !this._email.readOnly;
|
||||||
this._email.querySelector("input").value = this._emailAddress;
|
|
||||||
this._email.classList.remove("ml-half");
|
|
||||||
} else {
|
|
||||||
this._email.textContent = this._emailAddress;
|
|
||||||
this._email.classList.add("ml-half");
|
|
||||||
}
|
|
||||||
this._emailEditButton.classList.toggle("ri-check-line");
|
this._emailEditButton.classList.toggle("ri-check-line");
|
||||||
this._emailEditButton.classList.toggle("ri-edit-line");
|
this._emailEditButton.classList.toggle("ri-edit-line");
|
||||||
};
|
};
|
||||||
@ -95,7 +80,7 @@ class user implements User {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
this._emailEditButton.onclick = () => {
|
this._emailEditButton.onclick = () => {
|
||||||
if (this._emailEditButton.classList.contains("ri-edit-line")) {
|
if (this._email.classList.contains("stealth-input-hidden")) {
|
||||||
document.addEventListener('click', outerClickListener);
|
document.addEventListener('click', outerClickListener);
|
||||||
} else {
|
} else {
|
||||||
this._updateEmail();
|
this._updateEmail();
|
||||||
@ -109,7 +94,7 @@ class user implements User {
|
|||||||
|
|
||||||
private _updateEmail = () => {
|
private _updateEmail = () => {
|
||||||
let oldEmail = this.email;
|
let oldEmail = this.email;
|
||||||
this.email = this._email.querySelector("input").value;
|
this.email = this._email.value;
|
||||||
let send = {};
|
let send = {};
|
||||||
send[this.id] = this.email;
|
send[this.id] = this.email;
|
||||||
_post("/users/emails", send, (req: XMLHttpRequest) => {
|
_post("/users/emails", send, (req: XMLHttpRequest) => {
|
||||||
|
10
views.go
10
views.go
@ -11,19 +11,17 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var css = []string{"bundle.css", "remixicon.css"}
|
var css = []string{"bundle.css", "remixicon.css"}
|
||||||
var cssHeader string
|
var cssHeader = func() string {
|
||||||
|
|
||||||
func (app *appContext) loadCSSHeader() string {
|
|
||||||
l := len(css)
|
l := len(css)
|
||||||
h := ""
|
h := ""
|
||||||
for i, f := range css {
|
for i, f := range css {
|
||||||
h += "<" + app.URLBase + "/css/" + f + ">; rel=preload; as=style"
|
h += "</css/" + f + ">; rel=preload; as=style"
|
||||||
if l > 1 && i != (l-1) {
|
if l > 1 && i != (l-1) {
|
||||||
h += ", "
|
h += ", "
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return h
|
return h
|
||||||
}
|
}()
|
||||||
|
|
||||||
func gcHTML(gc *gin.Context, code int, file string, templ gin.H) {
|
func gcHTML(gc *gin.Context, code int, file string, templ gin.H) {
|
||||||
gc.Header("Cache-Control", "no-cache")
|
gc.Header("Cache-Control", "no-cache")
|
||||||
@ -36,7 +34,7 @@ func (app *appContext) pushResources(gc *gin.Context, admin bool) {
|
|||||||
if admin {
|
if admin {
|
||||||
toPush := []string{"/js/admin.js", "/js/theme.js", "/js/lang.js", "/js/modal.js", "/js/tabs.js", "/js/invites.js", "/js/accounts.js", "/js/settings.js", "/js/profiles.js", "/js/common.js"}
|
toPush := []string{"/js/admin.js", "/js/theme.js", "/js/lang.js", "/js/modal.js", "/js/tabs.js", "/js/invites.js", "/js/accounts.js", "/js/settings.js", "/js/profiles.js", "/js/common.js"}
|
||||||
for _, f := range toPush {
|
for _, f := range toPush {
|
||||||
if err := pusher.Push(app.URLBase+f, nil); err != nil {
|
if err := pusher.Push(f, nil); err != nil {
|
||||||
app.debug.Printf("Failed HTTP2 ServerPush of \"%s\": %+v", f, err)
|
app.debug.Printf("Failed HTTP2 ServerPush of \"%s\": %+v", f, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user