Example #1
0
 def _get_document(self, trans, uri, check_etag):
     username, domain = uri.user.username, uri.user.domain
     self._normalize_document_path(uri)
     doc_type = self.app_mapping[uri.application_id]
     query = """SELECT doc, etag FROM %(table)s
                WHERE username = %%(username)s AND domain = %%(domain)s
                AND doc_type= %%(doc_type)s AND doc_uri=%%(document_path)s""" % {
         "table": Config.xcap_table
     }
     params = {
         "username": username,
         "domain": domain,
         "doc_type": doc_type,
         "document_path": uri.doc_selector.document_path
     }
     trans.execute(query, params)
     result = trans.fetchall()
     if len(result) > 1:
         raise MultipleResultsError(params)
     elif result:
         doc, etag = result[0]
         if isinstance(doc, unicode):
             doc = doc.encode('utf-8')
         check_etag(etag)
         response = StatusResponse(200, etag, doc)
     else:
         response = StatusResponse(404)
     return response
Example #2
0
class Storage(object):
    __metaclass__ = Singleton

    def __init__(self):
        self._database = DatabaseConnection()
        self._provisioning = XCAPProvisioning()
        self._sip_notifier = SIPNotifier()
        self._notifier = Notifier(ServerConfig.root,
                                  self._sip_notifier.send_publish)

    def _normalize_document_path(self, uri):
        if uri.application_id in ("pres-rules",
                                  "org.openmobilealliance.pres-rules"):
            # some clients e.g. counterpath's eyebeam save presence rules under
            # different filenames between versions and they expect to find the same
            # information, thus we are forcing all presence rules documents to be
            # saved under "index.xml" default filename
            uri.doc_selector.document_path = "index.xml"

    def get_document(self, uri, check_etag):
        self._normalize_document_path(uri)
        result = self._database.get(uri)
        result.addCallback(self._got_document, check_etag)
        result.addErrback(self._eb_not_found)
        return result

    def _eb_not_found(self, failure):
        failure.trap(NotFound)
        return StatusResponse(404)

    def _got_document(self, (doc, etag), check_etag):
        check_etag(etag)
        return StatusResponse(200, etag, doc.encode('utf-8'))
Example #3
0
 def _cb_put(self, result, uri, thor_key):
     if result[0]:
         code = 200
     else:
         code = 201
     self._provisioning.notify("update", "sip_account", thor_key)
     self._notifier.on_change(uri, result[1], result[2])
     return StatusResponse(code, result[2])
Example #4
0
 def _delete_document(self, trans, uri, check_etag):
     username, domain = uri.user.username, uri.user.domain
     self._normalize_document_path(uri)
     doc_type = self.app_mapping[uri.application_id]
     document_path = uri.doc_selector.document_path
     query = """SELECT etag FROM %(table)s
                WHERE username = %%(username)s AND domain = %%(domain)s
                AND doc_type= %%(doc_type)s AND doc_uri = %%(document_path)s""" % {
         "table": Config.xcap_table
     }
     params = {
         "username": username,
         "domain": domain,
         "doc_type": doc_type,
         "document_path": document_path
     }
     trans.execute(query, params)
     result = trans.fetchall()
     if len(result) > 1:
         raise MultipleResultsError(params)
     elif result:
         etag = result[0][0]
         check_etag(etag)
         query = """DELETE FROM %(table)s
                    WHERE username = %%(username)s AND domain = %%(domain)s
                    AND doc_type= %%(doc_type)s AND doc_uri = %%(document_path)s
                    AND etag = %%(etag)s""" % {
             "table": Config.xcap_table
         }
         params = {
             "username": username,
             "domain": domain,
             "doc_type": doc_type,
             "document_path": document_path,
             "etag": etag
         }
         trans.execute(query, params)
         deleted = getattr(trans._connection, 'affected_rows', lambda: 1)()
         if not deleted:
             # the document was replaced/removed after the SELECT but before the DELETE
             raise DeleteFailed
         assert deleted == 1, deleted
         return StatusResponse(200, old_etag=etag)
     else:
         return StatusResponse(404)
Example #5
0
 def _cb_get_element(self, response, uri):
     """This is called when the document related to the element is retrieved."""
     if response.code == 404:     ## XXX why not let the storage raise?
         raise errors.ResourceNotFound("The requested document %s was not found on this server" % uri.doc_selector)
     result = element.get(response.data, uri.node_selector.element_selector)
     if not result:
         msg = "The requested element %s was not found in the document %s" % (uri.node_selector, uri.doc_selector)
         raise errors.ResourceNotFound(msg)
     return StatusResponse(200, response.etag, result)
Example #6
0
 def _delete_all_documents(self, trans, uri):
     username, domain = uri.user.username, uri.user.domain
     query = """DELETE FROM %(table)s
                 WHERE username = %%(username)s AND domain = %%(domain)s
             """ % {
         "table": Config.xcap_table
     }
     params = {"username": username, "domain": domain}
     trans.execute(query, params)
     return StatusResponse(200)
Example #7
0
 def _watchers_to_xml(self, watchers, uri, check_etag):
     root = etree.Element("watchers", nsmap={None: self.default_ns})
     for watcher in watchers:
         watcher_elem = etree.SubElement(root, "watcher")
         for name, value in watcher.iteritems():
             etree.SubElement(watcher_elem, name).text = value
     doc = etree.tostring(root, encoding="utf-8", pretty_print=True, xml_declaration=True)
     #self.validate_document(doc)
     etag = make_etag(uri, doc)
     check_etag(etag)
     return StatusResponse(200, data=doc, etag=etag)
