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:
parent
bf29443ad4
commit
e96c21d342
@ -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"`
|
||||||
|
|||||||
@ -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]
|
||||||
|
|||||||
@ -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)
|
||||||
|
|||||||
@ -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() {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user