rename libraries -> libraryFolder (#2774)

The selector moniker "libraries" is incorrect.  It should refer to the library folder, since it only
matches on directory structures within a given
drive.  The 'library' is analogous to the drive
itself, and will need a separate selector of its
own.

---

#### Does this PR need a docs update or release note?

- [x]  No

#### Type of change

- [x] 🐛 Bugfix

#### Issue(s)

* #2757

#### Test Plan

- [x]  Unit test
- [x] 💚 E2E
This commit is contained in:
Keepers 2023-03-13 19:38:54 -06:00 committed by GitHub
parent 120eb0d256
commit 635e4f6bc4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
23 changed files with 391 additions and 345 deletions

View File

@ -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` --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. // called by backup.go to map subcommands to provider-specific handling.
func addOneDriveCommands(cmd *cobra.Command) *cobra.Command { func addOneDriveCommands(cmd *cobra.Command) *cobra.Command {
var ( var (
@ -103,14 +98,14 @@ func addOneDriveCommands(cmd *cobra.Command) *cobra.Command {
// onedrive hierarchy flags // onedrive hierarchy flags
fs.StringSliceVar( fs.StringSliceVar(
&folderPaths, &utils.FolderPaths,
utils.FolderFN, nil, utils.FolderFN, nil,
"Select backup details by OneDrive folder; defaults to root.") "Select backup details by OneDrive folder; defaults to root.")
fs.StringSliceVar( fs.StringSliceVar(
&fileNames, &utils.FileNames,
utils.FileFN, nil, utils.FileFN, nil,
"Select backup details by file name or ID.") "Select backup details by file name.")
// onedrive info flags // onedrive info flags
@ -263,8 +258,8 @@ func detailsOneDriveCmd(cmd *cobra.Command, args []string) error {
ctx := cmd.Context() ctx := cmd.Context()
opts := utils.OneDriveOpts{ opts := utils.OneDriveOpts{
Users: user, Users: user,
Names: fileNames, FileNames: utils.FileNames,
Paths: folderPaths, FolderPaths: utils.FolderPaths,
FileCreatedAfter: utils.FileCreatedAfter, FileCreatedAfter: utils.FileCreatedAfter,
FileCreatedBefore: utils.FileCreatedBefore, FileCreatedBefore: utils.FileCreatedBefore,
FileModifiedAfter: utils.FileModifiedAfter, FileModifiedAfter: utils.FileModifiedAfter,

View File

@ -26,12 +26,8 @@ import (
// sharePoint bucket info from flags // sharePoint bucket info from flags
var ( var (
libraryItems []string
libraryPaths []string
pageFolders []string pageFolders []string
page []string page []string
site []string
weburl []string
sharepointData []string sharepointData []string
) )
@ -43,34 +39,29 @@ const (
const ( const (
sharePointServiceCommand = "sharepoint" sharePointServiceCommand = "sharepoint"
sharePointServiceCommandCreateUseSuffix = "--site <siteId> | '" + utils.Wildcard + "'" sharePointServiceCommandCreateUseSuffix = "--web-url <siteURL> | '" + utils.Wildcard + "'"
sharePointServiceCommandDeleteUseSuffix = "--backup <backupId>" sharePointServiceCommandDeleteUseSuffix = "--backup <backupId>"
sharePointServiceCommandDetailsUseSuffix = "--backup <backupId>" sharePointServiceCommandDetailsUseSuffix = "--backup <backupId>"
) )
const ( const (
sharePointServiceCommandCreateExamples = `# Backup SharePoint data for <site> sharePointServiceCommandCreateExamples = `# Backup SharePoint data for a Site
corso backup create sharepoint --site <site_id> corso backup create sharepoint --web-url <siteURL>
# Backup SharePoint for Alice and Bob # Backup SharePoint for two sites: HR and Team
corso backup create sharepoint --site <site_id_1>,<site_id_2> 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 --web-url '*'`
# Backup all SharePoint data for all sites
corso backup create sharepoint --site '*'`
sharePointServiceCommandDeleteExamples = `# Delete SharePoint backup with ID 1234abcd-12ab-cd34-56de-1234abcd sharePointServiceCommandDeleteExamples = `# Delete SharePoint backup with ID 1234abcd-12ab-cd34-56de-1234abcd
corso backup delete sharepoint --backup 1234abcd-12ab-cd34-56de-1234abcd` corso backup delete sharepoint --backup 1234abcd-12ab-cd34-56de-1234abcd`
sharePointServiceCommandDetailsExamples = `# Explore <site>'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 <site_id>
<<<<<<< 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. # Find all site files that were created before a certain date.
>>>>>>> main
corso backup details sharepoint --backup 1234abcd-12ab-cd34-56de-1234abcd \ corso backup details sharepoint --backup 1234abcd-12ab-cd34-56de-1234abcd \
--web-url https://example.com --file-created-before 2015-01-01T00:00:00 --web-url https://example.com --file-created-before 2015-01-01T00:00:00
` `
@ -90,11 +81,13 @@ func addSharePointCommands(cmd *cobra.Command) *cobra.Command {
c.Use = c.Use + " " + sharePointServiceCommandCreateUseSuffix c.Use = c.Use + " " + sharePointServiceCommandCreateUseSuffix
c.Example = sharePointServiceCommandCreateExamples c.Example = sharePointServiceCommandCreateExamples
fs.StringArrayVar(&site, fs.StringArrayVar(
&utils.Site,
utils.SiteFN, nil, utils.SiteFN, nil,
"Backup SharePoint data by site ID; accepts '"+utils.Wildcard+"' to select all sites.") "Backup SharePoint data by site ID; accepts '"+utils.Wildcard+"' to select all sites.")
fs.StringSliceVar(&weburl, fs.StringSliceVar(
&utils.WebURL,
utils.WebURLFN, nil, utils.WebURLFN, nil,
"Restore data by site web URL; accepts '"+utils.Wildcard+"' to select all sites.") "Restore data by site web URL; accepts '"+utils.Wildcard+"' to select all sites.")
@ -126,21 +119,28 @@ func addSharePointCommands(cmd *cobra.Command) *cobra.Command {
// sharepoint hierarchy flags // sharepoint hierarchy flags
fs.StringSliceVar( fs.StringVar(
&libraryPaths, &utils.Library,
utils.LibraryFN, nil, utils.LibraryFN, "",
"Select backup details by Library name.") "Select backup details within a library. Defaults includes all libraries.")
fs.StringSliceVar( fs.StringSliceVar(
&libraryItems, &utils.FolderPaths,
utils.LibraryItemFN, nil, utils.FolderFN, nil,
"Select backup details by library item name or ID.") "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, utils.SiteFN, nil,
"Select backup details by site ID; accepts '"+utils.Wildcard+"' to select all sites.") "Select backup details by site ID; accepts '"+utils.Wildcard+"' to select all sites.")
fs.StringSliceVar(&weburl, fs.StringSliceVar(
&utils.WebURL,
utils.WebURLFN, nil, utils.WebURLFN, nil,
"Select backup data by site webURL; accepts '"+utils.Wildcard+"' to select all sites.") "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( fs.StringSliceVar(
&page, &page,
utils.PagesFN, nil, 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 // sharepoint info flags
fs.StringVar( fs.StringVar(
&utils.FileCreatedAfter, &utils.FileCreatedAfter,
utils.FileCreatedAfterFN, "", utils.FileCreatedAfterFN, "",
"Select backup details for items created after this datetime.") "Select backup details created after this datetime.")
fs.StringVar( fs.StringVar(
&utils.FileCreatedBefore, &utils.FileCreatedBefore,
utils.FileCreatedBeforeFN, "", utils.FileCreatedBeforeFN, "",
"Select backup details for files created before this datetime.") "Select backup details created before this datetime.")
fs.StringVar( fs.StringVar(
&utils.FileModifiedAfter, &utils.FileModifiedAfter,
utils.FileModifiedAfterFN, "", utils.FileModifiedAfterFN, "",
"Select backup details for files modified after this datetime.") "Select backup details modified after this datetime.")
fs.StringVar( fs.StringVar(
&utils.FileModifiedBefore, &utils.FileModifiedBefore,
utils.FileModifiedBeforeFN, "", utils.FileModifiedBeforeFN, "",
"Select backup details for files modified before this datetime.") "Select backup details modified before this datetime.")
case deleteCommand: case deleteCommand:
c, fs = utils.AddCommand(cmd, sharePointDeleteCmd(), utils.MarkPreReleaseCommand()) c, fs = utils.AddCommand(cmd, sharePointDeleteCmd(), utils.MarkPreReleaseCommand())
@ -214,7 +213,7 @@ func createSharePointCmd(cmd *cobra.Command, args []string) error {
return nil return nil
} }
if err := validateSharePointBackupCreateFlags(site, weburl, sharepointData); err != nil { if err := validateSharePointBackupCreateFlags(utils.Site, utils.WebURL, sharepointData); err != nil {
return err return err
} }
@ -233,7 +232,7 @@ func createSharePointCmd(cmd *cobra.Command, args []string) error {
return Only(ctx, errors.Wrap(err, "Failed to connect to Microsoft APIs")) 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 { if err != nil {
return Only(ctx, errors.Wrap(err, "Retrieving up sharepoint sites by ID and Web URL")) return Only(ctx, errors.Wrap(err, "Retrieving up sharepoint sites by ID and Web URL"))
} }
@ -319,13 +318,13 @@ func includeAllSitesWithCategories(categories []string) *selectors.SharePointBac
func addCategories(sel *selectors.SharePointBackup, cats []string) *selectors.SharePointBackup { func addCategories(sel *selectors.SharePointBackup, cats []string) *selectors.SharePointBackup {
// Issue #2631: Libraries are the only supported feature for SharePoint at this time. // Issue #2631: Libraries are the only supported feature for SharePoint at this time.
if len(cats) == 0 { if len(cats) == 0 {
sel.Include(sel.Libraries(selectors.Any())) sel.Include(sel.LibraryFolders(selectors.Any()))
} }
for _, d := range cats { for _, d := range cats {
switch d { switch d {
case dataLibraries: case dataLibraries:
sel.Include(sel.Libraries(selectors.Any())) sel.Include(sel.LibraryFolders(selectors.Any()))
case dataPages: case dataPages:
sel.Include(sel.Pages(selectors.Any())) sel.Include(sel.Pages(selectors.Any()))
} }
@ -396,10 +395,11 @@ func detailsSharePointCmd(cmd *cobra.Command, args []string) error {
ctx := cmd.Context() ctx := cmd.Context()
opts := utils.SharePointOpts{ opts := utils.SharePointOpts{
LibraryItems: libraryItems, FolderPaths: utils.FolderPaths,
LibraryPaths: libraryPaths, FileNames: utils.FileNames,
Sites: site, Library: utils.Library,
WebURLs: weburl, Sites: utils.Site,
WebURLs: utils.WebURL,
FileCreatedAfter: fileCreatedAfter, FileCreatedAfter: fileCreatedAfter,
FileCreatedBefore: fileCreatedBefore, FileCreatedBefore: fileCreatedBefore,
FileModifiedAfter: fileModifiedAfter, FileModifiedAfter: fileModifiedAfter,

View File

@ -161,7 +161,7 @@ func (suite *BackupDeleteSharePointE2ESuite) SetupSuite() {
// some tests require an existing backup // some tests require an existing backup
sel := selectors.NewSharePointBackup(sites) 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) suite.backupOp, err = suite.repo.NewBackup(ctx, sel.Selector)
require.NoError(t, suite.backupOp.Run(ctx)) require.NoError(t, suite.backupOp.Run(ctx))

View File

@ -133,8 +133,8 @@ func restoreOneDriveCmd(cmd *cobra.Command, args []string) error {
opts := utils.OneDriveOpts{ opts := utils.OneDriveOpts{
Users: user, Users: user,
Names: fileNames, FileNames: fileNames,
Paths: folderPaths, FolderPaths: folderPaths,
FileCreatedAfter: utils.FileCreatedAfter, FileCreatedAfter: utils.FileCreatedAfter,
FileCreatedBefore: utils.FileCreatedBefore, FileCreatedBefore: utils.FileCreatedBefore,
FileModifiedAfter: utils.FileModifiedAfter, FileModifiedAfter: utils.FileModifiedAfter,

View File

@ -20,10 +20,6 @@ var (
listPaths []string listPaths []string
pageFolders []string pageFolders []string
pages []string pages []string
libraryItems []string
libraryPaths []string
site []string
weburl []string
) )
// called by restore.go to map subcommands to provider-specific handling. // 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. // More generic (ex: --site) and more frequently used flags take precedence.
fs.SortFlags = false fs.SortFlags = false
fs.StringVar(&backupID, fs.StringVar(
&backupID,
utils.BackupFN, "", utils.BackupFN, "",
"ID of the backup to restore. (required)") "ID of the backup to restore. (required)")
cobra.CheckErr(c.MarkFlagRequired(utils.BackupFN)) cobra.CheckErr(c.MarkFlagRequired(utils.BackupFN))
fs.StringSliceVar(&site, fs.StringSliceVar(
&utils.Site,
utils.SiteFN, nil, utils.SiteFN, nil,
"Restore data by site ID; accepts '"+utils.Wildcard+"' to select all sites.") "Restore data by site ID; accepts '"+utils.Wildcard+"' to select all sites.")
fs.StringSliceVar(&weburl, fs.StringSliceVar(
&utils.WebURL,
utils.WebURLFN, nil, utils.WebURLFN, nil,
"Restore data by site webURL; accepts '"+utils.Wildcard+"' to select all sites.") "Restore data by site webURL; accepts '"+utils.Wildcard+"' to select all sites.")
// sharepoint hierarchy (path/name) flags // sharepoint hierarchy (path/name) flags
fs.StringSliceVar( fs.StringVar(
&libraryPaths, &utils.Library,
utils.LibraryFN, nil, utils.LibraryFN, "",
"Restore library items by SharePoint library") "Restore files within a library. Default includes all libraries.")
fs.StringSliceVar( fs.StringSliceVar(
&libraryItems, &utils.FolderPaths,
utils.LibraryItemFN, nil, utils.FolderFN, nil,
"Restore library items by file name or ID") "Restore files by folder; defaults to root.")
fs.StringSliceVar(
&utils.FileNames,
utils.FileFN, nil,
"Restore files by name.")
fs.StringSliceVar( fs.StringSliceVar(
&listPaths, &listPaths,
@ -81,21 +85,33 @@ func addSharePointCommands(cmd *cobra.Command) *cobra.Command {
fs.StringSliceVar( fs.StringSliceVar(
&pageFolders, &pageFolders,
utils.PageFolderFN, nil, utils.PageFolderFN, nil,
"Restore Site pages by page folder name", "Restore Site pages by page folder name")
)
fs.StringSliceVar( fs.StringSliceVar(
&pages, &pages,
utils.PagesFN, nil, utils.PagesFN, nil,
"Restore site pages by file name(s)", "Restore site pages by file name(s)")
)
// sharepoint info flags // sharepoint info flags
// fs.StringVar( fs.StringVar(
// &fileCreatedAfter, &utils.FileCreatedAfter,
// utils.FileCreatedAfterFN, "", utils.FileCreatedAfterFN, "",
// "Restore files created after this datetime") "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 // others
options.AddOperationFlags(c) options.AddOperationFlags(c)
@ -112,13 +128,13 @@ const (
sharePointServiceCommandRestoreExamples = `# Restore file with ID 98765abcdef sharePointServiceCommandRestoreExamples = `# Restore file with ID 98765abcdef
corso restore sharepoint --backup 1234abcd-12ab-cd34-56de-1234abcd --file 98765abcdef corso restore sharepoint --backup 1234abcd-12ab-cd34-56de-1234abcd --file 98765abcdef
# Restore <site>'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 \ corso restore sharepoint --backup 1234abcd-12ab-cd34-56de-1234abcd \
--site <siteID> --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 <site> 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 corso restore sharepoint --backup 1234abcd-12ab-cd34-56de-1234abcd
--site <siteID> --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 [<flag>...]` // `corso restore sharepoint [<flag>...]`
@ -141,14 +157,15 @@ func restoreSharePointCmd(cmd *cobra.Command, args []string) error {
} }
opts := utils.SharePointOpts{ opts := utils.SharePointOpts{
LibraryItems: libraryItems, FileNames: utils.FileNames,
LibraryPaths: libraryPaths, FolderPaths: utils.FolderPaths,
Library: utils.Library,
ListItems: listItems, ListItems: listItems,
ListPaths: listPaths, ListPaths: listPaths,
PageFolders: pageFolders, PageFolders: pageFolders,
Pages: pages, Pages: pages,
Sites: site, Sites: utils.Site,
WebURLs: weburl, WebURLs: utils.WebURL,
FileCreatedAfter: utils.FileCreatedAfter, FileCreatedAfter: utils.FileCreatedAfter,
FileCreatedBefore: utils.FileCreatedBefore, FileCreatedBefore: utils.FileCreatedBefore,
FileModifiedAfter: utils.FileModifiedAfter, FileModifiedAfter: utils.FileModifiedAfter,

View File

@ -10,18 +10,37 @@ import (
"github.com/alcionai/corso/src/pkg/path" "github.com/alcionai/corso/src/pkg/path"
) )
// ============================================== // common flag vars
// 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
// ================================================
var ( var (
FolderPaths []string
FileNames []string
FileCreatedAfter string FileCreatedAfter string
FileCreatedBefore string FileCreatedBefore string
FileModifiedAfter string FileModifiedAfter string
FileModifiedBefore 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{} type PopulatedFlags map[string]struct{}

View File

@ -6,17 +6,10 @@ import (
"github.com/alcionai/corso/src/pkg/selectors" "github.com/alcionai/corso/src/pkg/selectors"
) )
const (
FileFN = "file"
FolderFN = "folder"
NamesFN = "name"
PathsFN = "path"
)
type OneDriveOpts struct { type OneDriveOpts struct {
Users []string Users []string
Names []string FileNames []string
Paths []string FolderPaths []string
FileCreatedAfter string FileCreatedAfter string
FileCreatedBefore string FileCreatedBefore string
FileModifiedAfter string FileModifiedAfter string
@ -74,7 +67,7 @@ func IncludeOneDriveRestoreDataSelectors(opts OneDriveOpts) *selectors.OneDriveR
sel := selectors.NewOneDriveRestore(users) 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 // only use the inclusion if either a path or item name
// is specified // is specified
@ -83,20 +76,20 @@ func IncludeOneDriveRestoreDataSelectors(opts OneDriveOpts) *selectors.OneDriveR
return sel return sel
} }
opts.Paths = trimFolderSlash(opts.Paths) opts.FolderPaths = trimFolderSlash(opts.FolderPaths)
if ln == 0 { 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 { if len(containsFolders) > 0 {
sel.Include(sel.Items(containsFolders, opts.Names)) sel.Include(sel.Items(containsFolders, opts.FileNames))
} }
if len(prefixFolders) > 0 { if len(prefixFolders) > 0 {
sel.Include(sel.Items(prefixFolders, opts.Names, selectors.PrefixMatch())) sel.Include(sel.Items(prefixFolders, opts.FileNames, selectors.PrefixMatch()))
} }
return sel return sel

View File

@ -37,8 +37,8 @@ func (suite *OneDriveUtilsSuite) TestIncludeOneDriveRestoreDataSelectors() {
name: "no inputs", name: "no inputs",
opts: utils.OneDriveOpts{ opts: utils.OneDriveOpts{
Users: empty, Users: empty,
Paths: empty, FileNames: empty,
Names: empty, FolderPaths: empty,
}, },
expectIncludeLen: 1, expectIncludeLen: 1,
}, },
@ -46,8 +46,8 @@ func (suite *OneDriveUtilsSuite) TestIncludeOneDriveRestoreDataSelectors() {
name: "single inputs", name: "single inputs",
opts: utils.OneDriveOpts{ opts: utils.OneDriveOpts{
Users: single, Users: single,
Paths: single, FileNames: single,
Names: single, FolderPaths: single,
}, },
expectIncludeLen: 1, expectIncludeLen: 1,
}, },
@ -55,8 +55,8 @@ func (suite *OneDriveUtilsSuite) TestIncludeOneDriveRestoreDataSelectors() {
name: "multi inputs", name: "multi inputs",
opts: utils.OneDriveOpts{ opts: utils.OneDriveOpts{
Users: multi, Users: multi,
Paths: multi, FileNames: multi,
Names: multi, FolderPaths: multi,
}, },
expectIncludeLen: 1, expectIncludeLen: 1,
}, },
@ -64,8 +64,8 @@ func (suite *OneDriveUtilsSuite) TestIncludeOneDriveRestoreDataSelectors() {
name: "folder contains", name: "folder contains",
opts: utils.OneDriveOpts{ opts: utils.OneDriveOpts{
Users: empty, Users: empty,
Paths: containsOnly, FileNames: empty,
Names: empty, FolderPaths: containsOnly,
}, },
expectIncludeLen: 1, expectIncludeLen: 1,
}, },
@ -73,8 +73,8 @@ func (suite *OneDriveUtilsSuite) TestIncludeOneDriveRestoreDataSelectors() {
name: "folder prefixes", name: "folder prefixes",
opts: utils.OneDriveOpts{ opts: utils.OneDriveOpts{
Users: empty, Users: empty,
Paths: prefixOnly, FileNames: empty,
Names: empty, FolderPaths: prefixOnly,
}, },
expectIncludeLen: 1, expectIncludeLen: 1,
}, },
@ -82,8 +82,8 @@ func (suite *OneDriveUtilsSuite) TestIncludeOneDriveRestoreDataSelectors() {
name: "folder prefixes and contains", name: "folder prefixes and contains",
opts: utils.OneDriveOpts{ opts: utils.OneDriveOpts{
Users: empty, Users: empty,
Paths: containsAndPrefix, FileNames: empty,
Names: empty, FolderPaths: containsAndPrefix,
}, },
expectIncludeLen: 2, expectIncludeLen: 2,
}, },

View File

@ -8,18 +8,16 @@ import (
) )
const ( const (
LibraryItemFN = "library-item"
LibraryFN = "library"
ListItemFN = "list-item" ListItemFN = "list-item"
ListFN = "list" ListFN = "list"
PageFolderFN = "page-folders" PageFolderFN = "page-folders"
PagesFN = "pages" PagesFN = "pages"
WebURLFN = "web-url"
) )
type SharePointOpts struct { type SharePointOpts struct {
LibraryItems []string FileNames []string // for libraries, to duplicate onedrive interface
LibraryPaths []string FolderPaths []string // for libraries, to duplicate onedrive interface
Library string
ListItems []string ListItems []string
ListPaths []string ListPaths []string
PageFolders []string PageFolders []string
@ -79,7 +77,7 @@ func AddSharePointFilter(
func IncludeSharePointRestoreDataSelectors(opts SharePointOpts) *selectors.SharePointRestore { func IncludeSharePointRestoreDataSelectors(opts SharePointOpts) *selectors.SharePointRestore {
sites := opts.Sites 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) ls, lwu := len(opts.Sites), len(opts.WebURLs)
slp, sli := len(opts.ListPaths), len(opts.ListItems) slp, sli := len(opts.ListPaths), len(opts.ListItems)
pf, pi := len(opts.PageFolders), len(opts.Pages) pf, pi := len(opts.PageFolders), len(opts.Pages)
@ -90,25 +88,25 @@ func IncludeSharePointRestoreDataSelectors(opts SharePointOpts) *selectors.Share
sel := selectors.NewSharePointRestore(sites) 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()) sel.Include(sel.AllData())
return sel return sel
} }
if lp+li > 0 { if lfp+lfn > 0 {
if li == 0 { if lfn == 0 {
opts.LibraryItems = selectors.Any() opts.FileNames = selectors.Any()
} }
opts.LibraryPaths = trimFolderSlash(opts.LibraryPaths) opts.FolderPaths = trimFolderSlash(opts.FolderPaths)
containsFolders, prefixFolders := splitFoldersIntoContainsAndPrefix(opts.LibraryPaths) containsFolders, prefixFolders := splitFoldersIntoContainsAndPrefix(opts.FolderPaths)
if len(containsFolders) > 0 { if len(containsFolders) > 0 {
sel.Include(sel.LibraryItems(containsFolders, opts.LibraryItems)) sel.Include(sel.LibraryItems(containsFolders, opts.FileNames))
} }
if len(prefixFolders) > 0 { 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, sel *selectors.SharePointRestore,
opts SharePointOpts, opts SharePointOpts,
) { ) {
AddSharePointFilter(sel, opts.Library, sel.Library)
AddSharePointFilter(sel, opts.FileCreatedAfter, sel.CreatedAfter) AddSharePointFilter(sel, opts.FileCreatedAfter, sel.CreatedAfter)
AddSharePointFilter(sel, opts.FileCreatedBefore, sel.CreatedBefore) AddSharePointFilter(sel, opts.FileCreatedBefore, sel.CreatedBefore)
AddSharePointFilter(sel, opts.FileModifiedAfter, sel.ModifiedAfter) AddSharePointFilter(sel, opts.FileModifiedAfter, sel.ModifiedAfter)

View File

@ -43,8 +43,8 @@ func (suite *SharePointUtilsSuite) TestIncludeSharePointRestoreDataSelectors() {
{ {
name: "single inputs", name: "single inputs",
opts: utils.SharePointOpts{ opts: utils.SharePointOpts{
LibraryItems: single, FileNames: single,
LibraryPaths: single, FolderPaths: single,
Sites: single, Sites: single,
WebURLs: single, WebURLs: single,
}, },
@ -53,8 +53,8 @@ func (suite *SharePointUtilsSuite) TestIncludeSharePointRestoreDataSelectors() {
{ {
name: "single extended", name: "single extended",
opts: utils.SharePointOpts{ opts: utils.SharePointOpts{
LibraryItems: single, FileNames: single,
LibraryPaths: single, FolderPaths: single,
ListItems: single, ListItems: single,
ListPaths: single, ListPaths: single,
Sites: single, Sites: single,
@ -65,38 +65,38 @@ func (suite *SharePointUtilsSuite) TestIncludeSharePointRestoreDataSelectors() {
{ {
name: "multi inputs", name: "multi inputs",
opts: utils.SharePointOpts{ opts: utils.SharePointOpts{
LibraryItems: multi, FileNames: multi,
LibraryPaths: multi, FolderPaths: multi,
Sites: multi, Sites: multi,
WebURLs: multi, WebURLs: multi,
}, },
expectIncludeLen: 4, expectIncludeLen: 4,
}, },
{ {
name: "library contains", name: "library folder contains",
opts: utils.SharePointOpts{ opts: utils.SharePointOpts{
LibraryItems: empty, FileNames: empty,
LibraryPaths: containsOnly, FolderPaths: containsOnly,
Sites: empty, Sites: empty,
WebURLs: empty, WebURLs: empty,
}, },
expectIncludeLen: 1, expectIncludeLen: 1,
}, },
{ {
name: "library prefixes", name: "library folder prefixes",
opts: utils.SharePointOpts{ opts: utils.SharePointOpts{
LibraryItems: empty, FileNames: empty,
LibraryPaths: prefixOnly, FolderPaths: prefixOnly,
Sites: empty, Sites: empty,
WebURLs: empty, WebURLs: empty,
}, },
expectIncludeLen: 1, expectIncludeLen: 1,
}, },
{ {
name: "library prefixes and contains", name: "library folder prefixes and contains",
opts: utils.SharePointOpts{ opts: utils.SharePointOpts{
LibraryItems: empty, FileNames: empty,
LibraryPaths: containsAndPrefix, FolderPaths: containsAndPrefix,
Sites: empty, Sites: empty,
WebURLs: empty, WebURLs: empty,
}, },
@ -105,8 +105,8 @@ func (suite *SharePointUtilsSuite) TestIncludeSharePointRestoreDataSelectors() {
{ {
name: "list contains", name: "list contains",
opts: utils.SharePointOpts{ opts: utils.SharePointOpts{
LibraryItems: empty, FileNames: empty,
LibraryPaths: empty, FolderPaths: empty,
ListItems: empty, ListItems: empty,
ListPaths: containsOnly, ListPaths: containsOnly,
Sites: empty, Sites: empty,
@ -131,28 +131,28 @@ func (suite *SharePointUtilsSuite) TestIncludeSharePointRestoreDataSelectors() {
{ {
name: "weburl contains", name: "weburl contains",
opts: utils.SharePointOpts{ opts: utils.SharePointOpts{
LibraryItems: empty, FileNames: empty,
LibraryPaths: empty, FolderPaths: empty,
Sites: empty, Sites: empty,
WebURLs: containsOnly, WebURLs: containsOnly,
}, },
expectIncludeLen: 3, expectIncludeLen: 3,
}, },
{ {
name: "library suffixes", name: "library folder suffixes",
opts: utils.SharePointOpts{ opts: utils.SharePointOpts{
LibraryItems: empty, FileNames: empty,
LibraryPaths: empty, FolderPaths: empty,
Sites: empty, Sites: empty,
WebURLs: prefixOnly, // prefix pattern matches suffix pattern WebURLs: prefixOnly, // prefix pattern matches suffix pattern
}, },
expectIncludeLen: 3, expectIncludeLen: 3,
}, },
{ {
name: "library suffixes and contains", name: "library folder suffixes and contains",
opts: utils.SharePointOpts{ opts: utils.SharePointOpts{
LibraryItems: empty, FileNames: empty,
LibraryPaths: empty, FolderPaths: empty,
Sites: empty, Sites: empty,
WebURLs: containsAndPrefix, // prefix pattern matches suffix pattern WebURLs: containsAndPrefix, // prefix pattern matches suffix pattern
}, },
@ -173,10 +173,10 @@ func (suite *SharePointUtilsSuite) TestIncludeSharePointRestoreDataSelectors() {
expectIncludeLen: 1, expectIncludeLen: 1,
}, },
{ {
name: "Page & Library", name: "Page & library Files",
opts: utils.SharePointOpts{ opts: utils.SharePointOpts{
PageFolders: single, PageFolders: single,
LibraryItems: multi, FileNames: multi,
}, },
expectIncludeLen: 2, expectIncludeLen: 2,
}, },

View File

@ -350,28 +350,28 @@ var (
Name: "AllFiles", Name: "AllFiles",
Expected: testdata.OneDriveItems, Expected: testdata.OneDriveItems,
Opts: utils.OneDriveOpts{ Opts: utils.OneDriveOpts{
Paths: selectors.Any(), FolderPaths: selectors.Any(),
}, },
}, },
{ {
Name: "FolderPrefixMatch", Name: "FolderPrefixMatch",
Expected: testdata.OneDriveItems, Expected: testdata.OneDriveItems,
Opts: utils.OneDriveOpts{ Opts: utils.OneDriveOpts{
Paths: []string{testdata.OneDriveFolderFolder}, FolderPaths: []string{testdata.OneDriveFolderFolder},
}, },
}, },
{ {
Name: "FolderPrefixMatchTrailingSlash", Name: "FolderPrefixMatchTrailingSlash",
Expected: testdata.OneDriveItems, Expected: testdata.OneDriveItems,
Opts: utils.OneDriveOpts{ Opts: utils.OneDriveOpts{
Paths: []string{testdata.OneDriveFolderFolder + "/"}, FolderPaths: []string{testdata.OneDriveFolderFolder + "/"},
}, },
}, },
{ {
Name: "FolderPrefixMatchTrailingSlash", Name: "FolderPrefixMatchTrailingSlash",
Expected: testdata.OneDriveItems, Expected: testdata.OneDriveItems,
Opts: utils.OneDriveOpts{ Opts: utils.OneDriveOpts{
Paths: []string{testdata.OneDriveFolderFolder + "/"}, FolderPaths: []string{testdata.OneDriveFolderFolder + "/"},
}, },
}, },
{ {
@ -381,7 +381,7 @@ var (
testdata.OneDriveItems[1], testdata.OneDriveItems[1],
}, },
Opts: utils.OneDriveOpts{ Opts: utils.OneDriveOpts{
Names: []string{ FileNames: []string{
testdata.OneDriveItems[0].ShortRef, testdata.OneDriveItems[0].ShortRef,
testdata.OneDriveItems[1].ShortRef, testdata.OneDriveItems[1].ShortRef,
}, },
@ -438,28 +438,28 @@ var (
Name: "AllLibraryItems", Name: "AllLibraryItems",
Expected: testdata.SharePointLibraryItems, Expected: testdata.SharePointLibraryItems,
Opts: utils.SharePointOpts{ Opts: utils.SharePointOpts{
LibraryPaths: selectors.Any(), FolderPaths: selectors.Any(),
}, },
}, },
{ {
Name: "FolderPrefixMatch", Name: "FolderPrefixMatch",
Expected: testdata.SharePointLibraryItems, Expected: testdata.SharePointLibraryItems,
Opts: utils.SharePointOpts{ Opts: utils.SharePointOpts{
LibraryPaths: []string{testdata.SharePointLibraryFolder}, FolderPaths: []string{testdata.SharePointLibraryFolder},
}, },
}, },
{ {
Name: "FolderPrefixMatchTrailingSlash", Name: "FolderPrefixMatchTrailingSlash",
Expected: testdata.SharePointLibraryItems, Expected: testdata.SharePointLibraryItems,
Opts: utils.SharePointOpts{ Opts: utils.SharePointOpts{
LibraryPaths: []string{testdata.SharePointLibraryFolder + "/"}, FolderPaths: []string{testdata.SharePointLibraryFolder + "/"},
}, },
}, },
{ {
Name: "FolderPrefixMatchTrailingSlash", Name: "FolderPrefixMatchTrailingSlash",
Expected: testdata.SharePointLibraryItems, Expected: testdata.SharePointLibraryItems,
Opts: utils.SharePointOpts{ Opts: utils.SharePointOpts{
LibraryPaths: []string{testdata.SharePointLibraryFolder + "/"}, FolderPaths: []string{testdata.SharePointLibraryFolder + "/"},
}, },
}, },
{ {
@ -469,7 +469,7 @@ var (
testdata.SharePointLibraryItems[1], testdata.SharePointLibraryItems[1],
}, },
Opts: utils.SharePointOpts{ Opts: utils.SharePointOpts{
LibraryItems: []string{ FileNames: []string{
testdata.SharePointLibraryItems[0].ShortRef, testdata.SharePointLibraryItems[0].ShortRef,
testdata.SharePointLibraryItems[1].ShortRef, testdata.SharePointLibraryItems[1].ShortRef,
}, },

View File

@ -17,18 +17,6 @@ import (
"github.com/alcionai/corso/src/pkg/storage" "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 ( const (
Wildcard = "*" Wildcard = "*"
) )

View File

@ -168,7 +168,7 @@ func (suite *ConnectorDataCollectionIntegrationSuite) TestDataCollections_invali
name: "Invalid sharepoint backup site", name: "Invalid sharepoint backup site",
getSelector: func(t *testing.T) selectors.Selector { getSelector: func(t *testing.T) selectors.Selector {
sel := selectors.NewSharePointBackup(owners) sel := selectors.NewSharePointBackup(owners)
sel.Include(sel.Libraries(selectors.Any())) sel.Include(sel.LibraryFolders(selectors.Any()))
return sel.Selector return sel.Selector
}, },
}, },
@ -194,7 +194,7 @@ func (suite *ConnectorDataCollectionIntegrationSuite) TestDataCollections_invali
name: "missing sharepoint backup site", name: "missing sharepoint backup site",
getSelector: func(t *testing.T) selectors.Selector { getSelector: func(t *testing.T) selectors.Selector {
sel := selectors.NewSharePointBackup(owners) sel := selectors.NewSharePointBackup(owners)
sel.Include(sel.Libraries(selectors.Any())) sel.Include(sel.LibraryFolders(selectors.Any()))
sel.DiscreteOwner = "" sel.DiscreteOwner = ""
return sel.Selector return sel.Selector
}, },
@ -237,7 +237,7 @@ func (suite *ConnectorDataCollectionIntegrationSuite) TestSharePointDataCollecti
name: "Libraries", name: "Libraries",
getSelector: func() selectors.Selector { getSelector: func() selectors.Selector {
sel := selectors.NewSharePointBackup(selSites) sel := selectors.NewSharePointBackup(selSites)
sel.Include(sel.Libraries(selectors.Any())) sel.Include(sel.LibraryFolders(selectors.Any()))
return sel.Selector return sel.Selector
}, },
}, },
@ -334,7 +334,7 @@ func (suite *ConnectorCreateSharePointCollectionIntegrationSuite) TestCreateShar
) )
sel := selectors.NewSharePointBackup(siteIDs) 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( cols, excludes, err := gc.DataCollections(
ctx, ctx,

View File

@ -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, // doesn't have its size value updated as a side effect of creation,
// and kiota drops any SetSize update. // and kiota drops any SetSize update.
func oneDriveItemInfo(di models.DriveItemable, itemSize int64) *details.OneDriveInfo { 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 { if di.GetCreatedBy() != nil && di.GetCreatedBy().GetUser() != nil {
// User is sometimes not available when created via some // 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 { if di.GetParentReference() != nil {
// EndPoint is not always populated from external apps driveID = ptr.Val(di.GetParentReference().GetDriveId())
parent = *di.GetParentReference().GetName() driveName = strings.TrimSpace(ptr.Val(di.GetParentReference().GetName()))
} }
return &details.OneDriveInfo{ return &details.OneDriveInfo{
ItemType: details.OneDriveItem,
ItemName: ptr.Val(di.GetName()),
Created: ptr.Val(di.GetCreatedDateTime()), Created: ptr.Val(di.GetCreatedDateTime()),
DriveID: driveID,
DriveName: driveName,
ItemName: ptr.Val(di.GetName()),
ItemType: details.OneDriveItem,
Modified: ptr.Val(di.GetLastModifiedDateTime()), Modified: ptr.Val(di.GetLastModifiedDateTime()),
DriveName: parent,
Size: itemSize,
Owner: email, Owner: email,
Size: itemSize,
} }
} }
@ -311,10 +312,7 @@ func filterUserPermissions(ctx context.Context, perms []models.Permissionable) [
// and kiota drops any SetSize update. // and kiota drops any SetSize update.
// TODO: Update drive name during Issue #2071 // TODO: Update drive name during Issue #2071
func sharePointItemInfo(di models.DriveItemable, itemSize int64) *details.SharePointInfo { func sharePointItemInfo(di models.DriveItemable, itemSize int64) *details.SharePointInfo {
var ( var id, driveName, driveID, weburl string
id, parentID, displayName, url string
reference = di.GetParentReference()
)
// TODO: we rely on this info for details/restore lookups, // TODO: we rely on this info for details/restore lookups,
// so if it's nil we have an issue, and will need an alternative // so if it's nil we have an issue, and will need an alternative
@ -323,16 +321,16 @@ func sharePointItemInfo(di models.DriveItemable, itemSize int64) *details.ShareP
gsi := di.GetSharepointIds() gsi := di.GetSharepointIds()
if gsi != nil { if gsi != nil {
id = ptr.Val(gsi.GetSiteId()) id = ptr.Val(gsi.GetSiteId())
url = ptr.Val(gsi.GetSiteUrl()) weburl = ptr.Val(gsi.GetSiteUrl())
if len(url) == 0 { if len(weburl) == 0 {
url = constructWebURL(di.GetAdditionalData()) weburl = constructWebURL(di.GetAdditionalData())
} }
} }
if reference != nil { if di.GetParentReference() != nil {
parentID = ptr.Val(reference.GetDriveId()) driveID = ptr.Val(di.GetParentReference().GetDriveId())
displayName = strings.TrimSpace(ptr.Val(reference.GetName())) driveName = strings.TrimSpace(ptr.Val(di.GetParentReference().GetName()))
} }
return &details.SharePointInfo{ return &details.SharePointInfo{
@ -340,11 +338,11 @@ func sharePointItemInfo(di models.DriveItemable, itemSize int64) *details.ShareP
ItemName: ptr.Val(di.GetName()), ItemName: ptr.Val(di.GetName()),
Created: ptr.Val(di.GetCreatedDateTime()), Created: ptr.Val(di.GetCreatedDateTime()),
Modified: ptr.Val(di.GetLastModifiedDateTime()), Modified: ptr.Val(di.GetLastModifiedDateTime()),
DriveName: parentID, DriveID: driveID,
DisplayName: displayName, DriveName: driveName,
Size: itemSize, Size: itemSize,
Owner: id, Owner: id,
WebURL: url, WebURL: weburl,
} }
} }

View File

@ -261,9 +261,9 @@ type folderMatcher struct {
} }
func (fm folderMatcher) IsAny() bool { func (fm folderMatcher) IsAny() bool {
return fm.scope.IsAny(selectors.SharePointLibrary) return fm.scope.IsAny(selectors.SharePointLibraryFolder)
} }
func (fm folderMatcher) Matches(dir string) bool { func (fm folderMatcher) Matches(dir string) bool {
return fm.scope.Matches(selectors.SharePointLibrary, dir) return fm.scope.Matches(selectors.SharePointLibraryFolder, dir)
} }

View File

@ -29,11 +29,11 @@ type testFolderMatcher struct {
} }
func (fm testFolderMatcher) IsAny() bool { func (fm testFolderMatcher) IsAny() bool {
return fm.scope.IsAny(selectors.SharePointLibrary) return fm.scope.IsAny(selectors.SharePointLibraryFolder)
} }
func (fm testFolderMatcher) Matches(path string) bool { 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() { func (suite *SharePointLibrariesUnitSuite) TestUpdateCollections() {
anyFolder := (&selectors.SharePointBackup{}).Libraries(selectors.Any())[0] anyFolder := (&selectors.SharePointBackup{}).LibraryFolders(selectors.Any())[0]
const ( const (
tenant = "tenant" tenant = "tenant"

View File

@ -1101,7 +1101,7 @@ func (suite *BackupOpIntegrationSuite) TestBackup_Run_sharePoint() {
sel = selectors.NewSharePointBackup([]string{suite.site}) 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{}) bo, _, kw, _, closer := prepNewTestBackupOp(t, ctx, mb, sel.Selector, control.Toggles{})
defer closer() defer closer()

View File

@ -219,9 +219,7 @@ func (suite *RestoreOpIntegrationSuite) SetupSuite() {
sites := []string{siteID} sites := []string{siteID}
csel := selectors.NewSharePointBackup(sites) csel := selectors.NewSharePointBackup(sites)
csel.DiscreteOwner = siteID csel.DiscreteOwner = siteID
csel.Include( csel.Include(csel.LibraryFolders(selectors.Any()))
csel.Libraries(selectors.Any()),
)
bo, err = NewBackupOperation( bo, err = NewBackupOperation(
ctx, ctx,

View File

@ -600,9 +600,9 @@ func (i ExchangeInfo) Values() []string {
// SharePointInfo describes a sharepoint item // SharePointInfo describes a sharepoint item
type SharePointInfo struct { type SharePointInfo struct {
Created time.Time `json:"created,omitempty"` Created time.Time `json:"created,omitempty"`
ItemName string `json:"itemName,omitempty"`
DriveName string `json:"driveName,omitempty"` DriveName string `json:"driveName,omitempty"`
DisplayName string `json:"displayName,omitempty"` DriveID string `json:"driveID,omitempty"`
ItemName string `json:"itemName,omitempty"`
ItemType ItemType `json:"itemType,omitempty"` ItemType ItemType `json:"itemType,omitempty"`
Modified time.Time `josn:"modified,omitempty"` Modified time.Time `josn:"modified,omitempty"`
Owner string `json:"owner,omitempty"` Owner string `json:"owner,omitempty"`
@ -614,7 +614,7 @@ type SharePointInfo struct {
// Headers returns the human-readable names of properties in a SharePointInfo // Headers returns the human-readable names of properties in a SharePointInfo
// for printing out to a terminal in a columnar display. // for printing out to a terminal in a columnar display.
func (i SharePointInfo) Headers() []string { 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 // Values returns the values matching the Headers list for printing
@ -622,7 +622,7 @@ func (i SharePointInfo) Headers() []string {
func (i SharePointInfo) Values() []string { func (i SharePointInfo) Values() []string {
return []string{ return []string{
i.ItemName, i.ItemName,
i.DisplayName, i.DriveName,
i.ParentPath, i.ParentPath,
humanize.Bytes(uint64(i.Size)), humanize.Bytes(uint64(i.Size)),
i.WebURL, i.WebURL,
@ -645,10 +645,11 @@ func (i *SharePointInfo) UpdateParentPath(newPath path.Path) error {
// OneDriveInfo describes a oneDrive item // OneDriveInfo describes a oneDrive item
type OneDriveInfo struct { type OneDriveInfo struct {
Created time.Time `json:"created,omitempty"` Created time.Time `json:"created,omitempty"`
ItemName string `json:"itemName,omitempty"` DriveID string `json:"driveID,omitempty"`
DriveName string `json:"driveName,omitempty"` DriveName string `json:"driveName,omitempty"`
ItemType ItemType `json:"itemType,omitempty"`
IsMeta bool `json:"isMeta,omitempty"` IsMeta bool `json:"isMeta,omitempty"`
ItemName string `json:"itemName,omitempty"`
ItemType ItemType `json:"itemType,omitempty"`
Modified time.Time `json:"modified,omitempty"` Modified time.Time `json:"modified,omitempty"`
Owner string `json:"owner,omitempty"` Owner string `json:"owner,omitempty"`
ParentPath string `json:"parentPath"` ParentPath string `json:"parentPath"`

View File

@ -117,17 +117,17 @@ func (suite *DetailsUnitSuite) TestDetailsEntry_HeadersValues() {
ParentPath: "parentPath", ParentPath: "parentPath",
Size: 1000, Size: 1000,
WebURL: "https://not.a.real/url", WebURL: "https://not.a.real/url",
DisplayName: "aDrive", DriveName: "aLibrary",
Created: now, Created: now,
Modified: 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{ expectVs: []string{
"deadbeef", "deadbeef",
"itemName", "itemName",
"aDrive", "aLibrary",
"parentPath", "parentPath",
"1.0 kB", "1.0 kB",
"https://not.a.real/url", "https://not.a.real/url",

View File

@ -346,7 +346,7 @@ func (suite *SelectorSuite) TestPathCategories_includes() {
isErr: assert.NoError, isErr: assert.NoError,
getSelector: func(t *testing.T) *Selector { getSelector: func(t *testing.T) *Selector {
sel := NewSharePointBackup(users) sel := NewSharePointBackup(users)
sel.Include(sel.Libraries([]string{"A directory"}, SuffixMatch())) sel.Include(sel.LibraryFolders([]string{"A directory"}, SuffixMatch()))
return &sel.Selector return &sel.Selector
}, },

View File

@ -225,7 +225,7 @@ func (s *sharePoint) AllData() []SharePointScope {
scopes = append( scopes = append(
scopes, scopes,
makeScope[SharePointScope](SharePointLibrary, Any()), makeScope[SharePointScope](SharePointLibraryFolder, Any()),
makeScope[SharePointScope](SharePointList, Any()), makeScope[SharePointScope](SharePointList, Any()),
makeScope[SharePointScope](SharePointPageFolder, Any()), makeScope[SharePointScope](SharePointPageFolder, Any()),
) )
@ -265,11 +265,28 @@ func (s *sharePoint) ListItems(lists, items []string, opts ...option) []SharePoi
return scopes 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.Any, that slice is reduced to [selectors.Any]
// If any slice contains selectors.None, that slice is reduced to [selectors.None] // If any slice contains selectors.None, that slice is reduced to [selectors.None]
// If any slice is empty, it defaults 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 ( var (
scopes = []SharePointScope{} scopes = []SharePointScope{}
os = append([]option{pathComparator()}, opts...) os = append([]option{pathComparator()}, opts...)
@ -277,7 +294,7 @@ func (s *sharePoint) Libraries(libraries []string, opts ...option) []SharePointS
scopes = append( scopes = append(
scopes, scopes,
makeScope[SharePointScope](SharePointLibrary, libraries, os...), makeScope[SharePointScope](SharePointLibraryFolder, libraryFolders, os...),
) )
return scopes return scopes
@ -294,7 +311,7 @@ func (s *sharePoint) LibraryItems(libraries, items []string, opts ...option) []S
scopes = append( scopes = append(
scopes, scopes,
makeScope[SharePointScope](SharePointLibraryItem, items). makeScope[SharePointScope](SharePointLibraryItem, items).
set(SharePointLibrary, libraries, opts...), set(SharePointLibraryFolder, libraries, opts...),
) )
return scopes return scopes
@ -394,7 +411,7 @@ const (
SharePointSite sharePointCategory = "SharePointSite" SharePointSite sharePointCategory = "SharePointSite"
SharePointList sharePointCategory = "SharePointList" SharePointList sharePointCategory = "SharePointList"
SharePointListItem sharePointCategory = "SharePointListItem" SharePointListItem sharePointCategory = "SharePointListItem"
SharePointLibrary sharePointCategory = "SharePointLibrary" SharePointLibraryFolder sharePointCategory = "SharePointLibraryFolder"
SharePointLibraryItem sharePointCategory = "SharePointLibraryItem" SharePointLibraryItem sharePointCategory = "SharePointLibraryItem"
SharePointPageFolder sharePointCategory = "SharePointPageFolder" SharePointPageFolder sharePointCategory = "SharePointPageFolder"
SharePointPage sharePointCategory = "SharePointPage" SharePointPage sharePointCategory = "SharePointPage"
@ -404,12 +421,15 @@ const (
SiteFilterCreatedBefore sharePointCategory = "FileFilterCreatedBefore" SiteFilterCreatedBefore sharePointCategory = "FileFilterCreatedBefore"
SiteFilterModifiedAfter sharePointCategory = "FileFilterModifiedAfter" SiteFilterModifiedAfter sharePointCategory = "FileFilterModifiedAfter"
SiteFilterModifiedBefore sharePointCategory = "FileFilterModifiedBefore" SiteFilterModifiedBefore sharePointCategory = "FileFilterModifiedBefore"
// library drive selection
SharePointFilterLibraryDrive sharePointCategory = "SharePointFilterLibraryDrive"
) )
// sharePointLeafProperties describes common metadata of the leaf categories // sharePointLeafProperties describes common metadata of the leaf categories
var sharePointLeafProperties = map[categorizer]leafProperty{ var sharePointLeafProperties = map[categorizer]leafProperty{
SharePointLibraryItem: { SharePointLibraryItem: {
pathKeys: []categorizer{SharePointLibrary, SharePointLibraryItem}, pathKeys: []categorizer{SharePointLibraryFolder, SharePointLibraryItem},
pathType: path.LibrariesCategory, pathType: path.LibrariesCategory,
}, },
SharePointListItem: { SharePointListItem: {
@ -437,7 +457,7 @@ func (c sharePointCategory) String() string {
// Ex: ServiceUser.leafCat() => ServiceUser // Ex: ServiceUser.leafCat() => ServiceUser
func (c sharePointCategory) leafCat() categorizer { func (c sharePointCategory) leafCat() categorizer {
switch c { switch c {
case SharePointLibrary, SharePointLibraryItem, case SharePointLibraryFolder, SharePointLibraryItem, SharePointFilterLibraryDrive,
SiteFilterCreatedAfter, SiteFilterCreatedBefore, SiteFilterCreatedAfter, SiteFilterCreatedBefore,
SiteFilterModifiedAfter, SiteFilterModifiedBefore: SiteFilterModifiedAfter, SiteFilterModifiedBefore:
return SharePointLibraryItem return SharePointLibraryItem
@ -480,8 +500,8 @@ func (c sharePointCategory) pathValues(repo path.Path, ent details.DetailsEntry)
var folderCat, itemCat categorizer var folderCat, itemCat categorizer
switch c { switch c {
case SharePointLibrary, SharePointLibraryItem: case SharePointLibraryFolder, SharePointLibraryItem:
folderCat, itemCat = SharePointLibrary, SharePointLibraryItem folderCat, itemCat = SharePointLibraryFolder, SharePointLibraryItem
case SharePointList, SharePointListItem: case SharePointList, SharePointListItem:
folderCat, itemCat = SharePointList, SharePointListItem folderCat, itemCat = SharePointList, SharePointListItem
case SharePointPage, SharePointPageFolder: case SharePointPage, SharePointPageFolder:
@ -572,7 +592,7 @@ func (s SharePointScope) set(cat sharePointCategory, v []string, opts ...option)
os := []option{} os := []option{}
switch cat { switch cat {
case SharePointLibrary, SharePointList, SharePointPage: case SharePointLibraryFolder, SharePointList, SharePointPage:
os = append(os, pathComparator()) os = append(os, pathComparator())
} }
@ -583,13 +603,13 @@ func (s SharePointScope) set(cat sharePointCategory, v []string, opts ...option)
func (s SharePointScope) setDefaults() { func (s SharePointScope) setDefaults() {
switch s.Category() { switch s.Category() {
case SharePointSite: case SharePointSite:
s[SharePointLibrary.String()] = passAny s[SharePointLibraryFolder.String()] = passAny
s[SharePointLibraryItem.String()] = passAny s[SharePointLibraryItem.String()] = passAny
s[SharePointList.String()] = passAny s[SharePointList.String()] = passAny
s[SharePointListItem.String()] = passAny s[SharePointListItem.String()] = passAny
s[SharePointPageFolder.String()] = passAny s[SharePointPageFolder.String()] = passAny
s[SharePointPage.String()] = passAny s[SharePointPage.String()] = passAny
case SharePointLibrary: case SharePointLibraryFolder:
s[SharePointLibraryItem.String()] = passAny s[SharePointLibraryItem.String()] = passAny
case SharePointList: case SharePointList:
s[SharePointListItem.String()] = passAny s[SharePointListItem.String()] = passAny
@ -647,6 +667,18 @@ func (s SharePointScope) matchesInfo(dii details.ItemInfo) bool {
i = common.FormatTime(info.Created) i = common.FormatTime(info.Created)
case SiteFilterModifiedAfter, SiteFilterModifiedBefore: case SiteFilterModifiedAfter, SiteFilterModifiedBefore:
i = common.FormatTime(info.Modified) 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) return s.Matches(filterCat, i)

View File

@ -80,7 +80,7 @@ func (suite *SharePointSelectorSuite) TestSharePointSelector_AllData() {
spsc, spsc,
map[categorizer]string{ map[categorizer]string{
SharePointLibraryItem: AnyTgt, SharePointLibraryItem: AnyTgt,
SharePointLibrary: AnyTgt, SharePointLibraryFolder: AnyTgt,
}, },
) )
case SharePointListItem: case SharePointListItem:
@ -289,7 +289,7 @@ func (suite *SharePointSelectorSuite) TestSharePointRestore_Reduce() {
deets: deets, deets: deets,
makeSelector: func() *SharePointRestore { makeSelector: func() *SharePointRestore {
odr := NewSharePointRestore([]string{"sid"}) odr := NewSharePointRestore([]string{"sid"})
odr.Include(odr.Libraries([]string{"folderA/folderB", pairAC})) odr.Include(odr.LibraryFolders([]string{"folderA/folderB", pairAC}))
return odr return odr
}, },
expect: arr(item, item2), expect: arr(item, item2),
@ -330,7 +330,7 @@ func (suite *SharePointSelectorSuite) TestSharePointCategory_PathValues() {
name: "SharePoint Libraries", name: "SharePoint Libraries",
sc: SharePointLibraryItem, sc: SharePointLibraryItem,
expected: map[categorizer][]string{ expected: map[categorizer][]string{
SharePointLibrary: {"dir1/dir2"}, SharePointLibraryFolder: {"dir1/dir2"},
SharePointLibraryItem: {"item", "short"}, SharePointLibraryItem: {"item", "short"},
}, },
}, },
@ -370,7 +370,7 @@ func (suite *SharePointSelectorSuite) TestSharePointCategory_PathValues() {
func (suite *SharePointSelectorSuite) TestSharePointScope_MatchesInfo() { func (suite *SharePointSelectorSuite) TestSharePointScope_MatchesInfo() {
var ( var (
ods = NewSharePointRestore(Any()) sel = NewSharePointRestore(Any())
host = "www.website.com" host = "www.website.com"
pth = "/foo" pth = "/foo"
url = host + pth url = host + pth
@ -386,29 +386,33 @@ func (suite *SharePointSelectorSuite) TestSharePointScope_MatchesInfo() {
scope []SharePointScope scope []SharePointScope
expect assert.BoolAssertionFunc expect assert.BoolAssertionFunc
}{ }{
{"host match", host, ods.WebURL([]string{host}), assert.True}, {"host match", host, sel.WebURL([]string{host}), assert.True},
{"url match", url, ods.WebURL([]string{url}), assert.True}, {"url match", url, sel.WebURL([]string{url}), assert.True},
{"url contains host", url, ods.WebURL([]string{host}), assert.True}, {"url contains host", url, sel.WebURL([]string{host}), assert.True},
{"host suffixes host", host, ods.WebURL([]string{host}, SuffixMatch()), assert.True}, {"host suffixes host", host, sel.WebURL([]string{host}, SuffixMatch()), assert.True},
{"url does not suffix host", url, ods.WebURL([]string{host}, SuffixMatch()), assert.False}, {"url does not suffix host", url, sel.WebURL([]string{host}, SuffixMatch()), assert.False},
{"url contains path", url, ods.WebURL([]string{pth}), assert.True}, {"url contains path", url, sel.WebURL([]string{pth}), assert.True},
{"url has path suffix", url, ods.WebURL([]string{pth}, SuffixMatch()), assert.True}, {"url has path suffix", url, sel.WebURL([]string{pth}, SuffixMatch()), assert.True},
{"host does not contain substring", host, ods.WebURL([]string{"website"}), assert.False}, {"host does not contain substring", host, sel.WebURL([]string{"website"}), assert.False},
{"url does not suffix substring", url, ods.WebURL([]string{"oo"}), assert.False}, {"url does not suffix substring", url, sel.WebURL([]string{"oo"}), assert.False},
{"host mismatch", host, ods.WebURL([]string{"www.google.com"}), assert.False}, {"host mismatch", host, sel.WebURL([]string{"www.google.com"}), assert.False},
{"file create after the epoch", host, ods.CreatedAfter(common.FormatTime(epoch)), assert.True}, {"file create after the epoch", host, sel.CreatedAfter(common.FormatTime(epoch)), assert.True},
{"file create after now", host, ods.CreatedAfter(common.FormatTime(now)), assert.False}, {"file create after now", host, sel.CreatedAfter(common.FormatTime(now)), assert.False},
{"file create after later", url, ods.CreatedAfter(common.FormatTime(future)), assert.False}, {"file create after later", url, sel.CreatedAfter(common.FormatTime(future)), assert.False},
{"file create before future", host, ods.CreatedBefore(common.FormatTime(future)), assert.True}, {"file create before future", host, sel.CreatedBefore(common.FormatTime(future)), assert.True},
{"file create before now", host, ods.CreatedBefore(common.FormatTime(now)), assert.False}, {"file create before now", host, sel.CreatedBefore(common.FormatTime(now)), assert.False},
{"file create before modification", host, ods.CreatedBefore(common.FormatTime(modification)), assert.True}, {"file create before modification", host, sel.CreatedBefore(common.FormatTime(modification)), assert.True},
{"file create before epoch", host, ods.CreatedBefore(common.FormatTime(now)), assert.False}, {"file create before epoch", host, sel.CreatedBefore(common.FormatTime(now)), assert.False},
{"file modified after the epoch", host, ods.ModifiedAfter(common.FormatTime(epoch)), assert.True}, {"file modified after the epoch", host, sel.ModifiedAfter(common.FormatTime(epoch)), assert.True},
{"file modified after now", host, ods.ModifiedAfter(common.FormatTime(now)), assert.True}, {"file modified after now", host, sel.ModifiedAfter(common.FormatTime(now)), assert.True},
{"file modified after later", host, ods.ModifiedAfter(common.FormatTime(future)), assert.False}, {"file modified after later", host, sel.ModifiedAfter(common.FormatTime(future)), assert.False},
{"file modified before future", host, ods.ModifiedBefore(common.FormatTime(future)), assert.True}, {"file modified before future", host, sel.ModifiedBefore(common.FormatTime(future)), assert.True},
{"file modified before now", host, ods.ModifiedBefore(common.FormatTime(now)), assert.False}, {"file modified before now", host, sel.ModifiedBefore(common.FormatTime(now)), assert.False},
{"file modified before epoch", host, ods.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 { for _, test := range table {
suite.Run(test.name, func() { suite.Run(test.name, func() {
@ -420,6 +424,8 @@ func (suite *SharePointSelectorSuite) TestSharePointScope_MatchesInfo() {
WebURL: test.infoURL, WebURL: test.infoURL,
Created: now, Created: now,
Modified: modification, Modified: modification,
DriveName: "included-library",
DriveID: "1234",
}, },
} }
@ -439,7 +445,7 @@ func (suite *SharePointSelectorSuite) TestCategory_PathType() {
{SharePointCategoryUnknown, path.UnknownCategory}, {SharePointCategoryUnknown, path.UnknownCategory},
{SharePointWebURL, path.UnknownCategory}, {SharePointWebURL, path.UnknownCategory},
{SharePointSite, path.UnknownCategory}, {SharePointSite, path.UnknownCategory},
{SharePointLibrary, path.LibrariesCategory}, {SharePointLibraryFolder, path.LibrariesCategory},
{SharePointLibraryItem, path.LibrariesCategory}, {SharePointLibraryItem, path.LibrariesCategory},
{SharePointList, path.ListsCategory}, {SharePointList, path.ListsCategory},
} }