changeset 95:3ad74552bbc7

Merge from RELENG_0: Implemented node configuration.
author Ralph Meijer <ralphm@ik.nu>
date Tue, 23 Nov 2004 16:18:52 +0000
parents bbebadd71d35
children f289c3e1dd0a
files idavoll/backend.py idavoll/implementation_issues.txt idavoll/pgsql_backend.py idavoll/pubsub.py
diffstat 4 files changed, 151 insertions(+), 11 deletions(-) [+]
line wrap: on
line diff
--- a/idavoll/backend.py	Wed Nov 17 21:08:29 2004 +0000
+++ b/idavoll/backend.py	Tue Nov 23 16:18:52 2004 +0000
@@ -205,8 +205,8 @@
 
     def _do_publish(self, result, node_id, items, requestor):
         configuration = result[0][1]
-        persist_items = configuration["persist_items"]
-        deliver_payloads = configuration["deliver_payloads"]
+        persist_items = configuration["pubsub#persist_items"]
+        deliver_payloads = configuration["pubsub#deliver_payloads"]
         affiliation = result[1][1]
 
         if affiliation not in ['owner', 'publisher']:
@@ -307,6 +307,14 @@
 
     __implements__ = INodeCreationService,
 
+    options = {"pubsub#persist_items":
+                  {"type": "boolean",
+                   "label": "Persist items to storage"},
+               "pubsub#deliver_payloads":
+                  { "type": "boolean",
+                   "label": "Deliver payloads with event notifications"}
+              }
+
     def supports_instant_nodes(self):
         return True
 
@@ -319,6 +327,44 @@
         d.addCallback(lambda _: node_id)
         return d
 
+    def get_node_configuration(self, node_id):
+        if node_id:
+            d = self.parent.storage.get_node_configuration(node_id)
+        else:
+            d = defer.succeed({"pubsub#persist_items": True,
+                               "pubsub#deliver_payloads": True})
+
+        d.addCallback(self._make_config)
+        return d
+
+    def _make_config(self, config):
+        options = []
+        for key, value in config.iteritems():
+            option = {"var": key}
+            option.update(self.options[key])
+            if option["type"] == "boolean":
+                option["value"] = str(int(bool(value)))
+            else:
+                option["value"] = str(value)
+            options.append(option)
+
+        return options
+
+    def set_node_configuration(self, node_id, options, requestor):
+        for key in options.iterkeys():
+            if not self.options.has_key(key):
+                raise InvalidConfigurationOption
+
+        d = self.parent.storage.get_affiliation(node_id, requestor)
+        d.addCallback(self._do_set_node_configuration, node_id, options)
+        return d
+
+    def _do_set_node_configuration(self, affiliation, node_id, options):
+        if affiliation != 'owner':
+            raise NotAuthorized
+
+        return self.parent.storage.set_node_configuration(node_id, options)
+
 class AffiliationsService(service.Service):
 
     __implements__ = IAffiliationsService,
--- a/idavoll/implementation_issues.txt	Wed Nov 17 21:08:29 2004 +0000
+++ b/idavoll/implementation_issues.txt	Tue Nov 23 16:18:52 2004 +0000
@@ -43,3 +43,7 @@
 
 - no disco feature for retracting items, purging nodes, deleting nodes, other
   owner use cases?
