add updates section to setup

This commit is contained in:
Harvey Tindall 2021-03-20 18:00:01 +00:00
parent cd67d3e7ab
commit de92516d52
Signed by: hrfee
GPG Key ID: BBC65952848FB1A2
7 changed files with 67 additions and 29 deletions

View File

@ -82,6 +82,20 @@
<span class="mt-half">{{ .lang.General.pathToKeyFile }}</span>
<input type="text" class="input ~neutral !normal mt-half mb-1" id="advanced-tls_key">
</label>
<span class="heading">{{ .lang.Updates.title }}</span>
<p class="content" id="updates-description"></p>
<label class="row switch pb-1">
<input type="checkbox" id="updates-enabled" checked><span>{{ .lang.Strings.enabled }}</span>
</label>
<label class="label">
<span>{{ .lang.Updates.updateChannel }}</span>
<div class="select ~neutral !normal mt-half mb-1">
<select id="updates-channel">
<option value="stable">{{ .lang.Updates.stable }}</option>
<option value="unstable">{{ .lang.Updates.unstable }}</option>
</select>
</div>
</label>
</div>
<div class="col">
<label class="label">

View File

@ -94,6 +94,7 @@ type setupLang struct {
StartPage langSection `json:"startPage"`
EndPage langSection `json:"endPage"`
General langSection `json:"general"`
Updates langSection `json:"updates"`
Language langSection `json:"language"`
Login langSection `json:"login"`
JellyfinEmby langSection `json:"jellyfinEmby"`

View File

@ -48,6 +48,13 @@
"pathToCertificate": "Path to certificate",
"pathToKeyFile": "Path to key file"
},
"updates": {
"title": "Updates",
"description": "Enable to be notified when new updates are available. jfa-go will check {n} every 30 minutes. No IPs or personally identifiable information are collected.",
"updateChannel": "Update Channel",
"stable": "Stable",
"unstable": "Unstable"
},
"login": {
"title": "Login",
"description": "To access the admin page, you need to login with a method below:",

64
main.go
View File

@ -152,7 +152,8 @@ func start(asDaemon, firstCall bool) {
set default config and data paths
data: Contains invites.json, emails.json, user_profile.json, etc.
config: config.ini. Usually in data, but can be changed via -config.
localFS is jfa-go's internal data. On external builds, the directory is named "data" and placed next to the executable.
localFS: jfa-go's internal data. On internal builds, this is contained within the binary.
On external builds, the directory is named "data" and placed next to the executable.
*/
userConfigDir, _ := os.UserConfigDir()
app.dataPath = filepath.Join(userConfigDir, "jfa-go")
@ -164,7 +165,7 @@ func start(asDaemon, firstCall bool) {
}
app.info = NewLogger(os.Stdout, "[INFO] ", log.Ltime, color.FgHiWhite)
app.err = NewLogger(os.Stdout, "[ERROR] ", log.Ltime|log.Lshortfile, color.FgRed)
app.err = NewLogger(os.Stdout, "[ERROR] ", log.Ltime, color.FgRed)
if firstCall {
DATA = flag.String("data", app.dataPath, "alternate path to data directory.")
@ -200,8 +201,7 @@ func start(asDaemon, firstCall bool) {
app.dataPath = *DATA
}
// env variables are necessary because syscall.Exec for self-restarts doesn't doesn't work with arguments for some reason.
// Previously used for self-restarts but leaving them here as they might be useful.
if v := os.Getenv("JFA_CONFIGPATH"); v != "" {
app.configPath = v
}
@ -254,6 +254,7 @@ func start(asDaemon, firstCall bool) {
app.debug = emptyLogger(false)
}
// Starts listener to receive commands over a unix socket. Use with 'jfa-go start/stop'
if asDaemon {
go func() {
socket := SOCK
@ -384,6 +385,7 @@ func start(asDaemon, firstCall bool) {
}
// Read config-base for settings on web.
app.configBasePath = "config-base.json"
configBase, _ := fs.ReadFile(localFS, app.configBasePath)
json.Unmarshal(configBase, &app.configBase)
@ -392,6 +394,7 @@ func start(asDaemon, firstCall bool) {
"Jellyfin (Dark)": "dark-theme",
"Default (Light)": "light-theme",
}
// For move from Bootstrap to a17t
if app.config.Section("ui").Key("theme").String() == "Bootstrap (Light)" {
app.config.Section("ui").Key("theme").SetValue("Default (Light)")
}
@ -403,18 +406,8 @@ func start(asDaemon, firstCall bool) {
app.err.Fatal(err)
}
os.Setenv("JFA_SECRET", secret)
app.jellyfinLogin = true
if val, _ := app.config.Section("ui").Key("jellyfin_login").Bool(); !val {
app.jellyfinLogin = false
user := User{}
user.UserID = shortuuid.New()
user.Username = app.config.Section("ui").Key("username").String()
user.Password = app.config.Section("ui").Key("password").String()
app.users = append(app.users, user)
} else {
app.debug.Println("Using Jellyfin for authentication")
}
// Initialize jellyfin/emby connection
server := app.config.Section("jellyfin").Key("server").String()
cacheTimeout := int(app.config.Section("jellyfin").Key("cache_timeout").MustUint(30))
stringServerType := app.config.Section("jellyfin").Key("type").String()
@ -444,7 +437,8 @@ func start(asDaemon, firstCall bool) {
app.err.Fatalf("Failed to authenticate with Jellyfin @ %s: Code %d", server, status)
}
app.info.Printf("Authenticated with %s", server)
// from 10.7.0, jellyfin may hyphenate user IDs. This checks if the version is equal or higher.
/* A couple of unstable Jellyfin 10.7.0 releases decided to hyphenate user IDs.
This checks if the version is equal or higher. */
checkVersion := func(version string) int {
numberStrings := strings.Split(version, ".")
n := 0
@ -498,27 +492,40 @@ func start(asDaemon, firstCall bool) {
}
}
// Auth (manual user/pass or jellyfin)
app.jellyfinLogin = true
if jfLogin, _ := app.config.Section("ui").Key("jellyfin_login").Bool(); !jfLogin {
app.jellyfinLogin = false
user := User{}
user.UserID = shortuuid.New()
user.Username = app.config.Section("ui").Key("username").String()
user.Password = app.config.Section("ui").Key("password").String()
app.users = append(app.users, user)
} else {
app.debug.Println("Using Jellyfin for authentication")
app.authJf, _ = mediabrowser.NewServer(serverType, server, "jfa-go", app.version, "auth", "auth", timeoutHandler, cacheTimeout)
}
// Since email depends on language, the email reload in loadConfig won't work first time.
app.email = NewEmailer(app)
app.authJf, _ = mediabrowser.NewServer(serverType, server, "jfa-go", app.version, "auth", "auth", timeoutHandler, cacheTimeout)
app.loadStrftime()
validatorConf := ValidatorConf{
"length": app.config.Section("password_validation").Key("min_length").MustInt(0),
"uppercase": app.config.Section("password_validation").Key("upper").MustInt(0),
"lowercase": app.config.Section("password_validation").Key("lower").MustInt(0),
"number": app.config.Section("password_validation").Key("number").MustInt(0),
"special": app.config.Section("password_validation").Key("special").MustInt(0),
}
var validatorConf ValidatorConf
if !app.config.Section("password_validation").Key("enabled").MustBool(false) {
for key := range validatorConf {
validatorConf[key] = 0
validatorConf = ValidatorConf{}
} else {
validatorConf = ValidatorConf{
"length": app.config.Section("password_validation").Key("min_length").MustInt(0),
"uppercase": app.config.Section("password_validation").Key("upper").MustInt(0),
"lowercase": app.config.Section("password_validation").Key("lower").MustInt(0),
"number": app.config.Section("password_validation").Key("number").MustInt(0),
"special": app.config.Section("password_validation").Key("special").MustInt(0),
}
}
app.validator.init(validatorConf)
// Test mode for testing connection to Jellyfin, accessed with 'jfa-go test'
if TEST {
test(app)
os.Exit(0)
@ -546,6 +553,7 @@ func start(asDaemon, firstCall bool) {
app.info.Fatalf("Failed to load language files: %+v\n", err)
}
}
cssHeader = app.loadCSSHeader()
// workaround for potentially broken windows mime types
mime.AddExtensionType(".js", "application/javascript")

View File

@ -89,6 +89,7 @@ func (st *Storage) loadLangSetup(filesystems ...fs.FS) error {
if fname != "en-us.json" {
patchLang(&english.Strings, &lang.Strings)
patchLang(&english.StartPage, &lang.StartPage)
patchLang(&english.Updates, &lang.Updates)
patchLang(&english.EndPage, &lang.EndPage)
patchLang(&english.Language, &lang.Language)
patchLang(&english.Login, &lang.Login)

View File

@ -173,7 +173,9 @@ class Select {
if (depends) {
document.addEventListener(`settings-${section}-${depends}`, (event: boolEvent) => {
let el = this._el as HTMLElement;
if (el.parentElement.tagName == "LABEL") { el = el.parentElement; }
while (el.tagName != "LABEL") {
el = el.parentElement;
}
if (event.detail !== dependsTrue) {
el.classList.add("unfocused");
} else {
@ -202,6 +204,7 @@ window.lang = new lang(window.langFile as LangFile);
html("language-description", window.lang.var("language", "description", `<a href="https://weblate.hrfee.pw">Weblate</a>`));
html("email-description", window.lang.var("email", "description", `<a href="https://mailgun.com">Mailgun</a>`));
html("email-dateformat-notice", window.lang.var("email", "dateFormatNotice", `<a href="https://strftime.ninja/">strftime.ninja</a>`));
html("updates-description", window.lang.var("updates", "description", `<a href="https://builds.hrfee.dev/view/hrfee/jfa-go">buildrone</a>`));
const settings = {
"jellyfin": {
@ -212,6 +215,10 @@ const settings = {
"password": new Input(get("jellyfin-password")),
"substitute_jellyfin_strings": new Input(get("jellyfin-substitute_jellyfin_strings"))
},
"updates": {
"enabled": new Checkbox(get("updates-enabled"), "", false, "updates", "enabled"),
"channel": new Select(get("updates-channel"), "enabled", true, "updates")
},
"ui": {
"host": new Input(get("ui-host")),
"port": new Input(get("ui-port")),