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] 🌻 Feature

## Issue(s)

#501

## Test Plan

- [x] 💪 Manual
- [x]  Unit test
- [ ] 💚 E2E
This commit is contained in:
Keepers 2022-09-02 10:25:58 -06:00 committed by GitHub
parent 568d8e2a0c
commit af9dfe6654
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 353 additions and 74 deletions

View File

@ -24,17 +24,26 @@ var (
backupID string backupID string
exchangeAll bool exchangeAll bool
exchangeData []string exchangeData []string
user []string
contact []string contact []string
contactFolder []string contactFolder []string
contactName string
email []string email []string
emailFolder []string emailFolder []string
emailReceivedAfter string emailReceivedAfter string
emailReceivedBefore string emailReceivedBefore string
emailSender string emailSender string
emailSubject string emailSubject string
event []string event []string
eventCalendar []string eventCalendar []string
user []string eventOrganizer string
eventRecurs string
eventStartsAfter string
eventStartsBefore string
eventSubject string
) )
const ( const (
@ -121,24 +130,65 @@ func addExchangeCommands(parent *cobra.Command) *cobra.Command {
) )
// exchange-info flags // exchange-info flags
fs.StringVar(
&contactName,
"contact-name",
"",
"Select backup details where the contact name contains this value",
)
fs.StringVar( fs.StringVar(
&emailReceivedAfter, &emailReceivedAfter,
"email-received-after", "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( fs.StringVar(
&emailReceivedBefore, &emailReceivedBefore,
"email-received-before", "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( fs.StringVar(
&emailSubject, &emailSubject,
"email-subject", "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: case deleteCommand:
@ -360,10 +410,16 @@ func detailsExchangeCmd(cmd *cobra.Command, args []string) error {
user) user)
filterExchangeBackupDetailInfoSelectors( filterExchangeBackupDetailInfoSelectors(
sel, sel,
contactName,
emailReceivedAfter, emailReceivedAfter,
emailReceivedBefore, emailReceivedBefore,
emailSender, emailSender,
emailSubject) emailSubject,
eventOrganizer,
eventRecurs,
eventStartsAfter,
eventStartsBefore,
eventSubject)
// if no selector flags were specified, get all data in the service. // if no selector flags were specified, get all data in the service.
if len(sel.Scopes()) == 0 { 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` // builds the info-selector filters for `backup details exchange`
func filterExchangeBackupDetailInfoSelectors( func filterExchangeBackupDetailInfoSelectors(
sel *selectors.ExchangeRestore, 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) filterExchangeInfoMailReceivedAfter(sel, emailReceivedAfter)
filterExchangeInfoMailReceivedBefore(sel, emailReceivedBefore) filterExchangeInfoMailReceivedBefore(sel, emailReceivedBefore)
filterExchangeInfoMailSender(sel, emailSender) filterExchangeInfoMailSender(sel, emailSender)
filterExchangeInfoMailSubject(sel, emailSubject) 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) { func filterExchangeInfoMailReceivedAfter(sel *selectors.ExchangeRestore, receivedAfter string) {
@ -485,6 +557,46 @@ func filterExchangeInfoMailSubject(sel *selectors.ExchangeRestore, subject strin
sel.Filter(sel.MailSubject(subject)) 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 // checks all flags for correctness and interdependencies
func validateExchangeBackupDetailFlags( func validateExchangeBackupDetailFlags(
contacts, contactFolders, emails, emailFolders, events, eventCalendars, users []string, contacts, contactFolders, emails, emailFolders, events, eventCalendars, users []string,

View File

@ -515,11 +515,12 @@ func (suite *ExchangeSuite) TestIncludeExchangeBackupDetailDataSelectors() {
func (suite *ExchangeSuite) TestFilterExchangeBackupDetailInfoSelectors() { func (suite *ExchangeSuite) TestFilterExchangeBackupDetailInfoSelectors() {
stub := "id-stub" stub := "id-stub"
a := utils.Wildcard
table := []struct { table := []struct {
name string name string
contactName string
after, before, sender, subject string after, before, sender, subject string
organizer, recurs, startsAfter, startsBefore, eventSubject string
expectFilterLen int expectFilterLen int
}{ }{
{ {
@ -527,52 +528,73 @@ func (suite *ExchangeSuite) TestFilterExchangeBackupDetailInfoSelectors() {
expectFilterLen: 0, expectFilterLen: 0,
}, },
{ {
name: "any receivedAfter", name: "contactName",
after: a, contactName: stub,
expectFilterLen: 1, expectFilterLen: 1,
}, },
{ {
name: "single receivedAfter", name: "receivedAfter",
after: stub, after: stub,
expectFilterLen: 1, expectFilterLen: 1,
}, },
{ {
name: "any receivedBefore", name: "receivedAfter",
before: a, after: stub,
expectFilterLen: 1, expectFilterLen: 1,
}, },
{ {
name: "single receivedBefore", name: "receivedBefore",
before: stub, before: stub,
expectFilterLen: 1, expectFilterLen: 1,
}, },
{ {
name: "any sender", name: "sender",
sender: a,
expectFilterLen: 1,
},
{
name: "single sender",
sender: stub, sender: stub,
expectFilterLen: 1, expectFilterLen: 1,
}, },
{ {
name: "any subject", name: "subject",
subject: a, subject: stub,
expectFilterLen: 1, expectFilterLen: 1,
}, },
{ {
name: "single subject", name: "organizer",
subject: stub, 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, expectFilterLen: 1,
}, },
{ {
name: "one of each", name: "one of each",
contactName: stub,
after: stub, after: stub,
before: stub, before: stub,
sender: stub, sender: stub,
subject: stub, subject: stub,
expectFilterLen: 4, organizer: stub,
recurs: stub,
startsAfter: stub,
startsBefore: stub,
eventSubject: stub,
expectFilterLen: 10,
}, },
} }
for _, test := range table { for _, test := range table {
@ -580,10 +602,16 @@ func (suite *ExchangeSuite) TestFilterExchangeBackupDetailInfoSelectors() {
sel := selectors.NewExchangeRestore() sel := selectors.NewExchangeRestore()
filterExchangeBackupDetailInfoSelectors( filterExchangeBackupDetailInfoSelectors(
sel, sel,
test.contactName,
test.after, test.after,
test.before, test.before,
test.sender, test.sender,
test.subject) test.subject,
test.organizer,
test.recurs,
test.startsAfter,
test.startsBefore,
test.eventSubject)
assert.Equal(t, test.expectFilterLen, len(sel.Filters)) assert.Equal(t, test.expectFilterLen, len(sel.Filters))
}) })
} }

View File

@ -16,17 +16,26 @@ import (
// exchange bucket info from flags // exchange bucket info from flags
var ( var (
backupID string backupID string
user []string
contact []string contact []string
contactFolder []string contactFolder []string
contactName string
email []string email []string
emailFolder []string emailFolder []string
emailReceivedAfter string emailReceivedAfter string
emailReceivedBefore string emailReceivedBefore string
emailSender string emailSender string
emailSubject string emailSubject string
event []string event []string
eventCalendar []string eventCalendar []string
user []string eventOrganizer string
eventRecurs string
eventStartsAfter string
eventStartsBefore string
eventSubject string
) )
// called by restore.go to map parent subcommands to provider-specific handling. // 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") "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") 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 // exchange-info flags
fs.StringVar(
&contactName,
"contact-name",
"",
"Restore contacts where the contact name contains this value",
)
fs.StringVar( fs.StringVar(
&emailReceivedAfter, &emailReceivedAfter,
"email-received-after", "email-received-after",
@ -88,8 +97,48 @@ func addExchangeCommands(parent *cobra.Command) *cobra.Command {
"", "",
"Restore mail 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(
fs.StringVar(&emailSubject, "email-subject", "", "Restore mail where the email subject lines contain this value") &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 // others
options.AddOperationFlags(c) options.AddOperationFlags(c)
@ -155,10 +204,16 @@ func restoreExchangeCmd(cmd *cobra.Command, args []string) error {
user) user)
filterExchangeRestoreInfoSelectors( filterExchangeRestoreInfoSelectors(
sel, sel,
contactName,
emailReceivedAfter, emailReceivedAfter,
emailReceivedBefore, emailReceivedBefore,
emailSender, emailSender,
emailSubject) emailSubject,
eventOrganizer,
eventRecurs,
eventStartsAfter,
eventStartsBefore,
eventSubject)
// if no selector flags were specified, get all data in the service. // if no selector flags were specified, get all data in the service.
if len(sel.Scopes()) == 0 { if len(sel.Scopes()) == 0 {
@ -244,12 +299,28 @@ func includeExchangeEvents(sel *selectors.ExchangeRestore, users, eventCalendars
// builds the info-selector filters for `restore exchange` // builds the info-selector filters for `restore exchange`
func filterExchangeRestoreInfoSelectors( func filterExchangeRestoreInfoSelectors(
sel *selectors.ExchangeRestore, 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) filterExchangeInfoMailReceivedAfter(sel, emailReceivedAfter)
filterExchangeInfoMailReceivedBefore(sel, emailReceivedBefore) filterExchangeInfoMailReceivedBefore(sel, emailReceivedBefore)
filterExchangeInfoMailSender(sel, emailSender) filterExchangeInfoMailSender(sel, emailSender)
filterExchangeInfoMailSubject(sel, emailSubject) 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) { func filterExchangeInfoMailReceivedAfter(sel *selectors.ExchangeRestore, receivedAfter string) {
@ -284,6 +355,46 @@ func filterExchangeInfoMailSubject(sel *selectors.ExchangeRestore, subject strin
sel.Filter(sel.MailSubject(subject)) 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 // checks all flags for correctness and interdependencies
func validateExchangeRestoreFlags( func validateExchangeRestoreFlags(
contacts, contactFolders, emails, emailFolders, events, eventCalendars, users []string, contacts, contactFolders, emails, emailFolders, events, eventCalendars, users []string,

View File

@ -350,11 +350,12 @@ func (suite *ExchangeSuite) TestIncludeExchangeRestoreDataSelectors() {
func (suite *ExchangeSuite) TestFilterExchangeRestoreInfoSelectors() { func (suite *ExchangeSuite) TestFilterExchangeRestoreInfoSelectors() {
stub := "id-stub" stub := "id-stub"
a := utils.Wildcard
table := []struct { table := []struct {
name string name string
contactName string
after, before, sender, subject string after, before, sender, subject string
organizer, recurs, startsAfter, startsBefore, eventSubject string
expectFilterLen int expectFilterLen int
}{ }{
{ {
@ -362,52 +363,73 @@ func (suite *ExchangeSuite) TestFilterExchangeRestoreInfoSelectors() {
expectFilterLen: 0, expectFilterLen: 0,
}, },
{ {
name: "any receivedAfter", name: "contactName",
after: a, contactName: stub,
expectFilterLen: 1, expectFilterLen: 1,
}, },
{ {
name: "single receivedAfter", name: "receivedAfter",
after: stub, after: stub,
expectFilterLen: 1, expectFilterLen: 1,
}, },
{ {
name: "any receivedBefore", name: "receivedAfter",
before: a, after: stub,
expectFilterLen: 1, expectFilterLen: 1,
}, },
{ {
name: "single receivedBefore", name: "receivedBefore",
before: stub, before: stub,
expectFilterLen: 1, expectFilterLen: 1,
}, },
{ {
name: "any senders", name: "sender",
sender: a,
expectFilterLen: 1,
},
{
name: "single sender",
sender: stub, sender: stub,
expectFilterLen: 1, expectFilterLen: 1,
}, },
{ {
name: "any subjects", name: "subject",
subject: a, subject: stub,
expectFilterLen: 1, expectFilterLen: 1,
}, },
{ {
name: "single subject", name: "organizer",
subject: stub, 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, expectFilterLen: 1,
}, },
{ {
name: "one of each", name: "one of each",
contactName: stub,
after: stub, after: stub,
before: stub, before: stub,
sender: stub, sender: stub,
subject: stub, subject: stub,
expectFilterLen: 4, organizer: stub,
recurs: stub,
startsAfter: stub,
startsBefore: stub,
eventSubject: stub,
expectFilterLen: 10,
}, },
} }
for _, test := range table { for _, test := range table {
@ -415,10 +437,16 @@ func (suite *ExchangeSuite) TestFilterExchangeRestoreInfoSelectors() {
sel := selectors.NewExchangeRestore() sel := selectors.NewExchangeRestore()
filterExchangeRestoreInfoSelectors( filterExchangeRestoreInfoSelectors(
sel, sel,
test.contactName,
test.after, test.after,
test.before, test.before,
test.sender, test.sender,
test.subject) test.subject,
test.organizer,
test.recurs,
test.startsAfter,
test.startsBefore,
test.eventSubject)
assert.Equal(t, test.expectFilterLen, len(sel.Filters)) assert.Equal(t, test.expectFilterLen, len(sel.Filters))
}) })
} }