+
+- no pubsub#error for bad node configuration options?
+
+- configure in pubsub#owner namespace??
--- a/idavoll/pgsql_backend.py	Wed Nov 17 21:08:29 2004 +0000
+++ b/idavoll/pgsql_backend.py	Tue Nov 23 16:18:52 2004 +0000
@@ -23,8 +23,8 @@
                           WHERE node=%s""",
                        (node_id,))
         try:
-            (configuration["persist_items"],
-             configuration["deliver_payloads"]) = cursor.fetchone()
+            (configuration["pubsub#persist_items"],
+             configuration["pubsub#deliver_payloads"]) = cursor.fetchone()
             return configuration
         except TypeError:
             raise backend.NodeNotFound
@@ -328,6 +328,20 @@
         cursor.execute("""DELETE FROM nodes WHERE node=%s""",
                        (node_id.encode('utf-8'),))
 
+    def set_node_configuration(self, node_id, options):
+        return self.dbpool.runInteraction(self._set_node_configuration,
+                                          node_id,
+                                          options)
+
+    def _set_node_configuration(self, cursor, node_id, options):
+        cursor.execute("""UPDATE nodes SET persistent=%s, deliver_payload=%s
+                          WHERE node=%s""",
+                       (options["pubsub#persist_items"].encode('utf8'),
+                        options["pubsub#deliver_payloads"].encode('utf8'),
+                        node_id.encode('utf-8')))
+        if cursor.rowcount != 1:
+            raise backend.Error
+
 class BackendService(backend.BackendService):
     """ PostgreSQL backend Service for a JEP-0060 pubsub service """
 
--- a/idavoll/pubsub.py	Wed Nov 17 21:08:29 2004 +0000
+++ b/idavoll/pubsub.py	Tue Nov 23 16:18:52 2004 +0000
@@ -11,20 +11,25 @@
 NS_PUBSUB = 'http://jabber.org/protocol/pubsub'
 NS_PUBSUB_EVENT = NS_PUBSUB + '#event'
 NS_PUBSUB_ERRORS = NS_PUBSUB + '#errors'
+NS_PUBSUB_OWNER = NS_PUBSUB + "#owner"
+NS_X_DATA = 'jabber:x:data'
 
 IQ_GET = '/iq[@type="get"]'
 IQ_SET = '/iq[@type="set"]'
 PUBSUB_ELEMENT = '/pubsub[@xmlns="' + NS_PUBSUB + '"]'
+PUBSUB_OWNER_ELEMENT = '/pubsub[@xmlns="' + NS_PUBSUB_OWNER + '"]'
 PUBSUB_GET = IQ_GET + PUBSUB_ELEMENT
 PUBSUB_SET = IQ_SET + PUBSUB_ELEMENT
+PUBSUB_OWNER_GET = IQ_GET + PUBSUB_OWNER_ELEMENT
+PUBSUB_OWNER_SET = IQ_SET + PUBSUB_OWNER_ELEMENT
 PUBSUB_CREATE = PUBSUB_SET + '/create'
 PUBSUB_PUBLISH = PUBSUB_SET + '/publish'
 PUBSUB_SUBSCRIBE = PUBSUB_SET + '/subscribe'
 PUBSUB_UNSUBSCRIBE = PUBSUB_SET + '/unsubscribe'
 PUBSUB_OPTIONS_GET = PUBSUB_GET + '/options'
 PUBSUB_OPTIONS_SET = PUBSUB_SET + '/options'
-PUBSUB_CONFIGURE_GET = PUBSUB_GET + '/configure'
-PUBSUB_CONFIGURE_SET = PUBSUB_SET + '/configure'
+PUBSUB_CONFIGURE_GET = PUBSUB_OWNER_GET + '/configure'
+PUBSUB_CONFIGURE_SET = PUBSUB_OWNER_SET + '/configure'
 PUBSUB_AFFILIATIONS = PUBSUB_GET + '/affiliations'
 PUBSUB_ITEMS = PUBSUB_GET + '/items'
 PUBSUB_RETRACT = PUBSUB_SET + '/retract'
@@ -92,7 +97,11 @@
     def success(self, result, iq):
         iq.swapAttributeValues("to", "from")
         iq["type"] = 'result'
-        iq.children = result or []
+        iq.children = []
+        if result:
+            for child in result:
+                iq.addChild(child)
+
         return iq
 
     def handler_wrapper(self, handler, iq):
@@ -280,6 +289,7 @@
 
         if not node:
             info.append(disco.Feature(NS_PUBSUB + "#create-nodes"))
+            info.append(disco.Feature(NS_PUBSUB + "#config-node"))
 
             if self.backend.supports_instant_nodes():
                 info.append(disco.Feature(NS_PUBSUB + "#instant-nodes"))
@@ -295,10 +305,10 @@
         owner = jid.JID(iq["from"]).userhostJID()
 
         d = self.backend.create_node(node, owner)
-        d.addCallback(self.return_create_response, iq)
+        d.addCallback(self._return_create_response, iq)
         return d
 
-    def return_create_response(self, result, iq):
+    def _return_create_response(self, result, iq):
         node_id = iq.pubsub.create.getAttribute("node")
         if not node_id or node_id != result:
             reply = domish.Element((NS_PUBSUB, 'pubsub'))
@@ -310,13 +320,79 @@
         self.handler_wrapper(self._onConfigureGet, iq)
 
     def _onConfigureGet(self, iq):
-        raise NodeNotConfigurable
+        try:
+            node_id = iq.pubsub.configure["node"]
+        except KeyError:
+            raise NodeNotConfigurable
+
+        d = self.backend.get_node_configuration(node_id)
+        d.addCallback(self._return_configuration_response, node_id)
+        return d
+
+    def _return_configuration_response(self, options, node_id):
+        reply = domish.Element((NS_PUBSUB_OWNER, "pubsub"))
+        configure = reply.addElement("configure")
+        if node_id:
+            configure["node"] = node_id
+        form = configure.addElement((NS_X_DATA, "x"))
+        form["type"] = "form"
+        field = form.addElement("field")
+        field["var"] = "FORM_TYPE"
+        field["type"] = "hidden"
+        field.addElement("value", content=NS_PUBSUB + "#node_config")
+
+        for option in options:
+            field = form.addElement("field")
+            field["var"] = option["var"]
+            field["type"] = option["type"]
+            field["label"] = option["label"]
+            field.addElement("value", content=option["value"])
+
+        return [reply]
 
     def onConfigureSet(self, iq):
         self.handler_wrapper(self._onConfigureSet, iq)
 
     def _onConfigureSet(self, iq):
-        raise NodeNotConfigurable
+        try:
+            node_id = iq.pubsub.configure["node"]
+        except KeyError:
+            raise BadRequest
+
+        requestor = jid.JID(iq["from"]).userhostJID()
+
+        for element in iq.pubsub.configure.elements():
+            if element.name != 'x' or element.uri != NS_X_DATA:
+                continue
+
+            type = element.getAttribute("type")
+            if type == "cancel":
+                return None
+            elif type != "submit":
+                continue
+
+            try:
+                options = self._get_form_options(element)
+            except:
+                raise BadRequest
+
+            if options["FORM_TYPE"] == NS_PUBSUB + "#node_config":
+                del options["FORM_TYPE"]
+                return self.backend.set_node_configuration(node_id,
+                                                           options,
+                                                           requestor)
+        
+        raise BadRequest
+
+    def _get_form_options(self, form):
+        options = {}
+
+        for element in form.elements():
+            if element.name == 'field' and element.uri == NS_X_DATA:
+                options[element["var"]] = str(element.value)
+
+        print options
+        return options
 
 components.registerAdapter(ComponentServiceFromNodeCreationService, backend.INodeCreationService, component.IService)