Trim trailing '/' from CLI input for restore/details (#1175)
## Description Use paths package to trim unescaped trailing '/' characters from input for Exchange mail and OneDrive folder names. Add tests for Exchange showing that the trimming also works properly if the folder name ends with '/'. ## Type of change <!--- Please check the type of change your PR introduces: ---> - [ ] 🌻 Feature - [x] 🐛 Bugfix - [ ] 🗺️ Documentation - [ ] 🤖 Test - [ ] 💻 CI/Deployment - [ ] 🐹 Trivial/Minor ## Issue(s) * closes #1147 ## Test Plan <!-- How will this be tested prior to merging.--> - [x] 💪 Manual - [x] ⚡ Unit test - [ ] 💚 E2E
This commit is contained in:
parent
7d72cd12a4
commit
72a3c7ab3b
@ -142,6 +142,8 @@ func IncludeExchangeRestoreDataSelectors(
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
opts.EmailFolder = trimFolderSlash(opts.EmailFolder)
|
||||||
|
|
||||||
// or add selectors for each type of data
|
// or add selectors for each type of data
|
||||||
AddExchangeInclude(sel, opts.Users, opts.ContactFolder, opts.Contact, sel.Contacts)
|
AddExchangeInclude(sel, opts.Users, opts.ContactFolder, opts.Contact, sel.Contacts)
|
||||||
AddExchangeInclude(sel, opts.Users, opts.EmailFolder, opts.Email, sel.Mails)
|
AddExchangeInclude(sel, opts.Users, opts.EmailFolder, opts.Email, sel.Mails)
|
||||||
|
|||||||
@ -7,6 +7,7 @@ import (
|
|||||||
"github.com/spf13/pflag"
|
"github.com/spf13/pflag"
|
||||||
|
|
||||||
"github.com/alcionai/corso/src/internal/common"
|
"github.com/alcionai/corso/src/internal/common"
|
||||||
|
"github.com/alcionai/corso/src/pkg/path"
|
||||||
)
|
)
|
||||||
|
|
||||||
type PopulatedFlags map[string]struct{}
|
type PopulatedFlags map[string]struct{}
|
||||||
@ -50,3 +51,16 @@ func IsValidBool(in string) bool {
|
|||||||
_, err := strconv.ParseBool(in)
|
_, err := strconv.ParseBool(in)
|
||||||
return err == nil
|
return err == nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// trimFolderSlash takes a set of folder paths and returns a set of folder paths
|
||||||
|
// with any unescaped trailing `/` characters removed.
|
||||||
|
func trimFolderSlash(folders []string) []string {
|
||||||
|
res := make([]string, 0, len(folders))
|
||||||
|
|
||||||
|
for _, p := range folders {
|
||||||
|
// Use path package because it has logic to handle escaping already.
|
||||||
|
res = append(res, path.TrimTrailingSlash(p))
|
||||||
|
}
|
||||||
|
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|||||||
@ -87,6 +87,8 @@ func IncludeOneDriveRestoreDataSelectors(
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
opts.Paths = trimFolderSlash(opts.Paths)
|
||||||
|
|
||||||
if lp == 0 {
|
if lp == 0 {
|
||||||
opts.Paths = selectors.Any()
|
opts.Paths = selectors.Any()
|
||||||
}
|
}
|
||||||
|
|||||||
39
src/cli/utils/testdata/opts.go
vendored
39
src/cli/utils/testdata/opts.go
vendored
@ -139,8 +139,38 @@ var (
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "EmailsBySubject",
|
Name: "EmailsFolderPrefixMatchTrailingSlash",
|
||||||
Expected: testdata.ExchangeEmailItems,
|
Expected: testdata.ExchangeEmailItems,
|
||||||
|
Opts: utils.ExchangeOpts{
|
||||||
|
EmailFolder: []string{testdata.ExchangeEmailInboxPath.Folder() + "/"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "EmailsFolderWithSlashPrefixMatch",
|
||||||
|
Expected: []details.DetailsEntry{
|
||||||
|
testdata.ExchangeEmailItems[1],
|
||||||
|
testdata.ExchangeEmailItems[2],
|
||||||
|
},
|
||||||
|
Opts: utils.ExchangeOpts{
|
||||||
|
EmailFolder: []string{testdata.ExchangeEmailBasePath2.Folder()},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "EmailsFolderWithSlashPrefixMatchTrailingSlash",
|
||||||
|
Expected: []details.DetailsEntry{
|
||||||
|
testdata.ExchangeEmailItems[1],
|
||||||
|
testdata.ExchangeEmailItems[2],
|
||||||
|
},
|
||||||
|
Opts: utils.ExchangeOpts{
|
||||||
|
EmailFolder: []string{testdata.ExchangeEmailBasePath2.Folder() + "/"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "EmailsBySubject",
|
||||||
|
Expected: []details.DetailsEntry{
|
||||||
|
testdata.ExchangeEmailItems[0],
|
||||||
|
testdata.ExchangeEmailItems[1],
|
||||||
|
},
|
||||||
Opts: utils.ExchangeOpts{
|
Opts: utils.ExchangeOpts{
|
||||||
EmailSender: "a-person",
|
EmailSender: "a-person",
|
||||||
},
|
},
|
||||||
@ -180,8 +210,11 @@ var (
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "MultipleMailShortRef",
|
Name: "MultipleMailShortRef",
|
||||||
Expected: testdata.ExchangeEmailItems,
|
Expected: []details.DetailsEntry{
|
||||||
|
testdata.ExchangeEmailItems[0],
|
||||||
|
testdata.ExchangeEmailItems[1],
|
||||||
|
},
|
||||||
Opts: utils.ExchangeOpts{
|
Opts: utils.ExchangeOpts{
|
||||||
Email: []string{
|
Email: []string{
|
||||||
testdata.ExchangeEmailItemPath1.ShortRef(),
|
testdata.ExchangeEmailItemPath1.ShortRef(),
|
||||||
|
|||||||
@ -145,7 +145,7 @@ func (pb *Builder) appendElements(escaped bool, elements []string) error {
|
|||||||
tmp := e
|
tmp := e
|
||||||
|
|
||||||
if escaped {
|
if escaped {
|
||||||
tmp = trimTrailingSlash(tmp)
|
tmp = TrimTrailingSlash(tmp)
|
||||||
// If tmp was just the path separator then it will be empty now.
|
// If tmp was just the path separator then it will be empty now.
|
||||||
if len(tmp) == 0 {
|
if len(tmp) == 0 {
|
||||||
continue
|
continue
|
||||||
@ -310,7 +310,7 @@ func (pb Builder) ToDataLayerOneDrivePath(
|
|||||||
// resource-specific type. If p does not match any resource-specific paths or
|
// resource-specific type. If p does not match any resource-specific paths or
|
||||||
// is malformed returns an error.
|
// is malformed returns an error.
|
||||||
func FromDataLayerPath(p string, isItem bool) (Path, error) {
|
func FromDataLayerPath(p string, isItem bool) (Path, error) {
|
||||||
p = trimTrailingSlash(p)
|
p = TrimTrailingSlash(p)
|
||||||
// If p was just the path separator then it will be empty now.
|
// If p was just the path separator then it will be empty now.
|
||||||
if len(p) == 0 {
|
if len(p) == 0 {
|
||||||
return nil, errors.Errorf("logically empty path given: %s", p)
|
return nil, errors.Errorf("logically empty path given: %s", p)
|
||||||
@ -437,11 +437,11 @@ func validateEscapedElement(element string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// trimTrailingSlash takes an escaped path element and returns an escaped path
|
// TrimTrailingSlash takes an escaped path element and returns an escaped path
|
||||||
// element with the trailing path separator character(s) removed if they were not
|
// element with the trailing path separator character(s) removed if they were not
|
||||||
// escaped. If there were no trailing path separator character(s) or the separator(s)
|
// escaped. If there were no trailing path separator character(s) or the separator(s)
|
||||||
// were escaped the input is returned unchanged.
|
// were escaped the input is returned unchanged.
|
||||||
func trimTrailingSlash(element string) string {
|
func TrimTrailingSlash(element string) string {
|
||||||
for len(element) > 0 && element[len(element)-1] == pathSeparator {
|
for len(element) > 0 && element[len(element)-1] == pathSeparator {
|
||||||
lastIdx := len(element) - 1
|
lastIdx := len(element) - 1
|
||||||
numSlashes := 0
|
numSlashes := 0
|
||||||
|
|||||||
@ -92,7 +92,10 @@ func (suite *SelectorReduceSuite) TestReduce() {
|
|||||||
|
|
||||||
return sel
|
return sel
|
||||||
},
|
},
|
||||||
expected: testdata.ExchangeEmailItems,
|
expected: []details.DetailsEntry{
|
||||||
|
testdata.ExchangeEmailItems[0],
|
||||||
|
testdata.ExchangeEmailItems[1],
|
||||||
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "ExchangeMailReceivedTime",
|
name: "ExchangeMailReceivedTime",
|
||||||
|
|||||||
18
src/pkg/selectors/testdata/details.go
vendored
18
src/pkg/selectors/testdata/details.go
vendored
@ -36,6 +36,7 @@ func mustAppendPath(p path.Path, newElement string, isItem bool) path.Path {
|
|||||||
const (
|
const (
|
||||||
ItemName1 = "item1"
|
ItemName1 = "item1"
|
||||||
ItemName2 = "item2"
|
ItemName2 = "item2"
|
||||||
|
ItemName3 = "item3"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@ -44,9 +45,11 @@ var (
|
|||||||
|
|
||||||
ExchangeEmailInboxPath = mustParsePath("tenant-id/exchange/user-id/email/Inbox", false)
|
ExchangeEmailInboxPath = mustParsePath("tenant-id/exchange/user-id/email/Inbox", false)
|
||||||
ExchangeEmailBasePath = mustAppendPath(ExchangeEmailInboxPath, "subfolder", false)
|
ExchangeEmailBasePath = mustAppendPath(ExchangeEmailInboxPath, "subfolder", false)
|
||||||
ExchangeEmailBasePath2 = mustAppendPath(ExchangeEmailInboxPath, "othersubfolder", false)
|
ExchangeEmailBasePath2 = mustAppendPath(ExchangeEmailInboxPath, "othersubfolder/", false)
|
||||||
|
ExchangeEmailBasePath3 = mustAppendPath(ExchangeEmailBasePath2, "subsubfolder", false)
|
||||||
ExchangeEmailItemPath1 = mustAppendPath(ExchangeEmailBasePath, ItemName1, true)
|
ExchangeEmailItemPath1 = mustAppendPath(ExchangeEmailBasePath, ItemName1, true)
|
||||||
ExchangeEmailItemPath2 = mustAppendPath(ExchangeEmailBasePath2, ItemName2, true)
|
ExchangeEmailItemPath2 = mustAppendPath(ExchangeEmailBasePath2, ItemName2, true)
|
||||||
|
ExchangeEmailItemPath3 = mustAppendPath(ExchangeEmailBasePath3, ItemName3, true)
|
||||||
|
|
||||||
ExchangeEmailItems = []details.DetailsEntry{
|
ExchangeEmailItems = []details.DetailsEntry{
|
||||||
{
|
{
|
||||||
@ -75,6 +78,19 @@ var (
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
RepoRef: ExchangeEmailItemPath3.String(),
|
||||||
|
ShortRef: ExchangeEmailItemPath3.ShortRef(),
|
||||||
|
ParentRef: ExchangeEmailItemPath3.ToBuilder().Dir().ShortRef(),
|
||||||
|
ItemInfo: details.ItemInfo{
|
||||||
|
Exchange: &details.ExchangeInfo{
|
||||||
|
ItemType: details.ExchangeMail,
|
||||||
|
Sender: "another-person",
|
||||||
|
Subject: "baz",
|
||||||
|
Received: Time2,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
ExchangeContactsRootPath = mustParsePath("tenant-id/exchange/user-id/contacts/contacts", false)
|
ExchangeContactsRootPath = mustParsePath("tenant-id/exchange/user-id/contacts/contacts", false)
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user