[CalendarServer-changes] [13053] CalendarServer/branches/users/sagen/move2who-4

source_changes at macosforge.org source_changes at macosforge.org
Sun Mar 30 16:06:13 PDT 2014


Revision: 13053
          http://trac.calendarserver.org//changeset/13053
Author:   gaya at apple.com
Date:     2014-03-30 16:06:13 -0700 (Sun, 30 Mar 2014)
Log Message:
-----------
all CDT tests work but one

Modified Paths:
--------------
    CalendarServer/branches/users/sagen/move2who-4/conf/auth/accounts-test.xml
    CalendarServer/branches/users/sagen/move2who-4/twistedcaldav/directorybackedaddressbook.py
    CalendarServer/branches/users/sagen/move2who-4/twistedcaldav/method/report_addressbook_query.py
    CalendarServer/branches/users/sagen/move2who-4/txdav/carddav/datastore/query/filter.py
    CalendarServer/branches/users/sagen/move2who-4/txdav/who/vcard.py

Modified: CalendarServer/branches/users/sagen/move2who-4/conf/auth/accounts-test.xml
===================================================================
--- CalendarServer/branches/users/sagen/move2who-4/conf/auth/accounts-test.xml	2014-03-30 15:10:20 UTC (rev 13052)
+++ CalendarServer/branches/users/sagen/move2who-4/conf/auth/accounts-test.xml	2014-03-30 23:06:13 UTC (rev 13053)
@@ -295,6 +295,7 @@
     <uid>public01</uid>
     <password>public01</password>
     <full-name>Public 01</full-name>
+    <email>public01 at example.com</email>
   </record>
 
   <record type="user">
@@ -302,6 +303,7 @@
     <uid>public02</uid>
     <password>public02</password>
     <full-name>Public 02</full-name>
+     <email>public02 at example.com</email>
   </record>
 
   <record type="user">
@@ -309,6 +311,7 @@
     <uid>public03</uid>
     <password>public03</password>
     <full-name>Public 03</full-name>
+     <email>public03 at example.com</email>
   </record>
 
   <record type="user">
@@ -316,6 +319,7 @@
     <uid>public04</uid>
     <password>public04</password>
     <full-name>Public 04</full-name>
+     <email>public04 at example.com</email>
   </record>
 
   <record type="user">
@@ -323,6 +327,7 @@
     <uid>public05</uid>
     <password>public05</password>
     <full-name>Public 05</full-name>
+     <email>public05 at example.com</email>
   </record>
 
   <record type="user">
@@ -330,6 +335,7 @@
     <uid>public06</uid>
     <password>public06</password>
     <full-name>Public 06</full-name>
+     <email>public06 at example.com</email>
   </record>
 
   <record type="user">
@@ -337,6 +343,7 @@
     <uid>public07</uid>
     <password>public07</password>
     <full-name>Public 07</full-name>
+     <email>public07 at example.com</email>
   </record>
 
   <record type="user">
@@ -344,6 +351,7 @@
     <uid>public08</uid>
     <password>public08</password>
     <full-name>Public 08</full-name>
+     <email>public08 at example.com</email>
   </record>
 
   <record type="user">
@@ -351,6 +359,7 @@
     <uid>public09</uid>
     <password>public09</password>
     <full-name>Public 09</full-name>
+     <email>public09 at example.com</email>
   </record>
 
   <record type="user">
@@ -358,6 +367,7 @@
     <uid>public10</uid>
     <password>public10</password>
     <full-name>Public 10</full-name>
+     <email>public10 at example.com</email>
   </record>
 
   <record type="group">

Modified: CalendarServer/branches/users/sagen/move2who-4/twistedcaldav/directorybackedaddressbook.py
===================================================================
--- CalendarServer/branches/users/sagen/move2who-4/twistedcaldav/directorybackedaddressbook.py	2014-03-30 15:10:20 UTC (rev 13052)
+++ CalendarServer/branches/users/sagen/move2who-4/twistedcaldav/directorybackedaddressbook.py	2014-03-30 23:06:13 UTC (rev 13053)
@@ -26,7 +26,7 @@
 from twext.python.log import Logger
 from twext.who.expression import Operand, MatchType, MatchFlags, \
     MatchExpression, CompoundExpression
-from twext.who.idirectory import FieldName, RecordType
+from twext.who.idirectory import FieldName
 from twisted.internet.defer import deferredGenerator
 from twisted.internet.defer import succeed, inlineCallbacks, maybeDeferred, \
     returnValue
