Skip to content

Commit 7c0f0b4

Browse files
committed
CI: Apply Go linter recommendations to "internal/config" packages photoprism#5330
Signed-off-by: Michael Mayer <[email protected]>
1 parent 57c9096 commit 7c0f0b4

37 files changed

+219
-133
lines changed

internal/config/cli_context.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ func ApplyCliContext(c interface{}, ctx *cli.Context) error {
3535
if s == "" {
3636
// Omit.
3737
} else if sec := txt.UInt(s); sec > 0 {
38-
fieldValue.Set(reflect.ValueOf(time.Duration(sec) * time.Second))
38+
fieldValue.Set(reflect.ValueOf(time.Duration(sec) * time.Second)) //nolint:gosec // txt.UInt is bounded; duration uses int64 on supported platforms
3939
} else if d, err := time.ParseDuration(s); err == nil {
4040
fieldValue.Set(reflect.ValueOf(d))
4141
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
package config
2+
3+
import (
4+
"flag"
5+
"testing"
6+
"time"
7+
8+
"github.com/stretchr/testify/assert"
9+
"github.com/urfave/cli/v2"
10+
)
11+
12+
type durationTarget struct {
13+
Interval time.Duration `flag:"interval"`
14+
}
15+
16+
func TestApplyCliContext_Duration(t *testing.T) {
17+
tests := []struct {
18+
name string
19+
input string
20+
expected time.Duration
21+
}{
22+
{name: "WithUnits", input: "1h30m", expected: 90 * time.Minute},
23+
{name: "NumericSeconds", input: "30", expected: 30 * time.Second},
24+
{name: "Invalid", input: "not-a-duration", expected: 0},
25+
}
26+
27+
for _, tc := range tests {
28+
tc := tc
29+
t.Run(tc.name, func(t *testing.T) {
30+
t.Parallel()
31+
32+
flags := flag.NewFlagSet("test", flag.ContinueOnError)
33+
flags.String("interval", "", "doc")
34+
app := cli.NewApp()
35+
ctx := cli.NewContext(app, flags, nil)
36+
_ = ctx.Set("interval", tc.input)
37+
38+
target := &durationTarget{}
39+
err := ApplyCliContext(target, ctx)
40+
41+
assert.NoError(t, err)
42+
assert.Equal(t, tc.expected, target.Interval)
43+
})
44+
}
45+
}

internal/config/cli_flag.go

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -99,15 +99,16 @@ func (f CliFlag) CommandFlag() string {
9999

100100
// Usage returns the command flag usage.
101101
func (f CliFlag) Usage() string {
102-
if list.Contains(f.Tags, EnvSponsor) {
102+
switch {
103+
case list.Contains(f.Tags, EnvSponsor):
103104
return f.Flag.GetUsage() + " *members only*"
104-
} else if list.Contains(f.Tags, Pro) {
105+
case list.Contains(f.Tags, Pro):
105106
return f.Flag.GetUsage() + " *pro*"
106-
} else if list.Contains(f.Tags, Plus) {
107+
case list.Contains(f.Tags, Plus):
107108
return f.Flag.GetUsage() + " *plus*"
108-
} else if list.Contains(f.Tags, Essentials) {
109+
case list.Contains(f.Tags, Essentials):
109110
return f.Flag.GetUsage() + " *essentials*"
110-
} else {
111+
default:
111112
return f.Flag.GetUsage()
112113
}
113114
}

internal/config/client_assets.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ func NewClientAssets(buildPath, baseUri string) *ClientAssets {
3838

3939
// Load loads the frontend assets from a webpack manifest file.
4040
func (a *ClientAssets) Load(fileName string) error {
41-
jsonFile, err := os.ReadFile(filepath.Join(a.BuildPath, fileName))
41+
jsonFile, err := os.ReadFile(filepath.Join(a.BuildPath, fileName)) //nolint:gosec // path derived from configured assets directory
4242

4343
if err != nil {
4444
return err
@@ -97,7 +97,7 @@ func (a *ClientAssets) SplashCssFile() string {
9797

9898
// SplashCssFileContents returns the splash screen CSS file contents for embedding in HTML.
9999
func (a *ClientAssets) SplashCssFileContents() template.CSS {
100-
return template.CSS(a.readFile(a.SplashCssFile()))
100+
return template.CSS(a.readFile(a.SplashCssFile())) //nolint:gosec // assets are loaded from trusted local build output
101101
}
102102

103103
// SplashJsUri returns the splash screen JS URI.
@@ -121,14 +121,14 @@ func (a *ClientAssets) SplashJsFileContents() template.JS {
121121
if a.SplashJs == "" {
122122
return ""
123123
}
124-
return template.JS(a.readFile(a.SplashJs))
124+
return template.JS(a.readFile(a.SplashJs)) //nolint:gosec // assets are loaded from trusted local build output
125125
}
126126

127127
// readFile reads the file contents and returns them as string.
128128
func (a *ClientAssets) readFile(fileName string) string {
129129
if fileName == "" {
130130
return ""
131-
} else if css, err := os.ReadFile(filepath.Join(a.BuildPath, fileName)); err != nil {
131+
} else if css, err := os.ReadFile(filepath.Join(a.BuildPath, fileName)); err != nil { //nolint:gosec // path derived from configured assets directory
132132
return ""
133133
} else {
134134
return string(bytes.TrimSpace(css))

internal/config/client_config.go

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -622,7 +622,7 @@ func (c *Config) ClientUser(withSettings bool) *ClientConfig {
622622

623623
// Exclude pictures in review from total count.
624624
if c.Settings().Features.Review {
625-
cfg.Count.All = cfg.Count.All - cfg.Count.Review
625+
cfg.Count.All -= cfg.Count.Review
626626
}
627627

628628
c.Db().
@@ -742,15 +742,16 @@ func (c *Config) ClientRole(role acl.Role) *ClientConfig {
742742

743743
// ClientSession provides the client config values for the specified session.
744744
func (c *Config) ClientSession(sess *entity.Session) (cfg *ClientConfig) {
745-
if sess.NoUser() && sess.IsClient() {
745+
switch {
746+
case sess.NoUser() && sess.IsClient():
746747
cfg = c.ClientUser(false).ApplyACL(acl.Rules, sess.GetClientRole())
747748
cfg.Settings = c.SessionSettings(sess)
748-
} else if sess.GetUser().IsVisitor() {
749+
case sess.GetUser().IsVisitor():
749750
cfg = c.ClientShare()
750-
} else if sess.GetUser().IsRegistered() {
751+
case sess.GetUser().IsRegistered():
751752
cfg = c.ClientUser(false).ApplyACL(acl.Rules, sess.GetUserRole())
752753
cfg.Settings = c.SessionSettings(sess)
753-
} else {
754+
default:
754755
cfg = c.ClientPublic()
755756
}
756757

internal/config/config.go

Lines changed: 16 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,8 @@ import (
4040

4141
"github.com/dustin/go-humanize"
4242
"github.com/jinzhu/gorm"
43-
_ "github.com/jinzhu/gorm/dialects/mysql"
44-
_ "github.com/jinzhu/gorm/dialects/sqlite"
43+
_ "github.com/jinzhu/gorm/dialects/mysql" // register mysql dialect
44+
_ "github.com/jinzhu/gorm/dialects/sqlite" // register sqlite dialect
4545
"github.com/klauspost/cpuid/v2"
4646
gc "github.com/patrickmn/go-cache"
4747
"github.com/pbnjay/memory"
@@ -69,7 +69,6 @@ import (
6969

7070
// Config aggregates CLI flags, options.yml overrides, runtime settings, and shared resources (database, caches) for the running instance.
7171
type Config struct {
72-
once sync.Once
7372
cliCtx *cli.Context
7473
options *Options
7574
settings *customize.Settings
@@ -135,13 +134,14 @@ func initLogger() {
135134
FullTimestamp: true,
136135
})
137136

138-
if Env(EnvProd) {
137+
switch {
138+
case Env(EnvProd):
139139
SetLogLevel(logrus.WarnLevel)
140-
} else if Env(EnvTrace) {
140+
case Env(EnvTrace):
141141
SetLogLevel(logrus.TraceLevel)
142-
} else if Env(EnvDebug) {
142+
case Env(EnvDebug):
143143
SetLogLevel(logrus.DebugLevel)
144-
} else {
144+
default:
145145
SetLogLevel(logrus.InfoLevel)
146146
}
147147
})
@@ -239,7 +239,7 @@ func (c *Config) Init() error {
239239
// Configure HTTPS proxy for outgoing connections.
240240
if httpsProxy := c.HttpsProxy(); httpsProxy != "" {
241241
http.DefaultTransport.(*http.Transport).TLSClientConfig = &tls.Config{
242-
InsecureSkipVerify: c.HttpsProxyInsecure(),
242+
InsecureSkipVerify: c.HttpsProxyInsecure(), //nolint:gosec // proxy settings are user-configurable and opt-in
243243
}
244244

245245
_ = os.Setenv("HTTPS_PROXY", httpsProxy)
@@ -454,15 +454,15 @@ func (c *Config) readSerial() string {
454454
backupName := c.BackupPath(serialName)
455455

456456
if fs.FileExists(storageName) {
457-
if data, err := os.ReadFile(storageName); err == nil && len(data) == 16 {
457+
if data, err := os.ReadFile(storageName); err == nil && len(data) == 16 { //nolint:gosec // path is computed from config storage
458458
return string(data)
459459
} else {
460460
log.Tracef("config: could not read %s (%s)", clean.Log(storageName), err)
461461
}
462462
}
463463

464464
if fs.FileExists(backupName) {
465-
if data, err := os.ReadFile(backupName); err == nil && len(data) == 16 {
465+
if data, err := os.ReadFile(backupName); err == nil && len(data) == 16 { //nolint:gosec // backup file path is generated internally
466466
return string(data)
467467
} else {
468468
log.Tracef("config: could not read %s (%s)", clean.Log(backupName), err)
@@ -729,7 +729,7 @@ func (c *Config) WakeupInterval() time.Duration {
729729
if c.options.WakeupInterval < MinWakeupInterval/time.Second {
730730
return MinWakeupInterval
731731
} else if c.options.WakeupInterval < MinWakeupInterval {
732-
c.options.WakeupInterval = c.options.WakeupInterval * time.Second
732+
c.options.WakeupInterval *= time.Second
733733
}
734734

735735
// Do not run less than once per day.
@@ -786,11 +786,12 @@ func (c *Config) ResolutionLimit() int {
786786

787787
// Disabling or increasing the limit is at your own risk.
788788
// Only sponsors receive support in case of problems.
789-
if result == 0 {
789+
switch {
790+
case result == 0:
790791
return DefaultResolutionLimit
791-
} else if result < 0 {
792+
case result < 0:
792793
return -1
793-
} else if result > 900 {
794+
case result > 900:
794795
result = 900
795796
}
796797

@@ -857,7 +858,7 @@ func (c *Config) initHub() {
857858
c.hubCancel = cancel
858859
c.hubLock.Unlock()
859860

860-
d := 23*time.Hour + time.Duration(float64(2*time.Hour)*rand.Float64())
861+
d := 23*time.Hour + time.Duration(float64(2*time.Hour)*rand.Float64()) //nolint:gosec // jitter for scheduling only, crypto not required
861862
ticker := time.NewTicker(d)
862863

863864
go func() {

internal/config/config_auth.go

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,9 @@ import (
1414
)
1515

1616
const (
17+
// AuthModePublic disables authentication and runs the app in public mode.
1718
AuthModePublic = "public"
19+
// AuthModePasswd enables password-based authentication (default).
1820
AuthModePasswd = "password"
1921
)
2022

@@ -92,7 +94,7 @@ func (c *Config) AdminPassword() string {
9294
} else if fileName := FlagFilePath("ADMIN_PASSWORD"); fileName == "" {
9395
// No password set, this is not an error.
9496
return ""
95-
} else if b, err := os.ReadFile(fileName); err != nil || len(b) == 0 {
97+
} else if b, err := os.ReadFile(fileName); err != nil || len(b) == 0 { //nolint:gosec // path is derived from config directory
9698
log.Warnf("config: failed to read admin password from %s (%s)", fileName, err)
9799
return ""
98100
} else {
@@ -111,11 +113,12 @@ func (c *Config) AdminScope() string {
111113

112114
// PasswordLength returns the minimum password length in characters.
113115
func (c *Config) PasswordLength() int {
114-
if c.Public() {
116+
switch {
117+
case c.Public():
115118
return 0
116-
} else if c.options.PasswordLength < 1 {
119+
case c.options.PasswordLength < 1:
117120
return entity.PasswordLengthDefault
118-
} else if c.options.PasswordLength > txt.ClipPassword {
121+
case c.options.PasswordLength > txt.ClipPassword:
119122
return txt.ClipPassword
120123
}
121124

@@ -194,11 +197,12 @@ func (c *Config) SessionTimeout() int64 {
194197

195198
// SessionCache returns the default session cache duration in seconds.
196199
func (c *Config) SessionCache() int64 {
197-
if c.options.SessionCache == 0 {
200+
switch {
201+
case c.options.SessionCache == 0:
198202
return DefaultSessionCache
199-
} else if c.options.SessionCache < 60 {
203+
case c.options.SessionCache < 60:
200204
return 60
201-
} else if c.options.SessionCache > 3600 {
205+
case c.options.SessionCache > 3600:
202206
return 3600
203207
}
204208

internal/config/config_backup.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,10 @@ import (
88
)
99

1010
const (
11+
// DefaultBackupSchedule defines the default cron schedule for backups.
1112
DefaultBackupSchedule = "daily"
12-
DefaultBackupRetain = 3
13+
// DefaultBackupRetain sets how many backup sets are kept by default.
14+
DefaultBackupRetain = 3
1315
)
1416

1517
// DisableBackups checks if database and album backups as well as YAML sidecar files should not be created.

internal/config/config_cache.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,13 @@ import (
66
gc "github.com/patrickmn/go-cache"
77
)
88

9+
// Cache stores shared config values for quick reuse across requests.
910
var Cache = gc.New(time.Hour, 15*time.Minute)
1011

1112
const (
12-
CacheKeyAppManifest = "app-manifest"
13+
// CacheKeyAppManifest is the cache key for the PWA manifest.
14+
CacheKeyAppManifest = "app-manifest"
15+
// CacheKeyWallpaperUri is the cache key for the current wallpaper URI.
1316
CacheKeyWallpaperUri = "wallpaper-uri"
1417
)
1518

internal/config/config_cluster.go

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,11 @@ import (
2222

2323
// DefaultPortalUrl specifies the default portal URL with variable cluster domain.
2424
var DefaultPortalUrl = "https://portal.${PHOTOPRISM_CLUSTER_DOMAIN}"
25+
26+
// DefaultNodeRole is the default node role assigned when none is configured.
2527
var DefaultNodeRole = cluster.RoleApp
28+
29+
// DefaultJWTAllowedScopes lists default OAuth scopes for cluster-issued JWTs.
2630
var DefaultJWTAllowedScopes = "config cluster vision metrics"
2731

2832
// ClusterDomain returns the cluster DOMAIN (lowercase DNS name; 1–63 chars).
@@ -146,7 +150,7 @@ func (c *Config) JoinToken() string {
146150
}
147151

148152
if fs.FileExistsNotEmpty(fileName) {
149-
if b, err := os.ReadFile(fileName); err != nil || len(b) == 0 {
153+
if b, err := os.ReadFile(fileName); err != nil || len(b) == 0 { //nolint:gosec // path derived from config directory
150154
log.Warnf("config: could not read cluster join token from %s (%s)", fileName, err)
151155
} else if s := strings.TrimSpace(string(b)); rnd.IsJoinToken(s, false) {
152156
if c.cache != nil {
@@ -355,7 +359,7 @@ func (c *Config) NodeClientSecret() string {
355359
return ""
356360
}
357361

358-
if b, err := os.ReadFile(fileName); err == nil && len(b) > 0 {
362+
if b, err := os.ReadFile(fileName); err == nil && len(b) > 0 { //nolint:gosec // path derived from config directory
359363
// Do not cache the value. Always read from the disk to ensure
360364
// that updates from other processes are observed.
361365
return string(b)
@@ -530,7 +534,7 @@ func (c *Config) SaveClusterUUID(uuid string) error {
530534
var m Values
531535

532536
if fs.FileExists(fileName) {
533-
if b, err := os.ReadFile(fileName); err == nil && len(b) > 0 {
537+
if b, err := os.ReadFile(fileName); err == nil && len(b) > 0 { //nolint:gosec // path derived from config directory
534538
_ = yaml.Unmarshal(b, &m)
535539
}
536540
}
@@ -573,7 +577,7 @@ func (c *Config) SaveNodeUUID(uuid string) error {
573577

574578
var m Values
575579
if fs.FileExists(fileName) {
576-
if b, err := os.ReadFile(fileName); err == nil && len(b) > 0 {
580+
if b, err := os.ReadFile(fileName); err == nil && len(b) > 0 { //nolint:gosec // path derived from config directory
577581
_ = yaml.Unmarshal(b, &m)
578582
}
579583
}

0 commit comments

Comments
 (0)