handles hyperlink columns and fields (#4971)
Hyperlink column of a list item is not identifiable from GRAPH's response. Hence this is a workaround to handle such fields until a column definition is introduced for `Hyperlink`. #### 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] 🌻 Feature #### Issue(s) #4754 #### Test Plan <!-- How will this be tested prior to merging.--> - [x] 💪 Manual - [x] ⚡ Unit test - [x] 💚 E2E
This commit is contained in:
parent
06afd53660
commit
8989fcd7cd
@ -1,5 +1,9 @@
|
|||||||
package api
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/alcionai/corso/src/internal/common/keys"
|
||||||
|
)
|
||||||
|
|
||||||
// Well knwon Folder Names
|
// Well knwon Folder Names
|
||||||
// Mail Definitions: https://docs.microsoft.com/en-us/graph/api/resources/mailfolder?view=graph-rest-1.0
|
// Mail Definitions: https://docs.microsoft.com/en-us/graph/api/resources/mailfolder?view=graph-rest-1.0
|
||||||
const (
|
const (
|
||||||
@ -11,3 +15,82 @@ const (
|
|||||||
// Kiota JSON invalid JSON error message.
|
// Kiota JSON invalid JSON error message.
|
||||||
invalidJSON = "invalid json type"
|
invalidJSON = "invalid json type"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// ************** Lists starts *****************
|
||||||
|
|
||||||
|
const (
|
||||||
|
AttachmentsColumnName = "Attachments"
|
||||||
|
EditColumnName = "Edit"
|
||||||
|
ContentTypeColumnName = "ContentType"
|
||||||
|
CreatedColumnName = "Created"
|
||||||
|
ModifiedColumnName = "Modified"
|
||||||
|
AuthorLookupIDColumnName = "AuthorLookupId"
|
||||||
|
EditorLookupIDColumnName = "EditorLookupId"
|
||||||
|
AppAuthorLookupIDColumnName = "AppAuthorLookupId"
|
||||||
|
TitleColumnName = "Title"
|
||||||
|
|
||||||
|
ContentTypeColumnDisplayName = "Content Type"
|
||||||
|
|
||||||
|
AddressKey = "address"
|
||||||
|
CoordinatesKey = "coordinates"
|
||||||
|
DisplayNameKey = "displayName"
|
||||||
|
LocationURIKey = "locationUri"
|
||||||
|
UniqueIDKey = "uniqueId"
|
||||||
|
|
||||||
|
// entries that are nested within a second layer
|
||||||
|
CityKey = "city"
|
||||||
|
CountryKey = "countryOrRegion"
|
||||||
|
PostalCodeKey = "postalCode"
|
||||||
|
StateKey = "state"
|
||||||
|
StreetKey = "street"
|
||||||
|
LatitudeKey = "latitude"
|
||||||
|
LongitudeKey = "longitude"
|
||||||
|
|
||||||
|
CountryOrRegionFN = "CountryOrRegion"
|
||||||
|
StateFN = "State"
|
||||||
|
CityFN = "City"
|
||||||
|
PostalCodeFN = "PostalCode"
|
||||||
|
StreetFN = "Street"
|
||||||
|
GeoLocFN = "GeoLoc"
|
||||||
|
DispNameFN = "DispName"
|
||||||
|
|
||||||
|
HyperlinkDescriptionKey = "Description"
|
||||||
|
HyperlinkURLKey = "Url"
|
||||||
|
|
||||||
|
LinkTitleFieldNamePart = "LinkTitle"
|
||||||
|
ChildCountFieldNamePart = "ChildCount"
|
||||||
|
LookupIDFieldNamePart = "LookupId"
|
||||||
|
|
||||||
|
ReadOnlyOrHiddenFieldNamePrefix = "_"
|
||||||
|
DescoratorFieldNamePrefix = "@"
|
||||||
|
|
||||||
|
WebTemplateExtensionsListTemplate = "webTemplateExtensionsList"
|
||||||
|
// This issue https://github.com/alcionai/corso/issues/4932
|
||||||
|
// tracks to backup/restore supportability of `documentLibrary` templated lists
|
||||||
|
DocumentLibraryListTemplate = "documentLibrary"
|
||||||
|
SharingLinksListTemplate = "sharingLinks"
|
||||||
|
AccessRequestsListTemplate = "accessRequest"
|
||||||
|
)
|
||||||
|
|
||||||
|
var addressFieldNames = []string{
|
||||||
|
AddressKey,
|
||||||
|
CoordinatesKey,
|
||||||
|
DisplayNameKey,
|
||||||
|
LocationURIKey,
|
||||||
|
UniqueIDKey,
|
||||||
|
}
|
||||||
|
|
||||||
|
var legacyColumns = keys.Set{
|
||||||
|
AttachmentsColumnName: {},
|
||||||
|
EditColumnName: {},
|
||||||
|
ContentTypeColumnDisplayName: {},
|
||||||
|
}
|
||||||
|
|
||||||
|
var SkipListTemplates = keys.Set{
|
||||||
|
WebTemplateExtensionsListTemplate: {},
|
||||||
|
DocumentLibraryListTemplate: {},
|
||||||
|
SharingLinksListTemplate: {},
|
||||||
|
AccessRequestsListTemplate: {},
|
||||||
|
}
|
||||||
|
|
||||||
|
// ************** Lists ends *****************
|
||||||
|
|||||||
@ -18,78 +18,6 @@ import (
|
|||||||
|
|
||||||
var ErrSkippableListTemplate = clues.New("unable to create lists with skippable templates")
|
var ErrSkippableListTemplate = clues.New("unable to create lists with skippable templates")
|
||||||
|
|
||||||
const (
|
|
||||||
AttachmentsColumnName = "Attachments"
|
|
||||||
EditColumnName = "Edit"
|
|
||||||
ContentTypeColumnName = "ContentType"
|
|
||||||
CreatedColumnName = "Created"
|
|
||||||
ModifiedColumnName = "Modified"
|
|
||||||
AuthorLookupIDColumnName = "AuthorLookupId"
|
|
||||||
EditorLookupIDColumnName = "EditorLookupId"
|
|
||||||
AppAuthorLookupIDColumnName = "AppAuthorLookupId"
|
|
||||||
TitleColumnName = "Title"
|
|
||||||
|
|
||||||
ContentTypeColumnDisplayName = "Content Type"
|
|
||||||
|
|
||||||
AddressKey = "address"
|
|
||||||
CoordinatesKey = "coordinates"
|
|
||||||
DisplayNameKey = "displayName"
|
|
||||||
LocationURIKey = "locationUri"
|
|
||||||
UniqueIDKey = "uniqueId"
|
|
||||||
|
|
||||||
// entries that are nested within a second layer
|
|
||||||
CityKey = "city"
|
|
||||||
CountryKey = "countryOrRegion"
|
|
||||||
PostalCodeKey = "postalCode"
|
|
||||||
StateKey = "state"
|
|
||||||
StreetKey = "street"
|
|
||||||
LatitudeKey = "latitude"
|
|
||||||
LongitudeKey = "longitude"
|
|
||||||
|
|
||||||
CountryOrRegionFN = "CountryOrRegion"
|
|
||||||
StateFN = "State"
|
|
||||||
CityFN = "City"
|
|
||||||
PostalCodeFN = "PostalCode"
|
|
||||||
StreetFN = "Street"
|
|
||||||
GeoLocFN = "GeoLoc"
|
|
||||||
DispNameFN = "DispName"
|
|
||||||
|
|
||||||
LinkTitleFieldNamePart = "LinkTitle"
|
|
||||||
ChildCountFieldNamePart = "ChildCount"
|
|
||||||
LookupIDFieldNamePart = "LookupId"
|
|
||||||
|
|
||||||
ReadOnlyOrHiddenFieldNamePrefix = "_"
|
|
||||||
DescoratorFieldNamePrefix = "@"
|
|
||||||
|
|
||||||
WebTemplateExtensionsListTemplate = "webTemplateExtensionsList"
|
|
||||||
// This issue https://github.com/alcionai/corso/issues/4932
|
|
||||||
// tracks to backup/restore supportability of `documentLibrary` templated lists
|
|
||||||
DocumentLibraryListTemplate = "documentLibrary"
|
|
||||||
SharingLinksListTemplate = "sharingLinks"
|
|
||||||
AccessRequestsListTemplate = "accessRequest"
|
|
||||||
)
|
|
||||||
|
|
||||||
var addressFieldNames = []string{
|
|
||||||
AddressKey,
|
|
||||||
CoordinatesKey,
|
|
||||||
DisplayNameKey,
|
|
||||||
LocationURIKey,
|
|
||||||
UniqueIDKey,
|
|
||||||
}
|
|
||||||
|
|
||||||
var legacyColumns = keys.Set{
|
|
||||||
AttachmentsColumnName: {},
|
|
||||||
EditColumnName: {},
|
|
||||||
ContentTypeColumnDisplayName: {},
|
|
||||||
}
|
|
||||||
|
|
||||||
var SkipListTemplates = keys.Set{
|
|
||||||
WebTemplateExtensionsListTemplate: {},
|
|
||||||
DocumentLibraryListTemplate: {},
|
|
||||||
SharingLinksListTemplate: {},
|
|
||||||
AccessRequestsListTemplate: {},
|
|
||||||
}
|
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
// controller
|
// controller
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
@ -507,6 +435,11 @@ func retrieveFieldData(orig models.FieldValueSetable, columnNames map[string]any
|
|||||||
additionalData[fieldName] = concatenatedAddress
|
additionalData[fieldName] = concatenatedAddress
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if hyperLinkField, fieldName, ok := hasHyperLinkFields(additionalData); ok {
|
||||||
|
concatenatedHyperlink := concatenateHyperLinkFields(hyperLinkField)
|
||||||
|
additionalData[fieldName] = concatenatedHyperlink
|
||||||
|
}
|
||||||
|
|
||||||
fields.SetAdditionalData(additionalData)
|
fields.SetAdditionalData(additionalData)
|
||||||
|
|
||||||
return fields
|
return fields
|
||||||
@ -547,6 +480,22 @@ func hasAddressFields(additionalData map[string]any) (map[string]any, string, bo
|
|||||||
return nil, "", false
|
return nil, "", false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func hasHyperLinkFields(additionalData map[string]any) (map[string]any, string, bool) {
|
||||||
|
for fieldName, value := range additionalData {
|
||||||
|
nestedFields, ok := value.(map[string]any)
|
||||||
|
if !ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if keys.HasKeys(nestedFields,
|
||||||
|
[]string{HyperlinkDescriptionKey, HyperlinkURLKey}...) {
|
||||||
|
return nestedFields, fieldName, true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, "", false
|
||||||
|
}
|
||||||
|
|
||||||
func concatenateAddressFields(addressFields map[string]any) string {
|
func concatenateAddressFields(addressFields map[string]any) string {
|
||||||
parts := make([]string, 0)
|
parts := make([]string, 0)
|
||||||
|
|
||||||
@ -574,6 +523,24 @@ func concatenateAddressFields(addressFields map[string]any) string {
|
|||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func concatenateHyperLinkFields(hyperlinkFields map[string]any) string {
|
||||||
|
parts := make([]string, 0)
|
||||||
|
|
||||||
|
if v, err := str.AnyValueToString(HyperlinkURLKey, hyperlinkFields); err == nil {
|
||||||
|
parts = append(parts, v)
|
||||||
|
}
|
||||||
|
|
||||||
|
if v, err := str.AnyValueToString(HyperlinkDescriptionKey, hyperlinkFields); err == nil {
|
||||||
|
parts = append(parts, v)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(parts) > 0 {
|
||||||
|
return strings.Join(parts, ",")
|
||||||
|
}
|
||||||
|
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
func addressKeyToVal(fields map[string]any, key string) string {
|
func addressKeyToVal(fields map[string]any, key string) string {
|
||||||
if v, err := str.AnyValueToString(key, fields); err == nil {
|
if v, err := str.AnyValueToString(key, fields); err == nil {
|
||||||
return v
|
return v
|
||||||
|
|||||||
@ -650,6 +650,59 @@ func (suite *ListsUnitSuite) TestHasAddressFields() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (suite *ListsUnitSuite) TestConcatenateHyperlinkFields() {
|
||||||
|
t := suite.T()
|
||||||
|
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
hyperlinkFields map[string]any
|
||||||
|
expectedResult string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "Valid Hyperlink",
|
||||||
|
hyperlinkFields: map[string]any{
|
||||||
|
HyperlinkURLKey: ptr.To("https://www.example.com"),
|
||||||
|
HyperlinkDescriptionKey: ptr.To("Example Website"),
|
||||||
|
},
|
||||||
|
expectedResult: "https://www.example.com,Example Website",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Empty Hyperlink Fields",
|
||||||
|
hyperlinkFields: map[string]any{
|
||||||
|
HyperlinkURLKey: nil,
|
||||||
|
HyperlinkDescriptionKey: nil,
|
||||||
|
},
|
||||||
|
expectedResult: "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Missing Description",
|
||||||
|
hyperlinkFields: map[string]any{
|
||||||
|
HyperlinkURLKey: ptr.To("https://www.example.com"),
|
||||||
|
},
|
||||||
|
expectedResult: "https://www.example.com",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Missing URL",
|
||||||
|
hyperlinkFields: map[string]any{
|
||||||
|
HyperlinkDescriptionKey: ptr.To("Example Website"),
|
||||||
|
},
|
||||||
|
expectedResult: "Example Website",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Empty Input",
|
||||||
|
hyperlinkFields: map[string]any{},
|
||||||
|
expectedResult: "",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range tests {
|
||||||
|
suite.Run(test.name, func() {
|
||||||
|
result := concatenateHyperLinkFields(test.hyperlinkFields)
|
||||||
|
assert.Equal(t, test.expectedResult, result)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
type ListsAPIIntgSuite struct {
|
type ListsAPIIntgSuite struct {
|
||||||
tester.Suite
|
tester.Suite
|
||||||
its intgTesterSetup
|
its intgTesterSetup
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user