# HG changeset patch # User Ralph Meijer # Date 1101226732 0 # Node ID 3ad74552bbc74647013934f881a985912c73a521 # Parent bbebadd71d351910bf946a8bf393235a2f720c73 Merge from RELENG_0: Implemented node configuration. diff -r bbebadd71d35 -r 3ad74552bbc7 idavoll/backend.py --- 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, diff -r bbebadd71d35 -r 3ad74552bbc7 idavoll/implementation_issues.txt --- 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?? diff -r bbebadd71d35 -r 3ad74552bbc7 idavoll/pgsql_backend.py --- 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 """ diff -r bbebadd71d35 -r 3ad74552bbc7 idavoll/pubsub.py --- 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)