mirror of
https://github.com/hrfee/jfa-go.git
synced 2024-12-29 12:30:11 +00:00
Compare commits
No commits in common. "a11ac1b1a30d112704977bd3fda3ef26d63b0918" and "fcdd4e4518822e6a9e98bcab364cd57bebf07ea8" have entirely different histories.
a11ac1b1a3
...
fcdd4e4518
@ -116,7 +116,7 @@ archives:
|
|||||||
checksum:
|
checksum:
|
||||||
name_template: 'checksums.txt'
|
name_template: 'checksums.txt'
|
||||||
snapshot:
|
snapshot:
|
||||||
version_template: "0.0.0-{{ .Env.JFA_GO_NFPM_EPOCH }}"
|
name_template: "0.0.0-{{ .Env.JFA_GO_NFPM_EPOCH }}"
|
||||||
changelog:
|
changelog:
|
||||||
sort: asc
|
sort: asc
|
||||||
filters:
|
filters:
|
||||||
|
43
Makefile
43
Makefile
@ -1,4 +1,4 @@
|
|||||||
.PHONY: configuration email typescript swagger copy compile compress inline-css variants-html install clean npm config-description config-default precompile
|
.PHONY: configuration email typescript swagger copy compile compress tailwind bundle-css inline-css variants-html install clean npm config-description config-default precompile
|
||||||
|
|
||||||
all: compile
|
all: compile
|
||||||
|
|
||||||
@ -101,22 +101,20 @@ else
|
|||||||
SWAGINSTALL :=
|
SWAGINSTALL :=
|
||||||
endif
|
endif
|
||||||
|
|
||||||
CONFIG_BASE = config/config-base.yaml
|
CONFIG_BASE = config/config-base.json
|
||||||
|
|
||||||
# CONFIG_DESCRIPTION = $(DATA)/config-base.json
|
CONFIG_DESCRIPTION = $(DATA)/config-base.json
|
||||||
CONFIG_DEFAULT = $(DATA)/config-default.ini
|
CONFIG_DEFAULT = $(DATA)/config-default.ini
|
||||||
# $(CONFIG_DESCRIPTION) &: $(CONFIG_BASE)
|
$(CONFIG_DESCRIPTION) &: $(CONFIG_BASE)
|
||||||
# $(info Fixing config-base)
|
$(info Fixing config-base)
|
||||||
# -mkdir -p $(DATA)
|
-mkdir -p $(DATA)
|
||||||
|
python3 scripts/enumerate_config.py -i config/config-base.json -o $(DATA)/config-base.json
|
||||||
|
|
||||||
$(DATA):
|
$(CONFIG_DEFAULT) &: $(CONFIG_BASE)
|
||||||
mkdir -p $(DATA)
|
|
||||||
|
|
||||||
$(CONFIG_DEFAULT): $(DATA) $(CONFIG_BASE)
|
|
||||||
$(info Generating config-default.ini)
|
$(info Generating config-default.ini)
|
||||||
go run scripts/ini/main.go -in $(CONFIG_BASE) -out $(DATA)/config-default.ini
|
python3 scripts/generate_ini.py -i config/config-base.json -o $(DATA)/config-default.ini
|
||||||
|
|
||||||
configuration: $(CONFIG_DEFAULT)
|
configuration: $(CONFIG_DESCRIPTION) $(CONFIG_DEFAULT)
|
||||||
|
|
||||||
EMAIL_SRC_MJML = $(wildcard mail/*.mjml)
|
EMAIL_SRC_MJML = $(wildcard mail/*.mjml)
|
||||||
EMAIL_SRC_TXT = $(wildcard mail/*.txt)
|
EMAIL_SRC_TXT = $(wildcard mail/*.txt)
|
||||||
@ -127,9 +125,7 @@ EMAIL_ALL = $(EMAIL_HTML) $(EMAIL_TXT)
|
|||||||
EMAIL_TARGET = mail/confirmation.html
|
EMAIL_TARGET = mail/confirmation.html
|
||||||
$(EMAIL_TARGET): $(EMAIL_SRC_MJML) $(EMAIL_SRC_TXT)
|
$(EMAIL_TARGET): $(EMAIL_SRC_MJML) $(EMAIL_SRC_TXT)
|
||||||
$(info Generating email html)
|
$(info Generating email html)
|
||||||
npx mjml mail/*.mjml -o $(DATA)/
|
python3 scripts/compile_mjml.py -o $(DATA)/
|
||||||
$(info Copying plaintext mail)
|
|
||||||
cp mail/*.txt $(DATA)/
|
|
||||||
|
|
||||||
TYPESCRIPT_FULLSRC = $(shell find ts/ -type f -name "*.ts")
|
TYPESCRIPT_FULLSRC = $(shell find ts/ -type f -name "*.ts")
|
||||||
TYPESCRIPT_SRC = $(wildcard ts/*.ts)
|
TYPESCRIPT_SRC = $(wildcard ts/*.ts)
|
||||||
@ -183,6 +179,8 @@ $(CSS_FULLTARGET): $(TYPESCRIPT_TARGET) $(VARIANTS_TARGET) $(ALL_CSS_SRC) $(wild
|
|||||||
# mv $(CSS_BUNDLE) $(DATA)/web/css/$(CSSVERSION)bundle.css
|
# mv $(CSS_BUNDLE) $(DATA)/web/css/$(CSSVERSION)bundle.css
|
||||||
# npx postcss -o $(CSS_TARGET) $(CSS_TARGET)
|
# npx postcss -o $(CSS_TARGET) $(CSS_TARGET)
|
||||||
|
|
||||||
|
bundle-css: tailwind
|
||||||
|
|
||||||
INLINE_SRC = html/crash.html
|
INLINE_SRC = html/crash.html
|
||||||
INLINE_TARGET = $(DATA)/crash.html
|
INLINE_TARGET = $(DATA)/crash.html
|
||||||
$(INLINE_TARGET): $(CSS_FULLTARGET) $(INLINE_SRC)
|
$(INLINE_TARGET): $(CSS_FULLTARGET) $(INLINE_SRC)
|
||||||
@ -199,8 +197,6 @@ COPY_SRC = images/banner.svg jfa-go.service LICENSE $(LANG_SRC) $(STATIC_SRC)
|
|||||||
COPY_TARGET = $(DATA)/jfa-go.service
|
COPY_TARGET = $(DATA)/jfa-go.service
|
||||||
# $(DATA)/LICENSE $(LANG_TARGET) $(STATIC_TARGET) $(DATA)/web/css/$(CSSVERSION)bundle.css
|
# $(DATA)/LICENSE $(LANG_TARGET) $(STATIC_TARGET) $(DATA)/web/css/$(CSSVERSION)bundle.css
|
||||||
$(COPY_TARGET): $(INLINE_TARGET) $(STATIC_SRC) $(LANG_SRC)
|
$(COPY_TARGET): $(INLINE_TARGET) $(STATIC_SRC) $(LANG_SRC)
|
||||||
$(info copying $(CONFIG_BASE))
|
|
||||||
cp $(CONFIG_BASE) $(DATA)/
|
|
||||||
$(info copying crash page)
|
$(info copying crash page)
|
||||||
cp $(DATA)/crash.html $(DATA)/html/
|
cp $(DATA)/crash.html $(DATA)/html/
|
||||||
$(info copying static data)
|
$(info copying static data)
|
||||||
@ -213,11 +209,11 @@ $(COPY_TARGET): $(INLINE_TARGET) $(STATIC_SRC) $(LANG_SRC)
|
|||||||
cp -r lang $(DATA)/
|
cp -r lang $(DATA)/
|
||||||
cp LICENSE $(DATA)/
|
cp LICENSE $(DATA)/
|
||||||
|
|
||||||
precompile: $(CONFIG_DEFAULT) $(EMAIL_TARGET) $(COPY_TARGET) $(SWAGGER_TARGET)
|
precompile: $(CONFIG_DESCRIPTION) $(CONFIG_DEFAULT) $(EMAIL_TARGET) $(COPY_TARGET) $(SWAGGER_TARGET)
|
||||||
|
|
||||||
GO_SRC = $(shell find ./ -name "*.go")
|
GO_SRC = $(shell find ./ -name "*.go")
|
||||||
GO_TARGET = build/jfa-go
|
GO_TARGET = build/jfa-go
|
||||||
$(GO_TARGET): $(CONFIG_DEFAULT) $(EMAIL_TARGET) $(COPY_TARGET) $(SWAGGER_TARGET) $(GO_SRC) go.mod go.sum
|
$(GO_TARGET): $(CONFIG_DESCRIPTION) $(CONFIG_DEFAULT) $(EMAIL_TARGET) $(COPY_TARGET) $(SWAGGER_TARGET) $(GO_SRC) go.mod go.sum
|
||||||
$(info Downloading deps)
|
$(info Downloading deps)
|
||||||
$(GOBINARY) mod download
|
$(GOBINARY) mod download
|
||||||
$(info Building)
|
$(info Building)
|
||||||
@ -229,6 +225,15 @@ compile: $(GO_TARGET)
|
|||||||
compress:
|
compress:
|
||||||
upx --lzma build/jfa-go
|
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:
|
install:
|
||||||
cp -r build $(DESTDIR)/jfa-go
|
cp -r build $(DESTDIR)/jfa-go
|
||||||
|
|
||||||
|
157
api.go
157
api.go
@ -6,7 +6,6 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/hrfee/jfa-go/common"
|
|
||||||
lm "github.com/hrfee/jfa-go/logmessages"
|
lm "github.com/hrfee/jfa-go/logmessages"
|
||||||
"github.com/hrfee/mediabrowser"
|
"github.com/hrfee/mediabrowser"
|
||||||
"github.com/itchyny/timefmt-go"
|
"github.com/itchyny/timefmt-go"
|
||||||
@ -230,15 +229,102 @@ func (app *appContext) ResetSetPassword(gc *gin.Context) {
|
|||||||
|
|
||||||
// @Summary Get jfa-go configuration.
|
// @Summary Get jfa-go configuration.
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Success 200 {object} common.Config "Uses the same format as config-base.json"
|
// @Success 200 {object} settings "Uses the same format as config-base.json"
|
||||||
// @Router /config [get]
|
// @Router /config [get]
|
||||||
// @Security Bearer
|
// @Security Bearer
|
||||||
// @tags Configuration
|
// @tags Configuration
|
||||||
func (app *appContext) GetConfig(gc *gin.Context) {
|
func (app *appContext) GetConfig(gc *gin.Context) {
|
||||||
if discordEnabled {
|
resp := app.configBase
|
||||||
app.PatchConfigDiscordRoles()
|
// 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
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
gc.JSON(200, app.patchedConfig)
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
}
|
}
|
||||||
|
|
||||||
// @Summary Modify app config.
|
// @Summary Modify app config.
|
||||||
@ -254,46 +340,35 @@ func (app *appContext) ModifyConfig(gc *gin.Context) {
|
|||||||
gc.BindJSON(&req)
|
gc.BindJSON(&req)
|
||||||
// Load a new config, as we set various default values in app.config that shouldn't be stored.
|
// Load a new config, as we set various default values in app.config that shouldn't be stored.
|
||||||
tempConfig, _ := ini.ShadowLoad(app.configPath)
|
tempConfig, _ := ini.ShadowLoad(app.configPath)
|
||||||
for _, section := range app.configBase.Sections {
|
for section, settings := range req {
|
||||||
ns, ok := req[section.Section]
|
if section != "restart-program" {
|
||||||
if !ok {
|
_, err := tempConfig.GetSection(section)
|
||||||
continue
|
if err != nil {
|
||||||
}
|
tempConfig.NewSection(section)
|
||||||
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
|
|
||||||
}
|
}
|
||||||
// Patch disabled to actually be an empty string
|
for setting, value := range settings.(map[string]interface{}) {
|
||||||
if section.Section == "email" && setting.Setting == "method" && newValue == "disabled" {
|
if section == "email" && setting == "method" && value == "disabled" {
|
||||||
newValue = ""
|
value = ""
|
||||||
}
|
}
|
||||||
// Copy language preference for chatbots to root one in "telegram"
|
if (section == "discord" || section == "matrix") && setting == "language" {
|
||||||
if (section.Section == "discord" || section.Section == "matrix") && setting.Setting == "language" {
|
tempConfig.Section("telegram").Key("language").SetValue(value.(string))
|
||||||
iniSection.Key("language").SetValue(newValue.(string))
|
} else if app.configBase.Sections[section].Settings[setting].Type == "list" {
|
||||||
} else if setting.Type == common.ListType {
|
splitValues := strings.Split(value.(string), "|")
|
||||||
splitValues := strings.Split(newValue.(string), "|")
|
// Delete the key first to get rid of any shadow values
|
||||||
// Delete the key first to get rid of any shadow values
|
tempConfig.Section(section).DeleteKey(setting)
|
||||||
iniSection.DeleteKey(setting.Setting)
|
for i, v := range splitValues {
|
||||||
for i, v := range splitValues {
|
if i == 0 {
|
||||||
if i == 0 {
|
tempConfig.Section(section).Key(setting).SetValue(v)
|
||||||
iniSection.Key(setting.Setting).SetValue(v)
|
} else {
|
||||||
} else {
|
tempConfig.Section(section).Key(setting).AddShadow(v)
|
||||||
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")
|
tempConfig.Section("").Key("first_run").SetValue("false")
|
||||||
if err := tempConfig.SaveTo(app.configPath); err != nil {
|
if err := tempConfig.SaveTo(app.configPath); err != nil {
|
||||||
app.err.Printf(lm.FailedWriting, app.configPath, err)
|
app.err.Printf(lm.FailedWriting, app.configPath, err)
|
||||||
@ -306,8 +381,6 @@ func (app *appContext) ModifyConfig(gc *gin.Context) {
|
|||||||
app.Restart()
|
app.Restart()
|
||||||
}
|
}
|
||||||
app.loadConfig()
|
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.
|
// Reinitialize password validator on config change, as opposed to every applicable request like in python.
|
||||||
if _, ok := req["password_validation"]; ok {
|
if _, ok := req["password_validation"]; ok {
|
||||||
validatorConf := ValidatorConf{
|
validatorConf := ValidatorConf{
|
||||||
|
1
auth.go
1
auth.go
@ -251,7 +251,6 @@ func (app *appContext) getTokenLogin(gc *gin.Context) {
|
|||||||
// host := gc.Request.URL.Hostname()
|
// host := gc.Request.URL.Hostname()
|
||||||
host := app.ExternalDomain
|
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.SetCookie("refresh", refresh, REFRESH_TOKEN_VALIDITY_SEC, "/", host, true, true)
|
||||||
gc.JSON(200, getTokenDTO{token})
|
gc.JSON(200, getTokenDTO{token})
|
||||||
}
|
}
|
||||||
|
@ -1,62 +0,0 @@
|
|||||||
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
|
replace github.com/hrfee/jfa-go/logmessages => ../logmessages
|
||||||
|
|
||||||
go 1.18
|
go 1.22.4
|
||||||
|
|
||||||
require github.com/hrfee/jfa-go/logmessages v0.0.0-20240806200606-6308db495a0a
|
require github.com/hrfee/jfa-go/logmessages v0.0.0-20240806200606-6308db495a0a
|
||||||
|
96
config.go
96
config.go
@ -10,7 +10,6 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/hrfee/jfa-go/common"
|
|
||||||
"github.com/hrfee/jfa-go/easyproxy"
|
"github.com/hrfee/jfa-go/easyproxy"
|
||||||
lm "github.com/hrfee/jfa-go/logmessages"
|
lm "github.com/hrfee/jfa-go/logmessages"
|
||||||
"gopkg.in/ini.v1"
|
"gopkg.in/ini.v1"
|
||||||
@ -251,98 +250,3 @@ func (app *appContext) loadConfig() error {
|
|||||||
|
|
||||||
return nil
|
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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
4
config/README.md
Normal file
4
config/README.md
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
### 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 +0,0 @@
|
|||||||
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.
|
|
2179
config/config-base.json
Normal file
2179
config/config-base.json
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1,35 +0,0 @@
|
|||||||
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)
|
|
@ -1,40 +0,0 @@
|
|||||||
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
|
module github.com/hrfee/jfa-go/easyproxy
|
||||||
|
|
||||||
go 1.18
|
go 1.20
|
||||||
|
|
||||||
require golang.org/x/net v0.23.0
|
require golang.org/x/net v0.15.0
|
||||||
|
|
||||||
require github.com/magisterquis/connectproxy v0.0.0-20200725203833-3582e84f0c9b
|
require github.com/magisterquis/connectproxy v0.0.0-20200725203833-3582e84f0c9b // indirect
|
||||||
|
@ -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 h1:xZ59n7Frzh8CwyfAapUZLSg+gXH5m63YEaFCMpDHhpI=
|
||||||
github.com/magisterquis/connectproxy v0.0.0-20200725203833-3582e84f0c9b/go.mod h1:uDd4sYVYsqcxAB8j+Q7uhL6IJCs/r1kxib1HV4bgOMg=
|
github.com/magisterquis/connectproxy v0.0.0-20200725203833-3582e84f0c9b/go.mod h1:uDd4sYVYsqcxAB8j+Q7uhL6IJCs/r1kxib1HV4bgOMg=
|
||||||
golang.org/x/net v0.23.0 h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs=
|
golang.org/x/net v0.15.0 h1:ugBLEUaxABaB5AJqW9enI0ACdci2RUd4eP51NTBvuJ8=
|
||||||
golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
|
golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
|
||||||
|
39
go.mod
39
go.mod
@ -1,8 +1,6 @@
|
|||||||
module github.com/hrfee/jfa-go
|
module github.com/hrfee/jfa-go
|
||||||
|
|
||||||
go 1.22
|
go 1.22.4
|
||||||
|
|
||||||
toolchain go1.22.4
|
|
||||||
|
|
||||||
replace github.com/hrfee/jfa-go/docs => ./docs
|
replace github.com/hrfee/jfa-go/docs => ./docs
|
||||||
|
|
||||||
@ -35,18 +33,18 @@ require (
|
|||||||
github.com/go-telegram-bot-api/telegram-bot-api v4.6.4+incompatible
|
github.com/go-telegram-bot-api/telegram-bot-api v4.6.4+incompatible
|
||||||
github.com/golang-jwt/jwt v3.2.2+incompatible
|
github.com/golang-jwt/jwt v3.2.2+incompatible
|
||||||
github.com/gomarkdown/markdown v0.0.0-20240730141124-034f12af3bf6
|
github.com/gomarkdown/markdown v0.0.0-20240730141124-034f12af3bf6
|
||||||
github.com/hrfee/jfa-go/common v0.0.0-20240824141650-fcdd4e451882
|
github.com/hrfee/jfa-go/common v0.0.0-20240806200606-6308db495a0a
|
||||||
github.com/hrfee/jfa-go/docs v0.0.0-20240824141650-fcdd4e451882
|
github.com/hrfee/jfa-go/docs v0.0.0-20240806200606-6308db495a0a
|
||||||
github.com/hrfee/jfa-go/easyproxy v0.0.0-20240824141650-fcdd4e451882
|
github.com/hrfee/jfa-go/easyproxy v0.0.0-20240806200606-6308db495a0a
|
||||||
github.com/hrfee/jfa-go/jellyseerr v0.0.0-20240824141650-fcdd4e451882
|
github.com/hrfee/jfa-go/jellyseerr v0.0.0-20240806200606-6308db495a0a
|
||||||
github.com/hrfee/jfa-go/linecache v0.0.0-20240824141650-fcdd4e451882
|
github.com/hrfee/jfa-go/linecache v0.0.0-20240806200606-6308db495a0a
|
||||||
github.com/hrfee/jfa-go/logger v0.0.0-20240824141650-fcdd4e451882
|
github.com/hrfee/jfa-go/logger v0.0.0-20240806200606-6308db495a0a
|
||||||
github.com/hrfee/jfa-go/logmessages v0.0.0-20240824141650-fcdd4e451882
|
github.com/hrfee/jfa-go/logmessages v0.0.0-20240806200606-6308db495a0a
|
||||||
github.com/hrfee/jfa-go/ombi v0.0.0-20240824141650-fcdd4e451882
|
github.com/hrfee/jfa-go/ombi v0.0.0-20240806200606-6308db495a0a
|
||||||
github.com/hrfee/mediabrowser v0.3.18
|
github.com/hrfee/mediabrowser v0.3.18
|
||||||
github.com/itchyny/timefmt-go v0.1.6
|
github.com/itchyny/timefmt-go v0.1.6
|
||||||
github.com/lithammer/shortuuid/v3 v3.0.7
|
github.com/lithammer/shortuuid/v3 v3.0.7
|
||||||
github.com/mailgun/mailgun-go/v4 v4.15.0
|
github.com/mailgun/mailgun-go/v4 v4.14.0
|
||||||
github.com/mattn/go-sqlite3 v1.14.22
|
github.com/mattn/go-sqlite3 v1.14.22
|
||||||
github.com/robert-nix/ansihtml v1.0.1
|
github.com/robert-nix/ansihtml v1.0.1
|
||||||
github.com/steambap/captcha v1.4.1
|
github.com/steambap/captcha v1.4.1
|
||||||
@ -56,8 +54,7 @@ require (
|
|||||||
github.com/writeas/go-strip-markdown v2.0.1+incompatible
|
github.com/writeas/go-strip-markdown v2.0.1+incompatible
|
||||||
github.com/xhit/go-simple-mail/v2 v2.16.0
|
github.com/xhit/go-simple-mail/v2 v2.16.0
|
||||||
gopkg.in/ini.v1 v1.67.0
|
gopkg.in/ini.v1 v1.67.0
|
||||||
gopkg.in/yaml.v3 v3.0.1
|
maunium.net/go/mautrix v0.19.0
|
||||||
maunium.net/go/mautrix v0.20.0
|
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
@ -113,8 +110,7 @@ require (
|
|||||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||||
github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c // indirect
|
github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c // indirect
|
||||||
github.com/pelletier/go-toml/v2 v2.2.3 // indirect
|
github.com/pelletier/go-toml/v2 v2.2.2 // indirect
|
||||||
github.com/petermattis/goid v0.0.0-20240813172612-4fcff4a6cae7 // indirect
|
|
||||||
github.com/pkg/errors v0.9.1 // indirect
|
github.com/pkg/errors v0.9.1 // indirect
|
||||||
github.com/rs/zerolog v1.33.0 // indirect
|
github.com/rs/zerolog v1.33.0 // indirect
|
||||||
github.com/swaggo/swag v1.16.3 // indirect
|
github.com/swaggo/swag v1.16.3 // indirect
|
||||||
@ -126,20 +122,21 @@ require (
|
|||||||
github.com/toorop/go-dkim v0.0.0-20240103092955-90b7d1423f92 // indirect
|
github.com/toorop/go-dkim v0.0.0-20240103092955-90b7d1423f92 // indirect
|
||||||
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
|
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
|
||||||
github.com/ugorji/go/codec v1.2.12 // indirect
|
github.com/ugorji/go/codec v1.2.12 // indirect
|
||||||
go.mau.fi/util v0.7.0 // indirect
|
go.mau.fi/util v0.6.0 // indirect
|
||||||
go.opencensus.io v0.24.0 // indirect
|
go.opencensus.io v0.24.0 // indirect
|
||||||
go.opentelemetry.io/otel v1.29.0 // indirect
|
go.opentelemetry.io/otel v1.28.0 // indirect
|
||||||
go.opentelemetry.io/otel/metric v1.29.0 // indirect
|
go.opentelemetry.io/otel/metric v1.28.0 // indirect
|
||||||
go.opentelemetry.io/otel/trace v1.29.0 // indirect
|
go.opentelemetry.io/otel/trace v1.28.0 // indirect
|
||||||
go.uber.org/multierr v1.11.0 // indirect
|
go.uber.org/multierr v1.11.0 // indirect
|
||||||
go.uber.org/zap v1.27.0 // indirect
|
go.uber.org/zap v1.27.0 // indirect
|
||||||
golang.org/x/arch v0.9.0 // indirect
|
golang.org/x/arch v0.9.0 // indirect
|
||||||
golang.org/x/crypto v0.26.0 // indirect
|
golang.org/x/crypto v0.26.0 // indirect
|
||||||
golang.org/x/exp v0.0.0-20240823005443-9b4947da3948 // indirect
|
golang.org/x/exp v0.0.0-20240808152545-0cdaa3abc0fa // indirect
|
||||||
golang.org/x/image v0.19.0 // indirect
|
golang.org/x/image v0.19.0 // indirect
|
||||||
golang.org/x/net v0.28.0 // indirect
|
golang.org/x/net v0.28.0 // indirect
|
||||||
golang.org/x/sys v0.24.0 // indirect
|
golang.org/x/sys v0.24.0 // indirect
|
||||||
golang.org/x/text v0.17.0 // indirect
|
golang.org/x/text v0.17.0 // indirect
|
||||||
golang.org/x/tools v0.24.0 // indirect
|
golang.org/x/tools v0.24.0 // indirect
|
||||||
google.golang.org/protobuf v1.34.2 // indirect
|
google.golang.org/protobuf v1.34.2 // indirect
|
||||||
|
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||||
)
|
)
|
||||||
|
18
go.sum
18
go.sum
@ -258,8 +258,6 @@ 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/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 h1:N9GMNs0XUq5nn3v2TlZHCknF9khSh88MkA1hdRm1o7I=
|
||||||
github.com/mailgun/mailgun-go/v4 v4.14.0/go.mod h1:L9s941Lgk7iB3TgywTPz074pK2Ekkg4kgbnAaAyJ2z8=
|
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-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-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||||
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||||
@ -292,10 +290,6 @@ 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 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 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.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.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
@ -390,25 +384,17 @@ 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=
|
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 h1:W6SyB3Bm/GjenQ5iq8Z8WWdN85Gy2xS6L0wmnR7SVjg=
|
||||||
go.mau.fi/util v0.6.0/go.mod h1:ljYdq3sPfpICc3zMU+/mHV/sa4z0nKxc67hSBwnrk8U=
|
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.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk=
|
||||||
go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0=
|
go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0=
|
||||||
go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo=
|
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.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 h1:/SqNcYk+idO0CxKEUOtKQClMK/MimZihKYMruSMViUo=
|
||||||
go.opentelemetry.io/otel v1.28.0/go.mod h1:q68ijF8Fc8CnMHKyzqL6akLO46ePnjkgfIMIjUIX9z4=
|
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 h1:f0HGvSl1KRAU1DLgLGFjrwVyismPlnuU6JD6bOeuA5Q=
|
||||||
go.opentelemetry.io/otel/metric v1.28.0/go.mod h1:Fb1eVBFZmLVTMb6PPohq3TO9IIhUisDsbJoL/+uQW4s=
|
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.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 h1:GhQ9cUuQGmNDd5BTCP2dAvv75RdMxEfTmYejp+lkx9g=
|
||||||
go.opentelemetry.io/otel/trace v1.28.0/go.mod h1:jPyXzNPg6da9+38HEwElrQiHlVMTnVfM3/yv2OlIHaI=
|
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/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.1.11-0.20210813005559-691160354723/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ=
|
||||||
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
|
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
|
||||||
@ -433,8 +419,6 @@ 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-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 h1:ELnwvuAXPNtPk1TJRuGkI9fDTwym6AYBu0qzT8AcHdI=
|
||||||
golang.org/x/exp v0.0.0-20240808152545-0cdaa3abc0fa/go.mod h1:akd2r19cwCdwSwWeIdzYQGa/EZZyqcOdwWiwj5L5eKQ=
|
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.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 h1:D9FX4QWkLfkeqaC62SonffIIuYdOk/UE2XKUBgRIBIQ=
|
||||||
golang.org/x/image v0.19.0/go.mod h1:y0zrRqlQRWQ5PXaYCOMLTW2fpsxZ8Qh9I/ohnInJEys=
|
golang.org/x/image v0.19.0/go.mod h1:y0zrRqlQRWQ5PXaYCOMLTW2fpsxZ8Qh9I/ohnInJEys=
|
||||||
@ -593,6 +577,4 @@ 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=
|
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 h1:67eSJWam93mw44Q0/1SiOG7zQzXMUknUv5UaWkrODDU=
|
||||||
maunium.net/go/mautrix v0.19.0/go.mod h1:UE+mSQ4sDUuJMbjN0aB9EjQSGgXd48AzMvZ6+QJV1k8=
|
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=
|
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
|
replace github.com/hrfee/jfa-go/common => ../common
|
||||||
|
|
||||||
go 1.18
|
go 1.22.4
|
||||||
|
|
||||||
require github.com/hrfee/jfa-go/common v0.0.0-20240728190513-dabef831d769
|
require github.com/hrfee/jfa-go/common v0.0.0-20240728190513-dabef831d769
|
||||||
|
|
||||||
|
38
lang.go
38
lang.go
@ -1,7 +1,5 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import "github.com/hrfee/jfa-go/common"
|
|
||||||
|
|
||||||
type langMeta struct {
|
type langMeta struct {
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
// Language to fall back on if strings are missing. Defaults to en-us.
|
// Language to fall back on if strings are missing. Defaults to en-us.
|
||||||
@ -15,11 +13,11 @@ type quantityString struct {
|
|||||||
|
|
||||||
type adminLangs map[string]adminLang
|
type adminLangs map[string]adminLang
|
||||||
|
|
||||||
func (ls *adminLangs) getOptions() []common.Option {
|
func (ls *adminLangs) getOptions() [][2]string {
|
||||||
opts := make([]common.Option, len(*ls))
|
opts := make([][2]string, len(*ls))
|
||||||
i := 0
|
i := 0
|
||||||
for key, lang := range *ls {
|
for key, lang := range *ls {
|
||||||
opts[i] = common.Option{key, lang.Meta.Name}
|
opts[i] = [2]string{key, lang.Meta.Name}
|
||||||
i++
|
i++
|
||||||
}
|
}
|
||||||
return opts
|
return opts
|
||||||
@ -44,11 +42,11 @@ type adminLang struct {
|
|||||||
|
|
||||||
type userLangs map[string]userLang
|
type userLangs map[string]userLang
|
||||||
|
|
||||||
func (ls *userLangs) getOptions() []common.Option {
|
func (ls *userLangs) getOptions() [][2]string {
|
||||||
opts := make([]common.Option, len(*ls))
|
opts := make([][2]string, len(*ls))
|
||||||
i := 0
|
i := 0
|
||||||
for key, lang := range *ls {
|
for key, lang := range *ls {
|
||||||
opts[i] = common.Option{key, lang.Meta.Name}
|
opts[i] = [2]string{key, lang.Meta.Name}
|
||||||
i++
|
i++
|
||||||
}
|
}
|
||||||
return opts
|
return opts
|
||||||
@ -67,11 +65,11 @@ type userLang struct {
|
|||||||
|
|
||||||
type pwrLangs map[string]pwrLang
|
type pwrLangs map[string]pwrLang
|
||||||
|
|
||||||
func (ls *pwrLangs) getOptions() []common.Option {
|
func (ls *pwrLangs) getOptions() [][2]string {
|
||||||
opts := make([]common.Option, len(*ls))
|
opts := make([][2]string, len(*ls))
|
||||||
i := 0
|
i := 0
|
||||||
for key, lang := range *ls {
|
for key, lang := range *ls {
|
||||||
opts[i] = common.Option{key, lang.Meta.Name}
|
opts[i] = [2]string{key, lang.Meta.Name}
|
||||||
i++
|
i++
|
||||||
}
|
}
|
||||||
return opts
|
return opts
|
||||||
@ -84,11 +82,11 @@ type pwrLang struct {
|
|||||||
|
|
||||||
type emailLangs map[string]emailLang
|
type emailLangs map[string]emailLang
|
||||||
|
|
||||||
func (ls *emailLangs) getOptions() []common.Option {
|
func (ls *emailLangs) getOptions() [][2]string {
|
||||||
opts := make([]common.Option, len(*ls))
|
opts := make([][2]string, len(*ls))
|
||||||
i := 0
|
i := 0
|
||||||
for key, lang := range *ls {
|
for key, lang := range *ls {
|
||||||
opts[i] = common.Option{key, lang.Meta.Name}
|
opts[i] = [2]string{key, lang.Meta.Name}
|
||||||
i++
|
i++
|
||||||
}
|
}
|
||||||
return opts
|
return opts
|
||||||
@ -137,11 +135,11 @@ type setupLang struct {
|
|||||||
JSON string
|
JSON string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ls *setupLangs) getOptions() []common.Option {
|
func (ls *setupLangs) getOptions() [][2]string {
|
||||||
opts := make([]common.Option, len(*ls))
|
opts := make([][2]string, len(*ls))
|
||||||
i := 0
|
i := 0
|
||||||
for key, lang := range *ls {
|
for key, lang := range *ls {
|
||||||
opts[i] = common.Option{key, lang.Meta.Name}
|
opts[i] = [2]string{key, lang.Meta.Name}
|
||||||
i++
|
i++
|
||||||
}
|
}
|
||||||
return opts
|
return opts
|
||||||
@ -154,11 +152,11 @@ type telegramLang struct {
|
|||||||
Strings langSection `json:"strings"`
|
Strings langSection `json:"strings"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ts *telegramLangs) getOptions() []common.Option {
|
func (ts *telegramLangs) getOptions() [][2]string {
|
||||||
opts := make([]common.Option, len(*ts))
|
opts := make([][2]string, len(*ts))
|
||||||
i := 0
|
i := 0
|
||||||
for key, lang := range *ts {
|
for key, lang := range *ts {
|
||||||
opts[i] = common.Option{key, lang.Meta.Name}
|
opts[i] = [2]string{key, lang.Meta.Name}
|
||||||
i++
|
i++
|
||||||
}
|
}
|
||||||
return opts
|
return opts
|
||||||
|
@ -1,3 +1,3 @@
|
|||||||
module github.com/hrfee/jfa-go/logmessages
|
module github.com/hrfee/jfa-go/logmessages
|
||||||
|
|
||||||
go 1.18
|
go 1.22.4
|
||||||
|
10
main.go
10
main.go
@ -32,7 +32,6 @@ import (
|
|||||||
"github.com/hrfee/mediabrowser"
|
"github.com/hrfee/mediabrowser"
|
||||||
"github.com/lithammer/shortuuid/v3"
|
"github.com/lithammer/shortuuid/v3"
|
||||||
"gopkg.in/ini.v1"
|
"gopkg.in/ini.v1"
|
||||||
"gopkg.in/yaml.v3"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@ -94,8 +93,7 @@ type appContext struct {
|
|||||||
config *ini.File
|
config *ini.File
|
||||||
configPath string
|
configPath string
|
||||||
configBasePath string
|
configBasePath string
|
||||||
configBase common.Config
|
configBase settings
|
||||||
patchedConfig common.Config
|
|
||||||
dataPath string
|
dataPath string
|
||||||
webFS httpFS
|
webFS httpFS
|
||||||
cssClass string // Default theme, "light"|"dark".
|
cssClass string // Default theme, "light"|"dark".
|
||||||
@ -390,11 +388,9 @@ func start(asDaemon, firstCall bool) {
|
|||||||
defer app.storage.db.Close()
|
defer app.storage.db.Close()
|
||||||
|
|
||||||
// Read config-base for settings on web.
|
// Read config-base for settings on web.
|
||||||
app.configBasePath = "config-base.yaml"
|
app.configBasePath = "config-base.json"
|
||||||
configBase, _ := fs.ReadFile(localFS, app.configBasePath)
|
configBase, _ := fs.ReadFile(localFS, app.configBasePath)
|
||||||
yaml.Unmarshal(configBase, &app.configBase)
|
json.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)
|
secret, err := generateSecret(16)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
37
models.go
37
models.go
@ -212,6 +212,43 @@ type errorListDTO map[string]map[string]string
|
|||||||
|
|
||||||
type configDTO map[string]interface{}
|
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 langDTO map[string]string
|
||||||
|
|
||||||
type emailListDTO map[string]emailListEl
|
type emailListDTO map[string]emailListEl
|
||||||
|
@ -2,7 +2,7 @@ module github.com/hrfee/jfa-go/ombi
|
|||||||
|
|
||||||
replace github.com/hrfee/jfa-go/common => ../common
|
replace github.com/hrfee/jfa-go/common => ../common
|
||||||
|
|
||||||
go 1.18
|
go 1.22.4
|
||||||
|
|
||||||
require github.com/hrfee/jfa-go/common v0.0.0-20240806200606-6308db495a0a
|
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",
|
"mjml": "^4.15.3",
|
||||||
"nightwind": "^1.1.13",
|
"nightwind": "^1.1.13",
|
||||||
"perl-regex": "^1.0.4",
|
"perl-regex": "^1.0.4",
|
||||||
"postcss": "^8.4.31",
|
"postcss": "^8.4.24",
|
||||||
"remixicon": "^4.3.0",
|
"remixicon": "^4.3.0",
|
||||||
"remove-markdown": "^0.5.0",
|
"remove-markdown": "^0.5.0",
|
||||||
"tailwindcss": "^3.3.2",
|
"tailwindcss": "^3.3.2",
|
||||||
@ -4669,9 +4669,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/postcss": {
|
"node_modules/postcss": {
|
||||||
"version": "8.4.31",
|
"version": "8.4.24",
|
||||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz",
|
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.24.tgz",
|
||||||
"integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==",
|
"integrity": "sha512-M0RzbcI0sO/XJNucsGjvWU9ERWxb/ytp1w6dKtxTKgixdtQDq4rmx/g8W1hnaheq9jgwL/oyEdH5Bc4WwJKMqg==",
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
"type": "opencollective",
|
"type": "opencollective",
|
||||||
@ -6653,9 +6653,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/uncss/node_modules/ws": {
|
"node_modules/uncss/node_modules/ws": {
|
||||||
"version": "6.2.3",
|
"version": "6.2.2",
|
||||||
"resolved": "https://registry.npmjs.org/ws/-/ws-6.2.3.tgz",
|
"resolved": "https://registry.npmjs.org/ws/-/ws-6.2.2.tgz",
|
||||||
"integrity": "sha512-jmTjYU0j60B+vHey6TfR3Z7RD61z/hmxBS3VMSGIrroOWXQEneK1zNuotOUrGyBHQj0yrpsLHPWtigEFd13ndA==",
|
"integrity": "sha512-zmhltoSR8u1cnDsD43TX59mzoMZsLKqUweyYBAIvTngR3shc0W6aOZylZmq/7hqyVxPdi+5Ud2QInblgyE72fw==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"async-limiter": "~1.0.0"
|
"async-limiter": "~1.0.0"
|
||||||
}
|
}
|
||||||
@ -7167,9 +7167,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/word-wrap": {
|
"node_modules/word-wrap": {
|
||||||
"version": "1.2.5",
|
"version": "1.2.3",
|
||||||
"resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz",
|
"resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz",
|
||||||
"integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==",
|
"integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
}
|
}
|
||||||
@ -7215,9 +7215,9 @@
|
|||||||
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="
|
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="
|
||||||
},
|
},
|
||||||
"node_modules/ws": {
|
"node_modules/ws": {
|
||||||
"version": "8.18.0",
|
"version": "8.13.0",
|
||||||
"resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz",
|
"resolved": "https://registry.npmjs.org/ws/-/ws-8.13.0.tgz",
|
||||||
"integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==",
|
"integrity": "sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=10.0.0"
|
"node": ">=10.0.0"
|
||||||
},
|
},
|
||||||
@ -10690,9 +10690,9 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"postcss": {
|
"postcss": {
|
||||||
"version": "8.4.31",
|
"version": "8.4.24",
|
||||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz",
|
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.24.tgz",
|
||||||
"integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==",
|
"integrity": "sha512-M0RzbcI0sO/XJNucsGjvWU9ERWxb/ytp1w6dKtxTKgixdtQDq4rmx/g8W1hnaheq9jgwL/oyEdH5Bc4WwJKMqg==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"nanoid": "^3.3.6",
|
"nanoid": "^3.3.6",
|
||||||
"picocolors": "^1.0.0",
|
"picocolors": "^1.0.0",
|
||||||
@ -12180,9 +12180,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"ws": {
|
"ws": {
|
||||||
"version": "6.2.3",
|
"version": "6.2.2",
|
||||||
"resolved": "https://registry.npmjs.org/ws/-/ws-6.2.3.tgz",
|
"resolved": "https://registry.npmjs.org/ws/-/ws-6.2.2.tgz",
|
||||||
"integrity": "sha512-jmTjYU0j60B+vHey6TfR3Z7RD61z/hmxBS3VMSGIrroOWXQEneK1zNuotOUrGyBHQj0yrpsLHPWtigEFd13ndA==",
|
"integrity": "sha512-zmhltoSR8u1cnDsD43TX59mzoMZsLKqUweyYBAIvTngR3shc0W6aOZylZmq/7hqyVxPdi+5Ud2QInblgyE72fw==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"async-limiter": "~1.0.0"
|
"async-limiter": "~1.0.0"
|
||||||
}
|
}
|
||||||
@ -12546,9 +12546,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"word-wrap": {
|
"word-wrap": {
|
||||||
"version": "1.2.5",
|
"version": "1.2.3",
|
||||||
"resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz",
|
"resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz",
|
||||||
"integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA=="
|
"integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ=="
|
||||||
},
|
},
|
||||||
"wrap-ansi": {
|
"wrap-ansi": {
|
||||||
"version": "7.0.0",
|
"version": "7.0.0",
|
||||||
@ -12576,9 +12576,9 @@
|
|||||||
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="
|
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="
|
||||||
},
|
},
|
||||||
"ws": {
|
"ws": {
|
||||||
"version": "8.18.0",
|
"version": "8.13.0",
|
||||||
"resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz",
|
"resolved": "https://registry.npmjs.org/ws/-/ws-8.13.0.tgz",
|
||||||
"integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==",
|
"integrity": "sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==",
|
||||||
"requires": {}
|
"requires": {}
|
||||||
},
|
},
|
||||||
"xml-name-validator": {
|
"xml-name-validator": {
|
||||||
|
@ -30,7 +30,7 @@
|
|||||||
"mjml": "^4.15.3",
|
"mjml": "^4.15.3",
|
||||||
"nightwind": "^1.1.13",
|
"nightwind": "^1.1.13",
|
||||||
"perl-regex": "^1.0.4",
|
"perl-regex": "^1.0.4",
|
||||||
"postcss": "^8.4.31",
|
"postcss": "^8.4.24",
|
||||||
"remixicon": "^4.3.0",
|
"remixicon": "^4.3.0",
|
||||||
"remove-markdown": "^0.5.0",
|
"remove-markdown": "^0.5.0",
|
||||||
"tailwindcss": "^3.3.2",
|
"tailwindcss": "^3.3.2",
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
module github.com/hrfee/jfa-go/scripts/account-gen
|
module github.com/hrfee/jfa-go/scripts/account-gen
|
||||||
|
|
||||||
go 1.18
|
go 1.20
|
||||||
|
|
||||||
require github.com/hrfee/mediabrowser v0.3.8 // indirect
|
require github.com/hrfee/mediabrowser v0.3.8 // indirect
|
||||||
|
52
scripts/compile_mjml.py
Executable file
52
scripts/compile_mjml.py
Executable file
@ -0,0 +1,52 @@
|
|||||||
|
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."
|
||||||
|
)
|
29
scripts/enumerate_config.py
Normal file
29
scripts/enumerate_config.py
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
# 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))
|
||||||
|
|
||||||
|
|
47
scripts/generate_ini.py
Normal file
47
scripts/generate_ini.py
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
# 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))
|
@ -1,12 +0,0 @@
|
|||||||
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
|
|
||||||
)
|
|
@ -1,7 +0,0 @@
|
|||||||
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=
|
|
@ -1,130 +0,0 @@
|
|||||||
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": {
|
"node_modules/word-wrap": {
|
||||||
"version": "1.2.5",
|
"version": "1.2.3",
|
||||||
"resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz",
|
"resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz",
|
||||||
"integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==",
|
"integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
}
|
}
|
||||||
@ -7828,9 +7828,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"word-wrap": {
|
"word-wrap": {
|
||||||
"version": "1.2.5",
|
"version": "1.2.3",
|
||||||
"resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz",
|
"resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz",
|
||||||
"integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA=="
|
"integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ=="
|
||||||
},
|
},
|
||||||
"wrappy": {
|
"wrappy": {
|
||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
|
@ -19,33 +19,20 @@ interface settingsChangedEvent extends Event {
|
|||||||
detail: string;
|
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 {
|
interface Meta {
|
||||||
name: string;
|
name: string;
|
||||||
description: string;
|
description: string;
|
||||||
advanced?: boolean;
|
advanced?: boolean;
|
||||||
disabled?: boolean;
|
|
||||||
depends_true?: string;
|
depends_true?: string;
|
||||||
depends_false?: string;
|
depends_false?: string;
|
||||||
wiki_link?: string;
|
wiki_link?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Setting {
|
interface Setting {
|
||||||
setting: string;
|
|
||||||
name: string;
|
name: string;
|
||||||
description: string;
|
description: string;
|
||||||
required?: boolean;
|
required: boolean;
|
||||||
requires_restart?: boolean;
|
requires_restart: boolean;
|
||||||
advanced?: boolean;
|
advanced?: boolean;
|
||||||
type: string;
|
type: string;
|
||||||
value: string | boolean | number | string[];
|
value: string | boolean | number | string[];
|
||||||
@ -80,17 +67,17 @@ class DOMSetting {
|
|||||||
protected _restart: HTMLSpanElement;
|
protected _restart: HTMLSpanElement;
|
||||||
protected _advanced: boolean;
|
protected _advanced: boolean;
|
||||||
protected _section: string;
|
protected _section: string;
|
||||||
setting: string;
|
protected _name: string;
|
||||||
|
|
||||||
hide = () => {
|
hide = () => {
|
||||||
this._hideEl.classList.add("unfocused");
|
this._hideEl.classList.add("unfocused");
|
||||||
const event = new CustomEvent(`settings-${this._section}-${this.setting}`, { "detail": false })
|
const event = new CustomEvent(`settings-${this._section}-${this._name}`, { "detail": false })
|
||||||
document.dispatchEvent(event);
|
document.dispatchEvent(event);
|
||||||
|
|
||||||
};
|
};
|
||||||
show = () => {
|
show = () => {
|
||||||
this._hideEl.classList.remove("unfocused");
|
this._hideEl.classList.remove("unfocused");
|
||||||
const event = new CustomEvent(`settings-${this._section}-${this.setting}`, { "detail": this.valueAsString() })
|
const event = new CustomEvent(`settings-${this._section}-${this._name}`, { "detail": this.valueAsString() })
|
||||||
document.dispatchEvent(event);
|
document.dispatchEvent(event);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -155,8 +142,8 @@ class DOMSetting {
|
|||||||
valueAsString = (): string => { return ""+this.value; };
|
valueAsString = (): string => { return ""+this.value; };
|
||||||
|
|
||||||
onValueChange = () => {
|
onValueChange = () => {
|
||||||
const event = new CustomEvent(`settings-${this._section}-${this.setting}`, { "detail": this.valueAsString() })
|
const event = new CustomEvent(`settings-${this._section}-${this._name}`, { "detail": this.valueAsString() })
|
||||||
const setEvent = new CustomEvent(`settings-set-${this._section}-${this.setting}`, { "detail": this.valueAsString() })
|
const setEvent = new CustomEvent(`settings-set-${this._section}-${this._name}`, { "detail": this.valueAsString() })
|
||||||
document.dispatchEvent(event);
|
document.dispatchEvent(event);
|
||||||
document.dispatchEvent(setEvent);
|
document.dispatchEvent(setEvent);
|
||||||
if (this.requires_restart) { document.dispatchEvent(new CustomEvent("settings-requires-restart")); }
|
if (this.requires_restart) { document.dispatchEvent(new CustomEvent("settings-requires-restart")); }
|
||||||
@ -164,7 +151,7 @@ class DOMSetting {
|
|||||||
|
|
||||||
constructor(input: string, setting: Setting, section: string, name: string, inputOnTop: boolean = false) {
|
constructor(input: string, setting: Setting, section: string, name: string, inputOnTop: boolean = false) {
|
||||||
this._section = section;
|
this._section = section;
|
||||||
this.setting = name;
|
this._name = name;
|
||||||
this._container = document.createElement("div");
|
this._container = document.createElement("div");
|
||||||
this._container.classList.add("setting");
|
this._container.classList.add("setting");
|
||||||
this._container.setAttribute("data-name", name);
|
this._container.setAttribute("data-name", name);
|
||||||
@ -236,7 +223,7 @@ interface SText extends Setting {
|
|||||||
}
|
}
|
||||||
class DOMText extends DOMInput implements SText {
|
class DOMText extends DOMInput implements SText {
|
||||||
constructor(setting: Setting, section: string, name: string) { super("text", setting, section, name); }
|
constructor(setting: Setting, section: string, name: string) { super("text", setting, section, name); }
|
||||||
type: SettingType = TextType;
|
type: string = "text";
|
||||||
get value(): string { return this._input.value }
|
get value(): string { return this._input.value }
|
||||||
set value(v: string) { this._input.value = v; }
|
set value(v: string) { this._input.value = v; }
|
||||||
}
|
}
|
||||||
@ -246,7 +233,7 @@ interface SPassword extends Setting {
|
|||||||
}
|
}
|
||||||
class DOMPassword extends DOMInput implements SPassword {
|
class DOMPassword extends DOMInput implements SPassword {
|
||||||
constructor(setting: Setting, section: string, name: string) { super("password", setting, section, name); }
|
constructor(setting: Setting, section: string, name: string) { super("password", setting, section, name); }
|
||||||
type: SettingType = PasswordType;
|
type: string = "password";
|
||||||
get value(): string { return this._input.value }
|
get value(): string { return this._input.value }
|
||||||
set value(v: string) { this._input.value = v; }
|
set value(v: string) { this._input.value = v; }
|
||||||
}
|
}
|
||||||
@ -256,7 +243,7 @@ interface SEmail extends Setting {
|
|||||||
}
|
}
|
||||||
class DOMEmail extends DOMInput implements SEmail {
|
class DOMEmail extends DOMInput implements SEmail {
|
||||||
constructor(setting: Setting, section: string, name: string) { super("email", setting, section, name); }
|
constructor(setting: Setting, section: string, name: string) { super("email", setting, section, name); }
|
||||||
type: SettingType = EmailType;
|
type: string = "email";
|
||||||
get value(): string { return this._input.value }
|
get value(): string { return this._input.value }
|
||||||
set value(v: string) { this._input.value = v; }
|
set value(v: string) { this._input.value = v; }
|
||||||
}
|
}
|
||||||
@ -266,7 +253,7 @@ interface SNumber extends Setting {
|
|||||||
}
|
}
|
||||||
class DOMNumber extends DOMInput implements SNumber {
|
class DOMNumber extends DOMInput implements SNumber {
|
||||||
constructor(setting: Setting, section: string, name: string) { super("number", setting, section, name); }
|
constructor(setting: Setting, section: string, name: string) { super("number", setting, section, name); }
|
||||||
type: SettingType = NumberType;
|
type: string = "number";
|
||||||
get value(): number { return +this._input.value; }
|
get value(): number { return +this._input.value; }
|
||||||
set value(v: number) { this._input.value = ""+v; }
|
set value(v: number) { this._input.value = ""+v; }
|
||||||
}
|
}
|
||||||
@ -276,7 +263,7 @@ interface SList extends Setting {
|
|||||||
}
|
}
|
||||||
class DOMList extends DOMSetting implements SList {
|
class DOMList extends DOMSetting implements SList {
|
||||||
protected _inputs: HTMLDivElement;
|
protected _inputs: HTMLDivElement;
|
||||||
type: SettingType = ListType;
|
type: string = "list";
|
||||||
|
|
||||||
valueAsString = (): string => { return this.value.join("|"); };
|
valueAsString = (): string => { return this.value.join("|"); };
|
||||||
|
|
||||||
@ -347,7 +334,7 @@ interface SBool extends Setting {
|
|||||||
value: boolean;
|
value: boolean;
|
||||||
}
|
}
|
||||||
class DOMBool extends DOMSetting implements SBool {
|
class DOMBool extends DOMSetting implements SBool {
|
||||||
type: SettingType = BoolType;
|
type: string = "bool";
|
||||||
|
|
||||||
get value(): boolean { return this._input.checked; }
|
get value(): boolean { return this._input.checked; }
|
||||||
set value(state: boolean) { this._input.checked = state; }
|
set value(state: boolean) { this._input.checked = state; }
|
||||||
@ -370,7 +357,7 @@ interface SSelect extends Setting {
|
|||||||
value: string;
|
value: string;
|
||||||
}
|
}
|
||||||
class DOMSelect extends DOMSetting implements SSelect {
|
class DOMSelect extends DOMSetting implements SSelect {
|
||||||
type: SettingType = SelectType;
|
type: string = "bool";
|
||||||
private _options: string[][];
|
private _options: string[][];
|
||||||
|
|
||||||
get options(): string[][] { return this._options; }
|
get options(): string[][] { return this._options; }
|
||||||
@ -408,7 +395,7 @@ interface SNote extends Setting {
|
|||||||
class DOMNote extends DOMSetting implements SNote {
|
class DOMNote extends DOMSetting implements SNote {
|
||||||
private _nameEl: HTMLElement;
|
private _nameEl: HTMLElement;
|
||||||
private _description: HTMLElement;
|
private _description: HTMLElement;
|
||||||
type: SettingType = NoteType;
|
type: string = "note";
|
||||||
private _style: string;
|
private _style: string;
|
||||||
|
|
||||||
// We're a note, no one depends on us so we don't need to broadcast a state change.
|
// We're a note, no one depends on us so we don't need to broadcast a state change.
|
||||||
@ -470,9 +457,9 @@ class DOMNote extends DOMSetting implements SNote {
|
|||||||
}
|
}
|
||||||
|
|
||||||
interface Section {
|
interface Section {
|
||||||
section: string;
|
|
||||||
meta: Meta;
|
meta: Meta;
|
||||||
settings: Setting[];
|
order: string[];
|
||||||
|
settings: { [settingName: string]: Setting };
|
||||||
}
|
}
|
||||||
|
|
||||||
class sectionPanel {
|
class sectionPanel {
|
||||||
@ -504,49 +491,50 @@ class sectionPanel {
|
|||||||
this.update(s);
|
this.update(s);
|
||||||
}
|
}
|
||||||
update = (s: Section) => {
|
update = (s: Section) => {
|
||||||
for (let setting of s.settings) {
|
for (let name of s.order) {
|
||||||
if (setting.setting in this._settings) {
|
let setting: Setting = s.settings[name];
|
||||||
this._settings[setting.setting].update(setting);
|
if (name in this._settings) {
|
||||||
|
this._settings[name].update(setting);
|
||||||
} else {
|
} else {
|
||||||
if (setting.deprecated) continue;
|
if (setting.deprecated) continue;
|
||||||
switch (setting.type) {
|
switch (setting.type) {
|
||||||
case TextType:
|
case "text":
|
||||||
setting = new DOMText(setting, this._sectionName, setting.setting);
|
setting = new DOMText(setting, this._sectionName, name);
|
||||||
break;
|
break;
|
||||||
case PasswordType:
|
case "password":
|
||||||
setting = new DOMPassword(setting, this._sectionName, setting.setting);
|
setting = new DOMPassword(setting, this._sectionName, name);
|
||||||
break;
|
break;
|
||||||
case EmailType:
|
case "email":
|
||||||
setting = new DOMEmail(setting, this._sectionName, setting.setting);
|
setting = new DOMEmail(setting, this._sectionName, name);
|
||||||
break;
|
break;
|
||||||
case NumberType:
|
case "number":
|
||||||
setting = new DOMNumber(setting, this._sectionName, setting.setting);
|
setting = new DOMNumber(setting, this._sectionName, name);
|
||||||
break;
|
break;
|
||||||
case BoolType:
|
case "bool":
|
||||||
setting = new DOMBool(setting as SBool, this._sectionName, setting.setting);
|
setting = new DOMBool(setting as SBool, this._sectionName, name);
|
||||||
break;
|
break;
|
||||||
case SelectType:
|
case "select":
|
||||||
setting = new DOMSelect(setting as SSelect, this._sectionName, setting.setting);
|
setting = new DOMSelect(setting as SSelect, this._sectionName, name);
|
||||||
break;
|
break;
|
||||||
case NoteType:
|
case "note":
|
||||||
setting = new DOMNote(setting as SNote, this._sectionName);
|
setting = new DOMNote(setting as SNote, this._sectionName);
|
||||||
break;
|
break;
|
||||||
case ListType:
|
case "list":
|
||||||
setting = new DOMList(setting as SList, this._sectionName, setting.setting);
|
setting = new DOMList(setting as SList, this._sectionName, name);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (setting.type != "note") {
|
if (setting.type != "note") {
|
||||||
this.values[setting.setting] = ""+setting.value;
|
this.values[name] = ""+setting.value;
|
||||||
// settings-section-name: Implies the setting changed or was shown/hidden.
|
// settings-section-name: Implies the setting changed or was shown/hidden.
|
||||||
// settings-set-section-name: Implies the setting changed.
|
// settings-set-section-name: Implies the setting changed.
|
||||||
document.addEventListener(`settings-set-${this._sectionName}-${setting.setting}`, (event: CustomEvent) => {
|
document.addEventListener(`settings-set-${this._sectionName}-${name}`, (event: CustomEvent) => {
|
||||||
// const oldValue = this.values[name];
|
// const oldValue = this.values[name];
|
||||||
this.values[setting.setting] = event.detail;
|
this.values[name] = event.detail;
|
||||||
document.dispatchEvent(new CustomEvent("settings-section-changed"));
|
document.dispatchEvent(new CustomEvent("settings-section-changed"));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
this._section.appendChild(setting.asElement());
|
this._section.appendChild(setting.asElement());
|
||||||
this._settings[setting.setting] = setting;
|
this._settings[name] = setting;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -564,7 +552,8 @@ class sectionPanel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
interface Settings {
|
interface Settings {
|
||||||
sections: Section[];
|
order: string[];
|
||||||
|
sections: { [sectionName: string]: Section };
|
||||||
}
|
}
|
||||||
|
|
||||||
export class settingsList {
|
export class settingsList {
|
||||||
@ -865,65 +854,65 @@ export class settingsList {
|
|||||||
}
|
}
|
||||||
addLoader(this._loader, false, true);
|
addLoader(this._loader, false, true);
|
||||||
_get("/config", null, (req: XMLHttpRequest) => {
|
_get("/config", null, (req: XMLHttpRequest) => {
|
||||||
if (req.readyState != 4) return;
|
if (req.readyState == 4) {
|
||||||
if (req.status != 200) {
|
if (req.status != 200) {
|
||||||
window.notifications.customError("settingsLoadError", window.lang.notif("errorLoadSettings"));
|
window.notifications.customError("settingsLoadError", window.lang.notif("errorLoadSettings"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this._settings = req.response as Settings;
|
this._settings = req.response as Settings;
|
||||||
for (let section of this._settings.sections) {
|
for (let name of this._settings.order) {
|
||||||
if (section.meta.disabled) continue;
|
if (name in this._sections) {
|
||||||
if (section.section in this._sections) {
|
this._sections[name].update(this._settings.sections[name]);
|
||||||
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 {
|
} else {
|
||||||
this.addSection(section.section, section);
|
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]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
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;
|
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -934,31 +923,31 @@ export class settingsList {
|
|||||||
if (query.replace(/\s+/g, "") == "") query = "";
|
if (query.replace(/\s+/g, "") == "") query = "";
|
||||||
|
|
||||||
let firstVisibleSection = "";
|
let firstVisibleSection = "";
|
||||||
for (let section of this._settings.sections) {
|
for (let section of this._settings.order) {
|
||||||
|
|
||||||
let dependencyCard = this._sections[section.section].asElement().querySelector(".settings-dependency-message");
|
let dependencyCard = this._sections[section].asElement().querySelector(".settings-dependency-message");
|
||||||
if (dependencyCard) dependencyCard.remove();
|
if (dependencyCard) dependencyCard.remove();
|
||||||
dependencyCard = null;
|
dependencyCard = null;
|
||||||
let dependencyList = null;
|
let dependencyList = null;
|
||||||
|
|
||||||
// hide button, unhide if matched
|
// hide button, unhide if matched
|
||||||
this._buttons[section.section].classList.add("unfocused");
|
this._buttons[section].classList.add("unfocused");
|
||||||
|
|
||||||
let matchedSection = false;
|
let matchedSection = false;
|
||||||
|
|
||||||
if (section.section.toLowerCase().includes(query) ||
|
if (section.toLowerCase().includes(query) ||
|
||||||
section.meta.name.toLowerCase().includes(query) ||
|
this._settings.sections[section].meta.name.toLowerCase().includes(query) ||
|
||||||
section.meta.description.toLowerCase().includes(query)) {
|
this._settings.sections[section].meta.description.toLowerCase().includes(query)) {
|
||||||
if ((section.meta.advanced && this._advanced) || !(section.meta.advanced)) {
|
if ((this._settings.sections[section].meta.advanced && this._advanced) || !(this._settings.sections[section].meta.advanced)) {
|
||||||
this._buttons[section.section].classList.remove("unfocused");
|
this._buttons[section].classList.remove("unfocused");
|
||||||
firstVisibleSection = firstVisibleSection || section.section;
|
firstVisibleSection = firstVisibleSection || section;
|
||||||
matchedSection = true;
|
matchedSection = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const sectionElement = this._sections[section.section].asElement();
|
const sectionElement = this._sections[section].asElement();
|
||||||
for (let setting of section.settings) {
|
for (let setting of this._settings.sections[section].order) {
|
||||||
if (setting.type == "note") continue;
|
if (this._settings.sections[section].settings[setting].type == "note") continue;
|
||||||
const element = sectionElement.querySelector(`div[data-name="${setting.setting}"]`) as HTMLElement;
|
const element = sectionElement.querySelector(`div[data-name="${setting}"]`) as HTMLElement;
|
||||||
|
|
||||||
// If we match the whole section, don't bother searching settings.
|
// If we match the whole section, don't bother searching settings.
|
||||||
if (matchedSection) {
|
if (matchedSection) {
|
||||||
@ -970,17 +959,17 @@ export class settingsList {
|
|||||||
// element.classList.remove("-mx-2", "my-2", "p-2", "aside", "~neutral", "@low");
|
// element.classList.remove("-mx-2", "my-2", "p-2", "aside", "~neutral", "@low");
|
||||||
element.classList.add("opacity-50", "pointer-events-none");
|
element.classList.add("opacity-50", "pointer-events-none");
|
||||||
element.setAttribute("aria-disabled", "true");
|
element.setAttribute("aria-disabled", "true");
|
||||||
if (setting.setting.toLowerCase().includes(query) ||
|
if (setting.toLowerCase().includes(query) ||
|
||||||
setting.name.toLowerCase().includes(query) ||
|
this._settings.sections[section].settings[setting].name.toLowerCase().includes(query) ||
|
||||||
setting.description.toLowerCase().includes(query) ||
|
this._settings.sections[section].settings[setting].description.toLowerCase().includes(query) ||
|
||||||
String(setting.value).toLowerCase().includes(query)) {
|
String(this._settings.sections[section].settings[setting].value).toLowerCase().includes(query)) {
|
||||||
if ((section.meta.advanced && this._advanced) || !(section.meta.advanced)) {
|
if ((this._settings.sections[section].meta.advanced && this._advanced) || !(this._settings.sections[section].meta.advanced)) {
|
||||||
this._buttons[section.section].classList.remove("unfocused");
|
this._buttons[section].classList.remove("unfocused");
|
||||||
firstVisibleSection = firstVisibleSection || section.section;
|
firstVisibleSection = firstVisibleSection || section;
|
||||||
}
|
}
|
||||||
const shouldShow = (query != "" &&
|
const shouldShow = (query != "" &&
|
||||||
((setting.advanced && this._advanced) ||
|
((this._settings.sections[section].settings[setting].advanced && this._advanced) ||
|
||||||
!(setting.advanced)));
|
!(this._settings.sections[section].settings[setting].advanced)));
|
||||||
if (shouldShow || query == "") {
|
if (shouldShow || query == "") {
|
||||||
// element.classList.add("-mx-2", "my-2", "p-2", "aside", "~neutral", "@low");
|
// element.classList.add("-mx-2", "my-2", "p-2", "aside", "~neutral", "@low");
|
||||||
element.classList.remove("opacity-50", "pointer-events-none");
|
element.classList.remove("opacity-50", "pointer-events-none");
|
||||||
@ -1000,21 +989,21 @@ export class settingsList {
|
|||||||
`;
|
`;
|
||||||
dependencyList = dependencyCard.querySelector(".settings-dependency-list") as HTMLUListElement;
|
dependencyList = dependencyCard.querySelector(".settings-dependency-list") as HTMLUListElement;
|
||||||
// Insert it right after the description
|
// Insert it right after the description
|
||||||
this._sections[section.section].asElement().insertBefore(dependencyCard, this._sections[section.section].asElement().querySelector(".settings-section-description").nextElementSibling);
|
this._sections[section].asElement().insertBefore(dependencyCard, this._sections[section].asElement().querySelector(".settings-section-description").nextElementSibling);
|
||||||
}
|
}
|
||||||
const li = document.createElement("li");
|
const li = document.createElement("li");
|
||||||
if (shouldShow) {
|
if (shouldShow) {
|
||||||
const depCode = setting.depends_true || setting.depends_false;
|
const depCode = this._settings.sections[section].settings[setting].depends_true || this._settings.sections[section].settings[setting].depends_false;
|
||||||
const dep = splitDependant(section.section, depCode);
|
const dep = splitDependant(section, depCode);
|
||||||
|
|
||||||
let depName = this._settings.sections[dep[0]].settings[dep[1]].name;
|
let depName = this._settings.sections[dep[0]].settings[dep[1]].name;
|
||||||
if (dep[0] != section.section) {
|
if (dep[0] != section) {
|
||||||
depName = this._settings.sections[dep[0]].meta.name + " > " + depName;
|
depName = this._settings.sections[dep[0]].meta.name + " > " + depName;
|
||||||
}
|
}
|
||||||
|
|
||||||
li.textContent = window.lang.strings("settingsDependsOn").replace("{setting}", `"`+setting.name+`"`).replace("{dependency}", `"`+depName+`"`);
|
li.textContent = window.lang.strings("settingsDependsOn").replace("{setting}", `"`+this._settings.sections[section].settings[setting].name+`"`).replace("{dependency}", `"`+depName+`"`);
|
||||||
} else {
|
} else {
|
||||||
li.textContent = window.lang.strings("settingsAdvancedMode").replace("{setting}", `"`+setting.name+`"`);
|
li.textContent = window.lang.strings("settingsAdvancedMode").replace("{setting}", `"`+this._settings.sections[section].settings[setting].name+`"`);
|
||||||
}
|
}
|
||||||
dependencyList.appendChild(li);
|
dependencyList.appendChild(li);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user