#### 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
702 lines
23 KiB
Go
702 lines
23 KiB
Go
package selectors
|
|
|
|
import (
|
|
"context"
|
|
|
|
"github.com/alcionai/clues"
|
|
|
|
"github.com/alcionai/corso/src/internal/common"
|
|
"github.com/alcionai/corso/src/pkg/backup/details"
|
|
"github.com/alcionai/corso/src/pkg/fault"
|
|
"github.com/alcionai/corso/src/pkg/filters"
|
|
"github.com/alcionai/corso/src/pkg/path"
|
|
)
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Selectors
|
|
// ---------------------------------------------------------------------------
|
|
|
|
type (
|
|
// sharePoint provides an api for selecting
|
|
// data scopes applicable to the SharePoint service.
|
|
sharePoint struct {
|
|
Selector
|
|
}
|
|
|
|
// SharePointBackup provides an api for selecting
|
|
// data scopes applicable to the SharePoint service,
|
|
// plus backup-specific methods.
|
|
SharePointBackup struct {
|
|
sharePoint
|
|
}
|
|
|
|
// SharePointRestorep provides an api for selecting
|
|
// data scopes applicable to the SharePoint service,
|
|
// plus restore-specific methods.
|
|
SharePointRestore struct {
|
|
sharePoint
|
|
}
|
|
)
|
|
|
|
var (
|
|
_ Reducer = &SharePointRestore{}
|
|
_ pathCategorier = &SharePointRestore{}
|
|
)
|
|
|
|
// NewSharePointBackup produces a new Selector with the service set to ServiceSharePoint.
|
|
func NewSharePointBackup(sites []string) *SharePointBackup {
|
|
src := SharePointBackup{
|
|
sharePoint{
|
|
newSelector(ServiceSharePoint, sites),
|
|
},
|
|
}
|
|
|
|
return &src
|
|
}
|
|
|
|
// ToSharePointBackup transforms the generic selector into an SharePointBackup.
|
|
// Errors if the service defined by the selector is not ServiceSharePoint.
|
|
func (s Selector) ToSharePointBackup() (*SharePointBackup, error) {
|
|
if s.Service != ServiceSharePoint {
|
|
return nil, badCastErr(ServiceSharePoint, s.Service)
|
|
}
|
|
|
|
src := SharePointBackup{sharePoint{s}}
|
|
|
|
return &src, nil
|
|
}
|
|
|
|
func (s SharePointBackup) SplitByResourceOwner(sites []string) []SharePointBackup {
|
|
sels := splitByResourceOwner[SharePointScope](s.Selector, sites, SharePointSite)
|
|
|
|
ss := make([]SharePointBackup, 0, len(sels))
|
|
for _, sel := range sels {
|
|
ss = append(ss, SharePointBackup{sharePoint{sel}})
|
|
}
|
|
|
|
return ss
|
|
}
|
|
|
|
// NewSharePointRestore produces a new Selector with the service set to ServiceSharePoint.
|
|
func NewSharePointRestore(sites []string) *SharePointRestore {
|
|
src := SharePointRestore{
|
|
sharePoint{
|
|
newSelector(ServiceSharePoint, sites),
|
|
},
|
|
}
|
|
|
|
return &src
|
|
}
|
|
|
|
// ToSharePointRestore transforms the generic selector into an SharePointRestore.
|
|
// Errors if the service defined by the selector is not ServiceSharePoint.
|
|
func (s Selector) ToSharePointRestore() (*SharePointRestore, error) {
|
|
if s.Service != ServiceSharePoint {
|
|
return nil, badCastErr(ServiceSharePoint, s.Service)
|
|
}
|
|
|
|
src := SharePointRestore{sharePoint{s}}
|
|
|
|
return &src, nil
|
|
}
|
|
|
|
func (s SharePointRestore) SplitByResourceOwner(sites []string) []SharePointRestore {
|
|
sels := splitByResourceOwner[SharePointScope](s.Selector, sites, SharePointSite)
|
|
|
|
ss := make([]SharePointRestore, 0, len(sels))
|
|
for _, sel := range sels {
|
|
ss = append(ss, SharePointRestore{sharePoint{sel}})
|
|
}
|
|
|
|
return ss
|
|
}
|
|
|
|
// PathCategories produces the aggregation of discrete users described by each type of scope.
|
|
func (s sharePoint) PathCategories() selectorPathCategories {
|
|
return selectorPathCategories{
|
|
Excludes: pathCategoriesIn[SharePointScope, sharePointCategory](s.Excludes),
|
|
Filters: pathCategoriesIn[SharePointScope, sharePointCategory](s.Filters),
|
|
Includes: pathCategoriesIn[SharePointScope, sharePointCategory](s.Includes),
|
|
}
|
|
}
|
|
|
|
// -------------------
|
|
// Scope Factories
|
|
|
|
// Include appends the provided scopes to the selector's inclusion set.
|
|
// Data is included if it matches ANY inclusion.
|
|
// The inclusion set is later filtered (all included data must pass ALL
|
|
// filters) and excluded (all included data must not match ANY exclusion).
|
|
// Data is included if it matches ANY inclusion (of the same data category).
|
|
//
|
|
// All parts of the scope must match for data to be exclucded.
|
|
// Ex: File(s1, f1, i1) => only excludes an item if it is owned by site s1,
|
|
// located in folder f1, and ID'd as i1. Use selectors.Any() to wildcard
|
|
// a scope value. No value will match if selectors.None() is provided.
|
|
//
|
|
// Group-level scopes will automatically apply the Any() wildcard to
|
|
// child properties.
|
|
// ex: Site(u1) automatically cascades to all folders and files owned
|
|
// by s1.
|
|
func (s *sharePoint) Include(scopes ...[]SharePointScope) {
|
|
s.Includes = appendScopes(s.Includes, scopes...)
|
|
}
|
|
|
|
// Exclude appends the provided scopes to the selector's exclusion set.
|
|
// Every Exclusion scope applies globally, affecting all inclusion scopes.
|
|
// Data is excluded if it matches ANY exclusion.
|
|
//
|
|
// All parts of the scope must match for data to be exclucded.
|
|
// Ex: File(s1, f1, i1) => only excludes an item if it is owned by site s1,
|
|
// located in folder f1, and ID'd as i1. Use selectors.Any() to wildcard
|
|
// a scope value. No value will match if selectors.None() is provided.
|
|
//
|
|
// Group-level scopes will automatically apply the Any() wildcard to
|
|
// child properties.
|
|
// ex: Site(u1) automatically cascades to all folders and files owned
|
|
// by s1.
|
|
func (s *sharePoint) Exclude(scopes ...[]SharePointScope) {
|
|
s.Excludes = appendScopes(s.Excludes, scopes...)
|
|
}
|
|
|
|
// Filter appends the provided scopes to the selector's filters set.
|
|
// A selector with >0 filters and 0 inclusions will include any data
|
|
// that passes all filters.
|
|
// A selector with >0 filters and >0 inclusions will reduce the
|
|
// inclusion set to only the data that passes all filters.
|
|
// Data is retained if it passes ALL filters.
|
|
//
|
|
// All parts of the scope must match for data to be exclucded.
|
|
// Ex: File(s1, f1, i1) => only excludes an item if it is owned by site s1,
|
|
// located in folder f1, and ID'd as i1. Use selectors.Any() to wildcard
|
|
// a scope value. No value will match if selectors.None() is provided.
|
|
//
|
|
// Group-level scopes will automatically apply the Any() wildcard to
|
|
// child properties.
|
|
// ex: Site(u1) automatically cascades to all folders and files owned
|
|
// by s1.
|
|
func (s *sharePoint) Filter(scopes ...[]SharePointScope) {
|
|
s.Filters = appendScopes(s.Filters, scopes...)
|
|
}
|
|
|
|
// Scopes retrieves the list of sharePointScopes in the selector.
|
|
func (s *sharePoint) Scopes() []SharePointScope {
|
|
return scopes[SharePointScope](s.Selector)
|
|
}
|
|
|
|
// -------------------
|
|
// Scope Factories
|
|
|
|
// Produces one or more SharePoint webURL scopes.
|
|
// One scope is created per webURL entry.
|
|
// 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 *SharePointRestore) WebURL(urlSuffixes []string, opts ...option) []SharePointScope {
|
|
scopes := []SharePointScope{}
|
|
|
|
scopes = append(
|
|
scopes,
|
|
makeFilterScope[SharePointScope](
|
|
SharePointLibraryItem,
|
|
SharePointWebURL,
|
|
urlSuffixes,
|
|
pathFilterFactory(opts...)),
|
|
makeFilterScope[SharePointScope](
|
|
SharePointListItem,
|
|
SharePointWebURL,
|
|
urlSuffixes,
|
|
pathFilterFactory(opts...)),
|
|
makeFilterScope[SharePointScope](
|
|
SharePointPage,
|
|
SharePointWebURL,
|
|
urlSuffixes,
|
|
pathFilterFactory(opts...)),
|
|
)
|
|
|
|
return scopes
|
|
}
|
|
|
|
// Produces one or more SharePoint site scopes.
|
|
// One scope is created per site entry.
|
|
// 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) AllData() []SharePointScope {
|
|
scopes := []SharePointScope{}
|
|
|
|
scopes = append(
|
|
scopes,
|
|
makeScope[SharePointScope](SharePointLibraryFolder, Any()),
|
|
makeScope[SharePointScope](SharePointList, Any()),
|
|
makeScope[SharePointScope](SharePointPageFolder, Any()),
|
|
)
|
|
|
|
return scopes
|
|
}
|
|
|
|
// Lists produces one or more SharePoint list 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]
|
|
// Any empty slice defaults to [selectors.None]
|
|
func (s *sharePoint) Lists(lists []string, opts ...option) []SharePointScope {
|
|
var (
|
|
scopes = []SharePointScope{}
|
|
os = append([]option{pathComparator()}, opts...)
|
|
)
|
|
|
|
scopes = append(scopes, makeScope[SharePointScope](SharePointList, lists, os...))
|
|
|
|
return scopes
|
|
}
|
|
|
|
// ListItems produces one or more SharePoint list 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 list scopes.
|
|
func (s *sharePoint) ListItems(lists, items []string, opts ...option) []SharePointScope {
|
|
scopes := []SharePointScope{}
|
|
|
|
scopes = append(
|
|
scopes,
|
|
makeScope[SharePointScope](SharePointListItem, items).
|
|
set(SharePointList, lists, opts...),
|
|
)
|
|
|
|
return 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) 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...)
|
|
)
|
|
|
|
scopes = append(
|
|
scopes,
|
|
makeScope[SharePointScope](SharePointLibraryFolder, libraryFolders, os...),
|
|
)
|
|
|
|
return scopes
|
|
}
|
|
|
|
// LibraryItems produces one or more SharePoint library 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 library scopes.
|
|
func (s *sharePoint) LibraryItems(libraries, items []string, opts ...option) []SharePointScope {
|
|
scopes := []SharePointScope{}
|
|
|
|
scopes = append(
|
|
scopes,
|
|
makeScope[SharePointScope](SharePointLibraryItem, items).
|
|
set(SharePointLibraryFolder, libraries, opts...),
|
|
)
|
|
|
|
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(SharePointPageFolder, pages, opts...),
|
|
)
|
|
|
|
return scopes
|
|
}
|
|
|
|
// -------------------
|
|
// Filter Factories
|
|
|
|
func (s *sharePoint) CreatedAfter(timeStrings string) []SharePointScope {
|
|
return []SharePointScope{
|
|
makeFilterScope[SharePointScope](
|
|
SharePointLibraryItem,
|
|
SharePointFilterCreatedAfter,
|
|
[]string{timeStrings},
|
|
wrapFilter(filters.Less)),
|
|
}
|
|
}
|
|
|
|
func (s *sharePoint) CreatedBefore(timeStrings string) []SharePointScope {
|
|
return []SharePointScope{
|
|
makeFilterScope[SharePointScope](
|
|
SharePointLibraryItem,
|
|
SharePointFilterCreatedBefore,
|
|
[]string{timeStrings},
|
|
wrapFilter(filters.Greater)),
|
|
}
|
|
}
|
|
|
|
func (s *sharePoint) ModifiedAfter(timeStrings string) []SharePointScope {
|
|
return []SharePointScope{
|
|
makeFilterScope[SharePointScope](
|
|
SharePointLibraryItem,
|
|
SharePointFilterModifiedAfter,
|
|
[]string{timeStrings},
|
|
wrapFilter(filters.Less)),
|
|
}
|
|
}
|
|
|
|
func (s *sharePoint) ModifiedBefore(timeStrings string) []SharePointScope {
|
|
return []SharePointScope{
|
|
makeFilterScope[SharePointScope](
|
|
SharePointLibraryItem,
|
|
SharePointFilterModifiedBefore,
|
|
[]string{timeStrings},
|
|
wrapFilter(filters.Greater)),
|
|
}
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Categories
|
|
// ---------------------------------------------------------------------------
|
|
|
|
// sharePointCategory enumerates the type of the lowest level
|
|
// of data () in a scope.
|
|
type sharePointCategory string
|
|
|
|
// interface compliance checks
|
|
var _ categorizer = SharePointCategoryUnknown
|
|
|
|
const (
|
|
SharePointCategoryUnknown sharePointCategory = ""
|
|
|
|
// types of data identified by SharePoint
|
|
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
|
|
SharePointFilterCreatedAfter sharePointCategory = "SharePointFilterCreatedAfter"
|
|
SharePointFilterCreatedBefore sharePointCategory = "SharePointFilterCreatedBefore"
|
|
SharePointFilterModifiedAfter sharePointCategory = "SharePointFilterModifiedAfter"
|
|
SharePointFilterModifiedBefore sharePointCategory = "SharePointFilterModifiedBefore"
|
|
|
|
// library drive selection
|
|
SharePointFilterLibraryDrive sharePointCategory = "SharePointFilterLibraryDrive"
|
|
)
|
|
|
|
// sharePointLeafProperties describes common metadata of the leaf categories
|
|
var sharePointLeafProperties = map[categorizer]leafProperty{
|
|
SharePointLibraryItem: {
|
|
pathKeys: []categorizer{SharePointLibraryFolder, 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,
|
|
},
|
|
}
|
|
|
|
func (c sharePointCategory) String() string {
|
|
return string(c)
|
|
}
|
|
|
|
// leafCat returns the leaf category of the receiver.
|
|
// If the receiver category has multiple leaves (ex: User) or no leaves,
|
|
// (ex: Unknown), the receiver itself is returned.
|
|
// Ex: ServiceTypeFolder.leafCat() => ServiceTypeItem
|
|
// Ex: ServiceUser.leafCat() => ServiceUser
|
|
func (c sharePointCategory) leafCat() categorizer {
|
|
switch c {
|
|
case SharePointLibraryFolder, SharePointLibraryItem, SharePointFilterLibraryDrive,
|
|
SharePointFilterCreatedAfter, SharePointFilterCreatedBefore,
|
|
SharePointFilterModifiedAfter, SharePointFilterModifiedBefore:
|
|
return SharePointLibraryItem
|
|
case SharePointList, SharePointListItem:
|
|
return SharePointListItem
|
|
case SharePointPage, SharePointPageFolder:
|
|
return SharePointPage
|
|
}
|
|
|
|
return c
|
|
}
|
|
|
|
// rootCat returns the root category type.
|
|
func (c sharePointCategory) rootCat() categorizer {
|
|
return SharePointSite
|
|
}
|
|
|
|
// unknownCat returns the unknown category type.
|
|
func (c sharePointCategory) unknownCat() categorizer {
|
|
return SharePointCategoryUnknown
|
|
}
|
|
|
|
// isUnion returns true if the category is a site or a webURL, which
|
|
// can act as an alternative identifier to siteID across all site types.
|
|
func (c sharePointCategory) isUnion() bool {
|
|
return c == SharePointWebURL || c == c.rootCat()
|
|
}
|
|
|
|
// isLeaf is true if the category is a SharePointItem category.
|
|
func (c sharePointCategory) isLeaf() bool {
|
|
return c == c.leafCat()
|
|
}
|
|
|
|
// pathValues transforms the two paths to maps of identified properties.
|
|
//
|
|
// Example:
|
|
// [tenantID, service, siteID, category, folder, itemID]
|
|
// => {spFolder: folder, spItemID: itemID}
|
|
func (c sharePointCategory) pathValues(
|
|
repo path.Path,
|
|
ent details.DetailsEntry,
|
|
) (map[categorizer][]string, error) {
|
|
var (
|
|
folderCat, itemCat categorizer
|
|
itemName = repo.Item()
|
|
)
|
|
|
|
switch c {
|
|
case SharePointLibraryFolder, SharePointLibraryItem:
|
|
if ent.SharePoint == nil {
|
|
return nil, clues.New("no SharePoint ItemInfo in details")
|
|
}
|
|
|
|
folderCat, itemCat = SharePointLibraryFolder, SharePointLibraryItem
|
|
itemName = ent.SharePoint.ItemName
|
|
|
|
case SharePointList, SharePointListItem:
|
|
folderCat, itemCat = SharePointList, SharePointListItem
|
|
|
|
case SharePointPage, SharePointPageFolder:
|
|
folderCat, itemCat = SharePointPageFolder, SharePointPage
|
|
|
|
default:
|
|
return nil, clues.New("unrecognized sharePointCategory").With("category", c)
|
|
}
|
|
|
|
result := map[categorizer][]string{
|
|
folderCat: {repo.Folder(false)},
|
|
itemCat: {itemName, ent.ShortRef},
|
|
}
|
|
|
|
if len(ent.LocationRef) > 0 {
|
|
result[folderCat] = append(result[folderCat], ent.LocationRef)
|
|
}
|
|
|
|
return result, nil
|
|
}
|
|
|
|
// pathKeys returns the path keys recognized by the receiver's leaf type.
|
|
func (c sharePointCategory) pathKeys() []categorizer {
|
|
return sharePointLeafProperties[c.leafCat()].pathKeys
|
|
}
|
|
|
|
// PathType converts the category's leaf type into the matching path.CategoryType.
|
|
func (c sharePointCategory) PathType() path.CategoryType {
|
|
return sharePointLeafProperties[c.leafCat()].pathType
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Scopes
|
|
// ---------------------------------------------------------------------------
|
|
|
|
// SharePointScope specifies the data available
|
|
// when interfacing with the SharePoint service.
|
|
type SharePointScope scope
|
|
|
|
// interface compliance checks
|
|
var _ scoper = &SharePointScope{}
|
|
|
|
// Category describes the type of the data in scope.
|
|
func (s SharePointScope) Category() sharePointCategory {
|
|
return sharePointCategory(getCategory(s))
|
|
}
|
|
|
|
// categorizer type is a generic wrapper around Category.
|
|
// Primarily used by scopes.go to for abstract comparisons.
|
|
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 {
|
|
return sharePointCategory(getFilterCategory(s))
|
|
}
|
|
|
|
// IncludeCategory checks whether the scope includes a
|
|
// certain category of data.
|
|
// Ex: to check if the scope includes file data:
|
|
// s.IncludesCategory(selector.SharePointFile)
|
|
func (s SharePointScope) IncludesCategory(cat sharePointCategory) bool {
|
|
return categoryMatches(s.Category(), cat)
|
|
}
|
|
|
|
// 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 {
|
|
return isAnyTarget(s, cat)
|
|
}
|
|
|
|
// Get returns the data category in the scope. If the scope
|
|
// contains all data types for a user, it'll return the
|
|
// SharePointUser category.
|
|
func (s SharePointScope) Get(cat sharePointCategory) []string {
|
|
return getCatValue(s, cat)
|
|
}
|
|
|
|
// sets a value by category to the scope. Only intended for internal use.
|
|
func (s SharePointScope) set(cat sharePointCategory, v []string, opts ...option) SharePointScope {
|
|
os := []option{}
|
|
|
|
switch cat {
|
|
case SharePointLibraryFolder, SharePointList, SharePointPage:
|
|
os = append(os, pathComparator())
|
|
}
|
|
|
|
return set(s, cat, v, append(os, opts...)...)
|
|
}
|
|
|
|
// setDefaults ensures that site scopes express `AnyTgt` for their child category types.
|
|
func (s SharePointScope) setDefaults() {
|
|
switch s.Category() {
|
|
case SharePointSite:
|
|
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 SharePointLibraryFolder:
|
|
s[SharePointLibraryItem.String()] = passAny
|
|
case SharePointList:
|
|
s[SharePointListItem.String()] = passAny
|
|
case SharePointPageFolder:
|
|
s[SharePointPage.String()] = passAny
|
|
}
|
|
}
|
|
|
|
// DiscreteCopy makes a shallow clone of the scope, then replaces the clone's
|
|
// site comparison with only the provided site.
|
|
func (s SharePointScope) DiscreteCopy(site string) SharePointScope {
|
|
return discreteCopy(s, site)
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Backup Details Filtering
|
|
// ---------------------------------------------------------------------------
|
|
|
|
// Reduce filters the entries in a details struct to only those that match the
|
|
// inclusions, filters, and exclusions in the selector.
|
|
func (s sharePoint) Reduce(
|
|
ctx context.Context,
|
|
deets *details.Details,
|
|
errs *fault.Bus,
|
|
) *details.Details {
|
|
return reduce[SharePointScope](
|
|
ctx,
|
|
deets,
|
|
s.Selector,
|
|
map[path.CategoryType]sharePointCategory{
|
|
path.LibrariesCategory: SharePointLibraryItem,
|
|
path.ListsCategory: SharePointListItem,
|
|
path.PagesCategory: SharePointPage,
|
|
},
|
|
errs)
|
|
}
|
|
|
|
// matchesInfo handles the standard behavior when comparing a scope and an sharePointInfo
|
|
// returns true if the scope and info match for the provided category.
|
|
func (s SharePointScope) matchesInfo(dii details.ItemInfo) bool {
|
|
var (
|
|
filterCat = s.FilterCategory()
|
|
i = ""
|
|
info = dii.SharePoint
|
|
)
|
|
|
|
if info == nil {
|
|
return false
|
|
}
|
|
|
|
switch filterCat {
|
|
case SharePointWebURL:
|
|
i = info.WebURL
|
|
case SharePointFilterCreatedAfter, SharePointFilterCreatedBefore:
|
|
i = common.FormatTime(info.Created)
|
|
case SharePointFilterModifiedAfter, SharePointFilterModifiedBefore:
|
|
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)
|
|
}
|