handles location columns and fields (#4970)

Location column of a list item is not identifiable from GRAPH's
response.
Hence this is a maneouver to handle such fields until a column
definition is introduced for `Location`.

#### 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

---------

Co-authored-by: aviator-app[bot] <48659329+aviator-app[bot]@users.noreply.github.com>
This commit is contained in:
Hitesh Pattanayak 2024-01-13 11:35:28 +05:30 committed by GitHub
parent b459d27cc7
commit 06afd53660
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 265 additions and 52 deletions

View File

@ -2,12 +2,15 @@ package api
import (
"context"
"fmt"
"strings"
"github.com/alcionai/clues"
"github.com/microsoftgraph/msgraph-sdk-go/models"
"github.com/alcionai/corso/src/internal/common/keys"
"github.com/alcionai/corso/src/internal/common/ptr"
"github.com/alcionai/corso/src/internal/common/str"
"github.com/alcionai/corso/src/pkg/backup/details"
"github.com/alcionai/corso/src/pkg/fault"
"github.com/alcionai/corso/src/pkg/services/m365/api/graph"
@ -28,19 +31,29 @@ const (
ContentTypeColumnDisplayName = "Content Type"
AddressFieldName = "address"
CoordinatesFieldName = "coordinates"
DisplayNameFieldName = "displayName"
LocationURIFieldName = "locationUri"
UniqueIDFieldName = "uniqueId"
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"
CountryOrRegionFieldName = "CountryOrRegion"
StateFieldName = "State"
CityFieldName = "City"
PostalCodeFieldName = "PostalCode"
StreetFieldName = "Street"
GeoLocFieldName = "GeoLoc"
DispNameFieldName = "DispName"
LinkTitleFieldNamePart = "LinkTitle"
ChildCountFieldNamePart = "ChildCount"
LookupIDFieldNamePart = "LookupId"
@ -56,6 +69,14 @@ const (
AccessRequestsListTemplate = "accessRequest"
)
var addressFieldNames = []string{
AddressKey,
CoordinatesKey,
DisplayNameKey,
LocationURIKey,
UniqueIDKey,
}
var legacyColumns = keys.Set{
AttachmentsColumnName: {},
EditColumnName: {},
@ -481,6 +502,11 @@ func retrieveFieldData(orig models.FieldValueSetable, columnNames map[string]any
fields := models.NewFieldValueSet()
additionalData := setAdditionalDataByColumnNames(orig, columnNames)
if addressField, fieldName, ok := hasAddressFields(additionalData); ok {
concatenatedAddress := concatenateAddressFields(addressField)
additionalData[fieldName] = concatenatedAddress
}
fields.SetAdditionalData(additionalData)
return fields
@ -506,6 +532,58 @@ func setAdditionalDataByColumnNames(
return filteredData
}
func hasAddressFields(additionalData map[string]any) (map[string]any, string, bool) {
for k, v := range additionalData {
nestedFields, ok := v.(map[string]any)
if !ok || keys.HasKeys(nestedFields, GeoLocFN) {
continue
}
if keys.HasKeys(nestedFields, addressFieldNames...) {
return nestedFields, k, true
}
}
return nil, "", false
}
func concatenateAddressFields(addressFields map[string]any) string {
parts := make([]string, 0)
if dispName, ok := addressFields[DisplayNameKey].(*string); ok {
parts = append(parts, ptr.Val(dispName))
}
if fields, ok := addressFields[AddressKey].(map[string]any); ok {
parts = append(parts, addressKeyToVal(fields, StreetKey))
parts = append(parts, addressKeyToVal(fields, CityKey))
parts = append(parts, addressKeyToVal(fields, StateKey))
parts = append(parts, addressKeyToVal(fields, CountryKey))
parts = append(parts, addressKeyToVal(fields, PostalCodeKey))
}
if coords, ok := addressFields[CoordinatesKey].(map[string]any); ok {
parts = append(parts, addressKeyToVal(coords, LatitudeKey))
parts = append(parts, addressKeyToVal(coords, LongitudeKey))
}
if len(parts) > 0 {
return strings.Join(parts, ",")
}
return ""
}
func addressKeyToVal(fields map[string]any, key string) string {
if v, err := str.AnyValueToString(key, fields); err == nil {
return v
} else if v, ok := fields[key].(*float64); ok {
return fmt.Sprintf("%v", ptr.Val(v))
}
return ""
}
func (c Lists) getListItemFields(
ctx context.Context,
siteID, listID, itemID string,

View File

@ -1,6 +1,7 @@
package api
import (
"fmt"
"testing"
"time"
@ -455,52 +456,54 @@ func (suite *ListsUnitSuite) TestFieldValueSetable() {
func (suite *ListsUnitSuite) TestFieldValueSetable_Location() {
t := suite.T()
displayName := "B123 Unit 1852 Prime Residences Tagaytay"
street := "Prime Residences CityLand 1852"
state := "Calabarzon"
postal := "4120"
country := "Philippines"
city := "Tagaytay"
lat := 14.1153
lon := 120.962
additionalData := map[string]any{
"MyAddress": map[string]any{
AddressFieldName: map[string]any{
"city": "Tagaytay",
"countryOrRegion": "Philippines",
"postalCode": "4120",
"state": "Calabarzon",
"street": "Prime Residences CityLand 1852",
AddressKey: map[string]any{
CityKey: ptr.To(city),
CountryKey: ptr.To(country),
PostalCodeKey: ptr.To(postal),
StateKey: ptr.To(state),
StreetKey: ptr.To(street),
},
CoordinatesFieldName: map[string]any{
"latitude": "14.1153",
"longitude": "120.962",
CoordinatesKey: map[string]any{
LatitudeKey: ptr.To(lat),
LongitudeKey: ptr.To(lon),
},
DisplayNameFieldName: "B123 Unit 1852 Prime Residences Tagaytay",
LocationURIFieldName: "https://www.bingapis.com/api/v6/localbusinesses/YN8144x496766267081923032",
UniqueIDFieldName: "https://www.bingapis.com/api/v6/localbusinesses/YN8144x496766267081923032",
DisplayNameKey: ptr.To(displayName),
LocationURIKey: ptr.To("https://www.bingapis.com/api/v6/localbusinesses/YN8144x496766267081923032"),
UniqueIDKey: ptr.To("https://www.bingapis.com/api/v6/localbusinesses/YN8144x496766267081923032"),
},
CountryOrRegionFieldName: "Philippines",
StateFieldName: "Calabarzon",
CityFieldName: "Tagaytay",
PostalCodeFieldName: "4120",
StreetFieldName: "Prime Residences CityLand 1852",
GeoLocFieldName: map[string]any{
"latitude": 14.1153,
"longitude": 120.962,
CountryOrRegionFN: ptr.To(country),
StateFN: ptr.To(state),
CityFN: ptr.To(city),
PostalCodeFN: ptr.To(postal),
StreetFN: ptr.To(street),
GeoLocFN: map[string]any{
"latitude": ptr.To(lat),
"longitude": ptr.To(lon),
},
DispNameFieldName: "B123 Unit 1852 Prime Residences Tagaytay",
DispNameFN: ptr.To(displayName),
}
expectedData := map[string]any{
"MyAddress": map[string]any{
AddressFieldName: map[string]any{
"city": "Tagaytay",
"countryOrRegion": "Philippines",
"postalCode": "4120",
"state": "Calabarzon",
"street": "Prime Residences CityLand 1852",
},
CoordinatesFieldName: map[string]any{
"latitude": "14.1153",
"longitude": "120.962",
},
DisplayNameFieldName: "B123 Unit 1852 Prime Residences Tagaytay",
LocationURIFieldName: "https://www.bingapis.com/api/v6/localbusinesses/YN8144x496766267081923032",
UniqueIDFieldName: "https://www.bingapis.com/api/v6/localbusinesses/YN8144x496766267081923032",
},
"MyAddress": fmt.Sprintf("%s,%s,%s,%s,%s,%s,%v,%v",
displayName,
street,
city,
state,
country,
postal,
lat,
lon),
}
origFs := models.NewFieldValueSet()
@ -515,6 +518,138 @@ func (suite *ListsUnitSuite) TestFieldValueSetable_Location() {
assert.Equal(t, expectedData, fsAdditionalData)
}
func (suite *ListsUnitSuite) TestConcatenateAddressFields() {
t := suite.T()
tests := []struct {
name string
addressFields map[string]any
expectedResult string
}{
{
name: "Valid Address",
addressFields: map[string]any{
DisplayNameKey: ptr.To("John Doe"),
AddressKey: map[string]any{
StreetKey: ptr.To("123 Main St"),
CityKey: ptr.To("Cityville"),
StateKey: ptr.To("State"),
CountryKey: ptr.To("Country"),
PostalCodeKey: ptr.To("12345"),
},
CoordinatesKey: map[string]any{
LatitudeKey: ptr.To(40.7128),
LongitudeKey: ptr.To(-74.0060),
},
},
expectedResult: "John Doe,123 Main St,Cityville,State,Country,12345,40.7128,-74.006",
},
{
name: "Empty Address Fields",
addressFields: map[string]any{
DisplayNameKey: ptr.To("John Doe"),
},
expectedResult: "John Doe",
},
{
name: "Empty Input",
addressFields: map[string]any{},
expectedResult: "",
},
}
for _, test := range tests {
suite.Run(test.name, func() {
result := concatenateAddressFields(test.addressFields)
assert.Equal(t, test.expectedResult, result, "address should match")
})
}
}
func (suite *ListsUnitSuite) TestHasAddressFields() {
t := suite.T()
tests := []struct {
name string
additionalData map[string]any
expectedFields map[string]any
expectedName string
expectedFound bool
}{
{
name: "Address Fields Found",
additionalData: map[string]any{
"person1": map[string]any{
AddressKey: map[string]any{
StreetKey: "123 Main St",
CityKey: "Cityville",
StateKey: "State",
CountryKey: "Country",
PostalCodeKey: "12345",
},
CoordinatesKey: map[string]any{
LatitudeKey: "40.7128",
LongitudeKey: "-74.0060",
},
DisplayNameKey: "John Doe",
LocationURIKey: "some loc",
UniqueIDKey: "some id",
},
},
expectedFields: map[string]any{
AddressKey: map[string]any{
StreetKey: "123 Main St",
CityKey: "Cityville",
StateKey: "State",
CountryKey: "Country",
PostalCodeKey: "12345",
},
CoordinatesKey: map[string]any{
LatitudeKey: "40.7128",
LongitudeKey: "-74.0060",
},
DisplayNameKey: "John Doe",
LocationURIKey: "some loc",
UniqueIDKey: "some id",
},
expectedName: "person1",
expectedFound: true,
},
{
name: "No Address Fields",
additionalData: map[string]any{
"person1": map[string]any{
"name": "John Doe",
"age": 30,
},
"person2": map[string]any{
"name": "Jane Doe",
"age": 25,
},
},
expectedFields: nil,
expectedName: "",
expectedFound: false,
},
{
name: "Empty Input",
additionalData: map[string]any{},
expectedFields: nil,
expectedName: "",
expectedFound: false,
},
}
for _, test := range tests {
suite.Run(test.name, func() {
fields, fieldName, found := hasAddressFields(test.additionalData)
require.Equal(t, test.expectedFound, found, "address fields identification should match")
assert.Equal(t, test.expectedName, fieldName, "address field name should match")
assert.Equal(t, test.expectedFields, fields, "address fields should match")
})
}
}
type ListsAPIIntgSuite struct {
tester.Suite
its intgTesterSetup