add channels info filters to selectors (#4093)

Adds groups channel message filters to group selectors. Includes scopes for message creation time, last response time, and message created by.

---

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

- [x]  No

#### Type of change

- [x] 🌻 Feature

#### Issue(s)

* #3989

#### Test Plan

- [x]  Unit test
- [x] 💚 E2E
This commit is contained in:
Keepers 2023-08-25 12:09:20 -06:00 committed by GitHub
parent bf29443ad4
commit e96c21d342
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 430 additions and 285 deletions

View File

@ -49,7 +49,7 @@ type GroupsInfo struct {
// Channels Specific // Channels Specific
ChannelName string `json:"channelName,omitempty"` ChannelName string `json:"channelName,omitempty"`
ChannelID string `json:"channelID,omitempty"` ChannelID string `json:"channelID,omitempty"`
LastResponseAt time.Time `json:"lastResponseAt,omitempty"` LastReplyAt time.Time `json:"lastResponseAt,omitempty"`
MessageCreator string `json:"messageCreator,omitempty"` MessageCreator string `json:"messageCreator,omitempty"`
MessagePreview string `json:"messagePreview,omitempty"` MessagePreview string `json:"messagePreview,omitempty"`
ReplyCount int `json:"replyCount,omitempty"` ReplyCount int `json:"replyCount,omitempty"`

View File

@ -335,7 +335,7 @@ func (s *exchange) AllData() []ExchangeScope {
} }
// ------------------- // -------------------
// Info Factories // ItemInfo Factories
// ContactName produces one or more exchange contact name info scopes. // ContactName produces one or more exchange contact name info scopes.
// Matches any contact whose name contains the provided string. // Matches any contact whose name contains the provided string.
@ -352,7 +352,7 @@ func (sr *ExchangeRestore) ContactName(senderID string) []ExchangeScope {
} }
} }
// EventSubject produces one or more exchange event subject info scopes. // EventOrganizer produces one or more exchange event subject info scopes.
// Matches any event where the event subject contains one of the provided strings. // Matches any event where the event subject contains one of the provided strings.
// 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]

View File

