From d437f494d0efadd2d9e980cce86012e9f315a71b Mon Sep 17 00:00:00 2001 From: pacoorozco Date: Sat, 21 Oct 2023 16:24:39 +0200 Subject: [PATCH 1/7] Update CHANGELOG Signed-off-by: pacoorozco --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index a6ec633..c80b4ed 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,8 +6,10 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/) and this ## 4.1.0 ### Added - Flag `--port` to configure the port where the authentication server will listen to when using the `auth` command ([#370][i370]) +- **New command to reset the already uploaded file tracker** (`reset file-tracker`), which removes the internal database ([#182][i182]) [i370]: https://github.com/gphotosuploader/gphotos-uploader-cli/issues/370 +[i182]: https://github.com/gphotosuploader/gphotos-uploader-cli/issues/182 ## 4.0.0 ### Added From a8e0f66917bcf2590ea55218d86c792ba0ceae58 Mon Sep 17 00:00:00 2001 From: pacoorozco Date: Mon, 23 Oct 2023 09:10:43 +0200 Subject: [PATCH 2/7] Added Album configuration option Signed-off-by: pacoorozco --- internal/config/config.go | 37 +++++++++++++++++-- internal/config/config_test.go | 26 +++++++++---- internal/config/schema.go | 19 +++++++++- .../testdata/invalid-config/AlbumAuto.hjson | 19 ++++++++++ .../invalid-config/AlbumBadFormat.hjson | 19 ++++++++++ .../testdata/invalid-config/AlbumBadKey.hjson | 19 ++++++++++ .../invalid-config/AlbumEmptyName.hjson | 19 ++++++++++ ...Type.hjson => BadSecretsBackendType.hjson} | 3 +- ...ums.hjson => DeprecatedCreateAlbums.hjson} | 0 .../{Account.hjson => EmptyAccount.hjson} | 3 +- ...als.hjson => EmptyAppAPICredentials.hjson} | 3 +- ...er.hjson => NonExistentSourceFolder.hjson} | 3 +- .../config/testdata/valid-config/config.hjson | 3 +- .../configWithAlbumAutoFolderNameOption.hjson | 19 ++++++++++ .../configWithAlbumAutoFolderPathOption.hjson | 19 ++++++++++ .../configWithAlbumIdOption.hjson | 19 ++++++++++ .../configWithAlbumNameOption.hjson | 19 ++++++++++ ...nfigWithDeprecatedCreateAlbumsOption.hjson | 19 ++++++++++ 18 files changed, 245 insertions(+), 23 deletions(-) create mode 100644 internal/config/testdata/invalid-config/AlbumAuto.hjson create mode 100644 internal/config/testdata/invalid-config/AlbumBadFormat.hjson create mode 100644 internal/config/testdata/invalid-config/AlbumBadKey.hjson create mode 100644 internal/config/testdata/invalid-config/AlbumEmptyName.hjson rename internal/config/testdata/invalid-config/{SecretsBackendType.hjson => BadSecretsBackendType.hjson} (90%) rename internal/config/testdata/invalid-config/{CreateAlbums.hjson => DeprecatedCreateAlbums.hjson} (100%) rename internal/config/testdata/invalid-config/{Account.hjson => EmptyAccount.hjson} (89%) rename internal/config/testdata/invalid-config/{AppAPICredentials.hjson => EmptyAppAPICredentials.hjson} (89%) rename internal/config/testdata/invalid-config/{SourceFolder.hjson => NonExistentSourceFolder.hjson} (90%) create mode 100644 internal/config/testdata/valid-config/configWithAlbumAutoFolderNameOption.hjson create mode 100644 internal/config/testdata/valid-config/configWithAlbumAutoFolderPathOption.hjson create mode 100644 internal/config/testdata/valid-config/configWithAlbumIdOption.hjson create mode 100644 internal/config/testdata/valid-config/configWithAlbumNameOption.hjson create mode 100644 internal/config/testdata/valid-config/configWithDeprecatedCreateAlbumsOption.hjson diff --git a/internal/config/config.go b/internal/config/config.go index 7fd587e..ce5b645 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -7,6 +7,7 @@ import ( "fmt" "io" "path/filepath" + "strings" "github.com/hjson/hjson-go/v4" "github.com/mitchellh/go-homedir" @@ -106,7 +107,7 @@ func readFile(fs afero.Fs, filename string) (*Config, error) { return nil, err } - // convert all path to absolute paths. + // convert all paths to absolute paths. if err := config.ensureSourceFolderAbsolutePaths(); err != nil { return nil, err } @@ -141,7 +142,11 @@ func (c Config) validateJobs(fs afero.Fs) error { if !exist { return fmt.Errorf("folder '%s' does not exist", job.SourceFolder) } - if !isValidCreateAlbums(job.CreateAlbums) { + if job.Album != "" && !isValidAlbum(job.Album) { + return fmt.Errorf("option Album is invalid, '%s", job.Album) + } + // TODO: Check CreateAlbums for backwards compatibility. It should be removed on version 5.x + if job.Album == "" && !isValidCreateAlbums(job.CreateAlbums) { return fmt.Errorf("option CreateAlbums is invalid, '%s", job.CreateAlbums) } } @@ -159,7 +164,7 @@ func (c Config) validateSecretsBackendType() error { func (c Config) ensureSourceFolderAbsolutePaths() error { for i := range c.Jobs { - item := &c.Jobs[i] // we do that way to modify original object while iterating. + item := &c.Jobs[i] // we do that way to modify an original object while iterating. src, err := homedir.Expand(item.SourceFolder) if err != nil { return err @@ -169,6 +174,31 @@ func (c Config) ensureSourceFolderAbsolutePaths() error { return nil } +func isValidAlbumGenerationMethod(method string) bool { + if method != "folderPath" && method != "folderName" { + return false + } + return true +} + +// isValidAlbum checks if the value is a valid Album option. +func isValidAlbum(value string) bool { + before, after, found := strings.Cut(value, ":") + if !found { + return false + } + if after == "" { + return false + } + switch before { + case "name", "id": + return true + case "auto": + return isValidAlbumGenerationMethod(after) + } + return false +} + // isValidCreateAlbums checks if the value is a valid CreateAlbums option. func isValidCreateAlbums(value string) bool { switch value { @@ -218,6 +248,7 @@ func defaultSettings() Config { Jobs: []FolderUploadJob{ { SourceFolder: "YOUR_FOLDER_PATH", + Album: "", CreateAlbums: "folderName", DeleteAfterUpload: false, }, diff --git a/internal/config/config_test.go b/internal/config/config_test.go index 8b609c2..15889c9 100644 --- a/internal/config/config_test.go +++ b/internal/config/config_test.go @@ -63,14 +63,23 @@ func TestFromFile(t *testing.T) { want string isErrExpected bool }{ - {"Should success", "testdata/valid-config/config.hjson", "youremail@domain.com", false}, - {"Should fail if dir does not exist", "testdata/non-existent/config.hjson", "", true}, - {"Should fail if Account is invalid", "testdata/invalid-config/Account.hjson", "", true}, - {"Should fail if SourceFolder does not exist", "testdata/invalid-config/SourceFolder.hjson", "", true}, - {"Should fail if SecretsBackendType is invalid", "testdata/invalid-config/SecretsBackendType.hjson", "", true}, - {"Should fail if AppAPICredentials are invalid", "testdata/invalid-config/AppAPICredentials.hjson", "", true}, - {"Should fail if CreateAlbums is invalid", "testdata/invalid-config/CreateAlbums.hjson", "", true}, + {"Should success with Album's name option", "testdata/valid-config/configWithAlbumNameOption.hjson", "youremail@domain.com", false}, + {"Should success with Album's id option", "testdata/valid-config/configWithAlbumIdOption.hjson", "youremail@domain.com", false}, + {"Should success with Album's auto folderName option", "testdata/valid-config/configWithAlbumAutoFolderNameOption.hjson", "youremail@domain.com", false}, + {"Should success with Album's auto folderPath option", "testdata/valid-config/configWithAlbumAutoFolderPathOption.hjson", "youremail@domain.com", false}, + {"Should success with deprecated CreateAlbums option", "testdata/valid-config/configWithDeprecatedCreateAlbumsOption.hjson", "youremail@domain.com", false}, + + {"Should fail if config dir does not exist", "testdata/non-existent/config.hjson", "", true}, + {"Should fail if Account is invalid", "testdata/invalid-config/EmptyAccount.hjson", "", true}, + {"Should fail if SourceFolder does not exist", "testdata/invalid-config/NonExistentSourceFolder.hjson", "", true}, + {"Should fail if SecretsBackendType is invalid", "testdata/invalid-config/BadSecretsBackendType.hjson", "", true}, + {"Should fail if AppAPICredentials are invalid", "testdata/invalid-config/EmptyAppAPICredentials.hjson", "", true}, {"Should fail if Jobs is empty", "testdata/invalid-config/NoJobs.hjson", "", true}, + {"Should fail if Album's format is invalid", "testdata/invalid-config/AlbumBadFormat.hjson", "", true}, + {"Should fail if Album's key is invalid", "testdata/invalid-config/AlbumBadKey.hjson", "", true}, + {"Should fail if Album's name is invalid", "testdata/invalid-config/AlbumEmptyName.hjson", "", true}, + {"Should fail if Album's auto value is invalid", "testdata/invalid-config/AlbumBadAutoValue.hjson", "", true}, + {"Should fail if deprecated CreateAlbums is invalid", "testdata/invalid-config/DeprecatedCreateAlbums.hjson", "", true}, } for _, tc := range testCases { @@ -100,6 +109,7 @@ func TestConfig_SafePrint(t *testing.T) { Jobs: []config.FolderUploadJob{ { SourceFolder: "foo", + Album: "name:albumName", CreateAlbums: "folderPath", DeleteAfterUpload: false, IncludePatterns: []string{}, @@ -107,7 +117,7 @@ func TestConfig_SafePrint(t *testing.T) { }, }, } - want := `{"APIAppCredentials":{"ClientID":"client-id","ClientSecret":"REMOVED"},"Account":"account","SecretsBackendType":"auto","Jobs":[{"SourceFolder":"foo","CreateAlbums":"folderPath","DeleteAfterUpload":false,"IncludePatterns":[],"ExcludePatterns":[]}]}` + want := `{"APIAppCredentials":{"ClientID":"client-id","ClientSecret":"REMOVED"},"Account":"account","SecretsBackendType":"auto","Jobs":[{"SourceFolder":"foo","Album":"name:albumName","CreateAlbums":"folderPath","DeleteAfterUpload":false,"IncludePatterns":[],"ExcludePatterns":[]}]}` if want != cfg.SafePrint() { t.Errorf("want: %s, got: %s", want, cfg.SafePrint()) diff --git a/internal/config/schema.go b/internal/config/schema.go index 87bd5c2..c486b50 100644 --- a/internal/config/schema.go +++ b/internal/config/schema.go @@ -1,6 +1,6 @@ package config -// Config represents the content of configuration file. +// Config represents the content of the configuration file. // It defines the schema for Marshal and Unmarshal the data of the configuration file. type Config struct { // APIAppCredentials represents Google Photos API credentials for OAuth. @@ -29,8 +29,23 @@ type FolderUploadJob struct { // SourceFolder is the folder containing the objects to be uploaded. SourceFolder string `json:"SourceFolder"` + // Album is the album where objects will be uploaded. + // If the Album option is not set, the objects will not be associated with an album in Google Photos. + // + // These are the valid values: "name:", "id:" and "auto:". + // "name:" : Followed by the album name in Google Photos (album names are not unique, so the first to match + // will be selected) + // "id:" : Followed by the album ID in Google Photos (album IDs are unique) + // "auto:" : Followed either "folderPath" or "folderName" will use an autogenerated album name based on the + // object's folder path or object's folder name. + Album string `json:"Album"` + // CreateAlbums is the parameter to create albums on Google Photos. - // Valid options are: + // + // Deprecated: CreateAlbums exists to maintain backwards compatibility with version 4.x. It should not be used in + // favor of the Album option. + // + // Valid options were: // Off: Disable album creation (default). // folderPath: Creates album with the name based on full folder path. // folderName: Creates album with the name based on the folder name. diff --git a/internal/config/testdata/invalid-config/AlbumAuto.hjson b/internal/config/testdata/invalid-config/AlbumAuto.hjson new file mode 100644 index 0000000..842ef79 --- /dev/null +++ b/internal/config/testdata/invalid-config/AlbumAuto.hjson @@ -0,0 +1,19 @@ +{ + APIAppCredentials: + { + ClientID: client-id + ClientSecret: client-secret + } + Account: youremail@domain.com + SecretsBackendType: auto + Jobs: + [ + { + SourceFolder: ./testdata + Album: auto:invalid + DeleteAfterUpload: false + IncludePatterns: [] + ExcludePatterns: [] + } + ] +} diff --git a/internal/config/testdata/invalid-config/AlbumBadFormat.hjson b/internal/config/testdata/invalid-config/AlbumBadFormat.hjson new file mode 100644 index 0000000..00a37dc --- /dev/null +++ b/internal/config/testdata/invalid-config/AlbumBadFormat.hjson @@ -0,0 +1,19 @@ +{ + APIAppCredentials: + { + ClientID: client-id + ClientSecret: client-secret + } + Account: youremail@domain.com + SecretsBackendType: auto + Jobs: + [ + { + SourceFolder: ./testdata + Album: invalid + DeleteAfterUpload: false + IncludePatterns: [] + ExcludePatterns: [] + } + ] +} diff --git a/internal/config/testdata/invalid-config/AlbumBadKey.hjson b/internal/config/testdata/invalid-config/AlbumBadKey.hjson new file mode 100644 index 0000000..7685a82 --- /dev/null +++ b/internal/config/testdata/invalid-config/AlbumBadKey.hjson @@ -0,0 +1,19 @@ +{ + APIAppCredentials: + { + ClientID: client-id + ClientSecret: client-secret + } + Account: youremail@domain.com + SecretsBackendType: auto + Jobs: + [ + { + SourceFolder: ./testdata + Album: invalid:fooBar + DeleteAfterUpload: false + IncludePatterns: [] + ExcludePatterns: [] + } + ] +} diff --git a/internal/config/testdata/invalid-config/AlbumEmptyName.hjson b/internal/config/testdata/invalid-config/AlbumEmptyName.hjson new file mode 100644 index 0000000..55170ba --- /dev/null +++ b/internal/config/testdata/invalid-config/AlbumEmptyName.hjson @@ -0,0 +1,19 @@ +{ + APIAppCredentials: + { + ClientID: client-id + ClientSecret: client-secret + } + Account: youremail@domain.com + SecretsBackendType: auto + Jobs: + [ + { + SourceFolder: ./testdata + Album: name: + DeleteAfterUpload: false + IncludePatterns: [] + ExcludePatterns: [] + } + ] +} diff --git a/internal/config/testdata/invalid-config/SecretsBackendType.hjson b/internal/config/testdata/invalid-config/BadSecretsBackendType.hjson similarity index 90% rename from internal/config/testdata/invalid-config/SecretsBackendType.hjson rename to internal/config/testdata/invalid-config/BadSecretsBackendType.hjson index 02fb721..3e7c880 100644 --- a/internal/config/testdata/invalid-config/SecretsBackendType.hjson +++ b/internal/config/testdata/invalid-config/BadSecretsBackendType.hjson @@ -10,10 +10,9 @@ [ { SourceFolder: ./testdata - CreateAlbums: folderName DeleteAfterUpload: false IncludePatterns: [] ExcludePatterns: [] } ] -} \ No newline at end of file +} diff --git a/internal/config/testdata/invalid-config/CreateAlbums.hjson b/internal/config/testdata/invalid-config/DeprecatedCreateAlbums.hjson similarity index 100% rename from internal/config/testdata/invalid-config/CreateAlbums.hjson rename to internal/config/testdata/invalid-config/DeprecatedCreateAlbums.hjson diff --git a/internal/config/testdata/invalid-config/Account.hjson b/internal/config/testdata/invalid-config/EmptyAccount.hjson similarity index 89% rename from internal/config/testdata/invalid-config/Account.hjson rename to internal/config/testdata/invalid-config/EmptyAccount.hjson index b840882..7d5763b 100644 --- a/internal/config/testdata/invalid-config/Account.hjson +++ b/internal/config/testdata/invalid-config/EmptyAccount.hjson @@ -10,10 +10,9 @@ [ { SourceFolder: ./testdata - CreateAlbums: folderName DeleteAfterUpload: false IncludePatterns: [] ExcludePatterns: [] } ] -} \ No newline at end of file +} diff --git a/internal/config/testdata/invalid-config/AppAPICredentials.hjson b/internal/config/testdata/invalid-config/EmptyAppAPICredentials.hjson similarity index 89% rename from internal/config/testdata/invalid-config/AppAPICredentials.hjson rename to internal/config/testdata/invalid-config/EmptyAppAPICredentials.hjson index a268620..e681ac5 100644 --- a/internal/config/testdata/invalid-config/AppAPICredentials.hjson +++ b/internal/config/testdata/invalid-config/EmptyAppAPICredentials.hjson @@ -10,10 +10,9 @@ [ { SourceFolder: ./testdata - CreateAlbums: folderName DeleteAfterUpload: false IncludePatterns: [] ExcludePatterns: [] } ] -} \ No newline at end of file +} diff --git a/internal/config/testdata/invalid-config/SourceFolder.hjson b/internal/config/testdata/invalid-config/NonExistentSourceFolder.hjson similarity index 90% rename from internal/config/testdata/invalid-config/SourceFolder.hjson rename to internal/config/testdata/invalid-config/NonExistentSourceFolder.hjson index da0dc9d..98d06ce 100644 --- a/internal/config/testdata/invalid-config/SourceFolder.hjson +++ b/internal/config/testdata/invalid-config/NonExistentSourceFolder.hjson @@ -10,10 +10,9 @@ [ { SourceFolder: ./testdata/non-existent - CreateAlbums: folderName DeleteAfterUpload: false IncludePatterns: [] ExcludePatterns: [] } ] -} \ No newline at end of file +} diff --git a/internal/config/testdata/valid-config/config.hjson b/internal/config/testdata/valid-config/config.hjson index 3ac46be..10c3c3b 100644 --- a/internal/config/testdata/valid-config/config.hjson +++ b/internal/config/testdata/valid-config/config.hjson @@ -10,10 +10,9 @@ [ { SourceFolder: ./testdata/valid-config - CreateAlbums: folderName DeleteAfterUpload: false IncludePatterns: [] ExcludePatterns: [] } ] -} \ No newline at end of file +} diff --git a/internal/config/testdata/valid-config/configWithAlbumAutoFolderNameOption.hjson b/internal/config/testdata/valid-config/configWithAlbumAutoFolderNameOption.hjson new file mode 100644 index 0000000..06f34ec --- /dev/null +++ b/internal/config/testdata/valid-config/configWithAlbumAutoFolderNameOption.hjson @@ -0,0 +1,19 @@ +{ + APIAppCredentials: + { + ClientID: client-id + ClientSecret: client-secret + } + Account: youremail@domain.com + SecretsBackendType: auto + Jobs: + [ + { + SourceFolder: ./testdata/valid-config + Album: auto:folderName + DeleteAfterUpload: false + IncludePatterns: [] + ExcludePatterns: [] + } + ] +} diff --git a/internal/config/testdata/valid-config/configWithAlbumAutoFolderPathOption.hjson b/internal/config/testdata/valid-config/configWithAlbumAutoFolderPathOption.hjson new file mode 100644 index 0000000..7524446 --- /dev/null +++ b/internal/config/testdata/valid-config/configWithAlbumAutoFolderPathOption.hjson @@ -0,0 +1,19 @@ +{ + APIAppCredentials: + { + ClientID: client-id + ClientSecret: client-secret + } + Account: youremail@domain.com + SecretsBackendType: auto + Jobs: + [ + { + SourceFolder: ./testdata/valid-config + Album: name:albumName + DeleteAfterUpload: false + IncludePatterns: [] + ExcludePatterns: [] + } + ] +} diff --git a/internal/config/testdata/valid-config/configWithAlbumIdOption.hjson b/internal/config/testdata/valid-config/configWithAlbumIdOption.hjson new file mode 100644 index 0000000..c2a657b --- /dev/null +++ b/internal/config/testdata/valid-config/configWithAlbumIdOption.hjson @@ -0,0 +1,19 @@ +{ + APIAppCredentials: + { + ClientID: client-id + ClientSecret: client-secret + } + Account: youremail@domain.com + SecretsBackendType: auto + Jobs: + [ + { + SourceFolder: ./testdata/valid-config + Album: id:albumId + DeleteAfterUpload: false + IncludePatterns: [] + ExcludePatterns: [] + } + ] +} diff --git a/internal/config/testdata/valid-config/configWithAlbumNameOption.hjson b/internal/config/testdata/valid-config/configWithAlbumNameOption.hjson new file mode 100644 index 0000000..1005620 --- /dev/null +++ b/internal/config/testdata/valid-config/configWithAlbumNameOption.hjson @@ -0,0 +1,19 @@ +{ + APIAppCredentials: + { + ClientID: client-id + ClientSecret: client-secret + } + Account: youremail@domain.com + SecretsBackendType: auto + Jobs: + [ + { + SourceFolder: ./testdata/valid-config + Album: auto:folderPath + DeleteAfterUpload: false + IncludePatterns: [] + ExcludePatterns: [] + } + ] +} diff --git a/internal/config/testdata/valid-config/configWithDeprecatedCreateAlbumsOption.hjson b/internal/config/testdata/valid-config/configWithDeprecatedCreateAlbumsOption.hjson new file mode 100644 index 0000000..3ac46be --- /dev/null +++ b/internal/config/testdata/valid-config/configWithDeprecatedCreateAlbumsOption.hjson @@ -0,0 +1,19 @@ +{ + APIAppCredentials: + { + ClientID: client-id + ClientSecret: client-secret + } + Account: youremail@domain.com + SecretsBackendType: auto + Jobs: + [ + { + SourceFolder: ./testdata/valid-config + CreateAlbums: folderName + DeleteAfterUpload: false + IncludePatterns: [] + ExcludePatterns: [] + } + ] +} \ No newline at end of file From 88917d35b6541bc794500c183a25c9b922328b57 Mon Sep 17 00:00:00 2001 From: pacoorozco Date: Mon, 23 Oct 2023 09:53:51 +0200 Subject: [PATCH 3/7] Remove Album option using album's id. It's too complex Signed-off-by: pacoorozco --- internal/config/config.go | 2 +- internal/config/config_test.go | 1 - internal/config/schema.go | 1 - .../configWithAlbumIdOption.hjson | 19 ------------------- 4 files changed, 1 insertion(+), 22 deletions(-) delete mode 100644 internal/config/testdata/valid-config/configWithAlbumIdOption.hjson diff --git a/internal/config/config.go b/internal/config/config.go index ce5b645..92b2371 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -191,7 +191,7 @@ func isValidAlbum(value string) bool { return false } switch before { - case "name", "id": + case "name": return true case "auto": return isValidAlbumGenerationMethod(after) diff --git a/internal/config/config_test.go b/internal/config/config_test.go index 15889c9..f2d02fd 100644 --- a/internal/config/config_test.go +++ b/internal/config/config_test.go @@ -64,7 +64,6 @@ func TestFromFile(t *testing.T) { isErrExpected bool }{ {"Should success with Album's name option", "testdata/valid-config/configWithAlbumNameOption.hjson", "youremail@domain.com", false}, - {"Should success with Album's id option", "testdata/valid-config/configWithAlbumIdOption.hjson", "youremail@domain.com", false}, {"Should success with Album's auto folderName option", "testdata/valid-config/configWithAlbumAutoFolderNameOption.hjson", "youremail@domain.com", false}, {"Should success with Album's auto folderPath option", "testdata/valid-config/configWithAlbumAutoFolderPathOption.hjson", "youremail@domain.com", false}, {"Should success with deprecated CreateAlbums option", "testdata/valid-config/configWithDeprecatedCreateAlbumsOption.hjson", "youremail@domain.com", false}, diff --git a/internal/config/schema.go b/internal/config/schema.go index c486b50..2f6d803 100644 --- a/internal/config/schema.go +++ b/internal/config/schema.go @@ -35,7 +35,6 @@ type FolderUploadJob struct { // These are the valid values: "name:", "id:" and "auto:". // "name:" : Followed by the album name in Google Photos (album names are not unique, so the first to match // will be selected) - // "id:" : Followed by the album ID in Google Photos (album IDs are unique) // "auto:" : Followed either "folderPath" or "folderName" will use an autogenerated album name based on the // object's folder path or object's folder name. Album string `json:"Album"` diff --git a/internal/config/testdata/valid-config/configWithAlbumIdOption.hjson b/internal/config/testdata/valid-config/configWithAlbumIdOption.hjson deleted file mode 100644 index c2a657b..0000000 --- a/internal/config/testdata/valid-config/configWithAlbumIdOption.hjson +++ /dev/null @@ -1,19 +0,0 @@ -{ - APIAppCredentials: - { - ClientID: client-id - ClientSecret: client-secret - } - Account: youremail@domain.com - SecretsBackendType: auto - Jobs: - [ - { - SourceFolder: ./testdata/valid-config - Album: id:albumId - DeleteAfterUpload: false - IncludePatterns: [] - ExcludePatterns: [] - } - ] -} From a8f4e337b1e6a7583a1199e958ca07242edb6837 Mon Sep 17 00:00:00 2001 From: pacoorozco Date: Mon, 23 Oct 2023 09:54:22 +0200 Subject: [PATCH 4/7] Implements push using the Album option Signed-off-by: pacoorozco --- internal/cli/push/push.go | 10 +++++++- internal/upload/album.go | 18 +++++++++++---- internal/upload/album_test.go | 38 ++++++++++++++++++------------- internal/upload/file_item_test.go | 26 ++++++++++----------- internal/upload/types.go | 2 +- internal/upload/walker_test.go | 1 - 6 files changed, 58 insertions(+), 37 deletions(-) diff --git a/internal/cli/push/push.go b/internal/cli/push/push.go index b0d506f..d87b609 100644 --- a/internal/cli/push/push.go +++ b/internal/cli/push/push.go @@ -60,6 +60,14 @@ func (cmd *PushCmd) Run(cobraCmd *cobra.Command, args []string) error { // launch all folder upload jobs for _, config := range cli.Config.Jobs { + + // TODO: CreateAlbums is maintained to ensure backwards compatibility. + //nolint:staticcheck // I want to use deprecated method. + if config.Album == "" && config.CreateAlbums != "" && config.CreateAlbums != "Off" { + //nolint:staticcheck // I want to use deprecated method. + config.Album = "auto:" + config.CreateAlbums + } + sourceFolder := config.SourceFolder filterFiles, err := filter.Compile(config.IncludePatterns, config.ExcludePatterns) @@ -71,7 +79,7 @@ func (cmd *PushCmd) Run(cobraCmd *cobra.Command, args []string) error { FileTracker: cli.FileTracker, SourceFolder: sourceFolder, - CreateAlbums: config.CreateAlbums, + Album: config.Album, Filter: filterFiles, } diff --git a/internal/upload/album.go b/internal/upload/album.go index c7e9cd8..fc9eada 100644 --- a/internal/upload/album.go +++ b/internal/upload/album.go @@ -5,18 +5,26 @@ import ( "strings" ) -// albumName returns Album name based on the configured parameter. -// If configuration option is "Off" or "", it returns empty string. +// albumName returns the album name based on the configured parameter. func (job *UploadFolderJob) albumName(path string) string { - switch job.CreateAlbums { - case "Off": + before, after, found := strings.Cut(job.Album, ":") + if !found { return "" + } + if before == "name" { + return after + } + if before != "auto" { + return "" + } + + switch after { case "folderPath": return albumNameUsingFolderPath(path) case "folderName": return albumNameUsingFolderName(path) default: - panic("invalid CreateAlbums parameter") + panic("invalid Albums parameter") } } diff --git a/internal/upload/album_test.go b/internal/upload/album_test.go index 793eb21..e18d476 100644 --- a/internal/upload/album_test.go +++ b/internal/upload/album_test.go @@ -7,36 +7,42 @@ import ( func TestAlbumName(t *testing.T) { var testData = []struct { - name string - createAlbums string + name string + album string in string want string }{ { - name: "createAlbumDisabled_With_Off", - createAlbums: "Off", - in: "/foo/bar/file.jpg", - want: "", + name: "album set an album's name", + album: "name:albumName", + in: "/foo/bar/file.jpg", + want: "albumName", }, { - name: "createAlbum_With_folderName", - createAlbums: "folderName", - in: "/foo/bar/file.jpg", - want: "bar", + name: "album set an album's name based on folder path", + album: "auto:folderPath", + in: "/foo/bar/file.jpg", + want: "foo_bar", }, { - name: "createAlbum_With_folderPath", - createAlbums: "folderPath", - in: "/foo/bar/file.jpg", - want: "foo_bar", + name: "album set an album's name based on folder name", + album: "auto:folderName", + in: "/foo/bar/file.jpg", + want: "bar", + }, + { + name: "album set an album's name with unexpected key (not `name` or `auto`)", + album: "foo:bar", + in: "/foo/bar/file.jpg", + want: "", }, } for _, tt := range testData { t.Run(tt.name, func(t *testing.T) { job := UploadFolderJob{ - CreateAlbums: tt.createAlbums, + Album: tt.album, } assert.Equal(t, tt.want, job.albumName(tt.in)) @@ -52,7 +58,7 @@ func TestAlbumNameWithInvalidParameter(t *testing.T) { } }() job := UploadFolderJob{ - CreateAlbums: "FooBar", + Album: "auto:fooBar", } _ = job.albumName("/foo/bar/file.jpg") } diff --git a/internal/upload/file_item_test.go b/internal/upload/file_item_test.go index b7f62ae..516652e 100644 --- a/internal/upload/file_item_test.go +++ b/internal/upload/file_item_test.go @@ -131,24 +131,24 @@ func TestFileItem_Remove(t *testing.T) { func TestFileItem_GroupByAlbum(t *testing.T) { items := []FileItem{ - {Path: "file1.jpg", AlbumName: "Album 1"}, - {Path: "file2.jpg", AlbumName: "Album 2"}, - {Path: "file3.jpg", AlbumName: "Album 1"}, - {Path: "file4.jpg", AlbumName: "Album 2"}, - {Path: "file5.jpg", AlbumName: "Album 3"}, + {Path: "file1.jpg", AlbumName: "album 1"}, + {Path: "file2.jpg", AlbumName: "album 2"}, + {Path: "file3.jpg", AlbumName: "album 1"}, + {Path: "file4.jpg", AlbumName: "album 2"}, + {Path: "file5.jpg", AlbumName: "album 3"}, } expectedGroups := map[string][]FileItem{ - "Album 1": { - {Path: "file1.jpg", AlbumName: "Album 1"}, - {Path: "file3.jpg", AlbumName: "Album 1"}, + "album 1": { + {Path: "file1.jpg", AlbumName: "album 1"}, + {Path: "file3.jpg", AlbumName: "album 1"}, }, - "Album 2": { - {Path: "file2.jpg", AlbumName: "Album 2"}, - {Path: "file4.jpg", AlbumName: "Album 2"}, + "album 2": { + {Path: "file2.jpg", AlbumName: "album 2"}, + {Path: "file4.jpg", AlbumName: "album 2"}, }, - "Album 3": { - {Path: "file5.jpg", AlbumName: "Album 3"}, + "album 3": { + {Path: "file5.jpg", AlbumName: "album 3"}, }, } diff --git a/internal/upload/types.go b/internal/upload/types.go index 29e5234..f487a2b 100644 --- a/internal/upload/types.go +++ b/internal/upload/types.go @@ -5,7 +5,7 @@ type UploadFolderJob struct { FileTracker FileTracker SourceFolder string - CreateAlbums string + Album string Filter FileFilterer } diff --git a/internal/upload/walker_test.go b/internal/upload/walker_test.go index 9609046..102ee9a 100644 --- a/internal/upload/walker_test.go +++ b/internal/upload/walker_test.go @@ -117,7 +117,6 @@ func getIncludedFilesByScanFolder(includePatterns []string, excludePatterns []st u := upload.UploadFolderJob{ FileTracker: ft, SourceFolder: "testdata", - CreateAlbums: "Off", Filter: filterFiles, } From 9367625eaaa1b7257a9bd64845fcd7c59a5acc89 Mon Sep 17 00:00:00 2001 From: pacoorozco Date: Mon, 23 Oct 2023 10:25:51 +0200 Subject: [PATCH 5/7] Move deprecated CreateAlbums option normalization to config package Signed-off-by: pacoorozco --- internal/cli/push/push.go | 10 +--------- internal/config/config.go | 14 +++++++++++++- internal/config/schema.go | 2 +- 3 files changed, 15 insertions(+), 11 deletions(-) diff --git a/internal/cli/push/push.go b/internal/cli/push/push.go index d87b609..582bcc9 100644 --- a/internal/cli/push/push.go +++ b/internal/cli/push/push.go @@ -59,15 +59,7 @@ func (cmd *PushCmd) Run(cobraCmd *cobra.Command, args []string) error { } // launch all folder upload jobs - for _, config := range cli.Config.Jobs { - - // TODO: CreateAlbums is maintained to ensure backwards compatibility. - //nolint:staticcheck // I want to use deprecated method. - if config.Album == "" && config.CreateAlbums != "" && config.CreateAlbums != "Off" { - //nolint:staticcheck // I want to use deprecated method. - config.Album = "auto:" + config.CreateAlbums - } - + for _, config := range cli.Config.GetJobs() { sourceFolder := config.SourceFolder filterFiles, err := filter.Compile(config.IncludePatterns, config.ExcludePatterns) diff --git a/internal/config/config.go b/internal/config/config.go index 92b2371..5856c38 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -153,6 +153,19 @@ func (c Config) validateJobs(fs afero.Fs) error { return nil } +// GetJobs returns the configured Jobs without deprecated options. +func (c Config) GetJobs() []FolderUploadJob { + jobs := c.Jobs + + // TODO: Translate the deprecated CreateAlbums into the Albums option for backwards compatibility + for _, j := range jobs { + if j.Album == "" && j.CreateAlbums != "" && j.CreateAlbums != "Off" { + j.Album = "auto:" + j.CreateAlbums + } + } + return jobs +} + func (c Config) validateSecretsBackendType() error { switch c.SecretsBackendType { case "auto", "secret-service", "keychain", "kwallet", "file": @@ -249,7 +262,6 @@ func defaultSettings() Config { { SourceFolder: "YOUR_FOLDER_PATH", Album: "", - CreateAlbums: "folderName", DeleteAfterUpload: false, }, }, diff --git a/internal/config/schema.go b/internal/config/schema.go index 2f6d803..81346da 100644 --- a/internal/config/schema.go +++ b/internal/config/schema.go @@ -37,7 +37,7 @@ type FolderUploadJob struct { // will be selected) // "auto:" : Followed either "folderPath" or "folderName" will use an autogenerated album name based on the // object's folder path or object's folder name. - Album string `json:"Album"` + Album string `json:"Album,omitempty"` // CreateAlbums is the parameter to create albums on Google Photos. // From fee72d3d982e259ecc5ccc00738b9552ac43fb86 Mon Sep 17 00:00:00 2001 From: pacoorozco Date: Mon, 23 Oct 2023 14:22:53 +0200 Subject: [PATCH 6/7] Add warning when using deprecated CreateAlbums option Signed-off-by: pacoorozco --- internal/cli/push/push.go | 14 +++++++++++++- internal/config/config.go | 13 ------------- 2 files changed, 13 insertions(+), 14 deletions(-) diff --git a/internal/cli/push/push.go b/internal/cli/push/push.go index 582bcc9..3388760 100644 --- a/internal/cli/push/push.go +++ b/internal/cli/push/push.go @@ -59,7 +59,19 @@ func (cmd *PushCmd) Run(cobraCmd *cobra.Command, args []string) error { } // launch all folder upload jobs - for _, config := range cli.Config.GetJobs() { + for _, config := range cli.Config.Jobs { + + //nolint:staticcheck // CreateAlbums is maintained for backwards compatibility + if config.CreateAlbums != "" { + cli.Logger.Warn("Deprecated 'CreateAlbums' option is used in configuration. Please, use the 'Album' option instead.") + } + + // TODO: Translate the deprecated CreateAlbums into the Albums option for backwards compatibility + //nolint:staticcheck // CreateAlbums is maintained for backwards compatibility + if config.Album == "" && config.CreateAlbums != "" && config.CreateAlbums != "Off" { + config.Album = "auto:" + config.CreateAlbums + } + sourceFolder := config.SourceFolder filterFiles, err := filter.Compile(config.IncludePatterns, config.ExcludePatterns) diff --git a/internal/config/config.go b/internal/config/config.go index 5856c38..2488c78 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -153,19 +153,6 @@ func (c Config) validateJobs(fs afero.Fs) error { return nil } -// GetJobs returns the configured Jobs without deprecated options. -func (c Config) GetJobs() []FolderUploadJob { - jobs := c.Jobs - - // TODO: Translate the deprecated CreateAlbums into the Albums option for backwards compatibility - for _, j := range jobs { - if j.Album == "" && j.CreateAlbums != "" && j.CreateAlbums != "Off" { - j.Album = "auto:" + j.CreateAlbums - } - } - return jobs -} - func (c Config) validateSecretsBackendType() error { switch c.SecretsBackendType { case "auto", "secret-service", "keychain", "kwallet", "file": From 01a8ceac84ec55c56a902520e1860fec3560c213 Mon Sep 17 00:00:00 2001 From: pacoorozco Date: Mon, 23 Oct 2023 14:34:15 +0200 Subject: [PATCH 7/7] Update CHANGELOG Signed-off-by: pacoorozco --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c80b4ed..58cbf55 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,9 +7,14 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/) and this ### Added - Flag `--port` to configure the port where the authentication server will listen to when using the `auth` command ([#370][i370]) - **New command to reset the already uploaded file tracker** (`reset file-tracker`), which removes the internal database ([#182][i182]) +- New **`Album` option in Job's configuration** which allows to set a fixed album's name to upload objects to. ([#393][i393]) + +### Deprecated +- The `CreateAlbums` option in Job's configuration is deprecated in favor of a new `Album` option. [i370]: https://github.com/gphotosuploader/gphotos-uploader-cli/issues/370 [i182]: https://github.com/gphotosuploader/gphotos-uploader-cli/issues/182 +[i393]: https://github.com/gphotosuploader/gphotos-uploader-cli/issues/393 ## 4.0.0 ### Added