carddav: do property filtering in match.Filter()

With this commit, the list of AddressObjects returned by `Filter()` will
always be a correct response to the query argument passed to it, even if
the input list contained objects with arbitraty properties present.
This commit is contained in:
Conrad Hoffmann 2022-05-19 14:26:35 +02:00 committed by Simon Ser
parent 21aea26c70
commit db966a275c
2 changed files with 73 additions and 3 deletions

View File

@ -7,6 +7,34 @@ import (
"github.com/emersion/go-vcard"
)
func filterProperties(req AddressDataRequest, ao AddressObject) AddressObject {
if req.AllProp || len(req.Props) == 0 {
return ao
}
if len(ao.Card) == 0 {
panic("request to process empty vCard")
}
result := AddressObject{
Path: ao.Path,
ModTime: ao.ModTime,
ETag: ao.ETag,
}
result.Card = make(vcard.Card)
// result would be invalid w/o version
result.Card[vcard.FieldVersion] = ao.Card[vcard.FieldVersion]
for _, prop := range req.Props {
value, ok := ao.Card[prop]
if ok {
result.Card[prop] = value
}
}
return result
}
// Filter returns the filtered list of address objects matching the provided query.
// A nil query will return the full list of address objects.
func Filter(query *AddressBookQuery, aos []AddressObject) ([]AddressObject, error) {
@ -29,9 +57,7 @@ func Filter(query *AddressBookQuery, aos []AddressObject) ([]AddressObject, erro
continue
}
// TODO properties are not currently filtered even if requested
out = append(out, ao)
out = append(out, filterProperties(query.DataRequest, ao))
if len(out) >= n {
break
}

View File

@ -45,6 +45,11 @@ FN;PID=1.1:Carla Gopher
N:Gopher;Carla;;;
EMAIL;PID=1.1:carla@example.com
CLIENTPIDMAP:1;urn:uuid:53e374d9-337e-4727-8803-a1e9c14e0553
END:VCARD`)
carlaFiltered := newAO(`BEGIN:VCARD
VERSION:4.0
UID:urn:uuid:4fbe8971-0bc3-424c-9c26-36c3e1eff6b3
EMAIL;PID=1.1:carla@example.com
END:VCARD`)
for _, tc := range []struct {
@ -177,6 +182,45 @@ END:VCARD`)
addrs: []AddressObject{alice, bob, carla},
want: []AddressObject{},
},
{
name: "email-match-filter-properties",
query: &AddressBookQuery{
DataRequest: AddressDataRequest{
Props: []string{
vcard.FieldVersion,
vcard.FieldUID,
vcard.FieldEmail,
},
},
PropFilters: []PropFilter{
{
Name: vcard.FieldEmail,
TextMatches: []TextMatch{{Text: "carla"}},
},
},
},
addrs: []AddressObject{alice, bob, carla},
want: []AddressObject{carlaFiltered},
},
{
name: "email-match-filter-properties-always-returns-version",
query: &AddressBookQuery{
DataRequest: AddressDataRequest{
Props: []string{
vcard.FieldUID,
vcard.FieldEmail,
},
},
PropFilters: []PropFilter{
{
Name: vcard.FieldEmail,
TextMatches: []TextMatch{{Text: "carla"}},
},
},
},
addrs: []AddressObject{alice, bob, carla},
want: []AddressObject{carlaFiltered},
},
} {
t.Run(tc.name, func(t *testing.T) {
got, err := Filter(tc.query, tc.addrs)