@ -6,6 +6,7 @@ import (
"github.com/alcionai/clues" "github.com/alcionai/clues"
"github.com/alcionai/corso/src/internal/common/dttm"
"github.com/alcionai/corso/src/pkg/backup/details" "github.com/alcionai/corso/src/pkg/backup/details"
"github.com/alcionai/corso/src/pkg/backup/identity" "github.com/alcionai/corso/src/pkg/backup/identity"
"github.com/alcionai/corso/src/pkg/fault" "github.com/alcionai/corso/src/pkg/fault"
@ -242,7 +243,7 @@ func (s *groups) Channel(channel string) []GroupsScope {
// 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) ChannelMessages(channels, messages []string, opts ...option) []GroupsScope { func (s *groups) ChannelMessages(channels, messages []string, opts ...option) []GroupsScope {
var ( var (
scopes = []GroupsScope{} scopes = []GroupsScope{}
os = append([]option{pathComparator()}, opts...) os = append([]option{pathComparator()}, opts...)
@ -309,7 +310,76 @@ func (s *groups) LibraryItems(libraries, items []string, opts ...option) []Group
// ------------------- // -------------------
// ItemInfo Factories // ItemInfo Factories
// TODO // MessageCreator produces one or more groups channelMessage info scopes.
// Matches any channel message created by the specified user.
// 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 *GroupsRestore) MessageCreator(creator string) []GroupsScope {
return []GroupsScope{
makeInfoScope[GroupsScope](
GroupsChannelMessage,
GroupsInfoChannelMessageCreator,
[]string{creator},
filters.In),
}
}
// MessageCreatedAfter produces a channel message created-after info scope.
// Matches any message where the creation time is after the timestring.
// If the input equals selectors.Any, the scope will match all times.
// If the input is empty or selectors.None, the scope will always fail comparisons.
func (s *GroupsRestore) MessageCreatedAfter(timeStrings string) []GroupsScope {
return []GroupsScope{
makeInfoScope[GroupsScope](
GroupsChannelMessage,
GroupsInfoChannelMessageCreatedAfter,
[]string{timeStrings},
filters.Less),
}
}
// MessageCreatedBefore produces a channel message created-before info scope.
// Matches any message where the creation time is after the timestring.
// If the input equals selectors.Any, the scope will match all times.
// If the input is empty or selectors.None, the scope will always fail comparisons.
func (s *GroupsRestore) MessageCreatedBefore(timeStrings string) []GroupsScope {
return []GroupsScope{
makeInfoScope[GroupsScope](
GroupsChannelMessage,
GroupsInfoChannelMessageCreatedBefore,
[]string{timeStrings},
filters.Greater),
}
}
// MessageLastReplyAfter produces a channel message last-response-after info scope.
// Matches any message where last response time is after the timestring.
// If the input equals selectors.Any, the scope will match all times.
// If the input is empty or selectors.None, the scope will always fail comparisons.
func (s *GroupsRestore) MessageLastReplyAfter(timeStrings string) []GroupsScope {
return []GroupsScope{
makeInfoScope[GroupsScope](
GroupsChannelMessage,
GroupsInfoChannelMessageLastReplyAfter,
[]string{timeStrings},
filters.Less),
}
}
// MessageLastReplyBefore produces a channel message last-response-before info scope.
// Matches any message where last response time is after the timestring.
// If the input equals selectors.Any, the scope will match all times.
// If the input is empty or selectors.None, the scope will always fail comparisons.
func (s *GroupsRestore) MessageLastReplyBefore(timeStrings string) []GroupsScope {
return []GroupsScope{
makeInfoScope[GroupsScope](
GroupsChannelMessage,
GroupsInfoChannelMessageLastReplyBefore,
[]string{timeStrings},
filters.Greater),
}
}
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// Categories // Categories
@ -334,9 +404,16 @@ const (
// details.itemInfo comparables // details.itemInfo comparables
// channel drive selection // channel and drive selection
GroupsInfoSiteLibraryDrive groupsCategory = "GroupsInfoSiteLibraryDrive" GroupsInfoSiteLibraryDrive groupsCategory = "GroupsInfoSiteLibraryDrive"
GroupsInfoChannel groupsCategory = "GroupsInfoChannel" GroupsInfoChannel groupsCategory = "GroupsInfoChannel"
// data contained within details.ItemInfo
GroupsInfoChannelMessageCreatedAfter groupsCategory = "GroupsInfoChannelMessageCreatedAfter"
GroupsInfoChannelMessageCreatedBefore groupsCategory = "GroupsInfoChannelMessageCreatedBefore"
GroupsInfoChannelMessageCreator groupsCategory = "GroupsInfoChannelMessageCreator"
GroupsInfoChannelMessageLastReplyAfter groupsCategory = "GroupsInfoChannelMessageLastReplyAfter"
GroupsInfoChannelMessageLastReplyBefore groupsCategory = "GroupsInfoChannelMessageLastReplyBefore"
) )
// groupsLeafProperties describes common metadata of the leaf categories // groupsLeafProperties describes common metadata of the leaf categories
@ -368,7 +445,9 @@ func (c groupsCategory) leafCat() categorizer {
switch c { switch c {
// TODO: if channels ever contain more than one type of item, // TODO: if channels ever contain more than one type of item,
// we'll need to fix this up. // we'll need to fix this up.
case GroupsChannel, GroupsChannelMessage: case GroupsChannel, GroupsChannelMessage,
GroupsInfoChannelMessageCreatedAfter, GroupsInfoChannelMessageCreatedBefore, GroupsInfoChannelMessageCreator,
GroupsInfoChannelMessageLastReplyAfter, GroupsInfoChannelMessageLastReplyBefore:
return GroupsChannelMessage return GroupsChannelMessage
case GroupsLibraryFolder, GroupsLibraryItem, GroupsInfoSiteLibraryDrive: case GroupsLibraryFolder, GroupsLibraryItem, GroupsInfoSiteLibraryDrive:
return GroupsLibraryItem return GroupsLibraryItem
@ -414,15 +493,15 @@ func (c groupsCategory) pathValues(
rFld string rFld string
) )
if ent.Groups == nil {
return nil, clues.New("no Groups ItemInfo in details")
}
switch c { switch c {
case GroupsChannel, GroupsChannelMessage: case GroupsChannel, GroupsChannelMessage:
folderCat, itemCat = GroupsChannel, GroupsChannelMessage folderCat, itemCat = GroupsChannel, GroupsChannelMessage
rFld = ent.Groups.ParentPath rFld = ent.Groups.ParentPath
case GroupsLibraryFolder, GroupsLibraryItem: case GroupsLibraryFolder, GroupsLibraryItem:
if ent.Groups == nil {
return nil, clues.New("no Groups ItemInfo in details")
}
folderCat, itemCat = GroupsLibraryFolder, GroupsLibraryItem folderCat, itemCat = GroupsLibraryFolder, GroupsLibraryItem
rFld = ent.Groups.ParentPath rFld = ent.Groups.ParentPath
default: default:
@ -591,8 +670,23 @@ func (s GroupsScope) matchesInfo(dii details.ItemInfo) bool {
return matchesAny(s, GroupsInfoSiteLibraryDrive, ds) return matchesAny(s, GroupsInfoSiteLibraryDrive, ds)
case GroupsInfoChannel: case GroupsInfoChannel:
ds := Any() ds := []string{}
if len(info.ChannelID) > 0 {
ds = append(ds, info.ChannelID)
}
if len(info.ChannelName) > 0 {
ds = append(ds, info.ChannelName)
}
return matchesAny(s, GroupsInfoChannel, ds) return matchesAny(s, GroupsInfoChannel, ds)
case GroupsInfoChannelMessageCreator:
i = info.MessageCreator
case GroupsInfoChannelMessageCreatedAfter, GroupsInfoChannelMessageCreatedBefore:
i = dttm.Format(info.Created)
case GroupsInfoChannelMessageLastReplyAfter, GroupsInfoChannelMessageLastReplyBefore:
i = dttm.Format(info.LastReplyAt)
} }
return s.Matches(infoCat, i) return s.Matches(infoCat, i)

View File

@ -1,15 +1,21 @@
package selectors package selectors
import ( import (
"strings"
"testing" "testing"
"time"
"github.com/alcionai/clues" "github.com/alcionai/clues"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"github.com/stretchr/testify/suite" "github.com/stretchr/testify/suite"
"golang.org/x/exp/slices"
"github.com/alcionai/corso/src/internal/common/dttm"
odConsts "github.com/alcionai/corso/src/internal/m365/service/onedrive/consts"
"github.com/alcionai/corso/src/internal/tester" "github.com/alcionai/corso/src/internal/tester"
"github.com/alcionai/corso/src/pkg/backup/details" "github.com/alcionai/corso/src/pkg/backup/details"
"github.com/alcionai/corso/src/pkg/fault"
"github.com/alcionai/corso/src/pkg/path" "github.com/alcionai/corso/src/pkg/path"
) )
@ -55,211 +61,236 @@ func (suite *GroupsSelectorSuite) TestToGroupsRestore() {
assert.NotZero(t, or.Scopes()) assert.NotZero(t, or.Scopes())
} }
// TODO(rkeepers): implement func (suite *GroupsSelectorSuite) TestGroupsRestore_Reduce() {
// func (suite *GroupsSelectorSuite) TestGroupsRestore_Reduce() { toRR := func(cat path.CategoryType, midID string, folders []string, item string) string {
// toRR := func(cat path.CategoryType, siteID string, folders []string, item string) string { var (
// folderElems := make([]string, 0, len(folders)) folderElems = make([]string, 0, len(folders))
isDrive = cat == path.LibrariesCategory
)
// for _, f := range folders { for _, f := range folders {
// folderElems = append(folderElems, f+".d") if isDrive {
// } f = f + ".d"
}
// return stubRepoRef( folderElems = append(folderElems, f)
// path.GroupsService, }
// cat,
// siteID,
// strings.Join(folderElems, "/"),
// item)
// }
// var ( return stubRepoRef(
// prefixElems = []string{ path.GroupsService,
// odConsts.DrivesPathDir, cat,
// "drive!id", midID,
// odConsts.RootPathDir, strings.Join(folderElems, "/"),
// } item)
// itemElems1 = []string{"folderA", "folderB"} }
// itemElems2 = []string{"folderA", "folderC"}
// itemElems3 = []string{"folderD", "folderE"}
// pairAC = "folderA/folderC"
// pairGH = "folderG/folderH"
// item = toRR(
// path.LibrariesCategory,
// "sid",
// append(slices.Clone(prefixElems), itemElems1...),
// "item")
// item2 = toRR(
// path.LibrariesCategory,
// "sid",
// append(slices.Clone(prefixElems), itemElems2...),
// "item2")
// item3 = toRR(
// path.LibrariesCategory,
// "sid",
// append(slices.Clone(prefixElems), itemElems3...),
// "item3")
// item4 = stubRepoRef(path.GroupsService, path.PagesCategory, "sid", pairGH, "item4")
// item5 = stubRepoRef(path.GroupsService, path.PagesCategory, "sid", pairGH, "item5")
// )
// deets := &details.Details{ var (
// DetailsModel: details.DetailsModel{ drivePrefixElems = []string{
// Entries: []details.Entry{ odConsts.DrivesPathDir,
// { "drive!id",
// RepoRef: item, odConsts.RootPathDir,
// ItemRef: "item", }
// LocationRef: strings.Join(append([]string{odConsts.RootPathDir}, itemElems1...), "/"), itemElems1 = []string{"folderA", "folderB"}
// ItemInfo: details.ItemInfo{ itemElems2 = []string{"folderA", "folderC"}
// Groups: &details.GroupsInfo{ itemElems3 = []string{"folderD", "folderE"}
// ItemType: details.GroupsLibrary, pairAC = "folderA/folderC"
// ItemName: "itemName", libItem = toRR(
// ParentPath: strings.Join(itemElems1, "/"), path.LibrariesCategory,
// }, "sid",
// }, append(slices.Clone(drivePrefixElems), itemElems1...),
// }, "item")
// { libItem2 = toRR(
// RepoRef: item2, path.LibrariesCategory,
// LocationRef: strings.Join(append([]string{odConsts.RootPathDir}, itemElems2...), "/"), "sid",
// // ItemRef intentionally blank to test fallback case append(slices.Clone(drivePrefixElems), itemElems2...),
// ItemInfo: details.ItemInfo{ "item2")
// Groups: &details.GroupsInfo{ libItem3 = toRR(
// ItemType: details.GroupsLibrary, path.LibrariesCategory,
// ItemName: "itemName2", "sid",
// ParentPath: strings.Join(itemElems2, "/"), append(slices.Clone(drivePrefixElems), itemElems3...),
// }, "item3")
// }, chanItem = toRR(path.ChannelMessagesCategory, "gid", slices.Clone(itemElems1), "chitem")
// }, chanItem2 = toRR(path.ChannelMessagesCategory, "gid", slices.Clone(itemElems2), "chitem2")
// { chanItem3 = toRR(path.ChannelMessagesCategory, "gid", slices.Clone(itemElems3), "chitem3")
// RepoRef: item3, )
// ItemRef: "item3",
// LocationRef: strings.Join(append([]string{odConsts.RootPathDir}, itemElems3...), "/"),
// ItemInfo: details.ItemInfo{
// Groups: &details.GroupsInfo{
// ItemType: details.GroupsLibrary,
// ItemName: "itemName3",
// ParentPath: strings.Join(itemElems3, "/"),
// },
// },
// },
// {
// RepoRef: item4,
// LocationRef: pairGH,
// ItemRef: "item4",
// ItemInfo: details.ItemInfo{
// Groups: &details.GroupsInfo{
// ItemType: details.GroupsPage,
// ItemName: "itemName4",
// ParentPath: pairGH,
// },
// },
// },
// {
// RepoRef: item5,
// LocationRef: pairGH,
// // ItemRef intentionally blank to test fallback case
// ItemInfo: details.ItemInfo{
// Groups: &details.GroupsInfo{
// ItemType: details.GroupsPage,
// ItemName: "itemName5",
// ParentPath: pairGH,
// },
// },
// },
// },
// },
// }
// arr := func(s ...string) []string { deets := &details.Details{
// return s DetailsModel: details.DetailsModel{
// } Entries: []details.Entry{
{
RepoRef: libItem,
ItemRef: "item",
LocationRef: strings.Join(append([]string{odConsts.RootPathDir}, itemElems1...), "/"),
ItemInfo: details.ItemInfo{
Groups: &details.GroupsInfo{
ItemType: details.SharePointLibrary,
ItemName: "itemName",
ParentPath: strings.Join(itemElems1, "/"),
},
},
},
{
RepoRef: libItem2,
LocationRef: strings.Join(append([]string{odConsts.RootPathDir}, itemElems2...), "/"),
// ItemRef intentionally blank to test fallback case
ItemInfo: details.ItemInfo{
Groups: &details.GroupsInfo{
ItemType: details.SharePointLibrary,
ItemName: "itemName2",
ParentPath: strings.Join(itemElems2, "/"),
},
},
},
{
RepoRef: libItem3,
ItemRef: "item3",
LocationRef: strings.Join(append([]string{odConsts.RootPathDir}, itemElems3...), "/"),
ItemInfo: details.ItemInfo{
Groups: &details.GroupsInfo{
ItemType: details.SharePointLibrary,
ItemName: "itemName3",
ParentPath: strings.Join(itemElems3, "/"),
},
},
},
{
RepoRef: chanItem,
ItemRef: "citem",
LocationRef: strings.Join(itemElems1, "/"),
ItemInfo: details.ItemInfo{
Groups: &details.GroupsInfo{
ItemType: details.TeamsChannelMessage,
ParentPath: strings.Join(itemElems1, "/"),
},
},
},
{
RepoRef: chanItem2,
LocationRef: strings.Join(itemElems2, "/"),
// ItemRef intentionally blank to test fallback case
ItemInfo: details.ItemInfo{
Groups: &details.GroupsInfo{
ItemType: details.TeamsChannelMessage,
ParentPath: strings.Join(itemElems2, "/"),
},
},
},
{
RepoRef: chanItem3,
ItemRef: "citem3",
LocationRef: strings.Join(itemElems3, "/"),
ItemInfo: details.ItemInfo{
Groups: &details.GroupsInfo{
ItemType: details.TeamsChannelMessage,
ParentPath: strings.Join(itemElems3, "/"),
},
},
},
},
},
}
// table := []struct { arr := func(s ...string) []string {
// name string return s
// makeSelector func() *GroupsRestore }
// expect []string
// cfg Config
// }{
// {
// name: "all",
// makeSelector: func() *GroupsRestore {
// odr := NewGroupsRestore(Any())
// odr.Include(odr.AllData())
// return odr
// },
// expect: arr(item, item2, item3, item4, item5),
// },
// {
// name: "only match item",
// makeSelector: func() *GroupsRestore {
// odr := NewGroupsRestore(Any())
// odr.Include(odr.LibraryItems(Any(), []string{"item2"}))
// return odr
// },
// expect: arr(item2),
// },
// {
// name: "id doesn't match name",
// makeSelector: func() *GroupsRestore {
// odr := NewGroupsRestore(Any())
// odr.Include(odr.LibraryItems(Any(), []string{"item2"}))
// return odr
// },
// expect: []string{},
// cfg: Config{OnlyMatchItemNames: true},
// },
// {
// name: "only match item name",
// makeSelector: func() *GroupsRestore {
// odr := NewGroupsRestore(Any())
// odr.Include(odr.LibraryItems(Any(), []string{"itemName2"}))
// return odr
// },
// expect: arr(item2),
// cfg: Config{OnlyMatchItemNames: true},
// },
// {
// name: "name doesn't match",
// makeSelector: func() *GroupsRestore {
// odr := NewGroupsRestore(Any())
// odr.Include(odr.LibraryItems(Any(), []string{"itemName2"}))
// return odr
// },
// expect: []string{},
// },
// {
// name: "only match folder",
// makeSelector: func() *GroupsRestore {
// odr := NewGroupsRestore([]string{"sid"})
// odr.Include(odr.LibraryFolders([]string{"folderA/folderB", pairAC}))
// return odr
// },
// expect: arr(item, item2),
// },
// {
// name: "pages match folder",
// makeSelector: func() *GroupsRestore {
// odr := NewGroupsRestore([]string{"sid"})
// odr.Include(odr.Pages([]string{pairGH, pairAC}))
// return odr
// },
// expect: arr(item4, item5),
// },
// }
// for _, test := range table {
// suite.Run(test.name, func() {
// t := suite.T()
// ctx, flush := tester.NewContext(t) table := []struct {
// defer flush() name string
makeSelector func() *GroupsRestore
expect []string
cfg Config
}{
{
name: "all",
makeSelector: func() *GroupsRestore {
sel := NewGroupsRestore(Any())
sel.Include(sel.AllData())
return sel
},
expect: arr(libItem, libItem2, libItem3, chanItem, chanItem2, chanItem3),
},
{
name: "only match library item",
makeSelector: func() *GroupsRestore {
sel := NewGroupsRestore(Any())
sel.Include(sel.LibraryItems(Any(), []string{"item2"}))
return sel
},
expect: arr(libItem2),
},
{
name: "only match channel item",
makeSelector: func() *GroupsRestore {
sel := NewGroupsRestore(Any())
sel.Include(sel.ChannelMessages(Any(), []string{"chitem2"}))
return sel
},
expect: arr(chanItem2),
},
{
name: "library id doesn't match name",
makeSelector: func() *GroupsRestore {
sel := NewGroupsRestore(Any())
sel.Include(sel.LibraryItems(Any(), []string{"item2"}))
return sel
},
expect: []string{},
cfg: Config{OnlyMatchItemNames: true},
},
{
name: "channel id doesn't match name",
makeSelector: func() *GroupsRestore {
sel := NewGroupsRestore(Any())
sel.Include(sel.ChannelMessages(Any(), []string{"item2"}))
return sel
},
expect: []string{},
cfg: Config{OnlyMatchItemNames: true},
},
{
name: "library only match item name",
makeSelector: func() *GroupsRestore {
sel := NewGroupsRestore(Any())
sel.Include(sel.LibraryItems(Any(), []string{"itemName2"}))
return sel
},
expect: arr(libItem2),
cfg: Config{OnlyMatchItemNames: true},
},
{
name: "name doesn't match",
makeSelector: func() *GroupsRestore {
sel := NewGroupsRestore(Any())
sel.Include(sel.LibraryItems(Any(), []string{"itemName2"}))
return sel
},
expect: []string{},
},
{
name: "only match folder",
makeSelector: func() *GroupsRestore {
sel := NewGroupsRestore([]string{"sid"})
sel.Include(sel.LibraryFolders([]string{"folderA/folderB", pairAC}))
return sel
},
expect: arr(libItem, libItem2),
},
}
for _, test := range table {
suite.Run(test.name, func() {
t := suite.T()
// sel := test.makeSelector() ctx, flush := tester.NewContext(t)
// sel.Configure(test.cfg) defer flush()
// results := sel.Reduce(ctx, deets, fault.New(true))
// paths := results.Paths() sel := test.makeSelector()
// assert.Equal(t, test.expect, paths) sel.Configure(test.cfg)
// }) results := sel.Reduce(ctx, deets, fault.New(true))
// } paths := results.Paths()
// } assert.Equal(t, test.expect, paths)
})
}
}
func (suite *GroupsSelectorSuite) TestGroupsCategory_PathValues() { func (suite *GroupsSelectorSuite) TestGroupsCategory_PathValues() {
var ( var (
@ -324,91 +355,111 @@ func (suite *GroupsSelectorSuite) TestGroupsCategory_PathValues() {
} }
} }
// TODO(abin): implement func (suite *GroupsSelectorSuite) TestGroupsScope_MatchesInfo() {
// func (suite *GroupsSelectorSuite) TestGroupsScope_MatchesInfo() { var (
// var ( sel = NewGroupsRestore(Any())
// sel = NewGroupsRestore(Any()) user = "user@mail.com"
// host = "www.website.com" host = "www.website.com"
// pth = "/foo" // pth = "/foo"
// url = host + pth // url = host + pth
// epoch = time.Time{} epoch = time.Time{}
// now = time.Now() now = time.Now()
// modification = now.Add(15 * time.Minute) modification = now.Add(15 * time.Minute)
// future = now.Add(45 * time.Minute) future = now.Add(45 * time.Minute)
// ) dtch = details.TeamsChannelMessage
)
// table := []struct { table := []struct {
// name string name string
// infoURL string itemType details.ItemType
// scope []GroupsScope creator string
// expect assert.BoolAssertionFunc scope []GroupsScope
// }{ expect assert.BoolAssertionFunc
// {"host match", host, sel.WebURL([]string{host}), assert.True}, }{
// {"url match", url, sel.WebURL([]string{url}), assert.True}, // TODO(abin): implement
// {"host suffixes host", host, sel.WebURL([]string{host}, SuffixMatch()), assert.True}, // {"host match", host, sel.WebURL([]string{host}), assert.True},
// {"url does not suffix host", url, sel.WebURL([]string{host}, SuffixMatch()), assert.False}, // {"url match", url, sel.WebURL([]string{url}), assert.True},
// {"url has path suffix", url, sel.WebURL([]string{pth}, SuffixMatch()), assert.True}, // {"host suffixes host", host, sel.WebURL([]string{host}, SuffixMatch()), assert.True},
// {"host does not contain substring", host, sel.WebURL([]string{"website"}), assert.False}, // {"url does not suffix host", url, sel.WebURL([]string{host}, SuffixMatch()), assert.False},
// {"url does not suffix substring", url, sel.WebURL([]string{"oo"}, SuffixMatch()), assert.False}, // {"url has path suffix", url, sel.WebURL([]string{pth}, SuffixMatch()), assert.True},
// {"host mismatch", host, sel.WebURL([]string{"www.google.com"}), assert.False}, // {"host does not contain substring", host, sel.WebURL([]string{"website"}), assert.False},
// {"file create after the epoch", host, sel.CreatedAfter(dttm.Format(epoch)), assert.True}, // {"url does not suffix substring", url, sel.WebURL([]string{"oo"}, SuffixMatch()), assert.False},
// {"file create after now", host, sel.CreatedAfter(dttm.Format(now)), assert.False}, // {"host mismatch", host, sel.WebURL([]string{"www.google.com"}), assert.False},
// {"file create after later", url, sel.CreatedAfter(dttm.Format(future)), assert.False}, // {"file create after the epoch", host, sel.CreatedAfter(dttm.Format(epoch)), assert.True},
// {"file create before future", host, sel.CreatedBefore(dttm.Format(future)), assert.True}, // {"file create after now", host, sel.CreatedAfter(dttm.Format(now)), assert.False},
// {"file create before now", host, sel.CreatedBefore(dttm.Format(now)), assert.False}, // {"file create after later", url, sel.CreatedAfter(dttm.Format(future)), assert.False},
// {"file create before modification", host, sel.CreatedBefore(dttm.Format(modification)), assert.True}, // {"file create before future", host, sel.CreatedBefore(dttm.Format(future)), assert.True},
// {"file create before epoch", host, sel.CreatedBefore(dttm.Format(now)), assert.False}, // {"file create before now", host, sel.CreatedBefore(dttm.Format(now)), assert.False},
// {"file modified after the epoch", host, sel.ModifiedAfter(dttm.Format(epoch)), assert.True}, // {"file create before modification", host, sel.CreatedBefore(dttm.Format(modification)), assert.True},
// {"file modified after now", host, sel.ModifiedAfter(dttm.Format(now)), assert.True}, // {"file create before epoch", host, sel.CreatedBefore(dttm.Format(now)), assert.False},
// {"file modified after later", host, sel.ModifiedAfter(dttm.Format(future)), assert.False}, // {"file modified after the epoch", host, sel.ModifiedAfter(dttm.Format(epoch)), assert.True},
// {"file modified before future", host, sel.ModifiedBefore(dttm.Format(future)), assert.True}, // {"file modified after now", host, sel.ModifiedAfter(dttm.Format(now)), assert.True},
// {"file modified before now", host, sel.ModifiedBefore(dttm.Format(now)), assert.False}, // {"file modified after later", host, sel.ModifiedAfter(dttm.Format(future)), assert.False},
// {"file modified before epoch", host, sel.ModifiedBefore(dttm.Format(now)), assert.False}, // {"file modified before future", host, sel.ModifiedBefore(dttm.Format(future)), assert.True},
// {"in library", host, sel.Library("included-library"), assert.True}, // {"file modified before now", host, sel.ModifiedBefore(dttm.Format(now)), assert.False},
// {"not in library", host, sel.Library("not-included-library"), assert.False}, // {"file modified before epoch", host, sel.ModifiedBefore(dttm.Format(now)), assert.False},
// {"library id", host, sel.Library("1234"), assert.True}, // {"in library", host, sel.Library("included-library"), assert.True},
// {"not library id", host, sel.Library("abcd"), assert.False}, // {"not in library", host, sel.Library("not-included-library"), assert.False},
// } // {"library id", host, sel.Library("1234"), assert.True},
// for _, test := range table { // {"not library id", host, sel.Library("abcd"), assert.False},
// suite.Run(test.name, func() {
// t := suite.T()
// itemInfo := details.ItemInfo{ {"channel message created by", dtch, user, sel.MessageCreator(user), assert.True},
// Groups: &details.GroupsInfo{ {"channel message not created by", dtch, user, sel.MessageCreator(host), assert.False},
// ItemType: details.GroupsPage, {"chan msg create after the epoch", dtch, user, sel.MessageCreatedAfter(dttm.Format(epoch)), assert.True},
// WebURL: test.infoURL, {"chan msg create after now", dtch, user, sel.MessageCreatedAfter(dttm.Format(now)), assert.False},
// Created: now, {"chan msg create after later", dtch, user, sel.MessageCreatedAfter(dttm.Format(future)), assert.False},
// Modified: modification, {"chan msg create before future", dtch, user, sel.MessageCreatedBefore(dttm.Format(future)), assert.True},
// DriveName: "included-library", {"chan msg create before now", dtch, user, sel.MessageCreatedBefore(dttm.Format(now)), assert.False},
// DriveID: "1234", {"chan msg create before reply", dtch, user, sel.MessageCreatedBefore(dttm.Format(modification)), assert.True},
// }, {"chan msg create before epoch", dtch, user, sel.MessageCreatedBefore(dttm.Format(now)), assert.False},
// } {"chan msg last reply after the epoch", dtch, user, sel.MessageLastReplyAfter(dttm.Format(epoch)), assert.True},
{"chan msg last reply after now", dtch, user, sel.MessageLastReplyAfter(dttm.Format(now)), assert.True},
{"chan msg last reply after later", dtch, user, sel.MessageLastReplyAfter(dttm.Format(future)), assert.False},
{"chan msg last reply before future", dtch, user, sel.MessageLastReplyBefore(dttm.Format(future)), assert.True},
{"chan msg last reply before now", dtch, user, sel.MessageLastReplyBefore(dttm.Format(now)), assert.False},
{"chan msg last reply before epoch", dtch, user, sel.MessageLastReplyBefore(dttm.Format(now)), assert.False},
}
for _, test := range table {
suite.Run(test.name, func() {
t := suite.T()
// scopes := setScopesToDefault(test.scope) itemInfo := details.ItemInfo{
// for _, scope := range scopes { Groups: &details.GroupsInfo{
// test.expect(t, scope.matchesInfo(itemInfo)) ItemType: test.itemType,
// } WebURL: test.creator,
// }) MessageCreator: test.creator,
// } Created: now,
// } Modified: modification,
LastReplyAt: modification,
DriveName: "included-library",
DriveID: "1234",
},
}
scopes := setScopesToDefault(test.scope)
for _, scope := range scopes {
test.expect(t, scope.matchesInfo(itemInfo))
}
})
}
}
func (suite *GroupsSelectorSuite) TestCategory_PathType() { func (suite *GroupsSelectorSuite) TestCategory_PathType() {
table := []struct { table := []struct {
cat groupsCategory cat groupsCategory
pathType path.CategoryType pathType path.CategoryType
}{ }{
{ {GroupsCategoryUnknown, path.UnknownCategory},
cat: GroupsCategoryUnknown, {GroupsChannel, path.ChannelMessagesCategory},
pathType: path.UnknownCategory, {GroupsChannelMessage, path.ChannelMessagesCategory},
}, {GroupsInfoChannelMessageCreator, path.ChannelMessagesCategory},
{ {GroupsInfoChannelMessageCreatedAfter, path.ChannelMessagesCategory},
cat: GroupsChannel, {GroupsInfoChannelMessageCreatedBefore, path.ChannelMessagesCategory},
pathType: path.ChannelMessagesCategory, {GroupsInfoChannelMessageLastReplyAfter, path.ChannelMessagesCategory},
}, {GroupsInfoChannelMessageLastReplyBefore, path.ChannelMessagesCategory},
{ {GroupsLibraryFolder, path.LibrariesCategory},
cat: GroupsChannelMessage, {GroupsLibraryItem, path.LibrariesCategory},
pathType: path.ChannelMessagesCategory, {GroupsInfoSiteLibraryDrive, path.LibrariesCategory},
},
} }
for _, test := range table { for _, test := range table {
suite.Run(test.cat.String(), func() { suite.Run(test.cat.String(), func() {