Liu Song’s Projects


~/Projects/webdav-go

git clone https://code.lsong.org/webdav-go

Commit

Commit
db966a275c93fd5dd0d63bf7522f52dfba848090
Author
Conrad Hoffmann <[email protected]>
Date
2022-05-19 14:26:35 +0200 +0200
Diffstat
 carddav/match.go | 32 +++++++++++++++++++++++++++++---
 carddav/match_test.go | 45 +++++++++++++++++++++++++++++++++++++++++++++

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.


diff --git a/carddav/match.go b/carddav/match.go
index d0c6450b81d98b7ab1f57103fbadbc735960f12d..dd5b4d8e0d917bb6dcb7a29b75f9bd615e11a336 100644
--- a/carddav/match.go
+++ b/carddav/match.go
@@ -7,6 +7,34 @@
 	"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 @@ 		if !ok {
 			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 9451ffeb03f19528c1c46a79af8105d1670a83a1..d0f84038e3a1ac9c9d21791b664dfe44f953bcbd 100644
--- a/carddav/match_test.go
+++ b/carddav/match_test.go
@@ -46,6 +46,11 @@ N:Gopher;Carla;;;
 EMAIL;PID=1.1:[email protected]
 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:[email protected]
+END:VCARD`)
 
 	for _, tc := range []struct {
 		name  string
@@ -176,6 +181,46 @@ 				},
 			},
 			addrs: []AddressObject{alice, bob, carla},
 	"github.com/emersion/go-vcard"
+	"strings"
+		},
+		{
+			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},
+		return AddressObject{
 	"strings"
 		},
 	} {