@@ -37,8 +37,8 @@
 from txdav.carddav.datastore.query.filter import IsNotDefined, TextMatch, \
     ParameterFilter
 from txdav.who.idirectory import FieldName as CalFieldName
-from txdav.who.vcard import recordTypeToVCardKindMap, vCardPropToParamMap, \
-    vCardConstantProperties, vCardFromRecord
+from txdav.who.vcard import recordTypeToVCardKindMap, vCardKindToRecordTypeMap, \
+    vCardPropToParamMap, vCardConstantProperties, vCardFromRecord
 from txdav.xml import element as davxml
 from txdav.xml.base import twisted_dav_namespace, dav_namespace, parse_date, \
     twisted_private_namespace
@@ -70,6 +70,8 @@
 
 
     def makeChild(self, name):
+        from twistedcaldav.simpleresource import SimpleCalDAVResource
+        return SimpleCalDAVResource(principalCollections=self.principalCollections())
         return self.directory
 
 
@@ -154,7 +156,7 @@
 
 
     @inlineCallbacks
-    def doAddressBookDirectoryQuery(self, addressBookFilter, addressBookQuery, maxResults):
+    def doAddressBookDirectoryQuery(self, addressBookFilter, addressBookQuery, maxResults, defaultKind=None):
         """
         Get vCards for a given addressBookFilter and addressBookQuery
         """
@@ -165,46 +167,42 @@
         limited = False
         maxQueryRecords = 0
 
