From a043304e0b5187bf79404bd28391f2102b6eae86 Mon Sep 17 00:00:00 2001 From: Keepers Date: Thu, 1 Sep 2022 13:56:17 -0600 Subject: [PATCH] add eventOrganizer selector (#720) ## Description Adds the eventOrganizer exchange filter, wraps up the addition of eventRecurs filtering, and fixes a couple improperly designed filter constructors. ## Type of change Please check the type of change your PR introduces: - [x] :sunflower: Feature ## Issue(s) #501 ## Test Plan - [x] :muscle: Manual - [x] :zap: Unit test - [ ] :green_heart: E2E --- src/cli/backup/exchange.go | 4 +- src/cli/restore/exchange.go | 4 +- src/pkg/selectors/exchange.go | 78 ++++++++++++++++++------------ src/pkg/selectors/exchange_test.go | 44 +++++++++-------- 4 files changed, 77 insertions(+), 53 deletions(-) diff --git a/src/cli/backup/exchange.go b/src/cli/backup/exchange.go index 3eb5b2ec3..b98ce3dcf 100644 --- a/src/cli/backup/exchange.go +++ b/src/cli/backup/exchange.go @@ -474,7 +474,7 @@ func filterExchangeInfoMailSender(sel *selectors.ExchangeRestore, sender string) return } - sel.Filter(sel.MailSender([]string{sender})) + sel.Filter(sel.MailSender(sender)) } func filterExchangeInfoMailSubject(sel *selectors.ExchangeRestore, subject string) { @@ -482,7 +482,7 @@ func filterExchangeInfoMailSubject(sel *selectors.ExchangeRestore, subject strin return } - sel.Filter(sel.MailSubject([]string{subject})) + sel.Filter(sel.MailSubject(subject)) } // checks all flags for correctness and interdependencies diff --git a/src/cli/restore/exchange.go b/src/cli/restore/exchange.go index 15c704b74..c85b8cc4f 100644 --- a/src/cli/restore/exchange.go +++ b/src/cli/restore/exchange.go @@ -273,7 +273,7 @@ func filterExchangeInfoMailSender(sel *selectors.ExchangeRestore, sender string) return } - sel.Filter(sel.MailSender([]string{sender})) + sel.Filter(sel.MailSender(sender)) } func filterExchangeInfoMailSubject(sel *selectors.ExchangeRestore, subject string) { @@ -281,7 +281,7 @@ func filterExchangeInfoMailSubject(sel *selectors.ExchangeRestore, subject strin return } - sel.Filter(sel.MailSubject([]string{subject})) + sel.Filter(sel.MailSubject(subject)) } // checks all flags for correctness and interdependencies diff --git a/src/pkg/selectors/exchange.go b/src/pkg/selectors/exchange.go index a7466ec38..e0126a05d 100644 --- a/src/pkg/selectors/exchange.go +++ b/src/pkg/selectors/exchange.go @@ -274,17 +274,47 @@ func (s *exchange) Users(users []string) []ExchangeScope { // ------------------- // Filter Factories +// 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] +// 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) ContactName(senderID string) []ExchangeScope { + return []ExchangeScope{ + makeFilterScope[ExchangeScope]( + ExchangeContact, + ExchangeFilterContactName, + []string{senderID}, + wrapFilter(filters.In)), + } +} + +// 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) EventOrganizer(organizer string) []ExchangeScope { + return []ExchangeScope{ + makeFilterScope[ExchangeScope]( + ExchangeEvent, + ExchangeFilterEventOrganizer, + []string{organizer}, + wrapFilter(filters.In)), + } +} + // 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 { +func (sr *ExchangeRestore) EventRecurs(recurs string) []ExchangeScope { return []ExchangeScope{ makeFilterScope[ExchangeScope]( ExchangeEvent, ExchangeFilterEventRecurs, - []string{strconv.FormatBool(recurs)}, + []string{recurs}, wrapFilter(filters.Equal)), } } @@ -322,27 +352,12 @@ func (sr *ExchangeRestore) EventStartsBefore(timeStrings string) []ExchangeScope // 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 { +func (sr *ExchangeRestore) EventSubject(subject 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] -// 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) ContactName(senderID string) []ExchangeScope { - return []ExchangeScope{ - makeFilterScope[ExchangeScope]( - ExchangeContact, - ExchangeFilterContactName, - []string{senderID}, + []string{subject}, wrapFilter(filters.In)), } } @@ -380,12 +395,12 @@ func (sr *ExchangeRestore) MailReceivedBefore(timeStrings string) []ExchangeScop // 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) MailSender(senderIDs []string) []ExchangeScope { +func (sr *ExchangeRestore) MailSender(sender string) []ExchangeScope { return []ExchangeScope{ makeFilterScope[ExchangeScope]( ExchangeMail, ExchangeFilterMailSender, - senderIDs, + []string{sender}, wrapFilter(filters.In)), } } @@ -395,12 +410,12 @@ func (sr *ExchangeRestore) MailSender(senderIDs []string) []ExchangeScope { // 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) MailSubject(subjectSubstrings []string) []ExchangeScope { +func (sr *ExchangeRestore) MailSubject(subject string) []ExchangeScope { return []ExchangeScope{ makeFilterScope[ExchangeScope]( ExchangeMail, ExchangeFilterMailSubject, - subjectSubstrings, + []string{subject}, wrapFilter(filters.In)), } } @@ -472,6 +487,7 @@ const ( ExchangeFilterMailReceivedAfter exchangeCategory = "ExchangeFilterMailReceivedAfter" ExchangeFilterMailReceivedBefore exchangeCategory = "ExchangeFilterMailReceivedBefore" ExchangeFilterContactName exchangeCategory = "ExchangeFilterContactName" + ExchangeFilterEventOrganizer exchangeCategory = "ExchangeFilterEventOrganizer" ExchangeFilterEventRecurs exchangeCategory = "ExchangeFilterEventRecurs" ExchangeFilterEventStartsAfter exchangeCategory = "ExchangeFilterEventStartsAfter" ExchangeFilterEventStartsBefore exchangeCategory = "ExchangeFilterEventStartsBefore" @@ -506,7 +522,7 @@ func (ec exchangeCategory) leafCat() categorizer { case ExchangeContact, ExchangeContactFolder, ExchangeFilterContactName: return ExchangeContact - case ExchangeEvent, ExchangeEventCalendar, ExchangeFilterEventRecurs, + case ExchangeEvent, ExchangeEventCalendar, ExchangeFilterEventOrganizer, ExchangeFilterEventRecurs, ExchangeFilterEventStartsAfter, ExchangeFilterEventStartsBefore, ExchangeFilterEventSubject: return ExchangeEvent @@ -696,18 +712,20 @@ func (s ExchangeScope) matchesInfo(info *details.ExchangeInfo) bool { switch filterCat { case ExchangeFilterContactName: i = info.ContactName + case ExchangeFilterEventOrganizer: + i = info.Organizer + case ExchangeFilterEventRecurs: + i = strconv.FormatBool(info.EventRecurs) + case ExchangeFilterEventStartsAfter, ExchangeFilterEventStartsBefore: + i = common.FormatTime(info.EventStart) + case ExchangeFilterEventSubject: + i = info.Subject case ExchangeFilterMailSender: i = info.Sender case ExchangeFilterMailSubject: i = info.Subject 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 4d2cac525..9e5d8e832 100644 --- a/src/pkg/selectors/exchange_test.go +++ b/src/pkg/selectors/exchange_test.go @@ -698,9 +698,10 @@ func (suite *ExchangeSelectorSuite) TestExchangeScope_MatchesInfo() { es := NewExchangeRestore() const ( - name = "smarf mcfnords" - sender = "smarf@2many.cooks" - subject = "I have seen the fnords!" + name = "smarf mcfnords" + organizer = "cooks@2many.smarf" + sender = "smarf@2many.cooks" + subject = "I have seen the fnords!" ) var ( @@ -709,11 +710,12 @@ func (suite *ExchangeSelectorSuite) TestExchangeScope_MatchesInfo() { future = now.Add(1 * time.Minute) info = &details.ExchangeInfo{ ContactName: name, + EventRecurs: true, EventStart: now, + Organizer: organizer, Sender: sender, Subject: subject, Received: now, - // TODO: event recurs } ) @@ -722,33 +724,37 @@ func (suite *ExchangeSelectorSuite) TestExchangeScope_MatchesInfo() { scope []ExchangeScope expect assert.BoolAssertionFunc }{ - {"any mail with a sender", es.MailSender(Any()), assert.True}, - {"no mail, regardless of sender", es.MailSender(None()), assert.False}, - {"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}, - {"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}, + {"any mail with a sender", es.MailSender(AnyTgt), assert.True}, + {"no mail, regardless of sender", es.MailSender(NoneTgt), assert.False}, + {"mail from a different sender", es.MailSender("magoo@ma.goo"), assert.False}, + {"mail from the matching sender", es.MailSender(sender), assert.True}, + {"mail with any subject", es.MailSubject(AnyTgt), assert.True}, + {"mail with none subject", es.MailSubject(NoneTgt), assert.False}, + {"mail with a different subject", es.MailSubject("fancy"), assert.False}, + {"mail with the matching subject", es.MailSubject(subject), assert.True}, + {"mail with a substring subject match", es.MailSubject(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(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(future)), assert.True}, - // TODO: {"event that recurs", es.EventRecurs(true), assert.True}, - // TODO: {"event that does not recur", es.EventRecurs(false), assert.False}, + {"event with any organizer", es.EventOrganizer(AnyTgt), assert.True}, + {"event with none organizer", es.EventOrganizer(NoneTgt), assert.False}, + {"event with a different organizer", es.EventOrganizer("fancy"), assert.False}, + {"event with the matching organizer", es.EventOrganizer(organizer), assert.True}, + {"event that recurs", es.EventRecurs("true"), assert.True}, + {"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}, + {"event with any subject", es.EventSubject(AnyTgt), assert.True}, + {"event with none subject", es.EventSubject(NoneTgt), assert.False}, + {"event with a different subject", es.EventSubject("fancy"), assert.False}, + {"event with the matching subject", es.EventSubject(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},