corso/src/cli/utils/exchange.go
Keepers a6a037df28
cli naming readability and clarification (#2990)
Appends FV to the shared values populated by
cobra flags.  This helps ensure those values are
not confused by other, like-named values used as
func params or local vars.  Also amends some
other varname issues.

---

#### Does this PR need a docs update or release note?

- [x]  No

#### Type of change

- [x] 🧹 Tech Debt/Cleanup

#### Test Plan

- [x]  Unit test
2023-03-30 18:11:38 +00:00

302 lines
8.5 KiB
Go

package utils
import (
"github.com/alcionai/clues"
"github.com/spf13/cobra"
"github.com/alcionai/corso/src/pkg/selectors"
)
// flag names (id: FN)
const (
ContactFN = "contact"
ContactFolderFN = "contact-folder"
ContactNameFN = "contact-name"
EmailFN = "email"
EmailFolderFN = "email-folder"
EmailReceivedAfterFN = "email-received-after"
EmailReceivedBeforeFN = "email-received-before"
EmailSenderFN = "email-sender"
EmailSubjectFN = "email-subject"
EventFN = "event"
EventCalendarFN = "event-calendar"
EventOrganizerFN = "event-organizer"
EventRecursFN = "event-recurs"
EventStartsAfterFN = "event-starts-after"
EventStartsBeforeFN = "event-starts-before"
EventSubjectFN = "event-subject"
)
// flag values (ie: FV)
var (
ContactFV []string
ContactFolderFV []string
ContactNameFV string
EmailFV []string
EmailFolderFV []string
EmailReceivedAfterFV string
EmailReceivedBeforeFV string
EmailSenderFV string
EmailSubjectFV string
EventFV []string
EventCalendarFV []string
EventOrganizerFV string
EventRecursFV string
EventStartsAfterFV string
EventStartsBeforeFV string
EventSubjectFV string
)
type ExchangeOpts struct {
Users []string
Contact []string
ContactFolder []string
ContactName string
Email []string
EmailFolder []string
EmailReceivedAfter string
EmailReceivedBefore string
EmailSender string
EmailSubject string
Event []string
EventCalendar []string
EventOrganizer string
EventRecurs string
EventStartsAfter string
EventStartsBefore string
EventSubject string
Populated PopulatedFlags
}
// populates an ExchangeOpts struct with the command's current flags.
func MakeExchangeOpts(cmd *cobra.Command) ExchangeOpts {
return ExchangeOpts{
Users: UserFV,
Contact: ContactFV,
ContactFolder: ContactFolderFV,
ContactName: ContactNameFV,
Email: EmailFV,
EmailFolder: EmailFolderFV,
EmailReceivedAfter: EmailReceivedAfterFV,
EmailReceivedBefore: EmailReceivedBeforeFV,
EmailSender: EmailSenderFV,
EmailSubject: EmailSubjectFV,
Event: EventFV,
EventCalendar: EventCalendarFV,
EventOrganizer: EventOrganizerFV,
EventRecurs: EventRecursFV,
EventStartsAfter: EventStartsAfterFV,
EventStartsBefore: EventStartsBeforeFV,
EventSubject: EventSubjectFV,
Populated: GetPopulatedFlags(cmd),
}
}
// AddExchangeDetailsAndRestoreFlags adds flags that are common to both the
// details and restore commands.
func AddExchangeDetailsAndRestoreFlags(cmd *cobra.Command) {
fs := cmd.Flags()
// email flags
fs.StringSliceVar(
&EmailFV,
EmailFN, nil,
"Select emails by email ID; accepts '"+Wildcard+"' to select all emails.")
fs.StringSliceVar(
&EmailFolderFV,
EmailFolderFN, nil,
"Select emails within a folder; accepts '"+Wildcard+"' to select all email folders.")
fs.StringVar(
&EmailSubjectFV,
EmailSubjectFN, "",
"Select emails with a subject containing this value.")
fs.StringVar(
&EmailSenderFV,
EmailSenderFN, "",
"Select emails from a specific sender.")
fs.StringVar(
&EmailReceivedAfterFV,
EmailReceivedAfterFN, "",
"Select emails received after this datetime.")
fs.StringVar(
&EmailReceivedBeforeFV,
EmailReceivedBeforeFN, "",
"Select emails received before this datetime.")
// event flags
fs.StringSliceVar(
&EventFV,
EventFN, nil,
"Select events by event ID; accepts '"+Wildcard+"' to select all events.")
fs.StringSliceVar(
&EventCalendarFV,
EventCalendarFN, nil,
"Select events under a calendar; accepts '"+Wildcard+"' to select all events.")
fs.StringVar(
&EventSubjectFV,
EventSubjectFN, "",
"Select events with a subject containing this value.")
fs.StringVar(
&EventOrganizerFV,
EventOrganizerFN, "",
"Select events from a specific organizer.")
fs.StringVar(
&EventRecursFV,
EventRecursFN, "",
"Select recurring events. Use `--event-recurs false` to select non-recurring events.")
fs.StringVar(
&EventStartsAfterFV,
EventStartsAfterFN, "",
"Select events starting after this datetime.")
fs.StringVar(
&EventStartsBeforeFV,
EventStartsBeforeFN, "",
"Select events starting before this datetime.")
// contact flags
fs.StringSliceVar(
&ContactFV,
ContactFN, nil,
"Select contacts by contact ID; accepts '"+Wildcard+"' to select all contacts.")
fs.StringSliceVar(
&ContactFolderFV,
ContactFolderFN, nil,
"Select contacts within a folder; accepts '"+Wildcard+"' to select all contact folders.")
fs.StringVar(
&ContactNameFV,
ContactNameFN, "",
"Select contacts whose contact name contains this value.")
}
// AddExchangeInclude adds the scope of the provided values to the selector's
// inclusion set. Any unpopulated slice will be replaced with selectors.Any()
// to act as a wildcard.
func AddExchangeInclude(
sel *selectors.ExchangeRestore,
folders, items []string,
eisc selectors.ExchangeItemScopeConstructor,
) {
lf, li := len(folders), len(items)
// only use the inclusion if either a folder or item of
// this type is specified.
if lf+li == 0 {
return
}
if li == 0 {
items = selectors.Any()
}
containsFolders, prefixFolders := splitFoldersIntoContainsAndPrefix(folders)
if len(containsFolders) > 0 {
sel.Include(eisc(containsFolders, items))
}
if len(prefixFolders) > 0 {
sel.Include(eisc(prefixFolders, items, selectors.PrefixMatch()))
}
}
// AddExchangeInfo adds the scope of the provided values to the selector's
// filter set
func AddExchangeInfo(
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(backupID string, opts ExchangeOpts) error {
if len(backupID) == 0 {
return clues.New("a backup ID is required")
}
if _, ok := opts.Populated[EmailReceivedAfterFN]; ok && !IsValidTimeFormat(opts.EmailReceivedAfter) {
return clues.New("invalid time format for email-received-after")
}
if _, ok := opts.Populated[EmailReceivedBeforeFN]; ok && !IsValidTimeFormat(opts.EmailReceivedBefore) {
return clues.New("invalid time format for email-received-before")
}
if _, ok := opts.Populated[EventStartsAfterFN]; ok && !IsValidTimeFormat(opts.EventStartsAfter) {
return clues.New("invalid time format for event-starts-after")
}
if _, ok := opts.Populated[EventStartsBeforeFN]; ok && !IsValidTimeFormat(opts.EventStartsBefore) {
return clues.New("invalid time format for event-starts-before")
}
if _, ok := opts.Populated[EventRecursFN]; ok && !IsValidBool(opts.EventRecurs) {
return clues.New("invalid format for event-recurs")
}
return nil
}
// IncludeExchangeRestoreDataSelectors builds the common data-selector
// inclusions for exchange commands.
func IncludeExchangeRestoreDataSelectors(opts ExchangeOpts) *selectors.ExchangeRestore {
users := opts.Users
if len(users) == 0 {
users = selectors.Any()
}
sel := selectors.NewExchangeRestore(users)
lc, lcf := len(opts.Contact), len(opts.ContactFolder)
le, lef := len(opts.Email), len(opts.EmailFolder)
lev, lec := len(opts.Event), len(opts.EventCalendar)
// either scope the request to a set of users
if lc+lcf+le+lef+lev+lec == 0 {
sel.Include(sel.AllData())
return sel
}
opts.EmailFolder = trimFolderSlash(opts.EmailFolder)
// or add selectors for each type of data
AddExchangeInclude(sel, opts.ContactFolder, opts.Contact, sel.Contacts)
AddExchangeInclude(sel, opts.EmailFolder, opts.Email, sel.Mails)
AddExchangeInclude(sel, opts.EventCalendar, opts.Event, sel.Events)
return sel
}
// FilterExchangeRestoreInfoSelectors builds the common info-selector filters.
func FilterExchangeRestoreInfoSelectors(
sel *selectors.ExchangeRestore,
opts ExchangeOpts,
) {
AddExchangeInfo(sel, opts.ContactName, sel.ContactName)
AddExchangeInfo(sel, opts.EmailReceivedAfter, sel.MailReceivedAfter)
AddExchangeInfo(sel, opts.EmailReceivedBefore, sel.MailReceivedBefore)
AddExchangeInfo(sel, opts.EmailSender, sel.MailSender)
AddExchangeInfo(sel, opts.EmailSubject, sel.MailSubject)
AddExchangeInfo(sel, opts.EventOrganizer, sel.EventOrganizer)
AddExchangeInfo(sel, opts.EventRecurs, sel.EventRecurs)
AddExchangeInfo(sel, opts.EventStartsAfter, sel.EventStartsAfter)
AddExchangeInfo(sel, opts.EventStartsBefore, sel.EventStartsBefore)
AddExchangeInfo(sel, opts.EventSubject, sel.EventSubject)
}