applies folder matching behavior to cli input (#1443)
## Description Allows users to specify whether they want to select folders by prefix or search behavior. Search/contains behavior is the default case, with prefix being an optional deviation if the folder input is prepended with a '/' character. Also, propagates the PrefixMatch setting to all integration tests that rely on selecting only the default folder in exchange. ## Type of change - [x] 🌻 Feature ## Issue(s) * #1224 ## Test Plan - [x] 💪 Manual - [x] ⚡ Unit test - [x] 💚 E2E
This commit is contained in:
parent
b20e7af533
commit
20795d3b56
@ -54,7 +54,7 @@ type ExchangeOpts struct {
|
|||||||
func AddExchangeInclude(
|
func AddExchangeInclude(
|
||||||
sel *selectors.ExchangeRestore,
|
sel *selectors.ExchangeRestore,
|
||||||
resource, folders, items []string,
|
resource, folders, items []string,
|
||||||
incl func([]string, []string, []string) []selectors.ExchangeScope,
|
eisc selectors.ExchangeItemScopeConstructor,
|
||||||
) {
|
) {
|
||||||
lf, li := len(folders), len(items)
|
lf, li := len(folders), len(items)
|
||||||
|
|
||||||
@ -68,15 +68,19 @@ func AddExchangeInclude(
|
|||||||
resource = selectors.Any()
|
resource = selectors.Any()
|
||||||
}
|
}
|
||||||
|
|
||||||
if lf == 0 {
|
|
||||||
folders = selectors.Any()
|
|
||||||
}
|
|
||||||
|
|
||||||
if li == 0 {
|
if li == 0 {
|
||||||
items = selectors.Any()
|
items = selectors.Any()
|
||||||
}
|
}
|
||||||
|
|
||||||
sel.Include(incl(resource, folders, items))
|
containsFolders, prefixFolders := splitFoldersIntoContainsAndPrefix(folders)
|
||||||
|
|
||||||
|
if len(containsFolders) > 0 {
|
||||||
|
sel.Include(eisc(resource, containsFolders, items))
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(prefixFolders) > 0 {
|
||||||
|
sel.Include(eisc(resource, prefixFolders, items, selectors.PrefixMatch()))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddExchangeFilter adds the scope of the provided values to the selector's
|
// AddExchangeFilter adds the scope of the provided values to the selector's
|
||||||
|
|||||||
@ -19,7 +19,7 @@ func TestExchangeUtilsSuite(t *testing.T) {
|
|||||||
suite.Run(t, new(ExchangeUtilsSuite))
|
suite.Run(t, new(ExchangeUtilsSuite))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (suite *ExchangeUtilsSuite) TestValidateBackupDetailFlags() {
|
func (suite *ExchangeUtilsSuite) TestValidateRestoreFlags() {
|
||||||
table := []struct {
|
table := []struct {
|
||||||
name string
|
name string
|
||||||
backupID string
|
backupID string
|
||||||
@ -56,7 +56,7 @@ func (suite *ExchangeUtilsSuite) TestValidateBackupDetailFlags() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (suite *ExchangeUtilsSuite) TestIncludeExchangeBackupDetailDataSelectors() {
|
func (suite *ExchangeUtilsSuite) TestIncludeExchangeRestoreDataSelectors() {
|
||||||
stub := []string{"id-stub"}
|
stub := []string{"id-stub"}
|
||||||
many := []string{"fnord", "smarf"}
|
many := []string{"fnord", "smarf"}
|
||||||
a := []string{utils.Wildcard}
|
a := []string{utils.Wildcard}
|
||||||
@ -308,7 +308,76 @@ func (suite *ExchangeUtilsSuite) TestIncludeExchangeBackupDetailDataSelectors()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (suite *ExchangeUtilsSuite) TestFilterExchangeBackupDetailInfoSelectors() {
|
func (suite *ExchangeUtilsSuite) TestAddExchangeInclude() {
|
||||||
|
var (
|
||||||
|
empty = []string{}
|
||||||
|
single = []string{"single"}
|
||||||
|
multi = []string{"more", "than", "one"}
|
||||||
|
containsOnly = []string{"contains"}
|
||||||
|
prefixOnly = []string{"/prefix"}
|
||||||
|
containsAndPrefix = []string{"contains", "/prefix"}
|
||||||
|
eisc = selectors.NewExchangeRestore().Contacts // type independent, just need the func
|
||||||
|
)
|
||||||
|
|
||||||
|
table := []struct {
|
||||||
|
name string
|
||||||
|
resources, folders, items []string
|
||||||
|
expectIncludeLen int
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "no inputs",
|
||||||
|
resources: empty,
|
||||||
|
folders: empty,
|
||||||
|
items: empty,
|
||||||
|
expectIncludeLen: 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "single inputs",
|
||||||
|
resources: single,
|
||||||
|
folders: single,
|
||||||
|
items: single,
|
||||||
|
expectIncludeLen: 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "multi inputs",
|
||||||
|
resources: multi,
|
||||||
|
folders: multi,
|
||||||
|
items: multi,
|
||||||
|
expectIncludeLen: 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "folder contains",
|
||||||
|
resources: empty,
|
||||||
|
folders: containsOnly,
|
||||||
|
items: empty,
|
||||||
|
expectIncludeLen: 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "folder prefixes",
|
||||||
|
resources: empty,
|
||||||
|
folders: prefixOnly,
|
||||||
|
items: empty,
|
||||||
|
expectIncludeLen: 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "folder prefixes and contains",
|
||||||
|
resources: empty,
|
||||||
|
folders: containsAndPrefix,
|
||||||
|
items: empty,
|
||||||
|
expectIncludeLen: 2,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, test := range table {
|
||||||
|
suite.T().Run(test.name, func(t *testing.T) {
|
||||||
|
sel := selectors.NewExchangeRestore()
|
||||||
|
// no return, mutates sel as a side effect
|
||||||
|
utils.AddExchangeInclude(sel, test.resources, test.folders, test.items, eisc)
|
||||||
|
assert.Len(t, sel.Includes, test.expectIncludeLen)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (suite *ExchangeUtilsSuite) TestFilterExchangeRestoreInfoSelectors() {
|
||||||
stub := "id-stub"
|
stub := "id-stub"
|
||||||
|
|
||||||
table := []struct {
|
table := []struct {
|
||||||
|
|||||||
@ -74,12 +74,18 @@ func IncludeOneDriveRestoreDataSelectors(
|
|||||||
sel *selectors.OneDriveRestore,
|
sel *selectors.OneDriveRestore,
|
||||||
opts OneDriveOpts,
|
opts OneDriveOpts,
|
||||||
) {
|
) {
|
||||||
|
lp, ln := len(opts.Paths), len(opts.Names)
|
||||||
|
|
||||||
|
// only use the inclusion if either a path or item name
|
||||||
|
// is specified
|
||||||
|
if lp+ln == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if len(opts.Users) == 0 {
|
if len(opts.Users) == 0 {
|
||||||
opts.Users = selectors.Any()
|
opts.Users = selectors.Any()
|
||||||
}
|
}
|
||||||
|
|
||||||
lp, ln := len(opts.Paths), len(opts.Names)
|
|
||||||
|
|
||||||
// either scope the request to a set of users
|
// either scope the request to a set of users
|
||||||
if lp+ln == 0 {
|
if lp+ln == 0 {
|
||||||
sel.Include(sel.Users(opts.Users))
|
sel.Include(sel.Users(opts.Users))
|
||||||
@ -89,15 +95,19 @@ func IncludeOneDriveRestoreDataSelectors(
|
|||||||
|
|
||||||
opts.Paths = trimFolderSlash(opts.Paths)
|
opts.Paths = trimFolderSlash(opts.Paths)
|
||||||
|
|
||||||
if lp == 0 {
|
|
||||||
opts.Paths = selectors.Any()
|
|
||||||
}
|
|
||||||
|
|
||||||
if ln == 0 {
|
if ln == 0 {
|
||||||
opts.Names = selectors.Any()
|
opts.Names = selectors.Any()
|
||||||
}
|
}
|
||||||
|
|
||||||
sel.Include(sel.Items(opts.Users, opts.Paths, opts.Names))
|
containsFolders, prefixFolders := splitFoldersIntoContainsAndPrefix(opts.Paths)
|
||||||
|
|
||||||
|
if len(containsFolders) > 0 {
|
||||||
|
sel.Include(sel.Items(opts.Users, containsFolders, opts.Names))
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(prefixFolders) > 0 {
|
||||||
|
sel.Include(sel.Items(opts.Users, prefixFolders, opts.Names, selectors.PrefixMatch()))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// FilterOneDriveRestoreInfoSelectors builds the common info-selector filters.
|
// FilterOneDriveRestoreInfoSelectors builds the common info-selector filters.
|
||||||
|
|||||||
90
src/cli/utils/onedrive_test.go
Normal file
90
src/cli/utils/onedrive_test.go
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
package utils_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
|
||||||
|
"github.com/alcionai/corso/src/cli/utils"
|
||||||
|
"github.com/alcionai/corso/src/pkg/selectors"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (suite *ExchangeUtilsSuite) TestIncludeOneDriveRestoreDataSelectors() {
|
||||||
|
var (
|
||||||
|
empty = []string{}
|
||||||
|
single = []string{"single"}
|
||||||
|
multi = []string{"more", "than", "one"}
|
||||||
|
containsOnly = []string{"contains"}
|
||||||
|
prefixOnly = []string{"/prefix"}
|
||||||
|
containsAndPrefix = []string{"contains", "/prefix"}
|
||||||
|
)
|
||||||
|
|
||||||
|
table := []struct {
|
||||||
|
name string
|
||||||
|
opts utils.OneDriveOpts
|
||||||
|
expectIncludeLen int
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "no inputs",
|
||||||
|
opts: utils.OneDriveOpts{
|
||||||
|
Users: empty,
|
||||||
|
Paths: empty,
|
||||||
|
Names: empty,
|
||||||
|
},
|
||||||
|
expectIncludeLen: 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "single inputs",
|
||||||
|
opts: utils.OneDriveOpts{
|
||||||
|
Users: single,
|
||||||
|
Paths: single,
|
||||||
|
Names: single,
|
||||||
|
},
|
||||||
|
expectIncludeLen: 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "multi inputs",
|
||||||
|
opts: utils.OneDriveOpts{
|
||||||
|
Users: multi,
|
||||||
|
Paths: multi,
|
||||||
|
Names: multi,
|
||||||
|
},
|
||||||
|
expectIncludeLen: 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "folder contains",
|
||||||
|
opts: utils.OneDriveOpts{
|
||||||
|
Users: empty,
|
||||||
|
Paths: containsOnly,
|
||||||
|
Names: empty,
|
||||||
|
},
|
||||||
|
expectIncludeLen: 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "folder prefixes",
|
||||||
|
opts: utils.OneDriveOpts{
|
||||||
|
Users: empty,
|
||||||
|
Paths: prefixOnly,
|
||||||
|
Names: empty,
|
||||||
|
},
|
||||||
|
expectIncludeLen: 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "folder prefixes and contains",
|
||||||
|
opts: utils.OneDriveOpts{
|
||||||
|
Users: empty,
|
||||||
|
Paths: containsAndPrefix,
|
||||||
|
Names: empty,
|
||||||
|
},
|
||||||
|
expectIncludeLen: 2,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, test := range table {
|
||||||
|
suite.T().Run(test.name, func(t *testing.T) {
|
||||||
|
sel := selectors.NewOneDriveRestore()
|
||||||
|
// no return, mutates sel as a side effect
|
||||||
|
utils.IncludeOneDriveRestoreDataSelectors(sel, test.opts)
|
||||||
|
assert.Len(t, sel.Includes, test.expectIncludeLen)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -8,7 +8,9 @@ import (
|
|||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
"github.com/spf13/pflag"
|
"github.com/spf13/pflag"
|
||||||
|
|
||||||
|
"github.com/alcionai/corso/src/pkg/path"
|
||||||
"github.com/alcionai/corso/src/pkg/repository"
|
"github.com/alcionai/corso/src/pkg/repository"
|
||||||
|
"github.com/alcionai/corso/src/pkg/selectors"
|
||||||
)
|
)
|
||||||
|
|
||||||
// common flag names
|
// common flag names
|
||||||
@ -64,3 +66,34 @@ func AddCommand(parent, c *cobra.Command) (*cobra.Command, *pflag.FlagSet) {
|
|||||||
|
|
||||||
return c, c.Flags()
|
return c, c.Flags()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// separates the provided folders into two sets: folders that use a pathContains
|
||||||
|
// comparison (the default), and folders that use a pathPrefix comparison.
|
||||||
|
// Any element beginning with a path.PathSeparator (ie: '/') is moved to the prefix
|
||||||
|
// comparison set. If folders is nil, returns only containsFolders with the any matcher.
|
||||||
|
func splitFoldersIntoContainsAndPrefix(folders []string) ([]string, []string) {
|
||||||
|
var (
|
||||||
|
containsFolders = []string{}
|
||||||
|
prefixFolders = []string{}
|
||||||
|
)
|
||||||
|
|
||||||
|
if len(folders) == 0 {
|
||||||
|
return selectors.Any(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// separate folder selection inputs by behavior.
|
||||||
|
// any input beginning with a '/' character acts as a prefix match.
|
||||||
|
for _, f := range folders {
|
||||||
|
if len(f) == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if f[0] == path.PathSeparator {
|
||||||
|
prefixFolders = append(prefixFolders, f)
|
||||||
|
} else {
|
||||||
|
containsFolders = append(containsFolders, f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return containsFolders, prefixFolders
|
||||||
|
}
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
package utils_test
|
package utils
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
@ -6,7 +6,7 @@ import (
|
|||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/suite"
|
"github.com/stretchr/testify/suite"
|
||||||
|
|
||||||
"github.com/alcionai/corso/src/cli/utils"
|
"github.com/alcionai/corso/src/pkg/selectors"
|
||||||
)
|
)
|
||||||
|
|
||||||
type CliUtilsSuite struct {
|
type CliUtilsSuite struct {
|
||||||
@ -33,6 +33,52 @@ func (suite *CliUtilsSuite) TestRequireProps() {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
for _, test := range table {
|
for _, test := range table {
|
||||||
test.errCheck(suite.T(), utils.RequireProps(test.props))
|
test.errCheck(suite.T(), RequireProps(test.props))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (suite *CliUtilsSuite) TestSplitFoldersIntoContainsAndPrefix() {
|
||||||
|
table := []struct {
|
||||||
|
name string
|
||||||
|
input []string
|
||||||
|
expectC []string
|
||||||
|
expectP []string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "empty",
|
||||||
|
expectC: selectors.Any(),
|
||||||
|
expectP: nil,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "only contains",
|
||||||
|
input: []string{"a", "b", "c"},
|
||||||
|
expectC: []string{"a", "b", "c"},
|
||||||
|
expectP: []string{},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "only leading slash counts as contains",
|
||||||
|
input: []string{"a/////", "\\/b", "\\//c\\/"},
|
||||||
|
expectC: []string{"a/////", "\\/b", "\\//c\\/"},
|
||||||
|
expectP: []string{},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "only prefix",
|
||||||
|
input: []string{"/a", "/b", "/\\/c"},
|
||||||
|
expectC: []string{},
|
||||||
|
expectP: []string{"/a", "/b", "/\\/c"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "mixed",
|
||||||
|
input: []string{"/a", "b", "/c"},
|
||||||
|
expectC: []string{"b"},
|
||||||
|
expectP: []string{"/a", "/c"},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, test := range table {
|
||||||
|
suite.T().Run(test.name, func(t *testing.T) {
|
||||||
|
c, p := splitFoldersIntoContainsAndPrefix(test.input)
|
||||||
|
assert.ElementsMatch(t, test.expectC, c, "contains set")
|
||||||
|
assert.ElementsMatch(t, test.expectP, p, "prefix set")
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -277,7 +277,7 @@ func (suite *ServiceFunctionsIntegrationSuite) TestGetAllMailFolders() {
|
|||||||
getScope: func(t *testing.T) selectors.ExchangeScope {
|
getScope: func(t *testing.T) selectors.ExchangeScope {
|
||||||
return selectors.
|
return selectors.
|
||||||
NewExchangeBackup().
|
NewExchangeBackup().
|
||||||
MailFolders([]string{userID}, []string{nonExistantLookup})[0]
|
MailFolders([]string{userID}, []string{nonExistantLookup}, selectors.PrefixMatch())[0]
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
@ -166,6 +166,8 @@ func (s *exchange) DiscreteScopes(userPNs []string) []ExchangeScope {
|
|||||||
return discreteScopes[ExchangeScope](s.Selector, ExchangeUser, userPNs)
|
return discreteScopes[ExchangeScope](s.Selector, ExchangeUser, userPNs)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ExchangeItemScopeConstructor func([]string, []string, []string, ...option) []ExchangeScope
|
||||||
|
|
||||||
// -------------------
|
// -------------------
|
||||||
// Scope Factories
|
// Scope Factories
|
||||||
|
|
||||||
@ -173,13 +175,14 @@ func (s *exchange) DiscreteScopes(userPNs []string) []ExchangeScope {
|
|||||||
// 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 *exchange) Contacts(users, folders, contacts []string) []ExchangeScope {
|
// options are only applied to the folder scopes.
|
||||||
|
func (s *exchange) Contacts(users, folders, contacts []string, opts ...option) []ExchangeScope {
|
||||||
scopes := []ExchangeScope{}
|
scopes := []ExchangeScope{}
|
||||||
|
|
||||||
scopes = append(
|
scopes = append(
|
||||||
scopes,
|
scopes,
|
||||||
makeScope[ExchangeScope](ExchangeContact, users, contacts).
|
makeScope[ExchangeScope](ExchangeContact, users, contacts).
|
||||||
set(ExchangeContactFolder, folders),
|
set(ExchangeContactFolder, folders, opts...),
|
||||||
)
|
)
|
||||||
|
|
||||||
return scopes
|
return scopes
|
||||||
@ -189,6 +192,7 @@ func (s *exchange) Contacts(users, folders, contacts []string) []ExchangeScope {
|
|||||||
// 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]
|
||||||
|
// options are only applied to the folder scopes.
|
||||||
func (s *exchange) ContactFolders(users, folders []string, opts ...option) []ExchangeScope {
|
func (s *exchange) ContactFolders(users, folders []string, opts ...option) []ExchangeScope {
|
||||||
var (
|
var (
|
||||||
scopes = []ExchangeScope{}
|
scopes = []ExchangeScope{}
|
||||||
@ -207,13 +211,14 @@ func (s *exchange) ContactFolders(users, folders []string, opts ...option) []Exc
|
|||||||
// 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 *exchange) Events(users, calendars, events []string) []ExchangeScope {
|
// options are only applied to the folder scopes.
|
||||||
|
func (s *exchange) Events(users, calendars, events []string, opts ...option) []ExchangeScope {
|
||||||
scopes := []ExchangeScope{}
|
scopes := []ExchangeScope{}
|
||||||
|
|
||||||
scopes = append(
|
scopes = append(
|
||||||
scopes,
|
scopes,
|
||||||
makeScope[ExchangeScope](ExchangeEvent, users, events).
|
makeScope[ExchangeScope](ExchangeEvent, users, events).
|
||||||
set(ExchangeEventCalendar, calendars),
|
set(ExchangeEventCalendar, calendars, opts...),
|
||||||
)
|
)
|
||||||
|
|
||||||
return scopes
|
return scopes
|
||||||
@ -224,6 +229,7 @@ func (s *exchange) Events(users, calendars, events []string) []ExchangeScope {
|
|||||||
// 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]
|
||||||
|
// options are only applied to the folder scopes.
|
||||||
func (s *exchange) EventCalendars(users, events []string, opts ...option) []ExchangeScope {
|
func (s *exchange) EventCalendars(users, events []string, opts ...option) []ExchangeScope {
|
||||||
var (
|
var (
|
||||||
scopes = []ExchangeScope{}
|
scopes = []ExchangeScope{}
|
||||||
@ -242,13 +248,14 @@ func (s *exchange) EventCalendars(users, events []string, opts ...option) []Exch
|
|||||||
// 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 *exchange) Mails(users, folders, mails []string) []ExchangeScope {
|
// options are only applied to the folder scopes.
|
||||||
|
func (s *exchange) Mails(users, folders, mails []string, opts ...option) []ExchangeScope {
|
||||||
scopes := []ExchangeScope{}
|
scopes := []ExchangeScope{}
|
||||||
|
|
||||||
scopes = append(
|
scopes = append(
|
||||||
scopes,
|
scopes,
|
||||||
makeScope[ExchangeScope](ExchangeMail, users, mails).
|
makeScope[ExchangeScope](ExchangeMail, users, mails).
|
||||||
set(ExchangeMailFolder, folders),
|
set(ExchangeMailFolder, folders, opts...),
|
||||||
)
|
)
|
||||||
|
|
||||||
return scopes
|
return scopes
|
||||||
@ -258,6 +265,7 @@ func (s *exchange) Mails(users, folders, mails []string) []ExchangeScope {
|
|||||||
// 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]
|
||||||
|
// options are only applied to the folder scopes.
|
||||||
func (s *exchange) MailFolders(users, folders []string, opts ...option) []ExchangeScope {
|
func (s *exchange) MailFolders(users, folders []string, opts ...option) []ExchangeScope {
|
||||||
var (
|
var (
|
||||||
scopes = []ExchangeScope{}
|
scopes = []ExchangeScope{}
|
||||||
|
|||||||
@ -179,6 +179,7 @@ func (s *oneDrive) Users(users []string) []OneDriveScope {
|
|||||||
// 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]
|
||||||
|
// options are only applied to the folder scopes.
|
||||||
func (s *oneDrive) Folders(users, folders []string, opts ...option) []OneDriveScope {
|
func (s *oneDrive) Folders(users, folders []string, opts ...option) []OneDriveScope {
|
||||||
var (
|
var (
|
||||||
scopes = []OneDriveScope{}
|
scopes = []OneDriveScope{}
|
||||||
@ -197,13 +198,14 @@ func (s *oneDrive) Folders(users, folders []string, opts ...option) []OneDriveSc
|
|||||||
// 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 *oneDrive) Items(users, folders, items []string) []OneDriveScope {
|
// options are only applied to the folder scopes.
|
||||||
|
func (s *oneDrive) Items(users, folders, items []string, opts ...option) []OneDriveScope {
|
||||||
scopes := []OneDriveScope{}
|
scopes := []OneDriveScope{}
|
||||||
|
|
||||||
scopes = append(
|
scopes = append(
|
||||||
scopes,
|
scopes,
|
||||||
makeScope[OneDriveScope](OneDriveItem, users, items).
|
makeScope[OneDriveScope](OneDriveItem, users, items).
|
||||||
set(OneDriveFolder, folders),
|
set(OneDriveFolder, folders, opts...),
|
||||||
)
|
)
|
||||||
|
|
||||||
return scopes
|
return scopes
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user