diff --git a/src/cli/backup/onedrive.go b/src/cli/backup/onedrive.go index a7ca08f85..f5662f6ab 100644 --- a/src/cli/backup/onedrive.go +++ b/src/cli/backup/onedrive.go @@ -55,11 +55,6 @@ corso backup details onedrive --backup 1234abcd-12ab-cd34-56de-1234abcd \ --user alice@example.com --file-created-before 2015-01-01T00:00:00` ) -var ( - folderPaths []string - fileNames []string -) - // called by backup.go to map subcommands to provider-specific handling. func addOneDriveCommands(cmd *cobra.Command) *cobra.Command { var ( @@ -103,14 +98,14 @@ func addOneDriveCommands(cmd *cobra.Command) *cobra.Command { // onedrive hierarchy flags fs.StringSliceVar( - &folderPaths, + &utils.FolderPaths, utils.FolderFN, nil, "Select backup details by OneDrive folder; defaults to root.") fs.StringSliceVar( - &fileNames, + &utils.FileNames, utils.FileFN, nil, - "Select backup details by file name or ID.") + "Select backup details by file name.") // onedrive info flags @@ -263,8 +258,8 @@ func detailsOneDriveCmd(cmd *cobra.Command, args []string) error { ctx := cmd.Context() opts := utils.OneDriveOpts{ Users: user, - Names: fileNames, - Paths: folderPaths, + FileNames: utils.FileNames, + FolderPaths: utils.FolderPaths, FileCreatedAfter: utils.FileCreatedAfter, FileCreatedBefore: utils.FileCreatedBefore, FileModifiedAfter: utils.FileModifiedAfter, diff --git a/src/cli/backup/sharepoint.go b/src/cli/backup/sharepoint.go index e3d12fe33..972db09b2 100644 --- a/src/cli/backup/sharepoint.go +++ b/src/cli/backup/sharepoint.go @@ -26,12 +26,8 @@ import ( // sharePoint bucket info from flags var ( - libraryItems []string - libraryPaths []string - pageFolders []string - page []string - site []string - weburl []string + pageFolders []string + page []string sharepointData []string ) @@ -43,34 +39,29 @@ const ( const ( sharePointServiceCommand = "sharepoint" - sharePointServiceCommandCreateUseSuffix = "--site | '" + utils.Wildcard + "'" + sharePointServiceCommandCreateUseSuffix = "--web-url | '" + utils.Wildcard + "'" sharePointServiceCommandDeleteUseSuffix = "--backup " sharePointServiceCommandDetailsUseSuffix = "--backup " ) const ( - sharePointServiceCommandCreateExamples = `# Backup SharePoint data for -corso backup create sharepoint --site + sharePointServiceCommandCreateExamples = `# Backup SharePoint data for a Site +corso backup create sharepoint --web-url -# Backup SharePoint for Alice and Bob -corso backup create sharepoint --site , +# Backup SharePoint for two sites: HR and Team +corso backup create sharepoint --site https://example.com/hr,https://example.com/team -# TODO: Site IDs may contain commas. We'll need to warn the site about escaping them. - -# Backup all SharePoint data for all sites -corso backup create sharepoint --site '*'` +# Backup all SharePoint data for all Sites +corso backup create sharepoint --web-url '*'` sharePointServiceCommandDeleteExamples = `# Delete SharePoint backup with ID 1234abcd-12ab-cd34-56de-1234abcd corso backup delete sharepoint --backup 1234abcd-12ab-cd34-56de-1234abcd` - sharePointServiceCommandDetailsExamples = `# Explore 's files from backup 1234abcd-12ab-cd34-56de-1234abcd + sharePointServiceCommandDetailsExamples = `# Explore a site's files from backup 1234abcd-12ab-cd34-56de-1234abcd + +corso backup details sharepoint --backup 1234abcd-12ab-cd34-56de-1234abcd --web-url https://example.com -corso backup details sharepoint --backup 1234abcd-12ab-cd34-56de-1234abcd --site -<<<<<<< HEAD -# Explore site's files created before end of 2015 from a specific backup -======= # Find all site files that were created before a certain date. ->>>>>>> main corso backup details sharepoint --backup 1234abcd-12ab-cd34-56de-1234abcd \ --web-url https://example.com --file-created-before 2015-01-01T00:00:00 ` @@ -90,13 +81,15 @@ func addSharePointCommands(cmd *cobra.Command) *cobra.Command { c.Use = c.Use + " " + sharePointServiceCommandCreateUseSuffix c.Example = sharePointServiceCommandCreateExamples - fs.StringArrayVar(&site, + fs.StringArrayVar( + &utils.Site, utils.SiteFN, nil, "Backup SharePoint data by site ID; accepts '"+utils.Wildcard+"' to select all sites.") - fs.StringSliceVar(&weburl, + fs.StringSliceVar( + &utils.WebURL, utils.WebURLFN, nil, - "Restore data by site webURL; accepts '"+utils.Wildcard+"' to select all sites.") + "Restore data by site web URL; accepts '"+utils.Wildcard+"' to select all sites.") fs.StringSliceVar( &sharepointData, @@ -126,21 +119,28 @@ func addSharePointCommands(cmd *cobra.Command) *cobra.Command { // sharepoint hierarchy flags - fs.StringSliceVar( - &libraryPaths, - utils.LibraryFN, nil, - "Select backup details by Library name.") + fs.StringVar( + &utils.Library, + utils.LibraryFN, "", + "Select backup details within a library. Defaults includes all libraries.") fs.StringSliceVar( - &libraryItems, - utils.LibraryItemFN, nil, - "Select backup details by library item name or ID.") + &utils.FolderPaths, + utils.FolderFN, nil, + "Select backup details by folder; defaults to root.") - fs.StringArrayVar(&site, + fs.StringSliceVar( + &utils.FileNames, + utils.FileFN, nil, + "Select backup details by file name.") + + fs.StringArrayVar( + &utils.Site, utils.SiteFN, nil, "Select backup details by site ID; accepts '"+utils.Wildcard+"' to select all sites.") - fs.StringSliceVar(&weburl, + fs.StringSliceVar( + &utils.WebURL, utils.WebURLFN, nil, "Select backup data by site webURL; accepts '"+utils.Wildcard+"' to select all sites.") @@ -152,29 +152,28 @@ func addSharePointCommands(cmd *cobra.Command) *cobra.Command { fs.StringSliceVar( &page, utils.PagesFN, nil, - "Select backup data by file name; accepts '"+utils.Wildcard+"' to select all pages within the site.", - ) + "Select backup data by file name; accepts '"+utils.Wildcard+"' to select all pages within the site.") // sharepoint info flags fs.StringVar( &utils.FileCreatedAfter, utils.FileCreatedAfterFN, "", - "Select backup details for items created after this datetime.") + "Select backup details created after this datetime.") fs.StringVar( &utils.FileCreatedBefore, utils.FileCreatedBeforeFN, "", - "Select backup details for files created before this datetime.") + "Select backup details created before this datetime.") fs.StringVar( &utils.FileModifiedAfter, utils.FileModifiedAfterFN, "", - "Select backup details for files modified after this datetime.") + "Select backup details modified after this datetime.") fs.StringVar( &utils.FileModifiedBefore, utils.FileModifiedBeforeFN, "", - "Select backup details for files modified before this datetime.") + "Select backup details modified before this datetime.") case deleteCommand: c, fs = utils.AddCommand(cmd, sharePointDeleteCmd(), utils.MarkPreReleaseCommand()) @@ -214,7 +213,7 @@ func createSharePointCmd(cmd *cobra.Command, args []string) error { return nil } - if err := validateSharePointBackupCreateFlags(site, weburl, sharepointData); err != nil { + if err := validateSharePointBackupCreateFlags(utils.Site, utils.WebURL, sharepointData); err != nil { return err } @@ -233,9 +232,9 @@ func createSharePointCmd(cmd *cobra.Command, args []string) error { return Only(ctx, errors.Wrap(err, "Failed to connect to Microsoft APIs")) } - sel, err := sharePointBackupCreateSelectors(ctx, site, weburl, sharepointData, gc) + sel, err := sharePointBackupCreateSelectors(ctx, utils.Site, utils.WebURL, sharepointData, gc) if err != nil { - return Only(ctx, errors.Wrap(err, "Retrieving up sharepoint sites by ID and WebURL")) + return Only(ctx, errors.Wrap(err, "Retrieving up sharepoint sites by ID and Web URL")) } selectorSet := []selectors.Selector{} @@ -319,13 +318,13 @@ func includeAllSitesWithCategories(categories []string) *selectors.SharePointBac func addCategories(sel *selectors.SharePointBackup, cats []string) *selectors.SharePointBackup { // Issue #2631: Libraries are the only supported feature for SharePoint at this time. if len(cats) == 0 { - sel.Include(sel.Libraries(selectors.Any())) + sel.Include(sel.LibraryFolders(selectors.Any())) } for _, d := range cats { switch d { case dataLibraries: - sel.Include(sel.Libraries(selectors.Any())) + sel.Include(sel.LibraryFolders(selectors.Any())) case dataPages: sel.Include(sel.Pages(selectors.Any())) } @@ -396,10 +395,11 @@ func detailsSharePointCmd(cmd *cobra.Command, args []string) error { ctx := cmd.Context() opts := utils.SharePointOpts{ - LibraryItems: libraryItems, - LibraryPaths: libraryPaths, - Sites: site, - WebURLs: weburl, + FolderPaths: utils.FolderPaths, + FileNames: utils.FileNames, + Library: utils.Library, + Sites: utils.Site, + WebURLs: utils.WebURL, FileCreatedAfter: fileCreatedAfter, FileCreatedBefore: fileCreatedBefore, FileModifiedAfter: fileModifiedAfter, diff --git a/src/cli/backup/sharepoint_e2e_test.go b/src/cli/backup/sharepoint_e2e_test.go index 3a02e7937..61dd543d6 100644 --- a/src/cli/backup/sharepoint_e2e_test.go +++ b/src/cli/backup/sharepoint_e2e_test.go @@ -161,7 +161,7 @@ func (suite *BackupDeleteSharePointE2ESuite) SetupSuite() { // some tests require an existing backup sel := selectors.NewSharePointBackup(sites) - sel.Include(sel.Libraries(selectors.Any())) + sel.Include(sel.LibraryFolders(selectors.Any())) suite.backupOp, err = suite.repo.NewBackup(ctx, sel.Selector) require.NoError(t, suite.backupOp.Run(ctx)) diff --git a/src/cli/restore/onedrive.go b/src/cli/restore/onedrive.go index 08a2f6629..9beeaf3a9 100644 --- a/src/cli/restore/onedrive.go +++ b/src/cli/restore/onedrive.go @@ -133,8 +133,8 @@ func restoreOneDriveCmd(cmd *cobra.Command, args []string) error { opts := utils.OneDriveOpts{ Users: user, - Names: fileNames, - Paths: folderPaths, + FileNames: fileNames, + FolderPaths: folderPaths, FileCreatedAfter: utils.FileCreatedAfter, FileCreatedBefore: utils.FileCreatedBefore, FileModifiedAfter: utils.FileModifiedAfter, diff --git a/src/cli/restore/sharepoint.go b/src/cli/restore/sharepoint.go index 0899788a4..a1ebc9a25 100644 --- a/src/cli/restore/sharepoint.go +++ b/src/cli/restore/sharepoint.go @@ -16,14 +16,10 @@ import ( ) var ( - listItems []string - listPaths []string - pageFolders []string - pages []string - libraryItems []string - libraryPaths []string - site []string - weburl []string + listItems []string + listPaths []string + pageFolders []string + pages []string ) // called by restore.go to map subcommands to provider-specific handling. @@ -43,30 +39,38 @@ func addSharePointCommands(cmd *cobra.Command) *cobra.Command { // More generic (ex: --site) and more frequently used flags take precedence. fs.SortFlags = false - fs.StringVar(&backupID, + fs.StringVar( + &backupID, utils.BackupFN, "", "ID of the backup to restore. (required)") cobra.CheckErr(c.MarkFlagRequired(utils.BackupFN)) - fs.StringSliceVar(&site, + fs.StringSliceVar( + &utils.Site, utils.SiteFN, nil, "Restore data by site ID; accepts '"+utils.Wildcard+"' to select all sites.") - fs.StringSliceVar(&weburl, + fs.StringSliceVar( + &utils.WebURL, utils.WebURLFN, nil, "Restore data by site webURL; accepts '"+utils.Wildcard+"' to select all sites.") // sharepoint hierarchy (path/name) flags - fs.StringSliceVar( - &libraryPaths, - utils.LibraryFN, nil, - "Restore library items by SharePoint library") + fs.StringVar( + &utils.Library, + utils.LibraryFN, "", + "Restore files within a library. Default includes all libraries.") fs.StringSliceVar( - &libraryItems, - utils.LibraryItemFN, nil, - "Restore library items by file name or ID") + &utils.FolderPaths, + utils.FolderFN, nil, + "Restore files by folder; defaults to root.") + + fs.StringSliceVar( + &utils.FileNames, + utils.FileFN, nil, + "Restore files by name.") fs.StringSliceVar( &listPaths, @@ -81,21 +85,33 @@ func addSharePointCommands(cmd *cobra.Command) *cobra.Command { fs.StringSliceVar( &pageFolders, utils.PageFolderFN, nil, - "Restore Site pages by page folder name", - ) + "Restore Site pages by page folder name") fs.StringSliceVar( &pages, utils.PagesFN, nil, - "Restore site pages by file name(s)", - ) + "Restore site pages by file name(s)") // sharepoint info flags - // fs.StringVar( - // &fileCreatedAfter, - // utils.FileCreatedAfterFN, "", - // "Restore files created after this datetime") + fs.StringVar( + &utils.FileCreatedAfter, + utils.FileCreatedAfterFN, "", + "Restore files created after this datetime.") + + fs.StringVar( + &utils.FileCreatedBefore, + utils.FileCreatedBeforeFN, "", + "Restore files created before this datetime.") + + fs.StringVar( + &utils.FileModifiedAfter, + utils.FileModifiedAfterFN, "", + "Restore files modified after this datetime.") + fs.StringVar( + &utils.FileModifiedBefore, + utils.FileModifiedBeforeFN, "", + "Restore files modified before this datetime.") // others options.AddOperationFlags(c) @@ -112,13 +128,13 @@ const ( sharePointServiceCommandRestoreExamples = `# Restore file with ID 98765abcdef corso restore sharepoint --backup 1234abcd-12ab-cd34-56de-1234abcd --file 98765abcdef -# Restore 's file named "ServerRenderTemplate.xsl in "Display Templates/Style Sheets" from a specific backup +# Restore a Site's file named "ServerRenderTemplate.xsl in "Display Templates/Style Sheets" from a specific backup corso restore sharepoint --backup 1234abcd-12ab-cd34-56de-1234abcd \ - --site --file "ServerRenderTemplate.xsl" --folder "Display Templates/Style Sheets" + --web-url https://example.com --file "ServerRenderTemplate.xsl" --folder "Display Templates/Style Sheets" -# Restore all files from that were created before 2020 when captured in a specific backup +# Restore all files from a Site that were created before 2020 when captured in a specific backup corso restore sharepoint --backup 1234abcd-12ab-cd34-56de-1234abcd - --site --folder "Display Templates/Style Sheets" --file-created-before 2020-01-01T00:00:00` + --web-url https://example.com --folder "Display Templates/Style Sheets" --file-created-before 2020-01-01T00:00:00` ) // `corso restore sharepoint [...]` @@ -141,14 +157,15 @@ func restoreSharePointCmd(cmd *cobra.Command, args []string) error { } opts := utils.SharePointOpts{ - LibraryItems: libraryItems, - LibraryPaths: libraryPaths, + FileNames: utils.FileNames, + FolderPaths: utils.FolderPaths, + Library: utils.Library, ListItems: listItems, ListPaths: listPaths, PageFolders: pageFolders, Pages: pages, - Sites: site, - WebURLs: weburl, + Sites: utils.Site, + WebURLs: utils.WebURL, FileCreatedAfter: utils.FileCreatedAfter, FileCreatedBefore: utils.FileCreatedBefore, FileModifiedAfter: utils.FileModifiedAfter, diff --git a/src/cli/utils/flags.go b/src/cli/utils/flags.go index ed446914d..1dbd00968 100644 --- a/src/cli/utils/flags.go +++ b/src/cli/utils/flags.go @@ -10,18 +10,37 @@ import ( "github.com/alcionai/corso/src/pkg/path" ) -// ============================================== -// Folder Object flags -// These options are flags for indicating -// that a time-based filter should be used for -// within returning objects for details. -// Used by: OneDrive, SharePoint -// ================================================ +// common flag vars var ( + FolderPaths []string + FileNames []string + FileCreatedAfter string FileCreatedBefore string FileModifiedAfter string FileModifiedBefore string + + Library string + Site []string + WebURL []string +) + +// common flag names +const ( + BackupFN = "backup" + DataFN = "data" + LibraryFN = "library" + SiteFN = "site" + UserFN = "user" + WebURLFN = "web-url" + + FileFN = "file" + FolderFN = "folder" + + FileCreatedAfterFN = "file-created-after" + FileCreatedBeforeFN = "file-created-before" + FileModifiedAfterFN = "file-modified-after" + FileModifiedBeforeFN = "file-modified-before" ) type PopulatedFlags map[string]struct{} diff --git a/src/cli/utils/onedrive.go b/src/cli/utils/onedrive.go index 17d71fbe2..04a317ff4 100644 --- a/src/cli/utils/onedrive.go +++ b/src/cli/utils/onedrive.go @@ -6,17 +6,10 @@ import ( "github.com/alcionai/corso/src/pkg/selectors" ) -const ( - FileFN = "file" - FolderFN = "folder" - NamesFN = "name" - PathsFN = "path" -) - type OneDriveOpts struct { Users []string - Names []string - Paths []string + FileNames []string + FolderPaths []string FileCreatedAfter string FileCreatedBefore string FileModifiedAfter string @@ -74,7 +67,7 @@ func IncludeOneDriveRestoreDataSelectors(opts OneDriveOpts) *selectors.OneDriveR sel := selectors.NewOneDriveRestore(users) - lp, ln := len(opts.Paths), len(opts.Names) + lp, ln := len(opts.FolderPaths), len(opts.FileNames) // only use the inclusion if either a path or item name // is specified @@ -83,20 +76,20 @@ func IncludeOneDriveRestoreDataSelectors(opts OneDriveOpts) *selectors.OneDriveR return sel } - opts.Paths = trimFolderSlash(opts.Paths) + opts.FolderPaths = trimFolderSlash(opts.FolderPaths) if ln == 0 { - opts.Names = selectors.Any() + opts.FileNames = selectors.Any() } - containsFolders, prefixFolders := splitFoldersIntoContainsAndPrefix(opts.Paths) + containsFolders, prefixFolders := splitFoldersIntoContainsAndPrefix(opts.FolderPaths) if len(containsFolders) > 0 { - sel.Include(sel.Items(containsFolders, opts.Names)) + sel.Include(sel.Items(containsFolders, opts.FileNames)) } if len(prefixFolders) > 0 { - sel.Include(sel.Items(prefixFolders, opts.Names, selectors.PrefixMatch())) + sel.Include(sel.Items(prefixFolders, opts.FileNames, selectors.PrefixMatch())) } return sel diff --git a/src/cli/utils/onedrive_test.go b/src/cli/utils/onedrive_test.go index f7d75f340..1858d717a 100644 --- a/src/cli/utils/onedrive_test.go +++ b/src/cli/utils/onedrive_test.go @@ -36,54 +36,54 @@ func (suite *OneDriveUtilsSuite) TestIncludeOneDriveRestoreDataSelectors() { { name: "no inputs", opts: utils.OneDriveOpts{ - Users: empty, - Paths: empty, - Names: empty, + Users: empty, + FileNames: empty, + FolderPaths: empty, }, expectIncludeLen: 1, }, { name: "single inputs", opts: utils.OneDriveOpts{ - Users: single, - Paths: single, - Names: single, + Users: single, + FileNames: single, + FolderPaths: single, }, expectIncludeLen: 1, }, { name: "multi inputs", opts: utils.OneDriveOpts{ - Users: multi, - Paths: multi, - Names: multi, + Users: multi, + FileNames: multi, + FolderPaths: multi, }, expectIncludeLen: 1, }, { name: "folder contains", opts: utils.OneDriveOpts{ - Users: empty, - Paths: containsOnly, - Names: empty, + Users: empty, + FileNames: empty, + FolderPaths: containsOnly, }, expectIncludeLen: 1, }, { name: "folder prefixes", opts: utils.OneDriveOpts{ - Users: empty, - Paths: prefixOnly, - Names: empty, + Users: empty, + FileNames: empty, + FolderPaths: prefixOnly, }, expectIncludeLen: 1, }, { name: "folder prefixes and contains", opts: utils.OneDriveOpts{ - Users: empty, - Paths: containsAndPrefix, - Names: empty, + Users: empty, + FileNames: empty, + FolderPaths: containsAndPrefix, }, expectIncludeLen: 2, }, diff --git a/src/cli/utils/sharepoint.go b/src/cli/utils/sharepoint.go index 6724c81a3..83cfc0a1a 100644 --- a/src/cli/utils/sharepoint.go +++ b/src/cli/utils/sharepoint.go @@ -8,18 +8,16 @@ import ( ) const ( - LibraryItemFN = "library-item" - LibraryFN = "library" - ListItemFN = "list-item" - ListFN = "list" - PageFolderFN = "page-folders" - PagesFN = "pages" - WebURLFN = "web-url" + ListItemFN = "list-item" + ListFN = "list" + PageFolderFN = "page-folders" + PagesFN = "pages" ) type SharePointOpts struct { - LibraryItems []string - LibraryPaths []string + FileNames []string // for libraries, to duplicate onedrive interface + FolderPaths []string // for libraries, to duplicate onedrive interface + Library string ListItems []string ListPaths []string PageFolders []string @@ -79,7 +77,7 @@ func AddSharePointFilter( func IncludeSharePointRestoreDataSelectors(opts SharePointOpts) *selectors.SharePointRestore { sites := opts.Sites - lp, li := len(opts.LibraryPaths), len(opts.LibraryItems) + lfp, lfn := len(opts.FolderPaths), len(opts.FileNames) ls, lwu := len(opts.Sites), len(opts.WebURLs) slp, sli := len(opts.ListPaths), len(opts.ListItems) pf, pi := len(opts.PageFolders), len(opts.Pages) @@ -90,25 +88,25 @@ func IncludeSharePointRestoreDataSelectors(opts SharePointOpts) *selectors.Share sel := selectors.NewSharePointRestore(sites) - if lp+li+lwu+slp+sli+pf+pi == 0 { + if lfp+lfn+lwu+slp+sli+pf+pi == 0 { sel.Include(sel.AllData()) return sel } - if lp+li > 0 { - if li == 0 { - opts.LibraryItems = selectors.Any() + if lfp+lfn > 0 { + if lfn == 0 { + opts.FileNames = selectors.Any() } - opts.LibraryPaths = trimFolderSlash(opts.LibraryPaths) - containsFolders, prefixFolders := splitFoldersIntoContainsAndPrefix(opts.LibraryPaths) + opts.FolderPaths = trimFolderSlash(opts.FolderPaths) + containsFolders, prefixFolders := splitFoldersIntoContainsAndPrefix(opts.FolderPaths) if len(containsFolders) > 0 { - sel.Include(sel.LibraryItems(containsFolders, opts.LibraryItems)) + sel.Include(sel.LibraryItems(containsFolders, opts.FileNames)) } if len(prefixFolders) > 0 { - sel.Include(sel.LibraryItems(prefixFolders, opts.LibraryItems, selectors.PrefixMatch())) + sel.Include(sel.LibraryItems(prefixFolders, opts.FileNames, selectors.PrefixMatch())) } } @@ -167,6 +165,7 @@ func FilterSharePointRestoreInfoSelectors( sel *selectors.SharePointRestore, opts SharePointOpts, ) { + AddSharePointFilter(sel, opts.Library, sel.Library) AddSharePointFilter(sel, opts.FileCreatedAfter, sel.CreatedAfter) AddSharePointFilter(sel, opts.FileCreatedBefore, sel.CreatedBefore) AddSharePointFilter(sel, opts.FileModifiedAfter, sel.ModifiedAfter) diff --git a/src/cli/utils/sharepoint_test.go b/src/cli/utils/sharepoint_test.go index 06061fe0f..1c467381d 100644 --- a/src/cli/utils/sharepoint_test.go +++ b/src/cli/utils/sharepoint_test.go @@ -43,74 +43,74 @@ func (suite *SharePointUtilsSuite) TestIncludeSharePointRestoreDataSelectors() { { name: "single inputs", opts: utils.SharePointOpts{ - LibraryItems: single, - LibraryPaths: single, - Sites: single, - WebURLs: single, + FileNames: single, + FolderPaths: single, + Sites: single, + WebURLs: single, }, expectIncludeLen: 4, }, { name: "single extended", opts: utils.SharePointOpts{ - LibraryItems: single, - LibraryPaths: single, - ListItems: single, - ListPaths: single, - Sites: single, - WebURLs: single, + FileNames: single, + FolderPaths: single, + ListItems: single, + ListPaths: single, + Sites: single, + WebURLs: single, }, expectIncludeLen: 5, }, { name: "multi inputs", opts: utils.SharePointOpts{ - LibraryItems: multi, - LibraryPaths: multi, - Sites: multi, - WebURLs: multi, + FileNames: multi, + FolderPaths: multi, + Sites: multi, + WebURLs: multi, }, expectIncludeLen: 4, }, { - name: "library contains", + name: "library folder contains", opts: utils.SharePointOpts{ - LibraryItems: empty, - LibraryPaths: containsOnly, - Sites: empty, - WebURLs: empty, + FileNames: empty, + FolderPaths: containsOnly, + Sites: empty, + WebURLs: empty, }, expectIncludeLen: 1, }, { - name: "library prefixes", + name: "library folder prefixes", opts: utils.SharePointOpts{ - LibraryItems: empty, - LibraryPaths: prefixOnly, - Sites: empty, - WebURLs: empty, + FileNames: empty, + FolderPaths: prefixOnly, + Sites: empty, + WebURLs: empty, }, expectIncludeLen: 1, }, { - name: "library prefixes and contains", + name: "library folder prefixes and contains", opts: utils.SharePointOpts{ - LibraryItems: empty, - LibraryPaths: containsAndPrefix, - Sites: empty, - WebURLs: empty, + FileNames: empty, + FolderPaths: containsAndPrefix, + Sites: empty, + WebURLs: empty, }, expectIncludeLen: 2, }, { name: "list contains", opts: utils.SharePointOpts{ - LibraryItems: empty, - LibraryPaths: empty, - ListItems: empty, - ListPaths: containsOnly, - Sites: empty, - WebURLs: empty, + FileNames: empty, + FolderPaths: empty, + ListItems: empty, + ListPaths: containsOnly, + Sites: empty, + WebURLs: empty, }, expectIncludeLen: 1, }, @@ -131,30 +131,30 @@ func (suite *SharePointUtilsSuite) TestIncludeSharePointRestoreDataSelectors() { { name: "weburl contains", opts: utils.SharePointOpts{ - LibraryItems: empty, - LibraryPaths: empty, - Sites: empty, - WebURLs: containsOnly, + FileNames: empty, + FolderPaths: empty, + Sites: empty, + WebURLs: containsOnly, }, expectIncludeLen: 3, }, { - name: "library suffixes", + name: "library folder suffixes", opts: utils.SharePointOpts{ - LibraryItems: empty, - LibraryPaths: empty, - Sites: empty, - WebURLs: prefixOnly, // prefix pattern matches suffix pattern + FileNames: empty, + FolderPaths: empty, + Sites: empty, + WebURLs: prefixOnly, // prefix pattern matches suffix pattern }, expectIncludeLen: 3, }, { - name: "library suffixes and contains", + name: "library folder suffixes and contains", opts: utils.SharePointOpts{ - LibraryItems: empty, - LibraryPaths: empty, - Sites: empty, - WebURLs: containsAndPrefix, // prefix pattern matches suffix pattern + FileNames: empty, + FolderPaths: empty, + Sites: empty, + WebURLs: containsAndPrefix, // prefix pattern matches suffix pattern }, expectIncludeLen: 6, }, @@ -173,10 +173,10 @@ func (suite *SharePointUtilsSuite) TestIncludeSharePointRestoreDataSelectors() { expectIncludeLen: 1, }, { - name: "Page & Library", + name: "Page & library Files", opts: utils.SharePointOpts{ - PageFolders: single, - LibraryItems: multi, + PageFolders: single, + FileNames: multi, }, expectIncludeLen: 2, }, diff --git a/src/cli/utils/testdata/opts.go b/src/cli/utils/testdata/opts.go index c280a04d7..1af633e40 100644 --- a/src/cli/utils/testdata/opts.go +++ b/src/cli/utils/testdata/opts.go @@ -350,28 +350,28 @@ var ( Name: "AllFiles", Expected: testdata.OneDriveItems, Opts: utils.OneDriveOpts{ - Paths: selectors.Any(), + FolderPaths: selectors.Any(), }, }, { Name: "FolderPrefixMatch", Expected: testdata.OneDriveItems, Opts: utils.OneDriveOpts{ - Paths: []string{testdata.OneDriveFolderFolder}, + FolderPaths: []string{testdata.OneDriveFolderFolder}, }, }, { Name: "FolderPrefixMatchTrailingSlash", Expected: testdata.OneDriveItems, Opts: utils.OneDriveOpts{ - Paths: []string{testdata.OneDriveFolderFolder + "/"}, + FolderPaths: []string{testdata.OneDriveFolderFolder + "/"}, }, }, { Name: "FolderPrefixMatchTrailingSlash", Expected: testdata.OneDriveItems, Opts: utils.OneDriveOpts{ - Paths: []string{testdata.OneDriveFolderFolder + "/"}, + FolderPaths: []string{testdata.OneDriveFolderFolder + "/"}, }, }, { @@ -381,7 +381,7 @@ var ( testdata.OneDriveItems[1], }, Opts: utils.OneDriveOpts{ - Names: []string{ + FileNames: []string{ testdata.OneDriveItems[0].ShortRef, testdata.OneDriveItems[1].ShortRef, }, @@ -438,28 +438,28 @@ var ( Name: "AllLibraryItems", Expected: testdata.SharePointLibraryItems, Opts: utils.SharePointOpts{ - LibraryPaths: selectors.Any(), + FolderPaths: selectors.Any(), }, }, { Name: "FolderPrefixMatch", Expected: testdata.SharePointLibraryItems, Opts: utils.SharePointOpts{ - LibraryPaths: []string{testdata.SharePointLibraryFolder}, + FolderPaths: []string{testdata.SharePointLibraryFolder}, }, }, { Name: "FolderPrefixMatchTrailingSlash", Expected: testdata.SharePointLibraryItems, Opts: utils.SharePointOpts{ - LibraryPaths: []string{testdata.SharePointLibraryFolder + "/"}, + FolderPaths: []string{testdata.SharePointLibraryFolder + "/"}, }, }, { Name: "FolderPrefixMatchTrailingSlash", Expected: testdata.SharePointLibraryItems, Opts: utils.SharePointOpts{ - LibraryPaths: []string{testdata.SharePointLibraryFolder + "/"}, + FolderPaths: []string{testdata.SharePointLibraryFolder + "/"}, }, }, { @@ -469,7 +469,7 @@ var ( testdata.SharePointLibraryItems[1], }, Opts: utils.SharePointOpts{ - LibraryItems: []string{ + FileNames: []string{ testdata.SharePointLibraryItems[0].ShortRef, testdata.SharePointLibraryItems[1].ShortRef, }, diff --git a/src/cli/utils/utils.go b/src/cli/utils/utils.go index f9921dd58..5b6c268dd 100644 --- a/src/cli/utils/utils.go +++ b/src/cli/utils/utils.go @@ -17,18 +17,6 @@ import ( "github.com/alcionai/corso/src/pkg/storage" ) -// common flag names -const ( - BackupFN = "backup" - DataFN = "data" - SiteFN = "site" - UserFN = "user" - FileCreatedAfterFN = "file-created-after" - FileCreatedBeforeFN = "file-created-before" - FileModifiedAfterFN = "file-modified-after" - FileModifiedBeforeFN = "file-modified-before" -) - const ( Wildcard = "*" ) diff --git a/src/internal/connector/data_collections_test.go b/src/internal/connector/data_collections_test.go index 2bfe0ede5..fd1ce5abb 100644 --- a/src/internal/connector/data_collections_test.go +++ b/src/internal/connector/data_collections_test.go @@ -168,7 +168,7 @@ func (suite *ConnectorDataCollectionIntegrationSuite) TestDataCollections_invali name: "Invalid sharepoint backup site", getSelector: func(t *testing.T) selectors.Selector { sel := selectors.NewSharePointBackup(owners) - sel.Include(sel.Libraries(selectors.Any())) + sel.Include(sel.LibraryFolders(selectors.Any())) return sel.Selector }, }, @@ -194,7 +194,7 @@ func (suite *ConnectorDataCollectionIntegrationSuite) TestDataCollections_invali name: "missing sharepoint backup site", getSelector: func(t *testing.T) selectors.Selector { sel := selectors.NewSharePointBackup(owners) - sel.Include(sel.Libraries(selectors.Any())) + sel.Include(sel.LibraryFolders(selectors.Any())) sel.DiscreteOwner = "" return sel.Selector }, @@ -237,7 +237,7 @@ func (suite *ConnectorDataCollectionIntegrationSuite) TestSharePointDataCollecti name: "Libraries", getSelector: func() selectors.Selector { sel := selectors.NewSharePointBackup(selSites) - sel.Include(sel.Libraries(selectors.Any())) + sel.Include(sel.LibraryFolders(selectors.Any())) return sel.Selector }, }, @@ -334,7 +334,7 @@ func (suite *ConnectorCreateSharePointCollectionIntegrationSuite) TestCreateShar ) sel := selectors.NewSharePointBackup(siteIDs) - sel.Include(sel.Libraries([]string{"foo"}, selectors.PrefixMatch())) + sel.Include(sel.LibraryFolders([]string{"foo"}, selectors.PrefixMatch())) cols, excludes, err := gc.DataCollections( ctx, diff --git a/src/internal/connector/onedrive/item.go b/src/internal/connector/onedrive/item.go index 73393498f..f345d482f 100644 --- a/src/internal/connector/onedrive/item.go +++ b/src/internal/connector/onedrive/item.go @@ -194,7 +194,7 @@ func downloadItem(ctx context.Context, hc *http.Client, item models.DriveItemabl // doesn't have its size value updated as a side effect of creation, // and kiota drops any SetSize update. func oneDriveItemInfo(di models.DriveItemable, itemSize int64) *details.OneDriveInfo { - var email, parent string + var email, driveName, driveID string if di.GetCreatedBy() != nil && di.GetCreatedBy().GetUser() != nil { // User is sometimes not available when created via some @@ -205,19 +205,20 @@ func oneDriveItemInfo(di models.DriveItemable, itemSize int64) *details.OneDrive } } - if di.GetParentReference() != nil && di.GetParentReference().GetName() != nil { - // EndPoint is not always populated from external apps - parent = *di.GetParentReference().GetName() + if di.GetParentReference() != nil { + driveID = ptr.Val(di.GetParentReference().GetDriveId()) + driveName = strings.TrimSpace(ptr.Val(di.GetParentReference().GetName())) } return &details.OneDriveInfo{ - ItemType: details.OneDriveItem, - ItemName: ptr.Val(di.GetName()), Created: ptr.Val(di.GetCreatedDateTime()), + DriveID: driveID, + DriveName: driveName, + ItemName: ptr.Val(di.GetName()), + ItemType: details.OneDriveItem, Modified: ptr.Val(di.GetLastModifiedDateTime()), - DriveName: parent, - Size: itemSize, Owner: email, + Size: itemSize, } } @@ -311,10 +312,7 @@ func filterUserPermissions(ctx context.Context, perms []models.Permissionable) [ // and kiota drops any SetSize update. // TODO: Update drive name during Issue #2071 func sharePointItemInfo(di models.DriveItemable, itemSize int64) *details.SharePointInfo { - var ( - id, parentID, displayName, url string - reference = di.GetParentReference() - ) + var id, driveName, driveID, weburl string // TODO: we rely on this info for details/restore lookups, // so if it's nil we have an issue, and will need an alternative @@ -323,28 +321,28 @@ func sharePointItemInfo(di models.DriveItemable, itemSize int64) *details.ShareP gsi := di.GetSharepointIds() if gsi != nil { id = ptr.Val(gsi.GetSiteId()) - url = ptr.Val(gsi.GetSiteUrl()) + weburl = ptr.Val(gsi.GetSiteUrl()) - if len(url) == 0 { - url = constructWebURL(di.GetAdditionalData()) + if len(weburl) == 0 { + weburl = constructWebURL(di.GetAdditionalData()) } } - if reference != nil { - parentID = ptr.Val(reference.GetDriveId()) - displayName = strings.TrimSpace(ptr.Val(reference.GetName())) + if di.GetParentReference() != nil { + driveID = ptr.Val(di.GetParentReference().GetDriveId()) + driveName = strings.TrimSpace(ptr.Val(di.GetParentReference().GetName())) } return &details.SharePointInfo{ - ItemType: details.OneDriveItem, - ItemName: ptr.Val(di.GetName()), - Created: ptr.Val(di.GetCreatedDateTime()), - Modified: ptr.Val(di.GetLastModifiedDateTime()), - DriveName: parentID, - DisplayName: displayName, - Size: itemSize, - Owner: id, - WebURL: url, + ItemType: details.OneDriveItem, + ItemName: ptr.Val(di.GetName()), + Created: ptr.Val(di.GetCreatedDateTime()), + Modified: ptr.Val(di.GetLastModifiedDateTime()), + DriveID: driveID, + DriveName: driveName, + Size: itemSize, + Owner: id, + WebURL: weburl, } } diff --git a/src/internal/connector/sharepoint/data_collections.go b/src/internal/connector/sharepoint/data_collections.go index cfe334e6b..35afe01e8 100644 --- a/src/internal/connector/sharepoint/data_collections.go +++ b/src/internal/connector/sharepoint/data_collections.go @@ -261,9 +261,9 @@ type folderMatcher struct { } func (fm folderMatcher) IsAny() bool { - return fm.scope.IsAny(selectors.SharePointLibrary) + return fm.scope.IsAny(selectors.SharePointLibraryFolder) } func (fm folderMatcher) Matches(dir string) bool { - return fm.scope.Matches(selectors.SharePointLibrary, dir) + return fm.scope.Matches(selectors.SharePointLibraryFolder, dir) } diff --git a/src/internal/connector/sharepoint/data_collections_test.go b/src/internal/connector/sharepoint/data_collections_test.go index 5aed5e649..bb7fc8e7f 100644 --- a/src/internal/connector/sharepoint/data_collections_test.go +++ b/src/internal/connector/sharepoint/data_collections_test.go @@ -29,11 +29,11 @@ type testFolderMatcher struct { } func (fm testFolderMatcher) IsAny() bool { - return fm.scope.IsAny(selectors.SharePointLibrary) + return fm.scope.IsAny(selectors.SharePointLibraryFolder) } func (fm testFolderMatcher) Matches(path string) bool { - return fm.scope.Matches(selectors.SharePointLibrary, path) + return fm.scope.Matches(selectors.SharePointLibraryFolder, path) } // --------------------------------------------------------------------------- @@ -49,7 +49,7 @@ func TestSharePointLibrariesUnitSuite(t *testing.T) { } func (suite *SharePointLibrariesUnitSuite) TestUpdateCollections() { - anyFolder := (&selectors.SharePointBackup{}).Libraries(selectors.Any())[0] + anyFolder := (&selectors.SharePointBackup{}).LibraryFolders(selectors.Any())[0] const ( tenant = "tenant" diff --git a/src/internal/operations/backup_integration_test.go b/src/internal/operations/backup_integration_test.go index 0acbe42b5..221956006 100644 --- a/src/internal/operations/backup_integration_test.go +++ b/src/internal/operations/backup_integration_test.go @@ -1101,7 +1101,7 @@ func (suite *BackupOpIntegrationSuite) TestBackup_Run_sharePoint() { sel = selectors.NewSharePointBackup([]string{suite.site}) ) - sel.Include(sel.Libraries(selectors.Any())) + sel.Include(sel.LibraryFolders(selectors.Any())) bo, _, kw, _, closer := prepNewTestBackupOp(t, ctx, mb, sel.Selector, control.Toggles{}) defer closer() diff --git a/src/internal/operations/restore_test.go b/src/internal/operations/restore_test.go index 910662c39..45a86fb0d 100644 --- a/src/internal/operations/restore_test.go +++ b/src/internal/operations/restore_test.go @@ -219,9 +219,7 @@ func (suite *RestoreOpIntegrationSuite) SetupSuite() { sites := []string{siteID} csel := selectors.NewSharePointBackup(sites) csel.DiscreteOwner = siteID - csel.Include( - csel.Libraries(selectors.Any()), - ) + csel.Include(csel.LibraryFolders(selectors.Any())) bo, err = NewBackupOperation( ctx, diff --git a/src/pkg/backup/details/details.go b/src/pkg/backup/details/details.go index 204dd1fc0..8ec5c1328 100644 --- a/src/pkg/backup/details/details.go +++ b/src/pkg/backup/details/details.go @@ -599,22 +599,22 @@ func (i ExchangeInfo) Values() []string { // SharePointInfo describes a sharepoint item type SharePointInfo struct { - Created time.Time `json:"created,omitempty"` - ItemName string `json:"itemName,omitempty"` - DriveName string `json:"driveName,omitempty"` - DisplayName string `json:"displayName,omitempty"` - ItemType ItemType `json:"itemType,omitempty"` - Modified time.Time `josn:"modified,omitempty"` - Owner string `json:"owner,omitempty"` - ParentPath string `json:"parentPath,omitempty"` - Size int64 `json:"size,omitempty"` - WebURL string `json:"webUrl,omitempty"` + Created time.Time `json:"created,omitempty"` + DriveName string `json:"driveName,omitempty"` + DriveID string `json:"driveID,omitempty"` + ItemName string `json:"itemName,omitempty"` + ItemType ItemType `json:"itemType,omitempty"` + Modified time.Time `josn:"modified,omitempty"` + Owner string `json:"owner,omitempty"` + ParentPath string `json:"parentPath,omitempty"` + Size int64 `json:"size,omitempty"` + WebURL string `json:"webUrl,omitempty"` } // Headers returns the human-readable names of properties in a SharePointInfo // for printing out to a terminal in a columnar display. func (i SharePointInfo) Headers() []string { - return []string{"ItemName", "Drive", "ParentPath", "Size", "WebURL", "Created", "Modified"} + return []string{"ItemName", "Library", "ParentPath", "Size", "WebURL", "Created", "Modified"} } // Values returns the values matching the Headers list for printing @@ -622,7 +622,7 @@ func (i SharePointInfo) Headers() []string { func (i SharePointInfo) Values() []string { return []string{ i.ItemName, - i.DisplayName, + i.DriveName, i.ParentPath, humanize.Bytes(uint64(i.Size)), i.WebURL, @@ -645,10 +645,11 @@ func (i *SharePointInfo) UpdateParentPath(newPath path.Path) error { // OneDriveInfo describes a oneDrive item type OneDriveInfo struct { Created time.Time `json:"created,omitempty"` - ItemName string `json:"itemName,omitempty"` + DriveID string `json:"driveID,omitempty"` DriveName string `json:"driveName,omitempty"` - ItemType ItemType `json:"itemType,omitempty"` IsMeta bool `json:"isMeta,omitempty"` + ItemName string `json:"itemName,omitempty"` + ItemType ItemType `json:"itemType,omitempty"` Modified time.Time `json:"modified,omitempty"` Owner string `json:"owner,omitempty"` ParentPath string `json:"parentPath"` diff --git a/src/pkg/backup/details/details_test.go b/src/pkg/backup/details/details_test.go index a259537ca..323d2770b 100644 --- a/src/pkg/backup/details/details_test.go +++ b/src/pkg/backup/details/details_test.go @@ -113,21 +113,21 @@ func (suite *DetailsUnitSuite) TestDetailsEntry_HeadersValues() { LocationRef: "locationref", ItemInfo: ItemInfo{ SharePoint: &SharePointInfo{ - ItemName: "itemName", - ParentPath: "parentPath", - Size: 1000, - WebURL: "https://not.a.real/url", - DisplayName: "aDrive", - Created: now, - Modified: now, + ItemName: "itemName", + ParentPath: "parentPath", + Size: 1000, + WebURL: "https://not.a.real/url", + DriveName: "aLibrary", + Created: now, + Modified: now, }, }, }, - expectHs: []string{"ID", "ItemName", "Drive", "ParentPath", "Size", "WebURL", "Created", "Modified"}, + expectHs: []string{"ID", "ItemName", "Library", "ParentPath", "Size", "WebURL", "Created", "Modified"}, expectVs: []string{ "deadbeef", "itemName", - "aDrive", + "aLibrary", "parentPath", "1.0 kB", "https://not.a.real/url", diff --git a/src/pkg/selectors/selectors_test.go b/src/pkg/selectors/selectors_test.go index da13e4f83..d2ba90cbe 100644 --- a/src/pkg/selectors/selectors_test.go +++ b/src/pkg/selectors/selectors_test.go @@ -346,7 +346,7 @@ func (suite *SelectorSuite) TestPathCategories_includes() { isErr: assert.NoError, getSelector: func(t *testing.T) *Selector { sel := NewSharePointBackup(users) - sel.Include(sel.Libraries([]string{"A directory"}, SuffixMatch())) + sel.Include(sel.LibraryFolders([]string{"A directory"}, SuffixMatch())) return &sel.Selector }, diff --git a/src/pkg/selectors/sharepoint.go b/src/pkg/selectors/sharepoint.go index f7cfc47e2..5ff36fcfa 100644 --- a/src/pkg/selectors/sharepoint.go +++ b/src/pkg/selectors/sharepoint.go @@ -225,7 +225,7 @@ func (s *sharePoint) AllData() []SharePointScope { scopes = append( scopes, - makeScope[SharePointScope](SharePointLibrary, Any()), + makeScope[SharePointScope](SharePointLibraryFolder, Any()), makeScope[SharePointScope](SharePointList, Any()), makeScope[SharePointScope](SharePointPageFolder, Any()), ) @@ -265,11 +265,28 @@ func (s *sharePoint) ListItems(lists, items []string, opts ...option) []SharePoi return scopes } -// Libraries produces one or more SharePoint library scopes. +// Library produces one or more SharePoint library scopes, where the library +// matches upon a given drive by ID or Name. In order to ensure library selection +// this should always be embedded within the Filter() set; include(Library()) will +// select all items in the library without further filtering. // If any slice contains selectors.Any, that slice is reduced to [selectors.Any] // If any slice contains selectors.None, that slice is reduced to [selectors.None] // If any slice is empty, it defaults to [selectors.None] -func (s *sharePoint) Libraries(libraries []string, opts ...option) []SharePointScope { +func (s *sharePoint) Library(library string) []SharePointScope { + return []SharePointScope{ + makeFilterScope[SharePointScope]( + SharePointLibraryItem, + SharePointFilterLibraryDrive, + []string{library}, + wrapFilter(filters.Equal)), + } +} + +// LibraryFolders produces one or more SharePoint libraryFolder scopes. +// If any slice contains selectors.Any, that slice is reduced to [selectors.Any] +// If any slice contains selectors.None, that slice is reduced to [selectors.None] +// If any slice is empty, it defaults to [selectors.None] +func (s *sharePoint) LibraryFolders(libraryFolders []string, opts ...option) []SharePointScope { var ( scopes = []SharePointScope{} os = append([]option{pathComparator()}, opts...) @@ -277,7 +294,7 @@ func (s *sharePoint) Libraries(libraries []string, opts ...option) []SharePointS scopes = append( scopes, - makeScope[SharePointScope](SharePointLibrary, libraries, os...), + makeScope[SharePointScope](SharePointLibraryFolder, libraryFolders, os...), ) return scopes @@ -294,7 +311,7 @@ func (s *sharePoint) LibraryItems(libraries, items []string, opts ...option) []S scopes = append( scopes, makeScope[SharePointScope](SharePointLibraryItem, items). - set(SharePointLibrary, libraries, opts...), + set(SharePointLibraryFolder, libraries, opts...), ) return scopes @@ -390,26 +407,29 @@ const ( SharePointCategoryUnknown sharePointCategory = "" // types of data identified by SharePoint - SharePointWebURL sharePointCategory = "SharePointWebURL" - SharePointSite sharePointCategory = "SharePointSite" - SharePointList sharePointCategory = "SharePointList" - SharePointListItem sharePointCategory = "SharePointListItem" - SharePointLibrary sharePointCategory = "SharePointLibrary" - SharePointLibraryItem sharePointCategory = "SharePointLibraryItem" - SharePointPageFolder sharePointCategory = "SharePointPageFolder" - SharePointPage sharePointCategory = "SharePointPage" + SharePointWebURL sharePointCategory = "SharePointWebURL" + SharePointSite sharePointCategory = "SharePointSite" + SharePointList sharePointCategory = "SharePointList" + SharePointListItem sharePointCategory = "SharePointListItem" + SharePointLibraryFolder sharePointCategory = "SharePointLibraryFolder" + SharePointLibraryItem sharePointCategory = "SharePointLibraryItem" + SharePointPageFolder sharePointCategory = "SharePointPageFolder" + SharePointPage sharePointCategory = "SharePointPage" // filterable topics identified by SharePoint SiteFilterCreatedAfter sharePointCategory = "FileFilterCreatedAfter" SiteFilterCreatedBefore sharePointCategory = "FileFilterCreatedBefore" SiteFilterModifiedAfter sharePointCategory = "FileFilterModifiedAfter" SiteFilterModifiedBefore sharePointCategory = "FileFilterModifiedBefore" + + // library drive selection + SharePointFilterLibraryDrive sharePointCategory = "SharePointFilterLibraryDrive" ) // sharePointLeafProperties describes common metadata of the leaf categories var sharePointLeafProperties = map[categorizer]leafProperty{ SharePointLibraryItem: { - pathKeys: []categorizer{SharePointLibrary, SharePointLibraryItem}, + pathKeys: []categorizer{SharePointLibraryFolder, SharePointLibraryItem}, pathType: path.LibrariesCategory, }, SharePointListItem: { @@ -437,7 +457,7 @@ func (c sharePointCategory) String() string { // Ex: ServiceUser.leafCat() => ServiceUser func (c sharePointCategory) leafCat() categorizer { switch c { - case SharePointLibrary, SharePointLibraryItem, + case SharePointLibraryFolder, SharePointLibraryItem, SharePointFilterLibraryDrive, SiteFilterCreatedAfter, SiteFilterCreatedBefore, SiteFilterModifiedAfter, SiteFilterModifiedBefore: return SharePointLibraryItem @@ -480,8 +500,8 @@ func (c sharePointCategory) pathValues(repo path.Path, ent details.DetailsEntry) var folderCat, itemCat categorizer switch c { - case SharePointLibrary, SharePointLibraryItem: - folderCat, itemCat = SharePointLibrary, SharePointLibraryItem + case SharePointLibraryFolder, SharePointLibraryItem: + folderCat, itemCat = SharePointLibraryFolder, SharePointLibraryItem case SharePointList, SharePointListItem: folderCat, itemCat = SharePointList, SharePointListItem case SharePointPage, SharePointPageFolder: @@ -572,7 +592,7 @@ func (s SharePointScope) set(cat sharePointCategory, v []string, opts ...option) os := []option{} switch cat { - case SharePointLibrary, SharePointList, SharePointPage: + case SharePointLibraryFolder, SharePointList, SharePointPage: os = append(os, pathComparator()) } @@ -583,13 +603,13 @@ func (s SharePointScope) set(cat sharePointCategory, v []string, opts ...option) func (s SharePointScope) setDefaults() { switch s.Category() { case SharePointSite: - s[SharePointLibrary.String()] = passAny + s[SharePointLibraryFolder.String()] = passAny s[SharePointLibraryItem.String()] = passAny s[SharePointList.String()] = passAny s[SharePointListItem.String()] = passAny s[SharePointPageFolder.String()] = passAny s[SharePointPage.String()] = passAny - case SharePointLibrary: + case SharePointLibraryFolder: s[SharePointLibraryItem.String()] = passAny case SharePointList: s[SharePointListItem.String()] = passAny @@ -647,6 +667,18 @@ func (s SharePointScope) matchesInfo(dii details.ItemInfo) bool { i = common.FormatTime(info.Created) case SiteFilterModifiedAfter, SiteFilterModifiedBefore: i = common.FormatTime(info.Modified) + case SharePointFilterLibraryDrive: + ds := []string{} + + if len(info.DriveName) > 0 { + ds = append(ds, info.DriveName) + } + + if len(info.DriveID) > 0 { + ds = append(ds, info.DriveID) + } + + return matchesAny(s, SharePointFilterLibraryDrive, ds) } return s.Matches(filterCat, i) diff --git a/src/pkg/selectors/sharepoint_test.go b/src/pkg/selectors/sharepoint_test.go index 7be9f90f4..812db2609 100644 --- a/src/pkg/selectors/sharepoint_test.go +++ b/src/pkg/selectors/sharepoint_test.go @@ -79,8 +79,8 @@ func (suite *SharePointSelectorSuite) TestSharePointSelector_AllData() { t, spsc, map[categorizer]string{ - SharePointLibraryItem: AnyTgt, - SharePointLibrary: AnyTgt, + SharePointLibraryItem: AnyTgt, + SharePointLibraryFolder: AnyTgt, }, ) case SharePointListItem: @@ -289,7 +289,7 @@ func (suite *SharePointSelectorSuite) TestSharePointRestore_Reduce() { deets: deets, makeSelector: func() *SharePointRestore { odr := NewSharePointRestore([]string{"sid"}) - odr.Include(odr.Libraries([]string{"folderA/folderB", pairAC})) + odr.Include(odr.LibraryFolders([]string{"folderA/folderB", pairAC})) return odr }, expect: arr(item, item2), @@ -330,8 +330,8 @@ func (suite *SharePointSelectorSuite) TestSharePointCategory_PathValues() { name: "SharePoint Libraries", sc: SharePointLibraryItem, expected: map[categorizer][]string{ - SharePointLibrary: {"dir1/dir2"}, - SharePointLibraryItem: {"item", "short"}, + SharePointLibraryFolder: {"dir1/dir2"}, + SharePointLibraryItem: {"item", "short"}, }, }, { @@ -370,7 +370,7 @@ func (suite *SharePointSelectorSuite) TestSharePointCategory_PathValues() { func (suite *SharePointSelectorSuite) TestSharePointScope_MatchesInfo() { var ( - ods = NewSharePointRestore(Any()) + sel = NewSharePointRestore(Any()) host = "www.website.com" pth = "/foo" url = host + pth @@ -386,29 +386,33 @@ func (suite *SharePointSelectorSuite) TestSharePointScope_MatchesInfo() { scope []SharePointScope expect assert.BoolAssertionFunc }{ - {"host match", host, ods.WebURL([]string{host}), assert.True}, - {"url match", url, ods.WebURL([]string{url}), assert.True}, - {"url contains host", url, ods.WebURL([]string{host}), assert.True}, - {"host suffixes host", host, ods.WebURL([]string{host}, SuffixMatch()), assert.True}, - {"url does not suffix host", url, ods.WebURL([]string{host}, SuffixMatch()), assert.False}, - {"url contains path", url, ods.WebURL([]string{pth}), assert.True}, - {"url has path suffix", url, ods.WebURL([]string{pth}, SuffixMatch()), assert.True}, - {"host does not contain substring", host, ods.WebURL([]string{"website"}), assert.False}, - {"url does not suffix substring", url, ods.WebURL([]string{"oo"}), assert.False}, - {"host mismatch", host, ods.WebURL([]string{"www.google.com"}), assert.False}, - {"file create after the epoch", host, ods.CreatedAfter(common.FormatTime(epoch)), assert.True}, - {"file create after now", host, ods.CreatedAfter(common.FormatTime(now)), assert.False}, - {"file create after later", url, ods.CreatedAfter(common.FormatTime(future)), assert.False}, - {"file create before future", host, ods.CreatedBefore(common.FormatTime(future)), assert.True}, - {"file create before now", host, ods.CreatedBefore(common.FormatTime(now)), assert.False}, - {"file create before modification", host, ods.CreatedBefore(common.FormatTime(modification)), assert.True}, - {"file create before epoch", host, ods.CreatedBefore(common.FormatTime(now)), assert.False}, - {"file modified after the epoch", host, ods.ModifiedAfter(common.FormatTime(epoch)), assert.True}, - {"file modified after now", host, ods.ModifiedAfter(common.FormatTime(now)), assert.True}, - {"file modified after later", host, ods.ModifiedAfter(common.FormatTime(future)), assert.False}, - {"file modified before future", host, ods.ModifiedBefore(common.FormatTime(future)), assert.True}, - {"file modified before now", host, ods.ModifiedBefore(common.FormatTime(now)), assert.False}, - {"file modified before epoch", host, ods.ModifiedBefore(common.FormatTime(now)), assert.False}, + {"host match", host, sel.WebURL([]string{host}), assert.True}, + {"url match", url, sel.WebURL([]string{url}), assert.True}, + {"url contains host", url, sel.WebURL([]string{host}), assert.True}, + {"host suffixes host", host, sel.WebURL([]string{host}, SuffixMatch()), assert.True}, + {"url does not suffix host", url, sel.WebURL([]string{host}, SuffixMatch()), assert.False}, + {"url contains path", url, sel.WebURL([]string{pth}), assert.True}, + {"url has path suffix", url, sel.WebURL([]string{pth}, SuffixMatch()), assert.True}, + {"host does not contain substring", host, sel.WebURL([]string{"website"}), assert.False}, + {"url does not suffix substring", url, sel.WebURL([]string{"oo"}), assert.False}, + {"host mismatch", host, sel.WebURL([]string{"www.google.com"}), assert.False}, + {"file create after the epoch", host, sel.CreatedAfter(common.FormatTime(epoch)), assert.True}, + {"file create after now", host, sel.CreatedAfter(common.FormatTime(now)), assert.False}, + {"file create after later", url, sel.CreatedAfter(common.FormatTime(future)), assert.False}, + {"file create before future", host, sel.CreatedBefore(common.FormatTime(future)), assert.True}, + {"file create before now", host, sel.CreatedBefore(common.FormatTime(now)), assert.False}, + {"file create before modification", host, sel.CreatedBefore(common.FormatTime(modification)), assert.True}, + {"file create before epoch", host, sel.CreatedBefore(common.FormatTime(now)), assert.False}, + {"file modified after the epoch", host, sel.ModifiedAfter(common.FormatTime(epoch)), assert.True}, + {"file modified after now", host, sel.ModifiedAfter(common.FormatTime(now)), assert.True}, + {"file modified after later", host, sel.ModifiedAfter(common.FormatTime(future)), assert.False}, + {"file modified before future", host, sel.ModifiedBefore(common.FormatTime(future)), assert.True}, + {"file modified before now", host, sel.ModifiedBefore(common.FormatTime(now)), assert.False}, + {"file modified before epoch", host, sel.ModifiedBefore(common.FormatTime(now)), assert.False}, + {"in library", host, sel.Library("included-library"), assert.True}, + {"not in library", host, sel.Library("not-included-library"), assert.False}, + {"library id", host, sel.Library("1234"), assert.True}, + {"not library id", host, sel.Library("abcd"), assert.False}, } for _, test := range table { suite.Run(test.name, func() { @@ -416,10 +420,12 @@ func (suite *SharePointSelectorSuite) TestSharePointScope_MatchesInfo() { itemInfo := details.ItemInfo{ SharePoint: &details.SharePointInfo{ - ItemType: details.SharePointPage, - WebURL: test.infoURL, - Created: now, - Modified: modification, + ItemType: details.SharePointPage, + WebURL: test.infoURL, + Created: now, + Modified: modification, + DriveName: "included-library", + DriveID: "1234", }, } @@ -439,7 +445,7 @@ func (suite *SharePointSelectorSuite) TestCategory_PathType() { {SharePointCategoryUnknown, path.UnknownCategory}, {SharePointWebURL, path.UnknownCategory}, {SharePointSite, path.UnknownCategory}, - {SharePointLibrary, path.LibrariesCategory}, + {SharePointLibraryFolder, path.LibrariesCategory}, {SharePointLibraryItem, path.LibrariesCategory}, {SharePointList, path.ListsCategory}, }