Example #8
0
 def _docs_to_xml(self, docs, uri):
     sip_uri = "sip:%s@%s" % (uri.user.username, uri.user.domain)
     root = etree.Element("xcap-directory", nsmap={None: self.default_ns})
     if docs:
         for k, v in docs.iteritems():
             folder = etree.SubElement(root, "folder", attrib={'auid': k})
             for item in v:
                 # We may have more than one document for the same application
                 entry_uri = "%s/%s/users/%s/%s" % (uri.xcap_root, k,
                                                    sip_uri, item[0])
                 entry = etree.SubElement(folder, "entry")
                 entry.set("uri", entry_uri)
                 entry.set("etag", item[1])
     doc = etree.tostring(root,
                          encoding="UTF-8",
                          pretty_print=True,
                          xml_declaration=True)
     #self.validate_document(doc)
     return defer.succeed(StatusResponse(200, etag=None, data=doc))
Example #9
0
        application = getApplicationForURI(uri)
        ns_dict = uri.node_selector.get_ns_bindings(application.default_ns)
        try:
            xpath = uri.node_selector.replace_default_prefix()
            attribute = xml_doc.xpath(xpath, namespaces = ns_dict)
        except Exception, ex:
            ex.http_error = errors.ResourceNotFound()
            raise
        if not attribute:
            raise errors.ResourceNotFound
        elif len(attribute) != 1:
            raise errors.ResourceNotFound('XPATH expression is ambiguous')
        # TODO
        # The server MUST NOT add namespace bindings representing namespaces
        # used by the element or its children, but declared in ancestor elements
        return StatusResponse(200, response.etag, attribute[0])

    def get_attribute(self, uri, check_etag):
        d = self.get_document(uri, check_etag)
        return d.addCallbacks(self._cb_get_attribute, callbackArgs=(uri, ))

    def _cb_delete_attribute(self, response, uri, check_etag):
        if response.code == 404:
            raise errors.ResourceNotFound
        document = response.data
        xml_doc = etree.parse(StringIO(document))
        application = getApplicationForURI(uri)
        ns_dict = uri.node_selector.get_ns_bindings(application.default_ns)
        try:
            elem = xml_doc.xpath(uri.node_selector.replace_default_prefix(append_terminal=False),namespaces=ns_dict)
        except Exception, ex:
Example #10
0
 def _cb_delete(self, result, uri, thor_key):
     self._provisioning.notify("update", "sip_account", thor_key)
     self._notifier.on_change(uri, result[1], None)
     return StatusResponse(200)
Example #11
0
 def _cb_delete_all(self, result, uri, thor_key):
     self._provisioning.notify("update", "sip_account", thor_key)
     return StatusResponse(200)
Example #12
0
 def _eb_not_found(self, failure):
     failure.trap(NotFound)
     return StatusResponse(404)
Example #13
0
    def _put_document(self, trans, uri, document, check_etag):
        username, domain = uri.user.username, uri.user.domain
        self._normalize_document_path(uri)
        doc_type = self.app_mapping[uri.application_id]
        document_path = uri.doc_selector.document_path
        query = """SELECT etag FROM %(table)s
                   WHERE username = %%(username)s AND domain = %%(domain)s
                   AND doc_type= %%(doc_type)s AND doc_uri=%%(document_path)s""" % {
            "table": Config.xcap_table
        }
        params = {
            "username": username,
            "domain": domain,
            "doc_type": doc_type,
            "document_path": document_path
        }
        trans.execute(query, params)
        result = trans.fetchall()
        if len(result) > 1:
            raise MultipleResultsError(params)
        elif not result:
            check_etag(None, False)
            ## the document doesn't exist, create it
            etag = make_random_etag(uri)
            query = """INSERT INTO %(table)s (username, domain, doc_type, etag, doc, doc_uri)
 VALUES (%%(username)s, %%(domain)s, %%(doc_type)s, %%(etag)s, %%(document)s, %%(document_path)s)""" % {
                "table": Config.xcap_table
            }
            params = {
                "username": username,
                "domain": domain,
                "doc_type": doc_type,
                "etag": etag,
                "document": document,
                "document_path": document_path
            }
            # may raise IntegrityError here, if the document was created in another connection
            # will be catched by repeat_on_error
            trans.execute(query, params)
            return StatusResponse(201, etag)
        else:
            old_etag = result[0][0]
            ## first check the etag of the existing resource
            check_etag(old_etag)
            ## the document exists, replace it
            etag = make_random_etag(uri)
            query = """UPDATE %(table)s
                       SET doc = %%(document)s, etag = %%(etag)s
                       WHERE username = %%(username)s AND domain = %%(domain)s
                       AND doc_type = %%(doc_type)s AND etag = %%(old_etag)s
                       AND doc_uri = %%(document_path)s""" % {
                "table": Config.xcap_table
            }
            params = {
                "document": document,
                "etag": etag,
                "username": username,
                "domain": domain,
                "doc_type": doc_type,
                "old_etag": old_etag,
                "document_path": document_path
            }
            trans.execute(query, params)
            # the request may not update anything (e.g. if etag was changed by another connection
            # after we did SELECT); if so, we should retry
            updated = getattr(trans._connection, 'affected_rows', lambda: 1)()
            if not updated:
                raise UpdateFailed
            assert updated == 1, updated
            return StatusResponse(200, etag, old_etag=old_etag)
Example #14
0
 def _purge_cb(self, result, uri):
     return StatusResponse(200)
Example #15
0
 def get_document_global(self, uri, check_etag):
     doc, etag = self._get_document()
     return defer.succeed(StatusResponse(200, etag=etag, data=doc))