diff --git a/api.go b/api.go index 8cbf83a..f3a8e91 100644 --- a/api.go +++ b/api.go @@ -1468,37 +1468,38 @@ func (app *appContext) SetEmail(gc *gin.Context) { respondBool(400, false, gc) return } - if id == "UserCreated" { + switch id { + case "UserCreated": app.storage.customEmails.UserCreated.Content = req.Content app.storage.customEmails.UserCreated.Enabled = true - } else if id == "InviteExpiry" { + case "InviteExpiry": app.storage.customEmails.InviteExpiry.Content = req.Content app.storage.customEmails.InviteExpiry.Enabled = true - } else if id == "PasswordReset" { + case "PasswordReset": app.storage.customEmails.PasswordReset.Content = req.Content app.storage.customEmails.PasswordReset.Enabled = true - } else if id == "UserDeleted" { + case "UserDeleted": app.storage.customEmails.UserDeleted.Content = req.Content app.storage.customEmails.UserDeleted.Enabled = true - } else if id == "UserDisabled" { + case "UserDisabled": app.storage.customEmails.UserDisabled.Content = req.Content app.storage.customEmails.UserDisabled.Enabled = true - } else if id == "UserEnabled" { + case "UserEnabled": app.storage.customEmails.UserEnabled.Content = req.Content app.storage.customEmails.UserEnabled.Enabled = true - } else if id == "InviteEmail" { + case "InviteEmail": app.storage.customEmails.InviteEmail.Content = req.Content app.storage.customEmails.InviteEmail.Enabled = true - } else if id == "WelcomeEmail" { + case "WelcomeEmail": app.storage.customEmails.WelcomeEmail.Content = req.Content app.storage.customEmails.WelcomeEmail.Enabled = true - } else if id == "EmailConfirmation" { + case "EmailConfirmation": app.storage.customEmails.EmailConfirmation.Content = req.Content app.storage.customEmails.EmailConfirmation.Enabled = true - } else if id == "UserExpired" { + case "UserExpired": app.storage.customEmails.UserExpired.Content = req.Content app.storage.customEmails.UserExpired.Enabled = true - } else { + default: respondBool(400, false, gc) return } @@ -1525,27 +1526,28 @@ func (app *appContext) SetEmailState(gc *gin.Context) { } else if s != "disable" { respondBool(400, false, gc) } - if id == "UserCreated" { + switch id { + case "UserCreated": app.storage.customEmails.UserCreated.Enabled = enabled - } else if id == "InviteExpiry" { + case "InviteExpiry": app.storage.customEmails.InviteExpiry.Enabled = enabled - } else if id == "PasswordReset" { + case "PasswordReset": app.storage.customEmails.PasswordReset.Enabled = enabled - } else if id == "UserDeleted" { + case "UserDeleted": app.storage.customEmails.UserDeleted.Enabled = enabled - } else if id == "UserDisabled" { + case "UserDisabled": app.storage.customEmails.UserDisabled.Enabled = enabled - } else if id == "UserEnabled" { + case "UserEnabled": app.storage.customEmails.UserEnabled.Enabled = enabled - } else if id == "InviteEmail" { + case "InviteEmail": app.storage.customEmails.InviteEmail.Enabled = enabled - } else if id == "WelcomeEmail" { + case "WelcomeEmail": app.storage.customEmails.WelcomeEmail.Enabled = enabled - } else if id == "EmailConfirmation" { + case "EmailConfirmation": app.storage.customEmails.EmailConfirmation.Enabled = enabled - } else if id == "UserExpired" { + case "UserExpired": app.storage.customEmails.UserExpired.Enabled = enabled - } else { + default: respondBool(400, false, gc) return } @@ -1576,7 +1578,8 @@ func (app *appContext) GetEmail(gc *gin.Context) { newEmail := false username := app.storage.lang.Email[lang].Strings.get("username") emailAddress := app.storage.lang.Email[lang].Strings.get("emailAddress") - if id == "UserCreated" { + switch id { + case "UserCreated": content = app.storage.customEmails.UserCreated.Content if content == "" { newEmail = true @@ -1588,7 +1591,7 @@ func (app *appContext) GetEmail(gc *gin.Context) { writeVars = func(variables []string) { app.storage.customEmails.UserCreated.Variables = variables } values = app.email.createdValues("xxxxxx", username, emailAddress, Invite{}, app, false) // app.storage.customEmails.UserCreated = content - } else if id == "InviteExpiry" { + case "InviteExpiry": content = app.storage.customEmails.InviteExpiry.Content if content == "" { newEmail = true @@ -1600,7 +1603,7 @@ func (app *appContext) GetEmail(gc *gin.Context) { writeVars = func(variables []string) { app.storage.customEmails.InviteExpiry.Variables = variables } values = app.email.expiryValues("xxxxxx", Invite{}, app, false) // app.storage.customEmails.InviteExpiry = content - } else if id == "PasswordReset" { + case "PasswordReset": content = app.storage.customEmails.PasswordReset.Content if content == "" { newEmail = true @@ -1612,7 +1615,7 @@ func (app *appContext) GetEmail(gc *gin.Context) { writeVars = func(variables []string) { app.storage.customEmails.PasswordReset.Variables = variables } values = app.email.resetValues(PasswordReset{Pin: "12-34-56", Username: username}, app, false) // app.storage.customEmails.PasswordReset = content - } else if id == "UserDeleted" { + case "UserDeleted": content = app.storage.customEmails.UserDeleted.Content if content == "" { newEmail = true @@ -1624,7 +1627,7 @@ func (app *appContext) GetEmail(gc *gin.Context) { writeVars = func(variables []string) { app.storage.customEmails.UserDeleted.Variables = variables } values = app.email.deletedValues(app.storage.lang.Email[lang].Strings.get("reason"), app, false) // app.storage.customEmails.UserDeleted = content - } else if id == "UserDisabled" { + case "UserDisabled": content = app.storage.customEmails.UserDisabled.Content if content == "" { newEmail = true @@ -1636,7 +1639,7 @@ func (app *appContext) GetEmail(gc *gin.Context) { writeVars = func(variables []string) { app.storage.customEmails.UserDisabled.Variables = variables } values = app.email.deletedValues(app.storage.lang.Email[lang].Strings.get("reason"), app, false) // app.storage.customEmails.UserDeleted = content - } else if id == "UserEnabled" { + case "UserEnabled": content = app.storage.customEmails.UserEnabled.Content if content == "" { newEmail = true @@ -1648,7 +1651,7 @@ func (app *appContext) GetEmail(gc *gin.Context) { writeVars = func(variables []string) { app.storage.customEmails.UserEnabled.Variables = variables } values = app.email.deletedValues(app.storage.lang.Email[lang].Strings.get("reason"), app, false) // app.storage.customEmails.UserEnabled = content - } else if id == "InviteEmail" { + case "InviteEmail": content = app.storage.customEmails.InviteEmail.Content if content == "" { newEmail = true @@ -1660,7 +1663,7 @@ func (app *appContext) GetEmail(gc *gin.Context) { writeVars = func(variables []string) { app.storage.customEmails.InviteEmail.Variables = variables } values = app.email.inviteValues("xxxxxx", Invite{}, app, false) // app.storage.customEmails.InviteEmail = content - } else if id == "WelcomeEmail" { + case "WelcomeEmail": content = app.storage.customEmails.WelcomeEmail.Content conditionals = []string{"{yourAccountWillExpire}"} app.storage.customEmails.WelcomeEmail.Conditionals = conditionals @@ -1676,7 +1679,7 @@ func (app *appContext) GetEmail(gc *gin.Context) { } // app.storage.customEmails.WelcomeEmail = content values = app.email.welcomeValues(username, time.Now(), app, false, true) - } else if id == "EmailConfirmation" { + case "EmailConfirmation": content = app.storage.customEmails.EmailConfirmation.Content if content == "" { newEmail = true @@ -1688,7 +1691,7 @@ func (app *appContext) GetEmail(gc *gin.Context) { writeVars = func(variables []string) { app.storage.customEmails.EmailConfirmation.Variables = variables } values = app.email.confirmationValues("xxxxxx", username, "xxxxxx", app, false) // app.storage.customEmails.EmailConfirmation = content - } else if id == "UserExpired" { + case "UserExpired": content = app.storage.customEmails.UserExpired.Content if content == "" { newEmail = true @@ -1699,7 +1702,7 @@ func (app *appContext) GetEmail(gc *gin.Context) { } writeVars = func(variables []string) { app.storage.customEmails.UserExpired.Variables = variables } values = app.email.userExpiredValues(app, false) - } else { + default: respondBool(400, false, gc) return } diff --git a/help.go b/args.go similarity index 50% rename from help.go rename to args.go index 974d371..c06085f 100644 --- a/help.go +++ b/args.go @@ -6,9 +6,75 @@ import ( "flag" "fmt" "os" + "path/filepath" "strings" ) +func (app *appContext) loadArgs(firstCall bool) { + if firstCall { + flag.Usage = helpFunc + help := flag.Bool("help", false, "prints this message.") + flag.BoolVar(help, "h", false, "SHORTHAND") + + DATA = flag.String("data", app.dataPath, "alternate path to data directory.") + flag.StringVar(DATA, "d", app.dataPath, "SHORTHAND") + CONFIG = flag.String("config", app.configPath, "alternate path to config file.") + flag.StringVar(CONFIG, "c", app.configPath, "SHORTHAND") + HOST = flag.String("host", "", "alternate address to host web ui on.") + PORT = flag.Int("port", 0, "alternate port to host web ui on.") + flag.IntVar(PORT, "p", 0, "SHORTHAND") + DEBUG = flag.Bool("debug", false, "Enables debug logging.") + PPROF = flag.Bool("pprof", false, "Exposes pprof profiler on /debug/pprof.") + SWAGGER = flag.Bool("swagger", false, "Enable swagger at /swagger/index.html") + + flag.Parse() + if *help { + flag.Usage() + os.Exit(0) + } + if *SWAGGER { + os.Setenv("SWAGGER", "1") + } + if *DEBUG { + os.Setenv("DEBUG", "1") + } + if *PPROF { + os.Setenv("PPROF", "1") + } + } + + if os.Getenv("SWAGGER") == "1" { + *SWAGGER = true + } + if os.Getenv("DEBUG") == "1" { + *DEBUG = true + } + if os.Getenv("PPROF") == "1" { + *PPROF = true + } + // attempt to apply command line flags correctly + if app.configPath == *CONFIG && app.dataPath != *DATA { + app.dataPath = *DATA + app.configPath = filepath.Join(app.dataPath, "config.ini") + } else if app.configPath != *CONFIG && app.dataPath == *DATA { + app.configPath = *CONFIG + } else { + app.configPath = *CONFIG + app.dataPath = *DATA + } + + // Previously used for self-restarts but leaving them here as they might be useful. + if v := os.Getenv("JFA_CONFIGPATH"); v != "" { + app.configPath = v + } + if v := os.Getenv("JFA_DATAPATH"); v != "" { + app.dataPath = v + } + + os.Setenv("JFA_CONFIGPATH", app.configPath) + os.Setenv("JFA_DATAPATH", app.dataPath) +} + /* Adds start/stop/systemd to help message, and also gets rid of usage for shorthand flags, and merge them with the full-length one. implementation is 🤢, will clean this up eventually. diff --git a/go.mod b/go.mod index c30f1fa..333a4ac 100644 --- a/go.mod +++ b/go.mod @@ -8,6 +8,8 @@ replace github.com/hrfee/jfa-go/common => ./common replace github.com/hrfee/jfa-go/ombi => ./ombi +replace github.com/hrfee/jfa-go/logger => ./logger + require ( github.com/dgrijalva/jwt-go v3.2.0+incompatible github.com/fatih/color v1.10.0 @@ -24,6 +26,7 @@ require ( github.com/google/uuid v1.1.2 // indirect github.com/hrfee/jfa-go/common v0.0.0-20210105184019-fdc97b4e86cc github.com/hrfee/jfa-go/docs v0.0.0-20201112212552-b6f3cd7c1f71 + github.com/hrfee/jfa-go/logger v0.0.0-00010101000000-000000000000 // indirect github.com/hrfee/jfa-go/ombi v0.0.0-20201112212552-b6f3cd7c1f71 github.com/hrfee/mediabrowser v0.3.3 github.com/itchyny/timefmt-go v0.1.2 diff --git a/logger/go.mod b/logger/go.mod new file mode 100644 index 0000000..1c45293 --- /dev/null +++ b/logger/go.mod @@ -0,0 +1,5 @@ +module github.com/hrfee/jfa-go/logger + +go 1.16 + +require github.com/fatih/color v1.10.0 diff --git a/logger/go.sum b/logger/go.sum new file mode 100644 index 0000000..9ee68f3 --- /dev/null +++ b/logger/go.sum @@ -0,0 +1,9 @@ +github.com/fatih/color v1.10.0 h1:s36xzo75JdqLaaWoiEHk767eHiwo0598uUxyfiPkDsg= +github.com/fatih/color v1.10.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM= +github.com/mattn/go-colorable v0.1.8 h1:c1ghPdyEDarC70ftn0y+A/Ee++9zz8ljHG1b13eJ0s8= +github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae h1:/WDfKMnPU+m5M4xB+6x4kaepxRw6jWvR5iDRdvjHgy8= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= diff --git a/logger.go b/logger/logger.go similarity index 80% rename from logger.go rename to logger/logger.go index a2ad4ef..d40792c 100644 --- a/logger.go +++ b/logger/logger.go @@ -1,4 +1,5 @@ -package main +// Package logger provides a wrapper around log that adds color support with github.com/fatih/color. +package logger import ( "io" @@ -99,10 +100,10 @@ func (l logger) Fatalf(format string, v ...interface{}) { l.logger.Fatal(out) } -type emptyLogger bool +type EmptyLogger bool -func (l emptyLogger) Printf(format string, v ...interface{}) {} -func (l emptyLogger) Print(v ...interface{}) {} -func (l emptyLogger) Println(v ...interface{}) {} -func (l emptyLogger) Fatal(v ...interface{}) {} -func (l emptyLogger) Fatalf(format string, v ...interface{}) {} +func (l EmptyLogger) Printf(format string, v ...interface{}) {} +func (l EmptyLogger) Print(v ...interface{}) {} +func (l EmptyLogger) Println(v ...interface{}) {} +func (l EmptyLogger) Fatal(v ...interface{}) {} +func (l EmptyLogger) Fatalf(format string, v ...interface{}) {} diff --git a/main.go b/main.go index 3ec8a01..dab521a 100644 --- a/main.go +++ b/main.go @@ -5,7 +5,6 @@ import ( "crypto/rand" "encoding/base64" "encoding/json" - "flag" "fmt" "io/fs" "log" @@ -24,6 +23,7 @@ import ( "github.com/fatih/color" "github.com/hrfee/jfa-go/common" _ "github.com/hrfee/jfa-go/docs" + "github.com/hrfee/jfa-go/logger" "github.com/hrfee/jfa-go/ombi" "github.com/hrfee/mediabrowser" "github.com/lithammer/shortuuid/v3" @@ -93,7 +93,7 @@ type appContext struct { storage Storage validator Validator email *Emailer - info, debug, err Logger + info, debug, err logger.Logger host string port int version string @@ -165,71 +165,10 @@ func start(asDaemon, firstCall bool) { fs: localFS, } - app.info = NewLogger(os.Stdout, "[INFO] ", log.Ltime, color.FgHiWhite) - app.err = NewLogger(os.Stdout, "[ERROR] ", log.Ltime, color.FgRed) + app.info = logger.NewLogger(os.Stdout, "[INFO] ", log.Ltime, color.FgHiWhite) + app.err = logger.NewLogger(os.Stdout, "[ERROR] ", log.Ltime|log.Lshortfile, color.FgRed) - if firstCall { - flag.Usage = helpFunc - help := flag.Bool("help", false, "prints this message.") - flag.BoolVar(help, "h", false, "SHORTHAND") - - DATA = flag.String("data", app.dataPath, "alternate path to data directory.") - flag.StringVar(DATA, "d", app.dataPath, "SHORTHAND") - CONFIG = flag.String("config", app.configPath, "alternate path to config file.") - flag.StringVar(CONFIG, "c", app.configPath, "SHORTHAND") - HOST = flag.String("host", "", "alternate address to host web ui on.") - PORT = flag.Int("port", 0, "alternate port to host web ui on.") - flag.IntVar(PORT, "p", 0, "SHORTHAND") - DEBUG = flag.Bool("debug", false, "Enables debug logging.") - PPROF = flag.Bool("pprof", false, "Exposes pprof profiler on /debug/pprof.") - SWAGGER = flag.Bool("swagger", false, "Enable swagger at /swagger/index.html") - - flag.Parse() - if *help { - flag.Usage() - os.Exit(0) - } - if *SWAGGER { - os.Setenv("SWAGGER", "1") - } - if *DEBUG { - os.Setenv("DEBUG", "1") - } - if *PPROF { - os.Setenv("PPROF", "1") - } - } - - if os.Getenv("SWAGGER") == "1" { - *SWAGGER = true - } - if os.Getenv("DEBUG") == "1" { - *DEBUG = true - } - if os.Getenv("PPROF") == "1" { - *PPROF = true - } - // attempt to apply command line flags correctly - if app.configPath == *CONFIG && app.dataPath != *DATA { - app.dataPath = *DATA - app.configPath = filepath.Join(app.dataPath, "config.ini") - } else if app.configPath != *CONFIG && app.dataPath == *DATA { - app.configPath = *CONFIG - } else { - app.configPath = *CONFIG - app.dataPath = *DATA - } - - // Previously used for self-restarts but leaving them here as they might be useful. - if v := os.Getenv("JFA_CONFIGPATH"); v != "" { - app.configPath = v - } - if v := os.Getenv("JFA_DATAPATH"); v != "" { - app.dataPath = v - } - - os.Setenv("JFA_CONFIGPATH", app.configPath) - os.Setenv("JFA_DATAPATH", app.dataPath) + app.loadArgs(firstCall) var firstRun bool if _, err := os.Stat(app.dataPath); os.IsNotExist(err) { @@ -256,8 +195,8 @@ func start(asDaemon, firstCall bool) { var debugMode bool var address string - if app.loadConfig() != nil { - app.err.Fatalf("Failed to load config file \"%s\"", app.configPath) + if err := app.loadConfig(); err != nil { + app.err.Fatalf("Failed to load config file \"%s\": %v", app.configPath, err) } app.version = app.config.Section("jellyfin").Key("version").String() // read from config... @@ -267,9 +206,9 @@ func start(asDaemon, firstCall bool) { debugMode = true } if debugMode { - app.debug = NewLogger(os.Stdout, "[DEBUG] ", log.Ltime|log.Lshortfile, color.FgYellow) + app.debug = logger.NewLogger(os.Stdout, "[DEBUG] ", log.Ltime|log.Lshortfile, color.FgYellow) } else { - app.debug = emptyLogger(false) + app.debug = logger.EmptyLogger(false) } if *PPROF { app.info.Print(warning("\n\nWARNING: Don't use pprof in production.\n\n")) @@ -278,9 +217,8 @@ func start(asDaemon, firstCall bool) { // Starts listener to receive commands over a unix socket. Use with 'jfa-go start/stop' if asDaemon { go func() { - socket := SOCK - os.Remove(socket) - listener, err := net.Listen("unix", socket) + os.Remove(SOCK) + listener, err := net.Listen("unix", SOCK) if err != nil { app.err.Fatalf("Couldn't establish socket connection at %s\n", SOCK) } @@ -288,7 +226,7 @@ func start(asDaemon, firstCall bool) { signal.Notify(c, os.Interrupt) go func() { <-c - os.Remove(socket) + os.Remove(SOCK) os.Exit(1) }() defer func() { @@ -298,13 +236,13 @@ func start(asDaemon, firstCall bool) { for { con, err := listener.Accept() if err != nil { - app.err.Printf("Couldn't read message on %s: %s", socket, err) + app.err.Printf("Couldn't read message on %s: %s", SOCK, err) continue } buf := make([]byte, 512) nr, err := con.Read(buf) if err != nil { - app.err.Printf("Couldn't read message on %s: %s", socket, err) + app.err.Printf("Couldn't read message on %s: %s", SOCK, err) continue } command := string(buf[0:nr]) @@ -390,6 +328,7 @@ func start(asDaemon, firstCall bool) { app.storage.profiles_path = app.config.Section("files").Key("user_profiles").String() app.storage.loadProfiles() + // Migrate from pre-0.2.0 user templates to profiles if !(app.storage.policy.BlockedTags == nil && app.storage.configuration.GroupedFolders == nil && len(app.storage.displayprefs) == 0) { app.info.Println("Migrating user template files to new profile format") app.storage.migrateToProfile() @@ -428,7 +367,7 @@ func start(asDaemon, firstCall bool) { "Jellyfin (Dark)": "dark-theme", "Default (Light)": "light-theme", } - // For move from Bootstrap to a17t + // For move from Bootstrap to a17t (0.2.5) if app.config.Section("ui").Key("theme").String() == "Bootstrap (Light)" { app.config.Section("ui").Key("theme").SetValue("Default (Light)") }