-        searchableFields = {
-            RecordType.user: {
-                "FN": FieldName.fullNames,
-                "N": FieldName.fullNames,
-                "EMAIL": FieldName.emailAddresses,
-                "UID": FieldName.uid,
-                "ADR": (
-                        CalFieldName.streetAddress,
-                        CalFieldName.floor,
-                        )
-             },
-            RecordType.group: {
-                "FN": FieldName.fullNames,
-                "N": FieldName.fullNames,
-                "EMAIL": FieldName.emailAddresses,
-                "UID": FieldName.uid,
-                "ADR": (
-                        CalFieldName.streetAddress,
-                        CalFieldName.floor,
-                        )
-                # LATER "X-ADDRESSBOOKSERVER-MEMBER": FieldName.membersUIDs,
-             },
+        vcardPropToRecordFieldMap = {
+            "FN": FieldName.fullNames,
+            "N": FieldName.fullNames,
+            "EMAIL": FieldName.emailAddresses,
+            "UID": FieldName.uid,
+            "ADR": (
+                    CalFieldName.streetAddress,
+                    CalFieldName.floor,
+                    ),
+            "KIND": FieldName.recordType,
+            # LATER "X-ADDRESSBOOKSERVER-MEMBER": FieldName.membersUIDs,
         }
 
-        allowedRecordTypes = set(self.directory.recordTypes()) & set(recordTypeToVCardKindMap.keys()) & set(searchableFields.keys())
+        allowedRecordTypes = set(self.directory.recordTypes()) & set(recordTypeToVCardKindMap.keys())
         log.debug("doAddressBookDirectoryQuery: allowedRecordTypes={allowedRecordTypes}", allowedRecordTypes=allowedRecordTypes,)
 
+        '''
         expressions = []
         for recordType in allowedRecordTypes:
 
             #log.debug("doAddressBookDirectoryQuery: recordType={recordType}", recordType=recordType,)
 
-            vcardPropToRecordFieldMap = searchableFields[recordType]
             kind = recordTypeToVCardKindMap[recordType]
             constantProperties = vCardConstantProperties.copy()
             constantProperties["KIND"] = kind
             # add KIND as constant so that query can be skipped if addressBookFilter needs a different kind
 
-            propNames, expression = expressionFromABFilter(addressBookFilter, vcardPropToRecordFieldMap, recordType=recordType, constantProperties=constantProperties)
+            propNames, expression = expressionFromABFilter(addressBookFilter, vcardPropToRecordFieldMap, constantProperties=constantProperties)
             #log.debug("doAddressBookDirectoryQuery: recordType={recordType}, expression={expression!r}, propNames={propNames}", recordType=recordType, expression=expression, propNames=propNames)
+        if expression:
+            recordTypeExpression = MatchExpression(FieldName.recordType, recordType, MatchType.equals)
+            if expression is True:
+                expression = recordTypeExpression
+            else:
+                expression = CompoundExpression((expression, recordTypeExpression,), Operand.AND)
+
             if expression:
                 expressions.append(expression)
 
@@ -213,7 +211,35 @@
                 expression = CompoundExpression(expressions, Operand.OR)
             else:
                 expression = expressions[0]
+        '''
 
+        propNames, expression = expressionFromABFilter(
+            addressBookFilter, vcardPropToRecordFieldMap, vCardConstantProperties
+        )
+
+        if expression:
+            if defaultKind and "KIND" not in propNames:
+                defaultRecordExpression = MatchExpression(
+                    FieldName.recordType, 
+                    vCardKindToRecordTypeMap[defaultKind], 
+                    MatchType.equals
+                )
+                if expression is True:
+                    expression = defaultRecordExpression
+                else:
+                    expression = CompoundExpression(
+                        (expression, defaultRecordExpression,),
+                        Operand.AND
+                    )
+            elif expression is True: # True means all records
+                expression = CompoundExpression(
+                    [
+                        MatchExpression(FieldName.recordType, recordType, MatchType.equals)
+                            for recordType in self.directory.recordTypes()
+                    ], Operand.OR
+                )
+
+            log.debug("doAddressBookDirectoryQuery: expression={expression!r}, propNames={propNames}", expression=expression, propNames=propNames)
             maxRecords = int(maxResults * 1.2)
 
             # keep trying query till we get results based on filter.  Especially when doing "all results" query
@@ -225,7 +251,7 @@
                 log.debug("doAddressBookDirectoryQuery: #records={n}, records={records!r}", n=len(records), records=records)
                 queryLimited = False
 
-                vCardsResults = [ABDirectoryQueryResult(self, record) for record in records]
+                vCardsResults = [(yield ABDirectoryQueryResult(self).generate(record)) for record in records]
 
                 filteredResults = []
                 for vCardResult in vCardsResults:
@@ -286,7 +312,7 @@
 
 
 
-def expressionFromABFilter(addressBookFilter, vcardPropToSearchableFieldMap, recordType, constantProperties={}):
+def expressionFromABFilter(addressBookFilter, vcardPropToSearchableFieldMap, constantProperties={}):
     """
     Convert the supplied addressbook-query into a ds expression tree.
 
@@ -347,17 +373,34 @@
             @return: (filterProperyNames, expressions) tuple.  expression==True means list all results, expression==False means no results
             """
 
+            def matchExpression(fieldName, matchString, matchType, matchFlags):
+                # special case recordType field
+                if fieldName == FieldName.recordType:
+                    # change kind to record type
+                    uMatchString = vCardKindToRecordTypeMap.get(matchString)
+                    if uMatchString is None:
+                        uMatchString = NamedConstant()
+                        uMatchString.description = u""
+
+                    # change types and flags
+                    matchFlags &= ~MatchFlags.caseInsensitive
+                    matchType = MatchType.equals
+                else:
+                    uMatchString = matchString.decode("utf-8")
+
+                return MatchExpression(fieldName, uMatchString, matchType, matchFlags)
+
+
             def definedExpression(defined, allOf):
-                if constant or propFilter.filter_name in ("N" , "FN", "UID", "SOURCE",):
+                if constant or propFilter.filter_name in ("N" , "FN", "UID", "SOURCE", "KIND",):
                     return defined  # all records have this property so no records do not have it
                 else:
-                    if defined:
-                        matchList = [MatchExpression(fieldName, u"", MatchType.startsWith) for fieldName in searchableFields]
-                    else:
-                        # this may generate inefficient LDAP query stirng
-                        matchList = [MatchExpression(fieldName, u"", MatchType.startsWith, MatchFlags.NOT) for fieldName in searchableFields]
+                    # this may generate inefficient LDAP query string
+                    matchFlags = MatchFlags.NOT & MatchFlags.caseInsensitive if defined else MatchFlags.NOT
+                    matchList = [matchExpression(fieldName, "", MatchType.startsWith, matchFlags) for fieldName in searchableFields]
                     return andOrExpression(allOf, matchList)
 
+
             def andOrExpression(propFilterAllOf, matchList):
                 matchList = list(set(matchList))
                 if propFilterAllOf and len(matchList) > 1:
@@ -448,10 +491,17 @@
 
                         matchList = []
                         for matchString in matchStrings:
-                            if textMatchElement.negate:
-                                matchList = [MatchExpression(fieldName, matchString.decode("utf-8"), matchType, MatchFlags.NOT) for fieldName in searchableFields]
+                            matchFlags = None
+                            if textMatchElement.collation == "i;unicode-casemap" and textMatchElement.negate:
+                                matchFlags = MatchFlags.caseInsensitive | MatchFlags.NOT
+                            elif textMatchElement.collation == "i;unicode-casemap":
+                                matchFlags = MatchFlags.caseInsensitive
+                            elif textMatchElement.negate:
+                                matchFlags = MatchFlags.NOT
                             else:
-                                matchList = [MatchExpression(fieldName, matchString.decode("utf-8"), matchType) for fieldName in searchableFields]
+                                matchFlags = MatchFlags.NOT & MatchFlags.caseInsensitive # MatchFlags.none
+
+                            matchList = [matchExpression(fieldName, matchString.decode("utf-8"), matchType, matchFlags) for fieldName in searchableFields]
                             matchList.extend(matchList)
                         return andOrExpression(propFilterAllOf, matchList)
 
@@ -541,14 +591,6 @@
         else:
             expression = not filterAllOf
 
-    #log.debug("expressionFromABFilter: recordType={rdn!r}, expression={q!r}, properties={pn}", rdn=recordType, q=expression, pn=properties)
-    if expression:
-        recordTypeExpression = MatchExpression(FieldName.recordType, recordType, MatchType.equals)
-        if expression is True:
-            expression = recordTypeExpression
-        else:
-            expression = CompoundExpression((expression, recordTypeExpression,), Operand.AND)
-
     #log.debug("expressionFromABFilter: expression={q!r}, properties={pn}", q=expression, pn=properties)
     return((properties, expression))
 
@@ -559,14 +601,10 @@
     Result from ab query report or multiget on directory
     """
 
-    def __init__(self, directoryBackedAddressBook, record,
-                 kind=None,
-                 addProps=None,
-                 ):
+    def __init__(self, directoryBackedAddressBook,):
 
         self._directoryBackedAddressBook = directoryBackedAddressBook
-        #generate a vCard here.  May throw an exception
-        self._vCard = vCardFromRecord(record, kind, addProps, directoryBackedAddressBook.uri)
+        #self._vCard = None
 
 
     def __repr__(self):
@@ -585,12 +623,18 @@
         return hash(s)
     '''
 
+    @inlineCallbacks
+    def generate(self, record, kind=None, addProps=None,):
+        self._vCard = yield vCardFromRecord(record, kind, addProps, None)
+        returnValue(self)
+
+
     def vCard(self):
         return self._vCard
 
 
     def vCardText(self):
-        return str(self.vCard())
+        return str(self._vCard)
 
 
     def uri(self):

Modified: CalendarServer/branches/users/sagen/move2who-4/twistedcaldav/method/report_addressbook_query.py
===================================================================
--- CalendarServer/branches/users/sagen/move2who-4/twistedcaldav/method/report_addressbook_query.py	2014-03-30 15:10:20 UTC (rev 13052)
+++ CalendarServer/branches/users/sagen/move2who-4/twistedcaldav/method/report_addressbook_query.py	2014-03-30 23:06:13 UTC (rev 13053)
@@ -157,7 +157,7 @@
         def queryDirectoryBackedAddressBook(directoryBackedAddressBook, addressBookFilter):
             """
             """
-            results, limited[0] = (yield directoryBackedAddressBook.doAddressBookDirectoryQuery(addressBookFilter, query, max_number_of_results[0]))
+            results, limited[0] = yield directoryBackedAddressBook.doAddressBookDirectoryQuery(addressBookFilter, query, max_number_of_results[0], defaultKind="individual")
             for vCardResult in results:
 
                 # match against original filter if different from addressBookFilter

Modified: CalendarServer/branches/users/sagen/move2who-4/txdav/carddav/datastore/query/filter.py
===================================================================
--- CalendarServer/branches/users/sagen/move2who-4/txdav/carddav/datastore/query/filter.py	2014-03-30 15:10:20 UTC (rev 13052)
+++ CalendarServer/branches/users/sagen/move2who-4/txdav/carddav/datastore/query/filter.py	2014-03-30 23:06:13 UTC (rev 13053)
@@ -136,7 +136,7 @@
                     return not allof
             return allof
         else:
-            return True
+            return False
 
 
     def valid(self):
@@ -190,9 +190,6 @@
             else:
                 raise ValueError("Unknown child element: %s" % (qname,))
 
-        if qualifier and isinstance(qualifier, IsNotDefined) and (len(filters) != 0):
-            raise ValueError("No other tests allowed when CardDAV:is-not-defined is present")
-
         if xml_element.qname() == (carddav_namespace, "prop-filter"):
             propfilter_test = xml_element.attributes.get("test", "anyof")
             if propfilter_test not in ("anyof", "allof"):
@@ -200,13 +197,16 @@
         else:
             propfilter_test = "anyof"
 
+        if qualifier and isinstance(qualifier, IsNotDefined) and (len(filters) != 0) and propfilter_test == "allof":
+            raise ValueError("When test is allof, no other tests allowed when CardDAV:is-not-defined is present")
+
         self.propfilter_test = propfilter_test
         self.qualifier = qualifier
         self.filters = filters
         self.filter_name = xml_element.attributes["name"]
         if isinstance(self.filter_name, unicode):
             self.filter_name = self.filter_name.encode("utf-8")
-        self.defined = not self.qualifier or not isinstance(qualifier, IsNotDefined)
+        self.defined = not self.qualifier or not isinstance(qualifier, IsNotDefined) or len(filters)
 
 
     def _deserialize(self, data):
@@ -241,25 +241,18 @@
         matches this filter, False otherwise.
         """
 
-        # Always return True for the is-not-defined case as the result of this will
-        # be negated by the caller
-        if not self.defined:
-            return True
+        allof = self.propfilter_test == "allof"
+        if self.qualifier and allof != self.qualifier.match(item):
+            return not allof
 
-        if self.qualifier and not self.qualifier.match(item):
-            return False
-
         if len(self.filters) > 0:
-            allof = self.propfilter_test == "allof"
             for filter in self.filters:
                 if allof != filter._match(item):
                     return not allof
             return allof
         else:
-            return True
+            return not allof
 
-
-
 class PropertyFilter (FilterChildBase):
     """
     Limits a search to specific properties.

Modified: CalendarServer/branches/users/sagen/move2who-4/txdav/who/vcard.py
===================================================================
--- CalendarServer/branches/users/sagen/move2who-4/txdav/who/vcard.py	2014-03-30 15:10:20 UTC (rev 13052)
+++ CalendarServer/branches/users/sagen/move2who-4/txdav/who/vcard.py	2014-03-30 23:06:13 UTC (rev 13053)
@@ -26,6 +26,7 @@
 from pycalendar.vcard.n import N
 from twext.python.log import Logger
 from twext.who.idirectory import FieldName, RecordType
+from twisted.internet.defer import inlineCallbacks, returnValue
 from twistedcaldav.config import config
 from twistedcaldav.vcard import Component, Property, vCardProductID
 from txdav.who.idirectory import FieldName as CalFieldName, \
@@ -42,7 +43,15 @@
    CalRecordType.resource: "device",
 }
 
+vCardKindToRecordTypeMap = {
+   "individual" : RecordType.user,
+   "group": RecordType.group,
+   "org": RecordType.group,
+   "location": CalRecordType.location,
+   "device": CalRecordType.resource,
+}
 
+
 # all possible generated parameters.
 vCardPropToParamMap = {
     #"PHOTO": {"ENCODING": ("B",), "TYPE": ("JPEG",), },
@@ -72,6 +81,7 @@
 }
 
 
+ at inlineCallbacks
 def vCardFromRecord(record, kind=None, addProps=None, parentURI=None):
 
     def isUniqueProperty(newProperty, ignoredParameters={}):
@@ -296,13 +306,9 @@
         vcard.addProperty(Property("X-ADDRESSBOOKSERVER-KIND", kind))
 
     # add members
-    # FIXME:  members() is a deferred.  I really want non-deferred FieldName.memberUIDs
-    if record.members():
-        pass
-        '''
-        for memberRecord in (yield record.members()):
-            vcard.addProperty(Property("X-ADDRESSBOOKSERVER-MEMBER", "urn:uuid:" + memberRecord.fields[FieldName.uid].encode("utf-8")))
-        '''
+    # FIXME:  members() is a deferred, so all of vCardFromRecord is deferred.
+    for memberRecord in (yield record.members()):
+        vcard.addProperty(Property("X-ADDRESSBOOKSERVER-MEMBER", "urn:uuid:" + memberRecord.fields[FieldName.uid].encode("utf-8")))
 
     #===================================================================
     # vCard 4.0  http://tools.ietf.org/html/rfc6350
@@ -321,4 +327,4 @@
         vcard.addProperty(Property("X-ABShowAs", "COMPANY"))
 
     log.debug("vCardFromRecord: vcard=\n{vcard}", vcard=vcard)
-    return vcard
+    returnValue(vcard)
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20140330/214d80f8/attachment-0001.html>


More information about the calendarserver-changes mailing list