deduplicate shared exchange code in cli (#732)

This commit is contained in:
Keepers 2022-09-09 18:30:15 -06:00 committed by GitHub
parent 57ddf26007
commit 25ce11b2c6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 216 additions and 549 deletions

View File

@ -66,15 +66,14 @@ func addExchangeCommands(parent *cobra.Command) *cobra.Command {
c, fs = utils.AddCommand(parent, exchangeCreateCmd())
fs.StringSliceVar(
&user,
"user",
nil,
"Backup Exchange data by user ID; accepts "+utils.Wildcard+" to select all users",
)
fs.BoolVar(&exchangeAll, "all", false, "Backup all Exchange data for all users")
"user", nil,
"Backup Exchange data by user ID; accepts "+utils.Wildcard+" to select all users")
fs.BoolVar(&exchangeAll,
"all", false,
"Backup all Exchange data for all users")
fs.StringSliceVar(
&exchangeData,
"data",
nil,
"data", nil,
"Select one or more types of data to backup: "+dataEmail+", "+dataContacts+", or "+dataEvents)
options.AddOperationFlags(c)
@ -83,113 +82,82 @@ func addExchangeCommands(parent *cobra.Command) *cobra.Command {
case detailsCommand:
c, fs = utils.AddCommand(parent, exchangeDetailsCmd())
fs.StringVar(&backupID, "backup", "", "ID of the backup containing the details to be shown")
fs.StringVar(&backupID,
"backup", "",
"ID of the backup containing the details to be shown")
cobra.CheckErr(c.MarkFlagRequired("backup"))
// per-data-type flags
fs.StringSliceVar(
&contact,
"contact",
nil,
"Select backup details by contact ID; accepts "+utils.Wildcard+" to select all contacts",
)
"contact", nil,
"Select backup details by contact ID; accepts "+utils.Wildcard+" to select all contacts")
fs.StringSliceVar(
&contactFolder,
"contact-folder",
nil,
"Select backup details by contact folder ID; accepts "+utils.Wildcard+" to select all contact folders",
)
"contact-folder", nil,
"Select backup details by contact folder ID; accepts "+utils.Wildcard+" to select all contact folders")
fs.StringSliceVar(
&email,
"email",
nil,
"Select backup details by emails ID; accepts "+utils.Wildcard+" to select all emails",
)
"email", nil,
"Select backup details by emails ID; accepts "+utils.Wildcard+" to select all emails")
fs.StringSliceVar(
&emailFolder,
"email-folder",
nil,
"email-folder", nil,
"Select backup details by email folder ID; accepts "+utils.Wildcard+" to select all email folders")
fs.StringSliceVar(
&event,
"event",
nil,
"Select backup details by event ID; accepts "+utils.Wildcard+" to select all events",
)
"event", nil,
"Select backup details by event ID; accepts "+utils.Wildcard+" to select all events")
fs.StringSliceVar(
&eventCalendar,
"event-calendar",
nil,
"Select backup details by event calendar ID; accepts "+utils.Wildcard+" to select all events",
)
"event-calendar", nil,
"Select backup details by event calendar ID; accepts "+utils.Wildcard+" to select all events")
fs.StringSliceVar(
&user,
"user",
nil,
"Select backup details by user ID; accepts "+utils.Wildcard+" to select all users",
)
"user", nil,
"Select backup details by user ID; accepts "+utils.Wildcard+" to select all users")
// exchange-info flags
fs.StringVar(
&contactName,
"contact-name",
"",
"Select backup details where the contact name contains this value",
)
"contact-name", "",
"Select backup details where the contact name contains this value")
fs.StringVar(
&emailReceivedAfter,
"email-received-after",
"",
"Restore mail where the email was received after this datetime",
)
"email-received-after", "",
"Restore mail where the email was received after this datetime")
fs.StringVar(
&emailReceivedBefore,
"email-received-before",
"",
"Restore mail where the email was received before this datetime",
)
"email-received-before", "",
"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",
)
"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",
)
"email-subject", "",
"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",
)
"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.",
)
"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",
)
"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",
)
"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",
)
"event-subject", "",
"Select backup details where the event subject contains this value")
case deleteCommand:
c, fs = utils.AddCommand(parent, exchangeDeleteCmd())
@ -368,7 +336,7 @@ func detailsExchangeCmd(cmd *cobra.Command, args []string) error {
return nil
}
if err := validateExchangeBackupDetailFlags(
if err := utils.ValidateExchangeRestoreFlags(
contact,
contactFolder,
email,
@ -399,7 +367,7 @@ func detailsExchangeCmd(cmd *cobra.Command, args []string) error {
}
sel := selectors.NewExchangeRestore()
includeExchangeBackupDetailDataSelectors(
utils.IncludeExchangeRestoreDataSelectors(
sel,
contact,
contactFolder,
@ -408,7 +376,7 @@ func detailsExchangeCmd(cmd *cobra.Command, args []string) error {
event,
eventCalendar,
user)
filterExchangeBackupDetailInfoSelectors(
utils.FilterExchangeRestoreInfoSelectors(
sel,
contactName,
emailReceivedAfter,
@ -436,207 +404,6 @@ func detailsExchangeCmd(cmd *cobra.Command, args []string) error {
return nil
}
// builds the data-selector inclusions for `backup details exchange`
func includeExchangeBackupDetailDataSelectors(
sel *selectors.ExchangeRestore,
contacts, contactFolders, emails, emailFolders, events, eventCalendars, users []string,
) {
lc, lcf := len(contacts), len(contactFolders)
le, lef := len(emails), len(emailFolders)
lev, lec := len(events), len(eventCalendars)
// either scope the request to a set of users
if lc+lcf+le+lef+lev+lec == 0 {
if len(users) == 0 {
users = selectors.Any()
}
sel.Include(sel.Users(users))
return
}
// or add selectors for each type of data
includeExchangeContacts(sel, users, contactFolders, contacts)
includeExchangeEmails(sel, users, emailFolders, email)
includeExchangeEvents(sel, users, eventCalendars, events)
}
func includeExchangeContacts(sel *selectors.ExchangeRestore, users, contactFolders, contacts []string) {
if len(contactFolders) == 0 {
return
}
if len(contacts) == 0 {
contacts = selectors.Any()
}
sel.Include(sel.Contacts(users, contactFolders, contacts))
}
func includeExchangeEmails(sel *selectors.ExchangeRestore, users, emailFolders, emails []string) {
if len(emailFolders) == 0 {
return
}
if len(emails) == 0 {
emails = selectors.Any()
}
sel.Include(sel.Mails(users, emailFolders, emails))
}
func includeExchangeEvents(sel *selectors.ExchangeRestore, users, eventCalendars, events []string) {
if len(eventCalendars) == 0 {
return
}
if len(events) == 0 {
events = selectors.Any()
}
sel.Include(sel.Events(users, eventCalendars, events))
}
// builds the info-selector filters for `backup details exchange`
func filterExchangeBackupDetailInfoSelectors(
sel *selectors.ExchangeRestore,
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) {
if len(receivedAfter) == 0 {
return
}
sel.Filter(sel.MailReceivedAfter(receivedAfter))
}
func filterExchangeInfoMailReceivedBefore(sel *selectors.ExchangeRestore, receivedBefore string) {
if len(receivedBefore) == 0 {
return
}
sel.Filter(sel.MailReceivedBefore(receivedBefore))
}
func filterExchangeInfoMailSender(sel *selectors.ExchangeRestore, sender string) {
if len(sender) == 0 {
return
}
sel.Filter(sel.MailSender(sender))
}
func filterExchangeInfoMailSubject(sel *selectors.ExchangeRestore, subject string) {
if len(subject) == 0 {
return
}
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,
backupID string,
) error {
if len(backupID) == 0 {
return errors.New("a backup ID is required")
}
lu := len(users)
lc, lcf := len(contacts), len(contactFolders)
le, lef := len(emails), len(emailFolders)
lev, lec := len(events), len(eventCalendars)
if lu+lc+lcf+le+lef+lev+lec == 0 {
return nil
}
if lu == 0 {
return errors.New("requires one or more --user ids, the wildcard --user *, or the --all flag")
}
if lc > 0 && lcf == 0 {
return errors.New(
"one or more --contact-folder ids or the wildcard --contact-folder * must be included to specify a --contact")
}
if le > 0 && lef == 0 {
return errors.New(
"one or more --email-folder ids or the wildcard --email-folder * must be included to specify an --email")
}
if lev > 0 && lec == 0 {
return errors.New(
"one or more --event-calendar ids or the wildcard --event-calendar * must be included to specify an --event")
}
return nil
}
// ------------------------------------------------------------------------------------------------
// backup delete
// ------------------------------------------------------------------------------------------------

View File

@ -303,7 +303,7 @@ func (suite *ExchangeSuite) TestValidateBackupDetailFlags() {
}
for _, test := range table {
suite.T().Run(test.name, func(t *testing.T) {
test.expect(t, validateExchangeBackupDetailFlags(
test.expect(t, utils.ValidateExchangeRestoreFlags(
test.contacts,
test.contactFolders,
test.emails,
@ -499,7 +499,7 @@ func (suite *ExchangeSuite) TestIncludeExchangeBackupDetailDataSelectors() {
for _, test := range table {
suite.T().Run(test.name, func(t *testing.T) {
sel := selectors.NewExchangeRestore()
includeExchangeBackupDetailDataSelectors(
utils.IncludeExchangeRestoreDataSelectors(
sel,
test.contacts,
test.contactFolders,
@ -600,7 +600,7 @@ func (suite *ExchangeSuite) TestFilterExchangeBackupDetailInfoSelectors() {
for _, test := range table {
suite.T().Run(test.name, func(t *testing.T) {
sel := selectors.NewExchangeRestore()
filterExchangeBackupDetailInfoSelectors(
utils.FilterExchangeRestoreInfoSelectors(
sel,
test.contactName,
test.after,

View File

@ -54,91 +54,71 @@ func addExchangeCommands(parent *cobra.Command) *cobra.Command {
// per-data-type flags
fs.StringSliceVar(
&contact,
"contact",
nil,
"Restore contacts by ID; accepts "+utils.Wildcard+" to select all contacts",
)
"contact", nil,
"Restore contacts by ID; accepts "+utils.Wildcard+" to select all contacts")
fs.StringSliceVar(
&contactFolder,
"contact-folder",
nil,
"contact-folder", nil,
"Restore all contacts within the folder ID; accepts "+utils.Wildcard+" to select all contact folders")
fs.StringSliceVar(&email, "email", nil, "Restore emails by ID; accepts "+utils.Wildcard+" to select all emails")
fs.StringSliceVar(&email,
"email", nil,
"Restore emails by ID; accepts "+utils.Wildcard+" to select all emails")
fs.StringSliceVar(
&emailFolder,
"email-folder",
nil,
"Restore all emails by folder ID; accepts "+utils.Wildcard+" to select all email folders",
)
fs.StringSliceVar(&event, "event", nil, "Restore events by ID; accepts "+utils.Wildcard+" to select all events")
"email-folder", nil,
"Restore all emails by folder ID; accepts "+utils.Wildcard+" to select all email folders")
fs.StringSliceVar(&event,
"event", nil,
"Restore events by ID; accepts "+utils.Wildcard+" to select all events")
fs.StringSliceVar(
&eventCalendar,
"event-calendar",
nil,
"event-calendar", nil,
"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")
// exchange-info flags
fs.StringVar(
&contactName,
"contact-name",
"",
"Restore contacts where the contact name contains this value",
)
"contact-name", "",
"Restore contacts where the contact name contains this value")
fs.StringVar(
&emailReceivedAfter,
"email-received-after",
"",
"Restore mail where the email was received after this datetime",
)
"email-received-after", "",
"Restore mail where the email was received after this datetime")
fs.StringVar(
&emailReceivedBefore,
"email-received-before",
"",
"Restore mail where the email was received before this datetime",
)
"email-received-before", "",
"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",
)
"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",
)
"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",
)
"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.",
)
"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",
)
"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",
)
"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",
)
"event-subject", "",
"Restore events where the event subject contains this value")
// others
options.AddOperationFlags(c)
@ -167,7 +147,7 @@ func restoreExchangeCmd(cmd *cobra.Command, args []string) error {
return nil
}
if err := validateExchangeRestoreFlags(
if err := utils.ValidateExchangeRestoreFlags(
contact,
contactFolder,
email,
@ -193,7 +173,7 @@ func restoreExchangeCmd(cmd *cobra.Command, args []string) error {
defer utils.CloseRepo(ctx, r)
sel := selectors.NewExchangeRestore()
includeExchangeRestoreDataSelectors(
utils.IncludeExchangeRestoreDataSelectors(
sel,
contact,
contactFolder,
@ -202,7 +182,7 @@ func restoreExchangeCmd(cmd *cobra.Command, args []string) error {
event,
eventCalendar,
user)
filterExchangeRestoreInfoSelectors(
utils.FilterExchangeRestoreInfoSelectors(
sel,
contactName,
emailReceivedAfter,
@ -233,205 +213,3 @@ func restoreExchangeCmd(cmd *cobra.Command, args []string) error {
return nil
}
// builds the data-selector inclusions for `restore exchange`
func includeExchangeRestoreDataSelectors(
sel *selectors.ExchangeRestore,
contacts, contactFolders, emails, emailFolders, events, eventCalendars, users []string,
) {
lc, lcf := len(contacts), len(contactFolders)
le, lef := len(emails), len(emailFolders)
lev, lec := len(events), len(eventCalendars)
// either scope the request to a set of users
if lc+lcf+le+lef+lev+lec == 0 {
if len(users) == 0 {
users = selectors.Any()
}
sel.Include(sel.Users(users))
return
}
// or add selectors for each type of data
includeExchangeContacts(sel, users, contactFolders, contacts)
includeExchangeEmails(sel, users, emailFolders, email)
includeExchangeEvents(sel, users, eventCalendars, events)
}
func includeExchangeContacts(sel *selectors.ExchangeRestore, users, contactFolders, contacts []string) {
if len(contactFolders) == 0 {
return
}
if len(contacts) == 0 {
contacts = selectors.Any()
}
sel.Include(sel.Contacts(users, contactFolders, contacts))
}
func includeExchangeEmails(sel *selectors.ExchangeRestore, users, emailFolders, emails []string) {
if len(emailFolders) == 0 {
return
}
if len(emails) == 0 {
emails = selectors.Any()
}
sel.Include(sel.Mails(users, emailFolders, emails))
}
func includeExchangeEvents(sel *selectors.ExchangeRestore, users, eventCalendars, events []string) {
if len(eventCalendars) == 0 {
return
}
if len(events) == 0 {
events = selectors.Any()
}
sel.Include(sel.Events(users, eventCalendars, events))
}
// builds the info-selector filters for `restore exchange`
func filterExchangeRestoreInfoSelectors(
sel *selectors.ExchangeRestore,
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) {
if len(receivedAfter) == 0 {
return
}
sel.Filter(sel.MailReceivedAfter(receivedAfter))
}
func filterExchangeInfoMailReceivedBefore(sel *selectors.ExchangeRestore, receivedBefore string) {
if len(receivedBefore) == 0 {
return
}
sel.Filter(sel.MailReceivedBefore(receivedBefore))
}
func filterExchangeInfoMailSender(sel *selectors.ExchangeRestore, sender string) {
if len(sender) == 0 {
return
}
sel.Filter(sel.MailSender(sender))
}
func filterExchangeInfoMailSubject(sel *selectors.ExchangeRestore, subject string) {
if len(subject) == 0 {
return
}
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,
backupID string,
) error {
if len(backupID) == 0 {
return errors.New("a backup ID is required")
}
lu := len(users)
lc, lcf := len(contacts), len(contactFolders)
le, lef := len(emails), len(emailFolders)
lev, lec := len(events), len(eventCalendars)
// if only the backupID is populated, that's the same as --all
if lu+lc+lcf+le+lef+lev+lec == 0 {
return nil
}
if lu == 0 {
return errors.New("requires one or more --user ids, the wildcard --user *, or the --all flag")
}
if lc > 0 && lcf == 0 {
return errors.New(
"one or more --contact-folder ids or the wildcard --contact-folder * must be included to specify a --contact")
}
if le > 0 && lef == 0 {
return errors.New(
"one or more --email-folder ids or the wildcard --email-folder * must be included to specify an --email")
}
if lev > 0 && lec == 0 {
return errors.New(
"one or more --event-calendar ids or the wildcard --event-calendar * must be included to specify an --event")
}
return nil
}

View File

@ -138,7 +138,7 @@ func (suite *ExchangeSuite) TestValidateExchangeRestoreFlags() {
}
for _, test := range table {
suite.T().Run(test.name, func(t *testing.T) {
test.expect(t, validateExchangeRestoreFlags(
test.expect(t, utils.ValidateExchangeRestoreFlags(
test.contacts,
test.contactFolders,
test.emails,
@ -334,7 +334,7 @@ func (suite *ExchangeSuite) TestIncludeExchangeRestoreDataSelectors() {
for _, test := range table {
suite.T().Run(test.name, func(t *testing.T) {
sel := selectors.NewExchangeRestore()
includeExchangeRestoreDataSelectors(
utils.IncludeExchangeRestoreDataSelectors(
sel,
test.contacts,
test.contactFolders,
@ -435,7 +435,7 @@ func (suite *ExchangeSuite) TestFilterExchangeRestoreInfoSelectors() {
for _, test := range table {
suite.T().Run(test.name, func(t *testing.T) {
sel := selectors.NewExchangeRestore()
filterExchangeRestoreInfoSelectors(
utils.FilterExchangeRestoreInfoSelectors(
sel,
test.contactName,
test.after,

126
src/cli/utils/exchange.go Normal file
View File

@ -0,0 +1,126 @@
package utils
import (
"errors"
"github.com/alcionai/corso/src/pkg/selectors"
)
// AddExchangeInclude adds the scope of the provided values to the selector's
// inclusion set.
func AddExchangeInclude(
sel *selectors.ExchangeRestore,
resource, folders, items []string,
incl func([]string, []string, []string) []selectors.ExchangeScope,
) {
if len(folders) == 0 {
return
}
if len(items) == 0 {
items = selectors.Any()
}
sel.Include(incl(resource, folders, items))
}
// AddExchangeFilter adds the scope of the provided values to the selector's
// filter set
func AddExchangeFilter(
sel *selectors.ExchangeRestore,
v string,
f func(string) []selectors.ExchangeScope,
) {
if len(v) == 0 {
return
}
sel.Filter(f(v))
}
// ValidateExchangeRestoreFlags checks common flags for correctness and interdependencies
func ValidateExchangeRestoreFlags(
contacts, contactFolders, emails, emailFolders, events, eventCalendars, users []string,
backupID string,
) error {
if len(backupID) == 0 {
return errors.New("a backup ID is required")
}
lu := len(users)
lc, lcf := len(contacts), len(contactFolders)
le, lef := len(emails), len(emailFolders)
lev, lec := len(events), len(eventCalendars)
// if only the backupID is populated, that's the same as --all
if lu+lc+lcf+le+lef+lev+lec == 0 {
return nil
}
if lu == 0 {
return errors.New("requires one or more --user ids, the wildcard --user *, or the --all flag")
}
if lc > 0 && lcf == 0 {
return errors.New(
"one or more --contact-folder ids or the wildcard --contact-folder * must be included to specify a --contact")
}
if le > 0 && lef == 0 {
return errors.New(
"one or more --email-folder ids or the wildcard --email-folder * must be included to specify an --email")
}
if lev > 0 && lec == 0 {
return errors.New(
"one or more --event-calendar ids or the wildcard --event-calendar * must be included to specify an --event")
}
return nil
}
// IncludeExchangeRestoreDataSelectors builds the common data-selector
// inclusions for exchange commands.
func IncludeExchangeRestoreDataSelectors(
sel *selectors.ExchangeRestore,
contacts, contactFolders, emails, emailFolders, events, eventCalendars, users []string,
) {
lc, lcf := len(contacts), len(contactFolders)
le, lef := len(emails), len(emailFolders)
lev, lec := len(events), len(eventCalendars)
// either scope the request to a set of users
if lc+lcf+le+lef+lev+lec == 0 {
if len(users) == 0 {
users = selectors.Any()
}
sel.Include(sel.Users(users))
return
}
// or add selectors for each type of data
AddExchangeInclude(sel, users, contactFolders, contacts, sel.Contacts)
AddExchangeInclude(sel, users, emailFolders, emails, sel.Mails)
AddExchangeInclude(sel, users, eventCalendars, events, sel.Events)
}
// FilterExchangeRestoreInfoSelectors builds the common info-selector filters.
func FilterExchangeRestoreInfoSelectors(
sel *selectors.ExchangeRestore,
contactName,
emailReceivedAfter, emailReceivedBefore, emailSender, emailSubject,
eventOrganizer, eventRecurs, eventStartsAfter, eventStartsBefore, eventSubject string,
) {
AddExchangeFilter(sel, contactName, sel.ContactName)
AddExchangeFilter(sel, emailReceivedAfter, sel.MailReceivedAfter)
AddExchangeFilter(sel, emailReceivedBefore, sel.MailReceivedBefore)
AddExchangeFilter(sel, emailSender, sel.MailSender)
AddExchangeFilter(sel, emailSubject, sel.MailSubject)
AddExchangeFilter(sel, eventOrganizer, sel.EventOrganizer)
AddExchangeFilter(sel, eventRecurs, sel.EventRecurs)
AddExchangeFilter(sel, eventStartsAfter, sel.EventStartsAfter)
AddExchangeFilter(sel, eventStartsBefore, sel.EventStartsBefore)
AddExchangeFilter(sel, eventSubject, sel.EventSubject)
}

View File

@ -12,6 +12,7 @@ require (
github.com/kopia/kopia v0.11.1
github.com/microsoft/kiota-abstractions-go v0.8.2
github.com/microsoft/kiota-authentication-azure-go v0.3.0
github.com/microsoft/kiota-http-go v0.6.0
github.com/microsoft/kiota-serialization-json-go v0.5.5
github.com/microsoftgraph/msgraph-sdk-go v0.34.0
github.com/microsoftgraph/msgraph-sdk-go-core v0.27.0
@ -48,7 +49,6 @@ require (
github.com/cespare/xxhash/v2 v2.1.2 // indirect
github.com/chmduquesne/rollinghash v4.0.0+incompatible // indirect
github.com/cjlapao/common-go v0.0.25 // indirect
github.com/cpuguy83/go-md2man/v2 v2.0.1 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/dustin/go-humanize v1.0.0 // indirect
github.com/edsrzf/mmap-go v1.1.0 // indirect
@ -71,7 +71,6 @@ require (
github.com/mattn/go-runewidth v0.0.13 // indirect
github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d // indirect
github.com/microsoft/kiota-http-go v0.6.0 // indirect
github.com/microsoft/kiota-serialization-text-go v0.4.1 // indirect
github.com/minio/md5-simd v1.1.2 // indirect
github.com/minio/minio-go/v7 v7.0.34 // indirect
@ -88,7 +87,6 @@ require (
github.com/prometheus/procfs v0.8.0 // indirect
github.com/rivo/uniseg v0.2.0 // indirect
github.com/rs/xid v1.4.0 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect
github.com/sirupsen/logrus v1.9.0 // indirect
github.com/yosida95/uritemplate/v3 v3.0.2 // indirect
github.com/zeebo/blake3 v0.2.3 // indirect

View File

@ -79,7 +79,6 @@ github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XP
github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/cpuguy83/go-md2man/v2 v2.0.1 h1:r/myEWzV9lfsM1tFLgDyu0atFtJ1fXn261LKYj/3DxU=
github.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
@ -335,7 +334,6 @@ github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFR
github.com/rogpeppe/go-internal v1.6.1 h1:/FiVV8dS/e+YqF2JvO3yXRFbBLTIuSDkuC7aBOAvL+k=
github.com/rs/xid v1.4.0 h1:qd7wPTDkN6KQx2VmMBLrpHkiyQwgFXRnkOLacUiaSNY=
github.com/rs/xid v1.4.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=