mirror of
https://github.com/hrfee/jfa-go.git
synced 2024-12-26 19:10:10 +00:00
Compare commits
16 Commits
fcdd4e4518
...
a11ac1b1a3
Author | SHA1 | Date | |
---|---|---|---|
a11ac1b1a3 | |||
73197df8d9 | |||
a492c06077 | |||
bc66f46d9e | |||
eefd350754 | |||
|
494b8b2399 | ||
|
e901ba6bb5 | ||
|
4455c15bca | ||
|
c2bdc67242 | ||
37545e1e36 | |||
|
19495be6e9 | ||
37a062e24d | |||
a4c60c71ea | |||
9e9f46d97b | |||
f063b970b4 | |||
711b817cff |
@ -116,7 +116,7 @@ archives:
|
||||
checksum:
|
||||
name_template: 'checksums.txt'
|
||||
snapshot:
|
||||
name_template: "0.0.0-{{ .Env.JFA_GO_NFPM_EPOCH }}"
|
||||
version_template: "0.0.0-{{ .Env.JFA_GO_NFPM_EPOCH }}"
|
||||
changelog:
|
||||
sort: asc
|
||||
filters:
|
||||
|
43
Makefile
43
Makefile
@ -1,4 +1,4 @@
|
||||
.PHONY: configuration email typescript swagger copy compile compress tailwind bundle-css inline-css variants-html install clean npm config-description config-default precompile
|
||||
.PHONY: configuration email typescript swagger copy compile compress inline-css variants-html install clean npm config-description config-default precompile
|
||||
|
||||
all: compile
|
||||
|
||||
@ -101,20 +101,22 @@ else
|
||||
SWAGINSTALL :=
|
||||
endif
|
||||
|
||||
CONFIG_BASE = config/config-base.json
|
||||
CONFIG_BASE = config/config-base.yaml
|
||||
|
||||
CONFIG_DESCRIPTION = $(DATA)/config-base.json
|
||||
# CONFIG_DESCRIPTION = $(DATA)/config-base.json
|
||||
CONFIG_DEFAULT = $(DATA)/config-default.ini
|
||||
$(CONFIG_DESCRIPTION) &: $(CONFIG_BASE)
|
||||
$(info Fixing config-base)
|
||||
-mkdir -p $(DATA)
|
||||
python3 scripts/enumerate_config.py -i config/config-base.json -o $(DATA)/config-base.json
|
||||
# $(CONFIG_DESCRIPTION) &: $(CONFIG_BASE)
|
||||
# $(info Fixing config-base)
|
||||
# -mkdir -p $(DATA)
|
||||
|
||||
$(CONFIG_DEFAULT) &: $(CONFIG_BASE)
|
||||
$(DATA):
|
||||
mkdir -p $(DATA)
|
||||
|
||||
$(CONFIG_DEFAULT): $(DATA) $(CONFIG_BASE)
|
||||
$(info Generating config-default.ini)
|
||||
python3 scripts/generate_ini.py -i config/config-base.json -o $(DATA)/config-default.ini
|
||||
go run scripts/ini/main.go -in $(CONFIG_BASE) -out $(DATA)/config-default.ini
|
||||
|
||||
configuration: $(CONFIG_DESCRIPTION) $(CONFIG_DEFAULT)
|
||||
configuration: $(CONFIG_DEFAULT)
|
||||
|
||||
EMAIL_SRC_MJML = $(wildcard mail/*.mjml)
|
||||
EMAIL_SRC_TXT = $(wildcard mail/*.txt)
|
||||
@ -125,7 +127,9 @@ EMAIL_ALL = $(EMAIL_HTML) $(EMAIL_TXT)
|
||||
EMAIL_TARGET = mail/confirmation.html
|
||||
$(EMAIL_TARGET): $(EMAIL_SRC_MJML) $(EMAIL_SRC_TXT)
|
||||
$(info Generating email html)
|
||||
python3 scripts/compile_mjml.py -o $(DATA)/
|
||||
npx mjml mail/*.mjml -o $(DATA)/
|
||||
$(info Copying plaintext mail)
|
||||
cp mail/*.txt $(DATA)/
|
||||
|
||||
TYPESCRIPT_FULLSRC = $(shell find ts/ -type f -name "*.ts")
|
||||
TYPESCRIPT_SRC = $(wildcard ts/*.ts)
|
||||
@ -179,8 +183,6 @@ $(CSS_FULLTARGET): $(TYPESCRIPT_TARGET) $(VARIANTS_TARGET) $(ALL_CSS_SRC) $(wild
|
||||
# mv $(CSS_BUNDLE) $(DATA)/web/css/$(CSSVERSION)bundle.css
|
||||
# npx postcss -o $(CSS_TARGET) $(CSS_TARGET)
|
||||
|
||||
bundle-css: tailwind
|
||||
|
||||
INLINE_SRC = html/crash.html
|
||||
INLINE_TARGET = $(DATA)/crash.html
|
||||
$(INLINE_TARGET): $(CSS_FULLTARGET) $(INLINE_SRC)
|
||||
@ -197,6 +199,8 @@ COPY_SRC = images/banner.svg jfa-go.service LICENSE $(LANG_SRC) $(STATIC_SRC)
|
||||
COPY_TARGET = $(DATA)/jfa-go.service
|
||||
# $(DATA)/LICENSE $(LANG_TARGET) $(STATIC_TARGET) $(DATA)/web/css/$(CSSVERSION)bundle.css
|
||||
$(COPY_TARGET): $(INLINE_TARGET) $(STATIC_SRC) $(LANG_SRC)
|
||||
$(info copying $(CONFIG_BASE))
|
||||
cp $(CONFIG_BASE) $(DATA)/
|
||||
$(info copying crash page)
|
||||
cp $(DATA)/crash.html $(DATA)/html/
|
||||
$(info copying static data)
|
||||
@ -209,11 +213,11 @@ $(COPY_TARGET): $(INLINE_TARGET) $(STATIC_SRC) $(LANG_SRC)
|
||||
cp -r lang $(DATA)/
|
||||
cp LICENSE $(DATA)/
|
||||
|
||||
precompile: $(CONFIG_DESCRIPTION) $(CONFIG_DEFAULT) $(EMAIL_TARGET) $(COPY_TARGET) $(SWAGGER_TARGET)
|
||||
precompile: $(CONFIG_DEFAULT) $(EMAIL_TARGET) $(COPY_TARGET) $(SWAGGER_TARGET)
|
||||
|
||||
GO_SRC = $(shell find ./ -name "*.go")
|
||||
GO_TARGET = build/jfa-go
|
||||
$(GO_TARGET): $(CONFIG_DESCRIPTION) $(CONFIG_DEFAULT) $(EMAIL_TARGET) $(COPY_TARGET) $(SWAGGER_TARGET) $(GO_SRC) go.mod go.sum
|
||||
$(GO_TARGET): $(CONFIG_DEFAULT) $(EMAIL_TARGET) $(COPY_TARGET) $(SWAGGER_TARGET) $(GO_SRC) go.mod go.sum
|
||||
$(info Downloading deps)
|
||||
$(GOBINARY) mod download
|
||||
$(info Building)
|
||||
@ -225,15 +229,6 @@ compile: $(GO_TARGET)
|
||||
compress:
|
||||
upx --lzma build/jfa-go
|
||||
|
||||
# internal-files:
|
||||
# python3 scripts/embed.py internal
|
||||
#
|
||||
# external-files:
|
||||
# python3 scripts/embed.py external
|
||||
# -mkdir -p build
|
||||
# $(info copying internal data into build/)
|
||||
# cp -r data build/
|
||||
|
||||
install:
|
||||
cp -r build $(DESTDIR)/jfa-go
|
||||
|
||||
|
153
api.go
153
api.go
@ -6,6 +6,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/hrfee/jfa-go/common"
|
||||
lm "github.com/hrfee/jfa-go/logmessages"
|
||||
"github.com/hrfee/mediabrowser"
|
||||
"github.com/itchyny/timefmt-go"
|
||||
@ -229,102 +230,15 @@ func (app *appContext) ResetSetPassword(gc *gin.Context) {
|
||||
|
||||
// @Summary Get jfa-go configuration.
|
||||
// @Produce json
|
||||
// @Success 200 {object} settings "Uses the same format as config-base.json"
|
||||
// @Success 200 {object} common.Config "Uses the same format as config-base.json"
|
||||
// @Router /config [get]
|
||||
// @Security Bearer
|
||||
// @tags Configuration
|
||||
func (app *appContext) GetConfig(gc *gin.Context) {
|
||||
resp := app.configBase
|
||||
// Load language options
|
||||
formOptions := app.storage.lang.User.getOptions()
|
||||
fl := resp.Sections["ui"].Settings["language-form"]
|
||||
fl.Options = formOptions
|
||||
fl.Value = app.config.Section("ui").Key("language-form").MustString("en-us")
|
||||
pwrOptions := app.storage.lang.PasswordReset.getOptions()
|
||||
pl := resp.Sections["password_resets"].Settings["language"]
|
||||
pl.Options = pwrOptions
|
||||
pl.Value = app.config.Section("password_resets").Key("language").MustString("en-us")
|
||||
adminOptions := app.storage.lang.Admin.getOptions()
|
||||
al := resp.Sections["ui"].Settings["language-admin"]
|
||||
al.Options = adminOptions
|
||||
al.Value = app.config.Section("ui").Key("language-admin").MustString("en-us")
|
||||
emailOptions := app.storage.lang.Email.getOptions()
|
||||
el := resp.Sections["email"].Settings["language"]
|
||||
el.Options = emailOptions
|
||||
el.Value = app.config.Section("email").Key("language").MustString("en-us")
|
||||
telegramOptions := app.storage.lang.Email.getOptions()
|
||||
tl := resp.Sections["telegram"].Settings["language"]
|
||||
tl.Options = telegramOptions
|
||||
tl.Value = app.config.Section("telegram").Key("language").MustString("en-us")
|
||||
if updater == "" {
|
||||
delete(resp.Sections, "updates")
|
||||
for i, v := range resp.Order {
|
||||
if v == "updates" {
|
||||
resp.Order = append(resp.Order[:i], resp.Order[i+1:]...)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
if PLATFORM == "windows" {
|
||||
delete(resp.Sections["smtp"].Settings, "ssl_cert")
|
||||
for i, v := range resp.Sections["smtp"].Order {
|
||||
if v == "ssl_cert" {
|
||||
sect := resp.Sections["smtp"]
|
||||
sect.Order = append(sect.Order[:i], sect.Order[i+1:]...)
|
||||
resp.Sections["smtp"] = sect
|
||||
}
|
||||
}
|
||||
}
|
||||
if !MatrixE2EE() {
|
||||
delete(resp.Sections["matrix"].Settings, "encryption")
|
||||
for i, v := range resp.Sections["matrix"].Order {
|
||||
if v == "encryption" {
|
||||
sect := resp.Sections["matrix"]
|
||||
sect.Order = append(sect.Order[:i], sect.Order[i+1:]...)
|
||||
resp.Sections["matrix"] = sect
|
||||
}
|
||||
}
|
||||
}
|
||||
for sectName, section := range resp.Sections {
|
||||
for settingName, setting := range section.Settings {
|
||||
val := app.config.Section(sectName).Key(settingName)
|
||||
s := resp.Sections[sectName].Settings[settingName]
|
||||
switch setting.Type {
|
||||
case "list":
|
||||
s.Value = val.StringsWithShadows("|")
|
||||
case "text", "email", "select", "password", "note":
|
||||
s.Value = val.MustString("")
|
||||
case "number":
|
||||
s.Value = val.MustInt(0)
|
||||
case "bool":
|
||||
s.Value = val.MustBool(false)
|
||||
}
|
||||
resp.Sections[sectName].Settings[settingName] = s
|
||||
}
|
||||
}
|
||||
if discordEnabled {
|
||||
r, err := app.discord.ListRoles()
|
||||
if err == nil {
|
||||
roles := make([][2]string, len(r)+1)
|
||||
roles[0] = [2]string{"", "None"}
|
||||
for i, role := range r {
|
||||
roles[i+1] = role
|
||||
}
|
||||
s := resp.Sections["discord"].Settings["apply_role"]
|
||||
s.Options = roles
|
||||
resp.Sections["discord"].Settings["apply_role"] = s
|
||||
}
|
||||
app.PatchConfigDiscordRoles()
|
||||
}
|
||||
|
||||
resp.Sections["ui"].Settings["language-form"] = fl
|
||||
resp.Sections["ui"].Settings["language-admin"] = al
|
||||
resp.Sections["email"].Settings["language"] = el
|
||||
resp.Sections["password_resets"].Settings["language"] = pl
|
||||
resp.Sections["telegram"].Settings["language"] = tl
|
||||
resp.Sections["discord"].Settings["language"] = tl
|
||||
resp.Sections["matrix"].Settings["language"] = tl
|
||||
|
||||
gc.JSON(200, resp)
|
||||
gc.JSON(200, app.patchedConfig)
|
||||
}
|
||||
|
||||
// @Summary Modify app config.
|
||||
@ -340,35 +254,46 @@ func (app *appContext) ModifyConfig(gc *gin.Context) {
|
||||
gc.BindJSON(&req)
|
||||
// Load a new config, as we set various default values in app.config that shouldn't be stored.
|
||||
tempConfig, _ := ini.ShadowLoad(app.configPath)
|
||||
for section, settings := range req {
|
||||
if section != "restart-program" {
|
||||
_, err := tempConfig.GetSection(section)
|
||||
if err != nil {
|
||||
tempConfig.NewSection(section)
|
||||
for _, section := range app.configBase.Sections {
|
||||
ns, ok := req[section.Section]
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
newSection := ns.(map[string]any)
|
||||
iniSection, err := tempConfig.GetSection(section.Section)
|
||||
if err != nil {
|
||||
iniSection, _ = tempConfig.NewSection(section.Section)
|
||||
}
|
||||
for _, setting := range section.Settings {
|
||||
newValue, ok := newSection[setting.Setting]
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
for setting, value := range settings.(map[string]interface{}) {
|
||||
if section == "email" && setting == "method" && value == "disabled" {
|
||||
value = ""
|
||||
}
|
||||
if (section == "discord" || section == "matrix") && setting == "language" {
|
||||
tempConfig.Section("telegram").Key("language").SetValue(value.(string))
|
||||
} else if app.configBase.Sections[section].Settings[setting].Type == "list" {
|
||||
splitValues := strings.Split(value.(string), "|")
|
||||
// Delete the key first to get rid of any shadow values
|
||||
tempConfig.Section(section).DeleteKey(setting)
|
||||
for i, v := range splitValues {
|
||||
if i == 0 {
|
||||
tempConfig.Section(section).Key(setting).SetValue(v)
|
||||
} else {
|
||||
tempConfig.Section(section).Key(setting).AddShadow(v)
|
||||
}
|
||||
// Patch disabled to actually be an empty string
|
||||
if section.Section == "email" && setting.Setting == "method" && newValue == "disabled" {
|
||||
newValue = ""
|
||||
}
|
||||
// Copy language preference for chatbots to root one in "telegram"
|
||||
if (section.Section == "discord" || section.Section == "matrix") && setting.Setting == "language" {
|
||||
iniSection.Key("language").SetValue(newValue.(string))
|
||||
} else if setting.Type == common.ListType {
|
||||
splitValues := strings.Split(newValue.(string), "|")
|
||||
// Delete the key first to get rid of any shadow values
|
||||
iniSection.DeleteKey(setting.Setting)
|
||||
for i, v := range splitValues {
|
||||
if i == 0 {
|
||||
iniSection.Key(setting.Setting).SetValue(v)
|
||||
} else {
|
||||
iniSection.Key(setting.Setting).AddShadow(v)
|
||||
}
|
||||
} else if value.(string) != app.config.Section(section).Key(setting).MustString("") {
|
||||
tempConfig.Section(section).Key(setting).SetValue(value.(string))
|
||||
}
|
||||
|
||||
} else if newValue.(string) != iniSection.Key(setting.Setting).MustString("") {
|
||||
iniSection.Key(setting.Setting).SetValue(newValue.(string))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tempConfig.Section("").Key("first_run").SetValue("false")
|
||||
if err := tempConfig.SaveTo(app.configPath); err != nil {
|
||||
app.err.Printf(lm.FailedWriting, app.configPath, err)
|
||||
@ -381,6 +306,8 @@ func (app *appContext) ModifyConfig(gc *gin.Context) {
|
||||
app.Restart()
|
||||
}
|
||||
app.loadConfig()
|
||||
// Patch new settings for next GetConfig
|
||||
app.PatchConfigBase()
|
||||
// Reinitialize password validator on config change, as opposed to every applicable request like in python.
|
||||
if _, ok := req["password_validation"]; ok {
|
||||
validatorConf := ValidatorConf{
|
||||
|
1
auth.go
1
auth.go
@ -251,6 +251,7 @@ func (app *appContext) getTokenLogin(gc *gin.Context) {
|
||||
// host := gc.Request.URL.Hostname()
|
||||
host := app.ExternalDomain
|
||||
|
||||
// Before you think this is broken: the first "true" arg is for "secure", i.e. only HTTPS!
|
||||
gc.SetCookie("refresh", refresh, REFRESH_TOKEN_VALIDITY_SEC, "/", host, true, true)
|
||||
gc.JSON(200, getTokenDTO{token})
|
||||
}
|
||||
|
62
common/config.go
Normal file
62
common/config.go
Normal file
@ -0,0 +1,62 @@
|
||||
package common
|
||||
|
||||
type SectionMeta struct {
|
||||
Name string `json:"name" yaml:"name" example:"My Section"` // friendly name of the section
|
||||
Description string `json:"description" yaml:"description"`
|
||||
Advanced bool `json:"advanced,omitempty" yaml:"advanced,omitempty"`
|
||||
Disabled bool `json:"disabled,omitempty" yaml:"disabled,omitempty"`
|
||||
DependsTrue string `json:"depends_true,omitempty" yaml:"depends_true,omitempty"`
|
||||
DependsFalse string `json:"depends_false,omitempty" yaml:"depends_false,omitempty"`
|
||||
WikiLink string `json:"wiki_link,omitempty" yaml:"wiki_link,omitempty"`
|
||||
}
|
||||
|
||||
type Option [2]string
|
||||
|
||||
type SettingType string
|
||||
|
||||
var (
|
||||
BoolType SettingType = "bool"
|
||||
SelectType SettingType = "select"
|
||||
TextType SettingType = "text"
|
||||
PasswordType SettingType = "password"
|
||||
NumberType SettingType = "number"
|
||||
NoteType SettingType = "note"
|
||||
EmailType SettingType = "email"
|
||||
ListType SettingType = "list"
|
||||
)
|
||||
|
||||
type Setting struct {
|
||||
Setting string `json:"setting" yaml:"setting" example:"my_setting"`
|
||||
Name string `json:"name" yaml:"name" example:"My Setting"`
|
||||
Description string `json:"description" yaml:"description"`
|
||||
Required bool `json:"required" yaml:"required"`
|
||||
RequiresRestart bool `json:"requires_restart" yaml:"requires_restart"`
|
||||
Advanced bool `json:"advanced,omitempty" yaml:"advanced,omitempty"`
|
||||
Type SettingType `json:"type" yaml:"type"` // Type (string, number, bool, etc.)
|
||||
Value any `json:"value" yaml:"value"`
|
||||
Options []Option `json:"options,omitempty" yaml:"options,omitempty"`
|
||||
DependsTrue string `json:"depends_true,omitempty" yaml:"depends_true,omitempty"` // If specified, this field is enabled when the specified bool setting is enabled.
|
||||
DependsFalse string `json:"depends_false,omitempty" yaml:"depends_false,omitempty"` // If specified, opposite behaviour of DependsTrue.
|
||||
Style string `json:"style,omitempty" yaml:"style,omitempty"`
|
||||
Deprecated bool `json:"deprecated,omitempty" yaml:"deprecated,omitempty"`
|
||||
WikiLink string `json:"wiki_link,omitempty" yaml:"wiki_link,omitempty"`
|
||||
}
|
||||
|
||||
type Section struct {
|
||||
Section string `json:"section" yaml:"section" example:"my_section"`
|
||||
Meta SectionMeta `json:"meta" yaml:"meta"`
|
||||
Settings []Setting `json:"settings" yaml:"settings"`
|
||||
}
|
||||
|
||||
type Config struct {
|
||||
Sections []Section `json:"sections" yaml:"sections"`
|
||||
}
|
||||
|
||||
func (c *Config) removeSection(section string) {
|
||||
for i, v := range c.Sections {
|
||||
if v.Section == section {
|
||||
c.Sections = append(c.Sections[:i], c.Sections[i+1:]...)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
@ -2,6 +2,6 @@ module github.com/hrfee/jfa-go/common
|
||||
|
||||
replace github.com/hrfee/jfa-go/logmessages => ../logmessages
|
||||
|
||||
go 1.22.4
|
||||
go 1.18
|
||||
|
||||
require github.com/hrfee/jfa-go/logmessages v0.0.0-20240806200606-6308db495a0a
|
||||
|
96
config.go
96
config.go
@ -10,6 +10,7 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/hrfee/jfa-go/common"
|
||||
"github.com/hrfee/jfa-go/easyproxy"
|
||||
lm "github.com/hrfee/jfa-go/logmessages"
|
||||
"gopkg.in/ini.v1"
|
||||
@ -250,3 +251,98 @@ func (app *appContext) loadConfig() error {
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (app *appContext) PatchConfigBase() {
|
||||
conf := app.configBase
|
||||
// Load language options
|
||||
formOptions := app.storage.lang.User.getOptions()
|
||||
pwrOptions := app.storage.lang.PasswordReset.getOptions()
|
||||
adminOptions := app.storage.lang.Admin.getOptions()
|
||||
emailOptions := app.storage.lang.Email.getOptions()
|
||||
telegramOptions := app.storage.lang.Email.getOptions()
|
||||
|
||||
for i, section := range app.configBase.Sections {
|
||||
if section.Section == "updates" && updater == "" {
|
||||
section.Meta.Disabled = true
|
||||
}
|
||||
for j, setting := range section.Settings {
|
||||
if section.Section == "ui" {
|
||||
if setting.Setting == "language-form" {
|
||||
setting.Options = formOptions
|
||||
setting.Value = "en-us"
|
||||
} else if setting.Setting == "language-admin" {
|
||||
setting.Options = adminOptions
|
||||
setting.Value = "en-us"
|
||||
}
|
||||
} else if section.Section == "password_resets" {
|
||||
if setting.Setting == "language" {
|
||||
setting.Options = pwrOptions
|
||||
setting.Value = "en-us"
|
||||
}
|
||||
} else if section.Section == "email" {
|
||||
if setting.Setting == "language" {
|
||||
setting.Options = emailOptions
|
||||
setting.Value = "en-us"
|
||||
}
|
||||
} else if section.Section == "telegram" {
|
||||
if setting.Setting == "language" {
|
||||
setting.Options = telegramOptions
|
||||
setting.Value = "en-us"
|
||||
}
|
||||
} else if section.Section == "smtp" {
|
||||
if setting.Setting == "ssl_cert" && PLATFORM == "windows" {
|
||||
// Not accurate but the effect is hiding the option, which we want.
|
||||
setting.Deprecated = true
|
||||
}
|
||||
} else if section.Section == "matrix" {
|
||||
if setting.Setting == "encryption" && !MatrixE2EE() {
|
||||
// Not accurate but the effect is hiding the option, which we want.
|
||||
setting.Deprecated = true
|
||||
}
|
||||
}
|
||||
val := app.config.Section(section.Section).Key(setting.Setting)
|
||||
switch setting.Type {
|
||||
case "list":
|
||||
setting.Value = val.StringsWithShadows("|")
|
||||
case "text", "email", "select", "password", "note":
|
||||
setting.Value = val.MustString("")
|
||||
case "number":
|
||||
setting.Value = val.MustInt(0)
|
||||
case "bool":
|
||||
setting.Value = val.MustBool(false)
|
||||
}
|
||||
section.Settings[j] = setting
|
||||
}
|
||||
conf.Sections[i] = section
|
||||
}
|
||||
app.patchedConfig = conf
|
||||
}
|
||||
|
||||
func (app *appContext) PatchConfigDiscordRoles() {
|
||||
if !discordEnabled {
|
||||
return
|
||||
}
|
||||
r, err := app.discord.ListRoles()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
roles := make([]common.Option, len(r)+1)
|
||||
roles[0] = common.Option{"", "None"}
|
||||
for i, role := range r {
|
||||
roles[i+1] = role
|
||||
}
|
||||
|
||||
for i, section := range app.patchedConfig.Sections {
|
||||
if section.Section != "discord" {
|
||||
continue
|
||||
}
|
||||
for j, setting := range section.Settings {
|
||||
if setting.Setting != "apply_role" {
|
||||
continue
|
||||
}
|
||||
setting.Options = roles
|
||||
section.Settings[j] = setting
|
||||
}
|
||||
app.patchedConfig.Sections[i] = section
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +0,0 @@
|
||||
### fixconfig
|
||||
|
||||
Python's `json` library retains the order of data in a JSON file, which meant settings sent to the web page would be in the right order. Go's `encoding/json` and maps do not retain order, so `enumerate/enumerate_config.py` opens the json file, and for each section, adds an "order" array which tells the web page in which order to display settings.
|
||||
Specify the input and output files with `-i` and `-o` respectively.
|
1
config/README.txt
Normal file
1
config/README.txt
Normal file
@ -0,0 +1 @@
|
||||
The two python scripts here, `config-json-to-new-yaml.py` and `gen-rough-schema.py` were used to convert the old format, which was stored in a JSON file, to the new format in YAML. The latter script is used to get the possible values for settings and sections, so they could be properly defined in common/config.go.
|
File diff suppressed because it is too large
Load Diff
1577
config/config-base.yaml
Normal file
1577
config/config-base.yaml
Normal file
File diff suppressed because it is too large
Load Diff
35
config/config-json-to-new-yaml.py
Normal file
35
config/config-json-to-new-yaml.py
Normal file
@ -0,0 +1,35 @@
|
||||
from ruamel.yaml import YAML
|
||||
import json
|
||||
from pathlib import Path
|
||||
import sys
|
||||
yaml = YAML()
|
||||
|
||||
# c = yaml.load(Path(sys.argv[len(sys.argv)-1]))
|
||||
with open(sys.argv[len(sys.argv)-1], 'r') as f:
|
||||
c = json.load(f)
|
||||
|
||||
c.pop("order")
|
||||
|
||||
c1 = c.copy()
|
||||
c1["sections"] = []
|
||||
for section in c["sections"]:
|
||||
codeSection = { "section": section }
|
||||
s = codeSection | c["sections"][section]
|
||||
s.pop("order")
|
||||
c1["sections"].append(s)
|
||||
|
||||
c2 = c.copy()
|
||||
c2["sections"] = []
|
||||
|
||||
for section in c1["sections"]:
|
||||
sArray = []
|
||||
for setting in section["settings"]:
|
||||
codeSetting = { "setting": setting }
|
||||
s = codeSetting | section["settings"][setting]
|
||||
sArray.append(s)
|
||||
|
||||
section["settings"] = sArray
|
||||
c2["sections"].append(section)
|
||||
|
||||
|
||||
yaml.dump(c2, sys.stdout)
|
40
config/gen-rough-schema.py
Normal file
40
config/gen-rough-schema.py
Normal file
@ -0,0 +1,40 @@
|
||||
import json
|
||||
import sys
|
||||
|
||||
sectionSchema = {}
|
||||
metaSchema = {}
|
||||
settingSchema = {}
|
||||
typeValues = {}
|
||||
|
||||
# c = yaml.load(Path(sys.argv[len(sys.argv)-1]))
|
||||
with open(sys.argv[len(sys.argv)-1], 'r') as f:
|
||||
c = json.load(f)
|
||||
|
||||
for section in c["sections"]:
|
||||
for key in c["sections"][section]:
|
||||
sectionSchema[key] = True
|
||||
|
||||
for key in c["sections"][section]["meta"]:
|
||||
metaSchema[key] = c["sections"][section]["meta"][key]
|
||||
|
||||
for setting in c["sections"][section]["settings"]:
|
||||
for field in c["sections"][section]["settings"][setting]:
|
||||
settingSchema[field] = c["sections"][section]["settings"][setting][field]
|
||||
typeValues[c["sections"][section]["settings"][setting]["type"]] = True
|
||||
|
||||
print("Section Content:")
|
||||
for v in sectionSchema:
|
||||
print(v)
|
||||
print("---")
|
||||
print("Meta Schema")
|
||||
for v in metaSchema:
|
||||
print(v, "=", type(metaSchema[v]))
|
||||
print("---")
|
||||
print("Setting Schema")
|
||||
for v in settingSchema:
|
||||
print(v, "=", type(settingSchema[v]))
|
||||
print("---")
|
||||
print("Possible Types")
|
||||
for v in typeValues:
|
||||
print(v)
|
||||
|
@ -1,7 +1,7 @@
|
||||
module github.com/hrfee/jfa-go/easyproxy
|
||||
|
||||
go 1.20
|
||||
go 1.18
|
||||
|
||||
require golang.org/x/net v0.15.0
|
||||
require golang.org/x/net v0.23.0
|
||||
|
||||
require github.com/magisterquis/connectproxy v0.0.0-20200725203833-3582e84f0c9b // indirect
|
||||
require github.com/magisterquis/connectproxy v0.0.0-20200725203833-3582e84f0c9b
|
||||
|
@ -1,4 +1,4 @@
|
||||
github.com/magisterquis/connectproxy v0.0.0-20200725203833-3582e84f0c9b h1:xZ59n7Frzh8CwyfAapUZLSg+gXH5m63YEaFCMpDHhpI=
|
||||
github.com/magisterquis/connectproxy v0.0.0-20200725203833-3582e84f0c9b/go.mod h1:uDd4sYVYsqcxAB8j+Q7uhL6IJCs/r1kxib1HV4bgOMg=
|
||||
golang.org/x/net v0.15.0 h1:ugBLEUaxABaB5AJqW9enI0ACdci2RUd4eP51NTBvuJ8=
|
||||
golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
|
||||
golang.org/x/net v0.23.0 h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs=
|
||||
golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
|
||||
|
39
go.mod
39
go.mod
@ -1,6 +1,8 @@
|
||||
module github.com/hrfee/jfa-go
|
||||
|
||||
go 1.22.4
|
||||
go 1.22
|
||||
|
||||
toolchain go1.22.4
|
||||
|
||||
replace github.com/hrfee/jfa-go/docs => ./docs
|
||||
|
||||
@ -33,18 +35,18 @@ require (
|
||||
github.com/go-telegram-bot-api/telegram-bot-api v4.6.4+incompatible
|
||||
github.com/golang-jwt/jwt v3.2.2+incompatible
|
||||
github.com/gomarkdown/markdown v0.0.0-20240730141124-034f12af3bf6
|
||||
github.com/hrfee/jfa-go/common v0.0.0-20240806200606-6308db495a0a
|
||||
github.com/hrfee/jfa-go/docs v0.0.0-20240806200606-6308db495a0a
|
||||
github.com/hrfee/jfa-go/easyproxy v0.0.0-20240806200606-6308db495a0a
|
||||
github.com/hrfee/jfa-go/jellyseerr v0.0.0-20240806200606-6308db495a0a
|
||||
github.com/hrfee/jfa-go/linecache v0.0.0-20240806200606-6308db495a0a
|
||||
github.com/hrfee/jfa-go/logger v0.0.0-20240806200606-6308db495a0a
|
||||
github.com/hrfee/jfa-go/logmessages v0.0.0-20240806200606-6308db495a0a
|
||||
github.com/hrfee/jfa-go/ombi v0.0.0-20240806200606-6308db495a0a
|
||||
github.com/hrfee/jfa-go/common v0.0.0-20240824141650-fcdd4e451882
|
||||
github.com/hrfee/jfa-go/docs v0.0.0-20240824141650-fcdd4e451882
|
||||
github.com/hrfee/jfa-go/easyproxy v0.0.0-20240824141650-fcdd4e451882
|
||||
github.com/hrfee/jfa-go/jellyseerr v0.0.0-20240824141650-fcdd4e451882
|
||||
github.com/hrfee/jfa-go/linecache v0.0.0-20240824141650-fcdd4e451882
|
||||
github.com/hrfee/jfa-go/logger v0.0.0-20240824141650-fcdd4e451882
|
||||
github.com/hrfee/jfa-go/logmessages v0.0.0-20240824141650-fcdd4e451882
|
||||
github.com/hrfee/jfa-go/ombi v0.0.0-20240824141650-fcdd4e451882
|
||||
github.com/hrfee/mediabrowser v0.3.18
|
||||
github.com/itchyny/timefmt-go v0.1.6
|
||||
github.com/lithammer/shortuuid/v3 v3.0.7
|
||||
github.com/mailgun/mailgun-go/v4 v4.14.0
|
||||
github.com/mailgun/mailgun-go/v4 v4.15.0
|
||||
github.com/mattn/go-sqlite3 v1.14.22
|
||||
github.com/robert-nix/ansihtml v1.0.1
|
||||
github.com/steambap/captcha v1.4.1
|
||||
@ -54,7 +56,8 @@ require (
|
||||
github.com/writeas/go-strip-markdown v2.0.1+incompatible
|
||||
github.com/xhit/go-simple-mail/v2 v2.16.0
|
||||
gopkg.in/ini.v1 v1.67.0
|
||||
maunium.net/go/mautrix v0.19.0
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
maunium.net/go/mautrix v0.20.0
|
||||
)
|
||||
|
||||
require (
|
||||
@ -110,7 +113,8 @@ require (
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||
github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c // indirect
|
||||
github.com/pelletier/go-toml/v2 v2.2.2 // indirect
|
||||
github.com/pelletier/go-toml/v2 v2.2.3 // indirect
|
||||
github.com/petermattis/goid v0.0.0-20240813172612-4fcff4a6cae7 // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/rs/zerolog v1.33.0 // indirect
|
||||
github.com/swaggo/swag v1.16.3 // indirect
|
||||
@ -122,21 +126,20 @@ require (
|
||||
github.com/toorop/go-dkim v0.0.0-20240103092955-90b7d1423f92 // indirect
|
||||
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
|
||||
github.com/ugorji/go/codec v1.2.12 // indirect
|
||||
go.mau.fi/util v0.6.0 // indirect
|
||||
go.mau.fi/util v0.7.0 // indirect
|
||||
go.opencensus.io v0.24.0 // indirect
|
||||
go.opentelemetry.io/otel v1.28.0 // indirect
|
||||
go.opentelemetry.io/otel/metric v1.28.0 // indirect
|
||||
go.opentelemetry.io/otel/trace v1.28.0 // indirect
|
||||
go.opentelemetry.io/otel v1.29.0 // indirect
|
||||
go.opentelemetry.io/otel/metric v1.29.0 // indirect
|
||||
go.opentelemetry.io/otel/trace v1.29.0 // indirect
|
||||
go.uber.org/multierr v1.11.0 // indirect
|
||||
go.uber.org/zap v1.27.0 // indirect
|
||||
golang.org/x/arch v0.9.0 // indirect
|
||||
golang.org/x/crypto v0.26.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20240808152545-0cdaa3abc0fa // indirect
|
||||
golang.org/x/exp v0.0.0-20240823005443-9b4947da3948 // indirect
|
||||
golang.org/x/image v0.19.0 // indirect
|
||||
golang.org/x/net v0.28.0 // indirect
|
||||
golang.org/x/sys v0.24.0 // indirect
|
||||
golang.org/x/text v0.17.0 // indirect
|
||||
golang.org/x/tools v0.24.0 // indirect
|
||||
google.golang.org/protobuf v1.34.2 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
)
|
||||
|
18
go.sum
18
go.sum
@ -258,6 +258,8 @@ github.com/magisterquis/connectproxy v0.0.0-20200725203833-3582e84f0c9b h1:xZ59n
|
||||
github.com/magisterquis/connectproxy v0.0.0-20200725203833-3582e84f0c9b/go.mod h1:uDd4sYVYsqcxAB8j+Q7uhL6IJCs/r1kxib1HV4bgOMg=
|
||||
github.com/mailgun/mailgun-go/v4 v4.14.0 h1:N9GMNs0XUq5nn3v2TlZHCknF9khSh88MkA1hdRm1o7I=
|
||||
github.com/mailgun/mailgun-go/v4 v4.14.0/go.mod h1:L9s941Lgk7iB3TgywTPz074pK2Ekkg4kgbnAaAyJ2z8=
|
||||
github.com/mailgun/mailgun-go/v4 v4.15.0 h1:3NQU0r2XItJbyIZ21iBI9ps0+vPIMoGyI2XK7ZTN/DQ=
|
||||
github.com/mailgun/mailgun-go/v4 v4.15.0/go.mod h1:L9s941Lgk7iB3TgywTPz074pK2Ekkg4kgbnAaAyJ2z8=
|
||||
github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||
github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||
@ -290,6 +292,10 @@ github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c/go.mod h1:X07ZCGwU
|
||||
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
|
||||
github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM=
|
||||
github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs=
|
||||
github.com/pelletier/go-toml/v2 v2.2.3 h1:YmeHyLY8mFWbdkNWwpr+qIL2bEqT0o95WSdkNHvL12M=
|
||||
github.com/pelletier/go-toml/v2 v2.2.3/go.mod h1:MfCQTFTvCcUyyvvwm1+G6H/jORL20Xlb6rzQu9GuUkc=
|
||||
github.com/petermattis/goid v0.0.0-20240813172612-4fcff4a6cae7 h1:Dx7Ovyv/SFnMFw3fD4oEoeorXc6saIiQ23LrGLth0Gw=
|
||||
github.com/petermattis/goid v0.0.0-20240813172612-4fcff4a6cae7/go.mod h1:pxMtw7cyUw6B2bRH0ZBANSPg+AoSud1I1iyJHI69jH4=
|
||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
@ -384,17 +390,25 @@ github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1
|
||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||
go.mau.fi/util v0.6.0 h1:W6SyB3Bm/GjenQ5iq8Z8WWdN85Gy2xS6L0wmnR7SVjg=
|
||||
go.mau.fi/util v0.6.0/go.mod h1:ljYdq3sPfpICc3zMU+/mHV/sa4z0nKxc67hSBwnrk8U=
|
||||
go.mau.fi/util v0.7.0 h1:l31z+ivrSQw+cv/9eFebEqtQW2zhxivGypn+JT0h/ws=
|
||||
go.mau.fi/util v0.7.0/go.mod h1:bWYreIoTULL/UiRbZdfddPh7uWDFW5yX4YCv5FB0eE0=
|
||||
go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk=
|
||||
go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0=
|
||||
go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo=
|
||||
go.opentelemetry.io/otel v1.9.0/go.mod h1:np4EoPGzoPs3O67xUVNoPPcmSvsfOxNlNA4F4AC+0Eo=
|
||||
go.opentelemetry.io/otel v1.28.0 h1:/SqNcYk+idO0CxKEUOtKQClMK/MimZihKYMruSMViUo=
|
||||
go.opentelemetry.io/otel v1.28.0/go.mod h1:q68ijF8Fc8CnMHKyzqL6akLO46ePnjkgfIMIjUIX9z4=
|
||||
go.opentelemetry.io/otel v1.29.0 h1:PdomN/Al4q/lN6iBJEN3AwPvUiHPMlt93c8bqTG5Llw=
|
||||
go.opentelemetry.io/otel v1.29.0/go.mod h1:N/WtXPs1CNCUEx+Agz5uouwCba+i+bJGFicT8SR4NP8=
|
||||
go.opentelemetry.io/otel/metric v1.28.0 h1:f0HGvSl1KRAU1DLgLGFjrwVyismPlnuU6JD6bOeuA5Q=
|
||||
go.opentelemetry.io/otel/metric v1.28.0/go.mod h1:Fb1eVBFZmLVTMb6PPohq3TO9IIhUisDsbJoL/+uQW4s=
|
||||
go.opentelemetry.io/otel/metric v1.29.0 h1:vPf/HFWTNkPu1aYeIsc98l4ktOQaL6LeSoeV2g+8YLc=
|
||||
go.opentelemetry.io/otel/metric v1.29.0/go.mod h1:auu/QWieFVWx+DmQOUMgj0F8LHWdgalxXqvp7BII/W8=
|
||||
go.opentelemetry.io/otel/trace v1.9.0/go.mod h1:2737Q0MuG8q1uILYm2YYVkAyLtOofiTNGg6VODnOiPo=
|
||||
go.opentelemetry.io/otel/trace v1.28.0 h1:GhQ9cUuQGmNDd5BTCP2dAvv75RdMxEfTmYejp+lkx9g=
|
||||
go.opentelemetry.io/otel/trace v1.28.0/go.mod h1:jPyXzNPg6da9+38HEwElrQiHlVMTnVfM3/yv2OlIHaI=
|
||||
go.opentelemetry.io/otel/trace v1.29.0 h1:J/8ZNK4XgR7a21DZUAsbF8pZ5Jcw1VhACmnYt39JTi4=
|
||||
go.opentelemetry.io/otel/trace v1.29.0/go.mod h1:eHl3w0sp3paPkYstJOmAimxhiFXPg+MMTlEh3nsQgWQ=
|
||||
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
||||
go.uber.org/goleak v1.1.11-0.20210813005559-691160354723/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ=
|
||||
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
|
||||
@ -419,6 +433,8 @@ golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn5
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20240808152545-0cdaa3abc0fa h1:ELnwvuAXPNtPk1TJRuGkI9fDTwym6AYBu0qzT8AcHdI=
|
||||
golang.org/x/exp v0.0.0-20240808152545-0cdaa3abc0fa/go.mod h1:akd2r19cwCdwSwWeIdzYQGa/EZZyqcOdwWiwj5L5eKQ=
|
||||
golang.org/x/exp v0.0.0-20240823005443-9b4947da3948 h1:kx6Ds3MlpiUHKj7syVnbp57++8WpuKPcR5yjLBjvLEA=
|
||||
golang.org/x/exp v0.0.0-20240823005443-9b4947da3948/go.mod h1:akd2r19cwCdwSwWeIdzYQGa/EZZyqcOdwWiwj5L5eKQ=
|
||||
golang.org/x/image v0.0.0-20210628002857-a66eb6448b8d/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM=
|
||||
golang.org/x/image v0.19.0 h1:D9FX4QWkLfkeqaC62SonffIIuYdOk/UE2XKUBgRIBIQ=
|
||||
golang.org/x/image v0.19.0/go.mod h1:y0zrRqlQRWQ5PXaYCOMLTW2fpsxZ8Qh9I/ohnInJEys=
|
||||
@ -577,4 +593,6 @@ honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWh
|
||||
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
maunium.net/go/mautrix v0.19.0 h1:67eSJWam93mw44Q0/1SiOG7zQzXMUknUv5UaWkrODDU=
|
||||
maunium.net/go/mautrix v0.19.0/go.mod h1:UE+mSQ4sDUuJMbjN0aB9EjQSGgXd48AzMvZ6+QJV1k8=
|
||||
maunium.net/go/mautrix v0.20.0 h1:bzQnVQR+LvQxV1YlAr7BSWCS8AWa0Ov0lyPhbbChM0o=
|
||||
maunium.net/go/mautrix v0.20.0/go.mod h1:V725r8w7oddsS7CxnmTAp634A4nwJCFY7J3jiTMUz2c=
|
||||
nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50=
|
||||
|
@ -2,7 +2,7 @@ module github.com/hrfee/jfa-go/jellyseerr
|
||||
|
||||
replace github.com/hrfee/jfa-go/common => ../common
|
||||
|
||||
go 1.22.4
|
||||
go 1.18
|
||||
|
||||
require github.com/hrfee/jfa-go/common v0.0.0-20240728190513-dabef831d769
|
||||
|
||||
|
38
lang.go
38
lang.go
@ -1,5 +1,7 @@
|
||||
package main
|
||||
|
||||
import "github.com/hrfee/jfa-go/common"
|
||||
|
||||
type langMeta struct {
|
||||
Name string `json:"name"`
|
||||
// Language to fall back on if strings are missing. Defaults to en-us.
|
||||
@ -13,11 +15,11 @@ type quantityString struct {
|
||||
|
||||
type adminLangs map[string]adminLang
|
||||
|
||||
func (ls *adminLangs) getOptions() [][2]string {
|
||||
opts := make([][2]string, len(*ls))
|
||||
func (ls *adminLangs) getOptions() []common.Option {
|
||||
opts := make([]common.Option, len(*ls))
|
||||
i := 0
|
||||
for key, lang := range *ls {
|
||||
opts[i] = [2]string{key, lang.Meta.Name}
|
||||
opts[i] = common.Option{key, lang.Meta.Name}
|
||||
i++
|
||||
}
|
||||
return opts
|
||||
@ -42,11 +44,11 @@ type adminLang struct {
|
||||
|
||||
type userLangs map[string]userLang
|
||||
|
||||
func (ls *userLangs) getOptions() [][2]string {
|
||||
opts := make([][2]string, len(*ls))
|
||||
func (ls *userLangs) getOptions() []common.Option {
|
||||
opts := make([]common.Option, len(*ls))
|
||||
i := 0
|
||||
for key, lang := range *ls {
|
||||
opts[i] = [2]string{key, lang.Meta.Name}
|
||||
opts[i] = common.Option{key, lang.Meta.Name}
|
||||
i++
|
||||
}
|
||||
return opts
|
||||
@ -65,11 +67,11 @@ type userLang struct {
|
||||
|
||||
type pwrLangs map[string]pwrLang
|
||||
|
||||
func (ls *pwrLangs) getOptions() [][2]string {
|
||||
opts := make([][2]string, len(*ls))
|
||||
func (ls *pwrLangs) getOptions() []common.Option {
|
||||
opts := make([]common.Option, len(*ls))
|
||||
i := 0
|
||||
for key, lang := range *ls {
|
||||
opts[i] = [2]string{key, lang.Meta.Name}
|
||||
opts[i] = common.Option{key, lang.Meta.Name}
|
||||
i++
|
||||
}
|
||||
return opts
|
||||
@ -82,11 +84,11 @@ type pwrLang struct {
|
||||
|
||||
type emailLangs map[string]emailLang
|
||||
|
||||
func (ls *emailLangs) getOptions() [][2]string {
|
||||
opts := make([][2]string, len(*ls))
|
||||
func (ls *emailLangs) getOptions() []common.Option {
|
||||
opts := make([]common.Option, len(*ls))
|
||||
i := 0
|
||||
for key, lang := range *ls {
|
||||
opts[i] = [2]string{key, lang.Meta.Name}
|
||||
opts[i] = common.Option{key, lang.Meta.Name}
|
||||
i++
|
||||
}
|
||||
return opts
|
||||
@ -135,11 +137,11 @@ type setupLang struct {
|
||||
JSON string
|
||||
}
|
||||
|
||||
func (ls *setupLangs) getOptions() [][2]string {
|
||||
opts := make([][2]string, len(*ls))
|
||||
func (ls *setupLangs) getOptions() []common.Option {
|
||||
opts := make([]common.Option, len(*ls))
|
||||
i := 0
|
||||
for key, lang := range *ls {
|
||||
opts[i] = [2]string{key, lang.Meta.Name}
|
||||
opts[i] = common.Option{key, lang.Meta.Name}
|
||||
i++
|
||||
}
|
||||
return opts
|
||||
@ -152,11 +154,11 @@ type telegramLang struct {
|
||||
Strings langSection `json:"strings"`
|
||||
}
|
||||
|
||||
func (ts *telegramLangs) getOptions() [][2]string {
|
||||
opts := make([][2]string, len(*ts))
|
||||
func (ts *telegramLangs) getOptions() []common.Option {
|
||||
opts := make([]common.Option, len(*ts))
|
||||
i := 0
|
||||
for key, lang := range *ts {
|
||||
opts[i] = [2]string{key, lang.Meta.Name}
|
||||
opts[i] = common.Option{key, lang.Meta.Name}
|
||||
i++
|
||||
}
|
||||
return opts
|
||||
|
@ -1,3 +1,3 @@
|
||||
module github.com/hrfee/jfa-go/logmessages
|
||||
|
||||
go 1.22.4
|
||||
go 1.18
|
||||
|
10
main.go
10
main.go
@ -32,6 +32,7 @@ import (
|
||||
"github.com/hrfee/mediabrowser"
|
||||
"github.com/lithammer/shortuuid/v3"
|
||||
"gopkg.in/ini.v1"
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
var (
|
||||
@ -93,7 +94,8 @@ type appContext struct {
|
||||
config *ini.File
|
||||
configPath string
|
||||
configBasePath string
|
||||
configBase settings
|
||||
configBase common.Config
|
||||
patchedConfig common.Config
|
||||
dataPath string
|
||||
webFS httpFS
|
||||
cssClass string // Default theme, "light"|"dark".
|
||||
@ -388,9 +390,11 @@ func start(asDaemon, firstCall bool) {
|
||||
defer app.storage.db.Close()
|
||||
|
||||
// Read config-base for settings on web.
|
||||
app.configBasePath = "config-base.json"
|
||||
app.configBasePath = "config-base.yaml"
|
||||
configBase, _ := fs.ReadFile(localFS, app.configBasePath)
|
||||
json.Unmarshal(configBase, &app.configBase)
|
||||
yaml.Unmarshal(configBase, &app.configBase)
|
||||
// copy it to app.patchedConfig, and patch in settings from app.config, and language stuff.
|
||||
app.PatchConfigBase()
|
||||
|
||||
secret, err := generateSecret(16)
|
||||
if err != nil {
|
||||
|
37
models.go
37
models.go
@ -212,43 +212,6 @@ type errorListDTO map[string]map[string]string
|
||||
|
||||
type configDTO map[string]interface{}
|
||||
|
||||
// Below are for sending config
|
||||
|
||||
type meta struct {
|
||||
Name string `json:"name"`
|
||||
Description string `json:"description"`
|
||||
Advanced bool `json:"advanced,omitempty"`
|
||||
DependsTrue string `json:"depends_true,omitempty"`
|
||||
DependsFalse string `json:"depends_false,omitempty"`
|
||||
WikiLink string `json:"wiki_link,omitempty"`
|
||||
}
|
||||
|
||||
type setting struct {
|
||||
Name string `json:"name"`
|
||||
Description string `json:"description"`
|
||||
Required bool `json:"required"`
|
||||
Advanced bool `json:"advanced,omitempty"`
|
||||
RequiresRestart bool `json:"requires_restart"`
|
||||
Type string `json:"type"` // Type (string, number, bool, etc.)
|
||||
Value interface{} `json:"value"`
|
||||
Options [][2]string `json:"options,omitempty"`
|
||||
DependsTrue string `json:"depends_true,omitempty"` // If specified, this field is enabled when the specified bool setting is enabled.
|
||||
DependsFalse string `json:"depends_false,omitempty"` // If specified, opposite behaviour of DependsTrue.
|
||||
Style string `json:"style,omitempty"`
|
||||
Deprecated bool `json:"deprecated,omitempty"`
|
||||
}
|
||||
|
||||
type section struct {
|
||||
Meta meta `json:"meta"`
|
||||
Order []string `json:"order"`
|
||||
Settings map[string]setting `json:"settings"`
|
||||
}
|
||||
|
||||
type settings struct {
|
||||
Order []string `json:"order"`
|
||||
Sections map[string]section `json:"sections"`
|
||||
}
|
||||
|
||||
type langDTO map[string]string
|
||||
|
||||
type emailListDTO map[string]emailListEl
|
||||
|
@ -2,7 +2,7 @@ module github.com/hrfee/jfa-go/ombi
|
||||
|
||||
replace github.com/hrfee/jfa-go/common => ../common
|
||||
|
||||
go 1.22.4
|
||||
go 1.18
|
||||
|
||||
require github.com/hrfee/jfa-go/common v0.0.0-20240806200606-6308db495a0a
|
||||
|
||||
|
50
package-lock.json
generated
50
package-lock.json
generated
@ -22,7 +22,7 @@
|
||||
"mjml": "^4.15.3",
|
||||
"nightwind": "^1.1.13",
|
||||
"perl-regex": "^1.0.4",
|
||||
"postcss": "^8.4.24",
|
||||
"postcss": "^8.4.31",
|
||||
"remixicon": "^4.3.0",
|
||||
"remove-markdown": "^0.5.0",
|
||||
"tailwindcss": "^3.3.2",
|
||||
@ -4669,9 +4669,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/postcss": {
|
||||
"version": "8.4.24",
|
||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.24.tgz",
|
||||
"integrity": "sha512-M0RzbcI0sO/XJNucsGjvWU9ERWxb/ytp1w6dKtxTKgixdtQDq4rmx/g8W1hnaheq9jgwL/oyEdH5Bc4WwJKMqg==",
|
||||
"version": "8.4.31",
|
||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz",
|
||||
"integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "opencollective",
|
||||
@ -6653,9 +6653,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/uncss/node_modules/ws": {
|
||||
"version": "6.2.2",
|
||||
"resolved": "https://registry.npmjs.org/ws/-/ws-6.2.2.tgz",
|
||||
"integrity": "sha512-zmhltoSR8u1cnDsD43TX59mzoMZsLKqUweyYBAIvTngR3shc0W6aOZylZmq/7hqyVxPdi+5Ud2QInblgyE72fw==",
|
||||
"version": "6.2.3",
|
||||
"resolved": "https://registry.npmjs.org/ws/-/ws-6.2.3.tgz",
|
||||
"integrity": "sha512-jmTjYU0j60B+vHey6TfR3Z7RD61z/hmxBS3VMSGIrroOWXQEneK1zNuotOUrGyBHQj0yrpsLHPWtigEFd13ndA==",
|
||||
"dependencies": {
|
||||
"async-limiter": "~1.0.0"
|
||||
}
|
||||
@ -7167,9 +7167,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/word-wrap": {
|
||||
"version": "1.2.3",
|
||||
"resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz",
|
||||
"integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==",
|
||||
"version": "1.2.5",
|
||||
"resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz",
|
||||
"integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==",
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
@ -7215,9 +7215,9 @@
|
||||
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="
|
||||
},
|
||||
"node_modules/ws": {
|
||||
"version": "8.13.0",
|
||||
"resolved": "https://registry.npmjs.org/ws/-/ws-8.13.0.tgz",
|
||||
"integrity": "sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==",
|
||||
"version": "8.18.0",
|
||||
"resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz",
|
||||
"integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==",
|
||||
"engines": {
|
||||
"node": ">=10.0.0"
|
||||
},
|
||||
@ -10690,9 +10690,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"postcss": {
|
||||
"version": "8.4.24",
|
||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.24.tgz",
|
||||
"integrity": "sha512-M0RzbcI0sO/XJNucsGjvWU9ERWxb/ytp1w6dKtxTKgixdtQDq4rmx/g8W1hnaheq9jgwL/oyEdH5Bc4WwJKMqg==",
|
||||
"version": "8.4.31",
|
||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz",
|
||||
"integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==",
|
||||
"requires": {
|
||||
"nanoid": "^3.3.6",
|
||||
"picocolors": "^1.0.0",
|
||||
@ -12180,9 +12180,9 @@
|
||||
}
|
||||
},
|
||||
"ws": {
|
||||
"version": "6.2.2",
|
||||
"resolved": "https://registry.npmjs.org/ws/-/ws-6.2.2.tgz",
|
||||
"integrity": "sha512-zmhltoSR8u1cnDsD43TX59mzoMZsLKqUweyYBAIvTngR3shc0W6aOZylZmq/7hqyVxPdi+5Ud2QInblgyE72fw==",
|
||||
"version": "6.2.3",
|
||||
"resolved": "https://registry.npmjs.org/ws/-/ws-6.2.3.tgz",
|
||||
"integrity": "sha512-jmTjYU0j60B+vHey6TfR3Z7RD61z/hmxBS3VMSGIrroOWXQEneK1zNuotOUrGyBHQj0yrpsLHPWtigEFd13ndA==",
|
||||
"requires": {
|
||||
"async-limiter": "~1.0.0"
|
||||
}
|
||||
@ -12546,9 +12546,9 @@
|
||||
}
|
||||
},
|
||||
"word-wrap": {
|
||||
"version": "1.2.3",
|
||||
"resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz",
|
||||
"integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ=="
|
||||
"version": "1.2.5",
|
||||
"resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz",
|
||||
"integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA=="
|
||||
},
|
||||
"wrap-ansi": {
|
||||
"version": "7.0.0",
|
||||
@ -12576,9 +12576,9 @@
|
||||
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="
|
||||
},
|
||||
"ws": {
|
||||
"version": "8.13.0",
|
||||
"resolved": "https://registry.npmjs.org/ws/-/ws-8.13.0.tgz",
|
||||
"integrity": "sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==",
|
||||
"version": "8.18.0",
|
||||
"resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz",
|
||||
"integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==",
|
||||
"requires": {}
|
||||
},
|
||||
"xml-name-validator": {
|
||||
|
@ -30,7 +30,7 @@
|
||||
"mjml": "^4.15.3",
|
||||
"nightwind": "^1.1.13",
|
||||
"perl-regex": "^1.0.4",
|
||||
"postcss": "^8.4.24",
|
||||
"postcss": "^8.4.31",
|
||||
"remixicon": "^4.3.0",
|
||||
"remove-markdown": "^0.5.0",
|
||||
"tailwindcss": "^3.3.2",
|
||||
|
@ -1,5 +1,5 @@
|
||||
module github.com/hrfee/jfa-go/scripts/account-gen
|
||||
|
||||
go 1.20
|
||||
go 1.18
|
||||
|
||||
require github.com/hrfee/mediabrowser v0.3.8 // indirect
|
||||
|
@ -1,52 +0,0 @@
|
||||
import subprocess
|
||||
import shutil
|
||||
import os
|
||||
import argparse
|
||||
from pathlib import Path
|
||||
from multiprocessing import Process
|
||||
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("-o", "--output", help="output directory for .html and .txt files")
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
def runcmd(cmd):
|
||||
if os.name == "nt":
|
||||
return subprocess.check_output(cmd, shell=True)
|
||||
with subprocess.Popen(cmd.split(), stdout=subprocess.PIPE) as proc:
|
||||
return proc.communicate()
|
||||
|
||||
def compile(mjml: Path):
|
||||
fname = mjml.with_suffix(".html")
|
||||
runcmd(f"npx mjml {str(mjml)} -o {str(fname)}")
|
||||
if fname.is_file():
|
||||
print(f"Compiled {mjml.name}")
|
||||
|
||||
local_path = Path("mail")
|
||||
|
||||
threads = []
|
||||
|
||||
for mjml in [f for f in local_path.iterdir() if f.is_file() and "mjml" in f.suffix]:
|
||||
p = Process(target=compile, args=(mjml,))
|
||||
p.start()
|
||||
threads.append(p)
|
||||
|
||||
for thread in threads:
|
||||
thread.join()
|
||||
|
||||
html = [f for f in local_path.iterdir() if f.is_file() and "html" in f.suffix]
|
||||
|
||||
output = Path(args.output) # local_path.parent / "build" / "data"
|
||||
output.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
for f in html:
|
||||
shutil.copy(str(f), str(output / f.name))
|
||||
print(f"Copied {f.name} to {str(output / f.name)}")
|
||||
txtfile = f.with_suffix(".txt")
|
||||
if txtfile.is_file():
|
||||
shutil.copy(str(txtfile), str(output / txtfile.name))
|
||||
print(f"Copied {txtfile.name} to {str(output / txtfile.name)}")
|
||||
else:
|
||||
print(
|
||||
f"Warning: {txtfile.name} does not exist. Text versions of emails should be supplied."
|
||||
)
|
@ -1,29 +0,0 @@
|
||||
# Since go doesn't order its json, this script adds ordered lists
|
||||
# of section/setting names for the settings tab to use.
|
||||
import json, argparse
|
||||
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("-i", "--input", help="input config base from jf-accounts")
|
||||
parser.add_argument("-o", "--output", help="output config base for jfa-go")
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
with open(args.input, 'r') as f:
|
||||
config = json.load(f)
|
||||
|
||||
newconfig = {"sections": {}, "order": []}
|
||||
|
||||
for sect in config["sections"]:
|
||||
newconfig["order"].append(sect)
|
||||
newconfig["sections"][sect] = {}
|
||||
newconfig["sections"][sect]["order"] = []
|
||||
newconfig["sections"][sect]["meta"] = config["sections"][sect]["meta"]
|
||||
newconfig["sections"][sect]["settings"] = {}
|
||||
for setting in config["sections"][sect]["settings"]:
|
||||
newconfig["sections"][sect]["order"].append(setting)
|
||||
newconfig["sections"][sect]["settings"][setting] = config["sections"][sect]["settings"][setting]
|
||||
|
||||
with open(args.output, 'w') as f:
|
||||
f.write(json.dumps(newconfig, indent=4))
|
||||
|
||||
|
@ -1,47 +0,0 @@
|
||||
# Generates config file
|
||||
import configparser
|
||||
import json
|
||||
import argparse
|
||||
from pathlib import Path
|
||||
|
||||
def fix_description(desc):
|
||||
return "; " + desc.replace("\n", "\n; ")
|
||||
|
||||
def generate_ini(base_file, ini_file):
|
||||
"""
|
||||
Generates .ini file from config-base file.
|
||||
"""
|
||||
with open(Path(base_file), "r") as f:
|
||||
config_base = json.load(f)
|
||||
|
||||
ini = configparser.RawConfigParser(allow_no_value=True)
|
||||
|
||||
for section in config_base["sections"]:
|
||||
ini.add_section(section)
|
||||
if "meta" in config_base["sections"][section]:
|
||||
ini.set(section, fix_description(config_base["sections"][section]["meta"]["description"]))
|
||||
for entry in config_base["sections"][section]["settings"]:
|
||||
if config_base["sections"][section]["settings"][entry]["type"] == "note":
|
||||
continue
|
||||
if "description" in config_base["sections"][section]["settings"][entry]:
|
||||
ini.set(section, fix_description(config_base["sections"][section]["settings"][entry]["description"]))
|
||||
value = config_base["sections"][section]["settings"][entry]["value"]
|
||||
if isinstance(value, bool):
|
||||
value = str(value).lower()
|
||||
else:
|
||||
value = str(value)
|
||||
ini.set(section, entry, value)
|
||||
|
||||
with open(Path(ini_file), "w") as config_file:
|
||||
ini.write(config_file)
|
||||
return True
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("-i", "--input", help="input config base from jf-accounts")
|
||||
parser.add_argument("-o", "--output", help="output ini")
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
print(generate_ini(base_file=args.input, ini_file=args.output))
|
12
scripts/ini/go.mod
Normal file
12
scripts/ini/go.mod
Normal file
@ -0,0 +1,12 @@
|
||||
module github.com/hrfee/jfa-go/scripts/ini
|
||||
|
||||
replace github.com/hrfee/jfa-go/common => ../../common
|
||||
|
||||
go 1.18
|
||||
|
||||
require (
|
||||
github.com/hrfee/jfa-go/common v0.0.0-20240824141650-fcdd4e451882 // indirect
|
||||
github.com/hrfee/jfa-go/logmessages v0.0.0-20240806200606-6308db495a0a // indirect
|
||||
gopkg.in/ini.v1 v1.67.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
)
|
7
scripts/ini/go.sum
Normal file
7
scripts/ini/go.sum
Normal file
@ -0,0 +1,7 @@
|
||||
github.com/hrfee/jfa-go/logmessages v0.0.0-20240806200606-6308db495a0a h1:qbXZgCqb9eaPSJfLEXczQD2lxTv6jb6silMPIWW9j6o=
|
||||
github.com/hrfee/jfa-go/logmessages v0.0.0-20240806200606-6308db495a0a/go.mod h1:c5HKkLayo0GrEUDlJwT12b67BL9cdPjP271Xlv/KDRQ=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
|
||||
gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
130
scripts/ini/main.go
Normal file
130
scripts/ini/main.go
Normal file
@ -0,0 +1,130 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"flag"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/hrfee/jfa-go/common"
|
||||
"gopkg.in/ini.v1"
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
func fixDescription(desc string) string {
|
||||
return "; " + strings.ReplaceAll(desc, "\n", "\n; ")
|
||||
}
|
||||
|
||||
func generateIni(yamlPath string, iniPath string) {
|
||||
yamlFile, err := os.ReadFile(yamlPath)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
configBase := common.Config{}
|
||||
err = yaml.Unmarshal(yamlFile, &configBase)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
conf := ini.Empty()
|
||||
|
||||
for _, section := range configBase.Sections {
|
||||
cSection, err := conf.NewSection(section.Section)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if section.Meta.Description != "" {
|
||||
cSection.Comment = fixDescription(section.Meta.Description)
|
||||
}
|
||||
for _, setting := range section.Settings {
|
||||
if setting.Type == common.NoteType {
|
||||
continue
|
||||
}
|
||||
val := ""
|
||||
if setting.Value != nil {
|
||||
// Easy way to convert bools and numbers to strings,
|
||||
// Instead of checking setting.Type
|
||||
val = fmt.Sprintf("%v", setting.Value)
|
||||
}
|
||||
cKey, err := cSection.NewKey(setting.Setting, val)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if setting.Description != "" {
|
||||
cKey.Comment = fixDescription(setting.Description)
|
||||
}
|
||||
// Explain how to use list type
|
||||
if setting.Type == common.ListType {
|
||||
if cKey.Comment != "" {
|
||||
cKey.Comment += "\n"
|
||||
}
|
||||
cKey.Comment += `List type: duplicate and edit the line to add more entries.`
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
err = conf.SaveTo(iniPath)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
// Compares two inis, used to check this script does the equivalent of the old generate_ini.py.
|
||||
func compareInis(p1, p2 string) {
|
||||
cA, err := ini.ShadowLoad(p1)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
cB, err := ini.ShadowLoad(p2)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
for _, pair := range [][2]*ini.File{{cA, cB}, {cB, cA}} {
|
||||
s1 := pair[0].Sections()
|
||||
s2 := pair[1].Sections()
|
||||
for i := range s1 {
|
||||
if s1[i].Name() != s2[i].Name() {
|
||||
panic(fmt.Errorf("mismatching section order: s0[i]=%s, s1[i]=%s", s1[i].Name(), s2[i].Name()))
|
||||
}
|
||||
// fmt.Println("Section order matches")
|
||||
st1 := s1[i].Keys()
|
||||
st2 := s2[i].Keys()
|
||||
for i := range st1 {
|
||||
if st1[i].Name() != st2[i].Name() {
|
||||
panic(fmt.Errorf("mismatching setting order: st1[i]=%s, st2[i]=%s", st1[i].Name(), st2[i].Name()))
|
||||
}
|
||||
if st1[i].Value() != st2[i].Value() {
|
||||
panic(fmt.Errorf("mismatching setting values: st1[i]=%s, st2[i]=%s", st1[i].Value(), st2[i].Value()))
|
||||
}
|
||||
// fmt.Println("Setting matches")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
var yamlPath string
|
||||
var iniPath string
|
||||
var comparePath string
|
||||
flag.StringVar(&yamlPath, "in", "", "Input of the config base in yaml.")
|
||||
flag.StringVar(&iniPath, "out", "", "Output path of an ini file.")
|
||||
flag.StringVar(&comparePath, "comp", "", "Path to ini file to compare against.")
|
||||
|
||||
flag.Parse()
|
||||
|
||||
if yamlPath == "" {
|
||||
panic(errors.New("invalid yaml path"))
|
||||
}
|
||||
if iniPath == "" {
|
||||
panic(errors.New("invalid ini path"))
|
||||
}
|
||||
|
||||
generateIni(yamlPath, iniPath)
|
||||
|
||||
if comparePath != "" {
|
||||
compareInis(iniPath, comparePath)
|
||||
fmt.Println("Passed.")
|
||||
}
|
||||
}
|
12
site/package-lock.json
generated
12
site/package-lock.json
generated
@ -4462,9 +4462,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/word-wrap": {
|
||||
"version": "1.2.3",
|
||||
"resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz",
|
||||
"integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==",
|
||||
"version": "1.2.5",
|
||||
"resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz",
|
||||
"integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==",
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
@ -7828,9 +7828,9 @@
|
||||
}
|
||||
},
|
||||
"word-wrap": {
|
||||
"version": "1.2.3",
|
||||
"resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz",
|
||||
"integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ=="
|
||||
"version": "1.2.5",
|
||||
"resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz",
|
||||
"integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA=="
|
||||
},
|
||||
"wrappy": {
|
||||
"version": "1.0.2",
|
||||
|
@ -19,20 +19,33 @@ interface settingsChangedEvent extends Event {
|
||||
detail: string;
|
||||
}
|
||||
|
||||
type SettingType = string;
|
||||
|
||||
const BoolType: SettingType = "bool";
|
||||
const SelectType: SettingType = "select";
|
||||
const TextType: SettingType = "text";
|
||||
const PasswordType: SettingType = "password";
|
||||
const NumberType: SettingType = "number";
|
||||
const NoteType: SettingType = "note";
|
||||
const EmailType: SettingType = "email";
|
||||
const ListType: SettingType = "list";
|
||||
|
||||
interface Meta {
|
||||
name: string;
|
||||
description: string;
|
||||
advanced?: boolean;
|
||||
disabled?: boolean;
|
||||
depends_true?: string;
|
||||
depends_false?: string;
|
||||
wiki_link?: string;
|
||||
}
|
||||
|
||||
interface Setting {
|
||||
setting: string;
|
||||
name: string;
|
||||
description: string;
|
||||
required: boolean;
|
||||
requires_restart: boolean;
|
||||
required?: boolean;
|
||||
requires_restart?: boolean;
|
||||
advanced?: boolean;
|
||||
type: string;
|
||||
value: string | boolean | number | string[];
|
||||
@ -67,17 +80,17 @@ class DOMSetting {
|
||||
protected _restart: HTMLSpanElement;
|
||||
protected _advanced: boolean;
|
||||
protected _section: string;
|
||||
protected _name: string;
|
||||
setting: string;
|
||||
|
||||
hide = () => {
|
||||
this._hideEl.classList.add("unfocused");
|
||||
const event = new CustomEvent(`settings-${this._section}-${this._name}`, { "detail": false })
|
||||
const event = new CustomEvent(`settings-${this._section}-${this.setting}`, { "detail": false })
|
||||
document.dispatchEvent(event);
|
||||
|
||||
};
|
||||
show = () => {
|
||||
this._hideEl.classList.remove("unfocused");
|
||||
const event = new CustomEvent(`settings-${this._section}-${this._name}`, { "detail": this.valueAsString() })
|
||||
const event = new CustomEvent(`settings-${this._section}-${this.setting}`, { "detail": this.valueAsString() })
|
||||
document.dispatchEvent(event);
|
||||
};
|
||||
|
||||
@ -142,8 +155,8 @@ class DOMSetting {
|
||||
valueAsString = (): string => { return ""+this.value; };
|
||||
|
||||
onValueChange = () => {
|
||||
const event = new CustomEvent(`settings-${this._section}-${this._name}`, { "detail": this.valueAsString() })
|
||||
const setEvent = new CustomEvent(`settings-set-${this._section}-${this._name}`, { "detail": this.valueAsString() })
|
||||
const event = new CustomEvent(`settings-${this._section}-${this.setting}`, { "detail": this.valueAsString() })
|
||||
const setEvent = new CustomEvent(`settings-set-${this._section}-${this.setting}`, { "detail": this.valueAsString() })
|
||||
document.dispatchEvent(event);
|
||||
document.dispatchEvent(setEvent);
|
||||
if (this.requires_restart) { document.dispatchEvent(new CustomEvent("settings-requires-restart")); }
|
||||
@ -151,7 +164,7 @@ class DOMSetting {
|
||||
|
||||
constructor(input: string, setting: Setting, section: string, name: string, inputOnTop: boolean = false) {
|
||||
this._section = section;
|
||||
this._name = name;
|
||||
this.setting = name;
|
||||
this._container = document.createElement("div");
|
||||
this._container.classList.add("setting");
|
||||
this._container.setAttribute("data-name", name);
|
||||
@ -223,7 +236,7 @@ interface SText extends Setting {
|
||||
}
|
||||
class DOMText extends DOMInput implements SText {
|
||||
constructor(setting: Setting, section: string, name: string) { super("text", setting, section, name); }
|
||||
type: string = "text";
|
||||
type: SettingType = TextType;
|
||||
get value(): string { return this._input.value }
|
||||
set value(v: string) { this._input.value = v; }
|
||||
}
|
||||
@ -233,7 +246,7 @@ interface SPassword extends Setting {
|
||||
}
|
||||
class DOMPassword extends DOMInput implements SPassword {
|
||||
constructor(setting: Setting, section: string, name: string) { super("password", setting, section, name); }
|
||||
type: string = "password";
|
||||
type: SettingType = PasswordType;
|
||||
get value(): string { return this._input.value }
|
||||
set value(v: string) { this._input.value = v; }
|
||||
}
|
||||
@ -243,7 +256,7 @@ interface SEmail extends Setting {
|
||||
}
|
||||
class DOMEmail extends DOMInput implements SEmail {
|
||||
constructor(setting: Setting, section: string, name: string) { super("email", setting, section, name); }
|
||||
type: string = "email";
|
||||
type: SettingType = EmailType;
|
||||
get value(): string { return this._input.value }
|
||||
set value(v: string) { this._input.value = v; }
|
||||
}
|
||||
@ -253,7 +266,7 @@ interface SNumber extends Setting {
|
||||
}
|
||||
class DOMNumber extends DOMInput implements SNumber {
|
||||
constructor(setting: Setting, section: string, name: string) { super("number", setting, section, name); }
|
||||
type: string = "number";
|
||||
type: SettingType = NumberType;
|
||||
get value(): number { return +this._input.value; }
|
||||
set value(v: number) { this._input.value = ""+v; }
|
||||
}
|
||||
@ -263,7 +276,7 @@ interface SList extends Setting {
|
||||
}
|
||||
class DOMList extends DOMSetting implements SList {
|
||||
protected _inputs: HTMLDivElement;
|
||||
type: string = "list";
|
||||
type: SettingType = ListType;
|
||||
|
||||
valueAsString = (): string => { return this.value.join("|"); };
|
||||
|
||||
@ -334,7 +347,7 @@ interface SBool extends Setting {
|
||||
value: boolean;
|
||||
}
|
||||
class DOMBool extends DOMSetting implements SBool {
|
||||
type: string = "bool";
|
||||
type: SettingType = BoolType;
|
||||
|
||||
get value(): boolean { return this._input.checked; }
|
||||
set value(state: boolean) { this._input.checked = state; }
|
||||
@ -357,7 +370,7 @@ interface SSelect extends Setting {
|
||||
value: string;
|
||||
}
|
||||
class DOMSelect extends DOMSetting implements SSelect {
|
||||
type: string = "bool";
|
||||
type: SettingType = SelectType;
|
||||
private _options: string[][];
|
||||
|
||||
get options(): string[][] { return this._options; }
|
||||
@ -395,7 +408,7 @@ interface SNote extends Setting {
|
||||
class DOMNote extends DOMSetting implements SNote {
|
||||
private _nameEl: HTMLElement;
|
||||
private _description: HTMLElement;
|
||||
type: string = "note";
|
||||
type: SettingType = NoteType;
|
||||
private _style: string;
|
||||
|
||||
// We're a note, no one depends on us so we don't need to broadcast a state change.
|
||||
@ -457,9 +470,9 @@ class DOMNote extends DOMSetting implements SNote {
|
||||
}
|
||||
|
||||
interface Section {
|
||||
section: string;
|
||||
meta: Meta;
|
||||
order: string[];
|
||||
settings: { [settingName: string]: Setting };
|
||||
settings: Setting[];
|
||||
}
|
||||
|
||||
class sectionPanel {
|
||||
@ -491,50 +504,49 @@ class sectionPanel {
|
||||
this.update(s);
|
||||
}
|
||||
update = (s: Section) => {
|
||||
for (let name of s.order) {
|
||||
let setting: Setting = s.settings[name];
|
||||
if (name in this._settings) {
|
||||
this._settings[name].update(setting);
|
||||
for (let setting of s.settings) {
|
||||
if (setting.setting in this._settings) {
|
||||
this._settings[setting.setting].update(setting);
|
||||
} else {
|
||||
if (setting.deprecated) continue;
|
||||
switch (setting.type) {
|
||||
case "text":
|
||||
setting = new DOMText(setting, this._sectionName, name);
|
||||
case TextType:
|
||||
setting = new DOMText(setting, this._sectionName, setting.setting);
|
||||
break;
|
||||
case "password":
|
||||
setting = new DOMPassword(setting, this._sectionName, name);
|
||||
case PasswordType:
|
||||
setting = new DOMPassword(setting, this._sectionName, setting.setting);
|
||||
break;
|
||||
case "email":
|
||||
setting = new DOMEmail(setting, this._sectionName, name);
|
||||
case EmailType:
|
||||
setting = new DOMEmail(setting, this._sectionName, setting.setting);
|
||||
break;
|
||||
case "number":
|
||||
setting = new DOMNumber(setting, this._sectionName, name);
|
||||
case NumberType:
|
||||
setting = new DOMNumber(setting, this._sectionName, setting.setting);
|
||||
break;
|
||||
case "bool":
|
||||
setting = new DOMBool(setting as SBool, this._sectionName, name);
|
||||
case BoolType:
|
||||
setting = new DOMBool(setting as SBool, this._sectionName, setting.setting);
|
||||
break;
|
||||
case "select":
|
||||
setting = new DOMSelect(setting as SSelect, this._sectionName, name);
|
||||
case SelectType:
|
||||
setting = new DOMSelect(setting as SSelect, this._sectionName, setting.setting);
|
||||
break;
|
||||
case "note":
|
||||
case NoteType:
|
||||
setting = new DOMNote(setting as SNote, this._sectionName);
|
||||
break;
|
||||
case "list":
|
||||
setting = new DOMList(setting as SList, this._sectionName, name);
|
||||
case ListType:
|
||||
setting = new DOMList(setting as SList, this._sectionName, setting.setting);
|
||||
break;
|
||||
}
|
||||
if (setting.type != "note") {
|
||||
this.values[name] = ""+setting.value;
|
||||
this.values[setting.setting] = ""+setting.value;
|
||||
// settings-section-name: Implies the setting changed or was shown/hidden.
|
||||
// settings-set-section-name: Implies the setting changed.
|
||||
document.addEventListener(`settings-set-${this._sectionName}-${name}`, (event: CustomEvent) => {
|
||||
document.addEventListener(`settings-set-${this._sectionName}-${setting.setting}`, (event: CustomEvent) => {
|
||||
// const oldValue = this.values[name];
|
||||
this.values[name] = event.detail;
|
||||
this.values[setting.setting] = event.detail;
|
||||
document.dispatchEvent(new CustomEvent("settings-section-changed"));
|
||||
});
|
||||
}
|
||||
this._section.appendChild(setting.asElement());
|
||||
this._settings[name] = setting;
|
||||
this._settings[setting.setting] = setting;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -552,8 +564,7 @@ class sectionPanel {
|
||||
}
|
||||
|
||||
interface Settings {
|
||||
order: string[];
|
||||
sections: { [sectionName: string]: Section };
|
||||
sections: Section[];
|
||||
}
|
||||
|
||||
export class settingsList {
|
||||
@ -854,65 +865,65 @@ export class settingsList {
|
||||
}
|
||||
addLoader(this._loader, false, true);
|
||||
_get("/config", null, (req: XMLHttpRequest) => {
|
||||
if (req.readyState == 4) {
|
||||
if (req.status != 200) {
|
||||
window.notifications.customError("settingsLoadError", window.lang.notif("errorLoadSettings"));
|
||||
return;
|
||||
}
|
||||
this._settings = req.response as Settings;
|
||||
for (let name of this._settings.order) {
|
||||
if (name in this._sections) {
|
||||
this._sections[name].update(this._settings.sections[name]);
|
||||
} else {
|
||||
if (name == "messages" || name == "user_page") {
|
||||
const editButton = document.createElement("div");
|
||||
editButton.classList.add("tooltip", "left");
|
||||
editButton.innerHTML = `
|
||||
<span class="button ~neutral @low">
|
||||
<i class="icon ri-edit-line"></i>
|
||||
</span>
|
||||
<span class="content sm">
|
||||
${window.lang.get("strings", "customizeMessages")}
|
||||
</span>
|
||||
`;
|
||||
(editButton.querySelector("span.button") as HTMLSpanElement).onclick = () => {
|
||||
this._messageEditor.showList(name == "messages" ? "email" : "user");
|
||||
};
|
||||
this.addSection(name, this._settings.sections[name], editButton);
|
||||
} else if (name == "updates") {
|
||||
const icon = document.createElement("span") as HTMLSpanElement;
|
||||
if (window.updater.updateAvailable) {
|
||||
icon.classList.add("button", "~urge");
|
||||
icon.innerHTML = `<i class="ri-download-line" title="${window.lang.strings("update")}"></i>`;
|
||||
icon.onclick = () => window.updater.checkForUpdates(window.modals.updateInfo.show);
|
||||
}
|
||||
this.addSection(name, this._settings.sections[name], icon);
|
||||
} else if (name == "matrix" && !window.matrixEnabled) {
|
||||
const addButton = document.createElement("div");
|
||||
addButton.classList.add("tooltip", "left");
|
||||
addButton.innerHTML = `
|
||||
<span class="button ~neutral @low">+</span>
|
||||
<span class="content sm">
|
||||
${window.lang.strings("linkMatrix")}
|
||||
</span>
|
||||
`;
|
||||
(addButton.querySelector("span.button") as HTMLSpanElement).onclick = this._addMatrix;
|
||||
this.addSection(name, this._settings.sections[name], addButton);
|
||||
} else {
|
||||
this.addSection(name, this._settings.sections[name]);
|
||||
if (req.readyState != 4) return;
|
||||
if (req.status != 200) {
|
||||
window.notifications.customError("settingsLoadError", window.lang.notif("errorLoadSettings"));
|
||||
return;
|
||||
}
|
||||
this._settings = req.response as Settings;
|
||||
for (let section of this._settings.sections) {
|
||||
if (section.meta.disabled) continue;
|
||||
if (section.section in this._sections) {
|
||||
this._sections[section.section].update(section);
|
||||
} else {
|
||||
if (section.section == "messages" || section.section == "user_page") {
|
||||
const editButton = document.createElement("div");
|
||||
editButton.classList.add("tooltip", "left");
|
||||
editButton.innerHTML = `
|
||||
<span class="button ~neutral @low">
|
||||
<i class="icon ri-edit-line"></i>
|
||||
</span>
|
||||
<span class="content sm">
|
||||
${window.lang.get("strings", "customizeMessages")}
|
||||
</span>
|
||||
`;
|
||||
(editButton.querySelector("span.button") as HTMLSpanElement).onclick = () => {
|
||||
this._messageEditor.showList(section.section == "messages" ? "email" : "user");
|
||||
};
|
||||
this.addSection(section.section, section, editButton);
|
||||
} else if (section.section == "updates") {
|
||||
const icon = document.createElement("span") as HTMLSpanElement;
|
||||
if (window.updater.updateAvailable) {
|
||||
icon.classList.add("button", "~urge");
|
||||
icon.innerHTML = `<i class="ri-download-line" title="${window.lang.strings("update")}"></i>`;
|
||||
icon.onclick = () => window.updater.checkForUpdates(window.modals.updateInfo.show);
|
||||
}
|
||||
this.addSection(section.section, section, icon);
|
||||
} else if (section.section == "matrix" && !window.matrixEnabled) {
|
||||
const addButton = document.createElement("div");
|
||||
addButton.classList.add("tooltip", "left");
|
||||
addButton.innerHTML = `
|
||||
<span class="button ~neutral @low">+</span>
|
||||
<span class="content sm">
|
||||
${window.lang.strings("linkMatrix")}
|
||||
</span>
|
||||
`;
|
||||
(addButton.querySelector("span.button") as HTMLSpanElement).onclick = this._addMatrix;
|
||||
this.addSection(section.section, section, addButton);
|
||||
} else {
|
||||
this.addSection(section.section, section);
|
||||
}
|
||||
}
|
||||
removeLoader(this._loader);
|
||||
for (let i = 0; i < this._loader.children.length; i++) {
|
||||
this._loader.children[i].classList.remove("invisible");
|
||||
}
|
||||
this._showPanel(this._settings.order[0]);
|
||||
document.dispatchEvent(new CustomEvent("settings-loaded"));
|
||||
document.dispatchEvent(new CustomEvent("settings-advancedState", { detail: false }));
|
||||
this._saveButton.classList.add("unfocused");
|
||||
this._needsRestart = false;
|
||||
}
|
||||
removeLoader(this._loader);
|
||||
for (let i = 0; i < this._loader.children.length; i++) {
|
||||
this._loader.children[i].classList.remove("invisible");
|
||||
}
|
||||
this._showPanel(this._settings.sections[0].section);
|
||||
document.dispatchEvent(new CustomEvent("settings-loaded"));
|
||||
document.dispatchEvent(new CustomEvent("settings-advancedState", { detail: false }));
|
||||
this._saveButton.classList.add("unfocused");
|
||||
this._needsRestart = false;
|
||||
})
|
||||
};
|
||||
|
||||
@ -923,31 +934,31 @@ export class settingsList {
|
||||
if (query.replace(/\s+/g, "") == "") query = "";
|
||||
|
||||
let firstVisibleSection = "";
|
||||
for (let section of this._settings.order) {
|
||||
for (let section of this._settings.sections) {
|
||||
|
||||
let dependencyCard = this._sections[section].asElement().querySelector(".settings-dependency-message");
|
||||
let dependencyCard = this._sections[section.section].asElement().querySelector(".settings-dependency-message");
|
||||
if (dependencyCard) dependencyCard.remove();
|
||||
dependencyCard = null;
|
||||
let dependencyList = null;
|
||||
|
||||
// hide button, unhide if matched
|
||||
this._buttons[section].classList.add("unfocused");
|
||||
this._buttons[section.section].classList.add("unfocused");
|
||||
|
||||
let matchedSection = false;
|
||||
|
||||
if (section.toLowerCase().includes(query) ||
|
||||
this._settings.sections[section].meta.name.toLowerCase().includes(query) ||
|
||||
this._settings.sections[section].meta.description.toLowerCase().includes(query)) {
|
||||
if ((this._settings.sections[section].meta.advanced && this._advanced) || !(this._settings.sections[section].meta.advanced)) {
|
||||
this._buttons[section].classList.remove("unfocused");
|
||||
firstVisibleSection = firstVisibleSection || section;
|
||||
if (section.section.toLowerCase().includes(query) ||
|
||||
section.meta.name.toLowerCase().includes(query) ||
|
||||
section.meta.description.toLowerCase().includes(query)) {
|
||||
if ((section.meta.advanced && this._advanced) || !(section.meta.advanced)) {
|
||||
this._buttons[section.section].classList.remove("unfocused");
|
||||
firstVisibleSection = firstVisibleSection || section.section;
|
||||
matchedSection = true;
|
||||
}
|
||||
}
|
||||
const sectionElement = this._sections[section].asElement();
|
||||
for (let setting of this._settings.sections[section].order) {
|
||||
if (this._settings.sections[section].settings[setting].type == "note") continue;
|
||||
const element = sectionElement.querySelector(`div[data-name="${setting}"]`) as HTMLElement;
|
||||
const sectionElement = this._sections[section.section].asElement();
|
||||
for (let setting of section.settings) {
|
||||
if (setting.type == "note") continue;
|
||||
const element = sectionElement.querySelector(`div[data-name="${setting.setting}"]`) as HTMLElement;
|
||||
|
||||
// If we match the whole section, don't bother searching settings.
|
||||
if (matchedSection) {
|
||||
@ -959,17 +970,17 @@ export class settingsList {
|
||||
// element.classList.remove("-mx-2", "my-2", "p-2", "aside", "~neutral", "@low");
|
||||
element.classList.add("opacity-50", "pointer-events-none");
|
||||
element.setAttribute("aria-disabled", "true");
|
||||
if (setting.toLowerCase().includes(query) ||
|
||||
this._settings.sections[section].settings[setting].name.toLowerCase().includes(query) ||
|
||||
this._settings.sections[section].settings[setting].description.toLowerCase().includes(query) ||
|
||||
String(this._settings.sections[section].settings[setting].value).toLowerCase().includes(query)) {
|
||||
if ((this._settings.sections[section].meta.advanced && this._advanced) || !(this._settings.sections[section].meta.advanced)) {
|
||||
this._buttons[section].classList.remove("unfocused");
|
||||
firstVisibleSection = firstVisibleSection || section;
|
||||
if (setting.setting.toLowerCase().includes(query) ||
|
||||
setting.name.toLowerCase().includes(query) ||
|
||||
setting.description.toLowerCase().includes(query) ||
|
||||
String(setting.value).toLowerCase().includes(query)) {
|
||||
if ((section.meta.advanced && this._advanced) || !(section.meta.advanced)) {
|
||||
this._buttons[section.section].classList.remove("unfocused");
|
||||
firstVisibleSection = firstVisibleSection || section.section;
|
||||
}
|
||||
const shouldShow = (query != "" &&
|
||||
((this._settings.sections[section].settings[setting].advanced && this._advanced) ||
|
||||
!(this._settings.sections[section].settings[setting].advanced)));
|
||||
((setting.advanced && this._advanced) ||
|
||||
!(setting.advanced)));
|
||||
if (shouldShow || query == "") {
|
||||
// element.classList.add("-mx-2", "my-2", "p-2", "aside", "~neutral", "@low");
|
||||
element.classList.remove("opacity-50", "pointer-events-none");
|
||||
@ -989,21 +1000,21 @@ export class settingsList {
|
||||
`;
|
||||
dependencyList = dependencyCard.querySelector(".settings-dependency-list") as HTMLUListElement;
|
||||
// Insert it right after the description
|
||||
this._sections[section].asElement().insertBefore(dependencyCard, this._sections[section].asElement().querySelector(".settings-section-description").nextElementSibling);
|
||||
this._sections[section.section].asElement().insertBefore(dependencyCard, this._sections[section.section].asElement().querySelector(".settings-section-description").nextElementSibling);
|
||||
}
|
||||
const li = document.createElement("li");
|
||||
if (shouldShow) {
|
||||
const depCode = this._settings.sections[section].settings[setting].depends_true || this._settings.sections[section].settings[setting].depends_false;
|
||||
const dep = splitDependant(section, depCode);
|
||||
const depCode = setting.depends_true || setting.depends_false;
|
||||
const dep = splitDependant(section.section, depCode);
|
||||
|
||||
let depName = this._settings.sections[dep[0]].settings[dep[1]].name;
|
||||
if (dep[0] != section) {
|
||||
if (dep[0] != section.section) {
|
||||
depName = this._settings.sections[dep[0]].meta.name + " > " + depName;
|
||||
}
|
||||
|
||||
li.textContent = window.lang.strings("settingsDependsOn").replace("{setting}", `"`+this._settings.sections[section].settings[setting].name+`"`).replace("{dependency}", `"`+depName+`"`);
|
||||
li.textContent = window.lang.strings("settingsDependsOn").replace("{setting}", `"`+setting.name+`"`).replace("{dependency}", `"`+depName+`"`);
|
||||
} else {
|
||||
li.textContent = window.lang.strings("settingsAdvancedMode").replace("{setting}", `"`+this._settings.sections[section].settings[setting].name+`"`);
|
||||
li.textContent = window.lang.strings("settingsAdvancedMode").replace("{setting}", `"`+setting.name+`"`);
|
||||
}
|
||||
dependencyList.appendChild(li);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user