CLI: Upgrade github.com/urfave/cli from v1 to v2 #3168

Signed-off-by: Michael Mayer <michael@photoprism.app>
This commit is contained in:
Michael Mayer
2024-12-05 17:15:59 +01:00
parent 3b61aba85d
commit 9eef183323
103 changed files with 1961 additions and 1642 deletions

View File

@@ -25,7 +25,7 @@ package main
import ( import (
"os" "os"
"github.com/urfave/cli" "github.com/urfave/cli/v2"
"github.com/photoprism/photoprism/internal/commands" "github.com/photoprism/photoprism/internal/commands"
"github.com/photoprism/photoprism/internal/config" "github.com/photoprism/photoprism/internal/config"

3
go.mod
View File

@@ -40,7 +40,6 @@ require (
github.com/tensorflow/tensorflow v1.15.2 github.com/tensorflow/tensorflow v1.15.2
github.com/tidwall/gjson v1.18.0 github.com/tidwall/gjson v1.18.0
github.com/ulule/deepcopier v0.0.0-20200430083143-45decc6639b6 github.com/ulule/deepcopier v0.0.0-20200430083143-45decc6639b6
github.com/urfave/cli v1.22.16
go4.org v0.0.0-20230225012048-214862532bf5 // indirect go4.org v0.0.0-20230225012048-214862532bf5 // indirect
golang.org/x/crypto v0.30.0 golang.org/x/crypto v0.30.0
golang.org/x/net v0.32.0 golang.org/x/net v0.32.0
@@ -85,6 +84,7 @@ require (
github.com/robfig/cron/v3 v3.0.1 github.com/robfig/cron/v3 v3.0.1
github.com/swaggo/files v1.0.1 github.com/swaggo/files v1.0.1
github.com/swaggo/gin-swagger v1.6.0 github.com/swaggo/gin-swagger v1.6.0
github.com/urfave/cli/v2 v2.27.5
github.com/zitadel/oidc/v3 v3.33.1 github.com/zitadel/oidc/v3 v3.33.1
) )
@@ -137,6 +137,7 @@ require (
github.com/tidwall/match v1.1.1 // indirect github.com/tidwall/match v1.1.1 // 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
github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 // indirect
github.com/zitadel/logging v0.6.1 // indirect github.com/zitadel/logging v0.6.1 // indirect
github.com/zitadel/schema v1.3.0 // indirect github.com/zitadel/schema v1.3.0 // indirect
go.opentelemetry.io/otel v1.29.0 // indirect go.opentelemetry.io/otel v1.29.0 // indirect

10
go.sum
View File

@@ -18,7 +18,6 @@ dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7
github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 h1:mFRzDkZVAjdal+s7s0MwaRv9igoPqLRdzOLzw/8Xvq8= github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 h1:mFRzDkZVAjdal+s7s0MwaRv9igoPqLRdzOLzw/8Xvq8=
github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU= github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/BurntSushi/toml v1.4.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc= github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc=
github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE= github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE=
@@ -371,7 +370,6 @@ github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVs
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
@@ -379,8 +377,6 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/sunfish-shogi/bufseekio v0.0.0-20210207115823-a4185644b365/go.mod h1:dEzdXgvImkQ3WLI+0KQpmEx8T/C/ma9KeS3AfmU899I= github.com/sunfish-shogi/bufseekio v0.0.0-20210207115823-a4185644b365/go.mod h1:dEzdXgvImkQ3WLI+0KQpmEx8T/C/ma9KeS3AfmU899I=
@@ -409,8 +405,10 @@ github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65E
github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
github.com/ulule/deepcopier v0.0.0-20200430083143-45decc6639b6 h1:TtyC78WMafNW8QFfv3TeP3yWNDG+uxNkk9vOrnDu6JA= github.com/ulule/deepcopier v0.0.0-20200430083143-45decc6639b6 h1:TtyC78WMafNW8QFfv3TeP3yWNDG+uxNkk9vOrnDu6JA=
github.com/ulule/deepcopier v0.0.0-20200430083143-45decc6639b6/go.mod h1:h8272+G2omSmi30fBXiZDMkmHuOgonplfKIKjQWzlfs= github.com/ulule/deepcopier v0.0.0-20200430083143-45decc6639b6/go.mod h1:h8272+G2omSmi30fBXiZDMkmHuOgonplfKIKjQWzlfs=
github.com/urfave/cli v1.22.16 h1:MH0k6uJxdwdeWQTwhSO42Pwr4YLrNLwBtg1MRgTqPdQ= github.com/urfave/cli/v2 v2.27.5 h1:WoHEJLdsXr6dDWoJgMq/CboDmyY/8HMMH1fTECbih+w=
github.com/urfave/cli v1.22.16/go.mod h1:EeJR6BKodywf4zciqrdw6hpCPk68JO9z5LazXZMn5Po= github.com/urfave/cli/v2 v2.27.5/go.mod h1:3Sevf16NykTbInEnD0yKkjDAeZDS0A6bzhBH5hrMvTQ=
github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 h1:gEOO8jv9F4OT7lGCjxCBTO/36wtF6j2nSip77qHd4x4=
github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1/go.mod h1:Ohn+xnUBiLI6FVj/9LpzZWtj1/D6lUovWYBkxHVV3aM=
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=
github.com/zitadel/logging v0.6.1 h1:Vyzk1rl9Kq9RCevcpX6ujUaTYFX43aa4LkvV1TvUk+Y= github.com/zitadel/logging v0.6.1 h1:Vyzk1rl9Kq9RCevcpX6ujUaTYFX43aa4LkvV1TvUk+Y=
github.com/zitadel/logging v0.6.1/go.mod h1:Y4CyAXHpl3Mig6JOszcV5Rqqsojj+3n7y2F591Mp/ow= github.com/zitadel/logging v0.6.1/go.mod h1:Y4CyAXHpl3Mig6JOszcV5Rqqsojj+3n7y2F591Mp/ow=

View File

@@ -1,7 +1,7 @@
package commands package commands
import ( import (
"github.com/urfave/cli" "github.com/urfave/cli/v2"
) )
// AuthCommands registers the API authentication subcommands. // AuthCommands registers the API authentication subcommands.
@@ -9,17 +9,17 @@ var AuthCommands = cli.Command{
Name: "auth", Name: "auth",
Aliases: []string{"sess"}, Aliases: []string{"sess"},
Usage: "API authentication subcommands", Usage: "API authentication subcommands",
Subcommands: []cli.Command{ Subcommands: []*cli.Command{
AuthListCommand, &AuthListCommand,
AuthAddCommand, &AuthAddCommand,
AuthShowCommand, &AuthShowCommand,
AuthRemoveCommand, &AuthRemoveCommand,
AuthResetCommand, &AuthResetCommand,
}, },
} }
// tokensFlag represents a CLI flag to include tokens in a report. // tokensFlag represents a CLI flag to include tokens in a report.
var tokensFlag = cli.BoolFlag{ var tokensFlag = &cli.BoolFlag{
Name: "tokens", Name: "tokens",
Usage: "show preview and download tokens", Usage: "show preview and download tokens",
} }

View File

@@ -4,7 +4,7 @@ import (
"fmt" "fmt"
"github.com/manifoldco/promptui" "github.com/manifoldco/promptui"
"github.com/urfave/cli" "github.com/urfave/cli/v2"
"github.com/photoprism/photoprism/internal/config" "github.com/photoprism/photoprism/internal/config"
"github.com/photoprism/photoprism/internal/entity" "github.com/photoprism/photoprism/internal/entity"
@@ -17,18 +17,21 @@ import (
// AuthAddFlags specifies the "photoprism auth add" command flags. // AuthAddFlags specifies the "photoprism auth add" command flags.
var AuthAddFlags = []cli.Flag{ var AuthAddFlags = []cli.Flag{
cli.StringFlag{ &cli.StringFlag{
Name: "name, n", Name: "name",
Usage: "`CLIENT` name to help identify the application", Aliases: []string{"n"},
Usage: "`CLIENT` name to help identify the application",
}, },
cli.StringFlag{ &cli.StringFlag{
Name: "scope, s", Name: "scope",
Usage: "authorization `SCOPES` e.g. \"metrics\" or \"photos albums\" (\"*\" to allow all)", Aliases: []string{"s"},
Usage: "authorization `SCOPES` e.g. \"metrics\" or \"photos albums\" (\"*\" to allow all)",
}, },
cli.Int64Flag{ &cli.Int64Flag{
Name: "expires, e", Name: "expires",
Usage: "authentication `LIFETIME` in seconds, after which access expires (-1 to disable the limit)", Aliases: []string{"e"},
Value: unix.Year, Usage: "authentication `LIFETIME` in seconds, after which access expires (-1 to disable the limit)",
Value: unix.Year,
}, },
} }

View File

@@ -12,11 +12,12 @@ func TestAuthAddCommand(t *testing.T) {
var err error var err error
// Create test context with flags and arguments. // Create test context with flags and arguments.
ctx := NewTestContext([]string{"add", "--scope=metrics", "--expires=5000", "--name=alice", "alice"}) args := []string{"add", "--scope=metrics", "--expires=5000", "--name=alice", "alice"}
ctx := NewTestContext(args)
// Run command with test context. // Run command with test context.
output := capture.Output(func() { output := capture.Output(func() {
err = AuthAddCommand.Run(ctx) err = AuthAddCommand.Run(ctx, args...)
}) })
// Check command output for plausibility. // Check command output for plausibility.
@@ -30,11 +31,12 @@ func TestAuthAddCommand(t *testing.T) {
var err error var err error
// Create test context with flags and arguments. // Create test context with flags and arguments.
ctx := NewTestContext([]string{"add", "--scope=test", "--expires=5000", "--name=xyz"}) args := []string{"add", "--scope=test", "--expires=5000", "--name=xyz"}
ctx := NewTestContext(args)
// Run command with test context. // Run command with test context.
output := capture.Output(func() { output := capture.Output(func() {
err = AuthAddCommand.Run(ctx) err = AuthAddCommand.Run(ctx, args...)
}) })
// Check command output for plausibility. // Check command output for plausibility.
@@ -48,11 +50,12 @@ func TestAuthAddCommand(t *testing.T) {
var err error var err error
// Create test context with flags and arguments. // Create test context with flags and arguments.
ctx := NewTestContext([]string{"add", "--scope=test", "--expires=5000", "xxxxx"}) args := []string{"add", "--scope=test", "--expires=5000", "xxxxx"}
ctx := NewTestContext(args)
// Run command with test context. // Run command with test context.
output := capture.Output(func() { output := capture.Output(func() {
err = AuthAddCommand.Run(ctx) err = AuthAddCommand.Run(ctx, args...)
}) })
// Check command output for plausibility. // Check command output for plausibility.
@@ -65,11 +68,12 @@ func TestAuthAddCommand(t *testing.T) {
var err error var err error
// Create test context with flags and arguments. // Create test context with flags and arguments.
ctx := NewTestContext([]string{"add", "--scope=test", "--expires=5000", "alice"}) args := []string{"add", "--scope=test", "--expires=5000", "alice"}
ctx := NewTestContext(args)
// Run command with test context. // Run command with test context.
output := capture.Output(func() { output := capture.Output(func() {
err = AuthAddCommand.Run(ctx) err = AuthAddCommand.Run(ctx, args...)
}) })
// Check command output for plausibility. // Check command output for plausibility.
@@ -81,11 +85,12 @@ func TestAuthAddCommand(t *testing.T) {
var err error var err error
// Create test context with flags and arguments. // Create test context with flags and arguments.
ctx := NewTestContext([]string{"add", "--name=test", "--expires=5000", "alice"}) args := []string{"add", "--name=test", "--expires=5000", "alice"}
ctx := NewTestContext(args)
// Run command with test context. // Run command with test context.
output := capture.Output(func() { output := capture.Output(func() {
err = AuthAddCommand.Run(ctx) err = AuthAddCommand.Run(ctx, args...)
}) })
// Check command output for plausibility. // Check command output for plausibility.

View File

@@ -4,7 +4,7 @@ import (
"fmt" "fmt"
"github.com/dustin/go-humanize/english" "github.com/dustin/go-humanize/english"
"github.com/urfave/cli" "github.com/urfave/cli/v2"
"github.com/photoprism/photoprism/internal/config" "github.com/photoprism/photoprism/internal/config"
"github.com/photoprism/photoprism/internal/entity/query" "github.com/photoprism/photoprism/internal/entity/query"
@@ -32,7 +32,7 @@ func authListAction(ctx *cli.Context) error {
} }
// Fetch sessions from database. // Fetch sessions from database.
results, err := query.Sessions(ctx.Int("n"), 0, "", ctx.Args().First()) results, err := query.Sessions(ctx.Int("count"), 0, "", ctx.Args().First())
if err != nil { if err != nil {
return err return err

View File

@@ -1,6 +1,8 @@
package commands package commands
import ( import (
"fmt"
"runtime/debug"
"testing" "testing"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
@@ -13,11 +15,12 @@ func TestAuthListCommand(t *testing.T) {
var err error var err error
// Create test context with flags and arguments. // Create test context with flags and arguments.
ctx := NewTestContext([]string{"ls"}) args := []string{"ls"}
ctx := NewTestContext(args)
// Run command with test context. // Run command with test context.
output := capture.Output(func() { output := capture.Output(func() {
err = AuthListCommand.Run(ctx) err = AuthListCommand.Run(ctx, args...)
}) })
// Check command output for plausibility. // Check command output for plausibility.
@@ -31,11 +34,12 @@ func TestAuthListCommand(t *testing.T) {
var err error var err error
// Create test context with flags and arguments. // Create test context with flags and arguments.
ctx := NewTestContext([]string{"ls", "alice"}) args := []string{"ls", "alice"}
ctx := NewTestContext(args)
// Run command with test context. // Run command with test context.
output := capture.Output(func() { output := capture.Output(func() {
err = AuthListCommand.Run(ctx) err = AuthListCommand.Run(ctx, args...)
}) })
// Check command output for plausibility. // Check command output for plausibility.
@@ -51,11 +55,12 @@ func TestAuthListCommand(t *testing.T) {
var err error var err error
// Create test context with flags and arguments. // Create test context with flags and arguments.
ctx := NewTestContext([]string{"ls", "--csv", "alice"}) args := []string{"ls", "--csv", "alice"}
ctx := NewTestContext(args)
// Run command with test context. // Run command with test context.
output := capture.Output(func() { output := capture.Output(func() {
err = AuthListCommand.Run(ctx) err = AuthListCommand.Run(ctx, args...)
}) })
// Check command output for plausibility. // Check command output for plausibility.
@@ -70,11 +75,12 @@ func TestAuthListCommand(t *testing.T) {
var err error var err error
// Create test context with flags and arguments. // Create test context with flags and arguments.
ctx := NewTestContext([]string{"ls", "--tokens", "alice"}) args := []string{"ls", "--tokens", "alice"}
ctx := NewTestContext(args)
// Run command with test context. // Run command with test context.
output := capture.Output(func() { output := capture.Output(func() {
err = AuthListCommand.Run(ctx) err = AuthListCommand.Run(ctx, args...)
}) })
// Check command output for plausibility. // Check command output for plausibility.
@@ -90,11 +96,12 @@ func TestAuthListCommand(t *testing.T) {
var err error var err error
// Create test context with flags and arguments. // Create test context with flags and arguments.
ctx := NewTestContext([]string{"ls", "--tokens", "notexisting"}) args := []string{"ls", "--tokens", "notexisting"}
ctx := NewTestContext(args)
// Run command with test context. // Run command with test context.
output := capture.Output(func() { output := capture.Output(func() {
err = AuthListCommand.Run(ctx) err = AuthListCommand.Run(ctx, args...)
}) })
// Check command output for plausibility. // Check command output for plausibility.
@@ -105,12 +112,20 @@ func TestAuthListCommand(t *testing.T) {
t.Run("Error", func(t *testing.T) { t.Run("Error", func(t *testing.T) {
var err error var err error
defer func() {
if r := recover(); r != nil {
err = fmt.Errorf("error: %s \nstack: %s", r, debug.Stack())
assert.Error(t, err)
}
}()
// Create test context with flags and arguments. // Create test context with flags and arguments.
ctx := NewTestContext([]string{"ls", "--xyz", "alice"}) args := []string{"ls", "--xyz", "alice"}
ctx := NewTestContext(args)
// Run command with test context. // Run command with test context.
output := capture.Output(func() { output := capture.Output(func() {
err = AuthListCommand.Run(ctx) err = AuthListCommand.Run(ctx, args...)
}) })
// Check command output for plausibility. // Check command output for plausibility.

View File

@@ -5,7 +5,7 @@ import (
"fmt" "fmt"
"github.com/manifoldco/promptui" "github.com/manifoldco/promptui"
"github.com/urfave/cli" "github.com/urfave/cli/v2"
"github.com/photoprism/photoprism/internal/config" "github.com/photoprism/photoprism/internal/config"
"github.com/photoprism/photoprism/internal/entity/query" "github.com/photoprism/photoprism/internal/entity/query"

View File

@@ -11,10 +11,11 @@ func TestAuthRemoveCommand(t *testing.T) {
t.Run("NotConfirmed", func(t *testing.T) { t.Run("NotConfirmed", func(t *testing.T) {
var err error var err error
ctx0 := NewTestContext([]string{"show", "sessgh6123yt"}) args0 := []string{"show", "sessgh6123yt"}
ctx0 := NewTestContext(args0)
output0 := capture.Output(func() { output0 := capture.Output(func() {
err = AuthShowCommand.Run(ctx0) err = AuthShowCommand.Run(ctx0, args0...)
}) })
//t.Logf(output0) //t.Logf(output0)
@@ -22,11 +23,12 @@ func TestAuthRemoveCommand(t *testing.T) {
assert.NotEmpty(t, output0) assert.NotEmpty(t, output0)
// Create test context with flags and arguments. // Create test context with flags and arguments.
ctx := NewTestContext([]string{"rm", "sessgh6123yt"}) args := []string{"rm", "sessgh6123yt"}
ctx := NewTestContext(args)
// Run command with test context. // Run command with test context.
output := capture.Output(func() { output := capture.Output(func() {
err = AuthRemoveCommand.Run(ctx) err = AuthRemoveCommand.Run(ctx, args...)
}) })
// Check command output for plausibility. // Check command output for plausibility.
@@ -35,7 +37,7 @@ func TestAuthRemoveCommand(t *testing.T) {
assert.Empty(t, output) assert.Empty(t, output)
output1 := capture.Output(func() { output1 := capture.Output(func() {
err = AuthShowCommand.Run(ctx0) err = AuthShowCommand.Run(ctx0, args0...)
}) })
//t.Logf(output1) //t.Logf(output1)

View File

@@ -6,7 +6,7 @@ import (
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
"github.com/manifoldco/promptui" "github.com/manifoldco/promptui"
"github.com/urfave/cli" "github.com/urfave/cli/v2"
"github.com/photoprism/photoprism/internal/config" "github.com/photoprism/photoprism/internal/config"
"github.com/photoprism/photoprism/internal/entity" "github.com/photoprism/photoprism/internal/entity"
@@ -20,13 +20,15 @@ var AuthResetCommand = cli.Command{
Usage: "Resets the authentication of all users and clients", Usage: "Resets the authentication of all users and clients",
Description: AuthResetDescription, Description: AuthResetDescription,
Flags: []cli.Flag{ Flags: []cli.Flag{
cli.BoolFlag{ &cli.BoolFlag{
Name: "trace, t", Name: "trace",
Usage: "show trace logs for debugging", Aliases: []string{"t"},
Usage: "show trace logs for debugging",
}, },
cli.BoolFlag{ &cli.BoolFlag{
Name: "yes, y", Name: "yes",
Usage: "assume \"yes\" and run non-interactively", Aliases: []string{"y"},
Usage: "assume \"yes\" and run non-interactively",
}, },
}, },
Action: authResetAction, Action: authResetAction,

View File

@@ -12,11 +12,12 @@ func TestAuthResetCommand(t *testing.T) {
var err error var err error
// Create test context with flags and arguments. // Create test context with flags and arguments.
ctx0 := NewTestContext([]string{"ls"}) args0 := []string{"ls"}
ctx0 := NewTestContext(args0)
// Run command with test context. // Run command with test context.
output0 := capture.Output(func() { output0 := capture.Output(func() {
err = AuthListCommand.Run(ctx0) err = AuthListCommand.Run(ctx0, args0...)
}) })
// Check command output for plausibility. // Check command output for plausibility.
@@ -26,11 +27,12 @@ func TestAuthResetCommand(t *testing.T) {
assert.Contains(t, output0, "visitor") assert.Contains(t, output0, "visitor")
// Create test context with flags and arguments. // Create test context with flags and arguments.
ctx := NewTestContext([]string{"reset"}) args := []string{"reset"}
ctx := NewTestContext(args)
// Run command with test context. // Run command with test context.
output := capture.Output(func() { output := capture.Output(func() {
err = AuthResetCommand.Run(ctx) err = AuthResetCommand.Run(ctx, args...)
}) })
// Check command output for plausibility. // Check command output for plausibility.
@@ -40,7 +42,7 @@ func TestAuthResetCommand(t *testing.T) {
// Run command with test context. // Run command with test context.
output1 := capture.Output(func() { output1 := capture.Output(func() {
err = AuthListCommand.Run(ctx0) err = AuthListCommand.Run(ctx0, args0...)
}) })
// Check command output for plausibility. // Check command output for plausibility.

View File

@@ -3,7 +3,7 @@ package commands
import ( import (
"fmt" "fmt"
"github.com/urfave/cli" "github.com/urfave/cli/v2"
"github.com/photoprism/photoprism/internal/config" "github.com/photoprism/photoprism/internal/config"
"github.com/photoprism/photoprism/internal/entity/query" "github.com/photoprism/photoprism/internal/entity/query"

View File

@@ -12,15 +12,16 @@ func TestAuthShowCommand(t *testing.T) {
var err error var err error
// Create test context with flags and arguments. // Create test context with flags and arguments.
ctx := NewTestContext([]string{"show", "sess34q3hael"}) args := []string{"show", "sess34q3hael"}
ctx := NewTestContext(args)
// Run command with test context. // Run command with test context.
output := capture.Output(func() { output := capture.Output(func() {
err = AuthShowCommand.Run(ctx) err = AuthShowCommand.Run(ctx, args...)
}) })
// Check command output for plausibility. // Check command output for plausibility.
// t.Logf(output) t.Logf(output)
assert.NoError(t, err) assert.NoError(t, err)
assert.Contains(t, output, "alice") assert.Contains(t, output, "alice")
assert.Contains(t, output, "access_token") assert.Contains(t, output, "access_token")
@@ -30,11 +31,12 @@ func TestAuthShowCommand(t *testing.T) {
var err error var err error
// Create test context with flags and arguments. // Create test context with flags and arguments.
ctx := NewTestContext([]string{"show", "sess34qxxxxx"}) args := []string{"show", "sess34qxxxxx"}
ctx := NewTestContext(args)
// Run command with test context. // Run command with test context.
output := capture.Output(func() { output := capture.Output(func() {
err = AuthShowCommand.Run(ctx) err = AuthShowCommand.Run(ctx, args...)
}) })
// Check command output for plausibility. // Check command output for plausibility.

View File

@@ -13,11 +13,12 @@ func TestAuthCommands(t *testing.T) {
var err error var err error
// Create test context with flags and arguments. // Create test context with flags and arguments.
ctx := NewTestContext([]string{"auth", "ls"}) args := []string{"auth", "ls"}
ctx := NewTestContext(args)
// Run command with test context. // Run command with test context.
output := capture.Output(func() { output := capture.Output(func() {
err = AuthCommands.Run(ctx) err = AuthCommands.Run(ctx, args...)
}) })
// Check command output for plausibility. // Check command output for plausibility.
@@ -31,11 +32,12 @@ func TestAuthCommands(t *testing.T) {
var err error var err error
// Create test context with flags and arguments. // Create test context with flags and arguments.
ctx := NewTestContext([]string{"auth", "ls", "alice"}) args := []string{"auth", "ls", "alice"}
ctx := NewTestContext(args)
// Run command with test context. // Run command with test context.
output := capture.Output(func() { output := capture.Output(func() {
err = AuthCommands.Run(ctx) err = AuthCommands.Run(ctx, args...)
}) })
// Check command output for plausibility. // Check command output for plausibility.

View File

@@ -7,7 +7,7 @@ import (
"time" "time"
"github.com/dustin/go-humanize/english" "github.com/dustin/go-humanize/english"
"github.com/urfave/cli" "github.com/urfave/cli/v2"
"github.com/photoprism/photoprism/internal/config" "github.com/photoprism/photoprism/internal/config"
"github.com/photoprism/photoprism/internal/photoprism/backup" "github.com/photoprism/photoprism/internal/photoprism/backup"
@@ -30,30 +30,35 @@ var BackupCommand = cli.Command{
} }
var backupFlags = []cli.Flag{ var backupFlags = []cli.Flag{
cli.BoolFlag{ &cli.BoolFlag{
Name: "force, f", Name: "force",
Usage: "replace the index database backup file, if it exists", Aliases: []string{"f"},
Usage: "replace the index database backup file, if it exists",
}, },
cli.BoolFlag{ &cli.BoolFlag{
Name: "albums, a", Name: "albums",
Usage: "create YAML files to back up album metadata (in the standard backup path if no other path is specified)", Aliases: []string{"a"},
Usage: "create YAML files to back up album metadata (in the standard backup path if no other path is specified)",
}, },
cli.StringFlag{ &cli.StringFlag{
Name: "albums-path", Name: "albums-path",
Usage: "custom album backup `PATH`", Usage: "custom album backup `PATH`",
}, },
cli.BoolFlag{ &cli.BoolFlag{
Name: "database, index, i", Name: "database",
Usage: "create index database backup (in the backup path with the date as filename if no filename is passed, or sent to stdout if - is passed as filename)", Aliases: []string{"index", "i"},
Usage: "create index database backup (in the backup path with the date as filename if no filename is passed, or sent to stdout if - is passed as filename)",
}, },
cli.StringFlag{ &cli.StringFlag{
Name: "database-path, index-path", Name: "database-path",
Usage: "custom database backup `PATH`", Aliases: []string{"index-path"},
Usage: "custom database backup `PATH`",
}, },
cli.IntFlag{ &cli.IntFlag{
Name: "retain, r", Name: "retain",
Usage: "`NUMBER` of database backups to keep (-1 to keep all)", Aliases: []string{"r"},
Value: config.DefaultBackupRetain, Usage: "`NUMBER` of database backups to keep (-1 to keep all)",
Value: config.DefaultBackupRetain,
}, },
} }

View File

@@ -5,7 +5,7 @@ import (
"time" "time"
"github.com/dustin/go-humanize/english" "github.com/dustin/go-humanize/english"
"github.com/urfave/cli" "github.com/urfave/cli/v2"
"github.com/photoprism/photoprism/internal/photoprism" "github.com/photoprism/photoprism/internal/photoprism"
"github.com/photoprism/photoprism/internal/photoprism/get" "github.com/photoprism/photoprism/internal/photoprism/get"
@@ -20,7 +20,7 @@ var CleanUpCommand = cli.Command{
} }
var cleanUpFlags = []cli.Flag{ var cleanUpFlags = []cli.Flag{
cli.BoolFlag{ &cli.BoolFlag{
Name: "dry", Name: "dry",
Usage: "dry run, don't actually remove anything", Usage: "dry run, don't actually remove anything",
}, },

View File

@@ -1,7 +1,7 @@
package commands package commands
import ( import (
"github.com/urfave/cli" "github.com/urfave/cli/v2"
"github.com/photoprism/photoprism/internal/auth/acl" "github.com/photoprism/photoprism/internal/auth/acl"
"github.com/photoprism/photoprism/pkg/authn" "github.com/photoprism/photoprism/pkg/authn"
@@ -30,59 +30,66 @@ var ClientsCommands = cli.Command{
Name: "clients", Name: "clients",
Aliases: []string{"client"}, Aliases: []string{"client"},
Usage: "Client credentials subcommands", Usage: "Client credentials subcommands",
Subcommands: []cli.Command{ Subcommands: []*cli.Command{
ClientsListCommand, &ClientsListCommand,
ClientsAddCommand, &ClientsAddCommand,
ClientsShowCommand, &ClientsShowCommand,
ClientsModCommand, &ClientsModCommand,
ClientsRemoveCommand, &ClientsRemoveCommand,
ClientsResetCommand, &ClientsResetCommand,
}, },
} }
// ClientAddFlags specifies the "photoprism client add" command flags. // ClientAddFlags specifies the "photoprism client add" command flags.
var ClientAddFlags = []cli.Flag{ var ClientAddFlags = []cli.Flag{
cli.StringFlag{ &cli.StringFlag{
Name: "id", Name: "id",
Usage: ClientIdUsage, Usage: ClientIdUsage,
Hidden: true, Hidden: true,
}, },
cli.StringFlag{ &cli.StringFlag{
Name: "name, n", Name: "name",
Usage: ClientNameUsage, Aliases: []string{"n"},
Usage: ClientNameUsage,
}, },
cli.StringFlag{ &cli.StringFlag{
Name: "role, r", Name: "role",
Usage: ClientRoleUsage, Aliases: []string{"r"},
Value: acl.RoleClient.String(), Usage: ClientRoleUsage,
Value: acl.RoleClient.String(),
}, },
cli.StringFlag{ &cli.StringFlag{
Name: "scope, s", Name: "scope",
Usage: ClientAuthScope, Aliases: []string{"s"},
Usage: ClientAuthScope,
}, },
cli.StringFlag{ &cli.StringFlag{
Name: "provider, p", Name: "provider",
Usage: ClientAuthProvider, Aliases: []string{"p"},
Value: authn.ProviderClient.String(), Usage: ClientAuthProvider,
Hidden: true, Value: authn.ProviderClient.String(),
Hidden: true,
}, },
cli.StringFlag{ &cli.StringFlag{
Name: "method, m", Name: "method",
Usage: ClientAuthMethod, Aliases: []string{"m"},
Value: authn.MethodOAuth2.String(), Usage: ClientAuthMethod,
Hidden: true, Value: authn.MethodOAuth2.String(),
Hidden: true,
}, },
cli.Int64Flag{ &cli.Int64Flag{
Name: "expires, e", Name: "expires",
Usage: ClientAuthExpires, Aliases: []string{"e"},
Value: unix.Day, Usage: ClientAuthExpires,
Value: unix.Day,
}, },
cli.Int64Flag{ &cli.Int64Flag{
Name: "tokens, t", Name: "tokens",
Usage: ClientAuthTokens, Aliases: []string{"t"},
Value: 10, Usage: ClientAuthTokens,
Value: 10,
}, },
cli.StringFlag{ &cli.StringFlag{
Name: "secret", Name: "secret",
Usage: ClientSecretUsage, Usage: ClientSecretUsage,
Hidden: true, Hidden: true,
@@ -91,55 +98,62 @@ var ClientAddFlags = []cli.Flag{
// ClientModFlags specifies the "photoprism client mod" command flags. // ClientModFlags specifies the "photoprism client mod" command flags.
var ClientModFlags = []cli.Flag{ var ClientModFlags = []cli.Flag{
cli.StringFlag{ &cli.StringFlag{
Name: "name, n", Name: "name",
Usage: ClientNameUsage, Aliases: []string{"n"},
Usage: ClientNameUsage,
}, },
cli.StringFlag{ &cli.StringFlag{
Name: "role, r", Name: "role",
Usage: ClientRoleUsage, Aliases: []string{"r"},
Value: acl.RoleClient.String(), Usage: ClientRoleUsage,
Value: acl.RoleClient.String(),
}, },
cli.StringFlag{ &cli.StringFlag{
Name: "scope, s", Name: "scope",
Usage: ClientAuthScope, Aliases: []string{"s"},
Usage: ClientAuthScope,
}, },
cli.StringFlag{ &cli.StringFlag{
Name: "provider, p", Name: "provider",
Usage: ClientAuthProvider, Aliases: []string{"p"},
Value: authn.ProviderClient.String(), Usage: ClientAuthProvider,
Hidden: true, Value: authn.ProviderClient.String(),
Hidden: true,
}, },
cli.StringFlag{ &cli.StringFlag{
Name: "method, m", Name: "method",
Usage: ClientAuthMethod, Aliases: []string{"m"},
Value: authn.MethodOAuth2.String(), Usage: ClientAuthMethod,
Hidden: true, Value: authn.MethodOAuth2.String(),
Hidden: true,
}, },
cli.Int64Flag{ &cli.Int64Flag{
Name: "expires, e", Name: "expires",
Usage: ClientAuthExpires, Aliases: []string{"e"},
Value: unix.Day, Usage: ClientAuthExpires,
Value: unix.Day,
}, },
cli.Int64Flag{ &cli.Int64Flag{
Name: "tokens, t", Name: "tokens",
Usage: ClientAuthTokens, Aliases: []string{"t"},
Value: 10, Usage: ClientAuthTokens,
Value: 10,
}, },
cli.StringFlag{ &cli.StringFlag{
Name: "secret", Name: "secret",
Usage: ClientSecretUsage, Usage: ClientSecretUsage,
Hidden: true, Hidden: true,
}, },
cli.BoolFlag{ &cli.BoolFlag{
Name: "regenerate", Name: "regenerate",
Usage: ClientRegenerateSecret, Usage: ClientRegenerateSecret,
}, },
cli.BoolFlag{ &cli.BoolFlag{
Name: "enable", Name: "enable",
Usage: ClientEnable, Usage: ClientEnable,
}, },
cli.BoolFlag{ &cli.BoolFlag{
Name: "disable", Name: "disable",
Usage: ClientDisable, Usage: ClientDisable,
}, },

View File

@@ -5,7 +5,7 @@ import (
"github.com/dustin/go-humanize/english" "github.com/dustin/go-humanize/english"
"github.com/manifoldco/promptui" "github.com/manifoldco/promptui"
"github.com/urfave/cli" "github.com/urfave/cli/v2"
"github.com/photoprism/photoprism/internal/config" "github.com/photoprism/photoprism/internal/config"
"github.com/photoprism/photoprism/internal/entity" "github.com/photoprism/photoprism/internal/entity"

View File

@@ -11,11 +11,12 @@ func TestClientsAddCommand(t *testing.T) {
t.Run("AddClient", func(t *testing.T) { t.Run("AddClient", func(t *testing.T) {
var err error var err error
ctx := NewTestContext([]string{"add", "--name=Clara Client", "--scope=photos albums", "--expires=5000", "--tokens=2", "clara"}) args := []string{"add", "--name=Clara Client", "--scope=photos albums", "--expires=5000", "--tokens=2", "clara"}
ctx := NewTestContext(args)
// Run command with test context. // Run command with test context.
output := capture.Output(func() { output := capture.Output(func() {
err = ClientsAddCommand.Run(ctx) err = ClientsAddCommand.Run(ctx, args...)
}) })
// Check command output for plausibility. // Check command output for plausibility.

View File

@@ -4,7 +4,7 @@ import (
"fmt" "fmt"
"github.com/dustin/go-humanize/english" "github.com/dustin/go-humanize/english"
"github.com/urfave/cli" "github.com/urfave/cli/v2"
"github.com/photoprism/photoprism/internal/config" "github.com/photoprism/photoprism/internal/config"
"github.com/photoprism/photoprism/internal/entity/query" "github.com/photoprism/photoprism/internal/entity/query"
@@ -26,7 +26,7 @@ func clientsListAction(ctx *cli.Context) error {
cols := []string{"Client ID", "Name", "Authentication Method", "User", "Role", "Scope", "Enabled", "Access Token Lifetime", "Created At"} cols := []string{"Client ID", "Name", "Authentication Method", "User", "Role", "Scope", "Enabled", "Access Token Lifetime", "Created At"}
// Fetch clients from database. // Fetch clients from database.
clients, err := query.Clients(ctx.Int("n"), 0, "", ctx.Args().First()) clients, err := query.Clients(ctx.Int("count"), 0, "", ctx.Args().First())
if err != nil { if err != nil {
return err return err

View File

@@ -1,6 +1,8 @@
package commands package commands
import ( import (
"fmt"
"runtime/debug"
"testing" "testing"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
@@ -13,11 +15,12 @@ func TestClientsListCommand(t *testing.T) {
var err error var err error
// Create test context with flags and arguments. // Create test context with flags and arguments.
ctx := NewTestContext([]string{"ls"}) args := []string{"ls"}
ctx := NewTestContext(args)
// Run command with test context. // Run command with test context.
output := capture.Output(func() { output := capture.Output(func() {
err = ClientsListCommand.Run(ctx) err = ClientsListCommand.Run(ctx, args...)
}) })
// Check command output for plausibility. // Check command output for plausibility.
@@ -32,11 +35,12 @@ func TestClientsListCommand(t *testing.T) {
var err error var err error
// Create test context with flags and arguments. // Create test context with flags and arguments.
ctx := NewTestContext([]string{"ls", "monitoring"}) args := []string{"ls", "monitoring"}
ctx := NewTestContext(args)
// Run command with test context. // Run command with test context.
output := capture.Output(func() { output := capture.Output(func() {
err = ClientsListCommand.Run(ctx) err = ClientsListCommand.Run(ctx, args...)
}) })
// Check command output for plausibility. // Check command output for plausibility.
@@ -52,11 +56,12 @@ func TestClientsListCommand(t *testing.T) {
var err error var err error
// Create test context with flags and arguments. // Create test context with flags and arguments.
ctx := NewTestContext([]string{"ls", "--csv", "monitoring"}) args := []string{"ls", "--csv", "monitoring"}
ctx := NewTestContext(args)
// Run command with test context. // Run command with test context.
output := capture.Output(func() { output := capture.Output(func() {
err = ClientsListCommand.Run(ctx) err = ClientsListCommand.Run(ctx, args...)
}) })
// Check command output for plausibility. // Check command output for plausibility.
@@ -72,11 +77,12 @@ func TestClientsListCommand(t *testing.T) {
var err error var err error
// Create test context with flags and arguments. // Create test context with flags and arguments.
ctx := NewTestContext([]string{"ls", "notexisting"}) args := []string{"ls", "notexisting"}
ctx := NewTestContext(args)
// Run command with test context. // Run command with test context.
output := capture.Output(func() { output := capture.Output(func() {
err = ClientsListCommand.Run(ctx) err = ClientsListCommand.Run(ctx, args...)
}) })
// Check command output for plausibility. // Check command output for plausibility.
@@ -87,12 +93,20 @@ func TestClientsListCommand(t *testing.T) {
t.Run("Error", func(t *testing.T) { t.Run("Error", func(t *testing.T) {
var err error var err error
defer func() {
if r := recover(); r != nil {
err = fmt.Errorf("error: %s \nstack: %s", r, debug.Stack())
assert.Error(t, err)
}
}()
// Create test context with flags and arguments. // Create test context with flags and arguments.
ctx := NewTestContext([]string{"ls", "--xyz", "monitoring"}) args := []string{"ls", "--xyz", "monitoring"}
ctx := NewTestContext(args)
// Run command with test context. // Run command with test context.
output := capture.Output(func() { output := capture.Output(func() {
err = ClientsListCommand.Run(ctx) err = ClientsListCommand.Run(ctx, args...)
}) })
// Check command output for plausibility. // Check command output for plausibility.

View File

@@ -3,7 +3,7 @@ package commands
import ( import (
"fmt" "fmt"
"github.com/urfave/cli" "github.com/urfave/cli/v2"
"github.com/photoprism/photoprism/internal/config" "github.com/photoprism/photoprism/internal/config"
"github.com/photoprism/photoprism/internal/entity" "github.com/photoprism/photoprism/internal/entity"

View File

@@ -12,11 +12,12 @@ func TestClientsModCommand(t *testing.T) {
var err error var err error
// Create test context with flags and arguments. // Create test context with flags and arguments.
ctx := NewTestContext([]string{"mod", "--name=New", "--scope=test", "cs5cpu17n6gjxxxx"}) args := []string{"mod", "--name=New", "--scope=test", "cs5cpu17n6gjxxxx"}
ctx := NewTestContext(args)
// Run command with test context. // Run command with test context.
output := capture.Output(func() { output := capture.Output(func() {
err = ClientsModCommand.Run(ctx) err = ClientsModCommand.Run(ctx, args...)
}) })
// Check command output for plausibility. // Check command output for plausibility.
@@ -26,11 +27,12 @@ func TestClientsModCommand(t *testing.T) {
t.Run("DisableEnableAuth", func(t *testing.T) { t.Run("DisableEnableAuth", func(t *testing.T) {
var err error var err error
ctx0 := NewTestContext([]string{"show", "cs7pvt5h8rw9aaqj"}) args0 := []string{"show", "cs7pvt5h8rw9aaqj"}
ctx0 := NewTestContext(args0)
// Run command with test context. // Run command with test context.
output0 := capture.Output(func() { output0 := capture.Output(func() {
err = ClientsShowCommand.Run(ctx0) err = ClientsShowCommand.Run(ctx0, args0...)
}) })
// Check command output for plausibility. // Check command output for plausibility.
@@ -40,11 +42,12 @@ func TestClientsModCommand(t *testing.T) {
assert.Contains(t, output0, "oauth2") assert.Contains(t, output0, "oauth2")
// Create test context with flags and arguments. // Create test context with flags and arguments.
ctx := NewTestContext([]string{"mod", "--disable", "cs7pvt5h8rw9aaqj"}) args := []string{"mod", "--disable", "cs7pvt5h8rw9aaqj"}
ctx := NewTestContext(args)
// Run command with test context. // Run command with test context.
output := capture.Output(func() { output := capture.Output(func() {
err = ClientsModCommand.Run(ctx) err = ClientsModCommand.Run(ctx, args...)
}) })
// Check command output for plausibility. // Check command output for plausibility.
@@ -54,7 +57,7 @@ func TestClientsModCommand(t *testing.T) {
// Run command with test context. // Run command with test context.
output1 := capture.Output(func() { output1 := capture.Output(func() {
err = ClientsShowCommand.Run(ctx0) err = ClientsShowCommand.Run(ctx0, args0...)
}) })
// Check command output for plausibility. // Check command output for plausibility.
@@ -63,11 +66,12 @@ func TestClientsModCommand(t *testing.T) {
assert.Contains(t, output1, "AuthEnabled | false") assert.Contains(t, output1, "AuthEnabled | false")
// Create test context with flags and arguments. // Create test context with flags and arguments.
ctx1 := NewTestContext([]string{"mod", "--enable", "cs7pvt5h8rw9aaqj"}) args1 := []string{"mod", "--enable", "cs7pvt5h8rw9aaqj"}
ctx1 := NewTestContext(args1)
// Run command with test context. // Run command with test context.
output2 := capture.Output(func() { output2 := capture.Output(func() {
err = ClientsModCommand.Run(ctx1) err = ClientsModCommand.Run(ctx1, args1...)
}) })
// Check command output for plausibility. // Check command output for plausibility.
@@ -76,7 +80,7 @@ func TestClientsModCommand(t *testing.T) {
// Run command with test context. // Run command with test context.
output3 := capture.Output(func() { output3 := capture.Output(func() {
err = ClientsShowCommand.Run(ctx0) err = ClientsShowCommand.Run(ctx0, args0...)
}) })
// Check command output for plausibility. // Check command output for plausibility.
@@ -88,11 +92,12 @@ func TestClientsModCommand(t *testing.T) {
var err error var err error
// Create test context with flags and arguments. // Create test context with flags and arguments.
ctx := NewTestContext([]string{"mod", "--regenerate", "cs7pvt5h8rw9aaqj"}) args := []string{"mod", "--regenerate", "cs7pvt5h8rw9aaqj"}
ctx := NewTestContext(args)
// Run command with test context. // Run command with test context.
output := capture.Output(func() { output := capture.Output(func() {
err = ClientsModCommand.Run(ctx) err = ClientsModCommand.Run(ctx, args...)
}) })
// Check command output for plausibility. // Check command output for plausibility.

View File

@@ -4,7 +4,7 @@ import (
"fmt" "fmt"
"github.com/manifoldco/promptui" "github.com/manifoldco/promptui"
"github.com/urfave/cli" "github.com/urfave/cli/v2"
"github.com/photoprism/photoprism/internal/config" "github.com/photoprism/photoprism/internal/config"
"github.com/photoprism/photoprism/internal/entity" "github.com/photoprism/photoprism/internal/entity"
@@ -17,9 +17,10 @@ var ClientsRemoveCommand = cli.Command{
Usage: "Deletes the specified client application", Usage: "Deletes the specified client application",
ArgsUsage: "[client id]", ArgsUsage: "[client id]",
Flags: []cli.Flag{ Flags: []cli.Flag{
cli.BoolFlag{ &cli.BoolFlag{
Name: "force, f", Name: "force",
Usage: "don't ask for confirmation", Aliases: []string{"f"},
Usage: "don't ask for confirmation",
}, },
}, },
Action: clientsRemoveAction, Action: clientsRemoveAction,

View File

@@ -11,10 +11,11 @@ func TestCientsRemoveCommand(t *testing.T) {
t.Run("NoConfirmationProvided", func(t *testing.T) { t.Run("NoConfirmationProvided", func(t *testing.T) {
var err error var err error
ctx0 := NewTestContext([]string{"show", "cs7pvt5h8rw9aaqj"}) args0 := []string{"show", "cs7pvt5h8rw9aaqj"}
ctx0 := NewTestContext(args0)
output0 := capture.Output(func() { output0 := capture.Output(func() {
err = ClientsShowCommand.Run(ctx0) err = ClientsShowCommand.Run(ctx0, args0...)
}) })
//t.Logf(output0) //t.Logf(output0)
@@ -23,11 +24,12 @@ func TestCientsRemoveCommand(t *testing.T) {
assert.Contains(t, output0, "client") assert.Contains(t, output0, "client")
// Create test context with flags and arguments. // Create test context with flags and arguments.
ctx := NewTestContext([]string{"rm", "cs7pvt5h8rw9aaqj"}) args := []string{"rm", "cs7pvt5h8rw9aaqj"}
ctx := NewTestContext(args)
// Run command with test context. // Run command with test context.
output := capture.Output(func() { output := capture.Output(func() {
err = ClientsRemoveCommand.Run(ctx) err = ClientsRemoveCommand.Run(ctx, args...)
}) })
// Check command output for plausibility. // Check command output for plausibility.
@@ -35,10 +37,11 @@ func TestCientsRemoveCommand(t *testing.T) {
assert.NoError(t, err) assert.NoError(t, err)
assert.Empty(t, output) assert.Empty(t, output)
ctx2 := NewTestContext([]string{"show", "cs7pvt5h8rw9aaqj"}) args2 := []string{"show", "cs7pvt5h8rw9aaqj"}
ctx2 := NewTestContext(args2)
output2 := capture.Output(func() { output2 := capture.Output(func() {
err = ClientsShowCommand.Run(ctx2) err = ClientsShowCommand.Run(ctx2, args2...)
}) })
//t.Logf(output2) //t.Logf(output2)
@@ -49,10 +52,11 @@ func TestCientsRemoveCommand(t *testing.T) {
t.Run("RemoveClient", func(t *testing.T) { t.Run("RemoveClient", func(t *testing.T) {
var err error var err error
ctx0 := NewTestContext([]string{"show", "cs7pvt5h8rw9aaqj"}) args0 := []string{"show", "cs7pvt5h8rw9aaqj"}
ctx0 := NewTestContext(args0)
output0 := capture.Output(func() { output0 := capture.Output(func() {
err = ClientsShowCommand.Run(ctx0) err = ClientsShowCommand.Run(ctx0, args0...)
}) })
//t.Logf(output0) //t.Logf(output0)
@@ -61,21 +65,23 @@ func TestCientsRemoveCommand(t *testing.T) {
assert.Contains(t, output0, "client") assert.Contains(t, output0, "client")
// Create test context with flags and arguments. // Create test context with flags and arguments.
ctx := NewTestContext([]string{"rm", "--force", "cs7pvt5h8rw9aaqj"}) args := []string{"rm", "--force", "cs7pvt5h8rw9aaqj"}
ctx := NewTestContext(args)
// Run command with test context. // Run command with test context.
output := capture.Output(func() { output := capture.Output(func() {
err = ClientsRemoveCommand.Run(ctx) err = ClientsRemoveCommand.Run(ctx, args...)
}) })
// Check command output for plausibility. // Check command output for plausibility.
assert.NoError(t, err) assert.NoError(t, err)
assert.Empty(t, output) assert.Empty(t, output)
ctx2 := NewTestContext([]string{"show", "cs7pvt5h8rw9aaqj"}) args2 := []string{"show", "cs7pvt5h8rw9aaqj"}
ctx2 := NewTestContext(args2)
output2 := capture.Output(func() { output2 := capture.Output(func() {
err = ClientsShowCommand.Run(ctx2) err = ClientsShowCommand.Run(ctx2, args2...)
}) })
assert.Error(t, err) assert.Error(t, err)
@@ -85,11 +91,12 @@ func TestCientsRemoveCommand(t *testing.T) {
var err error var err error
// Create test context with flags and arguments. // Create test context with flags and arguments.
ctx := NewTestContext([]string{"rm", "--force", "cs7pvt5h8rw9a000"}) args := []string{"rm", "--force", "cs7pvt5h8rw9a000"}
ctx := NewTestContext(args)
// Run command with test context. // Run command with test context.
output := capture.Output(func() { output := capture.Output(func() {
err = ClientsRemoveCommand.Run(ctx) err = ClientsRemoveCommand.Run(ctx, args...)
}) })
// Check command output for plausibility. // Check command output for plausibility.

View File

@@ -5,7 +5,7 @@ import (
"github.com/manifoldco/promptui" "github.com/manifoldco/promptui"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
"github.com/urfave/cli" "github.com/urfave/cli/v2"
"github.com/photoprism/photoprism/internal/config" "github.com/photoprism/photoprism/internal/config"
"github.com/photoprism/photoprism/internal/entity" "github.com/photoprism/photoprism/internal/entity"
@@ -16,13 +16,15 @@ var ClientsResetCommand = cli.Command{
Name: "reset", Name: "reset",
Usage: "Removes all registered client applications", Usage: "Removes all registered client applications",
Flags: []cli.Flag{ Flags: []cli.Flag{
cli.BoolFlag{ &cli.BoolFlag{
Name: "trace, t", Name: "trace",
Usage: "show trace logs for debugging", Aliases: []string{"t"},
Usage: "show trace logs for debugging",
}, },
cli.BoolFlag{ &cli.BoolFlag{
Name: "yes, y", Name: "yes",
Usage: "assume \"yes\" and run non-interactively", Aliases: []string{"y"},
Usage: "assume \"yes\" and run non-interactively",
}, },
}, },
Action: clientsResetAction, Action: clientsResetAction,

View File

@@ -12,11 +12,12 @@ func TestClientsResetCommand(t *testing.T) {
var err error var err error
// Create test context with flags and arguments. // Create test context with flags and arguments.
ctx0 := NewTestContext([]string{"ls"}) args0 := []string{"ls"}
ctx0 := NewTestContext(args0)
// Run command with test context. // Run command with test context.
output0 := capture.Output(func() { output0 := capture.Output(func() {
err = ClientsListCommand.Run(ctx0) err = ClientsListCommand.Run(ctx0, args0...)
}) })
// Check command output for plausibility. // Check command output for plausibility.
@@ -26,11 +27,12 @@ func TestClientsResetCommand(t *testing.T) {
assert.Contains(t, output0, "metrics") assert.Contains(t, output0, "metrics")
// Create test context with flags and arguments. // Create test context with flags and arguments.
ctx := NewTestContext([]string{"reset"}) args := []string{"reset"}
ctx := NewTestContext(args)
// Run command with test context. // Run command with test context.
output := capture.Output(func() { output := capture.Output(func() {
err = ClientsResetCommand.Run(ctx) err = ClientsResetCommand.Run(ctx, args...)
}) })
// Check command output for plausibility. // Check command output for plausibility.
@@ -40,7 +42,7 @@ func TestClientsResetCommand(t *testing.T) {
// Run command with test context. // Run command with test context.
output1 := capture.Output(func() { output1 := capture.Output(func() {
err = ClientsListCommand.Run(ctx0) err = ClientsListCommand.Run(ctx0, args0...)
}) })
// Check command output for plausibility. // Check command output for plausibility.

View File

@@ -3,7 +3,7 @@ package commands
import ( import (
"fmt" "fmt"
"github.com/urfave/cli" "github.com/urfave/cli/v2"
"github.com/photoprism/photoprism/internal/config" "github.com/photoprism/photoprism/internal/config"
"github.com/photoprism/photoprism/internal/entity" "github.com/photoprism/photoprism/internal/entity"

View File

@@ -12,11 +12,12 @@ func TestClientsShowCommand(t *testing.T) {
var err error var err error
// Create test context with flags and arguments. // Create test context with flags and arguments.
ctx := NewTestContext([]string{"show", "cs5gfen1bgxz7s9i"}) args := []string{"show", "cs5gfen1bgxz7s9i"}
ctx := NewTestContext(args)
// Run command with test context. // Run command with test context.
output := capture.Output(func() { output := capture.Output(func() {
err = ClientsShowCommand.Run(ctx) err = ClientsShowCommand.Run(ctx, args...)
}) })
// Check command output for plausibility. // Check command output for plausibility.
@@ -30,11 +31,12 @@ func TestClientsShowCommand(t *testing.T) {
var err error var err error
// Create test context with flags and arguments. // Create test context with flags and arguments.
ctx := NewTestContext([]string{"show", "cs5gfen1bgxzxxxx"}) args := []string{"show", "cs5gfen1bgxzxxxx"}
ctx := NewTestContext(args)
// Run command with test context. // Run command with test context.
output := capture.Output(func() { output := capture.Output(func() {
err = ClientsShowCommand.Run(ctx) err = ClientsShowCommand.Run(ctx, args...)
}) })
// Check command output for plausibility. // Check command output for plausibility.

View File

@@ -30,7 +30,7 @@ import (
"syscall" "syscall"
"github.com/sevlyar/go-daemon" "github.com/sevlyar/go-daemon"
"github.com/urfave/cli" "github.com/urfave/cli/v2"
"github.com/photoprism/photoprism/internal/config" "github.com/photoprism/photoprism/internal/config"
"github.com/photoprism/photoprism/internal/event" "github.com/photoprism/photoprism/internal/event"
@@ -40,42 +40,44 @@ import (
var log = event.Log var log = event.Log
// PhotoPrism contains the photoprism CLI (sub-)commands. // PhotoPrism contains the photoprism CLI (sub-)commands.
var PhotoPrism = []cli.Command{ var PhotoPrism = []*cli.Command{
StartCommand, &StartCommand,
StopCommand, &StopCommand,
StatusCommand, &StatusCommand,
IndexCommand, &IndexCommand,
FindCommand, &FindCommand,
ImportCommand, &ImportCommand,
CopyCommand, &CopyCommand,
FacesCommands, &FacesCommands,
PlacesCommands, &PlacesCommands,
PurgeCommand, &PurgeCommand,
CleanUpCommand, &CleanUpCommand,
OptimizeCommand, &OptimizeCommand,
MomentsCommand, &MomentsCommand,
ConvertCommand, &ConvertCommand,
ThumbsCommand, &ThumbsCommand,
MigrateCommand, &MigrateCommand,
MigrationsCommands, &MigrationsCommands,
BackupCommand, &BackupCommand,
RestoreCommand, &RestoreCommand,
ResetCommand, &ResetCommand,
PasswdCommand, &PasswdCommand,
UsersCommands, &UsersCommands,
ClientsCommands, &ClientsCommands,
AuthCommands, &AuthCommands,
ShowCommands, &ShowCommands,
VersionCommand, &VersionCommand,
ShowConfigCommand, &EditionCommand,
ConnectCommand, &ShowConfigCommand,
&ConnectCommand,
} }
// CountFlag represents a CLI flag to limit the number of report rows. // CountFlag represents a CLI flag to limit the number of report rows.
var CountFlag = cli.UintFlag{ var CountFlag = &cli.UintFlag{
Name: "n", Name: "count",
Usage: "`LIMIT` number of results", Aliases: []string{"n"},
Value: 100, Usage: "`LIMIT` number of results",
Value: 100,
} }
// LogErr logs an error if the argument is not nil. // LogErr logs an error if the argument is not nil.

View File

@@ -6,7 +6,7 @@ import (
"testing" "testing"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
"github.com/urfave/cli" "github.com/urfave/cli/v2"
"github.com/photoprism/photoprism/internal/config" "github.com/photoprism/photoprism/internal/config"
"github.com/photoprism/photoprism/internal/event" "github.com/photoprism/photoprism/internal/event"
@@ -39,11 +39,14 @@ func TestMain(m *testing.M) {
func NewTestContext(args []string) *cli.Context { func NewTestContext(args []string) *cli.Context {
// Create new command-line app. // Create new command-line app.
app := cli.NewApp() app := cli.NewApp()
app.Name = "photoprism"
app.Usage = "PhotoPrism®" app.Usage = "PhotoPrism®"
app.Description = ""
app.Version = "test" app.Version = "test"
app.Copyright = "(c) 2018-2024 PhotoPrism UG. All rights reserved." app.Copyright = "(c) 2018-2024 PhotoPrism UG. All rights reserved."
app.EnableBashCompletion = true
app.Flags = config.Flags.Cli() app.Flags = config.Flags.Cli()
app.Commands = PhotoPrism
app.EnableBashCompletion = false
app.Metadata = map[string]interface{}{ app.Metadata = map[string]interface{}{
"Name": "PhotoPrism", "Name": "PhotoPrism",
"About": "PhotoPrism®", "About": "PhotoPrism®",
@@ -52,9 +55,9 @@ func NewTestContext(args []string) *cli.Context {
} }
// Parse command arguments. // Parse command arguments.
flags := flag.NewFlagSet("test", 0) set := flag.NewFlagSet("test", flag.ContinueOnError)
LogErr(flags.Parse(args)) LogErr(set.Parse(args))
// Create and return new context. // Create and return new context.
return cli.NewContext(app, flags, nil) return cli.NewContext(app, set, nil)
} }

View File

@@ -1,7 +1,7 @@
package commands package commands
import ( import (
"github.com/urfave/cli" "github.com/urfave/cli/v2"
"github.com/photoprism/photoprism/internal/config" "github.com/photoprism/photoprism/internal/config"
"github.com/photoprism/photoprism/internal/photoprism/get" "github.com/photoprism/photoprism/internal/photoprism/get"

View File

@@ -1,7 +1,7 @@
package commands package commands
import ( import (
"github.com/urfave/cli" "github.com/urfave/cli/v2"
"github.com/photoprism/photoprism/internal/config" "github.com/photoprism/photoprism/internal/config"
) )

View File

@@ -6,7 +6,7 @@ import (
"strings" "strings"
"time" "time"
"github.com/urfave/cli" "github.com/urfave/cli/v2"
"github.com/photoprism/photoprism/internal/config" "github.com/photoprism/photoprism/internal/config"
"github.com/photoprism/photoprism/internal/photoprism/get" "github.com/photoprism/photoprism/internal/photoprism/get"
@@ -19,13 +19,15 @@ var ConvertCommand = cli.Command{
Usage: "Converts files in other formats to JPEG and AVC as needed", Usage: "Converts files in other formats to JPEG and AVC as needed",
ArgsUsage: "[subfolder]", ArgsUsage: "[subfolder]",
Flags: []cli.Flag{ Flags: []cli.Flag{
cli.StringSliceFlag{ &cli.StringSliceFlag{
Name: "ext, e", Name: "ext",
Usage: "only process files with the specified extensions, e.g. mp4", Aliases: []string{"e"},
Usage: "only process files with the specified extensions, e.g. mp4",
}, },
cli.BoolFlag{ &cli.BoolFlag{
Name: "force, f", Name: "force",
Usage: "replace existing JPEG files in the sidecar folder", Aliases: []string{"f"},
Usage: "replace existing JPEG files in the sidecar folder",
}, },
}, },
Action: convertAction, Action: convertAction,

View File

@@ -7,7 +7,7 @@ import (
"strings" "strings"
"time" "time"
"github.com/urfave/cli" "github.com/urfave/cli/v2"
"github.com/photoprism/photoprism/internal/config" "github.com/photoprism/photoprism/internal/config"
"github.com/photoprism/photoprism/internal/photoprism" "github.com/photoprism/photoprism/internal/photoprism"
@@ -22,9 +22,10 @@ var CopyCommand = cli.Command{
Usage: "Copies media files to originals", Usage: "Copies media files to originals",
ArgsUsage: "[source]", ArgsUsage: "[source]",
Flags: []cli.Flag{ Flags: []cli.Flag{
cli.StringFlag{ &cli.StringFlag{
Name: "dest, d", Name: "dest",
Usage: "relative originals `PATH` to which the files should be imported", Aliases: []string{"d"},
Usage: "relative originals `PATH` to which the files should be imported",
}, },
}, },
Action: copyAction, Action: copyAction,

View File

@@ -0,0 +1,26 @@
package commands
import (
"fmt"
"github.com/urfave/cli/v2"
"github.com/photoprism/photoprism/internal/config"
)
// EditionCommand configures the "photoprism edition" command.
var EditionCommand = cli.Command{
Name: "edition",
Usage: "Shows edition information",
Hidden: true,
Action: editionAction,
}
// editionAction displays information about the current edition.
func editionAction(ctx *cli.Context) error {
conf := config.NewConfig(ctx)
fmt.Println(conf.Edition())
return nil
}

View File

@@ -0,0 +1,28 @@
package commands
import (
"testing"
"github.com/photoprism/photoprism/pkg/capture"
"github.com/stretchr/testify/assert"
)
func TestEditionCommand(t *testing.T) {
t.Run("Success", func(t *testing.T) {
var err error
// Create test context with flags and arguments.
args := []string{"edition"}
ctx := NewTestContext(args)
// Run command with test context.
output := capture.Output(func() {
err = EditionCommand.Run(ctx, args...)
})
// Check command output for plausibility.
// t.Logf(output)
assert.NoError(t, err)
assert.Contains(t, output, "ce")
})
}

View File

@@ -8,7 +8,7 @@ import (
"github.com/dustin/go-humanize/english" "github.com/dustin/go-humanize/english"
"github.com/manifoldco/promptui" "github.com/manifoldco/promptui"
"github.com/urfave/cli" "github.com/urfave/cli/v2"
"github.com/photoprism/photoprism/internal/config" "github.com/photoprism/photoprism/internal/config"
"github.com/photoprism/photoprism/internal/entity/query" "github.com/photoprism/photoprism/internal/entity/query"
@@ -22,7 +22,7 @@ import (
var FacesCommands = cli.Command{ var FacesCommands = cli.Command{
Name: "faces", Name: "faces",
Usage: "Face recognition subcommands", Usage: "Face recognition subcommands",
Subcommands: []cli.Command{ Subcommands: []*cli.Command{
{ {
Name: "stats", Name: "stats",
Usage: "Shows stats on face samples", Usage: "Shows stats on face samples",
@@ -32,9 +32,10 @@ var FacesCommands = cli.Command{
Name: "audit", Name: "audit",
Usage: "Scans the index for issues", Usage: "Scans the index for issues",
Flags: []cli.Flag{ Flags: []cli.Flag{
cli.BoolFlag{ &cli.BoolFlag{
Name: "fix, f", Name: "fix",
Usage: "fix discovered issues", Aliases: []string{"f"},
Usage: "fix discovered issues",
}, },
}, },
Action: facesAuditAction, Action: facesAuditAction,
@@ -43,9 +44,10 @@ var FacesCommands = cli.Command{
Name: "reset", Name: "reset",
Usage: "Removes people and faces after confirmation", Usage: "Removes people and faces after confirmation",
Flags: []cli.Flag{ Flags: []cli.Flag{
cli.BoolFlag{ &cli.BoolFlag{
Name: "force, f", Name: "force",
Usage: "remove all people and faces", Aliases: []string{"f"},
Usage: "remove all people and faces",
}, },
}, },
Action: facesResetAction, Action: facesResetAction,
@@ -60,9 +62,10 @@ var FacesCommands = cli.Command{
Name: "update", Name: "update",
Usage: "Performs face clustering and matching", Usage: "Performs face clustering and matching",
Flags: []cli.Flag{ Flags: []cli.Flag{
cli.BoolFlag{ &cli.BoolFlag{
Name: "force, f", Name: "force",
Usage: "update all faces", Aliases: []string{"f"},
Usage: "update all faces",
}, },
}, },
Action: facesUpdateAction, Action: facesUpdateAction,

View File

@@ -6,7 +6,7 @@ import (
"strings" "strings"
"github.com/dustin/go-humanize" "github.com/dustin/go-humanize"
"github.com/urfave/cli" "github.com/urfave/cli/v2"
"github.com/photoprism/photoprism/internal/entity/search" "github.com/photoprism/photoprism/internal/entity/search"
"github.com/photoprism/photoprism/internal/entity/sortby" "github.com/photoprism/photoprism/internal/entity/sortby"
@@ -19,10 +19,11 @@ var FindCommand = cli.Command{
Name: "find", Name: "find",
Usage: "Searches the index for specific files", Usage: "Searches the index for specific files",
ArgsUsage: "filter", ArgsUsage: "filter",
Flags: append(report.CliFlags, cli.UintFlag{ Flags: append(report.CliFlags, &cli.UintFlag{
Name: "n", Name: "count",
Usage: "maximum number of search `RESULTS`", Aliases: []string{"n"},
Value: 10000, Usage: "maximum number of search `RESULTS`",
Value: 10000,
}), }),
Action: findAction, Action: findAction,
} }
@@ -44,7 +45,7 @@ func findAction(ctx *cli.Context) error {
Query: strings.TrimSpace(ctx.Args().First()), Query: strings.TrimSpace(ctx.Args().First()),
Primary: false, Primary: false,
Merged: false, Merged: false,
Count: ctx.Int("n"), Count: ctx.Int("count"),
Offset: 0, Offset: 0,
Order: sortby.Name, Order: sortby.Name,
} }

View File

@@ -12,11 +12,12 @@ func TestFindCommand(t *testing.T) {
var err error var err error
// Create test context with flags and arguments. // Create test context with flags and arguments.
ctx := NewTestContext([]string{"find", "--csv"}) args := []string{"find", "--csv"}
ctx := NewTestContext(args)
// Run command with test context. // Run command with test context.
output := capture.Output(func() { output := capture.Output(func() {
err = FindCommand.Run(ctx) err = FindCommand.Run(ctx, args...)
}) })
// Check command output for plausibility. // Check command output for plausibility.

View File

@@ -7,7 +7,7 @@ import (
"strings" "strings"
"time" "time"
"github.com/urfave/cli" "github.com/urfave/cli/v2"
"github.com/photoprism/photoprism/internal/config" "github.com/photoprism/photoprism/internal/config"
"github.com/photoprism/photoprism/internal/photoprism" "github.com/photoprism/photoprism/internal/photoprism"
@@ -22,9 +22,10 @@ var ImportCommand = cli.Command{
Usage: "Moves media files to originals", Usage: "Moves media files to originals",
ArgsUsage: "[source]", ArgsUsage: "[source]",
Flags: []cli.Flag{ Flags: []cli.Flag{
cli.StringFlag{ &cli.StringFlag{
Name: "dest, d", Name: "dest",
Usage: "relative originals `PATH` to which the files should be imported", Aliases: []string{"d"},
Usage: "relative originals `PATH` to which the files should be imported",
}, },
}, },
Action: importAction, Action: importAction,

View File

@@ -7,7 +7,7 @@ import (
"time" "time"
"github.com/dustin/go-humanize/english" "github.com/dustin/go-humanize/english"
"github.com/urfave/cli" "github.com/urfave/cli/v2"
"github.com/photoprism/photoprism/internal/photoprism" "github.com/photoprism/photoprism/internal/photoprism"
"github.com/photoprism/photoprism/internal/photoprism/get" "github.com/photoprism/photoprism/internal/photoprism/get"
@@ -25,17 +25,20 @@ var IndexCommand = cli.Command{
} }
var indexFlags = []cli.Flag{ var indexFlags = []cli.Flag{
cli.BoolFlag{ &cli.BoolFlag{
Name: "force, f", Name: "force",
Usage: "rescan all originals, including unchanged files", Aliases: []string{"f"},
Usage: "rescan all originals, including unchanged files",
}, },
cli.BoolFlag{ &cli.BoolFlag{
Name: "archived, a", Name: "archived",
Usage: "do not skip files belonging to archived photos", Aliases: []string{"a"},
Usage: "do not skip files belonging to archived photos",
}, },
cli.BoolFlag{ &cli.BoolFlag{
Name: "cleanup, c", Name: "cleanup",
Usage: "remove orphan index entries and thumbnails", Aliases: []string{"c"},
Usage: "remove orphan index entries and thumbnails",
}, },
} }

View File

@@ -1,6 +1,6 @@
package commands package commands
import "github.com/urfave/cli" import "github.com/urfave/cli/v2"
// MigrateCommand configures the command name, flags, and action. // MigrateCommand configures the command name, flags, and action.
var MigrateCommand = cli.Command{ var MigrateCommand = cli.Command{

View File

@@ -9,7 +9,7 @@ import (
"time" "time"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
"github.com/urfave/cli" "github.com/urfave/cli/v2"
"github.com/photoprism/photoprism/internal/config" "github.com/photoprism/photoprism/internal/config"
"github.com/photoprism/photoprism/internal/entity/migrate" "github.com/photoprism/photoprism/internal/entity/migrate"
@@ -31,13 +31,15 @@ var MigrationsRunCommand = cli.Command{
Usage: "Executes database schema migrations", Usage: "Executes database schema migrations",
ArgsUsage: "[migrations...]", ArgsUsage: "[migrations...]",
Flags: []cli.Flag{ Flags: []cli.Flag{
cli.BoolFlag{ &cli.BoolFlag{
Name: "failed, f", Name: "failed",
Usage: "run previously failed migrations", Aliases: []string{"f"},
Usage: "run previously failed migrations",
}, },
cli.BoolFlag{ &cli.BoolFlag{
Name: "trace, t", Name: "trace",
Usage: "show trace logs for debugging", Aliases: []string{"t"},
Usage: "show trace logs for debugging",
}, },
}, },
Action: migrationsRunAction, Action: migrationsRunAction,
@@ -47,9 +49,9 @@ var MigrationsRunCommand = cli.Command{
var MigrationsCommands = cli.Command{ var MigrationsCommands = cli.Command{
Name: "migrations", Name: "migrations",
Usage: "Database schema migration subcommands", Usage: "Database schema migration subcommands",
Subcommands: []cli.Command{ Subcommands: []*cli.Command{
MigrationsStatusCommand, &MigrationsStatusCommand,
MigrationsRunCommand, &MigrationsRunCommand,
}, },
} }

View File

@@ -4,7 +4,7 @@ import (
"context" "context"
"time" "time"
"github.com/urfave/cli" "github.com/urfave/cli/v2"
"github.com/photoprism/photoprism/internal/photoprism/get" "github.com/photoprism/photoprism/internal/photoprism/get"
) )

View File

@@ -4,7 +4,7 @@ import (
"context" "context"
"time" "time"
"github.com/urfave/cli" "github.com/urfave/cli/v2"
"github.com/photoprism/photoprism/internal/entity" "github.com/photoprism/photoprism/internal/entity"
"github.com/photoprism/photoprism/internal/workers" "github.com/photoprism/photoprism/internal/workers"
@@ -15,9 +15,10 @@ var OptimizeCommand = cli.Command{
Name: "optimize", Name: "optimize",
Usage: "Maintains titles, estimates, and other metadata", Usage: "Maintains titles, estimates, and other metadata",
Flags: []cli.Flag{ Flags: []cli.Flag{
cli.BoolFlag{ &cli.BoolFlag{
Name: "force, f", Name: "force",
Usage: "update all, including recently optimized", Aliases: []string{"f"},
Usage: "update all, including recently optimized",
}, },
}, },
Action: optimizeAction, Action: optimizeAction,

View File

@@ -10,7 +10,7 @@ import (
"strings" "strings"
"syscall" "syscall"
"github.com/urfave/cli" "github.com/urfave/cli/v2"
"github.com/photoprism/photoprism/internal/entity" "github.com/photoprism/photoprism/internal/entity"
"github.com/photoprism/photoprism/pkg/clean" "github.com/photoprism/photoprism/pkg/clean"
@@ -24,13 +24,15 @@ var PasswdCommand = cli.Command{
Usage: "Changes the local account password of a registered user", Usage: "Changes the local account password of a registered user",
ArgsUsage: "[username]", ArgsUsage: "[username]",
Flags: []cli.Flag{ Flags: []cli.Flag{
cli.BoolFlag{ &cli.BoolFlag{
Name: "show, s", Name: "show",
Usage: "show bcrypt hash of new password", Aliases: []string{"s"},
Usage: "show bcrypt hash of new password",
}, },
cli.BoolFlag{ &cli.BoolFlag{
Name: "remove, rm", Name: "remove",
Usage: "remove password to disable local authentication", Aliases: []string{"rm"},
Usage: "remove password to disable local authentication",
}, },
}, },
Action: passwdAction, Action: passwdAction,

View File

@@ -11,11 +11,12 @@ func TestPasswdCommand(t *testing.T) {
t.Run("UserNotFound", func(t *testing.T) { t.Run("UserNotFound", func(t *testing.T) {
var err error var err error
ctx := NewTestContext([]string{"passwd", "--show", "mila"}) args := []string{"passwd", "--show", "mila"}
ctx := NewTestContext(args)
// Run command with test context. // Run command with test context.
output := capture.Output(func() { output := capture.Output(func() {
err = PasswdCommand.Run(ctx) err = PasswdCommand.Run(ctx, args...)
}) })
// Check command output for plausibility. // Check command output for plausibility.
@@ -25,11 +26,12 @@ func TestPasswdCommand(t *testing.T) {
t.Run("DeletedUser", func(t *testing.T) { t.Run("DeletedUser", func(t *testing.T) {
var err error var err error
ctx := NewTestContext([]string{"passwd", "--show", "uqxqg7i1kperxvu8"}) args := []string{"passwd", "--show", "uqxqg7i1kperxvu8"}
ctx := NewTestContext(args)
// Run command with test context. // Run command with test context.
output := capture.Output(func() { output := capture.Output(func() {
err = PasswdCommand.Run(ctx) err = PasswdCommand.Run(ctx, args...)
}) })
// Check command output for plausibility. // Check command output for plausibility.
@@ -39,7 +41,8 @@ func TestPasswdCommand(t *testing.T) {
t.Run("DeletePassword", func(t *testing.T) { t.Run("DeletePassword", func(t *testing.T) {
var err error var err error
ctx := NewTestContext([]string{"passwd", "--rm", "no_local_auth"}) args := []string{"passwd", "--rm", "no_local_auth"}
ctx := NewTestContext(args)
// Run command with test context. // Run command with test context.
output := capture.Output(func() { output := capture.Output(func() {

View File

@@ -5,7 +5,7 @@ import (
"time" "time"
"github.com/manifoldco/promptui" "github.com/manifoldco/promptui"
"github.com/urfave/cli" "github.com/urfave/cli/v2"
"github.com/photoprism/photoprism/internal/entity" "github.com/photoprism/photoprism/internal/entity"
"github.com/photoprism/photoprism/internal/entity/query" "github.com/photoprism/photoprism/internal/entity/query"
@@ -16,19 +16,21 @@ import (
var PlacesCommands = cli.Command{ var PlacesCommands = cli.Command{
Name: "places", Name: "places",
Usage: "Maps and location information subcommands", Usage: "Maps and location information subcommands",
Subcommands: []cli.Command{ Subcommands: []*cli.Command{
{ {
Name: "update", Name: "update",
Usage: "Updates location information", Usage: "Updates location information",
Description: "Updates missing location information only if used without the --force flag.", Description: "Updates missing location information only if used without the --force flag.",
Flags: []cli.Flag{ Flags: []cli.Flag{
cli.BoolFlag{ &cli.BoolFlag{
Name: "force, f", Name: "force",
Usage: "forces the location of all pictures to be updated", Aliases: []string{"f"},
Usage: "forces the location of all pictures to be updated",
}, },
cli.BoolFlag{ &cli.BoolFlag{
Name: "yes, y", Name: "yes",
Usage: "assume \"yes\" and run non-interactively", Aliases: []string{"y"},
Usage: "assume \"yes\" and run non-interactively",
}, },
}, },
Action: placesUpdateAction, Action: placesUpdateAction,

View File

@@ -7,7 +7,7 @@ import (
"time" "time"
"github.com/dustin/go-humanize/english" "github.com/dustin/go-humanize/english"
"github.com/urfave/cli" "github.com/urfave/cli/v2"
"github.com/photoprism/photoprism/internal/photoprism" "github.com/photoprism/photoprism/internal/photoprism"
"github.com/photoprism/photoprism/internal/photoprism/get" "github.com/photoprism/photoprism/internal/photoprism/get"
@@ -24,11 +24,11 @@ var PurgeCommand = cli.Command{
} }
var purgeFlags = []cli.Flag{ var purgeFlags = []cli.Flag{
cli.BoolFlag{ &cli.BoolFlag{
Name: "hard", Name: "hard",
Usage: "permanently remove from index", Usage: "permanently remove from index",
}, },
cli.BoolFlag{ &cli.BoolFlag{
Name: "dry", Name: "dry",
Usage: "dry run, don't actually remove anything", Usage: "dry run, don't actually remove anything",
}, },

View File

@@ -10,7 +10,7 @@ import (
"github.com/manifoldco/promptui" "github.com/manifoldco/promptui"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
"github.com/urfave/cli" "github.com/urfave/cli/v2"
"github.com/photoprism/photoprism/internal/config" "github.com/photoprism/photoprism/internal/config"
"github.com/photoprism/photoprism/internal/entity" "github.com/photoprism/photoprism/internal/entity"
@@ -22,17 +22,20 @@ var ResetCommand = cli.Command{
Name: "reset", Name: "reset",
Usage: "Resets the index, clears the cache, and removes sidecar files", Usage: "Resets the index, clears the cache, and removes sidecar files",
Flags: []cli.Flag{ Flags: []cli.Flag{
cli.BoolFlag{ &cli.BoolFlag{
Name: "index, i", Name: "index",
Usage: "reset index database only", Aliases: []string{"i"},
Usage: "reset index database only",
}, },
cli.BoolFlag{ &cli.BoolFlag{
Name: "trace, t", Name: "trace",
Usage: "show trace logs for debugging", Aliases: []string{"t"},
Usage: "show trace logs for debugging",
}, },
cli.BoolFlag{ &cli.BoolFlag{
Name: "yes, y", Name: "yes",
Usage: "assume \"yes\" and run non-interactively", Aliases: []string{"y"},
Usage: "assume \"yes\" and run non-interactively",
}, },
}, },
Action: resetAction, Action: resetAction,

View File

@@ -5,7 +5,7 @@ import (
"time" "time"
"github.com/dustin/go-humanize/english" "github.com/dustin/go-humanize/english"
"github.com/urfave/cli" "github.com/urfave/cli/v2"
"github.com/photoprism/photoprism/internal/photoprism/backup" "github.com/photoprism/photoprism/internal/photoprism/backup"
"github.com/photoprism/photoprism/internal/photoprism/get" "github.com/photoprism/photoprism/internal/photoprism/get"
@@ -28,25 +28,29 @@ var RestoreCommand = cli.Command{
} }
var restoreFlags = []cli.Flag{ var restoreFlags = []cli.Flag{
cli.BoolFlag{ &cli.BoolFlag{
Name: "force, f", Name: "force",
Usage: "replace the index database with the backup, if it already exists", Aliases: []string{"f"},
Usage: "replace the index database with the backup, if it already exists",
}, },
cli.BoolFlag{ &cli.BoolFlag{
Name: "albums, a", Name: "albums",
Usage: "restore albums from the YAML backup files found in the album backup path", Aliases: []string{"a"},
Usage: "restore albums from the YAML backup files found in the album backup path",
}, },
cli.StringFlag{ &cli.StringFlag{
Name: "albums-path", Name: "albums-path",
Usage: "custom album backup `PATH`", Usage: "custom album backup `PATH`",
}, },
cli.BoolFlag{ &cli.BoolFlag{
Name: "database, index, i", Name: "database",
Usage: "restore the index database from the specified file (stdin if - is passed as filename), or the most recent backup found in the database backup path", Aliases: []string{"index", "i"},
Usage: "restore the index database from the specified file (stdin if - is passed as filename), or the most recent backup found in the database backup path",
}, },
cli.StringFlag{ &cli.StringFlag{
Name: "database-path, index-path", Name: "database-path",
Usage: "custom database backup `PATH`", Aliases: []string{"index-path"},
Usage: "custom database backup `PATH`",
}, },
} }

View File

@@ -1,21 +1,21 @@
package commands package commands
import ( import (
"github.com/urfave/cli" "github.com/urfave/cli/v2"
) )
// ShowCommands configures the show subcommands. // ShowCommands configures the show subcommands.
var ShowCommands = cli.Command{ var ShowCommands = cli.Command{
Name: "show", Name: "show",
Usage: "Shows supported formats, features, and config options", Usage: "Shows supported formats, features, and config options",
Subcommands: []cli.Command{ Subcommands: []*cli.Command{
ShowConfigCommand, &ShowConfigCommand,
ShowConfigOptionsCommand, &ShowConfigOptionsCommand,
ShowConfigYamlCommand, &ShowConfigYamlCommand,
ShowSearchFiltersCommand, &ShowSearchFiltersCommand,
ShowFileFormatsCommand, &ShowFileFormatsCommand,
ShowThumbSizesCommand, &ShowThumbSizesCommand,
ShowVideoSizesCommand, &ShowVideoSizesCommand,
ShowMetadataCommand, &ShowMetadataCommand,
}, },
} }

View File

@@ -5,7 +5,7 @@ import (
"strings" "strings"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
"github.com/urfave/cli" "github.com/urfave/cli/v2"
"github.com/photoprism/photoprism/internal/config" "github.com/photoprism/photoprism/internal/config"
"github.com/photoprism/photoprism/internal/photoprism/get" "github.com/photoprism/photoprism/internal/photoprism/get"

View File

@@ -4,7 +4,7 @@ import (
"fmt" "fmt"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
"github.com/urfave/cli" "github.com/urfave/cli/v2"
"github.com/photoprism/photoprism/internal/config" "github.com/photoprism/photoprism/internal/config"
"github.com/photoprism/photoprism/pkg/txt/report" "github.com/photoprism/photoprism/pkg/txt/report"

View File

@@ -10,10 +10,10 @@ import (
func TestShowConfigOptionsCommand(t *testing.T) { func TestShowConfigOptionsCommand(t *testing.T) {
var err error var err error
ctx := NewTestContext([]string{"config-options", "--md"}) args := []string{"config-options", "--md"}
ctx := NewTestContext(args)
output := capture.Stdout(func() { output := capture.Stdout(func() {
err = ShowConfigOptionsCommand.Run(ctx) err = ShowConfigOptionsCommand.Run(ctx, args...)
}) })
assert.NoError(t, err) assert.NoError(t, err)

View File

@@ -4,7 +4,7 @@ import (
"fmt" "fmt"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
"github.com/urfave/cli" "github.com/urfave/cli/v2"
"github.com/photoprism/photoprism/internal/config" "github.com/photoprism/photoprism/internal/config"
"github.com/photoprism/photoprism/pkg/txt/report" "github.com/photoprism/photoprism/pkg/txt/report"

View File

@@ -10,10 +10,10 @@ import (
func TestShowConfigYamlCommand(t *testing.T) { func TestShowConfigYamlCommand(t *testing.T) {
var err error var err error
ctx := NewTestContext([]string{"config-yaml", "--md"}) args := []string{"config-yaml", "--md"}
ctx := NewTestContext(args)
output := capture.Stdout(func() { output := capture.Stdout(func() {
err = ShowConfigYamlCommand.Run(ctx) err = ShowConfigYamlCommand.Run(ctx, args...)
}) })
if err != nil { if err != nil {

View File

@@ -3,7 +3,7 @@ package commands
import ( import (
"fmt" "fmt"
"github.com/urfave/cli" "github.com/urfave/cli/v2"
"github.com/photoprism/photoprism/pkg/fs" "github.com/photoprism/photoprism/pkg/fs"
"github.com/photoprism/photoprism/pkg/media" "github.com/photoprism/photoprism/pkg/media"
@@ -15,9 +15,10 @@ var ShowFileFormatsCommand = cli.Command{
Name: "file-formats", Name: "file-formats",
Aliases: []string{"formats"}, Aliases: []string{"formats"},
Usage: "Displays supported media and sidecar file formats", Usage: "Displays supported media and sidecar file formats",
Flags: append(report.CliFlags, cli.BoolFlag{ Flags: append(report.CliFlags, &cli.BoolFlag{
Name: "short, s", Name: "short",
Usage: "hide format descriptions", Aliases: []string{"s"},
Usage: "hide format descriptions",
}), }),
Action: showFileFormatsAction, Action: showFileFormatsAction,
} }

View File

@@ -4,7 +4,7 @@ import (
"fmt" "fmt"
"sort" "sort"
"github.com/urfave/cli" "github.com/urfave/cli/v2"
"github.com/photoprism/photoprism/internal/meta" "github.com/photoprism/photoprism/internal/meta"
"github.com/photoprism/photoprism/pkg/txt/report" "github.com/photoprism/photoprism/pkg/txt/report"
@@ -15,9 +15,10 @@ var ShowMetadataCommand = cli.Command{
Name: "metadata", Name: "metadata",
Aliases: []string{"meta"}, Aliases: []string{"meta"},
Usage: "Displays supported metadata tags and standards", Usage: "Displays supported metadata tags and standards",
Flags: append(report.CliFlags, cli.BoolFlag{ Flags: append(report.CliFlags, &cli.BoolFlag{
Name: "short, s", Name: "short",
Usage: "hide links to documentation", Aliases: []string{"s"},
Usage: "hide links to documentation",
}), }),
Action: showMetadataAction, Action: showMetadataAction,
} }

View File

@@ -4,7 +4,7 @@ import (
"fmt" "fmt"
"sort" "sort"
"github.com/urfave/cli" "github.com/urfave/cli/v2"
"github.com/photoprism/photoprism/internal/form" "github.com/photoprism/photoprism/internal/form"
"github.com/photoprism/photoprism/pkg/txt/report" "github.com/photoprism/photoprism/pkg/txt/report"

View File

@@ -3,7 +3,7 @@ package commands
import ( import (
"fmt" "fmt"
"github.com/urfave/cli" "github.com/urfave/cli/v2"
"github.com/photoprism/photoprism/internal/thumb" "github.com/photoprism/photoprism/internal/thumb"
"github.com/photoprism/photoprism/pkg/txt/report" "github.com/photoprism/photoprism/pkg/txt/report"

View File

@@ -3,7 +3,7 @@ package commands
import ( import (
"fmt" "fmt"
"github.com/urfave/cli" "github.com/urfave/cli/v2"
"github.com/photoprism/photoprism/internal/thumb" "github.com/photoprism/photoprism/internal/thumb"
"github.com/photoprism/photoprism/pkg/txt/report" "github.com/photoprism/photoprism/pkg/txt/report"

View File

@@ -11,9 +11,10 @@ import (
"github.com/dustin/go-humanize/english" "github.com/dustin/go-humanize/english"
"github.com/sevlyar/go-daemon" "github.com/sevlyar/go-daemon"
"github.com/urfave/cli" "github.com/urfave/cli/v2"
"github.com/photoprism/photoprism/internal/auth/session" "github.com/photoprism/photoprism/internal/auth/session"
"github.com/photoprism/photoprism/internal/config"
"github.com/photoprism/photoprism/internal/mutex" "github.com/photoprism/photoprism/internal/mutex"
"github.com/photoprism/photoprism/internal/photoprism/backup" "github.com/photoprism/photoprism/internal/photoprism/backup"
"github.com/photoprism/photoprism/internal/server" "github.com/photoprism/photoprism/internal/server"
@@ -35,14 +36,16 @@ var StartCommand = cli.Command{
// startFlags specifies the start command parameters. // startFlags specifies the start command parameters.
var startFlags = []cli.Flag{ var startFlags = []cli.Flag{
cli.BoolFlag{ &cli.BoolFlag{
Name: "detach-server, d", Name: "detach-server",
Usage: "detach from the console (daemon mode)", Aliases: []string{"d"},
EnvVar: "PHOTOPRISM_DETACH_SERVER", Usage: "detach from the console (daemon mode)",
EnvVars: config.EnvVars("DETACH_SERVER"),
}, },
cli.BoolFlag{ &cli.BoolFlag{
Name: "config, c", Name: "config",
Usage: "show config", Aliases: []string{"c"},
Usage: "show config",
}, },
} }
@@ -89,7 +92,7 @@ func startAction(ctx *cli.Context) error {
dctx := new(daemon.Context) dctx := new(daemon.Context)
dctx.LogFileName = conf.LogFilename() dctx.LogFileName = conf.LogFilename()
dctx.PidFileName = conf.PIDFilename() dctx.PidFileName = conf.PIDFilename()
dctx.Args = ctx.Args() dctx.Args = ctx.Args().Slice()
if !daemon.WasReborn() && conf.DetachServer() { if !daemon.WasReborn() && conf.DetachServer() {
conf.Shutdown() conf.Shutdown()

View File

@@ -9,7 +9,7 @@ import (
"time" "time"
"github.com/tidwall/gjson" "github.com/tidwall/gjson"
"github.com/urfave/cli" "github.com/urfave/cli/v2"
"github.com/photoprism/photoprism/internal/config" "github.com/photoprism/photoprism/internal/config"
) )

View File

@@ -4,7 +4,7 @@ import (
"syscall" "syscall"
"github.com/sevlyar/go-daemon" "github.com/sevlyar/go-daemon"
"github.com/urfave/cli" "github.com/urfave/cli/v2"
"github.com/photoprism/photoprism/pkg/clean" "github.com/photoprism/photoprism/pkg/clean"
) )

View File

@@ -5,7 +5,7 @@ import (
"strings" "strings"
"time" "time"
"github.com/urfave/cli" "github.com/urfave/cli/v2"
"github.com/photoprism/photoprism/internal/photoprism/get" "github.com/photoprism/photoprism/internal/photoprism/get"
"github.com/photoprism/photoprism/pkg/clean" "github.com/photoprism/photoprism/pkg/clean"
@@ -17,13 +17,15 @@ var ThumbsCommand = cli.Command{
Usage: "(Re-)generates thumbnails based on the current configuration", Usage: "(Re-)generates thumbnails based on the current configuration",
ArgsUsage: "[subfolder]", ArgsUsage: "[subfolder]",
Flags: []cli.Flag{ Flags: []cli.Flag{
cli.BoolFlag{ &cli.BoolFlag{
Name: "force, f", Name: "force",
Usage: "replace existing thumbnail images", Aliases: []string{"f"},
Usage: "replace existing thumbnail images",
}, },
cli.BoolFlag{ &cli.BoolFlag{
Name: "originals, o", Name: "originals",
Usage: "scan originals only, skip sidecar folder", Aliases: []string{"o"},
Usage: "scan originals only, skip sidecar folder",
}, },
}, },
Action: thumbsAction, Action: thumbsAction,

View File

@@ -1,7 +1,7 @@
package commands package commands
import ( import (
"github.com/urfave/cli" "github.com/urfave/cli/v2"
"github.com/photoprism/photoprism/internal/auth/acl" "github.com/photoprism/photoprism/internal/auth/acl"
"github.com/photoprism/photoprism/pkg/authn" "github.com/photoprism/photoprism/pkg/authn"
@@ -26,80 +26,91 @@ var UsersCommands = cli.Command{
Name: "users", Name: "users",
Aliases: []string{"user"}, Aliases: []string{"user"},
Usage: "User management subcommands", Usage: "User management subcommands",
Subcommands: []cli.Command{ Subcommands: []*cli.Command{
UsersListCommand, &UsersListCommand,
UsersLegacyCommand, &UsersLegacyCommand,
UsersAddCommand, &UsersAddCommand,
UsersShowCommand, &UsersShowCommand,
UsersModCommand, &UsersModCommand,
UsersRemoveCommand, &UsersRemoveCommand,
UsersResetCommand, &UsersResetCommand,
}, },
} }
// UserFlags specifies the add and modify user command flags. // UserFlags specifies the add and modify user command flags.
var UserFlags = []cli.Flag{ var UserFlags = []cli.Flag{
cli.StringFlag{ &cli.StringFlag{
Name: "name, n", Name: "name",
Usage: UserNameUsage, Aliases: []string{"n"},
Usage: UserNameUsage,
}, },
cli.StringFlag{ &cli.StringFlag{
Name: "email, m", Name: "email",
Usage: UserEmailUsage, Aliases: []string{"m"},
Usage: UserEmailUsage,
}, },
cli.StringFlag{ &cli.StringFlag{
Name: "password, p", Name: "password",
Usage: UserPasswordUsage, Aliases: []string{"p"},
Usage: UserPasswordUsage,
}, },
cli.StringFlag{ &cli.StringFlag{
Name: "role, r", Name: "role",
Usage: UserRoleUsage, Aliases: []string{"r"},
Value: acl.RoleAdmin.String(), Usage: UserRoleUsage,
Value: acl.RoleAdmin.String(),
}, },
cli.StringFlag{ &cli.StringFlag{
Name: "auth, A", Name: "auth",
Usage: UserAuthUsage, Aliases: []string{"A"},
Value: authn.ProviderDefault.String(), Usage: UserAuthUsage,
Value: authn.ProviderDefault.String(),
}, },
cli.StringFlag{ &cli.StringFlag{
Name: "auth-id", Name: "auth-id",
Usage: UserAuthIDUsage, Usage: UserAuthIDUsage,
Value: "", Value: "",
}, },
cli.BoolFlag{ &cli.BoolFlag{
Name: "superadmin, s", Name: "superadmin",
Usage: UserAdminUsage, Aliases: []string{"s"},
Usage: UserAdminUsage,
}, },
cli.BoolFlag{ &cli.BoolFlag{
Name: "no-login, l", Name: "no-login",
Usage: UserNoLoginUsage, Aliases: []string{"l"},
Usage: UserNoLoginUsage,
}, },
cli.BoolFlag{ &cli.BoolFlag{
Name: "webdav, w", Name: "webdav",
Usage: UserWebDAVUsage, Aliases: []string{"w"},
Usage: UserWebDAVUsage,
}, },
} }
// UserTokensFlag is a CLI flag for showing the security tokens in reports. // UserTokensFlag is a CLI flag for showing the security tokens in reports.
var UserTokensFlag = cli.BoolFlag{ var UserTokensFlag = &cli.BoolFlag{
Name: "tokens", Name: "tokens",
Usage: "show user preview and download tokens", Usage: "show user preview and download tokens",
} }
// UsersLoginFlag is a CLI flag for showing the last login timestamp in reports. // UsersLoginFlag is a CLI flag for showing the last login timestamp in reports.
var UsersLoginFlag = cli.BoolFlag{ var UsersLoginFlag = &cli.BoolFlag{
Name: "login, l", Name: "login",
Usage: "show date and time of last login", Aliases: []string{"l"},
Usage: "show date and time of last login",
} }
// UsersCreatedFlag is a CLI flag for showing the account creation timestamp in reports. // UsersCreatedFlag is a CLI flag for showing the account creation timestamp in reports.
var UsersCreatedFlag = cli.BoolFlag{ var UsersCreatedFlag = &cli.BoolFlag{
Name: "created, a", Name: "created",
Usage: "show account creation timestamp", Aliases: []string{"a"},
Usage: "show account creation timestamp",
} }
// UsersDeletedFlag is a CLI flag for showing deleted user accounts in reports. // UsersDeletedFlag is a CLI flag for showing deleted user accounts in reports.
var UsersDeletedFlag = cli.BoolFlag{ var UsersDeletedFlag = &cli.BoolFlag{
Name: "deleted, r", Name: "deleted",
Usage: "show deleted user accounts", Aliases: []string{"r"},
Usage: "show deleted user accounts",
} }

View File

@@ -4,7 +4,7 @@ import (
"fmt" "fmt"
"github.com/manifoldco/promptui" "github.com/manifoldco/promptui"
"github.com/urfave/cli" "github.com/urfave/cli/v2"
"github.com/photoprism/photoprism/internal/config" "github.com/photoprism/photoprism/internal/config"
"github.com/photoprism/photoprism/internal/entity" "github.com/photoprism/photoprism/internal/entity"

View File

@@ -12,11 +12,12 @@ func TestUsersAddCommand(t *testing.T) {
var err error var err error
// Create test context with flags and arguments. // Create test context with flags and arguments.
ctx := NewTestContext([]string{"add", "--name=Alice", "--email=jane@test.de", "--password=test1234", "--role=admin", "alice"}) args := []string{"add", "--name=Alice", "--email=jane@test.de", "--password=test1234", "--role=admin", "alice"}
ctx := NewTestContext(args)
// Run command with test context. // Run command with test context.
output := capture.Output(func() { output := capture.Output(func() {
err = UsersAddCommand.Run(ctx) err = UsersAddCommand.Run(ctx, args...)
}) })
// Check command output for plausibility. // Check command output for plausibility.
@@ -29,11 +30,12 @@ func TestUsersAddCommand(t *testing.T) {
var err error var err error
// Create test context with flags and arguments. // Create test context with flags and arguments.
ctx := NewTestContext([]string{"add", "--name=deleted", "--password=test1234", "deleted"}) args := []string{"add", "--name=deleted", "--password=test1234", "deleted"}
ctx := NewTestContext(args)
// Run command with test context. // Run command with test context.
output := capture.Output(func() { output := capture.Output(func() {
err = UsersAddCommand.Run(ctx) err = UsersAddCommand.Run(ctx, args...)
}) })
// Check command output for plausibility. // Check command output for plausibility.
@@ -46,11 +48,12 @@ func TestUsersAddCommand(t *testing.T) {
var err error var err error
// Create test context with flags and arguments. // Create test context with flags and arguments.
ctx := NewTestContext([]string{"add", "--name=noname", "--password=test1234", "/##"}) args := []string{"add", "--name=noname", "--password=test1234", "/##"}
ctx := NewTestContext(args)
// Run command with test context. // Run command with test context.
output := capture.Output(func() { output := capture.Output(func() {
err = UsersAddCommand.Run(ctx) err = UsersAddCommand.Run(ctx, args...)
}) })
// Check command output for plausibility. // Check command output for plausibility.

View File

@@ -4,7 +4,7 @@ import (
"fmt" "fmt"
"github.com/dustin/go-humanize/english" "github.com/dustin/go-humanize/english"
"github.com/urfave/cli" "github.com/urfave/cli/v2"
"github.com/photoprism/photoprism/internal/config" "github.com/photoprism/photoprism/internal/config"
"github.com/photoprism/photoprism/internal/entity" "github.com/photoprism/photoprism/internal/entity"

View File

@@ -12,11 +12,12 @@ func TestUsersLegacyCommand(t *testing.T) {
var err error var err error
// Create test context with flags and arguments. // Create test context with flags and arguments.
ctx := NewTestContext([]string{""}) args := []string{""}
ctx := NewTestContext(args)
// Run command with test context. // Run command with test context.
output := capture.Output(func() { output := capture.Output(func() {
err = UsersLegacyCommand.Run(ctx) err = UsersLegacyCommand.Run(ctx, args...)
}) })
// Check command output for plausibility. // Check command output for plausibility.

View File

@@ -4,7 +4,7 @@ import (
"fmt" "fmt"
"github.com/dustin/go-humanize/english" "github.com/dustin/go-humanize/english"
"github.com/urfave/cli" "github.com/urfave/cli/v2"
"github.com/photoprism/photoprism/internal/config" "github.com/photoprism/photoprism/internal/config"
"github.com/photoprism/photoprism/internal/entity/query" "github.com/photoprism/photoprism/internal/entity/query"
@@ -39,7 +39,7 @@ func usersListAction(ctx *cli.Context) error {
} }
// Fetch users from database. // Fetch users from database.
users, err := query.Users(ctx.Int("n"), 0, "", ctx.Args().First(), ctx.Bool("deleted")) users, err := query.Users(ctx.Int("count"), 0, "", ctx.Args().First(), ctx.Bool("deleted"))
if err != nil { if err != nil {
return err return err

View File

@@ -1,6 +1,8 @@
package commands package commands
import ( import (
"fmt"
"runtime/debug"
"testing" "testing"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
@@ -13,11 +15,12 @@ func TestUsersListCommand(t *testing.T) {
var err error var err error
// Create test context with flags and arguments. // Create test context with flags and arguments.
ctx := NewTestContext([]string{"ls", "--login", "--created", "--deleted", "-n", "100", "--md"}) args := []string{"ls", "--login", "--created", "--deleted", "-n", "100", "--md"}
ctx := NewTestContext(args)
// Run command with test context. // Run command with test context.
output := capture.Output(func() { output := capture.Output(func() {
err = UsersListCommand.Run(ctx) err = UsersListCommand.Run(ctx, args...)
}) })
// Check command output for plausibility. // Check command output for plausibility.
@@ -32,11 +35,12 @@ func TestUsersListCommand(t *testing.T) {
var err error var err error
// Create test context with flags and arguments. // Create test context with flags and arguments.
ctx := NewTestContext([]string{"ls", "-l", "friend"}) args := []string{"ls", "-l", "friend"}
ctx := NewTestContext(args)
// Run command with test context. // Run command with test context.
output := capture.Output(func() { output := capture.Output(func() {
err = UsersListCommand.Run(ctx) err = UsersListCommand.Run(ctx, args...)
}) })
// Check command output for plausibility. // Check command output for plausibility.
@@ -52,11 +56,12 @@ func TestUsersListCommand(t *testing.T) {
var err error var err error
// Create test context with flags and arguments. // Create test context with flags and arguments.
ctx := NewTestContext([]string{"ls", "-a", "friend"}) args := []string{"ls", "-a", "friend"}
ctx := NewTestContext(args)
// Run command with test context. // Run command with test context.
output := capture.Output(func() { output := capture.Output(func() {
err = UsersListCommand.Run(ctx) err = UsersListCommand.Run(ctx, args...)
}) })
// Check command output for plausibility. // Check command output for plausibility.
@@ -72,11 +77,12 @@ func TestUsersListCommand(t *testing.T) {
var err error var err error
// Create test context with flags and arguments. // Create test context with flags and arguments.
ctx := NewTestContext([]string{"ls", "-r", "friend"}) args := []string{"ls", "-r", "friend"}
ctx := NewTestContext(args)
// Run command with test context. // Run command with test context.
output := capture.Output(func() { output := capture.Output(func() {
err = UsersListCommand.Run(ctx) err = UsersListCommand.Run(ctx, args...)
}) })
// Check command output for plausibility. // Check command output for plausibility.
@@ -92,11 +98,12 @@ func TestUsersListCommand(t *testing.T) {
var err error var err error
// Create test context with flags and arguments. // Create test context with flags and arguments.
ctx := NewTestContext([]string{"ls", "--csv", "friend"}) args := []string{"ls", "--csv", "friend"}
ctx := NewTestContext(args)
// Run command with test context. // Run command with test context.
output := capture.Output(func() { output := capture.Output(func() {
err = UsersListCommand.Run(ctx) err = UsersListCommand.Run(ctx, args...)
}) })
// Check command output for plausibility. // Check command output for plausibility.
@@ -112,11 +119,12 @@ func TestUsersListCommand(t *testing.T) {
var err error var err error
// Create test context with flags and arguments. // Create test context with flags and arguments.
ctx := NewTestContext([]string{"ls", "notexisting"}) args := []string{"ls", "notexisting"}
ctx := NewTestContext(args)
// Run command with test context. // Run command with test context.
output := capture.Output(func() { output := capture.Output(func() {
err = UsersListCommand.Run(ctx) err = UsersListCommand.Run(ctx, args...)
}) })
// Check command output for plausibility. // Check command output for plausibility.
@@ -124,15 +132,39 @@ func TestUsersListCommand(t *testing.T) {
assert.NoError(t, err) assert.NoError(t, err)
assert.Empty(t, output) assert.Empty(t, output)
}) })
t.Run("InvalidFlag", func(t *testing.T) { t.Run("OneResult", func(t *testing.T) {
var err error var err error
// Create test context with flags and arguments. // Create test context with flags and arguments.
ctx := NewTestContext([]string{"ls", "--xyz", "friend"}) args := []string{"ls", "--count=1", "friend"}
ctx := NewTestContext(args)
// Run command with test context. // Run command with test context.
output := capture.Output(func() { output := capture.Output(func() {
err = UsersListCommand.Run(ctx) err = UsersListCommand.Run(ctx, args...)
})
// Check result.
assert.NoError(t, err)
assert.NotEmpty(t, output)
})
t.Run("InvalidFlag", func(t *testing.T) {
var err error
defer func() {
if r := recover(); r != nil {
err = fmt.Errorf("error: %s \nstack: %s", r, debug.Stack())
assert.Error(t, err)
}
}()
// Create test context with flags and arguments.
args := []string{"ls", "--xyz", "friend"}
ctx := NewTestContext(args)
// Run command with test context.
output := capture.Output(func() {
err = UsersListCommand.Run(ctx, args...)
}) })
// Check command output for plausibility. // Check command output for plausibility.
@@ -140,20 +172,4 @@ func TestUsersListCommand(t *testing.T) {
assert.Error(t, err) assert.Error(t, err)
assert.Empty(t, output) assert.Empty(t, output)
}) })
t.Run("InvalidValue", func(t *testing.T) {
var err error
// Create test context with flags and arguments.
ctx := NewTestContext([]string{"ls", "-n=-1", "friend"})
// Run command with test context.
output := capture.Output(func() {
err = UsersListCommand.Run(ctx)
})
// Check command output for plausibility.
//t.Logf(output)
assert.Error(t, err)
assert.Empty(t, output)
})
} }

View File

@@ -4,7 +4,7 @@ import (
"fmt" "fmt"
"github.com/manifoldco/promptui" "github.com/manifoldco/promptui"
"github.com/urfave/cli" "github.com/urfave/cli/v2"
"github.com/photoprism/photoprism/internal/config" "github.com/photoprism/photoprism/internal/config"
"github.com/photoprism/photoprism/internal/entity" "github.com/photoprism/photoprism/internal/entity"
@@ -17,7 +17,7 @@ var UsersModCommand = cli.Command{
Name: "mod", Name: "mod",
Usage: "Changes user account settings", Usage: "Changes user account settings",
ArgsUsage: "[username]", ArgsUsage: "[username]",
Flags: append(UserFlags, cli.BoolFlag{ Flags: append(UserFlags, &cli.BoolFlag{
Name: "disable-2fa", Name: "disable-2fa",
Usage: UserDisable2FA, Usage: UserDisable2FA,
}), }),

View File

@@ -12,11 +12,12 @@ func TestUsersModCommand(t *testing.T) {
var err error var err error
// Create test context with flags and arguments. // Create test context with flags and arguments.
ctx := NewTestContext([]string{"mod", "--name=New", "--email=new@test.de", "uqxqg7i1kperxxx0"}) args := []string{"mod", "--name=New", "--email=new@test.de", "uqxqg7i1kperxxx0"}
ctx := NewTestContext(args)
// Run command with test context. // Run command with test context.
output := capture.Output(func() { output := capture.Output(func() {
err = UsersModCommand.Run(ctx) err = UsersModCommand.Run(ctx, args...)
}) })
// Check command output for plausibility. // Check command output for plausibility.
@@ -28,11 +29,12 @@ func TestUsersModCommand(t *testing.T) {
var err error var err error
// Create test context with flags and arguments. // Create test context with flags and arguments.
ctx := NewTestContext([]string{"mod", "--name=New", "--email=new@test.de", "deleted"}) args := []string{"mod", "--name=New", "--email=new@test.de", "deleted"}
ctx := NewTestContext(args)
// Run command with test context. // Run command with test context.
output := capture.Output(func() { output := capture.Output(func() {
err = UsersModCommand.Run(ctx) err = UsersModCommand.Run(ctx, args...)
}) })
// Check command output for plausibility. // Check command output for plausibility.

View File

@@ -4,7 +4,7 @@ import (
"fmt" "fmt"
"github.com/manifoldco/promptui" "github.com/manifoldco/promptui"
"github.com/urfave/cli" "github.com/urfave/cli/v2"
"github.com/photoprism/photoprism/internal/config" "github.com/photoprism/photoprism/internal/config"
"github.com/photoprism/photoprism/internal/entity" "github.com/photoprism/photoprism/internal/entity"
@@ -18,9 +18,10 @@ var UsersRemoveCommand = cli.Command{
Usage: "Deletes a registered user account", Usage: "Deletes a registered user account",
ArgsUsage: "[username]", ArgsUsage: "[username]",
Flags: []cli.Flag{ Flags: []cli.Flag{
cli.BoolFlag{ &cli.BoolFlag{
Name: "force, f", Name: "force",
Usage: "don't ask for confirmation", Aliases: []string{"f"},
Usage: "don't ask for confirmation",
}, },
}, },
Action: usersRemoveAction, Action: usersRemoveAction,

View File

@@ -12,11 +12,12 @@ func TestUsersRemoveCommand(t *testing.T) {
var err error var err error
// Create test context with flags and arguments. // Create test context with flags and arguments.
ctx := NewTestContext([]string{"rm", "uqxqg7i1kperxxx0"}) args := []string{"rm", "uqxqg7i1kperxxx0"}
ctx := NewTestContext(args)
// Run command with test context. // Run command with test context.
output := capture.Output(func() { output := capture.Output(func() {
err = UsersRemoveCommand.Run(ctx) err = UsersRemoveCommand.Run(ctx, args...)
}) })
// Check command output for plausibility. // Check command output for plausibility.
@@ -28,11 +29,12 @@ func TestUsersRemoveCommand(t *testing.T) {
var err error var err error
// Create test context with flags and arguments. // Create test context with flags and arguments.
ctx := NewTestContext([]string{"rm", "deleted"}) args := []string{"rm", "deleted"}
ctx := NewTestContext(args)
// Run command with test context. // Run command with test context.
output := capture.Output(func() { output := capture.Output(func() {
err = UsersRemoveCommand.Run(ctx) err = UsersRemoveCommand.Run(ctx, args...)
}) })
// Check command output for plausibility. // Check command output for plausibility.

View File

@@ -5,7 +5,7 @@ import (
"github.com/manifoldco/promptui" "github.com/manifoldco/promptui"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
"github.com/urfave/cli" "github.com/urfave/cli/v2"
"github.com/photoprism/photoprism/internal/config" "github.com/photoprism/photoprism/internal/config"
"github.com/photoprism/photoprism/internal/entity" "github.com/photoprism/photoprism/internal/entity"
@@ -19,13 +19,15 @@ var UsersResetCommand = cli.Command{
Usage: "Removes all registered user accounts", Usage: "Removes all registered user accounts",
Description: UsersResetDescription, Description: UsersResetDescription,
Flags: []cli.Flag{ Flags: []cli.Flag{
cli.BoolFlag{ &cli.BoolFlag{
Name: "trace, t", Name: "trace",
Usage: "show trace logs for debugging", Aliases: []string{"t"},
Usage: "show trace logs for debugging",
}, },
cli.BoolFlag{ &cli.BoolFlag{
Name: "yes, y", Name: "yes",
Usage: "assume \"yes\" and run non-interactively", Aliases: []string{"y"},
Usage: "assume \"yes\" and run non-interactively",
}, },
}, },
Action: usersResetAction, Action: usersResetAction,

View File

@@ -12,11 +12,12 @@ func TestUsersResetCommand(t *testing.T) {
var err error var err error
// Create test context with flags and arguments. // Create test context with flags and arguments.
ctx0 := NewTestContext([]string{"ls"}) args0 := []string{"ls"}
ctx0 := NewTestContext(args0)
// Run command with test context. // Run command with test context.
output0 := capture.Output(func() { output0 := capture.Output(func() {
err = UsersListCommand.Run(ctx0) err = UsersListCommand.Run(ctx0, args0...)
}) })
// Check command output for plausibility. // Check command output for plausibility.
@@ -26,11 +27,12 @@ func TestUsersResetCommand(t *testing.T) {
assert.Contains(t, output0, "bob") assert.Contains(t, output0, "bob")
// Create test context with flags and arguments. // Create test context with flags and arguments.
ctx := NewTestContext([]string{"reset"}) args := []string{"reset"}
ctx := NewTestContext(args)
// Run command with test context. // Run command with test context.
output := capture.Output(func() { output := capture.Output(func() {
err = UsersResetCommand.Run(ctx) err = UsersResetCommand.Run(ctx, args...)
}) })
// Check command output for plausibility. // Check command output for plausibility.
@@ -40,7 +42,7 @@ func TestUsersResetCommand(t *testing.T) {
// Run command with test context. // Run command with test context.
output1 := capture.Output(func() { output1 := capture.Output(func() {
err = UsersListCommand.Run(ctx0) err = UsersListCommand.Run(ctx0, args0...)
}) })
// Check command output for plausibility. // Check command output for plausibility.

View File

@@ -3,7 +3,7 @@ package commands
import ( import (
"fmt" "fmt"
"github.com/urfave/cli" "github.com/urfave/cli/v2"
"github.com/photoprism/photoprism/internal/config" "github.com/photoprism/photoprism/internal/config"
"github.com/photoprism/photoprism/internal/entity" "github.com/photoprism/photoprism/internal/entity"

View File

@@ -12,11 +12,12 @@ func TestUsersShowCommand(t *testing.T) {
var err error var err error
// Create test context with flags and arguments. // Create test context with flags and arguments.
ctx := NewTestContext([]string{"show", "alice"}) args := []string{"show", "alice"}
ctx := NewTestContext(args)
// Run command with test context. // Run command with test context.
output := capture.Output(func() { output := capture.Output(func() {
err = UsersShowCommand.Run(ctx) err = UsersShowCommand.Run(ctx, args...)
}) })
// Check command output for plausibility. // Check command output for plausibility.
@@ -30,11 +31,12 @@ func TestUsersShowCommand(t *testing.T) {
var err error var err error
// Create test context with flags and arguments. // Create test context with flags and arguments.
ctx := NewTestContext([]string{"show", "notexisting"}) args := []string{"show", "notexisting"}
ctx := NewTestContext(args)
// Run command with test context. // Run command with test context.
output := capture.Output(func() { output := capture.Output(func() {
err = UsersShowCommand.Run(ctx) err = UsersShowCommand.Run(ctx, args...)
}) })
// Check command output for plausibility. // Check command output for plausibility.

View File

@@ -12,11 +12,12 @@ func TestUsersCommand(t *testing.T) {
var err error var err error
//Add John //Add John
ctx := NewTestContext([]string{"add", "--name=John", "--email=john@test.de", "--password=test1234", "--role=admin", "john"}) args := []string{"add", "--name=John", "--email=john@test.de", "--password=test1234", "--role=admin", "john"}
ctx := NewTestContext(args)
// Run command with test context. // Run command with test context.
output := capture.Output(func() { output := capture.Output(func() {
err = UsersAddCommand.Run(ctx) err = UsersAddCommand.Run(ctx, args...)
}) })
// Check command output for plausibility. // Check command output for plausibility.
@@ -24,11 +25,12 @@ func TestUsersCommand(t *testing.T) {
assert.NoError(t, err) assert.NoError(t, err)
assert.Empty(t, output) assert.Empty(t, output)
ctx2 := NewTestContext([]string{"show", "john"}) args2 := []string{"show", "john"}
ctx2 := NewTestContext(args2)
// Run command with test context. // Run command with test context.
output2 := capture.Output(func() { output2 := capture.Output(func() {
err = UsersShowCommand.Run(ctx2) err = UsersShowCommand.Run(ctx2, args2...)
}) })
//t.Logf(output2) //t.Logf(output2)
@@ -40,11 +42,12 @@ func TestUsersCommand(t *testing.T) {
//Modify John //Modify John
// Create test context with flags and arguments. // Create test context with flags and arguments.
ctx3 := NewTestContext([]string{"mod", "--name=Johnny", "--email=johnnny@test.de", "--password=test12345", "john"}) args3 := []string{"mod", "--name=Johnny", "--email=johnnny@test.de", "--password=test12345", "john"}
ctx3 := NewTestContext(args3)
// Run command with test context. // Run command with test context.
output3 := capture.Output(func() { output3 := capture.Output(func() {
err = UsersModCommand.Run(ctx3) err = UsersModCommand.Run(ctx3, args3...)
}) })
// Check command output for plausibility. // Check command output for plausibility.
@@ -53,7 +56,7 @@ func TestUsersCommand(t *testing.T) {
assert.Empty(t, output3) assert.Empty(t, output3)
output4 := capture.Output(func() { output4 := capture.Output(func() {
err = UsersShowCommand.Run(ctx2) err = UsersShowCommand.Run(ctx2, args2...)
}) })
//t.Logf(output4) //t.Logf(output4)
@@ -65,11 +68,12 @@ func TestUsersCommand(t *testing.T) {
//Remove John //Remove John
// Create test context with flags and arguments. // Create test context with flags and arguments.
ctx5 := NewTestContext([]string{"rm", "--force", "john"}) args5 := []string{"rm", "--force", "john"}
ctx5 := NewTestContext(args5)
// Run command with test context. // Run command with test context.
output5 := capture.Output(func() { output5 := capture.Output(func() {
err = UsersRemoveCommand.Run(ctx5) err = UsersRemoveCommand.Run(ctx5, args5...)
}) })
// Check command output for plausibility. // Check command output for plausibility.
@@ -78,7 +82,7 @@ func TestUsersCommand(t *testing.T) {
assert.Empty(t, output5) assert.Empty(t, output5)
output6 := capture.Output(func() { output6 := capture.Output(func() {
err = UsersShowCommand.Run(ctx2) err = UsersShowCommand.Run(ctx2, args2...)
}) })
//t.Logf(output6) //t.Logf(output6)

View File

@@ -3,19 +3,19 @@ package commands
import ( import (
"fmt" "fmt"
"github.com/urfave/cli" "github.com/urfave/cli/v2"
"github.com/photoprism/photoprism/internal/config" "github.com/photoprism/photoprism/internal/config"
) )
// VersionCommand configures the command name, flags, and action. // VersionCommand configures the "photoprism version" command.
var VersionCommand = cli.Command{ var VersionCommand = cli.Command{
Name: "version", Name: "version",
Usage: "Shows version information", Usage: "Shows version information",
Action: versionAction, Action: versionAction,
} }
// versionAction prints the current version // versionAction displays information about the current version.
func versionAction(ctx *cli.Context) error { func versionAction(ctx *cli.Context) error {
conf := config.NewConfig(ctx) conf := config.NewConfig(ctx)

View File

@@ -8,18 +8,21 @@ import (
) )
func TestVersionCommand(t *testing.T) { func TestVersionCommand(t *testing.T) {
var err error t.Run("Success", func(t *testing.T) {
var err error
// Create test context with flags and arguments. // Create test context with flags and arguments.
ctx := NewTestContext([]string{""}) args := []string{"version"}
ctx := NewTestContext(args)
// Run command with test context. // Run command with test context.
output := capture.Output(func() { output := capture.Output(func() {
err = VersionCommand.Run(ctx) err = VersionCommand.Run(ctx, args...)
})
// Check command output for plausibility.
// t.Logf(output)
assert.NoError(t, err)
assert.Contains(t, output, "test")
}) })
// Check command output for plausibility.
// t.Logf(output)
assert.NoError(t, err)
assert.Contains(t, output, "test")
} }

View File

@@ -4,7 +4,7 @@ import (
"reflect" "reflect"
"time" "time"
"github.com/urfave/cli" "github.com/urfave/cli/v2"
"github.com/photoprism/photoprism/pkg/txt" "github.com/photoprism/photoprism/pkg/txt"
) )
@@ -26,10 +26,8 @@ func ApplyCliContext(c interface{}, ctx *cli.Context) error {
var s string var s string
// Get duration string. // Get duration string.
if ctx.IsSet(tagValue) { if ctx.IsSet(tagValue) || fieldValue.Interface().(time.Duration) == 0 {
s = ctx.String(tagValue) s = ctx.String(tagValue)
} else if ctx.GlobalIsSet(tagValue) || fieldValue.Interface().(time.Duration) == 0 {
s = ctx.GlobalString(tagValue)
} }
// Parse duration string. // Parse duration string.
@@ -42,55 +40,37 @@ func ApplyCliContext(c interface{}, ctx *cli.Context) error {
} }
case float64: case float64:
// Only if explicitly set or current value is empty (use default). // Only if explicitly set or current value is empty (use default).
if ctx.IsSet(tagValue) { if ctx.IsSet(tagValue) || fieldValue.Float() == 0 {
f := ctx.Float64(tagValue) f := ctx.Float64(tagValue)
fieldValue.SetFloat(f) fieldValue.SetFloat(f)
} else if ctx.GlobalIsSet(tagValue) || fieldValue.Float() == 0 {
f := ctx.GlobalFloat64(tagValue)
fieldValue.SetFloat(f)
} }
case int, int64: case int, int64:
// Only if explicitly set or current value is empty (use default). // Only if explicitly set or current value is empty (use default).
if ctx.IsSet(tagValue) { if ctx.IsSet(tagValue) || fieldValue.Int() == 0 {
f := ctx.Int64(tagValue) f := ctx.Int64(tagValue)
fieldValue.SetInt(f) fieldValue.SetInt(f)
} else if ctx.GlobalIsSet(tagValue) || fieldValue.Int() == 0 {
f := ctx.GlobalInt64(tagValue)
fieldValue.SetInt(f)
} }
case uint, uint64: case uint, uint64:
// Only if explicitly set or current value is empty (use default). // Only if explicitly set or current value is empty (use default).
if ctx.IsSet(tagValue) { if ctx.IsSet(tagValue) || fieldValue.Uint() == 0 {
f := ctx.Uint64(tagValue) f := ctx.Uint64(tagValue)
fieldValue.SetUint(f) fieldValue.SetUint(f)
} else if ctx.GlobalIsSet(tagValue) || fieldValue.Uint() == 0 {
f := ctx.GlobalUint64(tagValue)
fieldValue.SetUint(f)
} }
case string: case string:
// Only if explicitly set or current value is empty (use default) // Only if explicitly set or current value is empty (use default)
if ctx.IsSet(tagValue) { if ctx.IsSet(tagValue) || fieldValue.String() == "" {
f := ctx.String(tagValue) f := ctx.String(tagValue)
fieldValue.SetString(f) fieldValue.SetString(f)
} else if ctx.GlobalIsSet(tagValue) || fieldValue.String() == "" {
f := ctx.GlobalString(tagValue)
fieldValue.SetString(f)
} }
case []string: case []string:
if ctx.IsSet(tagValue) { if ctx.IsSet(tagValue) || fieldValue.Len() == 0 {
f := reflect.ValueOf(ctx.StringSlice(tagValue)) f := reflect.ValueOf(ctx.StringSlice(tagValue))
fieldValue.Set(f) fieldValue.Set(f)
} else if ctx.GlobalIsSet(tagValue) || fieldValue.Len() == 0 {
f := reflect.ValueOf(ctx.GlobalStringSlice(tagValue))
fieldValue.Set(f)
} }
case bool: case bool:
if ctx.IsSet(tagValue) { if ctx.IsSet(tagValue) {
f := ctx.Bool(tagValue) f := ctx.Bool(tagValue)
fieldValue.SetBool(f) fieldValue.SetBool(f)
} else if ctx.GlobalIsSet(tagValue) {
f := ctx.GlobalBool(tagValue)
fieldValue.SetBool(f)
} }
default: default:
log.Warnf("cannot assign value of type %s from cli flag %s", t, tagValue) log.Warnf("cannot assign value of type %s from cli flag %s", t, tagValue)

View File

@@ -4,7 +4,7 @@ import (
"reflect" "reflect"
"strings" "strings"
"github.com/urfave/cli" "github.com/urfave/cli/v2"
"github.com/photoprism/photoprism/pkg/list" "github.com/photoprism/photoprism/pkg/list"
) )
@@ -52,26 +52,49 @@ func (f CliFlag) Hidden() bool {
return true return true
} }
// EnvVar returns the flag environment variable name. // EnvVar returns the names of the environment variables as a comma separated string.
func (f CliFlag) EnvVar() string { func (f CliFlag) EnvVar() string {
field := f.Fields().FieldByName("EnvVar") return strings.Join(f.EnvVars(), ", ")
if !field.IsValid() {
return ""
}
return field.String()
} }
// Name returns the command flag name. // EnvVars returns the environment variable names as string slice.
func (f CliFlag) EnvVars() []string {
field := f.Fields().FieldByName("EnvVars")
if !field.IsValid() {
return []string{}
}
if vars := field.Interface().([]string); len(vars) > 0 {
return vars
}
return []string{}
}
// Name returns the command flag names as a comma-separated string.
func (f CliFlag) String() string {
return strings.Join(f.Names(), ", ")
}
// Name returns the default command flag name.
func (f CliFlag) Name() string { func (f CliFlag) Name() string {
return f.Flag.GetName() if n := f.Flag.Names(); len(n) > 0 {
return n[0]
}
return ""
}
// Names returns the command flag names as string slice.
func (f CliFlag) Names() []string {
return f.Flag.Names()
} }
// CommandFlag returns the full command flag based on the name. // CommandFlag returns the full command flag based on the name.
func (f CliFlag) CommandFlag() string { func (f CliFlag) CommandFlag() string {
n := strings.Split(f.Name(), ",") n := strings.Split(f.String(), ",")
return "--" + n[0] return "--" + strings.TrimSpace(n[0])
} }
// Usage returns the command flag usage. // Usage returns the command flag usage.

View File

@@ -4,24 +4,24 @@ import (
"testing" "testing"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/urfave/cli" "github.com/urfave/cli/v2"
) )
func TestCliFlag_Skip(t *testing.T) { func TestCliFlag_Skip(t *testing.T) {
withTags := CliFlag{ withTags := CliFlag{
Flag: cli.StringFlag{ Flag: &cli.StringFlag{
Name: "with-tags", Name: "with-tags",
Usage: "`STRING`", Usage: "`STRING`",
EnvVar: "PHOTOPRISM_WITH_TAGS", EnvVars: []string{"PHOTOPRISM_WITH_TAGS"},
}, },
Tags: []string{"foo", "bar"}, Tags: []string{"foo", "bar"},
} }
noTags := CliFlag{ noTags := CliFlag{
Flag: cli.StringFlag{ Flag: &cli.StringFlag{
Name: "no-tags", Name: "no-tags",
Usage: "`STRING`", Usage: "`STRING`",
EnvVar: "PHOTOPRISM_NO_TAGS", EnvVars: []string{"PHOTOPRISM_NO_TAGS"},
}, },
Tags: []string{}, Tags: []string{},
} }
@@ -38,21 +38,21 @@ func TestCliFlag_Skip(t *testing.T) {
func TestCliFlag_Hidden(t *testing.T) { func TestCliFlag_Hidden(t *testing.T) {
hidden := CliFlag{ hidden := CliFlag{
Flag: cli.StringFlag{ Flag: &cli.StringFlag{
Name: "is-hidden", Name: "is-hidden",
Usage: "`STRING`", Usage: "`STRING`",
EnvVar: "PHOTOPRISM_HIDDEN", EnvVars: []string{"PHOTOPRISM_HIDDEN"},
Hidden: true, Hidden: true,
}, },
Tags: []string{"foo", "bar"}, Tags: []string{"foo", "bar"},
} }
visible := CliFlag{ visible := CliFlag{
Flag: cli.StringFlag{ Flag: &cli.StringFlag{
Name: "is-visible", Name: "is-visible",
Usage: "`STRING`", Usage: "`STRING`",
EnvVar: "PHOTOPRISM_VISIBLE", EnvVars: []string{"PHOTOPRISM_VISIBLE"},
Hidden: false, Hidden: false,
}, },
Tags: []string{}, Tags: []string{},
} }
@@ -67,20 +67,20 @@ func TestCliFlag_Hidden(t *testing.T) {
func TestCliFlag_Default(t *testing.T) { func TestCliFlag_Default(t *testing.T) {
hasdefault := CliFlag{ hasdefault := CliFlag{
Flag: cli.StringFlag{ Flag: &cli.StringFlag{
Name: "flag-with-default", Name: "flag-with-default",
Usage: "`STRING`", Usage: "`STRING`",
EnvVar: "PHOTOPRISM_DEFAULT", EnvVars: []string{"PHOTOPRISM_DEFAULT"},
}, },
DocDefault: "default-value", DocDefault: "default-value",
Tags: []string{"foo", "bar"}, Tags: []string{"foo", "bar"},
} }
nodefault := CliFlag{ nodefault := CliFlag{
Flag: cli.StringFlag{ Flag: &cli.StringFlag{
Name: "flag-without-default", Name: "flag-without-default",
Usage: "`STRING`", Usage: "`STRING`",
EnvVar: "PHOTOPRISM_NODEFAULT", EnvVars: []string{"PHOTOPRISM_NODEFAULT"},
}, },
Tags: []string{}, Tags: []string{},
} }
@@ -91,10 +91,10 @@ func TestCliFlag_Default(t *testing.T) {
func TestCliFlag_EnvVar(t *testing.T) { func TestCliFlag_EnvVar(t *testing.T) {
hasDefault := CliFlag{ hasDefault := CliFlag{
Flag: cli.StringFlag{ Flag: &cli.StringFlag{
Name: "flag-with-default", Name: "flag-with-default",
Usage: "`STRING`", Usage: "`STRING`",
EnvVar: "PHOTOPRISM_DEFAULT", EnvVars: []string{"PHOTOPRISM_DEFAULT"},
}, },
DocDefault: "default-value", DocDefault: "default-value",
Tags: []string{"foo", "bar"}, Tags: []string{"foo", "bar"},
@@ -105,10 +105,10 @@ func TestCliFlag_EnvVar(t *testing.T) {
func TestCliFlag_CommandFlag(t *testing.T) { func TestCliFlag_CommandFlag(t *testing.T) {
hasdefault := CliFlag{ hasdefault := CliFlag{
Flag: cli.StringFlag{ Flag: &cli.StringFlag{
Name: "flag-with-default", Name: "flag-with-default",
Usage: "`STRING`", Usage: "`STRING`",
EnvVar: "PHOTOPRISM_DEFAULT", EnvVars: []string{"PHOTOPRISM_DEFAULT"},
}, },
DocDefault: "default-value", DocDefault: "default-value",
Tags: []string{"foo", "bar"}, Tags: []string{"foo", "bar"},
@@ -119,7 +119,7 @@ func TestCliFlag_CommandFlag(t *testing.T) {
func TestCliFlag_Usage(t *testing.T) { func TestCliFlag_Usage(t *testing.T) {
community := CliFlag{ community := CliFlag{
Flag: cli.StringFlag{ Flag: &cli.StringFlag{
Name: "flag-community", Name: "flag-community",
Usage: "`STRING`", Usage: "`STRING`",
}, },
@@ -128,7 +128,7 @@ func TestCliFlag_Usage(t *testing.T) {
} }
essentials := CliFlag{ essentials := CliFlag{
Flag: cli.StringFlag{ Flag: &cli.StringFlag{
Name: "flag-essentials", Name: "flag-essentials",
Usage: "`STRING`", Usage: "`STRING`",
}, },
@@ -136,7 +136,7 @@ func TestCliFlag_Usage(t *testing.T) {
} }
plus := CliFlag{ plus := CliFlag{
Flag: cli.StringFlag{ Flag: &cli.StringFlag{
Name: "flag-plus", Name: "flag-plus",
Usage: "`STRING`", Usage: "`STRING`",
}, },
@@ -144,7 +144,7 @@ func TestCliFlag_Usage(t *testing.T) {
} }
pro := CliFlag{ pro := CliFlag{
Flag: cli.StringFlag{ Flag: &cli.StringFlag{
Name: "flag-pro", Name: "flag-pro",
Usage: "`STRING`", Usage: "`STRING`",
}, },

View File

@@ -1,12 +1,22 @@
package config package config
import ( import (
"github.com/urfave/cli" "strings"
"github.com/urfave/cli/v2"
"github.com/photoprism/photoprism/pkg/clean" "github.com/photoprism/photoprism/pkg/clean"
"github.com/photoprism/photoprism/pkg/list" "github.com/photoprism/photoprism/pkg/list"
) )
func firstName(names string) string {
if n := strings.Split(names, ","); len(n) > 0 {
return strings.TrimSpace(n[0])
}
return ""
}
// CliFlags represents a list of command-line parameters. // CliFlags represents a list of command-line parameters.
type CliFlags []CliFlag type CliFlags []CliFlag
@@ -41,7 +51,7 @@ func (f CliFlags) Remove(names []string) (result CliFlags) {
result = make(CliFlags, 0, len(f)) result = make(CliFlags, 0, len(f))
for _, flag := range f { for _, flag := range f {
if list.Contains(names, flag.Name()) { if list.ContainsAny(names, []string{flag.Name(), flag.String()}) {
continue continue
} }
@@ -55,10 +65,12 @@ func (f CliFlags) Remove(names []string) (result CliFlags) {
func (f CliFlags) Replace(name string, replacement CliFlag) CliFlags { func (f CliFlags) Replace(name string, replacement CliFlag) CliFlags {
done := false done := false
for i, flag := range f { if name = firstName(name); name != "" {
if !done && flag.Name() == name { for i, flag := range f {
f[i] = replacement if !done && flag.Name() == name {
done = true f[i] = replacement
done = true
}
} }
} }
@@ -72,15 +84,16 @@ func (f CliFlags) Replace(name string, replacement CliFlag) CliFlags {
// Insert inserts command flags, if possible after the flag specified by name. // Insert inserts command flags, if possible after the flag specified by name.
func (f CliFlags) Insert(name string, insert []CliFlag) (result CliFlags) { func (f CliFlags) Insert(name string, insert []CliFlag) (result CliFlags) {
result = make(CliFlags, 0, len(f)+len(insert)) result = make(CliFlags, 0, len(f)+len(insert))
done := false done := false
for _, flag := range f { if name = firstName(name); name != "" {
result = append(result, flag) for _, flag := range f {
result = append(result, flag)
if !done && flag.Name() == name { if !done && flag.Name() == name {
result = append(result, insert...) result = append(result, insert...)
done = true done = true
}
} }
} }
@@ -95,16 +108,17 @@ func (f CliFlags) Insert(name string, insert []CliFlag) (result CliFlags) {
// InsertBefore inserts command flags, if possible before the flag specified by name. // InsertBefore inserts command flags, if possible before the flag specified by name.
func (f CliFlags) InsertBefore(name string, insert []CliFlag) (result CliFlags) { func (f CliFlags) InsertBefore(name string, insert []CliFlag) (result CliFlags) {
result = make(CliFlags, 0, len(f)+len(insert)) result = make(CliFlags, 0, len(f)+len(insert))
done := false done := false
for _, flag := range f { if name = firstName(name); name != "" {
if !done && flag.Name() == name { for _, flag := range f {
result = append(result, insert...) if !done && flag.Name() == name {
done = true result = append(result, insert...)
} done = true
}
result = append(result, flag) result = append(result, flag)
}
} }
if !done { if !done {

View File

@@ -4,7 +4,7 @@ import (
"testing" "testing"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/urfave/cli" "github.com/urfave/cli/v2"
) )
func TestCliFlags_Cli(t *testing.T) { func TestCliFlags_Cli(t *testing.T) {
@@ -26,39 +26,42 @@ func TestCliFlags_Find(t *testing.T) {
} }
func TestCliFlags_Replace(t *testing.T) { func TestCliFlags_Replace(t *testing.T) {
originalPublicFlag := CliFlag{Flag: cli.BoolFlag{ originalPublicFlag := CliFlag{Flag: &cli.BoolFlag{
Name: "public, p", Name: "public",
Hidden: true, Aliases: []string{"p"},
Usage: "disable authentication, advanced settings, and WebDAV remote access", Hidden: true,
EnvVar: EnvVar("PUBLIC"), Usage: "disable authentication, advanced settings, and WebDAV remote access",
EnvVars: EnvVars("PUBLIC"),
}} }}
newPublicFlag := CliFlag{Flag: cli.BoolFlag{ newPublicFlag := CliFlag{Flag: &cli.BoolFlag{
Name: "public", Name: "public",
Hidden: false, Hidden: false,
Usage: "disable authentication, advanced settings, and WebDAV remote access", Usage: "disable authentication, advanced settings, and WebDAV remote access",
EnvVar: EnvVar("PUBLIC"), EnvVars: EnvVars("PUBLIC"),
}} }}
cliFlags := CliFlags{ cliFlags := CliFlags{
{ {
Flag: cli.StringFlag{ Flag: &cli.StringFlag{
Name: "auth-mode, a", Name: "auth-mode",
Usage: "authentication `MODE` (public, password)", Aliases: []string{"a"},
Value: "password", Usage: "authentication `MODE` (public, password)",
EnvVar: EnvVar("AUTH_MODE"), Value: "password",
EnvVars: EnvVars("AUTH_MODE"),
}}, }},
originalPublicFlag, originalPublicFlag,
{ {
Flag: cli.StringFlag{ Flag: &cli.StringFlag{
Name: "admin-user, login", Name: "admin-user",
Usage: "`USERNAME` of the superadmin account that is created on first startup", Aliases: []string{"login"},
Value: "admin", Usage: "`USERNAME` of the superadmin account that is created on first startup",
EnvVar: EnvVar("ADMIN_USER"), Value: "admin",
EnvVars: EnvVars("ADMIN_USER"),
}}} }}}
assert.Equal(t, 3, len(cliFlags)) assert.Equal(t, 3, len(cliFlags))
assert.Equal(t, originalPublicFlag.Name(), cliFlags[1].Name()) assert.Equal(t, originalPublicFlag.String(), cliFlags[1].String())
assert.Equal(t, originalPublicFlag.Hidden(), cliFlags[1].Hidden()) assert.Equal(t, originalPublicFlag.Hidden(), cliFlags[1].Hidden())
t.Run("WrongName", func(t *testing.T) { t.Run("WrongName", func(t *testing.T) {
@@ -66,16 +69,16 @@ func TestCliFlags_Replace(t *testing.T) {
r := cliFlags.Replace("xxx", newPublicFlag) r := cliFlags.Replace("xxx", newPublicFlag)
assert.Equal(t, 3, len(r)) assert.Equal(t, 3, len(r))
assert.Equal(t, "auth-mode, a", r[0].Name()) assert.Equal(t, "auth-mode, a", r[0].String())
assert.Equal(t, originalPublicFlag.Name(), r[1].Name()) assert.Equal(t, originalPublicFlag.String(), r[1].String())
assert.Equal(t, "admin-user, login", r[2].Name()) assert.Equal(t, "admin-user, login", r[2].String())
}) })
t.Run("Success", func(t *testing.T) { t.Run("Success", func(t *testing.T) {
r := cliFlags.Replace("public, p", newPublicFlag) r := cliFlags.Replace("public, p", newPublicFlag)
assert.Equal(t, 3, len(r)) assert.Equal(t, 3, len(r))
assert.Equal(t, newPublicFlag.Name(), r[1].Name()) assert.Equal(t, newPublicFlag.String(), r[1].String())
assert.Equal(t, newPublicFlag.Hidden(), r[1].Hidden()) assert.Equal(t, newPublicFlag.Hidden(), r[1].Hidden())
}) })
} }
@@ -83,148 +86,161 @@ func TestCliFlags_Replace(t *testing.T) {
func TestCliFlags_Remove(t *testing.T) { func TestCliFlags_Remove(t *testing.T) {
cliFlags := CliFlags{ cliFlags := CliFlags{
{ {
Flag: cli.StringFlag{ Flag: &cli.StringFlag{
Name: "auth-mode, a", Name: "auth-mode",
Usage: "authentication `MODE` (public, password)", Aliases: []string{"a"},
Value: "password", Usage: "authentication `MODE` (public, password)",
EnvVar: EnvVar("AUTH_MODE"), Value: "password",
EnvVars: EnvVars("AUTH_MODE"),
}}, }},
{ {
Flag: cli.StringFlag{ Flag: &cli.StringFlag{
Name: "admin-user, login", Name: "admin-user",
Usage: "`USERNAME` of the superadmin account that is created on first startup", Aliases: []string{"login"},
Value: "admin", Usage: "`USERNAME` of the superadmin account that is created on first startup",
EnvVar: EnvVar("ADMIN_USER"), Value: "admin",
EnvVars: EnvVars("ADMIN_USER"),
}}} }}}
assert.Equal(t, 2, len(cliFlags)) assert.Equal(t, 2, len(cliFlags))
r := cliFlags.Remove([]string{"auth-mode, a"}) result := cliFlags.Remove([]string{"auth-mode, a"})
assert.Equal(t, 1, len(r)) assert.Equal(t, 1, len(result))
} }
func TestCliFlags_Insert(t *testing.T) { func TestCliFlags_Insert(t *testing.T) {
PublicFlag := CliFlag{Flag: cli.BoolFlag{ PublicFlag := CliFlag{Flag: &cli.BoolFlag{
Name: "public, p", Name: "public",
Hidden: true, Aliases: []string{"p"},
Usage: "disable authentication, advanced settings, and WebDAV remote access", Hidden: true,
EnvVar: EnvVar("PUBLIC"), Usage: "disable authentication, advanced settings, and WebDAV remote access",
EnvVars: EnvVars("PUBLIC"),
}} }}
cliFlags := CliFlags{ cliFlags := CliFlags{
{ {
Flag: cli.StringFlag{ Flag: &cli.StringFlag{
Name: "auth-mode, a", Name: "auth-mode",
Usage: "authentication `MODE` (public, password)", Aliases: []string{"a"},
Value: "password", Usage: "authentication `MODE` (public, password)",
EnvVar: EnvVar("AUTH_MODE"), Value: "password",
EnvVars: EnvVars("AUTH_MODE"),
}}, }},
{ {
Flag: cli.StringFlag{ Flag: &cli.StringFlag{
Name: "admin-user, login", Name: "admin-user",
Usage: "`USERNAME` of the superadmin account that is created on first startup", Aliases: []string{"login"},
Value: "admin", Usage: "`USERNAME` of the superadmin account that is created on first startup",
EnvVar: EnvVar("ADMIN_USER"), Value: "admin",
EnvVars: EnvVars("ADMIN_USER"),
}}} }}}
assert.Equal(t, 2, len(cliFlags)) assert.Equal(t, 2, len(cliFlags))
t.Run("Success", func(t *testing.T) { t.Run("Success", func(t *testing.T) {
r := cliFlags.Insert("auth-mode, a", []CliFlag{PublicFlag}) result := cliFlags.Insert("auth-mode, a", []CliFlag{PublicFlag})
assert.Equal(t, 3, len(r)) assert.Equal(t, 3, len(result))
assert.Equal(t, "auth-mode, a", r[0].Name()) assert.Equal(t, "auth-mode, a", result[0].String())
assert.Equal(t, PublicFlag.Name(), r[1].Name()) assert.Equal(t, PublicFlag.String(), result[1].String())
assert.Equal(t, "admin-user, login", r[2].Name()) assert.Equal(t, "admin-user, login", result[2].String())
}) })
t.Run("WrongName", func(t *testing.T) { t.Run("WrongName", func(t *testing.T) {
r := cliFlags.Insert("xxx", []CliFlag{PublicFlag}) result := cliFlags.Insert("xxx", []CliFlag{PublicFlag})
assert.Equal(t, 3, len(r)) assert.Equal(t, 3, len(result))
assert.Equal(t, "auth-mode, a", r[0].Name()) assert.Equal(t, "auth-mode, a", result[0].String())
assert.Equal(t, "admin-user, login", r[1].Name()) assert.Equal(t, "admin-user, login", result[1].String())
assert.Equal(t, PublicFlag.Name(), r[2].Name()) assert.Equal(t, PublicFlag.String(), result[2].String())
}) })
} }
func TestCliFlags_InsertBefore(t *testing.T) { func TestCliFlags_InsertBefore(t *testing.T) {
PublicFlag := CliFlag{Flag: cli.BoolFlag{ PublicFlag := CliFlag{Flag: &cli.BoolFlag{
Name: "public, p", Name: "public",
Hidden: true, Aliases: []string{"p"},
Usage: "disable authentication, advanced settings, and WebDAV remote access", Hidden: true,
EnvVar: EnvVar("PUBLIC"), Usage: "disable authentication, advanced settings, and WebDAV remote access",
EnvVars: EnvVars("PUBLIC"),
}} }}
cliFlags := CliFlags{ cliFlags := CliFlags{
{ {
Flag: cli.StringFlag{ Flag: &cli.StringFlag{
Name: "auth-mode, a", Name: "auth-mode",
Usage: "authentication `MODE` (public, password)", Aliases: []string{"a"},
Value: "password", Usage: "authentication `MODE` (public, password)",
EnvVar: EnvVar("AUTH_MODE"), Value: "password",
EnvVars: EnvVars("AUTH_MODE"),
}}, }},
{ {
Flag: cli.StringFlag{ Flag: &cli.StringFlag{
Name: "admin-user, login", Name: "admin-user",
Usage: "`USERNAME` of the superadmin account that is created on first startup", Aliases: []string{"login"},
Value: "admin", Usage: "`USERNAME` of the superadmin account that is created on first startup",
EnvVar: EnvVar("ADMIN_USER"), Value: "admin",
EnvVars: EnvVars("ADMIN_USER"),
}}} }}}
assert.Equal(t, 2, len(cliFlags)) assert.Equal(t, 2, len(cliFlags))
t.Run("Success", func(t *testing.T) { t.Run("Success", func(t *testing.T) {
r := cliFlags.InsertBefore("auth-mode, a", []CliFlag{PublicFlag}) result := cliFlags.InsertBefore("auth-mode, a", []CliFlag{PublicFlag})
assert.Equal(t, 3, len(r)) assert.Equal(t, 3, len(result))
assert.Equal(t, "auth-mode, a", r[1].Name()) assert.Equal(t, "auth-mode, a", result[1].String())
assert.Equal(t, PublicFlag.Name(), r[0].Name()) assert.Equal(t, PublicFlag.String(), result[0].String())
assert.Equal(t, "admin-user, login", r[2].Name()) assert.Equal(t, "admin-user, login", result[2].String())
}) })
t.Run("WrongName", func(t *testing.T) { t.Run("WrongName", func(t *testing.T) {
r := cliFlags.InsertBefore("xxx", []CliFlag{PublicFlag}) result := cliFlags.InsertBefore("xxx", []CliFlag{PublicFlag})
assert.Equal(t, 3, len(r)) assert.Equal(t, 3, len(result))
assert.Equal(t, "auth-mode, a", r[0].Name()) t.Logf("flags: %#v", result)
assert.Equal(t, "admin-user, login", r[1].Name())
assert.Equal(t, PublicFlag.Name(), r[2].Name()) assert.Equal(t, "auth-mode, a", result[0].String())
assert.Equal(t, "admin-user, login", result[1].String())
assert.Equal(t, PublicFlag.String(), result[2].String())
}) })
} }
func TestCliFlags_Prepend(t *testing.T) { func TestCliFlags_Prepend(t *testing.T) {
PublicFlag := CliFlag{Flag: cli.BoolFlag{ PublicFlag := CliFlag{Flag: &cli.BoolFlag{
Name: "public, p", Name: "public",
Hidden: true, Aliases: []string{"p"},
Usage: "disable authentication, advanced settings, and WebDAV remote access", Hidden: true,
EnvVar: EnvVar("PUBLIC"), Usage: "disable authentication, advanced settings, and WebDAV remote access",
EnvVars: EnvVars("PUBLIC"),
}} }}
cliFlags := CliFlags{ cliFlags := CliFlags{
{ {
Flag: cli.StringFlag{ Flag: &cli.StringFlag{
Name: "auth-mode, a", Name: "auth-mode",
Usage: "authentication `MODE` (public, password)", Aliases: []string{"a"},
Value: "password", Usage: "authentication `MODE` (public, password)",
EnvVar: EnvVar("AUTH_MODE"), Value: "password",
EnvVars: EnvVars("AUTH_MODE"),
}}, }},
{ {
Flag: cli.StringFlag{ Flag: &cli.StringFlag{
Name: "admin-user, login", Name: "admin-user",
Usage: "`USERNAME` of the superadmin account that is created on first startup", Aliases: []string{"login"},
Value: "admin", Usage: "`USERNAME` of the superadmin account that is created on first startup",
EnvVar: EnvVar("ADMIN_USER"), Value: "admin",
EnvVars: EnvVars("ADMIN_USER"),
}}} }}}
assert.Equal(t, 2, len(cliFlags)) assert.Equal(t, 2, len(cliFlags))
r := cliFlags.Prepend([]CliFlag{PublicFlag}) r := cliFlags.Prepend([]CliFlag{PublicFlag})
assert.Equal(t, "auth-mode, a", r[1].Name()) assert.Equal(t, "auth-mode, a", r[1].String())
assert.Equal(t, PublicFlag.Name(), r[0].Name()) assert.Equal(t, PublicFlag.String(), r[0].String())
assert.Equal(t, "admin-user, login", r[2].Name()) assert.Equal(t, "admin-user, login", r[2].String())
} }

View File

@@ -42,7 +42,7 @@ import (
"github.com/klauspost/cpuid/v2" "github.com/klauspost/cpuid/v2"
"github.com/pbnjay/memory" "github.com/pbnjay/memory"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
"github.com/urfave/cli" "github.com/urfave/cli/v2"
"github.com/photoprism/photoprism/internal/ai/face" "github.com/photoprism/photoprism/internal/ai/face"
"github.com/photoprism/photoprism/internal/config/customize" "github.com/photoprism/photoprism/internal/config/customize"
@@ -323,13 +323,13 @@ func (c *Config) CliContext() *cli.Context {
return c.cliCtx return c.cliCtx
} }
// CliGlobalString returns a global cli string flag value if set. // CliContextString returns a global cli string flag value if set.
func (c *Config) CliGlobalString(name string) string { func (c *Config) CliContextString(name string) string {
if c.cliCtx == nil { if c.cliCtx == nil {
return "" return ""
} }
return c.cliCtx.GlobalString(name) return c.cliCtx.String(name)
} }
// readSerial reads and returns the current storage serial. // readSerial reads and returns the current storage serial.

View File

@@ -145,7 +145,7 @@ func (c *Config) SitePreview() string {
// LegalInfo returns the legal info text for the page footer. // LegalInfo returns the legal info text for the page footer.
func (c *Config) LegalInfo() string { func (c *Config) LegalInfo() string {
if s := c.CliGlobalString("imprint"); s != "" { if s := c.CliContextString("imprint"); s != "" {
log.Warnf("config: option 'imprint' is deprecated, please use 'legal-info'") log.Warnf("config: option 'imprint' is deprecated, please use 'legal-info'")
return s return s
} }
@@ -155,7 +155,7 @@ func (c *Config) LegalInfo() string {
// LegalUrl returns the legal info url. // LegalUrl returns the legal info url.
func (c *Config) LegalUrl() string { func (c *Config) LegalUrl() string {
if s := c.CliGlobalString("imprint-url"); s != "" { if s := c.CliContextString("imprint-url"); s != "" {
log.Warnf("config: option 'imprint-url' is deprecated, please use 'legal-url'") log.Warnf("config: option 'imprint-url' is deprecated, please use 'legal-url'")
return s return s
} }

View File

@@ -23,6 +23,17 @@ func EnvVar(flag string) string {
return "PHOTOPRISM_" + strings.ToUpper(strings.ReplaceAll(flag, "-", "_")) return "PHOTOPRISM_" + strings.ToUpper(strings.ReplaceAll(flag, "-", "_"))
} }
// EnvVars returns the names of the environment variable for the specified config flag.
func EnvVars(flags ...string) (vars []string) {
vars = make([]string, len(flags))
for i, flag := range flags {
vars[i] = EnvVar(flag)
}
return vars
}
// Env checks the presence of environment and command-line flags. // Env checks the presence of environment and command-line flags.
func Env(vars ...string) bool { func Env(vars ...string) bool {
for _, s := range vars { for _, s := range vars {

File diff suppressed because it is too large Load Diff

View File

@@ -6,7 +6,7 @@ import (
"os" "os"
"time" "time"
"github.com/urfave/cli" "github.com/urfave/cli/v2"
"gopkg.in/yaml.v2" "gopkg.in/yaml.v2"
"github.com/photoprism/photoprism/pkg/clean" "github.com/photoprism/photoprism/pkg/clean"
@@ -25,6 +25,7 @@ type Options struct {
PartnerID string `yaml:"-" json:"-" flag:"partner-id"` PartnerID string `yaml:"-" json:"-" flag:"partner-id"`
AuthMode string `yaml:"AuthMode" json:"-" flag:"auth-mode"` AuthMode string `yaml:"AuthMode" json:"-" flag:"auth-mode"`
Public bool `yaml:"Public" json:"-" flag:"public"` Public bool `yaml:"Public" json:"-" flag:"public"`
NoHub bool `yaml:"NoHub" json:"-" flag:"no-hub"`
AdminUser string `yaml:"AdminUser" json:"-" flag:"admin-user"` AdminUser string `yaml:"AdminUser" json:"-" flag:"admin-user"`
AdminPassword string `yaml:"AdminPassword" json:"-" flag:"admin-password"` AdminPassword string `yaml:"AdminPassword" json:"-" flag:"admin-password"`
PasswordLength int `yaml:"PasswordLength" json:"-" flag:"password-length"` PasswordLength int `yaml:"PasswordLength" json:"-" flag:"password-length"`
@@ -236,7 +237,7 @@ func NewOptions(ctx *cli.Context) *Options {
c.BackupAlbums = true c.BackupAlbums = true
// Initialize options with the values from the "defaults.yml" file, if it exists. // Initialize options with the values from the "defaults.yml" file, if it exists.
if defaultsYaml := ctx.GlobalString("defaults-yaml"); defaultsYaml == "" { if defaultsYaml := ctx.String("defaults-yaml"); defaultsYaml == "" {
log.Tracef("config: defaults file was not specified") log.Tracef("config: defaults file was not specified")
} else if c.DefaultsYaml = fs.Abs(defaultsYaml); !fs.FileExists(c.DefaultsYaml) { } else if c.DefaultsYaml = fs.Abs(defaultsYaml); !fs.FileExists(c.DefaultsYaml) {
log.Tracef("config: defaults file %s does not exist", clean.Log(c.DefaultsYaml)) log.Tracef("config: defaults file %s does not exist", clean.Log(c.DefaultsYaml))

View File

@@ -10,7 +10,7 @@ import (
"sync" "sync"
"time" "time"
"github.com/urfave/cli" "github.com/urfave/cli/v2"
_ "github.com/jinzhu/gorm/dialects/mysql" _ "github.com/jinzhu/gorm/dialects/mysql"
_ "github.com/jinzhu/gorm/dialects/sqlite" _ "github.com/jinzhu/gorm/dialects/sqlite"
@@ -216,7 +216,7 @@ func NewTestContext(args []string) *cli.Context {
} }
// Parse command arguments. // Parse command arguments.
flags := flag.NewFlagSet("test", 0) flags := flag.NewFlagSet("test", flag.ContinueOnError)
LogErr(flags.Parse(args)) LogErr(flags.Parse(args))
// Create and return new context. // Create and return new context.
@@ -227,7 +227,7 @@ func NewTestContext(args []string) *cli.Context {
func CliTestContext() *cli.Context { func CliTestContext() *cli.Context {
config := NewTestOptions("config-cli") config := NewTestOptions("config-cli")
globalSet := flag.NewFlagSet("test", 0) globalSet := flag.NewFlagSet("test", flag.ContinueOnError)
globalSet.String("config-path", config.ConfigPath, "doc") globalSet.String("config-path", config.ConfigPath, "doc")
globalSet.String("admin-password", config.DarktableBin, "doc") globalSet.String("admin-password", config.DarktableBin, "doc")
globalSet.String("oidc-uri", config.OIDCUri, "doc") globalSet.String("oidc-uri", config.OIDCUri, "doc")

View File

@@ -6,7 +6,7 @@ import (
"github.com/jinzhu/gorm" "github.com/jinzhu/gorm"
"github.com/photoprism/photoprism/pkg/fs" "github.com/photoprism/photoprism/pkg/fs"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/urfave/cli" "github.com/urfave/cli/v2"
) )
func TestConfig_TestdataPath2(t *testing.T) { func TestConfig_TestdataPath2(t *testing.T) {

View File

@@ -2,7 +2,7 @@ package entity
import ( import (
"github.com/photoprism/photoprism/pkg/authn" "github.com/photoprism/photoprism/pkg/authn"
"github.com/urfave/cli" "github.com/urfave/cli/v2"
"github.com/photoprism/photoprism/internal/form" "github.com/photoprism/photoprism/internal/form"
"github.com/photoprism/photoprism/pkg/clean" "github.com/photoprism/photoprism/pkg/clean"

View File

@@ -1,7 +1,7 @@
package form package form
import ( import (
"github.com/urfave/cli" "github.com/urfave/cli/v2"
"github.com/photoprism/photoprism/internal/auth/acl" "github.com/photoprism/photoprism/internal/auth/acl"
"github.com/photoprism/photoprism/pkg/authn" "github.com/photoprism/photoprism/pkg/authn"

Some files were not shown because too many files have changed in this diff Show More