def _maybeNormalizeUUIDs(self):
     """
     Normalize the UUIDs in the proxy database so they correspond to the
     normalized UUIDs in the main calendar database.
     """
     alreadyDone = yield self._db_value_for_sql(
         "select VALUE from CALDAV where KEY = 'UUIDS_NORMALIZED'"
     )
     if alreadyDone is None:
         for (groupname, member) in (
                 (yield self._db_all_values_for_sql(
                     "select GROUPNAME, MEMBER from GROUPS"))
             ):
             grouplist = groupname.split("#")
             grouplist[0] = normalizeUUID(grouplist[0])
             newGroupName = "#".join(grouplist)
             newMemberName = normalizeUUID(member)
             if newGroupName != groupname or newMemberName != member:
                 yield self._db_execute("""
                     update GROUPS set GROUPNAME = :1, MEMBER = :2
                     where GROUPNAME = :3 and MEMBER = :4
                 """, [newGroupName, newMemberName,
                       groupname, member])
         yield self._db_execute(
             """
             insert or ignore into CALDAV (KEY, VALUE)
             values ('UUIDS_NORMALIZED', 'YES')
             """
         )
 def _maybeNormalizeUUIDs(self):
     """
     Normalize the UUIDs in the proxy database so they correspond to the
     normalized UUIDs in the main calendar database.
     """
     alreadyDone = yield self._db_value_for_sql(
         "select VALUE from CALDAV where KEY = 'UUIDS_NORMALIZED'"
     )
     if alreadyDone is None:
         for (groupname, member) in (
             (yield self._db_all_values_for_sql(
                 "select GROUPNAME, MEMBER from GROUPS"))
         ):
             grouplist = groupname.split("#")
             grouplist[0] = normalizeUUID(grouplist[0])
             newGroupName = "#".join(grouplist)
             newMemberName = normalizeUUID(member)
             if newGroupName != groupname or newMemberName != member:
                 yield self._db_execute("""
                     update GROUPS set GROUPNAME = :1, MEMBER = :2
                     where GROUPNAME = :3 and MEMBER = :4
                 """, [newGroupName, newMemberName,
                       groupname, member])
         yield self._db_execute(
             """
             insert or ignore into CALDAV (KEY, VALUE)
             values ('UUIDS_NORMALIZED', 'YES')
             """
         )
Пример #3
0
    def updateRecord(self, recordType, guid=None, shortNames=(), authIDs=set(),
        fullName=None, firstName=None, lastName=None, emailAddresses=set(),
        uid=None, password=None, **kwargs):
        """
        Update the record matching guid.  In this XML-based implementation,
        the xml accounts are read in and converted to elementtree elements.
        The account matching the given guid is replaced, then the document
        is serialized to disk.
        """

        guid = normalizeUUID(guid)

        # Make sure latest XML records are read in
        accounts = self._forceReload()

        accountsElement = createElement("accounts", realm=self.realmName)
        for recType in self.recordTypes():

            for xmlPrincipal in accounts[recType].itervalues():
                if xmlPrincipal.guid == guid:
                    # Replace this record
                    xmlPrincipal.shortNames = shortNames
                    xmlPrincipal.password = password
                    xmlPrincipal.fullName = fullName
                    xmlPrincipal.firstName = firstName
                    xmlPrincipal.lastName = lastName
                    xmlPrincipal.emailAddresses = emailAddresses
                    xmlPrincipal.extras = kwargs
                    self._addElement(accountsElement, xmlPrincipal)
                else:
                    self._addElement(accountsElement, xmlPrincipal)

        self._persistRecords(accountsElement)
        self._forceReload()
        return self.recordWithGUID(guid)
