corso/src/cli/utils/exchange.go
Abin Simon fd9c431bea
Add cli for exchange export (#4641)
<!-- PR description-->

---

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

- [ ]  Yes, it's included
- [x] 🕐 Yes, but in a later PR
- [ ]  No

#### Type of change

<!--- Please check the type of change your PR introduces: --->
- [x] 🌻 Feature
- [ ] 🐛 Bugfix
- [ ] 🗺️ Documentation
- [ ] 🤖 Supportability/Tests
- [ ] 💻 CI/Deployment
- [ ] 🧹 Tech Debt/Cleanup

#### Issue(s)

<!-- Can reference multiple issues. Use one of the following "magic words" - "closes, fixes" to auto-close the Github issue. -->
* https://github.com/alcionai/corso/issues/3893

#### Test Plan

<!-- How will this be tested prior to merging.-->
- [ ] 💪 Manual
- [x]  Unit test
- [ ] 💚 E2E
2023-11-16 04:53:16 +00:00

192 lines
5.6 KiB
Go

package utils
import (
"github.com/alcionai/clues"
"github.com/spf13/cobra"
"github.com/alcionai/corso/src/cli/flags"
"github.com/alcionai/corso/src/pkg/selectors"
)
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
RestoreCfg RestoreCfgOpts
ExportCfg ExportCfgOpts
Populated flags.PopulatedFlags
}
// populates an ExchangeOpts struct with the command's current flags.
func MakeExchangeOpts(cmd *cobra.Command) ExchangeOpts {
return ExchangeOpts{
Users: flags.UserFV,
Contact: flags.ContactFV,
ContactFolder: flags.ContactFolderFV,
ContactName: flags.ContactNameFV,
Email: flags.EmailFV,
EmailFolder: flags.EmailFolderFV,
EmailReceivedAfter: flags.EmailReceivedAfterFV,
EmailReceivedBefore: flags.EmailReceivedBeforeFV,
EmailSender: flags.EmailSenderFV,
EmailSubject: flags.EmailSubjectFV,
Event: flags.EventFV,
EventCalendar: flags.EventCalendarFV,
EventOrganizer: flags.EventOrganizerFV,
EventRecurs: flags.EventRecursFV,
EventStartsAfter: flags.EventStartsAfterFV,
EventStartsBefore: flags.EventStartsBeforeFV,
EventSubject: flags.EventSubjectFV,
RestoreCfg: makeRestoreCfgOpts(cmd),
ExportCfg: makeExportCfgOpts(cmd),
// populated contains the list of flags that appear in the
// command, according to pflags. Use this to differentiate
// between an "empty" and a "missing" value.
Populated: flags.GetPopulatedFlags(cmd),
}
}
// 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[flags.EmailReceivedAfterFN]; ok && !IsValidTimeFormat(opts.EmailReceivedAfter) {
return clues.New("invalid time format for email-received-after")
}
if _, ok := opts.Populated[flags.EmailReceivedBeforeFN]; ok && !IsValidTimeFormat(opts.EmailReceivedBefore) {
return clues.New("invalid time format for email-received-before")
}
if _, ok := opts.Populated[flags.EventStartsAfterFN]; ok && !IsValidTimeFormat(opts.EventStartsAfter) {
return clues.New("invalid time format for event-starts-after")
}
if _, ok := opts.Populated[flags.EventStartsBeforeFN]; ok && !IsValidTimeFormat(opts.EventStartsBefore) {
return clues.New("invalid time format for event-starts-before")
}
if _, ok := opts.Populated[flags.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)
}