diff --git a/src/pkg/selectors/exchange.go b/src/pkg/selectors/exchange.go index f095bec96..f2be5b4fe 100644 --- a/src/pkg/selectors/exchange.go +++ b/src/pkg/selectors/exchange.go @@ -1,6 +1,8 @@ package selectors import ( + "strconv" + "github.com/alcionai/corso/internal/common" "github.com/alcionai/corso/pkg/backup/details" "github.com/alcionai/corso/pkg/filters" @@ -260,6 +262,64 @@ func (s *exchange) Users(users []string) []ExchangeScope { // ------------------- // Filter Factories +// EventRecurs produces one or more exchange event recurrence filter scopes. +// Matches any event if the comparator flag matches the event recurrence flag. +// 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 (sr *ExchangeRestore) EventRecurs(recurs bool) []ExchangeScope { + return []ExchangeScope{ + makeFilterScope[ExchangeScope]( + ExchangeEvent, + ExchangeFilterEventRecurs, + []string{strconv.FormatBool(recurs)}, + wrapFilter(filters.Equal)), + } +} + +// EventStartsAfter produces an exchange event starts-after filter scope. +// Matches any event where the start 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 (sr *ExchangeRestore) EventStartsAfter(timeStrings string) []ExchangeScope { + return []ExchangeScope{ + makeFilterScope[ExchangeScope]( + ExchangeMail, + ExchangeFilterMailReceivedAfter, + []string{timeStrings}, + wrapFilter(filters.Less)), + } +} + +// EventStartsBefore produces an exchange event starts-before filter scope. +// Matches any event where the start time is before 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 (sr *ExchangeRestore) EventStartsBefore(timeStrings string) []ExchangeScope { + return []ExchangeScope{ + makeFilterScope[ExchangeScope]( + ExchangeMail, + ExchangeFilterMailReceivedBefore, + []string{timeStrings}, + wrapFilter(filters.Greater)), + } +} + +// EventSubject produces one or more exchange event subject filter scopes. +// 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.None, that slice is reduced to [selectors.None] +// If any slice is empty, it defaults to [selectors.None] +func (sr *ExchangeRestore) EventSubject(subjectSubstrings []string) []ExchangeScope { + return []ExchangeScope{ + makeFilterScope[ExchangeScope]( + ExchangeEvent, + ExchangeFilterEventSubject, + subjectSubstrings, + wrapFilter(filters.In)), + } +} + // ContactName produces one or more exchange contact name filter scopes. // Matches any contact whose name contains the provided string. // If any slice contains selectors.Any, that slice is reduced to [selectors.Any] @@ -399,6 +459,10 @@ const ( ExchangeFilterMailReceivedAfter exchangeCategory = "ExchangeFilterMailReceivedAfter" ExchangeFilterMailReceivedBefore exchangeCategory = "ExchangeFilterMailReceivedBefore" ExchangeFilterContactName exchangeCategory = "ExchangeFilterContactName" + ExchangeFilterEventRecurs exchangeCategory = "ExchangeFilterEventRecurs" + ExchangeFilterEventStartsAfter exchangeCategory = "ExchangeFilterEventStartsAfter" + ExchangeFilterEventStartsBefore exchangeCategory = "ExchangeFilterEventStartsBefore" + ExchangeFilterEventSubject exchangeCategory = "ExchangeFilterEventSubject" // append new filter cats here ) @@ -428,6 +492,9 @@ func (ec exchangeCategory) leafCat() categorizer { switch ec { case ExchangeContact, ExchangeContactFolder, ExchangeFilterContactName: return ExchangeContact + case ExchangeEvent, ExchangeFilterEventRecurs, ExchangeFilterEventStartsAfter, + ExchangeFilterEventStartsBefore, ExchangeFilterEventSubject: + return ExchangeEvent case ExchangeMail, ExchangeMailFolder, ExchangeFilterMailReceivedAfter, ExchangeFilterMailReceivedBefore, ExchangeFilterMailSender, ExchangeFilterMailSubject: return ExchangeMail @@ -631,10 +698,14 @@ func (s ExchangeScope) matchesInfo(info *details.ExchangeInfo) bool { i = info.Sender case ExchangeFilterMailSubject: i = info.Subject - case ExchangeFilterMailReceivedAfter: - i = common.FormatTime(info.Received) - case ExchangeFilterMailReceivedBefore: + case ExchangeFilterMailReceivedAfter, ExchangeFilterMailReceivedBefore: i = common.FormatTime(info.Received) + case ExchangeFilterEventRecurs: + i = "" // TODO: add EventRecurs is added to ExchangeInfo. + case ExchangeFilterEventStartsAfter, ExchangeFilterEventStartsBefore: + i = common.FormatTime(info.EventStart) + case ExchangeFilterEventSubject: + i = info.Subject } return s.Matches(filterCat, i) diff --git a/src/pkg/selectors/exchange_test.go b/src/pkg/selectors/exchange_test.go index 53212aa40..4b05284ee 100644 --- a/src/pkg/selectors/exchange_test.go +++ b/src/pkg/selectors/exchange_test.go @@ -652,14 +652,16 @@ func (suite *ExchangeSelectorSuite) TestExchangeScope_MatchesInfo() { ) var ( - epoch = time.Time{} - now = time.Now() - then = now.Add(1 * time.Minute) - info = &details.ExchangeInfo{ + epoch = time.Time{} + now = time.Now() + future = now.Add(1 * time.Minute) + info = &details.ExchangeInfo{ + ContactName: name, + EventStart: now, Sender: sender, Subject: subject, Received: now, - ContactName: name, + // TODO: event recurs } ) @@ -673,16 +675,28 @@ func (suite *ExchangeSelectorSuite) TestExchangeScope_MatchesInfo() { {"mail from a different sender", es.MailSender([]string{"magoo@ma.goo"}), assert.False}, {"mail from the matching sender", es.MailSender([]string{sender}), assert.True}, {"mail with any subject", es.MailSubject(Any()), assert.True}, - {"no mail, regardless of subject", es.MailSubject(None()), assert.False}, + {"mail with none subject", es.MailSubject(None()), assert.False}, {"mail with a different subject", es.MailSubject([]string{"fancy"}), assert.False}, {"mail with the matching subject", es.MailSubject([]string{subject}), assert.True}, {"mail with a substring subject match", es.MailSubject([]string{subject[5:9]}), assert.True}, {"mail received after the epoch", es.MailReceivedAfter(common.FormatTime(epoch)), assert.True}, {"mail received after now", es.MailReceivedAfter(common.FormatTime(now)), assert.False}, - {"mail received after sometime later", es.MailReceivedAfter(common.FormatTime(then)), assert.False}, + {"mail received after sometime later", es.MailReceivedAfter(common.FormatTime(future)), assert.False}, {"mail received before the epoch", es.MailReceivedBefore(common.FormatTime(epoch)), assert.False}, {"mail received before now", es.MailReceivedBefore(common.FormatTime(now)), assert.False}, - {"mail received before sometime later", es.MailReceivedBefore(common.FormatTime(then)), assert.True}, + {"mail received before sometime later", es.MailReceivedBefore(common.FormatTime(future)), assert.True}, + // TODO: {"event that recurs", es.EventRecurs(true), assert.True}, + // TODO: {"event that does not recur", es.EventRecurs(false), assert.False}, + {"event starting after the epoch", es.EventStartsAfter(common.FormatTime(epoch)), assert.True}, + {"event starting after now", es.EventStartsAfter(common.FormatTime(now)), assert.False}, + {"event starting after sometime later", es.EventStartsAfter(common.FormatTime(future)), assert.False}, + {"event starting before the epoch", es.EventStartsBefore(common.FormatTime(epoch)), assert.False}, + {"event starting before now", es.EventStartsBefore(common.FormatTime(now)), assert.False}, + {"event starting before sometime later", es.EventStartsBefore(common.FormatTime(future)), assert.True}, + {"event with any subject", es.EventSubject(Any()), assert.True}, + {"event with none subject", es.EventSubject(None()), assert.False}, + {"event with a different subject", es.EventSubject([]string{"fancy"}), assert.False}, + {"event with the matching subject", es.EventSubject([]string{subject}), assert.True}, {"contact with a different name", es.ContactName("blarps"), assert.False}, {"contact with the same name", es.ContactName(name), assert.True}, {"contact with a subname search", es.ContactName(name[2:5]), assert.True},