Пример #4
0
 def recordWithGUID(self, guid):
     guid = normalizeUUID(guid)
     for recordType in self.recordTypes():
         record = self._lookupInIndex(recordType, self.INDEX_TYPE_GUID, guid)
         if record is not None:
             return record
     return None
    def parseXML(self, node):
        for child in node.getchildren():
            if child.tag == ELEMENT_SHORTNAME:
                self.shortNames.append(child.text.encode("utf-8"))
            elif child.tag == ELEMENT_GUID:
                self.guid = normalizeUUID(child.text.encode("utf-8"))
                if len(self.guid) < 4:
                    self.guid += "?" * (4 - len(self.guid))
            elif child.tag == ELEMENT_PASSWORD:
                self.password = child.text.encode("utf-8")
            elif child.tag == ELEMENT_NAME:
                self.fullName = child.text.encode("utf-8")
            elif child.tag == ELEMENT_FIRST_NAME:
                self.firstName = child.text.encode("utf-8")
            elif child.tag == ELEMENT_LAST_NAME:
                self.lastName = child.text.encode("utf-8")
            elif child.tag == ELEMENT_EMAIL_ADDRESS:
                self.emailAddresses.add(child.text.encode("utf-8").lower())
            elif child.tag == ELEMENT_MEMBERS:
                self._parseMembers(child, self.members)
            elif child.tag == ELEMENT_EXTRAS:
                self._parseExtras(child, self.extras)
            else:
                raise RuntimeError("Unknown account attribute: %s" % (child.tag,))

        if not self.shortNames:
            self.shortNames.append(self.guid)
Пример #6
0
    def createRecord(self, recordType, guid=None, shortNames=(), authIDs=set(),
        fullName=None, firstName=None, lastName=None, emailAddresses=set(),
        uid=None, password=None, **kwargs):
        """
        Create and persist a record using the provided information.  In this
        XML-based implementation, the xml accounts are read in and converted
        to elementtree elements, a new element is added for the new record,
        and the document is serialized to disk.
        """
        if guid is None:
            guid = str(uuid4())
        guid = normalizeUUID(guid)

        if not shortNames:
            shortNames = (guid,)

        # Make sure latest XML records are read in
        accounts = self._forceReload()

        accountsElement = createElement("accounts", realm=self.realmName)
        for recType in self.recordTypes():
            for xmlPrincipal in accounts[recType].itervalues():
                if xmlPrincipal.guid == guid:
                    raise DirectoryError("Duplicate guid: %s" % (guid,))
                for shortName in shortNames:
                    if shortName in xmlPrincipal.shortNames:
                        raise DirectoryError("Duplicate shortName: %s" %
                            (shortName,))
                self._addElement(accountsElement, xmlPrincipal)

        xmlPrincipal = XMLAccountRecord(recordType)
        xmlPrincipal.shortNames = shortNames
        xmlPrincipal.guid = guid
        xmlPrincipal.password = password
        xmlPrincipal.fullName = fullName
        xmlPrincipal.firstName = firstName
        xmlPrincipal.lastName = lastName
        xmlPrincipal.emailAddresses = emailAddresses
        xmlPrincipal.extras = kwargs
        self._addElement(accountsElement, xmlPrincipal)

        self._persistRecords(accountsElement)
        self._forceReload()
        return self.recordWithGUID(guid)
Пример #7
0
    def destroyRecord(self, recordType, guid=None):
        """
        Remove the record matching guid.  In this XML-based implementation,
        the xml accounts are read in and those not matching the given guid are
        converted to elementtree elements, then the document is serialized to
        disk.
        """

        guid = normalizeUUID(guid)

        # Make sure latest XML records are read in
        accounts = self._forceReload()

        accountsElement = createElement("accounts", realm=self.realmName)
        for recType in self.recordTypes():

            for xmlPrincipal in accounts[recType].itervalues():
                if xmlPrincipal.guid != guid:
                    self._addElement(accountsElement, xmlPrincipal)

        self._persistRecords(accountsElement)
        self._forceReload()
Пример #8
0
    def normalizeUUIDs(self):
        """
        Normalize (uppercase) all augment UIDs which are parseable as UUIDs.

        @return: a L{Deferred} that fires when all records have been
            normalized.
        """
        remove = []
        add = []
        for uid in (yield self.getAllUIDs()):
            nuid = normalizeUUID(uid)
            if uid != nuid:
                old = yield self._lookupAugmentRecord(uid)
                new = copy.deepcopy(old)
                new.uid = uid.upper()
                remove.append(uid)
                add.append(new)
        try:
            yield self.removeAugmentRecords(remove)
            yield self.addAugmentRecords(add)
        except IOError:
            # It's OK if we can't re-write the file.
            pass
