Selectors: Add selectors for new sharepoint category (#2111)
## Description Expands SharePoint Selectors to include `SharePoint.Pages` within the Corso package.<!-- Insert PR description--> ## Does this PR need a docs update or release note? - [x] ✅ Yes, it's included ## Type of change <!--- Please check the type of change your PR introduces: ---> - [x] 🌻 Feature - [x] 🐛 Bugfix Prerequisites ----- - [ ] Merge #2114 - [x] Resolve #2112 ## Issue(s) <!-- Can reference multiple issues. Use one of the following "magic words" - "closes, fixes" to auto-close the Github issue. --> * closes #2110<issue> * related #2107 ## Test Plan Testing will - [x] ⚡ Unit test
This commit is contained in:
parent
51e29f2975
commit
9f185a9b41
@ -11,6 +11,8 @@ const (
|
||||
LibraryFN = "library"
|
||||
ListItemFN = "list-item"
|
||||
ListFN = "list"
|
||||
PageFN = "page"
|
||||
PageItemFN = "page-item"
|
||||
WebURLFN = "web-url"
|
||||
)
|
||||
|
||||
@ -19,6 +21,8 @@ type SharePointOpts struct {
|
||||
LibraryPaths []string
|
||||
ListItems []string
|
||||
ListPaths []string
|
||||
PageFolders []string
|
||||
Pages []string
|
||||
Sites []string
|
||||
WebURLs []string
|
||||
|
||||
@ -60,6 +64,7 @@ func IncludeSharePointRestoreDataSelectors(opts SharePointOpts) *selectors.Share
|
||||
lp, li := len(opts.LibraryPaths), len(opts.LibraryItems)
|
||||
ls, lwu := len(opts.Sites), len(opts.WebURLs)
|
||||
slp, sli := len(opts.ListPaths), len(opts.ListItems)
|
||||
pf, pi := len(opts.PageFolders), len(opts.Pages)
|
||||
|
||||
if ls == 0 {
|
||||
sites = selectors.Any()
|
||||
@ -67,7 +72,7 @@ func IncludeSharePointRestoreDataSelectors(opts SharePointOpts) *selectors.Share
|
||||
|
||||
sel := selectors.NewSharePointRestore(sites)
|
||||
|
||||
if lp+li+lwu+slp+sli == 0 {
|
||||
if lp+li+lwu+slp+sli+pf+pi == 0 {
|
||||
sel.Include(sel.AllData())
|
||||
return sel
|
||||
}
|
||||
@ -106,6 +111,23 @@ func IncludeSharePointRestoreDataSelectors(opts SharePointOpts) *selectors.Share
|
||||
}
|
||||
}
|
||||
|
||||
if pf+pi > 0 {
|
||||
if pi == 0 {
|
||||
opts.Pages = selectors.Any()
|
||||
}
|
||||
|
||||
opts.PageFolders = trimFolderSlash(opts.PageFolders)
|
||||
containsFolders, prefixFolders := splitFoldersIntoContainsAndPrefix(opts.PageFolders)
|
||||
|
||||
if len(containsFolders) > 0 {
|
||||
sel.Include(sel.PageItems(containsFolders, opts.Pages))
|
||||
}
|
||||
|
||||
if len(prefixFolders) > 0 {
|
||||
sel.Include(sel.PageItems(prefixFolders, opts.Pages, selectors.PrefixMatch()))
|
||||
}
|
||||
}
|
||||
|
||||
if lwu > 0 {
|
||||
opts.WebURLs = trimFolderSlash(opts.WebURLs)
|
||||
containsURLs, suffixURLs := splitFoldersIntoContainsAndPrefix(opts.WebURLs)
|
||||
|
||||
@ -17,6 +17,8 @@ func TestSharePointUtilsSuite(t *testing.T) {
|
||||
suite.Run(t, new(SharePointUtilsSuite))
|
||||
}
|
||||
|
||||
// Tests selector build for SharePoint properly
|
||||
// differentiates between the 3 categories: Pages, Libraries and Lists CLI
|
||||
func (suite *SharePointUtilsSuite) TestIncludeSharePointRestoreDataSelectors() {
|
||||
var (
|
||||
empty = []string{}
|
||||
@ -34,13 +36,8 @@ func (suite *SharePointUtilsSuite) TestIncludeSharePointRestoreDataSelectors() {
|
||||
}{
|
||||
{
|
||||
name: "no inputs",
|
||||
opts: utils.SharePointOpts{
|
||||
LibraryItems: empty,
|
||||
LibraryPaths: empty,
|
||||
Sites: empty,
|
||||
WebURLs: empty,
|
||||
},
|
||||
expectIncludeLen: 2,
|
||||
opts: utils.SharePointOpts{},
|
||||
expectIncludeLen: 3,
|
||||
},
|
||||
{
|
||||
name: "single inputs",
|
||||
@ -50,7 +47,7 @@ func (suite *SharePointUtilsSuite) TestIncludeSharePointRestoreDataSelectors() {
|
||||
Sites: single,
|
||||
WebURLs: single,
|
||||
},
|
||||
expectIncludeLen: 3,
|
||||
expectIncludeLen: 4,
|
||||
},
|
||||
{
|
||||
name: "single extended",
|
||||
@ -62,7 +59,7 @@ func (suite *SharePointUtilsSuite) TestIncludeSharePointRestoreDataSelectors() {
|
||||
Sites: single,
|
||||
WebURLs: single,
|
||||
},
|
||||
expectIncludeLen: 4,
|
||||
expectIncludeLen: 5,
|
||||
},
|
||||
{
|
||||
name: "multi inputs",
|
||||
@ -72,7 +69,7 @@ func (suite *SharePointUtilsSuite) TestIncludeSharePointRestoreDataSelectors() {
|
||||
Sites: multi,
|
||||
WebURLs: multi,
|
||||
},
|
||||
expectIncludeLen: 3,
|
||||
expectIncludeLen: 4,
|
||||
},
|
||||
{
|
||||
name: "library contains",
|
||||
@ -138,7 +135,7 @@ func (suite *SharePointUtilsSuite) TestIncludeSharePointRestoreDataSelectors() {
|
||||
Sites: empty,
|
||||
WebURLs: containsOnly,
|
||||
},
|
||||
expectIncludeLen: 2,
|
||||
expectIncludeLen: 3,
|
||||
},
|
||||
{
|
||||
name: "library suffixes",
|
||||
@ -148,7 +145,7 @@ func (suite *SharePointUtilsSuite) TestIncludeSharePointRestoreDataSelectors() {
|
||||
Sites: empty,
|
||||
WebURLs: prefixOnly, // prefix pattern matches suffix pattern
|
||||
},
|
||||
expectIncludeLen: 2,
|
||||
expectIncludeLen: 3,
|
||||
},
|
||||
{
|
||||
name: "library suffixes and contains",
|
||||
@ -158,7 +155,29 @@ func (suite *SharePointUtilsSuite) TestIncludeSharePointRestoreDataSelectors() {
|
||||
Sites: empty,
|
||||
WebURLs: containsAndPrefix, // prefix pattern matches suffix pattern
|
||||
},
|
||||
expectIncludeLen: 4,
|
||||
expectIncludeLen: 6,
|
||||
},
|
||||
{
|
||||
name: "Page Folder",
|
||||
opts: utils.SharePointOpts{
|
||||
PageFolders: single,
|
||||
},
|
||||
expectIncludeLen: 1,
|
||||
},
|
||||
{
|
||||
name: "Site Page ",
|
||||
opts: utils.SharePointOpts{
|
||||
Pages: single,
|
||||
},
|
||||
expectIncludeLen: 1,
|
||||
},
|
||||
{
|
||||
name: "Page & Library",
|
||||
opts: utils.SharePointOpts{
|
||||
PageFolders: single,
|
||||
LibraryItems: multi,
|
||||
},
|
||||
expectIncludeLen: 2,
|
||||
},
|
||||
}
|
||||
for _, test := range table {
|
||||
|
||||
@ -239,3 +239,130 @@ func (suite *SelectorSuite) TestSplitByResourceOnwer() {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestPathCategories verifies that no scope produces a `path.UnknownCategory`
|
||||
func (suite *SelectorSuite) TestPathCategories_includes() {
|
||||
users := []string{"someuser@onmicrosoft.com"}
|
||||
|
||||
table := []struct {
|
||||
name string
|
||||
getSelector func(t *testing.T) *Selector
|
||||
isErr assert.ErrorAssertionFunc
|
||||
}{
|
||||
{
|
||||
name: "empty",
|
||||
isErr: assert.Error,
|
||||
getSelector: func(t *testing.T) *Selector {
|
||||
return &Selector{}
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Mail_B",
|
||||
isErr: assert.NoError,
|
||||
getSelector: func(t *testing.T) *Selector {
|
||||
sel := NewExchangeBackup(users)
|
||||
sel.Include(sel.MailFolders([]string{"MailFolder"}, PrefixMatch()))
|
||||
sel.Mails([]string{"MailFolder2"}, []string{"Mail"})
|
||||
return &sel.Selector
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Mail_R",
|
||||
isErr: assert.NoError,
|
||||
getSelector: func(t *testing.T) *Selector {
|
||||
sel := NewExchangeRestore(users)
|
||||
sel.Include(sel.MailFolders([]string{"MailFolder"}, PrefixMatch()))
|
||||
|
||||
return &sel.Selector
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Contacts",
|
||||
isErr: assert.NoError,
|
||||
getSelector: func(t *testing.T) *Selector {
|
||||
sel := NewExchangeBackup(users)
|
||||
sel.Include(sel.ContactFolders([]string{"Contact Folder"}, PrefixMatch()))
|
||||
return &sel.Selector
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Contacts_R",
|
||||
isErr: assert.NoError,
|
||||
getSelector: func(t *testing.T) *Selector {
|
||||
sel := NewExchangeRestore(users)
|
||||
sel.Include(sel.ContactFolders([]string{"Contact Folder"}, PrefixMatch()))
|
||||
return &sel.Selector
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Events",
|
||||
isErr: assert.NoError,
|
||||
getSelector: func(t *testing.T) *Selector {
|
||||
sel := NewExchangeBackup(users)
|
||||
sel.Include(sel.EventCalendars([]string{"July"}, PrefixMatch()))
|
||||
return &sel.Selector
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Events_R",
|
||||
isErr: assert.NoError,
|
||||
getSelector: func(t *testing.T) *Selector {
|
||||
sel := NewExchangeRestore(users)
|
||||
sel.Include(sel.EventCalendars([]string{"July"}, PrefixMatch()))
|
||||
sel.EventCalendars([]string{"Independence Day EventID"})
|
||||
return &sel.Selector
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "SharePoint Pages",
|
||||
isErr: assert.NoError,
|
||||
getSelector: func(t *testing.T) *Selector {
|
||||
sel := NewSharePointBackup(users)
|
||||
sel.Include(sel.Pages([]string{"Something"}, SuffixMatch()))
|
||||
sel.PageItems([]string{"Home Directory"}, []string{"Event Page"})
|
||||
|
||||
return &sel.Selector
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "SharePoint Lists",
|
||||
isErr: assert.NoError,
|
||||
getSelector: func(t *testing.T) *Selector {
|
||||
sel := NewSharePointBackup(users)
|
||||
sel.Include(sel.Lists([]string{"Lists from website"}, SuffixMatch()))
|
||||
|
||||
return &sel.Selector
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "SharePoint Libraries",
|
||||
isErr: assert.NoError,
|
||||
getSelector: func(t *testing.T) *Selector {
|
||||
sel := NewSharePointBackup(users)
|
||||
sel.Include(sel.Libraries([]string{"A directory"}, SuffixMatch()))
|
||||
|
||||
return &sel.Selector
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "OneDrive",
|
||||
isErr: assert.NoError,
|
||||
getSelector: func(t *testing.T) *Selector {
|
||||
sel := NewOneDriveBackup(users)
|
||||
sel.Include(sel.Folders([]string{"Single Folder"}, PrefixMatch()))
|
||||
|
||||
return &sel.Selector
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, test := range table {
|
||||
suite.T().Run(test.name, func(t *testing.T) {
|
||||
obj := test.getSelector(t)
|
||||
cats, err := obj.PathCategories()
|
||||
for _, entry := range cats.Includes {
|
||||
assert.NotEqual(t, entry, path.UnknownCategory)
|
||||
}
|
||||
test.isErr(t, err)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@ -202,6 +202,11 @@ func (s *SharePointRestore) WebURL(urlSuffixes []string, opts ...option) []Share
|
||||
SharePointWebURL,
|
||||
urlSuffixes,
|
||||
pathFilterFactory(opts...)),
|
||||
makeFilterScope[SharePointScope](
|
||||
SharePointPage,
|
||||
SharePointWebURL,
|
||||
urlSuffixes,
|
||||
pathFilterFactory(opts...)),
|
||||
)
|
||||
|
||||
return scopes
|
||||
@ -219,6 +224,7 @@ func (s *sharePoint) AllData() []SharePointScope {
|
||||
scopes,
|
||||
makeScope[SharePointScope](SharePointLibrary, Any()),
|
||||
makeScope[SharePointScope](SharePointList, Any()),
|
||||
makeScope[SharePointScope](SharePointPage, Any()),
|
||||
)
|
||||
|
||||
return scopes
|
||||
@ -291,6 +297,38 @@ func (s *sharePoint) LibraryItems(libraries, items []string, opts ...option) []S
|
||||
return scopes
|
||||
}
|
||||
|
||||
// Pages produces one or more SharePoint page 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) Pages(pages []string, opts ...option) []SharePointScope {
|
||||
var (
|
||||
scopes = []SharePointScope{}
|
||||
os = append([]option{pathComparator()}, opts...)
|
||||
)
|
||||
|
||||
scopes = append(scopes, makeScope[SharePointScope](SharePointPageFolder, pages, os...))
|
||||
|
||||
return scopes
|
||||
}
|
||||
|
||||
// PageItems produces one or more SharePoint page item 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]
|
||||
// options are only applied to the page scopes.
|
||||
func (s *sharePoint) PageItems(pages, items []string, opts ...option) []SharePointScope {
|
||||
scopes := []SharePointScope{}
|
||||
|
||||
scopes = append(
|
||||
scopes,
|
||||
makeScope[SharePointScope](SharePointPage, items).
|
||||
set(SharePointPage, pages, opts...),
|
||||
)
|
||||
|
||||
return scopes
|
||||
}
|
||||
|
||||
// -------------------
|
||||
// Filter Factories
|
||||
|
||||
@ -315,6 +353,8 @@ const (
|
||||
SharePointListItem sharePointCategory = "SharePointListItem"
|
||||
SharePointLibrary sharePointCategory = "SharePointLibrary"
|
||||
SharePointLibraryItem sharePointCategory = "SharePointLibraryItem"
|
||||
SharePointPageFolder sharePointCategory = "SharePointPageFolder"
|
||||
SharePointPage sharePointCategory = "SharePointPage"
|
||||
|
||||
// filterable topics identified by SharePoint
|
||||
)
|
||||
@ -325,14 +365,18 @@ var sharePointLeafProperties = map[categorizer]leafProperty{
|
||||
pathKeys: []categorizer{SharePointLibrary, SharePointLibraryItem},
|
||||
pathType: path.LibrariesCategory,
|
||||
},
|
||||
SharePointListItem: {
|
||||
pathKeys: []categorizer{SharePointList, SharePointListItem},
|
||||
pathType: path.ListsCategory,
|
||||
},
|
||||
SharePointPage: {
|
||||
pathKeys: []categorizer{SharePointPageFolder, SharePointPage},
|
||||
pathType: path.PagesCategory,
|
||||
},
|
||||
SharePointSite: { // the root category must be represented, even though it isn't a leaf
|
||||
pathKeys: []categorizer{SharePointSite},
|
||||
pathType: path.UnknownCategory,
|
||||
},
|
||||
SharePointListItem: {
|
||||
pathKeys: []categorizer{SharePointSite, SharePointList, SharePointListItem},
|
||||
pathType: path.ListsCategory,
|
||||
},
|
||||
}
|
||||
|
||||
func (c sharePointCategory) String() string {
|
||||
@ -350,6 +394,8 @@ func (c sharePointCategory) leafCat() categorizer {
|
||||
return SharePointLibraryItem
|
||||
case SharePointList, SharePointListItem:
|
||||
return SharePointListItem
|
||||
case SharePointPage, SharePointPageFolder:
|
||||
return SharePointPage
|
||||
}
|
||||
|
||||
return c
|
||||
@ -389,6 +435,10 @@ func (c sharePointCategory) pathValues(p path.Path) map[categorizer]string {
|
||||
folderCat, itemCat = SharePointLibrary, SharePointLibraryItem
|
||||
case SharePointList, SharePointListItem:
|
||||
folderCat, itemCat = SharePointList, SharePointListItem
|
||||
case SharePointPage, SharePointPageFolder:
|
||||
folderCat, itemCat = SharePointPageFolder, SharePointPage
|
||||
default:
|
||||
return map[categorizer]string{}
|
||||
}
|
||||
|
||||
return map[categorizer]string{
|
||||
@ -429,6 +479,12 @@ func (s SharePointScope) categorizer() categorizer {
|
||||
return s.Category()
|
||||
}
|
||||
|
||||
// Matches returns true if the category is included in the scope's
|
||||
// data type, and the target string matches that category's comparator.
|
||||
func (s SharePointScope) Matches(cat sharePointCategory, target string) bool {
|
||||
return matches(s, cat, target)
|
||||
}
|
||||
|
||||
// FilterCategory returns the category enum of the scope filter.
|
||||
// If the scope is not a filter type, returns SharePointUnknownCategory.
|
||||
func (s SharePointScope) FilterCategory() sharePointCategory {
|
||||
@ -443,12 +499,6 @@ func (s SharePointScope) IncludesCategory(cat sharePointCategory) bool {
|
||||
return categoryMatches(s.Category(), cat)
|
||||
}
|
||||
|
||||
// Matches returns true if the category is included in the scope's
|
||||
// data type, and the target string matches that category's comparator.
|
||||
func (s SharePointScope) Matches(cat sharePointCategory, target string) bool {
|
||||
return matches(s, cat, target)
|
||||
}
|
||||
|
||||
// returns true if the category is included in the scope's data type,
|
||||
// and the value is set to Any().
|
||||
func (s SharePointScope) IsAny(cat sharePointCategory) bool {
|
||||
@ -467,7 +517,7 @@ func (s SharePointScope) set(cat sharePointCategory, v []string, opts ...option)
|
||||
os := []option{}
|
||||
|
||||
switch cat {
|
||||
case SharePointLibrary, SharePointList:
|
||||
case SharePointLibrary, SharePointList, SharePointPage:
|
||||
os = append(os, pathComparator())
|
||||
}
|
||||
|
||||
@ -482,10 +532,14 @@ func (s SharePointScope) setDefaults() {
|
||||
s[SharePointLibraryItem.String()] = passAny
|
||||
s[SharePointList.String()] = passAny
|
||||
s[SharePointListItem.String()] = passAny
|
||||
s[SharePointPageFolder.String()] = passAny
|
||||
s[SharePointPage.String()] = passAny
|
||||
case SharePointLibrary:
|
||||
s[SharePointLibraryItem.String()] = passAny
|
||||
case SharePointList:
|
||||
s[SharePointListItem.String()] = passAny
|
||||
case SharePointPageFolder:
|
||||
s[SharePointPage.String()] = passAny
|
||||
}
|
||||
}
|
||||
|
||||
@ -509,6 +563,7 @@ func (s sharePoint) Reduce(ctx context.Context, deets *details.Details) *details
|
||||
map[path.CategoryType]sharePointCategory{
|
||||
path.LibrariesCategory: SharePointLibraryItem,
|
||||
path.ListsCategory: SharePointListItem,
|
||||
path.PagesCategory: SharePointPage,
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
@ -61,7 +61,7 @@ func (suite *SharePointSelectorSuite) TestSharePointSelector_AllData() {
|
||||
{"Filter Scopes", sel.Filters},
|
||||
}
|
||||
for _, test := range table {
|
||||
require.Len(t, test.scopesToCheck, 2)
|
||||
require.Len(t, test.scopesToCheck, 3)
|
||||
|
||||
for _, scope := range test.scopesToCheck {
|
||||
var (
|
||||
@ -106,7 +106,7 @@ func (suite *SharePointSelectorSuite) TestSharePointSelector_Include_WebURLs() {
|
||||
sel := NewSharePointRestore([]string{s1, s2})
|
||||
sel.Include(sel.WebURL([]string{s1, s2}))
|
||||
scopes := sel.Includes
|
||||
require.Len(t, scopes, 2)
|
||||
require.Len(t, scopes, 3)
|
||||
|
||||
for _, sc := range scopes {
|
||||
scopeMustHave(
|
||||
@ -139,7 +139,7 @@ func (suite *SharePointSelectorSuite) TestSharePointSelector_Include_WebURLs_any
|
||||
sel := NewSharePointRestore(Any())
|
||||
sel.Include(sel.WebURL(test.in))
|
||||
scopes := sel.Includes
|
||||
require.Len(t, scopes, 2)
|
||||
require.Len(t, scopes, 3)
|
||||
|
||||
for _, sc := range scopes {
|
||||
scopeMustHave(
|
||||
@ -163,7 +163,7 @@ func (suite *SharePointSelectorSuite) TestSharePointSelector_Exclude_WebURLs() {
|
||||
sel := NewSharePointRestore([]string{s1, s2})
|
||||
sel.Exclude(sel.WebURL([]string{s1, s2}))
|
||||
scopes := sel.Excludes
|
||||
require.Len(t, scopes, 2)
|
||||
require.Len(t, scopes, 3)
|
||||
|
||||
for _, sc := range scopes {
|
||||
scopeMustHave(
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user