+
{{ .lang.Login.title }}
{{ .lang.Login.description }}
@@ -199,7 +198,7 @@
{{ .lang.Strings.next }}
-
+
{{ .lang.JellyfinEmby.title }}
{{ .lang.JellyfinEmby.description }}
@@ -250,7 +249,7 @@
-
+
{{ .lang.Ombi.title }}
{{ .lang.Ombi.description }}
@@ -292,7 +291,7 @@
-
+
{{ .lang.UserPage.title }}
{{ .lang.UserPage.description }}
@@ -309,7 +308,7 @@
-
+
{{ .lang.Messages.title }}
@@ -404,7 +403,7 @@
-
-
-
-
+
{{ .lang.PasswordValidation.title }}
{{ .lang.PasswordValidation.description }}
@@ -522,7 +521,7 @@
-
+
{{ .lang.HelpMessages.title }}
{{ .lang.HelpMessages.description }}
@@ -555,10 +554,10 @@
-
+
{{ .lang.EndPage.finished }}
- {{ .lang.EndPage.restartMessage }}
+ {{ .lang.EndPage.restartMessage }} {{ .lang.EndPage.urlChangedNotice }}
-
+
diff --git a/jellyseerr/jellyseerr.go b/jellyseerr/jellyseerr.go
index f7d52ca..79ddc1c 100644
--- a/jellyseerr/jellyseerr.go
+++ b/jellyseerr/jellyseerr.go
@@ -87,7 +87,7 @@ func (js *Jellyseerr) req(mode string, uri string, data any, queryParams url.Val
}
}
resp, err := js.httpClient.Do(req)
- err = co.GenericErr(resp.StatusCode, err)
+ err = co.GenericErrFromResponse(resp, err)
defer js.timeoutHandler()
var responseText string
defer resp.Body.Close()
diff --git a/lang/setup/en-us.json b/lang/setup/en-us.json
index f6031c3..55c13e7 100644
--- a/lang/setup/en-us.json
+++ b/lang/setup/en-us.json
@@ -34,6 +34,7 @@
"endPage": {
"finished": "Finished!",
"restartMessage": "Features like Discord/Telegram/Matrix bots, custom Markdown messages, and a user-accessible \"My Account\" page can be found in Settings, so make sure to give it a browse. Click below to restart, then refresh the page.",
+ "urlChangedNotice": "If you've changed the host, port, subfolder etc. that jfa-go is hosted on, check the URL is right.",
"refreshPage": "Refresh"
},
"language": {
diff --git a/logmessages/logmessages.go b/logmessages/logmessages.go
index fbde1e1..9e8249b 100644
--- a/logmessages/logmessages.go
+++ b/logmessages/logmessages.go
@@ -212,9 +212,10 @@ const (
InitProxy = "Initialized proxy @ \"%s\""
FailedInitProxy = "Failed to initialize proxy @ \"%s\": %v\nStartup will pause for a bit to grab your attention."
NoURLSuffix = `Warning: Given "jfa_url"/"External jfa-go URL" value does not include "url_base" value!`
- BadURLBase = `Warning: Given URL Base "%s" may conflict with the applications subpaths.`
+ BadURLBase = `Warning: Given reverse proxy subfolder "%s" may conflict with the applications subpaths.`
NoExternalHost = `No "External jfa-go URL" provided, set one in Settings > General.`
LoginWontSave = ` Your login won't save until you do.`
+ SubpathBlockMessage = `URLs: Root subfolder = "%s", Admin = "%s", My Account = "%s", Invite forms = "%s"`
// discord.go
StartDaemon = "Started %s daemon"
diff --git a/main.go b/main.go
index d2f881c..7d1de5a 100644
--- a/main.go
+++ b/main.go
@@ -103,37 +103,37 @@ type appContext struct {
adminUsers []User
invalidTokens []string
// Keeping jf name because I can't think of a better one
- jf *mediabrowser.MediaBrowser
- authJf *mediabrowser.MediaBrowser
- ombi *OmbiWrapper
- js *JellyseerrWrapper
- thirdPartyServices []ThirdPartyService
- datePattern string
- timePattern string
- storage Storage
- validator Validator
- email *Emailer
- telegram *TelegramDaemon
- discord *DiscordDaemon
- matrix *MatrixDaemon
- contactMethods []ContactMethodLinker
- info, debug, err *logger.Logger
- host string
- port int
- version string
- URLBase, ExternalURI, ExternalDomain string
- updater *Updater
- webhooks *WebhookSender
- newUpdate bool // Whether whatever's in update is new.
- tag Tag
- update Update
- proxyEnabled bool
- proxyTransport *http.Transport
- proxyConfig easyproxy.ProxyConfig
- internalPWRs map[string]InternalPWR
- pwrCaptchas map[string]Captcha
- ConfirmationKeys map[string]map[string]ConfirmationKey // Map of invite code to jwt to request
- confirmationKeysLock sync.Mutex
+ jf *mediabrowser.MediaBrowser
+ authJf *mediabrowser.MediaBrowser
+ ombi *OmbiWrapper
+ js *JellyseerrWrapper
+ thirdPartyServices []ThirdPartyService
+ datePattern string
+ timePattern string
+ storage Storage
+ validator Validator
+ email *Emailer
+ telegram *TelegramDaemon
+ discord *DiscordDaemon
+ matrix *MatrixDaemon
+ contactMethods []ContactMethodLinker
+ info, debug, err *logger.Logger
+ host string
+ port int
+ version string
+ ExternalURI, ExternalDomain string
+ updater *Updater
+ webhooks *WebhookSender
+ newUpdate bool // Whether whatever's in update is new.
+ tag Tag
+ update Update
+ proxyEnabled bool
+ proxyTransport *http.Transport
+ proxyConfig easyproxy.ProxyConfig
+ internalPWRs map[string]InternalPWR
+ pwrCaptchas map[string]Captcha
+ ConfirmationKeys map[string]map[string]ConfirmationKey // Map of invite code to jwt to request
+ confirmationKeysLock sync.Mutex
}
func generateSecret(length int) (string, error) {
@@ -147,7 +147,7 @@ func generateSecret(length int) (string, error) {
func test(app *appContext) {
fmt.Printf("\n\n----\n\n")
- settings := map[string]interface{}{
+ settings := map[string]any{
"server": app.jf.Server,
"server version": app.jf.ServerInfo.Version,
"server name": app.jf.ServerInfo.Name,
diff --git a/models.go b/models.go
index 97e669b..686effd 100644
--- a/models.go
+++ b/models.go
@@ -467,3 +467,18 @@ type ContactMethodKey struct {
PIN string
User ContactMethodUser
}
+
+type PagePaths struct {
+ // The base subfolder the app is hosted on.
+ Base string `json:"Base"`
+ // Those for other pages
+ Admin string `json:"Admin"`
+ MyAccount string `json:"MyAccount"`
+ Form string `json:"Form"`
+}
+
+type PagePathsDTO struct {
+ PagePaths
+ // The subdirectory this bit of the app is hosted on (e.g. admin is usually on "/", myacc is usually on "/my/account")
+ Current string `json:"Current"`
+}
diff --git a/router.go b/router.go
index 9edc32c..e88f49f 100644
--- a/router.go
+++ b/router.go
@@ -108,8 +108,8 @@ func (app *appContext) loadRouter(address string, debug bool) *gin.Engine {
}
func (app *appContext) loadRoutes(router *gin.Engine) {
- routePrefixes := []string{app.URLBase}
- if app.URLBase != "" {
+ routePrefixes := []string{PAGES.Base}
+ if PAGES.Base != "" {
routePrefixes = append(routePrefixes, "")
}
@@ -118,7 +118,7 @@ func (app *appContext) loadRoutes(router *gin.Engine) {
for _, p := range routePrefixes {
router.GET(p+"/lang/:page", app.GetLanguages)
router.Use(static.Serve(p+"/", app.webFS))
- router.GET(p+"/", app.AdminPage)
+ router.GET(p+PAGES.Admin, app.AdminPage)
if app.config.Section("password_resets").Key("link_reset").MustBool(false) {
router.GET(p+"/reset", app.ResetPassword)
@@ -127,39 +127,39 @@ func (app *appContext) loadRoutes(router *gin.Engine) {
}
}
- router.GET(p+"/accounts", app.AdminPage)
- router.GET(p+"/settings", app.AdminPage)
- router.GET(p+"/activity", app.AdminPage)
- router.GET(p+"/accounts/user/:userID", app.AdminPage)
- router.GET(p+"/invites/:code", app.AdminPage)
+ router.GET(p+PAGES.Admin+"/accounts", app.AdminPage)
+ router.GET(p+PAGES.Admin+"/settings", app.AdminPage)
+ router.GET(p+PAGES.Admin+"/activity", app.AdminPage)
+ router.GET(p+PAGES.Admin+"/accounts/user/:userID", app.AdminPage)
+ router.GET(p+PAGES.Admin+"/invites/:code", app.AdminPage)
router.GET(p+"/lang/:page/:file", app.ServeLang)
router.GET(p+"/token/login", app.getTokenLogin)
router.GET(p+"/token/refresh", app.getTokenRefresh)
router.POST(p+"/user/invite", app.NewUserFromInvite)
- router.Use(static.Serve(p+"/invite/", app.webFS))
- router.GET(p+"/invite/:invCode", app.InviteProxy)
+ router.Use(static.Serve(p+PAGES.Form, app.webFS))
+ router.GET(p+PAGES.Form+"/:invCode", app.InviteProxy)
if app.config.Section("captcha").Key("enabled").MustBool(false) {
router.GET(p+"/captcha/gen/:invCode", app.GenCaptcha)
router.GET(p+"/captcha/img/:invCode/:captchaID", app.GetCaptcha)
router.POST(p+"/captcha/verify/:invCode/:captchaID/:text", app.VerifyCaptcha)
}
if telegramEnabled {
- router.GET(p+"/invite/:invCode/telegram/verified/:pin", app.TelegramVerifiedInvite)
+ router.GET(p+PAGES.Form+"/:invCode/telegram/verified/:pin", app.TelegramVerifiedInvite)
}
if discordEnabled {
- router.GET(p+"/invite/:invCode/discord/verified/:pin", app.DiscordVerifiedInvite)
+ router.GET(p+PAGES.Form+"/:invCode/discord/verified/:pin", app.DiscordVerifiedInvite)
if app.config.Section("discord").Key("provide_invite").MustBool(false) {
- router.GET(p+"/invite/:invCode/discord/invite", app.DiscordServerInvite)
+ router.GET(p+PAGES.Form+"/:invCode/discord/invite", app.DiscordServerInvite)
}
}
if matrixEnabled {
- router.GET(p+"/invite/:invCode/matrix/verified/:userID/:pin", app.MatrixCheckPIN)
- router.POST(p+"/invite/:invCode/matrix/user", app.MatrixSendPIN)
+ router.GET(p+PAGES.Form+"/:invCode/matrix/verified/:userID/:pin", app.MatrixCheckPIN)
+ router.POST(p+PAGES.Form+"/:invCode/matrix/user", app.MatrixSendPIN)
router.POST(p+"/users/matrix", app.MatrixConnect)
}
if userPageEnabled {
- router.GET(p+"/my/account", app.MyUserPage)
- router.GET(p+"/my/account/password/reset", app.MyUserPage)
+ router.GET(p+PAGES.MyAccount, app.MyUserPage)
+ router.GET(p+PAGES.MyAccount+"/password/reset", app.MyUserPage)
router.GET(p+"/my/token/login", app.getUserTokenLogin)
router.GET(p+"/my/token/refresh", app.getUserTokenRefresh)
router.GET(p+"/my/confirm/:jwt", app.ConfirmMyAction)
diff --git a/setup.go b/setup.go
index bebba74..5d2f1ab 100644
--- a/setup.go
+++ b/setup.go
@@ -39,8 +39,10 @@ func (app *appContext) ServeSetup(gc *gin.Context) {
respond(500, "Failed to fetch default values", gc)
return
}
+ pages := PagePathsDTO{PagePaths: PAGES}
gc.HTML(200, "setup.html", gin.H{
"cssVersion": cssVersion,
+ "pages": pages,
"lang": app.storage.lang.Setup[lang],
"strings": app.storage.lang.Setup[lang].Strings,
"emailLang": app.storage.lang.Email[emailLang],
diff --git a/ts/admin.ts b/ts/admin.ts
index 814fa37..6ee213b 100644
--- a/ts/admin.ts
+++ b/ts/admin.ts
@@ -11,6 +11,8 @@ import { _get, _post, notificationBox, whichAnimationEvent, bindManualDropdowns
import { Updater } from "./modules/update.js";
import { Login } from "./modules/login.js";
+declare var window: GlobalWindow;
+
const theme = new ThemeManager(document.getElementById("button-theme"));
window.lang = new lang(window.langFile as LangFile);
@@ -165,18 +167,17 @@ const defaultTab = tabs[0];
window.tabs = new Tabs();
for (let tab of tabs) {
- window.tabs.addTab(tab.id, tab.url, null, tab.reloader);
+ window.tabs.addTab(tab.id, window.pages.Admin + "/" + tab.url, null, tab.reloader);
}
let matchedTab = false
-for (let tab of tabs) {
- if (window.location.pathname.startsWith(window.URLBase + "/" + tab.url)) {
+for (const tab of tabs) {
+ if (window.location.pathname.startsWith(window.pages.Base + window.pages.Current + "/" + tab.url)) {
window.tabs.switch(tab.url, true);
matchedTab = true;
}
}
// Default tab
-// if ((window.URLBase + "/").includes(window.location.pathname)) {
if (!matchedTab) {
window.tabs.switch("", true);
}
diff --git a/ts/form.ts b/ts/form.ts
index 6552040..7ec413c 100644
--- a/ts/form.ts
+++ b/ts/form.ts
@@ -6,7 +6,7 @@ import { Validator, ValidatorConf, ValidatorRespDTO } from "./modules/validator.
import { Discord, Telegram, Matrix, ServiceConfiguration, MatrixConfiguration } from "./modules/account-linking.js";
import { Captcha, GreCAPTCHA } from "./modules/captcha.js";
-interface formWindow extends Window {
+interface formWindow extends GlobalWindow {
invalidPassword: string;
successModal: Modal;
telegramModal: Modal;
@@ -59,7 +59,7 @@ if (window.telegramEnabled) {
modal: window.telegramModal as Modal,
pin: window.telegramPIN,
pinURL: "",
- verifiedURL: "/invite/" + window.code + "/telegram/verified/",
+ verifiedURL: window.pages.Form + "/" + window.code + "/telegram/verified/",
invalidCodeError: window.messages["errorInvalidPIN"],
accountLinkedError: window.messages["errorAccountLinked"],
successError: window.messages["verified"],
@@ -89,9 +89,9 @@ if (window.discordEnabled) {
const discordConf: ServiceConfiguration = {
modal: window.discordModal as Modal,
pin: window.discordPIN,
- inviteURL: window.discordInviteLink ? ("/invite/" + window.code + "/discord/invite") : "",
+ inviteURL: window.discordInviteLink ? (window.pages.Form + "/" + window.code + "/discord/invite") : "",
pinURL: "",
- verifiedURL: "/invite/" + window.code + "/discord/verified/",
+ verifiedURL: window.pages.Form + "/" + window.code + "/discord/verified/",
invalidCodeError: window.messages["errorInvalidPIN"],
accountLinkedError: window.messages["errorAccountLinked"],
successError: window.messages["verified"],
@@ -121,8 +121,8 @@ if (window.matrixEnabled) {
const matrixConf: MatrixConfiguration = {
modal: window.matrixModal as Modal,
- sendMessageURL: "/invite/" + window.code + "/matrix/user",
- verifiedURL: "/invite/" + window.code + "/matrix/verified/",
+ sendMessageURL: window.pages.Form + "/" + window.code + "/matrix/user",
+ verifiedURL: window.pages.Form + "/" + window.code + "/matrix/verified/",
invalidCodeError: window.messages["errorInvalidPIN"],
accountLinkedError: window.messages["errorAccountLinked"],
unknownError: window.messages["errorUnknown"],
diff --git a/ts/modules/account-linking.ts b/ts/modules/account-linking.ts
index 301c3cb..effc511 100644
--- a/ts/modules/account-linking.ts
+++ b/ts/modules/account-linking.ts
@@ -1,7 +1,7 @@
import { Modal } from "../modules/modal.js";
import { _get, _post, toggleLoader, addLoader, removeLoader } from "../modules/common.js";
-interface formWindow extends Window {
+interface formWindow extends GlobalWindow {
invalidPassword: string;
successModal: Modal;
telegramModal: Modal;
diff --git a/ts/modules/accounts.ts b/ts/modules/accounts.ts
index ab88af0..c338bfc 100644
--- a/ts/modules/accounts.ts
+++ b/ts/modules/accounts.ts
@@ -6,6 +6,8 @@ import { DiscordUser, newDiscordSearch } from "../modules/discord.js";
import { Search, SearchConfiguration, QueryType, SearchableItem } from "../modules/search.js";
import { HiddenInputField } from "./ui.js";
+declare var window: GlobalWindow;
+
const dateParser = require("any-date-parser");
interface User {
diff --git a/ts/modules/activity.ts b/ts/modules/activity.ts
index d54972f..1049390 100644
--- a/ts/modules/activity.ts
+++ b/ts/modules/activity.ts
@@ -3,6 +3,8 @@ import { Search, SearchConfiguration, QueryType, SearchableItem } from "../modul
import { accountURLEvent } from "../modules/accounts.js";
import { inviteURLEvent } from "../modules/invites.js";
+declare var window: GlobalWindow;
+
export interface activity {
id: string;
type: string;
@@ -52,8 +54,8 @@ export class Activity implements activity, SearchableItem {
link = link.split(split)[0];
}
if (link.slice(-1) != "/") { link += "/"; }
- // FIXME: I should probably just be using window.URLBase, but incase thats not right, i'll put this warning here
- if (link != window.URLBase) console.error(`URL Bases don't match: "${link}" != "${window.URLBase}"`);
+ // FIXME: I should probably just be using window.pages.Base, but incase thats not right, i'll put this warning here
+ if (link != window.pages.Base) console.error(`URL Bases don't match: "${link}" != "${window.pages.Base}"`);
return link;
})(); */
@@ -66,17 +68,17 @@ export class Activity implements activity, SearchableItem {
}
_genUserLink = (): string => {
- return `
${this._genUserText()}`;
+ return `
${this._genUserText()}`;
}
_genSrcUserLink = (): string => {
- return `
${this._genSrcUserText()}`;
+ return `
${this._genSrcUserText()}`;
}
private _renderInvText = (): string => { return `
${this.value || this.invite_code || "???"}`; }
private _genInvLink = (): string => {
- return `
${this._renderInvText()}`;
+ return `
${this._renderInvText()}`;
}
diff --git a/ts/modules/common.ts b/ts/modules/common.ts
index d87498a..40b5ddd 100644
--- a/ts/modules/common.ts
+++ b/ts/modules/common.ts
@@ -1,4 +1,4 @@
-declare var window: Window;
+declare var window: GlobalWindow;
export function toDateString(date: Date): string {
const locale = window.language || (window as any).navigator.userLanguage || window.navigator.language;
@@ -23,7 +23,7 @@ export function toDateString(date: Date): string {
export const _get = (url: string, data: Object, onreadystatechange: (req: XMLHttpRequest) => void, noConnectionError: boolean = false): void => {
let req = new XMLHttpRequest();
- if (window.URLBase) { url = window.URLBase + url; }
+ if (window.pages) { url = window.pages.Base + url; }
req.open("GET", url, true);
req.responseType = 'json';
req.setRequestHeader("Authorization", "Bearer " + window.token);
@@ -42,7 +42,7 @@ export const _get = (url: string, data: Object, onreadystatechange: (req: XMLHtt
export const _download = (url: string, fname: string): void => {
let req = new XMLHttpRequest();
- if (window.URLBase) { url = window.URLBase + url; }
+ if (window.pages) { url = window.pages.Base + url; }
req.open("GET", url, true);
req.responseType = 'blob';
req.setRequestHeader("Authorization", "Bearer " + window.token);
@@ -58,7 +58,7 @@ export const _download = (url: string, fname: string): void => {
export const _upload = (url: string, formData: FormData): void => {
let req = new XMLHttpRequest();
- if (window.URLBase) { url = window.URLBase + url; }
+ if (window.pages) { url = window.pages.Base + url; }
req.open("POST", url, true);
req.setRequestHeader("Authorization", "Bearer " + window.token);
// req.setRequestHeader('Content-Type', 'multipart/form-data');
@@ -67,7 +67,8 @@ export const _upload = (url: string, formData: FormData): void => {
export const _post = (url: string, data: Object, onreadystatechange: (req: XMLHttpRequest) => void, response?: boolean, statusHandler?: (req: XMLHttpRequest) => void, noConnectionError: boolean = false): void => {
let req = new XMLHttpRequest();
- req.open("POST", window.URLBase + url, true);
+ if (window.pages) { url = window.pages.Base + url; }
+ req.open("POST", url, true);
if (response) {
req.responseType = 'json';
}
@@ -88,7 +89,8 @@ export const _post = (url: string, data: Object, onreadystatechange: (req: XMLHt
export function _delete(url: string, data: Object, onreadystatechange: (req: XMLHttpRequest) => void, noConnectionError: boolean = false): void {
let req = new XMLHttpRequest();
- req.open("DELETE", window.URLBase + url, true);
+ if (window.pages) { url = window.pages.Base + url; }
+ req.open("DELETE", url, true);
req.setRequestHeader("Authorization", "Bearer " + window.token);
req.setRequestHeader('Content-Type', 'application/json; charset=UTF-8');
req.onreadystatechange = () => {
diff --git a/ts/modules/discord.ts b/ts/modules/discord.ts
index 89e8a8c..f773ccf 100644
--- a/ts/modules/discord.ts
+++ b/ts/modules/discord.ts
@@ -1,5 +1,7 @@
import {addLoader, removeLoader, _get} from "../modules/common.js";
+declare var window: GlobalWindow;
+
export interface DiscordUser {
name: string;
avatar_url: string;
diff --git a/ts/modules/invites.ts b/ts/modules/invites.ts
index c9b759c..4c34a90 100644
--- a/ts/modules/invites.ts
+++ b/ts/modules/invites.ts
@@ -2,6 +2,8 @@ import { _get, _post, _delete, toClipboard, toggleLoader, toDateString } from ".
import { DiscordUser, newDiscordSearch } from "../modules/discord.js";
import { reloadProfileNames } from "../modules/profiles.js";
+declare var window: GlobalWindow;
+
class DOMInvite implements Invite {
updateNotify = (checkbox: HTMLInputElement) => {
let state: { [code: string]: { [type: string]: boolean } } = {};
@@ -66,7 +68,7 @@ class DOMInvite implements Invite {
codeLink = codeLink.split(split)[0];
}
if (codeLink.slice(-1) != "/") { codeLink += "/"; }
- this._codeLink = codeLink + "invite/" + code;
+ this._codeLink = codeLink + window.pages.Form + "/" + code;
const linkEl = this._codeArea.querySelector("a") as HTMLAnchorElement;
if (this.label == "") {
linkEl.textContent = code.replace(/-/g, '-');
diff --git a/ts/modules/login.ts b/ts/modules/login.ts
index 71cd590..11d09bd 100644
--- a/ts/modules/login.ts
+++ b/ts/modules/login.ts
@@ -1,6 +1,8 @@
import { Modal } from "../modules/modal.js";
import { toggleLoader, _post, unicodeB64Encode } from "../modules/common.js";
+declare var window: GlobalWindow;
+
export class Login {
loggedIn: boolean = false;
private _modal: Modal;
@@ -14,7 +16,7 @@ export class Login {
constructor(modal: Modal, endpoint: string, appearance: string) {
this._endpoint = endpoint;
- this._url = window.URLBase + endpoint;
+ this._url = window.pages.Base + endpoint;
if (this._url[this._url.length-1] != '/') this._url += "/";
this._modal = modal;
diff --git a/ts/modules/modal.ts b/ts/modules/modal.ts
index 77cbb4e..92e3435 100644
--- a/ts/modules/modal.ts
+++ b/ts/modules/modal.ts
@@ -1,4 +1,4 @@
-declare var window: Window;
+declare var window: GlobalWindow;
export class Modal implements Modal {
modal: HTMLElement;
diff --git a/ts/modules/pages.ts b/ts/modules/pages.ts
index 686f771..cc29c9a 100644
--- a/ts/modules/pages.ts
+++ b/ts/modules/pages.ts
@@ -32,7 +32,15 @@ export class PageManager {
private _onpopstate = (event: PopStateEvent) => {
let name = event.state;
- if (!this.pages.has(event.state)) {
+ if (name == null) {
+ // Attempt to use hash from URL, if it isn't there, try the last part of the URL.
+ if (window.location.hash && window.location.hash.charAt(0) == "#") {
+ name = window.location.hash.substring(1);
+ } else {
+ name = window.location.pathname.split("/").filter(Boolean).at(-1);
+ }
+ }
+ if (!this.pages.has(name)) {
name = this.pageList[0]
}
let success = this.pages.get(name).show();
diff --git a/ts/modules/profiles.ts b/ts/modules/profiles.ts
index e58fb27..51d6eb3 100644
--- a/ts/modules/profiles.ts
+++ b/ts/modules/profiles.ts
@@ -1,5 +1,7 @@
import { _get, _post, _delete, toggleLoader } from "../modules/common.js";
+declare var window: GlobalWindow;
+
export const profileLoadEvent = new CustomEvent("profileLoadEvent");
export const reloadProfileNames = (then?: () => void) => _get("/profiles/names", null, (req: XMLHttpRequest) => {
if (req.readyState != 4) return;
diff --git a/ts/modules/search.ts b/ts/modules/search.ts
index dd01dbe..fa8d1e1 100644
--- a/ts/modules/search.ts
+++ b/ts/modules/search.ts
@@ -1,5 +1,7 @@
const dateParser = require("any-date-parser");
+declare var window: GlobalWindow;
+
export interface QueryType {
name: string;
description?: string;
diff --git a/ts/modules/settings.ts b/ts/modules/settings.ts
index c9d1459..a1a43f8 100644
--- a/ts/modules/settings.ts
+++ b/ts/modules/settings.ts
@@ -2,6 +2,8 @@ import { _get, _post, _delete, _download, _upload, toggleLoader, addLoader, remo
import { Marked } from "@ts-stack/markdown";
import { stripMarkdown } from "../modules/stripmd.js";
+declare var window: GlobalWindow;
+
const toBool = (s: string): boolean => {
let b = Boolean(s);
if (s == "false") b = false;
diff --git a/ts/modules/tabs.ts b/ts/modules/tabs.ts
index 628ed7e..3f7d78b 100644
--- a/ts/modules/tabs.ts
+++ b/ts/modules/tabs.ts
@@ -1,5 +1,7 @@
import { PageManager, Page } from "../modules/pages.js";
+declare var window: GlobalWindow;
+
export interface Tab {
page: Page;
tabEl: HTMLDivElement;
@@ -38,7 +40,7 @@ export class Tabs implements Tabs {
tab.page = {
name: tabID,
title: document.title, /*FIXME: Get actual names from translations*/
- url: window.URLBase + "/" + url,
+ url: url,
show: () => {
tab.buttonEl.classList.add("active", "~urge");
tab.tabEl.classList.remove("unfocused");
diff --git a/ts/modules/update.ts b/ts/modules/update.ts
index ba2c946..c39fc63 100644
--- a/ts/modules/update.ts
+++ b/ts/modules/update.ts
@@ -1,6 +1,8 @@
import { _get, _post, toggleLoader, toDateString } from "../modules/common.js";
import { Marked, Renderer } from "@ts-stack/markdown";
+declare var window: GlobalWindow;
+
interface updateDTO {
new: boolean;
update: Update;
diff --git a/ts/pwr-pin.ts b/ts/pwr-pin.ts
index 8774967..a274a58 100644
--- a/ts/pwr-pin.ts
+++ b/ts/pwr-pin.ts
@@ -1,5 +1,7 @@
import { toClipboard, notificationBox } from "./modules/common.js";
+declare var window: GlobalWindow;
+
const pin = document.getElementById("pin") as HTMLSpanElement;
if (pin) {
diff --git a/ts/setup.ts b/ts/setup.ts
index 747ed83..d987060 100644
--- a/ts/setup.ts
+++ b/ts/setup.ts
@@ -3,12 +3,11 @@ import { lang, LangFile, loadLangSelector } from "./modules/lang.js";
import { ThemeManager } from "./modules/theme.js";
import { PageManager } from "./modules/pages.js";
-interface sWindow extends Window {
+interface sWindow extends GlobalWindow {
messages: {};
}
declare var window: sWindow;
-window.URLBase = "";
const theme = new ThemeManager(document.getElementById("button-theme"));
diff --git a/ts/typings/d.ts b/ts/typings/d.ts
index a53a3fb..b19a1c7 100644
--- a/ts/typings/d.ts
+++ b/ts/typings/d.ts
@@ -12,8 +12,19 @@ interface ArrayConstructor {
from(arrayLike: any, mapFn?, thisArg?): Array
;
}
-declare interface Window {
- URLBase: string;
+declare interface PagePaths {
+ // The base subfolder the app is hosted on.
+ Base: string;
+ // The subdirectory this bit of the app is hosted on (e.g. admin is usually on "/", myacc is usually on "/my/account")
+ Current: string;
+ // Those for other pages
+ Admin: string;
+ MyAccount: string;
+ Form: string;
+}
+
+declare interface GlobalWindow extends Window {
+ pages: PagePaths;
modals: Modals;
cssFile: string;
availableProfiles: string[];
@@ -25,6 +36,7 @@ declare interface Window {
matrixEnabled: boolean;
ombiEnabled: boolean;
jellyseerrEnabled: boolean;
+ pwrEnabled: boolean;
usernameEnabled: boolean;
linkResetEnabled: boolean;
token: string;
diff --git a/ts/user.ts b/ts/user.ts
index b72b22b..e087066 100644
--- a/ts/user.ts
+++ b/ts/user.ts
@@ -7,7 +7,7 @@ import { Discord, Telegram, Matrix, ServiceConfiguration, MatrixConfiguration }
import { Validator, ValidatorConf, ValidatorRespDTO } from "./modules/validator.js";
import { PageManager } from "./modules/pages.js";
-interface userWindow extends Window {
+interface userWindow extends GlobalWindow {
jellyfinID: string;
username: string;
emailRequired: boolean;
@@ -18,14 +18,13 @@ interface userWindow extends Window {
discordInviteLink: boolean;
matrixUserID: string;
discordSendPINMessage: string;
- pwrEnabled: string;
referralsEnabled: boolean;
}
-const basePath = window.location.pathname.replace("/password/reset", "");
-
declare var window: userWindow;
+const basePath = window.location.pathname.replace("/password/reset", "");
+
const theme = new ThemeManager(document.getElementById("button-theme"));
window.lang = new lang(window.langFile as LangFile);
@@ -38,7 +37,7 @@ window.token = "";
window.modals = {} as Modals;
-let pages = new PageManager({
+const pages = new PageManager({
hideOthersOnPageShow: true,
defaultName: "",
defaultTitle: document.title,
@@ -311,7 +310,7 @@ class ReferralCard {
path = path.split(split)[0];
}
if (path.slice(-1) != "/") { path += "/"; }
- path = path + "invite/" + this._code;
+ path = path + window.pages.Form + "/" + this._code;
u.pathname = path;
u.hash = "";
@@ -661,7 +660,7 @@ document.addEventListener("details-reload", () => {
expiryCard.expiry = details.expiry;
const adminBackButton = document.getElementById("admin-back-button") as HTMLAnchorElement;
- adminBackButton.href = window.location.href.replace("my/account", "");
+ adminBackButton.href = window.pages.Base + window.pages.Admin;
let messageCard = document.getElementById("card-message");
if (details.accounts_admin) {
diff --git a/user-auth.go b/user-auth.go
index 5af2320..c80e213 100644
--- a/user-auth.go
+++ b/user-auth.go
@@ -67,7 +67,8 @@ func (app *appContext) getUserTokenLogin(gc *gin.Context) {
// host := gc.Request.URL.Hostname()
host := app.ExternalDomain
uri := "/my"
- if strings.HasPrefix(gc.Request.RequestURI, app.URLBase) {
+ // FIXME: This seems like a bad idea? I think it's to deal with people having Reverse proxy subfolder/URL base set to /accounts.
+ if strings.HasPrefix(gc.Request.RequestURI, PAGES.Base) {
uri = "/accounts/my"
}
gc.SetCookie("user-refresh", refresh, REFRESH_TOKEN_VALIDITY_SEC, uri, host, true, true)
diff --git a/views.go b/views.go
index 7542606..be574b4 100644
--- a/views.go
+++ b/views.go
@@ -32,7 +32,7 @@ func (app *appContext) loadCSSHeader() string {
l := len(css)
h := ""
for i, f := range css {
- h += "<" + app.URLBase + "/css/" + f + ">; rel=preload; as=style"
+ h += "<" + PAGES.Base + "/css/" + f + ">; rel=preload; as=style"
if l > 1 && i != (l-1) {
h += ", "
}
@@ -41,18 +41,19 @@ func (app *appContext) loadCSSHeader() string {
}
func (app *appContext) getURLBase(gc *gin.Context) string {
- if strings.HasPrefix(gc.Request.URL.String(), app.URLBase) {
+ if strings.HasPrefix(gc.Request.URL.String(), PAGES.Base) {
// Hack to fix the common URL base /accounts
- if app.URLBase == "/accounts" && strings.HasPrefix(gc.Request.URL.String(), "/accounts/user/") {
+ if PAGES.Base == "/accounts" && strings.HasPrefix(gc.Request.URL.String(), "/accounts/user/") {
return ""
}
- return app.URLBase
+ return PAGES.Base
}
return ""
}
-func gcHTML(gc *gin.Context, code int, file string, templ gin.H) {
+func (app *appContext) gcHTML(gc *gin.Context, code int, file string, page Page, templ gin.H) {
gc.Header("Cache-Control", "no-cache")
+ app.BasePageTemplateValues(gc, page, templ)
gc.HTML(code, file, templ)
}
@@ -61,16 +62,14 @@ func (app *appContext) pushResources(gc *gin.Context, page Page) {
switch page {
case AdminPage:
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"}
- break
case UserPage:
toPush = []string{"/js/user.js", "/js/theme.js", "/js/lang.js", "/js/modal.js", "/js/common.js"}
- break
default:
toPush = []string{}
}
if pusher := gc.Writer.Pusher(); pusher != nil {
for _, f := range toPush {
- if err := pusher.Push(app.URLBase+f, nil); err != nil {
+ if err := pusher.Push(PAGES.Base+f, nil); err != nil {
app.debug.Printf(lm.FailedServerPush, err)
}
}
@@ -78,6 +77,48 @@ func (app *appContext) pushResources(gc *gin.Context, page Page) {
gc.Header("Link", cssHeader)
}
+// Returns a gin.H with general values (url base, css version, etc.)
+func (app *appContext) BasePageTemplateValues(gc *gin.Context, page Page, base gin.H) {
+ set := func(k string, v any) {
+ if _, ok := base[k]; !ok {
+ base[k] = v
+ }
+ }
+
+ pages := PagePathsDTO{
+ PagePaths: PAGES,
+ }
+ pages.Base = app.getURLBase(gc)
+ switch page {
+ case AdminPage:
+ pages.Current = PAGES.Admin
+ case FormPage:
+ pages.Current = PAGES.Form
+ case UserPage:
+ pages.Current = PAGES.MyAccount
+ default:
+ pages.Current = "/"
+ }
+ set("pages", pages)
+ ombiEnabled := app.config.Section("ombi").Key("enabled").MustBool(false)
+ jellyseerrEnabled := app.config.Section("jellyseerr").Key("enabled").MustBool(false)
+ notificationsEnabled, _ := app.config.Section("notifications").Key("enabled").Bool()
+ set("notifications", notificationsEnabled)
+ set("cssClass", app.cssClass)
+ set("cssVersion", cssVersion)
+ set("emailEnabled", emailEnabled)
+ set("telegramEnabled", telegramEnabled)
+ set("discordEnabled", discordEnabled)
+ set("matrixEnabled", matrixEnabled)
+ set("ombiEnabled", ombiEnabled)
+ set("jellyseerrEnabled", jellyseerrEnabled)
+ // QUIRK: The login modal html template uses this' existence to check if the modal is for the admin or user page.
+ if page != AdminPage {
+ set("pwrEnabled", app.config.Section("password_resets").Key("enabled").MustBool(false))
+ }
+ set("referralsEnabled", app.config.Section("user_page").Key("enabled").MustBool(false) && app.config.Section("user_page").Key("referrals").MustBool(false))
+}
+
type Page int
const (
@@ -132,10 +173,6 @@ func (app *appContext) getLang(gc *gin.Context, page Page, chosen string) string
func (app *appContext) AdminPage(gc *gin.Context) {
app.pushResources(gc, AdminPage)
lang := app.getLang(gc, AdminPage, app.storage.lang.chosenAdminLang)
- emailEnabled, _ := app.config.Section("invite_emails").Key("enabled").Bool()
- notificationsEnabled, _ := app.config.Section("notifications").Key("enabled").Bool()
- ombiEnabled := app.config.Section("ombi").Key("enabled").MustBool(false)
- jellyseerrEnabled := app.config.Section("jellyseerr").Key("enabled").MustBool(false)
jfAdminOnly := app.config.Section("ui").Key("admin_only").MustBool(true)
jfAllowAll := app.config.Section("ui").Key("allow_all").MustBool(false)
var license string
@@ -157,62 +194,36 @@ func (app *appContext) AdminPage(gc *gin.Context) {
builtBy = "???"
}
- gcHTML(gc, http.StatusOK, "admin.html", gin.H{
- "urlBase": app.getURLBase(gc),
- "cssClass": app.cssClass,
- "cssVersion": cssVersion,
- "contactMessage": "",
- "emailEnabled": emailEnabled,
- "telegramEnabled": telegramEnabled,
- "discordEnabled": discordEnabled,
- "matrixEnabled": matrixEnabled,
- "ombiEnabled": ombiEnabled,
- "jellyseerrEnabled": jellyseerrEnabled,
- "linkResetEnabled": app.config.Section("password_resets").Key("link_reset").MustBool(false),
- "notifications": notificationsEnabled,
- "version": version,
- "commit": commit,
- "buildTime": buildTime,
- "builtBy": builtBy,
- "buildTags": buildTags,
- "username": !app.config.Section("email").Key("no_username").MustBool(false),
- "strings": app.storage.lang.Admin[lang].Strings,
- "quantityStrings": app.storage.lang.Admin[lang].QuantityStrings,
- "language": app.storage.lang.Admin[lang].JSON,
- "langName": lang,
- "license": license,
- "jellyfinLogin": app.jellyfinLogin,
- "jfAdminOnly": jfAdminOnly,
- "jfAllowAll": jfAllowAll,
- "userPageEnabled": app.config.Section("user_page").Key("enabled").MustBool(false),
- "showUserPageLink": app.config.Section("user_page").Key("show_link").MustBool(true),
- "referralsEnabled": app.config.Section("user_page").Key("enabled").MustBool(false) && app.config.Section("user_page").Key("referrals").MustBool(false),
- "loginAppearance": app.config.Section("ui").Key("login_appearance").MustString("clear"),
+ app.gcHTML(gc, http.StatusOK, "admin.html", AdminPage, gin.H{
+ "contactMessage": "",
+ "linkResetEnabled": app.config.Section("password_resets").Key("link_reset").MustBool(false),
+ "version": version,
+ "commit": commit,
+ "buildTime": buildTime,
+ "builtBy": builtBy,
+ "buildTags": buildTags,
+ "username": !app.config.Section("email").Key("no_username").MustBool(false),
+ "strings": app.storage.lang.Admin[lang].Strings,
+ "quantityStrings": app.storage.lang.Admin[lang].QuantityStrings,
+ "language": app.storage.lang.Admin[lang].JSON,
+ "langName": lang,
+ "license": license,
+ "jellyfinLogin": app.jellyfinLogin,
+ "jfAdminOnly": jfAdminOnly,
+ "jfAllowAll": jfAllowAll,
+ "userPageEnabled": app.config.Section("user_page").Key("enabled").MustBool(false),
+ "showUserPageLink": app.config.Section("user_page").Key("show_link").MustBool(true),
+ "loginAppearance": app.config.Section("ui").Key("login_appearance").MustString("clear"),
})
}
func (app *appContext) MyUserPage(gc *gin.Context) {
app.pushResources(gc, UserPage)
lang := app.getLang(gc, UserPage, app.storage.lang.chosenUserLang)
- emailEnabled, _ := app.config.Section("invite_emails").Key("enabled").Bool()
- notificationsEnabled, _ := app.config.Section("notifications").Key("enabled").Bool()
- ombiEnabled := app.config.Section("ombi").Key("enabled").MustBool(false)
- jellyseerrEnabled := app.config.Section("jellyseerr").Key("enabled").MustBool(false)
data := gin.H{
- "urlBase": app.getURLBase(gc),
- "cssClass": app.cssClass,
- "cssVersion": cssVersion,
"contactMessage": app.config.Section("ui").Key("contact_message").String(),
- "emailEnabled": emailEnabled,
"emailRequired": app.config.Section("email").Key("required").MustBool(false),
- "telegramEnabled": telegramEnabled,
- "discordEnabled": discordEnabled,
- "matrixEnabled": matrixEnabled,
- "ombiEnabled": ombiEnabled,
- "jellyseerrEnabled": jellyseerrEnabled,
- "pwrEnabled": app.config.Section("password_resets").Key("enabled").MustBool(false),
"linkResetEnabled": app.config.Section("password_resets").Key("link_reset").MustBool(false),
- "notifications": notificationsEnabled,
"username": !app.config.Section("email").Key("no_username").MustBool(false),
"strings": app.storage.lang.User[lang].Strings,
"validationStrings": app.storage.lang.User[lang].validationStringsJSON,
@@ -220,7 +231,6 @@ func (app *appContext) MyUserPage(gc *gin.Context) {
"langName": lang,
"jfLink": app.config.Section("ui").Key("redirect_url").String(),
"requirements": app.validator.getCriteria(),
- "referralsEnabled": app.config.Section("user_page").Key("enabled").MustBool(false) && app.config.Section("user_page").Key("referrals").MustBool(false),
}
if telegramEnabled {
data["telegramUsername"] = app.telegram.username
@@ -264,7 +274,7 @@ func (app *appContext) MyUserPage(gc *gin.Context) {
data[name+"MessageContent"] = template.HTML(markdown.ToHTML([]byte(msg.Content), nil, markdownRenderer))
}
- gcHTML(gc, http.StatusOK, "user.html", data)
+ app.gcHTML(gc, http.StatusOK, "user.html", UserPage, data)
}
func (app *appContext) ResetPassword(gc *gin.Context) {
@@ -278,14 +288,9 @@ func (app *appContext) ResetPassword(gc *gin.Context) {
app.pushResources(gc, PWRPage)
lang := app.getLang(gc, PWRPage, app.storage.lang.chosenPWRLang)
data := gin.H{
- "urlBase": app.getURLBase(gc),
- "cssClass": app.cssClass,
- "cssVersion": cssVersion,
"contactMessage": app.config.Section("ui").Key("contact_message").String(),
"strings": app.storage.lang.PasswordReset[lang].Strings,
"success": false,
- "ombiEnabled": app.config.Section("ombi").Key("enabled").MustBool(false),
- "jellyseerrEnabled": app.config.Section("jellyseerr").Key("enabled").MustBool(false),
"customSuccessCard": false,
}
pwr, isInternal := app.internalPWRs[pin]
@@ -299,6 +304,7 @@ func (app *appContext) ResetPassword(gc *gin.Context) {
data["requirements"] = app.validator.getCriteria()
data["strings"] = app.storage.lang.PasswordReset[lang].Strings
data["validationStrings"] = app.storage.lang.User[lang].validationStringsJSON
+ // ewwwww, reusing an existing field, FIXME!
data["notifications"] = app.storage.lang.User[lang].notificationsJSON
data["langName"] = lang
data["passwordReset"] = true
@@ -309,10 +315,10 @@ func (app *appContext) ResetPassword(gc *gin.Context) {
data["reCAPTCHA"] = app.config.Section("captcha").Key("recaptcha").MustBool(false)
data["reCAPTCHASiteKey"] = app.config.Section("captcha").Key("recaptcha_site_key").MustString("")
data["pwrPIN"] = pin
- gcHTML(gc, http.StatusOK, "form-loader.html", data)
+ app.gcHTML(gc, http.StatusOK, "form-loader.html", PWRPage, data)
return
}
- defer gcHTML(gc, http.StatusOK, "password-reset.html", data)
+ defer app.gcHTML(gc, http.StatusOK, "password-reset.html", PWRPage, data)
// If it's a bot, pretend to be a success so the preview is nice.
if isBot {
app.debug.Println(lm.IgnoreBotPWR)
@@ -413,10 +419,7 @@ func (app *appContext) GetCaptcha(gc *gin.Context) {
if !isPWR {
inv, ok = app.storage.GetInvitesKey(code)
if !ok {
- gcHTML(gc, 404, "invalidCode.html", gin.H{
- "urlBase": app.getURLBase(gc),
- "cssClass": app.cssClass,
- "cssVersion": cssVersion,
+ app.gcHTML(gc, 404, "invalidCode.html", OtherPage, gin.H{
"contactMessage": app.config.Section("ui").Key("contact_message").String(),
})
}
@@ -453,10 +456,7 @@ func (app *appContext) GenCaptcha(gc *gin.Context) {
}
if !ok {
- gcHTML(gc, 404, "invalidCode.html", gin.H{
- "urlBase": app.getURLBase(gc),
- "cssClass": app.cssClass,
- "cssVersion": cssVersion,
+ app.gcHTML(gc, 404, "invalidCode.html", OtherPage, gin.H{
"contactMessage": app.config.Section("ui").Key("contact_message").String(),
})
}
@@ -587,10 +587,7 @@ func (app *appContext) VerifyCaptcha(gc *gin.Context) {
if !isPWR {
inv, ok = app.storage.GetInvitesKey(code)
if !ok {
- gcHTML(gc, 404, "invalidCode.html", gin.H{
- "urlBase": app.getURLBase(gc),
- "cssClass": app.cssClass,
- "cssVersion": cssVersion,
+ app.gcHTML(gc, 404, "invalidCode.html", OtherPage, gin.H{
"contactMessage": app.config.Section("ui").Key("contact_message").String(),
})
return
@@ -617,10 +614,7 @@ func (app *appContext) VerifyCaptcha(gc *gin.Context) {
func (app *appContext) NewUserFromConfirmationKey(invite Invite, key string, lang string, gc *gin.Context) {
fail := func() {
- gcHTML(gc, 404, "404.html", gin.H{
- "urlBase": app.getURLBase(gc),
- "cssClass": app.cssClass,
- "cssVersion": cssVersion,
+ app.gcHTML(gc, 404, "404.html", OtherPage, gin.H{
"contactMessage": app.config.Section("ui").Key("contact_message").String(),
})
}
@@ -691,10 +685,7 @@ func (app *appContext) NewUserFromConfirmationKey(invite Invite, key string, lan
if app.config.Section("ui").Key("auto_redirect").MustBool(false) {
gc.Redirect(301, jfLink)
} else {
- gcHTML(gc, http.StatusOK, "create-success.html", gin.H{
- "urlBase": app.getURLBase(gc),
- "cssClass": app.cssClass,
- "cssVersion": cssVersion,
+ app.gcHTML(gc, http.StatusOK, "create-success.html", OtherPage, gin.H{
"strings": app.storage.lang.User[lang].Strings,
"successMessage": app.config.Section("ui").Key("success_message").String(),
"contactMessage": app.config.Section("ui").Key("contact_message").String(),
@@ -725,10 +716,7 @@ func (app *appContext) InviteProxy(gc *gin.Context) {
// if app.checkInvite(code, false, "") {
invite, ok := app.storage.GetInvitesKey(gc.Param("invCode"))
if !ok {
- gcHTML(gc, 404, "invalidCode.html", gin.H{
- "urlBase": app.getURLBase(gc),
- "cssClass": app.cssClass,
- "cssVersion": cssVersion,
+ app.gcHTML(gc, 404, "invalidCode.html", FormPage, gin.H{
"contactMessage": app.config.Section("ui").Key("contact_message").String(),
})
return
@@ -747,7 +735,7 @@ func (app *appContext) InviteProxy(gc *gin.Context) {
discord := discordEnabled && app.config.Section("discord").Key("show_on_reg").MustBool(true)
matrix := matrixEnabled && app.config.Section("matrix").Key("show_on_reg").MustBool(true)
- userPageAddress := fmt.Sprintf("%s/my/account", app.ExternalURI)
+ userPageAddress := app.ExternalURI + PAGES.MyAccount
fromUser := ""
if invite.ReferrerJellyfinID != "" {
@@ -758,9 +746,6 @@ func (app *appContext) InviteProxy(gc *gin.Context) {
}
data := gin.H{
- "urlBase": app.getURLBase(gc),
- "cssClass": app.cssClass,
- "cssVersion": cssVersion,
"contactMessage": app.config.Section("ui").Key("contact_message").String(),
"helpMessage": app.config.Section("ui").Key("help_message").String(),
"successMessage": app.config.Section("ui").Key("success_message").String(),
@@ -772,28 +757,29 @@ func (app *appContext) InviteProxy(gc *gin.Context) {
"username": !app.config.Section("email").Key("no_username").MustBool(false),
"strings": app.storage.lang.User[lang].Strings,
"validationStrings": app.storage.lang.User[lang].validationStringsJSON,
- "notifications": app.storage.lang.User[lang].notificationsJSON,
- "code": invite.Code,
- "confirmation": app.config.Section("email_confirmation").Key("enabled").MustBool(false),
- "userExpiry": invite.UserExpiry,
- "userExpiryMonths": invite.UserMonths,
- "userExpiryDays": invite.UserDays,
- "userExpiryHours": invite.UserHours,
- "userExpiryMinutes": invite.UserMinutes,
- "userExpiryMessage": app.storage.lang.User[lang].Strings.get("yourAccountIsValidUntil"),
- "langName": lang,
- "passwordReset": false,
- "customSuccessCard": false,
- "telegramEnabled": telegram,
- "discordEnabled": discord,
- "matrixEnabled": matrix,
- "emailRequired": app.config.Section("email").Key("required").MustBool(false),
- "captcha": app.config.Section("captcha").Key("enabled").MustBool(false),
- "reCAPTCHA": app.config.Section("captcha").Key("recaptcha").MustBool(false),
- "reCAPTCHASiteKey": app.config.Section("captcha").Key("recaptcha_site_key").MustString(""),
- "userPageEnabled": app.config.Section("user_page").Key("enabled").MustBool(false),
- "userPageAddress": userPageAddress,
- "fromUser": fromUser,
+ // ewwwww, reusing an existing field, FIXME!
+ "notifications": app.storage.lang.User[lang].notificationsJSON,
+ "code": invite.Code,
+ "confirmation": app.config.Section("email_confirmation").Key("enabled").MustBool(false),
+ "userExpiry": invite.UserExpiry,
+ "userExpiryMonths": invite.UserMonths,
+ "userExpiryDays": invite.UserDays,
+ "userExpiryHours": invite.UserHours,
+ "userExpiryMinutes": invite.UserMinutes,
+ "userExpiryMessage": app.storage.lang.User[lang].Strings.get("yourAccountIsValidUntil"),
+ "langName": lang,
+ "passwordReset": false,
+ "customSuccessCard": false,
+ "telegramEnabled": telegram,
+ "discordEnabled": discord,
+ "matrixEnabled": matrix,
+ "emailRequired": app.config.Section("email").Key("required").MustBool(false),
+ "captcha": app.config.Section("captcha").Key("enabled").MustBool(false),
+ "reCAPTCHA": app.config.Section("captcha").Key("recaptcha").MustBool(false),
+ "reCAPTCHASiteKey": app.config.Section("captcha").Key("recaptcha_site_key").MustString(""),
+ "userPageEnabled": app.config.Section("user_page").Key("enabled").MustBool(false),
+ "userPageAddress": userPageAddress,
+ "fromUser": fromUser,
}
if telegram {
data["telegramPIN"] = app.telegram.NewAuthToken()
@@ -837,15 +823,12 @@ func (app *appContext) InviteProxy(gc *gin.Context) {
// pin := ""
// for _, token := range app.discord.tokens {
// if
- gcHTML(gc, http.StatusOK, "form-loader.html", data)
+ app.gcHTML(gc, http.StatusOK, "form-loader.html", OtherPage, data)
}
func (app *appContext) NoRouteHandler(gc *gin.Context) {
app.pushResources(gc, OtherPage)
- gcHTML(gc, 404, "404.html", gin.H{
- "urlBase": app.getURLBase(gc),
- "cssClass": app.cssClass,
- "cssVersion": cssVersion,
+ app.gcHTML(gc, 404, "404.html", OtherPage, gin.H{
"contactMessage": app.config.Section("ui").Key("contact_message").String(),
})
}