Пример #9
0
    def normalizeUUIDs(self):
        """
        Normalize (uppercase) all augment UIDs which are parseable as UUIDs.

        @return: a L{Deferred} that fires when all records have been
            normalized.
        """
        remove = []
        add = []
        for uid in (yield self.getAllUIDs()):
            nuid = normalizeUUID(uid)
            if uid != nuid:
                old = yield self._lookupAugmentRecord(uid)
                new = copy.deepcopy(old)
                new.uid = uid.upper()
                remove.append(uid)
                add.append(new)
        try:
            yield self.removeAugmentRecords(remove)
            yield self.addAugmentRecords(add)
        except IOError:
            # It's OK if we can't re-write the file.
            pass
Пример #10
0
    def test_normalizeUUID(self):

        # Ensure that record.guid automatically gets normalized to
        # uppercase+hyphenated form if the value is one that uuid.UUID( )
        # recognizes.

        data = (
            (
                "0543A85A-D446-4CF6-80AE-6579FA60957F",
                "0543A85A-D446-4CF6-80AE-6579FA60957F"
            ),
            (
                "0543a85a-d446-4cf6-80ae-6579fa60957f",
                "0543A85A-D446-4CF6-80AE-6579FA60957F"
            ),
            (
                "0543A85AD4464CF680AE-6579FA60957F",
                "0543A85A-D446-4CF6-80AE-6579FA60957F"
            ),
            (
                "0543a85ad4464cf680ae6579fa60957f",
                "0543A85A-D446-4CF6-80AE-6579FA60957F"
            ),
            (
                "foo",
                "foo"
            ),
            (
                None,
                None
            ),
        )
        for original, expected in data:
            self.assertEquals(expected, normalizeUUID(original))
            record = DirectoryRecord(self.service, "users", original,
                shortNames=("testing",))
            self.assertEquals(expected, record.guid)
 def recordWithGUID(self, guid):
     guid = normalizeUUID(guid)
     return self._lookupRecord(None, CachingDirectoryService.INDEX_TYPE_GUID, guid)
    def repeat(self, ctr):
        """
        Create another object like this but with all text items having % substitution
        done on them with the numeric value provided.
        @param ctr: an integer to substitute into text.
        """

        # Regular expression which matches ~ followed by a number
        matchNumber = re.compile(r"(~\d+)")

        def expand(text, ctr):
            """
            Returns a string where ~<number> is replaced by the first <number>
            characters from the md5 hexdigest of str(ctr), e.g.::

                expand("~9 foo", 1)

            returns::

                "c4ca4238a foo"

            ...since "c4ca4238a" is the first 9 characters of::

                hashlib.md5(str(1)).hexdigest()

            If <number> is larger than 32, the hash will repeat as needed.
            """
            if text:
                m = matchNumber.search(text)
                if m:
                    length = int(m.group(0)[1:])
                    hash = hashlib.md5(str(ctr)).hexdigest()
                    string = (hash*((length/32)+1))[:-(32-(length%32))]
                    return text.replace(m.group(0), string)
            return text

        shortNames = []
        for shortName in self.shortNames:
            if shortName.find("%") != -1:
                shortNames.append(shortName % ctr)
            else:
                shortNames.append(shortName)
        if self.guid and self.guid.find("%") != -1:
            guid = self.guid % ctr
        else:
            guid = self.guid
        if self.password.find("%") != -1:
            password = self.password % ctr
        else:
            password = self.password
        if self.fullName.find("%") != -1:
            fullName = self.fullName % ctr
        else:
            fullName = self.fullName
        fullName = expand(fullName, ctr)
        if self.firstName and self.firstName.find("%") != -1:
            firstName = self.firstName % ctr
        else:
            firstName = self.firstName
        firstName = expand(firstName, ctr)
        if self.lastName and self.lastName.find("%") != -1:
            lastName = self.lastName % ctr
        else:
            lastName = self.lastName
        lastName = expand(lastName, ctr)
        emailAddresses = set()
        for emailAddr in self.emailAddresses:
            emailAddr = expand(emailAddr, ctr)
            if emailAddr.find("%") != -1:
                emailAddresses.add(emailAddr % ctr)
            else:
                emailAddresses.add(emailAddr)
        
        result = XMLAccountRecord(self.recordType)
        result.shortNames = shortNames
        result.guid = normalizeUUID(guid)
        result.password = password
        result.fullName = fullName
        result.firstName = firstName
        result.lastName = lastName
        result.emailAddresses = emailAddresses
        result.members = self.members
        result.extras = self.extras
        return result