add per-data type flags to backup details (#355)
* add per-data type flags to backup details Adds the contacts, contact folders, emails, email folders, events, and users flag support to `corso backup create exchange` to enable selector support.
This commit is contained in:
parent
746c88a233
commit
43c024f4b2
@ -19,6 +19,11 @@ var (
|
|||||||
backupDetailsID string
|
backupDetailsID string
|
||||||
exchangeAll bool
|
exchangeAll bool
|
||||||
exchangeData []string
|
exchangeData []string
|
||||||
|
contact []string
|
||||||
|
contactFolder []string
|
||||||
|
email []string
|
||||||
|
emailFolder []string
|
||||||
|
event []string
|
||||||
user []string
|
user []string
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -37,8 +42,8 @@ func addExchangeCommands(parent *cobra.Command) *cobra.Command {
|
|||||||
switch parent.Use {
|
switch parent.Use {
|
||||||
case createCommand:
|
case createCommand:
|
||||||
c, fs = utils.AddCommand(parent, exchangeCreateCmd)
|
c, fs = utils.AddCommand(parent, exchangeCreateCmd)
|
||||||
fs.StringArrayVar(&user, "user", nil, "Back up Exchange data by user ID; accepts "+utils.Wildcard+" to select all users")
|
fs.StringArrayVar(&user, "user", nil, "Backup Exchange data by user ID; accepts "+utils.Wildcard+" to select all users")
|
||||||
fs.BoolVar(&exchangeAll, "all", false, "Back up all Exchange data for all users")
|
fs.BoolVar(&exchangeAll, "all", false, "Backup all Exchange data for all users")
|
||||||
fs.StringArrayVar(
|
fs.StringArrayVar(
|
||||||
&exchangeData,
|
&exchangeData,
|
||||||
"data",
|
"data",
|
||||||
@ -51,6 +56,25 @@ func addExchangeCommands(parent *cobra.Command) *cobra.Command {
|
|||||||
c, fs = utils.AddCommand(parent, exchangeDetailsCmd)
|
c, fs = utils.AddCommand(parent, exchangeDetailsCmd)
|
||||||
fs.StringVar(&backupDetailsID, "backup-details", "", "ID of the backup details to be shown")
|
fs.StringVar(&backupDetailsID, "backup-details", "", "ID of the backup details to be shown")
|
||||||
cobra.CheckErr(c.MarkFlagRequired("backup-details"))
|
cobra.CheckErr(c.MarkFlagRequired("backup-details"))
|
||||||
|
fs.StringArrayVar(&contact, "contact", nil, "Select backup details by contact ID; accepts "+utils.Wildcard+" to select all contacts")
|
||||||
|
fs.StringArrayVar(
|
||||||
|
&contactFolder,
|
||||||
|
"contact-folder",
|
||||||
|
nil,
|
||||||
|
"Select backup details by contact folder ID; accepts "+utils.Wildcard+" to select all contact folders")
|
||||||
|
fs.StringArrayVar(&email, "email", nil, "Select backup details by emails ID; accepts "+utils.Wildcard+" to select all emails")
|
||||||
|
fs.StringArrayVar(
|
||||||
|
&emailFolder,
|
||||||
|
"email-folder",
|
||||||
|
nil,
|
||||||
|
"Select backup details by email folder ID; accepts "+utils.Wildcard+" to select all email folderss")
|
||||||
|
fs.StringArrayVar(&event, "event", nil, "Select backup details by event ID; accepts "+utils.Wildcard+" to select all events")
|
||||||
|
fs.StringArrayVar(&user, "user", nil, "Select backup details 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"))
|
||||||
}
|
}
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
@ -237,3 +261,89 @@ func detailsExchangeCmd(cmd *cobra.Command, args []string) error {
|
|||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func exchangeBackupDetailSelectors(
|
||||||
|
contacts, contactFolders, emails, emailFolders, events, users []string,
|
||||||
|
) selectors.Selector {
|
||||||
|
sel := selectors.NewExchangeBackup()
|
||||||
|
// normalize the inputs
|
||||||
|
lc, lcf := len(contacts), len(contactFolders)
|
||||||
|
le, lef := len(emails), len(emailFolders)
|
||||||
|
lev := len(events)
|
||||||
|
lu := len(users)
|
||||||
|
|
||||||
|
// if only the backupID is provided, treat that as an --all query
|
||||||
|
if lc+lcf+le+lef+lev+lu == 0 {
|
||||||
|
sel.Include(sel.Users(selectors.All()))
|
||||||
|
return sel.Selector
|
||||||
|
}
|
||||||
|
|
||||||
|
// if only users are provided, we only get one selector
|
||||||
|
if lc+lcf+le+lef+lev == 0 {
|
||||||
|
sel.Include(sel.Users(users))
|
||||||
|
return sel.Selector
|
||||||
|
}
|
||||||
|
|
||||||
|
// otherwise, add selectors for each type of data
|
||||||
|
includeExchangeContacts(sel, users, contactFolders, contacts)
|
||||||
|
includeExchangeEmails(sel, users, emailFolders, email)
|
||||||
|
includeExchangeEvents(sel, users, events)
|
||||||
|
|
||||||
|
return sel.Selector
|
||||||
|
}
|
||||||
|
|
||||||
|
func includeExchangeContacts(sel *selectors.ExchangeBackup, users, contactFolders, contacts []string) {
|
||||||
|
if len(contactFolders) == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if len(contacts) > 0 {
|
||||||
|
sel.Include(sel.Contacts(users, contactFolders, contacts))
|
||||||
|
} else {
|
||||||
|
sel.Include(sel.ContactFolders(users, contactFolders))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func includeExchangeEmails(sel *selectors.ExchangeBackup, users, emailFolders, emails []string) {
|
||||||
|
if len(emailFolders) == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if len(emails) > 0 {
|
||||||
|
sel.Include(sel.Mails(users, emailFolders, emails))
|
||||||
|
} else {
|
||||||
|
sel.Include(sel.MailFolders(users, emailFolders))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func includeExchangeEvents(sel *selectors.ExchangeBackup, users, events []string) {
|
||||||
|
if len(events) == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
sel.Include(sel.Events(users, events))
|
||||||
|
}
|
||||||
|
|
||||||
|
func validateExchangeBackupDetailFlags(
|
||||||
|
contacts, contactFolders, emails, emailFolders, events, users []string,
|
||||||
|
backupID string,
|
||||||
|
) error {
|
||||||
|
if len(backupID) == 0 {
|
||||||
|
return errors.New("a backup ID is requried")
|
||||||
|
}
|
||||||
|
lu := len(users)
|
||||||
|
lc, lcf := len(contacts), len(contactFolders)
|
||||||
|
le, lef := len(emails), len(emailFolders)
|
||||||
|
lev := len(events)
|
||||||
|
// if only the backupID is populated, that's the same as --all
|
||||||
|
if lu+lc+lcf+le+lef+lev == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if lu == 0 {
|
||||||
|
return errors.New("requries 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 a --email")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|||||||
@ -212,3 +212,267 @@ func (suite *ExchangeSuite) TestExchangeBackupCreateSelectors() {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (suite *ExchangeSuite) TestValidateBackupDetailFlags() {
|
||||||
|
stub := []string{"id-stub"}
|
||||||
|
table := []struct {
|
||||||
|
name string
|
||||||
|
contacts, contactFolders, emails, emailFolders, events, users []string
|
||||||
|
backupID string
|
||||||
|
expect assert.ErrorAssertionFunc
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "only backupid",
|
||||||
|
backupID: "bid",
|
||||||
|
expect: assert.NoError,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "all values populated",
|
||||||
|
backupID: "bid",
|
||||||
|
contacts: stub,
|
||||||
|
contactFolders: stub,
|
||||||
|
emails: stub,
|
||||||
|
emailFolders: stub,
|
||||||
|
events: stub,
|
||||||
|
users: stub,
|
||||||
|
expect: assert.NoError,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "nothing populated",
|
||||||
|
expect: assert.Error,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "no backup id",
|
||||||
|
contacts: stub,
|
||||||
|
contactFolders: stub,
|
||||||
|
emails: stub,
|
||||||
|
emailFolders: stub,
|
||||||
|
events: stub,
|
||||||
|
users: stub,
|
||||||
|
expect: assert.Error,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "no users",
|
||||||
|
backupID: "bid",
|
||||||
|
contacts: stub,
|
||||||
|
contactFolders: stub,
|
||||||
|
emails: stub,
|
||||||
|
emailFolders: stub,
|
||||||
|
events: stub,
|
||||||
|
expect: assert.Error,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "no contact folders",
|
||||||
|
backupID: "bid",
|
||||||
|
contacts: stub,
|
||||||
|
emails: stub,
|
||||||
|
emailFolders: stub,
|
||||||
|
events: stub,
|
||||||
|
users: stub,
|
||||||
|
expect: assert.Error,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "no email folders",
|
||||||
|
backupID: "bid",
|
||||||
|
contacts: stub,
|
||||||
|
contactFolders: stub,
|
||||||
|
emails: stub,
|
||||||
|
events: stub,
|
||||||
|
users: stub,
|
||||||
|
expect: assert.Error,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, test := range table {
|
||||||
|
suite.T().Run(test.name, func(t *testing.T) {
|
||||||
|
test.expect(t, validateExchangeBackupDetailFlags(
|
||||||
|
test.contacts,
|
||||||
|
test.contactFolders,
|
||||||
|
test.emails,
|
||||||
|
test.emailFolders,
|
||||||
|
test.events,
|
||||||
|
test.users,
|
||||||
|
test.backupID,
|
||||||
|
))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (suite *ExchangeSuite) TestExchangeBackupDetailSelectors() {
|
||||||
|
stub := []string{"id-stub"}
|
||||||
|
all := []string{utils.Wildcard}
|
||||||
|
table := []struct {
|
||||||
|
name string
|
||||||
|
contacts, contactFolders, emails, emailFolders, events, users []string
|
||||||
|
expectIncludeLen int
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "no selectors",
|
||||||
|
expectIncludeLen: 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "all users",
|
||||||
|
users: all,
|
||||||
|
expectIncludeLen: 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "single user",
|
||||||
|
users: stub,
|
||||||
|
expectIncludeLen: 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "multiple users",
|
||||||
|
users: []string{"fnord", "smarf"},
|
||||||
|
expectIncludeLen: 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "all users, all data",
|
||||||
|
contacts: all,
|
||||||
|
contactFolders: all,
|
||||||
|
emails: all,
|
||||||
|
emailFolders: all,
|
||||||
|
events: all,
|
||||||
|
users: all,
|
||||||
|
expectIncludeLen: 3,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "all users, all folders",
|
||||||
|
contactFolders: all,
|
||||||
|
emailFolders: all,
|
||||||
|
users: all,
|
||||||
|
expectIncludeLen: 2,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "single user, single of each data",
|
||||||
|
contacts: stub,
|
||||||
|
contactFolders: stub,
|
||||||
|
emails: stub,
|
||||||
|
emailFolders: stub,
|
||||||
|
events: stub,
|
||||||
|
users: stub,
|
||||||
|
expectIncludeLen: 3,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "single user, single of each folder",
|
||||||
|
contactFolders: stub,
|
||||||
|
emailFolders: stub,
|
||||||
|
users: stub,
|
||||||
|
expectIncludeLen: 2,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "all users, contacts",
|
||||||
|
contacts: all,
|
||||||
|
contactFolders: stub,
|
||||||
|
users: all,
|
||||||
|
expectIncludeLen: 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "single user, contacts",
|
||||||
|
contacts: stub,
|
||||||
|
contactFolders: stub,
|
||||||
|
users: stub,
|
||||||
|
expectIncludeLen: 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "all users, emails",
|
||||||
|
emails: all,
|
||||||
|
emailFolders: stub,
|
||||||
|
users: all,
|
||||||
|
expectIncludeLen: 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "single user, emails",
|
||||||
|
emails: stub,
|
||||||
|
emailFolders: stub,
|
||||||
|
users: stub,
|
||||||
|
expectIncludeLen: 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "all users, events",
|
||||||
|
events: all,
|
||||||
|
users: all,
|
||||||
|
expectIncludeLen: 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "single user, events",
|
||||||
|
events: stub,
|
||||||
|
users: stub,
|
||||||
|
expectIncludeLen: 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "all users, contacts + email",
|
||||||
|
contacts: all,
|
||||||
|
contactFolders: all,
|
||||||
|
emails: all,
|
||||||
|
emailFolders: all,
|
||||||
|
users: all,
|
||||||
|
expectIncludeLen: 2,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "single users, contacts + email",
|
||||||
|
contacts: stub,
|
||||||
|
contactFolders: stub,
|
||||||
|
emails: stub,
|
||||||
|
emailFolders: stub,
|
||||||
|
users: stub,
|
||||||
|
expectIncludeLen: 2,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "all users, email + event",
|
||||||
|
emails: all,
|
||||||
|
emailFolders: all,
|
||||||
|
events: all,
|
||||||
|
users: all,
|
||||||
|
expectIncludeLen: 2,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "single users, email + event",
|
||||||
|
emails: stub,
|
||||||
|
emailFolders: stub,
|
||||||
|
events: stub,
|
||||||
|
users: stub,
|
||||||
|
expectIncludeLen: 2,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "all users, event + contact",
|
||||||
|
contacts: all,
|
||||||
|
contactFolders: all,
|
||||||
|
events: all,
|
||||||
|
users: all,
|
||||||
|
expectIncludeLen: 2,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "single users, event + contact",
|
||||||
|
contacts: stub,
|
||||||
|
contactFolders: stub,
|
||||||
|
events: stub,
|
||||||
|
users: stub,
|
||||||
|
expectIncludeLen: 2,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "many users, events",
|
||||||
|
events: []string{"foo", "bar"},
|
||||||
|
users: []string{"fnord", "smarf"},
|
||||||
|
expectIncludeLen: 2,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "many users, events + contacts",
|
||||||
|
contacts: []string{"foo", "bar"},
|
||||||
|
contactFolders: []string{"foo", "bar"},
|
||||||
|
events: []string{"foo", "bar"},
|
||||||
|
users: []string{"fnord", "smarf"},
|
||||||
|
expectIncludeLen: 6,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, test := range table {
|
||||||
|
suite.T().Run(test.name, func(t *testing.T) {
|
||||||
|
sel := exchangeBackupDetailSelectors(
|
||||||
|
test.contacts,
|
||||||
|
test.contactFolders,
|
||||||
|
test.emails,
|
||||||
|
test.emailFolders,
|
||||||
|
test.events,
|
||||||
|
test.users)
|
||||||
|
assert.Equal(t, test.expectIncludeLen, len(sel.Includes))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -5,9 +5,10 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/alcionai/corso/pkg/repository"
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
"github.com/spf13/pflag"
|
"github.com/spf13/pflag"
|
||||||
|
|
||||||
|
"github.com/alcionai/corso/pkg/repository"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user