selects list by name while export and restore #### Does this PR need a docs update or release note? - [x] ⛔ No #### Type of change <!--- Please check the type of change your PR introduces: ---> - [x] 🧹 Tech Debt/Cleanup #### Issue(s) #4754 #### Test Plan <!-- How will this be tested prior to merging.--> - [x] 💪 Manual - [x] ⚡ Unit test - [x] 💚 E2E
242 lines
6.3 KiB
Go
242 lines
6.3 KiB
Go
package utils
|
|
|
|
import (
|
|
"context"
|
|
"net/url"
|
|
"strings"
|
|
|
|
"github.com/alcionai/clues"
|
|
"github.com/spf13/cobra"
|
|
|
|
"github.com/alcionai/corso/src/cli/flags"
|
|
"github.com/alcionai/corso/src/pkg/logger"
|
|
"github.com/alcionai/corso/src/pkg/selectors"
|
|
)
|
|
|
|
type SharePointOpts struct {
|
|
SiteID []string
|
|
WebURL []string
|
|
|
|
Library string
|
|
FileName []string // for libraries, to duplicate onedrive interface
|
|
FolderPath []string // for libraries, to duplicate onedrive interface
|
|
FileCreatedAfter string
|
|
FileCreatedBefore string
|
|
FileModifiedAfter string
|
|
FileModifiedBefore string
|
|
|
|
Lists []string
|
|
|
|
PageFolder []string
|
|
Page []string
|
|
|
|
RestoreCfg RestoreCfgOpts
|
|
ExportCfg ExportCfgOpts
|
|
|
|
Populated flags.PopulatedFlags
|
|
}
|
|
|
|
func (s SharePointOpts) GetFileTimeField(flag string) string {
|
|
switch flag {
|
|
case flags.FileCreatedAfterFN:
|
|
return s.FileCreatedAfter
|
|
case flags.FileCreatedBeforeFN:
|
|
return s.FileCreatedBefore
|
|
case flags.FileModifiedAfterFN:
|
|
return s.FileModifiedAfter
|
|
case flags.FileModifiedBeforeFN:
|
|
return s.FileModifiedBefore
|
|
default:
|
|
return ""
|
|
}
|
|
}
|
|
|
|
func MakeSharePointOpts(cmd *cobra.Command) SharePointOpts {
|
|
return SharePointOpts{
|
|
SiteID: flags.SiteIDFV,
|
|
WebURL: flags.WebURLFV,
|
|
|
|
Library: flags.LibraryFV,
|
|
FileName: flags.FileNameFV,
|
|
FolderPath: flags.FolderPathFV,
|
|
FileCreatedAfter: flags.FileCreatedAfterFV,
|
|
FileCreatedBefore: flags.FileCreatedBeforeFV,
|
|
FileModifiedAfter: flags.FileModifiedAfterFV,
|
|
FileModifiedBefore: flags.FileModifiedBeforeFV,
|
|
|
|
Lists: flags.ListFV,
|
|
|
|
Page: flags.PageFV,
|
|
PageFolder: flags.PageFolderFV,
|
|
|
|
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),
|
|
}
|
|
}
|
|
|
|
func SharePointAllowedCategories() map[string]struct{} {
|
|
return map[string]struct{}{
|
|
flags.DataLibraries: {},
|
|
// flags.DataLists: {}, [TODO]: uncomment when lists are enabled
|
|
}
|
|
}
|
|
|
|
func AddCategories(sel *selectors.SharePointBackup, cats []string) *selectors.SharePointBackup {
|
|
if len(cats) == 0 {
|
|
// backup of sharepoint lists not enabled yet
|
|
// sel.Include(sel.LibraryFolders(selectors.Any()), sel.Lists(selectors.Any()))
|
|
sel.Include(sel.LibraryFolders(selectors.Any()))
|
|
}
|
|
|
|
for _, d := range cats {
|
|
switch d {
|
|
// backup of sharepoint lists not enabled yet
|
|
// case flags.DataLists:
|
|
// sel.Include(sel.Lists(selectors.Any()))
|
|
case flags.DataLibraries:
|
|
sel.Include(sel.LibraryFolders(selectors.Any()))
|
|
}
|
|
}
|
|
|
|
return sel
|
|
}
|
|
|
|
// ValidateSharePointRestoreFlags checks common flags for correctness and interdependencies
|
|
func ValidateSharePointRestoreFlags(backupID string, opts SharePointOpts) error {
|
|
if len(backupID) == 0 {
|
|
return clues.New("a backup ID is required")
|
|
}
|
|
|
|
// ensure url can parse all weburls provided by --site.
|
|
if _, ok := opts.Populated[flags.SiteFN]; ok {
|
|
for _, wu := range opts.WebURL {
|
|
if _, err := url.Parse(wu); err != nil {
|
|
return clues.New("invalid site url: " + wu)
|
|
}
|
|
}
|
|
}
|
|
|
|
return validateCommonTimeFlags(opts)
|
|
}
|
|
|
|
// AddSharePointInfo adds the scope of the provided values to the selector's
|
|
// filter set
|
|
func AddSharePointInfo(
|
|
sel *selectors.SharePointRestore,
|
|
v string,
|
|
f func(string) []selectors.SharePointScope,
|
|
) {
|
|
if len(v) == 0 {
|
|
return
|
|
}
|
|
|
|
sel.Filter(f(v))
|
|
}
|
|
|
|
// IncludeSharePointRestoreDataSelectors builds the common data-selector
|
|
// inclusions for SharePoint commands.
|
|
func IncludeSharePointRestoreDataSelectors(ctx context.Context, opts SharePointOpts) *selectors.SharePointRestore {
|
|
sites := opts.SiteID
|
|
|
|
folderPaths, fileNames := len(opts.FolderPath), len(opts.FileName)
|
|
siteIDs, webUrls := len(opts.SiteID), len(opts.WebURL)
|
|
lists := len(opts.Lists)
|
|
pageFolders, pageItems := len(opts.PageFolder), len(opts.Page)
|
|
|
|
if siteIDs == 0 {
|
|
sites = selectors.Any()
|
|
}
|
|
|
|
sel := selectors.NewSharePointRestore(sites)
|
|
|
|
if folderPaths+fileNames+webUrls+lists+pageFolders+pageItems == 0 {
|
|
sel.Include(sel.AllData())
|
|
return sel
|
|
}
|
|
|
|
if folderPaths+fileNames > 0 {
|
|
if fileNames == 0 {
|
|
opts.FileName = selectors.Any()
|
|
}
|
|
|
|
opts.FolderPath = trimFolderSlash(opts.FolderPath)
|
|
containsFolders, prefixFolders := splitFoldersIntoContainsAndPrefix(opts.FolderPath)
|
|
|
|
if len(containsFolders) > 0 {
|
|
sel.Include(sel.LibraryItems(containsFolders, opts.FileName))
|
|
}
|
|
|
|
if len(prefixFolders) > 0 {
|
|
sel.Include(sel.LibraryItems(prefixFolders, opts.FileName, selectors.PrefixMatch()))
|
|
}
|
|
}
|
|
|
|
if lists > 0 {
|
|
opts.Lists = trimFolderSlash(opts.Lists)
|
|
sel.Include(sel.ListItems(opts.Lists, opts.Lists, selectors.StrictEqualMatch()))
|
|
sel.Configure(selectors.Config{OnlyMatchItemNames: true})
|
|
}
|
|
|
|
if pageFolders+pageItems > 0 {
|
|
if pageItems == 0 {
|
|
opts.Page = selectors.Any()
|
|
}
|
|
|
|
opts.PageFolder = trimFolderSlash(opts.PageFolder)
|
|
containsFolders, prefixFolders := splitFoldersIntoContainsAndPrefix(opts.PageFolder)
|
|
|
|
if len(containsFolders) > 0 {
|
|
sel.Include(sel.PageItems(containsFolders, opts.Page))
|
|
}
|
|
|
|
if len(prefixFolders) > 0 {
|
|
sel.Include(sel.PageItems(prefixFolders, opts.Page, selectors.PrefixMatch()))
|
|
}
|
|
}
|
|
|
|
if webUrls > 0 {
|
|
urls := make([]string, 0, len(opts.WebURL))
|
|
|
|
for _, wu := range opts.WebURL {
|
|
// for normalization, ensure the site has a https:// prefix.
|
|
wu = strings.TrimPrefix(wu, "https://")
|
|
wu = strings.TrimPrefix(wu, "http://")
|
|
|
|
// don't add a prefix to path-only values
|
|
if len(wu) > 0 && wu != "*" && !strings.HasPrefix(wu, "/") {
|
|
wu = "https://" + wu
|
|
}
|
|
|
|
u, err := url.Parse(wu)
|
|
if err != nil {
|
|
// shouldn't be possible to err, if we called validation first.
|
|
logger.Ctx(ctx).With("web_url", wu).Error("malformed web url")
|
|
continue
|
|
}
|
|
|
|
urls = append(urls, u.String())
|
|
}
|
|
|
|
sel.Include(sel.WebURL(urls))
|
|
}
|
|
|
|
return sel
|
|
}
|
|
|
|
// FilterSharePointRestoreInfoSelectors builds the common info-selector filters.
|
|
func FilterSharePointRestoreInfoSelectors(
|
|
sel *selectors.SharePointRestore,
|
|
opts SharePointOpts,
|
|
) {
|
|
AddSharePointInfo(sel, opts.Library, sel.Library)
|
|
AddSharePointInfo(sel, opts.FileCreatedAfter, sel.CreatedAfter)
|
|
AddSharePointInfo(sel, opts.FileCreatedBefore, sel.CreatedBefore)
|
|
AddSharePointInfo(sel, opts.FileModifiedAfter, sel.ModifiedAfter)
|
|
AddSharePointInfo(sel, opts.FileModifiedBefore, sel.ModifiedBefore)
|
|
}
|