diff --git a/carddav/match.go b/carddav/match.go index d0c6450..dd5b4d8 100644 --- a/carddav/match.go +++ b/carddav/match.go @@ -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 } diff --git a/carddav/match_test.go b/carddav/match_test.go index 9451ffe..d0f8403 100644 --- a/carddav/match_test.go +++ b/carddav/match_test.go @@ -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)