From af9dfe6654ed45c4aef011919b691b913773e1ec Mon Sep 17 00:00:00 2001 From: Keepers Date: Fri, 2 Sep 2022 10:25:58 -0600 Subject: [PATCH] expose event info flags in cli (#727) ## Description Adds the new event filter selectors to the CLI for backup detail and restore commands. ## 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 | 140 +++++++++++++++++++++++++++--- src/cli/backup/exchange_test.go | 72 +++++++++++----- src/cli/restore/exchange.go | 143 +++++++++++++++++++++++++++---- src/cli/restore/exchange_test.go | 72 +++++++++++----- 4 files changed, 353 insertions(+), 74 deletions(-) diff --git a/src/cli/backup/exchange.go b/src/cli/backup/exchange.go index b98ce3dcf..78a4c10c7 100644 --- a/src/cli/backup/exchange.go +++ b/src/cli/backup/exchange.go @@ -21,20 +21,29 @@ import ( // exchange bucket info from flags var ( - backupID string - exchangeAll bool - exchangeData []string - contact []string - contactFolder []string + backupID string + exchangeAll bool + exchangeData []string + user []string + + contact []string + contactFolder []string + contactName string + email []string emailFolder []string emailReceivedAfter string emailReceivedBefore string emailSender string emailSubject string - event []string - eventCalendar []string - user []string + + event []string + eventCalendar []string + eventOrganizer string + eventRecurs string + eventStartsAfter string + eventStartsBefore string + eventSubject string ) const ( @@ -121,24 +130,65 @@ func addExchangeCommands(parent *cobra.Command) *cobra.Command { ) // exchange-info flags + fs.StringVar( + &contactName, + "contact-name", + "", + "Select backup details where the contact name contains this value", + ) fs.StringVar( &emailReceivedAfter, "email-received-after", "", - "Select backup details where the email was received after this datetime", + "Restore mail where the email was received after this datetime", ) fs.StringVar( &emailReceivedBefore, "email-received-before", "", - "Select backup details where the email was received before this datetime", + "Restore mail where the email was received before this datetime", + ) + fs.StringVar( + &emailSender, + "email-sender", + "", + "Restore mail where the email sender matches this user id", ) - fs.StringVar(&emailSender, "email-sender", "", "Select backup details where the email sender matches this user id") fs.StringVar( &emailSubject, "email-subject", "", - "Select backup details where the email subject lines contain this value", + "Restore mail where the email subject lines contain this value", + ) + fs.StringVar( + &eventOrganizer, + "event-organizer", + "", + "Select backup details where the event organizer user id contains this value", + ) + fs.StringVar( + &eventRecurs, + "event-recurs", + "", + "Select backup details if the event recurs. Use --event-recurs false to select where the event does not recur.", + ) + fs.StringVar( + &eventStartsAfter, + "event-starts-after", + "", + "Select backup details where the event starts after this datetime", + ) + fs.StringVar( + &eventStartsBefore, + "event-starts-before", + "", + "Select backup details where the event starts before this datetime", + ) + fs.StringVar( + &eventSubject, + "event-subject", + "", + "Select backup details where the event subject contains this value", ) case deleteCommand: @@ -360,10 +410,16 @@ func detailsExchangeCmd(cmd *cobra.Command, args []string) error { user) filterExchangeBackupDetailInfoSelectors( sel, + contactName, emailReceivedAfter, emailReceivedBefore, emailSender, - emailSubject) + emailSubject, + eventOrganizer, + eventRecurs, + eventStartsAfter, + eventStartsBefore, + eventSubject) // if no selector flags were specified, get all data in the service. if len(sel.Scopes()) == 0 { @@ -445,12 +501,28 @@ func includeExchangeEvents(sel *selectors.ExchangeRestore, users, eventCalendars // builds the info-selector filters for `backup details exchange` func filterExchangeBackupDetailInfoSelectors( sel *selectors.ExchangeRestore, - emailReceivedAfter, emailReceivedBefore, emailSender, emailSubject string, + contactName, + emailReceivedAfter, emailReceivedBefore, emailSender, emailSubject, + eventOrganizer, eventRecurs, eventStartsAfter, eventStartsBefore, eventSubject string, ) { + filterExchangeInfoContactName(sel, contactName) filterExchangeInfoMailReceivedAfter(sel, emailReceivedAfter) filterExchangeInfoMailReceivedBefore(sel, emailReceivedBefore) filterExchangeInfoMailSender(sel, emailSender) filterExchangeInfoMailSubject(sel, emailSubject) + filterExchangeInfoEventOrganizer(sel, eventOrganizer) + filterExchangeInfoEventRecurs(sel, eventRecurs) + filterExchangeInfoEventStartsAfter(sel, eventStartsAfter) + filterExchangeInfoEventStartsBefore(sel, eventStartsBefore) + filterExchangeInfoEventSubject(sel, eventSubject) +} + +func filterExchangeInfoContactName(sel *selectors.ExchangeRestore, name string) { + if len(name) == 0 { + return + } + + sel.Filter(sel.ContactName(name)) } func filterExchangeInfoMailReceivedAfter(sel *selectors.ExchangeRestore, receivedAfter string) { @@ -485,6 +557,46 @@ func filterExchangeInfoMailSubject(sel *selectors.ExchangeRestore, subject strin sel.Filter(sel.MailSubject(subject)) } +func filterExchangeInfoEventOrganizer(sel *selectors.ExchangeRestore, organizer string) { + if len(organizer) == 0 { + return + } + + sel.Filter(sel.EventOrganizer(organizer)) +} + +func filterExchangeInfoEventRecurs(sel *selectors.ExchangeRestore, recurs string) { + if len(recurs) == 0 { + return + } + + sel.Filter(sel.EventRecurs(recurs)) +} + +func filterExchangeInfoEventStartsAfter(sel *selectors.ExchangeRestore, startsAfter string) { + if len(startsAfter) == 0 { + return + } + + sel.Filter(sel.EventStartsAfter(startsAfter)) +} + +func filterExchangeInfoEventStartsBefore(sel *selectors.ExchangeRestore, startsBefore string) { + if len(startsBefore) == 0 { + return + } + + sel.Filter(sel.EventStartsBefore(startsBefore)) +} + +func filterExchangeInfoEventSubject(sel *selectors.ExchangeRestore, subject string) { + if len(subject) == 0 { + return + } + + sel.Filter(sel.EventSubject(subject)) +} + // checks all flags for correctness and interdependencies func validateExchangeBackupDetailFlags( contacts, contactFolders, emails, emailFolders, events, eventCalendars, users []string, diff --git a/src/cli/backup/exchange_test.go b/src/cli/backup/exchange_test.go index e9d4066ed..a37a48c34 100644 --- a/src/cli/backup/exchange_test.go +++ b/src/cli/backup/exchange_test.go @@ -515,64 +515,86 @@ func (suite *ExchangeSuite) TestIncludeExchangeBackupDetailDataSelectors() { func (suite *ExchangeSuite) TestFilterExchangeBackupDetailInfoSelectors() { stub := "id-stub" - a := utils.Wildcard table := []struct { - name string - after, before, sender, subject string - expectFilterLen int + name string + contactName string + after, before, sender, subject string + organizer, recurs, startsAfter, startsBefore, eventSubject string + expectFilterLen int }{ { name: "no selectors", expectFilterLen: 0, }, { - name: "any receivedAfter", - after: a, + name: "contactName", + contactName: stub, expectFilterLen: 1, }, { - name: "single receivedAfter", + name: "receivedAfter", after: stub, expectFilterLen: 1, }, { - name: "any receivedBefore", - before: a, + name: "receivedAfter", + after: stub, expectFilterLen: 1, }, { - name: "single receivedBefore", + name: "receivedBefore", before: stub, expectFilterLen: 1, }, { - name: "any sender", - sender: a, - expectFilterLen: 1, - }, - { - name: "single sender", + name: "sender", sender: stub, expectFilterLen: 1, }, { - name: "any subject", - subject: a, + name: "subject", + subject: stub, expectFilterLen: 1, }, { - name: "single subject", - subject: stub, + name: "organizer", + organizer: stub, + expectFilterLen: 1, + }, + { + name: "recurs", + recurs: stub, + expectFilterLen: 1, + }, + { + name: "startsAfter", + startsAfter: stub, + expectFilterLen: 1, + }, + { + name: "startsBefore", + startsBefore: stub, + expectFilterLen: 1, + }, + { + name: "eventSubject", + eventSubject: stub, expectFilterLen: 1, }, { name: "one of each", + contactName: stub, after: stub, before: stub, sender: stub, subject: stub, - expectFilterLen: 4, + organizer: stub, + recurs: stub, + startsAfter: stub, + startsBefore: stub, + eventSubject: stub, + expectFilterLen: 10, }, } for _, test := range table { @@ -580,10 +602,16 @@ func (suite *ExchangeSuite) TestFilterExchangeBackupDetailInfoSelectors() { sel := selectors.NewExchangeRestore() filterExchangeBackupDetailInfoSelectors( sel, + test.contactName, test.after, test.before, test.sender, - test.subject) + test.subject, + test.organizer, + test.recurs, + test.startsAfter, + test.startsBefore, + test.eventSubject) assert.Equal(t, test.expectFilterLen, len(sel.Filters)) }) } diff --git a/src/cli/restore/exchange.go b/src/cli/restore/exchange.go index c85b8cc4f..04706d5dc 100644 --- a/src/cli/restore/exchange.go +++ b/src/cli/restore/exchange.go @@ -15,18 +15,27 @@ import ( // exchange bucket info from flags var ( - backupID string - contact []string - contactFolder []string + backupID string + user []string + + contact []string + contactFolder []string + contactName string + email []string emailFolder []string emailReceivedAfter string emailReceivedBefore string emailSender string emailSubject string - event []string - eventCalendar []string - user []string + + event []string + eventCalendar []string + eventOrganizer string + eventRecurs string + eventStartsAfter string + eventStartsBefore string + eventSubject string ) // called by restore.go to map parent subcommands to provider-specific handling. @@ -69,13 +78,13 @@ func addExchangeCommands(parent *cobra.Command) *cobra.Command { "Restore events by calendar ID; accepts "+utils.Wildcard+" to select all event calendars") fs.StringSliceVar(&user, "user", nil, "Restore all data by user ID; accepts "+utils.Wildcard+" to select all users") - // TODO: reveal these flags when their production is supported in GC - cobra.CheckErr(fs.MarkHidden("contact")) - cobra.CheckErr(fs.MarkHidden("contact-folder")) - cobra.CheckErr(fs.MarkHidden("event")) - cobra.CheckErr(fs.MarkHidden("event-calendar")) - // exchange-info flags + fs.StringVar( + &contactName, + "contact-name", + "", + "Restore contacts where the contact name contains this value", + ) fs.StringVar( &emailReceivedAfter, "email-received-after", @@ -88,8 +97,48 @@ func addExchangeCommands(parent *cobra.Command) *cobra.Command { "", "Restore mail where the email was received before this datetime", ) - fs.StringVar(&emailSender, "email-sender", "", "Restore mail where the email sender matches this user id") - fs.StringVar(&emailSubject, "email-subject", "", "Restore mail where the email subject lines contain this value") + fs.StringVar( + &emailSender, + "email-sender", + "", + "Restore mail where the email sender matches this user id", + ) + fs.StringVar( + &emailSubject, + "email-subject", + "", + "Restore mail where the email subject lines contain this value", + ) + fs.StringVar( + &eventOrganizer, + "event-organizer", + "", + "Restore events where the event organizer user id contains this value", + ) + fs.StringVar( + &eventRecurs, + "event-recurs", + "", + "Restore events if the event recurs. Use --event-recurs false to select where the event does not recur.", + ) + fs.StringVar( + &eventStartsAfter, + "event-starts-after", + "", + "Restore events where the event starts after this datetime", + ) + fs.StringVar( + &eventStartsBefore, + "event-starts-before", + "", + "Restore events where the event starts before this datetime", + ) + fs.StringVar( + &eventSubject, + "event-subject", + "", + "Restore events where the event subject contains this value", + ) // others options.AddOperationFlags(c) @@ -155,10 +204,16 @@ func restoreExchangeCmd(cmd *cobra.Command, args []string) error { user) filterExchangeRestoreInfoSelectors( sel, + contactName, emailReceivedAfter, emailReceivedBefore, emailSender, - emailSubject) + emailSubject, + eventOrganizer, + eventRecurs, + eventStartsAfter, + eventStartsBefore, + eventSubject) // if no selector flags were specified, get all data in the service. if len(sel.Scopes()) == 0 { @@ -244,12 +299,28 @@ func includeExchangeEvents(sel *selectors.ExchangeRestore, users, eventCalendars // builds the info-selector filters for `restore exchange` func filterExchangeRestoreInfoSelectors( sel *selectors.ExchangeRestore, - emailReceivedAfter, emailReceivedBefore, emailSender, emailSubject string, + contactName, + emailReceivedAfter, emailReceivedBefore, emailSender, emailSubject, + eventOrganizer, eventRecurs, eventStartsAfter, eventStartsBefore, eventSubject string, ) { + filterExchangeInfoContactName(sel, contactName) filterExchangeInfoMailReceivedAfter(sel, emailReceivedAfter) filterExchangeInfoMailReceivedBefore(sel, emailReceivedBefore) filterExchangeInfoMailSender(sel, emailSender) filterExchangeInfoMailSubject(sel, emailSubject) + filterExchangeInfoEventOrganizer(sel, eventOrganizer) + filterExchangeInfoEventRecurs(sel, eventRecurs) + filterExchangeInfoEventStartsAfter(sel, eventStartsAfter) + filterExchangeInfoEventStartsBefore(sel, eventStartsBefore) + filterExchangeInfoEventSubject(sel, eventSubject) +} + +func filterExchangeInfoContactName(sel *selectors.ExchangeRestore, name string) { + if len(name) == 0 { + return + } + + sel.Filter(sel.ContactName(name)) } func filterExchangeInfoMailReceivedAfter(sel *selectors.ExchangeRestore, receivedAfter string) { @@ -284,6 +355,46 @@ func filterExchangeInfoMailSubject(sel *selectors.ExchangeRestore, subject strin sel.Filter(sel.MailSubject(subject)) } +func filterExchangeInfoEventOrganizer(sel *selectors.ExchangeRestore, organizer string) { + if len(organizer) == 0 { + return + } + + sel.Filter(sel.EventOrganizer(organizer)) +} + +func filterExchangeInfoEventRecurs(sel *selectors.ExchangeRestore, recurs string) { + if len(recurs) == 0 { + return + } + + sel.Filter(sel.EventRecurs(recurs)) +} + +func filterExchangeInfoEventStartsAfter(sel *selectors.ExchangeRestore, startsAfter string) { + if len(startsAfter) == 0 { + return + } + + sel.Filter(sel.EventStartsAfter(startsAfter)) +} + +func filterExchangeInfoEventStartsBefore(sel *selectors.ExchangeRestore, startsBefore string) { + if len(startsBefore) == 0 { + return + } + + sel.Filter(sel.EventStartsBefore(startsBefore)) +} + +func filterExchangeInfoEventSubject(sel *selectors.ExchangeRestore, subject string) { + if len(subject) == 0 { + return + } + + sel.Filter(sel.EventSubject(subject)) +} + // checks all flags for correctness and interdependencies func validateExchangeRestoreFlags( contacts, contactFolders, emails, emailFolders, events, eventCalendars, users []string, diff --git a/src/cli/restore/exchange_test.go b/src/cli/restore/exchange_test.go index 6ca4f7122..497cea3ae 100644 --- a/src/cli/restore/exchange_test.go +++ b/src/cli/restore/exchange_test.go @@ -350,64 +350,86 @@ func (suite *ExchangeSuite) TestIncludeExchangeRestoreDataSelectors() { func (suite *ExchangeSuite) TestFilterExchangeRestoreInfoSelectors() { stub := "id-stub" - a := utils.Wildcard table := []struct { - name string - after, before, sender, subject string - expectFilterLen int + name string + contactName string + after, before, sender, subject string + organizer, recurs, startsAfter, startsBefore, eventSubject string + expectFilterLen int }{ { name: "no selectors", expectFilterLen: 0, }, { - name: "any receivedAfter", - after: a, + name: "contactName", + contactName: stub, expectFilterLen: 1, }, { - name: "single receivedAfter", + name: "receivedAfter", after: stub, expectFilterLen: 1, }, { - name: "any receivedBefore", - before: a, + name: "receivedAfter", + after: stub, expectFilterLen: 1, }, { - name: "single receivedBefore", + name: "receivedBefore", before: stub, expectFilterLen: 1, }, { - name: "any senders", - sender: a, - expectFilterLen: 1, - }, - { - name: "single sender", + name: "sender", sender: stub, expectFilterLen: 1, }, { - name: "any subjects", - subject: a, + name: "subject", + subject: stub, expectFilterLen: 1, }, { - name: "single subject", - subject: stub, + name: "organizer", + organizer: stub, + expectFilterLen: 1, + }, + { + name: "recurs", + recurs: stub, + expectFilterLen: 1, + }, + { + name: "startsAfter", + startsAfter: stub, + expectFilterLen: 1, + }, + { + name: "startsBefore", + startsBefore: stub, + expectFilterLen: 1, + }, + { + name: "eventSubject", + eventSubject: stub, expectFilterLen: 1, }, { name: "one of each", + contactName: stub, after: stub, before: stub, sender: stub, subject: stub, - expectFilterLen: 4, + organizer: stub, + recurs: stub, + startsAfter: stub, + startsBefore: stub, + eventSubject: stub, + expectFilterLen: 10, }, } for _, test := range table { @@ -415,10 +437,16 @@ func (suite *ExchangeSuite) TestFilterExchangeRestoreInfoSelectors() { sel := selectors.NewExchangeRestore() filterExchangeRestoreInfoSelectors( sel, + test.contactName, test.after, test.before, test.sender, - test.subject) + test.subject, + test.organizer, + test.recurs, + test.startsAfter, + test.startsBefore, + test.eventSubject) assert.Equal(t, test.expectFilterLen, len(sel.Filters)) }) }