Define struct and interface for corso paths (#339)
* Define struct and interface for corso paths * Add wrapper for ExchangeMail as an example
This commit is contained in:
parent
532922f662
commit
da8ff3c267
104
src/internal/path/exchange_path.go
Normal file
104
src/internal/path/exchange_path.go
Normal file
@ -0,0 +1,104 @@
|
||||
package path
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
const (
|
||||
emailCategory = "email"
|
||||
)
|
||||
|
||||
var _ Path = &ExchangeMail{}
|
||||
|
||||
type ExchangeMail struct {
|
||||
Base
|
||||
}
|
||||
|
||||
// NewExchangeEmailPath creates and returns a new ExchangeEmailPath struct after
|
||||
// verifying the path is properly escaped and contains information for the
|
||||
// required segments.
|
||||
func NewExchangeMail(
|
||||
tenant string,
|
||||
user string,
|
||||
folder []string,
|
||||
item string,
|
||||
) (*ExchangeMail, error) {
|
||||
tmpFolder := strings.Join(folder, "")
|
||||
if err := validateExchangeMailSegments(tenant, user, tmpFolder, item); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
p := newPath([][]string{
|
||||
{tenant},
|
||||
{emailCategory},
|
||||
{user},
|
||||
folder,
|
||||
{item},
|
||||
})
|
||||
|
||||
return &ExchangeMail{p}, nil
|
||||
}
|
||||
|
||||
func NewExchangeMailFromEscapedSegments(tenant, user, folder, item string) (*ExchangeMail, error) {
|
||||
if err := validateExchangeMailSegments(tenant, user, folder, item); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
p, err := newPathFromEscapedSegments([]string{tenant, emailCategory, user, folder, item})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &ExchangeMail{p}, nil
|
||||
}
|
||||
|
||||
func validateExchangeMailSegments(tenant, user, folder, item string) error {
|
||||
if len(tenant) == 0 {
|
||||
return errors.Wrap(errMissingSegment, "tenant")
|
||||
}
|
||||
|
||||
if len(user) == 0 {
|
||||
return errors.Wrap(errMissingSegment, "user")
|
||||
}
|
||||
|
||||
if len(folder) == 0 {
|
||||
return errors.Wrap(errMissingSegment, "mail folder")
|
||||
}
|
||||
|
||||
if len(item) == 0 {
|
||||
return errors.Wrap(errMissingSegment, "mail item")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Tenant returns the tenant ID for the referenced email resource.
|
||||
func (emp ExchangeMail) Tenant() string {
|
||||
return emp.segment(0)
|
||||
}
|
||||
|
||||
// Cateory returns an identifier noting this is a path for an email resource.
|
||||
func (emp ExchangeMail) Category() string {
|
||||
return emp.segment(1)
|
||||
}
|
||||
|
||||
// User returns the user ID for the referenced email resource.
|
||||
func (emp ExchangeMail) User() string {
|
||||
return emp.segment(2)
|
||||
}
|
||||
|
||||
// Folder returns the folder segment for the referenced email resource.
|
||||
func (emp ExchangeMail) Folder() string {
|
||||
return emp.segment(3)
|
||||
}
|
||||
|
||||
func (emp ExchangeMail) FolderElements() []string {
|
||||
return emp.unescapedSegmentElements(3)
|
||||
}
|
||||
|
||||
// Mail returns the email ID for the referenced email resource.
|
||||
func (emp ExchangeMail) Item() string {
|
||||
return emp.segment(4)
|
||||
}
|
||||
98
src/internal/path/path.go
Normal file
98
src/internal/path/path.go
Normal file
@ -0,0 +1,98 @@
|
||||
// Package path provides a set of functions for wrangling paths from the outside
|
||||
// world into paths that corso can understand. Paths use the standard Unix path
|
||||
// separator character '/'. If for some reason an individual element in a raw
|
||||
// path contains the '/' character, it should be escaped with '\'. If the path
|
||||
// contains '\' it should be escaped by turning it into '\\'.
|
||||
//
|
||||
// Paths can be split into elements by splitting on '/' if the '/' is not
|
||||
// escaped. Additionally, corso may operate on segments in a path. Segments are
|
||||
// made up of one or more path elements.
|
||||
//
|
||||
// Examples of paths splitting by elements and canonicalization with escaping:
|
||||
// 1.
|
||||
// input path: `this/is/a/path`
|
||||
// elements of path: `this`, `is`, `a`, `path`
|
||||
// 2.
|
||||
// input path: `this/is\/a/path`
|
||||
// elements of path: `this`, `is/a`, `path`
|
||||
// 3.
|
||||
// input path: `this/is\\/a/path`
|
||||
// elements of path: `this`, `is\`, `a`, `path`
|
||||
// 4.
|
||||
// input path: `this/is\\\/a/path`
|
||||
// elements of path: `this`, `is\/a`, `path`
|
||||
// 5.
|
||||
// input path: `this/is//a/path`
|
||||
// elements of path: `this`, `is`, `a`, `path`
|
||||
// 6.
|
||||
// input path: `this/is\//a/path`
|
||||
// elements of path: `this`, `is/`, `a`, `path`
|
||||
// 7.
|
||||
// input path: `this/is/a/path/`
|
||||
// elements of path: `this`, `is`, `a`, `path`
|
||||
// 8.
|
||||
// input path: `this/is/a/path\/`
|
||||
// elements of path: `this`, `is`, `a`, `path/`
|
||||
|
||||
package path
|
||||
|
||||
import (
|
||||
"errors"
|
||||
)
|
||||
|
||||
var errMissingSegment = errors.New("missing required path segment")
|
||||
|
||||
// TODO(ashmrtn): Getting the category should either be through type-switches or
|
||||
// through a function, but if it's a function it should re-use existing enums
|
||||
// for resource types.
|
||||
// For now, adding generic functions to pull information from segments.
|
||||
// Resources that don't have the requested information should return an empty
|
||||
// string.
|
||||
type Path interface {
|
||||
String() string
|
||||
Tenant() string
|
||||
User() string
|
||||
Folder() string
|
||||
Item() string
|
||||
}
|
||||
|
||||
type Base struct {
|
||||
}
|
||||
|
||||
// newPath takes a path that is broken into segments and elements in the segment
|
||||
// and returns a Base. Each element in the input is escaped.
|
||||
func newPath(segments [][]string) Base {
|
||||
return Base{}
|
||||
}
|
||||
|
||||
// NewPathFromEscapedSegments takes already escaped segments of a path, verifies
|
||||
// the segments are escaped properly, and returns a new Base struct. If there is
|
||||
// an unescaped trailing '/' it is removed.
|
||||
func newPathFromEscapedSegments(segments []string) (Base, error) {
|
||||
return Base{}, errors.New("not implemented")
|
||||
}
|
||||
|
||||
// String returns a string that contains all path segments joined
|
||||
// together. Elements of the path that need escaping will be escaped.
|
||||
func (p Base) String() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
// segment returns the nth segment of the path. Path segment indices are
|
||||
// 0-based.
|
||||
func (p Base) segment(n int) string {
|
||||
return ""
|
||||
}
|
||||
|
||||
// unescapedSegmentElements returns the unescaped version of the elements that
|
||||
// comprise the requested segment.
|
||||
func (p Base) unescapedSegmentElements(n int) []string {
|
||||
return nil
|
||||
}
|
||||
|
||||
// TransformedSegments returns a slice of the path segments where each segments
|
||||
// has also been transformed such that it contains no characters outside the set
|
||||
// of acceptable file system path characters.
|
||||
func (p Base) TransformedSegments() []string {
|
||||
return nil
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user