fix sharepoint library folder selection (#2962)

Bugfix:
Sharepoint LibraryFolder scopes always return
zero matches in filtering with a prefix due to the
path not having the drive root prefix truncated, as is
expected of onedrive-based storage paths.

---

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

- [x]  Yes, it's included

#### Type of change

- [x] 🐛 Bugfix

#### Test Plan

- [x] 💪 Manual
- [x]  Unit test
This commit is contained in:
Keepers 2023-03-27 19:21:20 -06:00 committed by GitHub
parent ac2a299c51
commit 8acff1ad93
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 45 additions and 23 deletions

View File

@ -14,6 +14,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Handle calendar events with no body. - Handle calendar events with no body.
- Items not being deleted if they were created and deleted during item enumeration of a OneDrive backup. - Items not being deleted if they were created and deleted during item enumeration of a OneDrive backup.
- Enable compression for all data uploaded by kopia. - Enable compression for all data uploaded by kopia.
- SharePoint --folder selectors correctly return items.
## [v0.6.1] (beta) - 2023-03-21 ## [v0.6.1] (beta) - 2023-03-21
@ -33,8 +34,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Known Issues ### Known Issues
- Owner (Full control) or empty (Restricted View) roles cannot be restored for OneDrive - Owner (Full control) or empty (Restricted View) roles cannot be restored for OneDrive
- OneDrive will not do an incremental backup if permissions are being backed up. - OneDrive will not do an incremental backup if permissions are being backed up.
- SharePoint --folder selection in details and restore always return "no items match the specified selectors".
### Known Issues
- Event instance exceptions (ie: changes to a single event within a recurring series) are not backed up. - Event instance exceptions (ie: changes to a single event within a recurring series) are not backed up.
## [v0.5.0] (beta) - 2023-03-13 ## [v0.5.0] (beta) - 2023-03-13

View File

@ -342,6 +342,8 @@ func runDetailsExchangeCmd(
return nil, errors.Wrap(errs.Failure(), "Failed to get backup details in the repository") return nil, errors.Wrap(errs.Failure(), "Failed to get backup details in the repository")
} }
ctx = clues.Add(ctx, "details_entries", len(d.Entries))
if !skipReduce { if !skipReduce {
sel := utils.IncludeExchangeRestoreDataSelectors(opts) sel := utils.IncludeExchangeRestoreDataSelectors(opts)
utils.FilterExchangeRestoreInfoSelectors(sel, opts) utils.FilterExchangeRestoreInfoSelectors(sel, opts)

View File

@ -281,6 +281,8 @@ func runDetailsOneDriveCmd(
return nil, errors.Wrap(errs.Failure(), "Failed to get backup details in the repository") return nil, errors.Wrap(errs.Failure(), "Failed to get backup details in the repository")
} }
ctx = clues.Add(ctx, "details_entries", len(d.Entries))
if !skipReduce { if !skipReduce {
sel := utils.IncludeOneDriveRestoreDataSelectors(opts) sel := utils.IncludeOneDriveRestoreDataSelectors(opts)
utils.FilterOneDriveRestoreInfoSelectors(sel, opts) utils.FilterOneDriveRestoreInfoSelectors(sel, opts)

View File

@ -389,6 +389,8 @@ func runDetailsSharePointCmd(
return nil, errors.Wrap(errs.Failure(), "Failed to get backup details in the repository") return nil, errors.Wrap(errs.Failure(), "Failed to get backup details in the repository")
} }
ctx = clues.Add(ctx, "details_entries", len(d.Entries))
if !skipReduce { if !skipReduce {
sel := utils.IncludeSharePointRestoreDataSelectors(opts) sel := utils.IncludeSharePointRestoreDataSelectors(opts)
utils.FilterSharePointRestoreInfoSelectors(sel, opts) utils.FilterSharePointRestoreInfoSelectors(sel, opts)

View File

@ -196,6 +196,7 @@ func (op *RestoreOperation) do(
ctx = clues.Add( ctx = clues.Add(
ctx, ctx,
"resource_owner", bup.Selector.DiscreteOwner, "resource_owner", bup.Selector.DiscreteOwner,
"details_entries", len(deets.Entries),
"details_paths", len(paths), "details_paths", len(paths),
"backup_snapshot_id", bup.SnapshotID, "backup_snapshot_id", bup.SnapshotID,
"backup_version", bup.Version) "backup_version", bup.Version)

View File

@ -503,8 +503,9 @@ func (c sharePointCategory) pathValues(
ent details.DetailsEntry, ent details.DetailsEntry,
) (map[categorizer][]string, error) { ) (map[categorizer][]string, error) {
var ( var (
folderCat, itemCat categorizer folderCat, itemCat categorizer
itemName = repo.Item() itemName = repo.Item()
dropDriveFolderPrefix bool
) )
switch c { switch c {
@ -513,6 +514,7 @@ func (c sharePointCategory) pathValues(
return nil, clues.New("no SharePoint ItemInfo in details") return nil, clues.New("no SharePoint ItemInfo in details")
} }
dropDriveFolderPrefix = true
folderCat, itemCat = SharePointLibraryFolder, SharePointLibraryItem folderCat, itemCat = SharePointLibraryFolder, SharePointLibraryItem
itemName = ent.SharePoint.ItemName itemName = ent.SharePoint.ItemName
@ -526,8 +528,14 @@ func (c sharePointCategory) pathValues(
return nil, clues.New("unrecognized sharePointCategory").With("category", c) return nil, clues.New("unrecognized sharePointCategory").With("category", c)
} }
rFld := repo.Folder(false)
if dropDriveFolderPrefix {
// like onedrive, ignore `drives/<driveID>/root:` for library folder comparison
rFld = path.Builder{}.Append(repo.Folders()...).PopFront().PopFront().PopFront().String()
}
result := map[categorizer][]string{ result := map[categorizer][]string{
folderCat: {repo.Folder(false)}, folderCat: {rFld},
itemCat: {itemName, ent.ShortRef}, itemCat: {itemName, ent.ShortRef},
} }

View File

@ -199,13 +199,14 @@ func (suite *SharePointSelectorSuite) TestToSharePointRestore() {
func (suite *SharePointSelectorSuite) TestSharePointRestore_Reduce() { func (suite *SharePointSelectorSuite) TestSharePointRestore_Reduce() {
var ( var (
pairAC = "folderA/folderC" drivePfx = "drive/drive!id/root:/"
pairGH = "folderG/folderH" pairAC = "folderA/folderC"
item = stubRepoRef(path.SharePointService, path.LibrariesCategory, "sid", "folderA/folderB", "item") pairGH = "folderG/folderH"
item2 = stubRepoRef(path.SharePointService, path.LibrariesCategory, "sid", pairAC, "item2") item = stubRepoRef(path.SharePointService, path.LibrariesCategory, "sid", drivePfx+"folderA/folderB", "item")
item3 = stubRepoRef(path.SharePointService, path.LibrariesCategory, "sid", "folderD/folderE", "item3") item2 = stubRepoRef(path.SharePointService, path.LibrariesCategory, "sid", drivePfx+pairAC, "item2")
item4 = stubRepoRef(path.SharePointService, path.PagesCategory, "sid", pairGH, "item4") item3 = stubRepoRef(path.SharePointService, path.LibrariesCategory, "sid", drivePfx+"folderD/folderE", "item3")
item5 = stubRepoRef(path.SharePointService, path.PagesCategory, "sid", pairGH, "item5") item4 = stubRepoRef(path.SharePointService, path.PagesCategory, "sid", pairGH, "item4")
item5 = stubRepoRef(path.SharePointService, path.PagesCategory, "sid", pairGH, "item5")
) )
deets := &details.Details{ deets := &details.Details{
@ -327,26 +328,32 @@ func (suite *SharePointSelectorSuite) TestSharePointRestore_Reduce() {
} }
func (suite *SharePointSelectorSuite) TestSharePointCategory_PathValues() { func (suite *SharePointSelectorSuite) TestSharePointCategory_PathValues() {
itemName := "item" var (
shortRef := "short" itemName = "item"
elems := []string{"dir1", "dir2", itemName + "-id"} shortRef = "short"
driveElems = []string{"drive", "drive!id", "root:", "dir1", "dir2", itemName + "-id"}
elems = []string{"dir1", "dir2", itemName + "-id"}
)
table := []struct { table := []struct {
name string name string
sc sharePointCategory sc sharePointCategory
expected map[categorizer][]string pathElems []string
expected map[categorizer][]string
}{ }{
{ {
name: "SharePoint Libraries", name: "SharePoint Libraries",
sc: SharePointLibraryItem, sc: SharePointLibraryItem,
pathElems: driveElems,
expected: map[categorizer][]string{ expected: map[categorizer][]string{
SharePointLibraryFolder: {"dir1/dir2"}, SharePointLibraryFolder: {"dir1/dir2"},
SharePointLibraryItem: {itemName, shortRef}, SharePointLibraryItem: {itemName, shortRef},
}, },
}, },
{ {
name: "SharePoint Lists", name: "SharePoint Lists",
sc: SharePointListItem, sc: SharePointListItem,
pathElems: elems,
expected: map[categorizer][]string{ expected: map[categorizer][]string{
SharePointList: {"dir1/dir2"}, SharePointList: {"dir1/dir2"},
SharePointListItem: {"item-id", shortRef}, SharePointListItem: {"item-id", shortRef},
@ -364,7 +371,7 @@ func (suite *SharePointSelectorSuite) TestSharePointCategory_PathValues() {
path.SharePointService, path.SharePointService,
test.sc.PathType(), test.sc.PathType(),
true, true,
elems...) test.pathElems...)
require.NoError(t, err, clues.ToCore(err)) require.NoError(t, err, clues.ToCore(err))
ent := details.DetailsEntry{ ent := details.DetailsEntry{