diff --git a/setup.py b/setup.py
index d253e3d4..1a0766e7 100644
--- a/setup.py
+++ b/setup.py
@@ -295,8 +295,7 @@ setup(name=NAME,
package_dir={'sat': 'src', 'sat_frontends': 'frontends/src', 'twisted.plugins': 'src/twisted/plugins'},
packages=['sat', 'sat.tools', 'sat.tools.common', 'sat.bridge', 'sat.plugins', 'sat.test', 'sat.core', 'sat.memory',
'sat_frontends', 'sat_frontends.bridge', 'sat_frontends.quick_frontend', 'sat_frontends.jp',
- 'sat_frontends.primitivus', 'sat_frontends.tools', 'sat.stdui','sat.tmp', 'sat.tmp.wokkel',
- 'twisted.plugins'],
+ 'sat_frontends.primitivus', 'sat_frontends.tools', 'sat.stdui', 'twisted.plugins'],
package_data={'sat': ['sat.sh'], },
data_files=[(os.path.join(sys.prefix, 'share/locale/fr/LC_MESSAGES'), ['i18n/fr/LC_MESSAGES/sat.mo']),
('share/doc/%s' % NAME, ['CHANGELOG', 'COPYING', 'INSTALL', 'README', 'README4TRANSLATORS']),
@@ -304,6 +303,6 @@ setup(name=NAME,
],
scripts=['frontends/src/jp/jp', 'frontends/src/primitivus/primitivus', ],
zip_safe=False,
- install_requires=['twisted >= 15.2.0', 'wokkel >= 0.7.1', 'progressbar', 'urwid >= 1.2.0', 'urwid-satext >= 0.6.1', 'mutagen', 'pillow', 'lxml >= 3.1.0', 'pyxdg', 'markdown', 'html2text', 'pycrypto >= 2.6.1', 'python-potr', 'PyOpenSSL', 'service_identity', 'shortuuid', 'babel'],
+ install_requires=['twisted >= 15.2.0', 'wokkel >= 0.7.1', 'sat_tmp', 'progressbar', 'urwid >= 1.2.0', 'urwid-satext >= 0.6.1', 'mutagen', 'pillow', 'lxml >= 3.1.0', 'pyxdg', 'markdown', 'html2text', 'pycrypto >= 2.6.1', 'python-potr', 'PyOpenSSL', 'service_identity', 'shortuuid', 'babel'],
cmdclass={'install': CustomInstall},
)
diff --git a/src/plugins/__init__.py b/src/plugins/__init__.py
index a86f20f8..1f834704 100644
--- a/src/plugins/__init__.py
+++ b/src/plugins/__init__.py
@@ -1,7 +1,7 @@
# FIXME: remove this when RSM and MAM are in wokkel
# XXX: the Monkey Patch is here and not in src/__init__ to avoir issues with pyjamas compilation
import wokkel
-from sat.tmp.wokkel import pubsub as tmp_pubsub, rsm as tmp_rsm, mam as tmp_mam
+from sat_tmp.wokkel import pubsub as tmp_pubsub, rsm as tmp_rsm, mam as tmp_mam
wokkel.pubsub = tmp_pubsub
wokkel.rsm = tmp_rsm
wokkel.mam = tmp_mam
diff --git a/src/plugins/plugin_xep_0060.py b/src/plugins/plugin_xep_0060.py
index e09068f7..3ef75af3 100755
--- a/src/plugins/plugin_xep_0060.py
+++ b/src/plugins/plugin_xep_0060.py
@@ -33,8 +33,8 @@ from collections import namedtuple
import urllib
import datetime
from dateutil import tz
-# XXX: tmp.wokkel.pubsub is actually use instead of wokkel version
-# mam and rsm come from tmp.wokkel too
+# XXX: sat_tmp.wokkel.pubsub is actually use instead of wokkel version
+# mam and rsm come from sat_tmp.wokkel too
from wokkel import pubsub
from wokkel import rsm
from wokkel import mam
diff --git a/src/plugins/plugin_xep_0277.py b/src/plugins/plugin_xep_0277.py
index 95e046e3..b46871a8 100755
--- a/src/plugins/plugin_xep_0277.py
+++ b/src/plugins/plugin_xep_0277.py
@@ -32,7 +32,7 @@ from sat.tools import sat_defer
from sat.tools import utils
from sat.tools.common import data_format
-# XXX: tmp.pubsub is actually used instead of wokkel version
+# XXX: sat_tmp.wokkel.pubsub is actually used instead of wokkel version
from wokkel import pubsub
from wokkel import disco, iwokkel
from zope.interface import implements
@@ -662,7 +662,7 @@ class XEP_0277(object):
@param access: Node access model, according to xep-0060 #4.5
@param profile_key: profile key
"""
- # FIXME: check if this mehtod is needed, deprecate it if not
+ # FIXME: check if this mehtod is need, deprecate it if not
client = self.host.getClient(profile_key)
_options = {self._p.OPT_ACCESS_MODEL: access, self._p.OPT_PERSIST_ITEMS: 1, self._p.OPT_MAX_ITEMS: -1, self._p.OPT_DELIVER_PAYLOADS: 1, self._p.OPT_SEND_ITEM_SUBSCRIBE: 1}
diff --git a/src/plugins/plugin_xep_0313.py b/src/plugins/plugin_xep_0313.py
index 88b1ac01..c72d21a7 100644
--- a/src/plugins/plugin_xep_0313.py
+++ b/src/plugins/plugin_xep_0313.py
@@ -31,7 +31,7 @@ from zope.interface import implements
from wokkel import disco
import uuid
-# XXX: mam and rsm come from tmp.wokkel
+# XXX: mam and rsm come from sat_tmp.wokkel
from wokkel import rsm
from wokkel import mam
diff --git a/src/test/helpers_plugins.py b/src/test/helpers_plugins.py
index 38d50658..4c92a8d4 100644
--- a/src/test/helpers_plugins.py
+++ b/src/test/helpers_plugins.py
@@ -27,7 +27,7 @@ from wokkel.generic import parseXml
from wokkel.disco import DiscoItem, DiscoItems
# temporary until the changes are integrated to Wokkel
-from sat.tmp.wokkel.rsm import RSMResponse
+from sat_tmp.wokkel.rsm import RSMResponse
from constants import Const as C
from sat.plugins import plugin_xep_0045
diff --git a/src/test/test_plugin_xep_0313.py b/src/test/test_plugin_xep_0313.py
index 758dacbc..126b68c9 100644
--- a/src/test/test_plugin_xep_0313.py
+++ b/src/test/test_plugin_xep_0313.py
@@ -30,8 +30,8 @@ from dateutil.tz import tzutc
import datetime
# TODO: change this when RSM and MAM are in wokkel
-from sat.tmp.wokkel.rsm import RSMRequest
-from sat.tmp.wokkel.mam import buildForm, MAMRequest
+from sat_tmp.wokkel.rsm import RSMRequest
+from sat_tmp.wokkel.mam import buildForm, MAMRequest
NS_PUBSUB = 'http://jabber.org/protocol/pubsub'
SERVICE = 'sat-pubsub.tazar.int'
diff --git a/src/tmp/README b/src/tmp/README
deleted file mode 100644
index bca02c8c..00000000
--- a/src/tmp/README
+++ /dev/null
@@ -1,6 +0,0 @@
-Use this module to temporary store files that need to be integrated to other
-projects such as Wokkel.
-
-For example, the changeset that introduced this folder adds RSM (XEP-0059)
-support to Wokkel. The files in sat.tmp.wokkel are imported over the initial
-wokkel files from sat.plugins.__init__.py
\ No newline at end of file
diff --git a/src/tmp/__init__.py b/src/tmp/__init__.py
deleted file mode 100644
index e69de29b..00000000
diff --git a/src/tmp/wokkel/__init__.py b/src/tmp/wokkel/__init__.py
deleted file mode 100644
index e69de29b..00000000
diff --git a/src/tmp/wokkel/mam.py b/src/tmp/wokkel/mam.py
deleted file mode 100644
index e02d28f5..00000000
--- a/src/tmp/wokkel/mam.py
+++ /dev/null
@@ -1,620 +0,0 @@
-# -*- coding: utf-8 -*-
-# -*- test-case-name: wokkel.test.test_mam -*-
-#
-# SàT Wokkel extension for Message Archive Management (XEP-0313)
-# Copyright (C) 2015 Jérôme Poisson (goffi@goffi.org)
-# Copyright (C) 2015 Adien Cossa (souliane@mailoo.org)
-
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Affero General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU Affero General Public License for more details.
-
-# You should have received a copy of the GNU Affero General Public License
-# along with this program. If not, see .
-
-"""
-XMPP Message Archive Management protocol.
-
-This protocol is specified in
-U{XEP-0313}.
-"""
-
-from dateutil import tz
-
-from zope.interface import implements
-from zope.interface import Interface
-
-from twisted.words.protocols.jabber import xmlstream
-from twisted.words.xish import domish
-from twisted.words.protocols.jabber import jid
-from twisted.words.protocols.jabber import error
-from twisted.internet import defer
-from twisted.python import log
-
-from wokkel import subprotocols
-from wokkel import disco
-from wokkel import data_form
-from wokkel import delay
-
-import rsm
-
-NS_MAM = 'urn:xmpp:mam:1'
-NS_FORWARD = 'urn:xmpp:forward:0'
-
-FIELDS_REQUEST = "/iq[@type='get']/query[@xmlns='%s']" % NS_MAM
-ARCHIVE_REQUEST = "/iq[@type='set']/query[@xmlns='%s']" % NS_MAM
-PREFS_GET_REQUEST = "/iq[@type='get']/prefs[@xmlns='%s']" % NS_MAM
-PREFS_SET_REQUEST = "/iq[@type='set']/prefs[@xmlns='%s']" % NS_MAM
-
-# TODO: add the tests!
-
-
-class MAMError(error.StanzaError):
- """
- MAM error.
- """
- def __init__(self, text=None):
- error.StanzaError.__init__(self, 'bad-request', text=text)
-
-
-class Unsupported(MAMError):
- def __init__(self, feature, text=None):
- self.feature = feature
- MAMError.__init__(self, 'feature-not-implemented',
- 'unsupported',
- feature,
- text)
-
- def __str__(self):
- message = MAMError.__str__(self)
- message += ', feature %r' % self.feature
- return message
-
-
-class MAMRequest(object):
- """
- A Message Archive Management request.
-
- @ivar form: Data Form specifing the filters.
- @itype form: L{data_form.Form}
-
- @ivar rsm: RSM request instance.
- @itype rsm: L{rsm.RSMRequest}
-
- @ivar node: pubsub node id if querying a pubsub node, else None.
- @itype node: C{unicode}
-
- @ivar query_id: id to use to track the query
- @itype query_id: C{unicode}
- """
- # FIXME: should be based on generic.Stanza
-
- def __init__(self, form=None, rsm_=None, node=None, query_id=None, sender=None, recipient=None):
- if form is not None:
- assert form.formType == 'submit'
- assert form.formNamespace == NS_MAM
- self.form = form
- self.rsm = rsm_
- self.node = node
- self.query_id = query_id
- self.sender = sender
- self.recipient = recipient
-
- @classmethod
- def fromElement(cls, iq):
- """Parse the DOM representation of a MAM request.
-
- @param iq: element containing a MAM .
- @type iq: L{Element}
-
- @return: MAMRequest instance.
- @rtype: L{MAMRequest}
- """
- sender = jid.JID(iq.getAttribute('from'))
- recipient = jid.JID(iq.getAttribute('to'))
- try:
- query = iq.elements(NS_MAM, 'query').next()
- except StopIteration:
- raise MAMError("Can't find MAM in element")
- form = data_form.findForm(query, NS_MAM)
- try:
- rsm_request = rsm.RSMRequest.fromElement(query)
- except rsm.RSMNotFoundError:
- rsm_request = None
- node = query.getAttribute('node')
- query_id = query.getAttribute('queryid')
- return MAMRequest(form, rsm_request, node, query_id, sender, recipient)
-
- def toElement(self):
- """
- Return the DOM representation of this RSM request.
-
- @rtype: L{Element}
- """
- mam_elt = domish.Element((NS_MAM, 'query'))
- if self.node is not None:
- mam_elt['node'] = self.node
- if self.query_id is not None:
- mam_elt['queryid'] = self.query_id
- if self.form is not None:
- mam_elt.addChild(self.form.toElement())
- if self.rsm is not None:
- mam_elt.addChild(self.rsm.toElement())
-
- return mam_elt
-
- def render(self, parent):
- """Embed the DOM representation of this MAM request in the given element.
-
- @param parent: parent IQ element.
- @type parent: L{Element}
-
- @return: MAM request element.
- @rtype: L{Element}
- """
- assert parent.name == 'iq'
- mam_elt = self.toElement()
- parent.addChild(mam_elt)
- return mam_elt
-
-
-class MAMPrefs(object):
- """
- A Message Archive Management request.
-
- @param default: A value in ('always', 'never', 'roster').
- @type : C{unicode} or C{None}
-
- @param always (list): A list of JID instances.
- @type always: C{list}
-
- @param never (list): A list of JID instances.
- @type never: C{list}
- """
-
- def __init__(self, default=None, always=None, never=None):
- if default is not None:
- # default must be defined in response, but can be empty in request (see http://xmpp.org/extensions/xep-0313.html#config)
- assert default in ('always', 'never', 'roster')
- self.default = default
- if always is not None:
- assert isinstance(always, list)
- else:
- always = []
- self.always = always
- if never is not None:
- assert isinstance(never, list)
- else:
- never = []
- self.never = never
-
- @classmethod
- def fromElement(cls, prefs_elt):
- """Parse the DOM representation of a MAM request.
-
- @param prefs_elt: MAM request element.
- @type prefs_elt: L{Element}
-
- @return: MAMPrefs instance.
- @rtype: L{MAMPrefs}
- """
- if prefs_elt.uri != NS_MAM or prefs_elt.name != 'prefs':
- raise MAMError('Element provided is not a MAM request')
- try:
- default = prefs_elt['default']
- except KeyError:
- # FIXME: return proper error here
- raise MAMError('Element provided is not a valid MAM request')
-
- prefs = {}
- for attr in ('always', 'never'):
- prefs[attr] = []
- try:
- pref = prefs_elt.elements(NS_MAM, attr).next()
- except StopIteration:
- # FIXME: return proper error here
- raise MAMError('Element provided is not a valid MAM request')
- else:
- for jid_s in pref.elements(NS_MAM, 'jid'):
- prefs[attr].append(jid.JID(jid_s))
- return MAMPrefs(default, **prefs)
-
- def toElement(self):
- """
- Return the DOM representation of this RSM request.
-
- @rtype: L{Element}
- """
- mam_elt = domish.Element((NS_MAM, 'prefs'))
- if self.default:
- mam_elt['default'] = self.default
- for attr in ('always', 'never'):
- attr_elt = mam_elt.addElement(attr)
- jids = getattr(self, attr)
- for jid_ in jids:
- attr_elt.addElement('jid', content=jid_.full())
- return mam_elt
-
- def render(self, parent):
- """Embed the DOM representation of this MAM request in the given element.
-
- @param parent: parent IQ element.
- @type parent: L{Element}
-
- @return: MAM request element.
- @rtype: L{Element}
- """
- assert parent.name == 'iq'
- mam_elt = self.toElement()
- parent.addChild(mam_elt)
- return mam_elt
-
-
-class MAMClient(subprotocols.XMPPHandler):
- """
- MAM client.
-
- This handler implements the protocol for sending out MAM requests.
- """
-
- def queryArchive(self, mam_query, service=None, sender=None):
- """Query a user, MUC or pubsub archive.
-
- @param mam_query: query to use
- @type form: L{MAMRequest}
-
- @param service: Entity offering the MAM service (None for user server).
- @type service: L{JID}
-
- @param sender: Optional sender address.
- @type sender: L{JID}
-
- @return: A deferred that fires upon receiving a response.
- @rtype: L{Deferred}
- """
- iq = xmlstream.IQ(self.xmlstream, 'set')
- mam_query.render(iq)
- if sender is not None:
- iq['from'] = unicode(sender)
- return iq.send(to=service.full() if service else None)
-
- def queryFields(self, service=None, sender=None):
- """Ask the server about supported fields.
-
- @param service: Entity offering the MAM service (None for user archives).
- @type service: L{JID}
-
- @param sender: Optional sender address.
- @type sender: L{JID}
-
- @return: data Form with the fields, or None if not found
- @rtype: L{Deferred}
- """
- # http://xmpp.org/extensions/xep-0313.html#query-form
- iq = xmlstream.IQ(self.xmlstream, 'get')
- MAMRequest().render(iq)
- if sender is not None:
- iq['from'] = unicode(sender)
- d = iq.send(to=service.full() if service else None)
- d.addCallback(lambda iq_result: iq_result.elements(NS_MAM, 'query').next())
- d.addCallback(data_form.findForm, NS_MAM)
- return d
-
- def queryPrefs(self, service=None, sender=None):
- """Retrieve the current user preferences.
-
- @param service: Entity offering the MAM service (None for user archives).
- @type service: L{JID}
-
- @param sender: Optional sender address.
- @type sender: L{JID}
-
- @return: A deferred that fires upon receiving a response.
- @rtype: L{Deferred}
- """
- # http://xmpp.org/extensions/xep-0313.html#prefs
- iq = xmlstream.IQ(self.xmlstream, 'get')
- MAMPrefs().render(iq)
- if sender is not None:
- iq['from'] = unicode(sender)
- return iq.send(to=service.full() if service else None)
-
- def setPrefs(self, service=None, default='roster', always=None, never=None, sender=None):
- """Set new user preferences.
-
- @param service: Entity offering the MAM service (None for user archives).
- @type service: L{JID}
-
- @param default: A value in ('always', 'never', 'roster').
- @type : C{unicode}
-
- @param always (list): A list of JID instances.
- @type always: C{list}
-
- @param never (list): A list of JID instances.
- @type never: C{list}
-
- @param sender: Optional sender address.
- @type sender: L{JID}
-
- @return: A deferred that fires upon receiving a response.
- @rtype: L{Deferred}
- """
- # http://xmpp.org/extensions/xep-0313.html#prefs
- assert default is not None
- iq = xmlstream.IQ(self.xmlstream, 'set')
- MAMPrefs(default, always, never).render(iq)
- if sender is not None:
- iq['from'] = unicode(sender)
- return iq.send(to=service.full() if service else None)
-
-
-class IMAMResource(Interface):
-
- def onArchiveRequest(self, mam):
- """
-
- @param mam: The MAM request.
- @type mam: L{MAMQueryReques}
-
- @return: The RSM answer.
- @rtype: L{RSMResponse}
- """
-
- def onPrefsGetRequest(self, requestor):
- """
-
- @param requestor: JID of the requestor.
- @type requestor: L{JID}
-
- @return: The current settings.
- @rtype: L{wokkel.mam.MAMPrefs}
- """
-
- def onPrefsSetRequest(self, prefs, requestor):
- """
-
- @param prefs: The new settings to set.
- @type prefs: L{wokkel.mam.MAMPrefs}
-
- @param requestor: JID of the requestor.
- @type requestor: L{JID}
-
- @return: The new current settings.
- @rtype: L{wokkel.mam.MAMPrefs}
- """
-
-class IMAMService(Interface):
- """
- Interface for XMPP MAM service.
- """
-
- def addFilter(self, field):
- """
- Add a new filter for querying MAM archive.
-
- @param field: data form field of the filter
- @type field: L{Form}
- """
-
-
-class MAMService(subprotocols.XMPPHandler, subprotocols.IQHandlerMixin):
- """
- Protocol implementation for a MAM service.
-
- This handler waits for XMPP Ping requests and sends a response.
- """
- implements(IMAMService, disco.IDisco)
-
- _request_class = MAMRequest
-
- iqHandlers = {FIELDS_REQUEST: '_onFieldsRequest',
- ARCHIVE_REQUEST: '_onArchiveRequest',
- PREFS_GET_REQUEST: '_onPrefsGetRequest',
- PREFS_SET_REQUEST: '_onPrefsSetRequest'
- }
-
- _legacyFilters = {'start': {'fieldType': 'text-single',
- 'var': 'start',
- 'label': 'Starting time',
- 'desc': 'Starting time a the result period.',
- },
- 'end': {'fieldType': 'text-single',
- 'var': 'end',
- 'label': 'Ending time',
- 'desc': 'Ending time of the result period.',
- },
- 'with': {'fieldType': 'jid-single',
- 'var': 'with',
- 'label': 'Entity',
- 'desc': 'Entity against which to match message.',
- },
- }
-
- def __init__(self, resource):
- """
- @param resource: instance implementing IMAMResource
- @type resource: L{object}
- """
- self.resource = resource
- self.extra_fields = {}
-
- def connectionInitialized(self):
- """
- Called when the XML stream has been initialized.
-
- This sets up an observer for incoming ping requests.
- """
- self.xmlstream.addObserver(FIELDS_REQUEST, self.handleRequest)
- self.xmlstream.addObserver(ARCHIVE_REQUEST, self.handleRequest)
- self.xmlstream.addObserver(PREFS_GET_REQUEST, self.handleRequest)
- self.xmlstream.addObserver(PREFS_SET_REQUEST, self.handleRequest)
-
- def addFilter(self, field):
- """
- Add a new filter for querying MAM archive.
-
- @param field: data form field of the filter
- @type field: L{Form}
- """
- self.extra_fields[field.var] = field
-
- def _onFieldsRequest(self, iq):
- """
- Called when a fields request has been received.
-
- This immediately replies with a result response.
- """
- iq.handled = True
- query = domish.Element((NS_MAM, 'query'))
- query.addChild(buildForm(extra_fields=self.extra_fields).toElement(), formType='form')
- return query
-
- def _onArchiveRequest(self, iq):
- """
- Called when a message archive request has been received.
-
- This replies with the list of archived message and the result
- @return: A tuple with list of message data (id, element, data) and RSM element
- @rtype: C{tuple}
- """
- iq.handled = True
- mam_ = self._request_class.fromElement(iq)
-
- # remove unsupported filters
- unsupported_fields = []
- if mam_.form:
- for key, field in mam_.form.fields.iteritems():
- if key not in self._legacyFilters and key not in self.extra_fields:
- log.msg('Ignored unsupported MAM filter: %s' % field)
- unsupported_fields.append(key)
- for key in unsupported_fields:
- del mam_.form.fields[key]
-
- def forwardMessage(id_, elt, date):
- msg = domish.Element((None, 'message'))
- msg['to'] = iq['from']
- result = msg.addElement((NS_MAM, 'result'))
- if mam_.query_id is not None:
- result['queryid'] = mam_.query_id
- result['id'] = id_
- forward = result.addElement((NS_FORWARD, 'forwarded'))
- forward.addChild(delay.Delay(date).toElement())
- forward.addChild(elt)
- self.xmlstream.send(msg)
-
- def cb(result):
- msg_data, rsm_elt = result
- for data in msg_data:
- forwardMessage(*data)
-
- fin_elt = domish.Element((NS_MAM, 'fin'))
-
- if rsm_elt is not None:
- fin_elt.addChild(rsm_elt)
- return fin_elt
-
- d = defer.maybeDeferred(self.resource.onArchiveRequest, mam_)
- d.addCallback(cb)
- return d
-
- def _onPrefsGetRequest(self, iq):
- """
- Called when a prefs get request has been received.
-
- This immediately replies with a result response.
- """
- iq.handled = True
- requestor = jid.JID(iq['from'])
-
- def cb(prefs):
- return prefs.toElement()
-
- d = self.resource.onPrefsGetRequest(requestor).addCallback(cb)
- return d
-
- def _onPrefsSetRequest(self, iq):
- """
- Called when a prefs get request has been received.
-
- This immediately replies with a result response.
- """
- iq.handled = True
-
- prefs = MAMPrefs.fromElement(iq.prefs)
- requestor = jid.JID(iq['from'])
-
- def cb(prefs):
- return prefs.toElement()
-
- d = self.resource.onPrefsSetRequest(prefs, requestor).addCallback(cb)
- return d
-
- def getDiscoInfo(self, requestor, target, nodeIdentifier=''):
- if nodeIdentifier:
- return []
- return [disco.DiscoFeature(NS_MAM)]
-
- def getDiscoItems(self, requestor, target, nodeIdentifier=''):
- return []
-
-
-def datetime2utc(datetime_obj):
- """Convert a datetime to a XEP-0082 compliant UTC datetime.
-
- @param datetime_obj: Offset-aware timestamp to convert.
- @type datetime_obj: L{datetime}
-
- @return: The datetime converted to UTC.
- @rtype: C{unicode}
- """
- stampFormat = '%Y-%m-%dT%H:%M:%SZ'
- return datetime_obj.astimezone(tz.tzutc()).strftime(stampFormat)
-
-
-def buildForm(start=None, end=None, with_jid=None, extra_fields=None, formType='submit'):
- """Prepare a Data Form for MAM.
-
- @param start: Offset-aware timestamp to filter out older messages.
- @type start: L{datetime}
-
- @param end: Offset-aware timestamp to filter out later messages.
- @type end: L{datetime}
-
- @param with_jid: JID against which to match messages.
- @type with_jid: L{JID}
-
- @param extra_fields: list of extra data form fields that are not defined by the
- specification.
- @type: C{list}
-
- @param formType: The type of the Data Form ('submit' or 'form').
- @type formType: C{unicode}
-
- @return: XEP-0004 Data Form object.
- @rtype: L{Form}
- """
- form = data_form.Form(formType, formNamespace=NS_MAM)
-
- if formType == 'form':
- for kwargs in MAMService._legacyFilters.values():
- form.addField(data_form.Field(**kwargs))
- elif formType == 'submit':
- if start:
- form.addField(data_form.Field(var='start', value=datetime2utc(start)))
- if end:
- form.addField(data_form.Field(var='end', value=datetime2utc(end)))
- if with_jid:
- form.addField(data_form.Field(fieldType='jid-single', var='with', value=with_jid.full()))
-
- if extra_fields is not None:
- for field in extra_fields:
- form.addField(field)
-
- return form
diff --git a/src/tmp/wokkel/pubsub.py b/src/tmp/wokkel/pubsub.py
deleted file mode 100755
index a2cf3f37..00000000
--- a/src/tmp/wokkel/pubsub.py
+++ /dev/null
@@ -1,1717 +0,0 @@
-# -*- coding: utf-8 -*-
-# -*- test-case-name: wokkel.test.test_pubsub -*-
-#
-# SàT adaptation for wokkel.pubsub
-# Copyright (C) 2015 Adien Cossa (souliane@mailoo.org)
-# Copyright (c) 2003-2012 Ralph Meijer.
-
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Affero General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU Affero General Public License for more details.
-
-# You should have received a copy of the GNU Affero General Public License
-# along with this program. If not, see .
-# --
-
-# This program is based on wokkel (https://wokkel.ik.nu/),
-# originaly written by Ralph Meijer
-# It is sublicensed under AGPL v3 (or any later version) as allowed by the original
-# license.
-
-# --
-
-# Here is a copy of the original license:
-
-# Copyright (c) 2003-2012 Ralph Meijer.
-#
-# Permission is hereby granted, free of charge, to any person obtaining
-# a copy of this software and associated documentation files (the
-# "Software"), to deal in the Software without restriction, including
-# without limitation the rights to use, copy, modify, merge, publish,
-# distribute, sublicense, and/or sell copies of the Software, and to
-# permit persons to whom the Software is furnished to do so, subject to
-# the following conditions:
-#
-# The above copyright notice and this permission notice shall be
-# included in all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
-# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
-# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-
-"""
-XMPP publish-subscribe protocol.
-
-This protocol is specified in
-U{XEP-0060}.
-"""
-
-from zope.interface import implements
-
-from twisted.internet import defer
-from twisted.python import log
-from twisted.words.protocols.jabber import jid, error
-from twisted.words.xish import domish
-
-from wokkel import disco, data_form, generic, shim
-from wokkel.compat import IQ
-from wokkel.subprotocols import IQHandlerMixin, XMPPHandler
-from wokkel.iwokkel import IPubSubClient, IPubSubService, IPubSubResource
-
-# Iq get and set XPath queries
-IQ_GET = '/iq[@type="get"]'
-IQ_SET = '/iq[@type="set"]'
-
-# Publish-subscribe namespaces
-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_PUBSUB_NODE_CONFIG = NS_PUBSUB + "#node_config"
-NS_PUBSUB_META_DATA = NS_PUBSUB + "#meta-data"
-NS_PUBSUB_SUBSCRIBE_OPTIONS = NS_PUBSUB + "#subscribe_options"
-
-# XPath to match pubsub requests
-PUBSUB_REQUEST = '/iq[@type="get" or @type="set"]/' + \
- 'pubsub[@xmlns="' + NS_PUBSUB + '" or ' + \
- '@xmlns="' + NS_PUBSUB_OWNER + '"]'
-
-BOOL_TRUE = ('1','true')
-BOOL_FALSE = ('0','false')
-
-class SubscriptionPending(Exception):
- """
- Raised when the requested subscription is pending acceptance.
- """
-
-
-
-class SubscriptionUnconfigured(Exception):
- """
- Raised when the requested subscription needs to be configured before
- becoming active.
- """
-
-
-
-class PubSubError(error.StanzaError):
- """
- Exception with publish-subscribe specific condition.
- """
- def __init__(self, condition, pubsubCondition, feature=None, text=None):
- appCondition = domish.Element((NS_PUBSUB_ERRORS, pubsubCondition))
- if feature:
- appCondition['feature'] = feature
- error.StanzaError.__init__(self, condition,
- text=text,
- appCondition=appCondition)
-
-
-
-class BadRequest(error.StanzaError):
- """
- Bad request stanza error.
- """
- def __init__(self, pubsubCondition=None, text=None):
- if pubsubCondition:
- appCondition = domish.Element((NS_PUBSUB_ERRORS, pubsubCondition))
- else:
- appCondition = None
- error.StanzaError.__init__(self, 'bad-request',
- text=text,
- appCondition=appCondition)
-
-
-
-class Unsupported(PubSubError):
- def __init__(self, feature, text=None):
- self.feature = feature
- PubSubError.__init__(self, 'feature-not-implemented',
- 'unsupported',
- feature,
- text)
-
- def __str__(self):
- message = PubSubError.__str__(self)
- message += ', feature %r' % self.feature
- return message
-
-
-class Subscription(object):
- """
- A subscription to a node.
-
- @ivar nodeIdentifier: The identifier of the node subscribed to. The root
- node is denoted by C{None}.
- @type nodeIdentifier: C{unicode}
-
- @ivar subscriber: The subscribing entity.
- @type subscriber: L{jid.JID}
-
- @ivar state: The subscription state. One of C{'subscribed'}, C{'pending'},
- C{'unconfigured'}, C{'none'}.
- @type state: C{unicode}
-
- @ivar options: Optional list of subscription options.
- @type options: C{dict}
-
- @ivar subscriptionIdentifier: Optional subscription identifier.
- @type subscriptionIdentifier: C{unicode}
- """
-
- def __init__(self, nodeIdentifier, subscriber, state, options=None,
- subscriptionIdentifier=None):
- self.nodeIdentifier = nodeIdentifier
- self.subscriber = subscriber
- self.state = state
- self.options = options or {}
- self.subscriptionIdentifier = subscriptionIdentifier
-
-
- @staticmethod
- def fromElement(element):
- return Subscription(
- element.getAttribute('node'),
- jid.JID(element.getAttribute('jid')),
- element.getAttribute('subscription'),
- subscriptionIdentifier=element.getAttribute('subid'))
-
-
- def toElement(self, defaultUri=None):
- """
- Return the DOM representation of this subscription.
-
- @rtype: L{domish.Element}
- """
- element = domish.Element((defaultUri, 'subscription'))
- if self.nodeIdentifier:
- element['node'] = self.nodeIdentifier
- element['jid'] = unicode(self.subscriber)
- element['subscription'] = self.state
- if self.subscriptionIdentifier:
- element['subid'] = self.subscriptionIdentifier
- return element
-
-
-
-class Item(domish.Element):
- """
- Publish subscribe item.
-
- This behaves like an object providing L{domish.IElement}.
-
- Item payload can be added using C{addChild} or C{addRawXml}, or using the
- C{payload} keyword argument to C{__init__}.
- """
-
- def __init__(self, id=None, payload=None):
- """
- @param id: optional item identifier
- @type id: C{unicode}
- @param payload: optional item payload. Either as a domish element, or
- as serialized XML.
- @type payload: object providing L{domish.IElement} or C{unicode}.
- """
-
- domish.Element.__init__(self, (None, 'item'))
- if id is not None:
- self['id'] = id
- if payload is not None:
- if isinstance(payload, basestring):
- self.addRawXml(payload)
- else:
- self.addChild(payload)
-
-
-
-class PubSubRequest(generic.Stanza):
- """
- A publish-subscribe request.
-
- The set of instance variables used depends on the type of request. If
- a variable is not applicable or not passed in the request, its value is
- C{None}.
-
- @ivar verb: The type of publish-subscribe request. See C{_requestVerbMap}.
- @type verb: C{str}.
-
- @ivar affiliations: Affiliations to be modified.
- @type affiliations: C{set}
-
- @ivar items: The items to be published, as L{domish.Element}s.
- @type items: C{list}
-
- @ivar itemIdentifiers: Identifiers of the items to be retrieved or
- retracted.
- @type itemIdentifiers: C{set}
-
- @ivar maxItems: Maximum number of items to retrieve.
- @type maxItems: C{int}.
-
- @ivar nodeIdentifier: Identifier of the node the request is about.
- @type nodeIdentifier: C{unicode}
-
- @ivar nodeType: The type of node that should be created, or for which the
- configuration is retrieved. C{'leaf'} or C{'collection'}.
- @type nodeType: C{str}
-
- @ivar options: Configurations options for nodes, subscriptions and publish
- requests.
- @type options: L{data_form.Form}
-
- @ivar subscriber: The subscribing entity.
- @type subscriber: L{JID}
-
- @ivar subscriptionIdentifier: Identifier for a specific subscription.
- @type subscriptionIdentifier: C{unicode}
-
- @ivar subscriptions: Subscriptions to be modified, as a set of
- L{Subscription}.
- @type subscriptions: C{set}
-
- @ivar affiliations: Affiliations to be modified, as a dictionary of entity
- (L{JID} to affiliation
- (C{unicode}).
- @type affiliations: C{dict}
- """
-
- verb = None
-
- items = None
- itemIdentifiers = None
- maxItems = None
- nodeIdentifier = None
- nodeType = None
- options = None
- subscriber = None
- subscriptionIdentifier = None
- subscriptions = None
- affiliations = None
- notify = None
-
- # Map request iq type and subelement name to request verb
- _requestVerbMap = {
- ('set', NS_PUBSUB, 'publish'): 'publish',
- ('set', NS_PUBSUB, 'subscribe'): 'subscribe',
- ('set', NS_PUBSUB, 'unsubscribe'): 'unsubscribe',
- ('get', NS_PUBSUB, 'options'): 'optionsGet',
- ('set', NS_PUBSUB, 'options'): 'optionsSet',
- ('get', NS_PUBSUB, 'subscriptions'): 'subscriptions',
- ('get', NS_PUBSUB, 'affiliations'): 'affiliations',
- ('set', NS_PUBSUB, 'create'): 'create',
- ('get', NS_PUBSUB_OWNER, 'default'): 'default',
- ('get', NS_PUBSUB_OWNER, 'configure'): 'configureGet',
- ('set', NS_PUBSUB_OWNER, 'configure'): 'configureSet',
- ('get', NS_PUBSUB, 'items'): 'items',
- ('set', NS_PUBSUB, 'retract'): 'retract',
- ('set', NS_PUBSUB_OWNER, 'purge'): 'purge',
- ('set', NS_PUBSUB_OWNER, 'delete'): 'delete',
- ('get', NS_PUBSUB_OWNER, 'affiliations'): 'affiliationsGet',
- ('set', NS_PUBSUB_OWNER, 'affiliations'): 'affiliationsSet',
- ('get', NS_PUBSUB_OWNER, 'subscriptions'): 'subscriptionsGet',
- ('set', NS_PUBSUB_OWNER, 'subscriptions'): 'subscriptionsSet',
- }
-
- # Map request verb to request iq type and subelement name
- _verbRequestMap = dict(((v, k) for k, v in _requestVerbMap.iteritems()))
-
- # Map request verb to parameter handler names
- _parameters = {
- 'publish': ['node', 'items'],
- 'subscribe': ['nodeOrEmpty', 'jid', 'optionsWithSubscribe'],
- 'unsubscribe': ['nodeOrEmpty', 'jid', 'subidOrNone'],
- 'optionsGet': ['nodeOrEmpty', 'jid', 'subidOrNone'],
- 'optionsSet': ['nodeOrEmpty', 'jid', 'options', 'subidOrNone'],
- 'subscriptions': ['nodeOrEmpty'],
- 'affiliations': ['nodeOrNone'],
- 'create': ['nodeOrNone', 'configureOrNone'],
- 'default': ['default'],
- 'configureGet': ['nodeOrEmpty'],
- 'configureSet': ['nodeOrEmpty', 'configureOrNone'],
- 'items': ['node', 'maxItems', 'itemIdentifiers', 'subidOrNone'],
- 'retract': ['node', 'notify', 'itemIdentifiers'],
- 'purge': ['node'],
- 'delete': ['node'],
- 'affiliationsGet': ['node'],
- 'affiliationsSet': ['node', 'affiliations'],
- 'subscriptionsGet': ['node'],
- 'subscriptionsSet': ['node', 'subscriptions'],
- }
-
- def __init__(self, verb=None):
- self.verb = verb
-
-
- def _parse_node(self, verbElement):
- """
- Parse the required node identifier out of the verbElement.
- """
- try:
- self.nodeIdentifier = verbElement["node"]
- except KeyError:
- raise BadRequest('nodeid-required')
-
-
- def _render_node(self, verbElement):
- """
- Render the required node identifier on the verbElement.
- """
- if not self.nodeIdentifier:
- raise Exception("Node identifier is required")
-
- verbElement['node'] = self.nodeIdentifier
-
-
- def _parse_nodeOrEmpty(self, verbElement):
- """
- Parse the node identifier out of the verbElement. May be empty.
- """
- self.nodeIdentifier = verbElement.getAttribute("node", '')
-
-
- def _render_nodeOrEmpty(self, verbElement):
- """
- Render the node identifier on the verbElement. May be empty.
- """
- if self.nodeIdentifier:
- verbElement['node'] = self.nodeIdentifier
-
-
- def _parse_nodeOrNone(self, verbElement):
- """
- Parse the optional node identifier out of the verbElement.
- """
- self.nodeIdentifier = verbElement.getAttribute("node")
-
-
- def _render_nodeOrNone(self, verbElement):
- """
- Render the optional node identifier on the verbElement.
- """
- if self.nodeIdentifier:
- verbElement['node'] = self.nodeIdentifier
-
-
- def _parse_items(self, verbElement):
- """
- Parse items out of the verbElement for publish requests.
- """
- self.items = []
- for element in verbElement.elements():
- if element.uri == NS_PUBSUB and element.name == 'item':
- self.items.append(element)
-
-
- def _render_items(self, verbElement):
- """
- Render items into the verbElement for publish requests.
- """
- if self.items:
- for item in self.items:
- item.uri = NS_PUBSUB
- verbElement.addChild(item)
-
-
- def _parse_jid(self, verbElement):
- """
- Parse subscriber out of the verbElement for un-/subscribe requests.
- """
- try:
- self.subscriber = jid.internJID(verbElement["jid"])
- except KeyError:
- raise BadRequest('jid-required')
-
-
- def _render_jid(self, verbElement):
- """
- Render subscriber into the verbElement for un-/subscribe requests.
- """
- verbElement['jid'] = self.subscriber.full()
-
-
- def _parse_default(self, verbElement):
- """
- Parse node type out of a request for the default node configuration.
- """
- form = data_form.findForm(verbElement, NS_PUBSUB_NODE_CONFIG)
- if form is not None and form.formType == 'submit':
- values = form.getValues()
- self.nodeType = values.get('pubsub#node_type', 'leaf')
- else:
- self.nodeType = 'leaf'
-
-
- def _parse_configure(self, verbElement):
- """
- Parse options out of a request for setting the node configuration.
- """
- form = data_form.findForm(verbElement, NS_PUBSUB_NODE_CONFIG)
- if form is not None:
- if form.formType in ('submit', 'cancel'):
- self.options = form
- else:
- raise BadRequest(text=u"Unexpected form type '%s'" % form.formType)
- else:
- raise BadRequest(text="Missing configuration form")
-
-
- def _parse_configureOrNone(self, verbElement):
- """
- Parse optional node configuration form in create request.
- """
- for element in verbElement.parent.elements():
- if element.uri in (NS_PUBSUB, NS_PUBSUB_OWNER) and element.name == 'configure':
- form = data_form.findForm(element, NS_PUBSUB_NODE_CONFIG)
- if form is not None:
- if form.formType != 'submit':
- raise BadRequest(text=u"Unexpected form type '%s'" %
- form.formType)
- else:
- form = data_form.Form('submit',
- formNamespace=NS_PUBSUB_NODE_CONFIG)
- self.options = form
-
-
- def _render_configureOrNone(self, verbElement):
- """
- Render optional node configuration form in create request.
- """
- if self.options is not None:
- if verbElement.name == 'configure':
- configure = verbElement
- else:
- configure = verbElement.parent.addElement('configure')
- configure.addChild(self.options.toElement())
-
-
- def _parse_itemIdentifiers(self, verbElement):
- """
- Parse item identifiers out of items and retract requests.
- """
- self.itemIdentifiers = []
- for element in verbElement.elements():
- if element.uri == NS_PUBSUB and element.name == 'item':
- try:
- self.itemIdentifiers.append(element["id"])
- except KeyError:
- raise BadRequest()
-
-
- def _render_itemIdentifiers(self, verbElement):
- """
- Render item identifiers into items and retract requests.
- """
- if self.itemIdentifiers:
- for itemIdentifier in self.itemIdentifiers:
- item = verbElement.addElement('item')
- item['id'] = itemIdentifier
-
-
- def _parse_maxItems(self, verbElement):
- """
- Parse maximum items out of an items request.
- """
- value = verbElement.getAttribute('max_items')
-
- if value:
- try:
- self.maxItems = int(value)
- except ValueError:
- raise BadRequest(text="Field max_items requires a positive " +
- "integer value")
-
-
- def _render_maxItems(self, verbElement):
- """
- Render maximum items into an items request.
- """
- if self.maxItems:
- verbElement['max_items'] = unicode(self.maxItems)
-
-
- def _parse_subidOrNone(self, verbElement):
- """
- Parse subscription identifier out of a request.
- """
- self.subscriptionIdentifier = verbElement.getAttribute("subid")
-
-
- def _render_subidOrNone(self, verbElement):
- """
- Render subscription identifier into a request.
- """
- if self.subscriptionIdentifier:
- verbElement['subid'] = self.subscriptionIdentifier
-
-
- def _parse_options(self, verbElement):
- """
- Parse options form out of a subscription options request.
- """
- form = data_form.findForm(verbElement, NS_PUBSUB_SUBSCRIBE_OPTIONS)
- if form is not None:
- if form.formType in ('submit', 'cancel'):
- self.options = form
- else:
- raise BadRequest(text=u"Unexpected form type '%s'" % form.formType)
- else:
- raise BadRequest(text="Missing options form")
-
-
- def _render_options(self, verbElement):
- verbElement.addChild(self.options.toElement())
-
-
- def _parse_optionsWithSubscribe(self, verbElement):
- for element in verbElement.parent.elements():
- if element.name == 'options' and element.uri == NS_PUBSUB:
- form = data_form.findForm(element,
- NS_PUBSUB_SUBSCRIBE_OPTIONS)
- if form is not None:
- if form.formType != 'submit':
- raise BadRequest(text=u"Unexpected form type '%s'" %
- form.formType)
- else:
- form = data_form.Form('submit',
- formNamespace=NS_PUBSUB_SUBSCRIBE_OPTIONS)
- self.options = form
-
-
- def _render_optionsWithSubscribe(self, verbElement):
- if self.options is not None:
- optionsElement = verbElement.parent.addElement('options')
- self._render_options(optionsElement)
-
-
- def _parse_affiliations(self, verbElement):
- self.affiliations = {}
- for element in verbElement.elements():
- if (element.uri == NS_PUBSUB_OWNER and
- element.name == 'affiliation'):
- try:
- entity = jid.internJID(element['jid']).userhostJID()
- except KeyError:
- raise BadRequest(text='Missing jid attribute')
-
- if entity in self.affiliations:
- raise BadRequest(text='Multiple affiliations for an entity')
-
- try:
- affiliation = element['affiliation']
- except KeyError:
- raise BadRequest(text='Missing affiliation attribute')
-
- self.affiliations[entity] = affiliation
-
-
- def _render_affiliations(self, verbElement):
- for entity, affiliation in self.affiliations.iteritems():
- affiliationElement = verbElement.addElement((NS_PUBSUB_OWNER, 'affiliation'))
- affiliationElement['jid'] = entity.full()
- affiliationElement['affiliation'] = affiliation
-
-
- def _parse_subscriptions(self, verbElement):
- self.subscriptions = set()
- seen_entities = set()
- for element in verbElement.elements():
- if (element.uri == NS_PUBSUB_OWNER and
- element.name == 'subscription'):
- try:
- subscriber = jid.internJID(element['jid']).userhostJID()
- except KeyError:
- raise BadRequest(text='Missing jid attribute')
-
- if subscriber in seen_entities:
- raise BadRequest(text='Multiple subscriptions for an subscriber')
- seen_entities.add(subscriber)
-
- try:
- state = element['subscription']
- except KeyError:
- # §8.8.2.1 says that value MUST NOT be changed
- # if subscription is missing
- continue
-
- self.subscriptions.add(Subscription(self.nodeIdentifier,
- subscriber,
- state))
-
-
- def _render_subscriptions(self, verbElement):
- for subscription in self.subscriptions:
- subscriptionElement = verbElement.addElement((NS_PUBSUB_OWNER, 'subscription'))
- subscriptionElement['jid'] = subscription.subscriber.full()
- subscriptionElement['subscription'] = subscription.state
-
-
- def _parse_notify(self, verbElement):
- value = verbElement.getAttribute('notify')
-
- if value:
- if value in BOOL_TRUE:
- self.notify = True
- elif value in BOOL_FALSE:
- self.notify = False
- else:
- raise BadRequest(text="Field notify must be a boolean value")
-
-
- def _render_notify(self, verbElement):
- if self.notify is not None:
- verbElement['notify'] = "true" if self.notify else "false"
-
-
- def parseElement(self, element):
- """
- Parse the publish-subscribe verb and parameters out of a request.
- """
- generic.Stanza.parseElement(self, element)
-
- verbs = []
- verbElements = []
- for child in element.pubsub.elements():
- key = (self.stanzaType, child.uri, child.name)
- try:
- verb = self._requestVerbMap[key]
- except KeyError:
- continue
-
- verbs.append(verb)
- verbElements.append(child)
-
- if not verbs:
- raise NotImplementedError()
-
- if len(verbs) > 1:
- if 'optionsSet' in verbs and 'subscribe' in verbs:
- self.verb = 'subscribe'
- verbElement = verbElements[verbs.index('subscribe')]
- else:
- raise NotImplementedError()
- else:
- self.verb = verbs[0]
- verbElement = verbElements[0]
-
- for parameter in self._parameters[self.verb]:
- getattr(self, '_parse_%s' % parameter)(verbElement)
-
-
-
- def send(self, xs):
- """
- Send this request to its recipient.
-
- This renders all of the relevant parameters for this specific
- requests into an L{IQ}, and invoke its C{send} method.
- This returns a deferred that fires upon reception of a response. See
- L{IQ} for details.
-
- @param xs: The XML stream to send the request on.
- @type xs: L{twisted.words.protocols.jabber.xmlstream.XmlStream}
- @rtype: L{defer.Deferred}.
- """
-
- try:
- (self.stanzaType,
- childURI,
- childName) = self._verbRequestMap[self.verb]
- except KeyError:
- raise NotImplementedError()
-
- iq = IQ(xs, self.stanzaType)
- iq.addElement((childURI, 'pubsub'))
- verbElement = iq.pubsub.addElement(childName)
-
- if self.sender:
- iq['from'] = self.sender.full()
- if self.recipient:
- iq['to'] = self.recipient.full()
-
- for parameter in self._parameters[self.verb]:
- getattr(self, '_render_%s' % parameter)(verbElement)
-
- return iq.send()
-
-
-
-class PubSubEvent(object):
- """
- A publish subscribe event.
-
- @param sender: The entity from which the notification was received.
- @type sender: L{jid.JID}
- @param recipient: The entity to which the notification was sent.
- @type recipient: L{wokkel.pubsub.ItemsEvent}
- @param nodeIdentifier: Identifier of the node the event pertains to.
- @type nodeIdentifier: C{unicode}
- @param headers: SHIM headers, see L{wokkel.shim.extractHeaders}.
- @type headers: C{dict}
- """
-
- def __init__(self, sender, recipient, nodeIdentifier, headers):
- self.sender = sender
- self.recipient = recipient
- self.nodeIdentifier = nodeIdentifier
- self.headers = headers
-
-
-
-class ItemsEvent(PubSubEvent):
- """
- A publish-subscribe event that signifies new, updated and retracted items.
-
- @param items: List of received items as domish elements.
- @type items: C{list} of L{domish.Element}
- """
-
- def __init__(self, sender, recipient, nodeIdentifier, items, headers):
- PubSubEvent.__init__(self, sender, recipient, nodeIdentifier, headers)
- self.items = items
-
-
-
-class DeleteEvent(PubSubEvent):
- """
- A publish-subscribe event that signifies the deletion of a node.
- """
-
- redirectURI = None
-
-
-
-class PurgeEvent(PubSubEvent):
- """
- A publish-subscribe event that signifies the purging of a node.
- """
-
-
-
-class PubSubClient(XMPPHandler):
- """
- Publish subscribe client protocol.
- """
- implements(IPubSubClient)
-
- _request_class = PubSubRequest
-
- def connectionInitialized(self):
- self.xmlstream.addObserver('/message/event[@xmlns="%s"]' %
- NS_PUBSUB_EVENT, self._onEvent)
-
-
- def _onEvent(self, message):
- if message.getAttribute('type') == 'error':
- return
-
- try:
- sender = jid.JID(message["from"])
- recipient = jid.JID(message["to"])
- except KeyError:
- return
-
- actionElement = None
- for element in message.event.elements():
- if element.uri == NS_PUBSUB_EVENT:
- actionElement = element
-
- if not actionElement:
- return
-
- eventHandler = getattr(self, "_onEvent_%s" % actionElement.name, None)
-
- if eventHandler:
- headers = shim.extractHeaders(message)
- eventHandler(sender, recipient, actionElement, headers)
- message.handled = True
-
-
- def _onEvent_items(self, sender, recipient, action, headers):
- nodeIdentifier = action["node"]
-
- items = [element for element in action.elements()
- if element.name in ('item', 'retract')]
-
- event = ItemsEvent(sender, recipient, nodeIdentifier, items, headers)
- self.itemsReceived(event)
-
-
- def _onEvent_delete(self, sender, recipient, action, headers):
- nodeIdentifier = action["node"]
- event = DeleteEvent(sender, recipient, nodeIdentifier, headers)
- if action.redirect:
- event.redirectURI = action.redirect.getAttribute('uri')
- self.deleteReceived(event)
-
-
- def _onEvent_purge(self, sender, recipient, action, headers):
- nodeIdentifier = action["node"]
- event = PurgeEvent(sender, recipient, nodeIdentifier, headers)
- self.purgeReceived(event)
-
-
- def itemsReceived(self, event):
- pass
-
-
- def deleteReceived(self, event):
- pass
-
-
- def purgeReceived(self, event):
- pass
-
-
- def createNode(self, service, nodeIdentifier=None, options=None,
- sender=None):
- """
- Create a publish subscribe node.
-
- @param service: The publish subscribe service to create the node at.
- @type service: L{JID}
- @param nodeIdentifier: Optional suggestion for the id of the node.
- @type nodeIdentifier: C{unicode}
- @param options: Optional node configuration options.
- @type options: C{dict}
- """
- request = self._request_class('create')
- request.recipient = service
- request.nodeIdentifier = nodeIdentifier
- request.sender = sender
-
- if options:
- form = data_form.Form(formType='submit',
- formNamespace=NS_PUBSUB_NODE_CONFIG)
- form.makeFields(options)
- request.options = form
-
- def cb(iq):
- try:
- new_node = iq.pubsub.create["node"]
- except AttributeError:
- # the suggested node identifier was accepted
- new_node = nodeIdentifier
- return new_node
-
- d = request.send(self.xmlstream)
- d.addCallback(cb)
- return d
-
-
- def deleteNode(self, service, nodeIdentifier, sender=None):
- """
- Delete a publish subscribe node.
-
- @param service: The publish subscribe service to delete the node from.
- @type service: L{JID}
- @param nodeIdentifier: The identifier of the node.
- @type nodeIdentifier: C{unicode}
- """
- request = self._request_class('delete')
- request.recipient = service
- request.nodeIdentifier = nodeIdentifier
- request.sender = sender
- return request.send(self.xmlstream)
-
-
- def subscribe(self, service, nodeIdentifier, subscriber,
- options=None, sender=None):
- """
- Subscribe to a publish subscribe node.
-
- @param service: The publish subscribe service that keeps the node.
- @type service: L{JID}
-
- @param nodeIdentifier: The identifier of the node.
- @type nodeIdentifier: C{unicode}
-
- @param subscriber: The entity to subscribe to the node. This entity
- will get notifications of new published items.
- @type subscriber: L{JID}
-
- @param options: Subscription options.
- @type options: C{dict}
-
- @return: Deferred that fires with L{Subscription} or errbacks with
- L{SubscriptionPending} or L{SubscriptionUnconfigured}.
- @rtype: L{defer.Deferred}
- """
- request = self._request_class('subscribe')
- request.recipient = service
- request.nodeIdentifier = nodeIdentifier
- request.subscriber = subscriber
- request.sender = sender
-
- if options:
- form = data_form.Form(formType='submit',
- formNamespace=NS_PUBSUB_SUBSCRIBE_OPTIONS)
- form.makeFields(options)
- request.options = form
-
- def cb(iq):
- subscription = Subscription.fromElement(iq.pubsub.subscription)
-
- if subscription.state == 'pending':
- raise SubscriptionPending()
- elif subscription.state == 'unconfigured':
- raise SubscriptionUnconfigured()
- else:
- # we assume subscription == 'subscribed'
- # any other value would be invalid, but that should have
- # yielded a stanza error.
- return subscription
-
- d = request.send(self.xmlstream)
- d.addCallback(cb)
- return d
-
-
- def unsubscribe(self, service, nodeIdentifier, subscriber,
- subscriptionIdentifier=None, sender=None):
- """
- Unsubscribe from a publish subscribe node.
-
- @param service: The publish subscribe service that keeps the node.
- @type service: L{JID}
-
- @param nodeIdentifier: The identifier of the node.
- @type nodeIdentifier: C{unicode}
-
- @param subscriber: The entity to unsubscribe from the node.
- @type subscriber: L{JID}
-
- @param subscriptionIdentifier: Optional subscription identifier.
- @type subscriptionIdentifier: C{unicode}
- """
- request = self._request_class('unsubscribe')
- request.recipient = service
- request.nodeIdentifier = nodeIdentifier
- request.subscriber = subscriber
- request.subscriptionIdentifier = subscriptionIdentifier
- request.sender = sender
- return request.send(self.xmlstream)
-
-
- def publish(self, service, nodeIdentifier, items=None, sender=None):
- """
- Publish to a publish subscribe node.
-
- @param service: The publish subscribe service that keeps the node.
- @type service: L{JID}
- @param nodeIdentifier: The identifier of the node.
- @type nodeIdentifier: C{unicode}
- @param items: Optional list of L{Item}s to publish.
- @type items: C{list}
- """
- request = self._request_class('publish')
- request.recipient = service
- request.nodeIdentifier = nodeIdentifier
- request.items = items
- request.sender = sender
- return request.send(self.xmlstream)
-
-
- def items(self, service, nodeIdentifier, maxItems=None, itemIdentifiers=None,
- subscriptionIdentifier=None, sender=None):
- """
- Retrieve previously published items from a publish subscribe node.
-
- @param service: The publish subscribe service that keeps the node.
- @type service: L{JID}
-
- @param nodeIdentifier: The identifier of the node.
- @type nodeIdentifier: C{unicode}
-
- @param maxItems: Optional limit on the number of retrieved items.
- @type maxItems: C{int}
-
- @param itemIdentifiers: Identifiers of the items to be retrieved.
- @type itemIdentifiers: C{set}
-
- @param subscriptionIdentifier: Optional subscription identifier. In
- case the node has been subscribed to multiple times, this narrows
- the results to the specific subscription.
- @type subscriptionIdentifier: C{unicode}
- """
- request = self._request_class('items')
- request.recipient = service
- request.nodeIdentifier = nodeIdentifier
- if maxItems:
- request.maxItems = str(int(maxItems))
- request.subscriptionIdentifier = subscriptionIdentifier
- request.sender = sender
- request.itemIdentifiers = itemIdentifiers
-
- def cb(iq):
- items = []
- for element in iq.pubsub.items.elements():
- if element.uri == NS_PUBSUB and element.name == 'item':
- items.append(element)
- return items
-
- d = request.send(self.xmlstream)
- d.addCallback(cb)
- return d
-
- def retractItems(self, service, nodeIdentifier, itemIdentifiers, notify=None, sender=None):
- """
- Retract items from a publish subscribe node.
-
- @param service: The publish subscribe service to delete the node from.
- @type service: L{JID}
- @param nodeIdentifier: The identifier of the node.
- @type nodeIdentifier: C{unicode}
- @param itemIdentifiers: Identifiers of the items to be retracted.
- @type itemIdentifiers: C{set}
- @param notify: True if notification is required
- @type notify: C{unicode}
- """
- request = self._request_class('retract')
- request.recipient = service
- request.nodeIdentifier = nodeIdentifier
- request.itemIdentifiers = itemIdentifiers
- request.notify = notify
- request.sender = sender
- return request.send(self.xmlstream)
-
- def getOptions(self, service, nodeIdentifier, subscriber,
- subscriptionIdentifier=None, sender=None):
- """
- Get subscription options.
-
- @param service: The publish subscribe service that keeps the node.
- @type service: L{JID}
-
- @param nodeIdentifier: The identifier of the node.
- @type nodeIdentifier: C{unicode}
-
- @param subscriber: The entity subscribed to the node.
- @type subscriber: L{JID}
-
- @param subscriptionIdentifier: Optional subscription identifier.
- @type subscriptionIdentifier: C{unicode}
-
- @rtype: L{data_form.Form}
- """
- request = self._request_class('optionsGet')
- request.recipient = service
- request.nodeIdentifier = nodeIdentifier
- request.subscriber = subscriber
- request.subscriptionIdentifier = subscriptionIdentifier
- request.sender = sender
-
- def cb(iq):
- form = data_form.findForm(iq.pubsub.options,
- NS_PUBSUB_SUBSCRIBE_OPTIONS)
- form.typeCheck()
- return form
-
- d = request.send(self.xmlstream)
- d.addCallback(cb)
- return d
-
-
- def setOptions(self, service, nodeIdentifier, subscriber,
- options, subscriptionIdentifier=None, sender=None):
- """
- Set subscription options.
-
- @param service: The publish subscribe service that keeps the node.
- @type service: L{JID}
-
- @param nodeIdentifier: The identifier of the node.
- @type nodeIdentifier: C{unicode}
-
- @param subscriber: The entity subscribed to the node.
- @type subscriber: L{JID}
-
- @param options: Subscription options.
- @type options: C{dict}.
-
- @param subscriptionIdentifier: Optional subscription identifier.
- @type subscriptionIdentifier: C{unicode}
- """
- request = self._request_class('optionsSet')
- request.recipient = service
- request.nodeIdentifier = nodeIdentifier
- request.subscriber = subscriber
- request.subscriptionIdentifier = subscriptionIdentifier
- request.sender = sender
-
- form = data_form.Form(formType='submit',
- formNamespace=NS_PUBSUB_SUBSCRIBE_OPTIONS)
- form.makeFields(options)
- request.options = form
-
- d = request.send(self.xmlstream)
- return d
-
-
-
-class PubSubService(XMPPHandler, IQHandlerMixin):
- """
- Protocol implementation for a XMPP Publish Subscribe Service.
-
- The word Service here is used as taken from the Publish Subscribe
- specification. It is the party responsible for keeping nodes and their
- subscriptions, and sending out notifications.
-
- Methods from the L{IPubSubService} interface that are called as a result
- of an XMPP request may raise exceptions. Alternatively the deferred
- returned by these methods may have their errback called. These are handled
- as follows:
-
- - If the exception is an instance of L{error.StanzaError}, an error
- response iq is returned.
- - Any other exception is reported using L{log.msg}. An error response
- with the condition C{internal-server-error} is returned.
-
- The default implementation of said methods raises an L{Unsupported}
- exception and are meant to be overridden.
-
- @ivar discoIdentity: Service discovery identity as a dictionary with
- keys C{'category'}, C{'type'} and C{'name'}.
- @ivar pubSubFeatures: List of supported publish-subscribe features for
- service discovery, as C{str}.
- @type pubSubFeatures: C{list} or C{None}
- """
-
- implements(IPubSubService, disco.IDisco)
-
- iqHandlers = {
- '/*': '_onPubSubRequest',
- }
-
- _legacyHandlers = {
- 'publish': ('publish', ['sender', 'recipient',
- 'nodeIdentifier', 'items']),
- 'subscribe': ('subscribe', ['sender', 'recipient',
- 'nodeIdentifier', 'subscriber']),
- 'unsubscribe': ('unsubscribe', ['sender', 'recipient',
- 'nodeIdentifier', 'subscriber']),
- 'subscriptions': ('subscriptions', ['sender', 'recipient']),
- 'affiliations': ('affiliations', ['sender', 'recipient']),
- 'create': ('create', ['sender', 'recipient', 'nodeIdentifier']),
- 'getConfigurationOptions': ('getConfigurationOptions', []),
- 'default': ('getDefaultConfiguration',
- ['sender', 'recipient', 'nodeType']),
- 'configureGet': ('getConfiguration', ['sender', 'recipient',
- 'nodeIdentifier']),
- 'configureSet': ('setConfiguration', ['sender', 'recipient',
- 'nodeIdentifier', 'options']),
- 'items': ('items', ['sender', 'recipient', 'nodeIdentifier',
- 'maxItems', 'itemIdentifiers']),
- 'retract': ('retract', ['sender', 'recipient', 'nodeIdentifier',
- 'itemIdentifiers']),
- 'purge': ('purge', ['sender', 'recipient', 'nodeIdentifier']),
- 'delete': ('delete', ['sender', 'recipient', 'nodeIdentifier']),
- }
-
- _request_class = PubSubRequest
-
- hideNodes = False
-
- def __init__(self, resource=None):
- self.resource = resource
- self.discoIdentity = {'category': 'pubsub',
- 'type': 'service',
- 'name': 'Generic Publish-Subscribe Service'}
-
- self.pubSubFeatures = []
-
-
- def connectionMade(self):
- self.xmlstream.addObserver(PUBSUB_REQUEST, self.handleRequest)
-
-
- def getDiscoInfo(self, requestor, target, nodeIdentifier=''):
- def toInfo(nodeInfo):
- if not nodeInfo:
- return
-
- (nodeType, metaData) = nodeInfo['type'], nodeInfo['meta-data']
- info.append(disco.DiscoIdentity('pubsub', nodeType))
- if metaData:
- form = data_form.Form(formType="result",
- formNamespace=NS_PUBSUB_META_DATA)
- form.addField(
- data_form.Field(
- var='pubsub#node_type',
- value=nodeType,
- label='The type of node (collection or leaf)'
- )
- )
-
- for metaDatum in metaData:
- form.addField(data_form.Field.fromDict(metaDatum))
-
- info.append(form)
-
- return
-
- info = []
-
- request = self._request_class('discoInfo')
-
- if self.resource is not None:
- resource = self.resource.locateResource(request)
- identity = resource.discoIdentity
- features = resource.features
- getInfo = resource.getInfo
- else:
- category = self.discoIdentity['category']
- idType = self.discoIdentity['type']
- name = self.discoIdentity['name']
- identity = disco.DiscoIdentity(category, idType, name)
- features = self.pubSubFeatures
- getInfo = self.getNodeInfo
-
- if not nodeIdentifier:
- info.append(identity)
- info.append(disco.DiscoFeature(disco.NS_DISCO_ITEMS))
- info.extend([disco.DiscoFeature("%s#%s" % (NS_PUBSUB, feature))
- for feature in features])
-
- d = defer.maybeDeferred(getInfo, requestor, target, nodeIdentifier or '')
- d.addCallback(toInfo)
- d.addErrback(log.err)
- d.addCallback(lambda _: info)
- return d
-
-
- def _parseNodes(self, nodes, target):
- """parse return values of resource.getNodes
-
- basestring values are used as node
- tuple are unpacked as node, name
- """
- items = []
- for node in nodes:
- if isinstance(node, basestring):
- items.append(disco.DiscoItem(target, node))
- else:
- _node, name = node
- items.append(disco.DiscoItem(target, _node, name))
- return items
-
-
- def getDiscoItems(self, requestor, target, nodeIdentifier=''):
- if self.hideNodes:
- d = defer.succeed([])
- elif self.resource is not None:
- request = self._request_class('discoInfo')
- resource = self.resource.locateResource(request)
- d = resource.getNodes(requestor, target, nodeIdentifier)
- elif nodeIdentifier:
- d = self.getNodes(requestor, target)
- else:
- d = defer.succeed([])
-
- d.addCallback(self._parseNodes, target)
- return d
-
-
- def _onPubSubRequest(self, iq):
- request = self._request_class.fromElement(iq)
- if self.resource is not None:
- resource = self.resource.locateResource(request)
- else:
- resource = self
-
- # Preprocess the request, knowing the handling resource
- try:
- preProcessor = getattr(self, '_preProcess_%s' % request.verb)
- except AttributeError:
- pass
- else:
- request = preProcessor(resource, request)
- if request is None:
- return defer.succeed(None)
-
- # Process the request itself,
- if resource is not self:
- try:
- handler = getattr(resource, request.verb)
- except AttributeError:
- text = "Request verb: %s" % request.verb
- return defer.fail(Unsupported('', text))
-
- d = handler(request)
- else:
- try:
- handlerName, argNames = self._legacyHandlers[request.verb]
- except KeyError:
- text = "Request verb: %s" % request.verb
- return defer.fail(Unsupported('', text))
-
- handler = getattr(self, handlerName)
- args = [getattr(request, arg) for arg in argNames]
- d = handler(*args)
-
- # If needed, translate the result into a response
- try:
- cb = getattr(self, '_toResponse_%s' % request.verb)
- except AttributeError:
- pass
- else:
- d.addCallback(cb, resource, request)
-
- return d
-
-
- def _toResponse_subscribe(self, result, resource, request):
- response = domish.Element((NS_PUBSUB, "pubsub"))
- response.addChild(result.toElement(NS_PUBSUB))
- return response
-
-
- def _toResponse_subscriptions(self, result, resource, request):
- response = domish.Element((NS_PUBSUB, 'pubsub'))
- subscriptions = response.addElement('subscriptions')
- for subscription in result:
- subscriptions.addChild(subscription.toElement(NS_PUBSUB))
- return response
-
-
- def _toResponse_affiliations(self, result, resource, request):
- response = domish.Element((NS_PUBSUB, 'pubsub'))
- affiliations = response.addElement('affiliations')
-
- for nodeIdentifier, affiliation in result:
- item = affiliations.addElement('affiliation')
- item['node'] = nodeIdentifier
- item['affiliation'] = affiliation
-
- return response
-
-
- def _toResponse_create(self, result, resource, request):
- if not request.nodeIdentifier or request.nodeIdentifier != result:
- response = domish.Element((NS_PUBSUB, 'pubsub'))
- create = response.addElement('create')
- create['node'] = result
- return response
- else:
- return None
-
-
- def _formFromConfiguration(self, resource, values):
- fieldDefs = resource.getConfigurationOptions()
- form = data_form.Form(formType="form",
- formNamespace=NS_PUBSUB_NODE_CONFIG)
- form.makeFields(values, fieldDefs)
- return form
-
-
- def _checkConfiguration(self, resource, form):
- fieldDefs = resource.getConfigurationOptions()
- form.typeCheck(fieldDefs, filterUnknown=True)
-
-
- def _preProcess_create(self, resource, request):
- if request.options:
- self._checkConfiguration(resource, request.options)
- return request
-
-
- def _preProcess_default(self, resource, request):
- if request.nodeType not in ('leaf', 'collection'):
- raise error.StanzaError('not-acceptable')
- else:
- return request
-
-
- def _toResponse_default(self, options, resource, request):
- response = domish.Element((NS_PUBSUB_OWNER, "pubsub"))
- default = response.addElement("default")
- form = self._formFromConfiguration(resource, options)
- default.addChild(form.toElement())
- return response
-
-
- def _toResponse_configureGet(self, options, resource, request):
- response = domish.Element((NS_PUBSUB_OWNER, "pubsub"))
- configure = response.addElement("configure")
- form = self._formFromConfiguration(resource, options)
- configure.addChild(form.toElement())
-
- if request.nodeIdentifier:
- configure["node"] = request.nodeIdentifier
-
- return response
-
-
- def _preProcess_configureSet(self, resource, request):
- if request.options.formType == 'cancel':
- return None
- else:
- self._checkConfiguration(resource, request.options)
- return request
-
-
- def _toResponse_items(self, result, resource, request):
- response = domish.Element((NS_PUBSUB, 'pubsub'))
- items = response.addElement('items')
- items["node"] = request.nodeIdentifier
-
- for item in result:
- item.uri = NS_PUBSUB
- items.addChild(item)
-
- return response
-
-
- def _createNotification(self, eventType, service, nodeIdentifier,
- subscriber, subscriptions=None):
- headers = []
-
- if subscriptions:
- for subscription in subscriptions:
- if nodeIdentifier != subscription.nodeIdentifier:
- headers.append(('Collection', subscription.nodeIdentifier))
-
- message = domish.Element((None, "message"))
- message["from"] = service.full()
- message["to"] = subscriber.full()
- event = message.addElement((NS_PUBSUB_EVENT, "event"))
-
- element = event.addElement(eventType)
- element["node"] = nodeIdentifier
-
- if headers:
- message.addChild(shim.Headers(headers))
-
- return message
-
-
- def _toResponse_affiliationsGet(self, result, resource, request):
- response = domish.Element((NS_PUBSUB_OWNER, 'pubsub'))
- affiliations = response.addElement('affiliations')
-
- if request.nodeIdentifier:
- affiliations['node'] = request.nodeIdentifier
-
- for entity, affiliation in result.iteritems():
- item = affiliations.addElement('affiliation')
- item['jid'] = entity.full()
- item['affiliation'] = affiliation
-
- return response
-
-
- def _toResponse_subscriptionsGet(self, result, resource, request):
- response = domish.Element((NS_PUBSUB, 'pubsub'))
- subscriptions = response.addElement('subscriptions')
- subscriptions['node'] = request.nodeIdentifier
- for subscription in result:
- subscription_element = subscription.toElement(NS_PUBSUB)
- del subscription_element['node']
- subscriptions.addChild(subscription_element)
- return response
-
-
- # public methods
-
- def notifyPublish(self, service, nodeIdentifier, notifications):
- for subscriber, subscriptions, items in notifications:
- message = self._createNotification('items', service,
- nodeIdentifier, subscriber,
- subscriptions)
- for item in items:
- item.uri = NS_PUBSUB_EVENT
- message.event.items.addChild(item)
- self.send(message)
-
-
- def notifyRetract(self, service, nodeIdentifier, notifications):
- for subscriber, subscriptions, items in notifications:
- message = self._createNotification('items', service,
- nodeIdentifier, subscriber,
- subscriptions)
- for item in items:
- retract = domish.Element((None, "retract"))
- retract['id'] = item['id']
- message.event.items.addChild(retract)
- self.send(message)
-
-
- def notifyDelete(self, service, nodeIdentifier, subscribers,
- redirectURI=None):
- for subscriber in subscribers:
- message = self._createNotification('delete', service,
- nodeIdentifier,
- subscriber)
- if redirectURI:
- redirect = message.event.delete.addElement('redirect')
- redirect['uri'] = redirectURI
- self.send(message)
-
-
- def getNodeInfo(self, requestor, service, nodeIdentifier):
- return None
-
-
- def getNodes(self, requestor, service):
- return []
-
-
- def publish(self, requestor, service, nodeIdentifier, items):
- raise Unsupported('publish')
-
-
- def subscribe(self, requestor, service, nodeIdentifier, subscriber):
- raise Unsupported('subscribe')
-
-
- def unsubscribe(self, requestor, service, nodeIdentifier, subscriber):
- raise Unsupported('subscribe')
-
-
- def subscriptions(self, requestor, service):
- raise Unsupported('retrieve-subscriptions')
-
-
- def affiliations(self, requestor, service):
- raise Unsupported('retrieve-affiliations')
-
-
- def create(self, requestor, service, nodeIdentifier):
- raise Unsupported('create-nodes')
-
-
- def getConfigurationOptions(self):
- return {}
-
-
- def getDefaultConfiguration(self, requestor, service, nodeType):
- raise Unsupported('retrieve-default')
-
-
- def getConfiguration(self, requestor, service, nodeIdentifier):
- raise Unsupported('config-node')
-
-
- def setConfiguration(self, requestor, service, nodeIdentifier, options):
- raise Unsupported('config-node')
-
-
- def items(self, requestor, service, nodeIdentifier, maxItems,
- itemIdentifiers):
- raise Unsupported('retrieve-items')
-
-
- def retract(self, requestor, service, nodeIdentifier, itemIdentifiers):
- raise Unsupported('retract-items')
-
-
- def purge(self, requestor, service, nodeIdentifier):
- raise Unsupported('purge-nodes')
-
-
- def delete(self, requestor, service, nodeIdentifier):
- raise Unsupported('delete-nodes')
-
-
-
-class PubSubResource(object):
-
- implements(IPubSubResource)
-
- features = []
- discoIdentity = disco.DiscoIdentity('pubsub',
- 'service',
- 'Publish-Subscribe Service')
-
-
- def locateResource(self, request):
- return self
-
-
- def getInfo(self, requestor, service, nodeIdentifier):
- return defer.succeed(None)
-
-
- def getNodes(self, requestor, service, nodeIdentifier):
- return defer.succeed([])
-
-
- def getConfigurationOptions(self):
- return {}
-
-
- def publish(self, request):
- return defer.fail(Unsupported('publish'))
-
-
- def subscribe(self, request):
- return defer.fail(Unsupported('subscribe'))
-
-
- def unsubscribe(self, request):
- return defer.fail(Unsupported('subscribe'))
-
-
- def subscriptions(self, request):
- return defer.fail(Unsupported('retrieve-subscriptions'))
-
-
- def affiliations(self, request):
- return defer.fail(Unsupported('retrieve-affiliations'))
-
-
- def create(self, request):
- return defer.fail(Unsupported('create-nodes'))
-
-
- def default(self, request):
- return defer.fail(Unsupported('retrieve-default'))
-
-
- def configureGet(self, request):
- return defer.fail(Unsupported('config-node'))
-
-
- def configureSet(self, request):
- return defer.fail(Unsupported('config-node'))
-
-
- def items(self, request):
- return defer.fail(Unsupported('retrieve-items'))
-
-
- def retract(self, request):
- return defer.fail(Unsupported('retract-items'))
-
-
- def purge(self, request):
- return defer.fail(Unsupported('purge-nodes'))
-
-
- def delete(self, request):
- return defer.fail(Unsupported('delete-nodes'))
-
-
- def affiliationsGet(self, request):
- return defer.fail(Unsupported('retrieve-affiliations'))
-
-
- def affiliationsSet(self, request):
- return defer.fail(Unsupported('modify-affiliations'))
-
-
- def subscriptionsGet(self, request):
- return defer.fail(Unsupported('manage-subscriptions'))
-
-
- def subscriptionsSet(self, request):
- return defer.fail(Unsupported('manage-subscriptions'))
diff --git a/src/tmp/wokkel/rsm.py b/src/tmp/wokkel/rsm.py
deleted file mode 100644
index d017f598..00000000
--- a/src/tmp/wokkel/rsm.py
+++ /dev/null
@@ -1,425 +0,0 @@
-# -*- coding: utf-8 -*-
-# -*- test-case-name: wokkel.test.test_rsm -*-
-#
-# SàT Wokkel extension for Result Set Management (XEP-0059)
-# Copyright (C) 2015 Adien Cossa (souliane@mailoo.org)
-
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Affero General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU Affero General Public License for more details.
-
-# You should have received a copy of the GNU Affero General Public License
-# along with this program. If not, see .
-
-"""
-XMPP Result Set Management protocol.
-
-This protocol is specified in
-U{XEP-0059}.
-"""
-
-from twisted.words.xish import domish
-from twisted.words.protocols.jabber import error
-
-import pubsub
-import copy
-
-
-NS_RSM = 'http://jabber.org/protocol/rsm'
-
-
-class RSMError(error.StanzaError):
- """
- RSM error.
- """
- def __init__(self, text=None):
- error.StanzaError.__init__(self, 'bad-request', text=text)
-
-
-class RSMNotFoundError(Exception):
- """
- An expected RSM element has not been found.
- """
-
-
-class RSMRequest(object):
- """
- A Result Set Management request.
-
- @ivar max_: limit on the number of retrieved items.
- @itype max_: C{int} or C{unicode}
-
- @ivar index: starting index of the requested page.
- @itype index: C{int} or C{unicode} or C{None}
-
- @ivar after: ID of the element immediately preceding the page.
- @itype after: C{unicode}
-
- @ivar before: ID of the element immediately following the page.
- @itype before: C{unicode}
- """
-
- def __init__(self, max_=10, after=None, before=None, index=None):
- self.max = int(max_)
-
- if index is not None:
- assert after is None and before is None
- index = int(index)
- self.index = index
-
- if after is not None:
- assert before is None
- assert isinstance(after, basestring)
- self.after = after
-
- if before is not None:
- assert isinstance(before, basestring)
- self.before = before
-
- def __str__(self):
- return "RSM Request: max={0.max} after={0.after} before={0.before} index={0.index}".format(self)
-
- @classmethod
- def fromElement(cls, element):
- """Parse the given request element.
-
- @param element: request containing a set element, or set element itself.
- @type element: L{domish.Element}
-
- @return: RSMRequest instance.
- @rtype: L{RSMRequest}
- """
-
- if element.name == 'set' and element.uri == NS_RSM:
- set_elt = element
- else:
- try:
- set_elt = element.elements(NS_RSM, 'set').next()
- except StopIteration:
- raise RSMNotFoundError()
-
- try:
- before_elt = set_elt.elements(NS_RSM, 'before').next()
- except StopIteration:
- before = None
- else:
- before = unicode(before_elt)
-
- try:
- after_elt = set_elt.elements(NS_RSM, 'after').next()
- except StopIteration:
- after = None
- else:
- after = unicode(after_elt)
- if not after:
- raise RSMError(" element can't be empty in RSM request")
-
- try:
- max_elt = set_elt.elements(NS_RSM, 'max').next()
- except StopIteration:
- # FIXME: even if it doesn't make a lot of sense without it
- # element is not mandatory in XEP-0059
- raise RSMError("RSM request is missing its 'max' element")
- else:
- try:
- max_ = int(unicode(max_elt))
- except ValueError:
- raise RSMError("bad value for 'max' element")
-
- try:
- index_elt = set_elt.elements(NS_RSM, 'index').next()
- except StopIteration:
- index = None
- else:
- try:
- index = int(unicode(index_elt))
- except ValueError:
- raise RSMError("bad value for 'index' element")
-
- return RSMRequest(max_, after, before, index)
-
- def toElement(self):
- """
- Return the DOM representation of this RSM request.
-
- @rtype: L{domish.Element}
- """
- set_elt = domish.Element((NS_RSM, 'set'))
- set_elt.addElement('max', content=unicode(self.max))
-
- if self.index is not None:
- set_elt.addElement('index', content=unicode(self.index))
-
- if self.before is not None:
- if self.before == '': # request the last page
- set_elt.addElement('before')
- else:
- set_elt.addElement('before', content=self.before)
-
- if self.after is not None:
- set_elt.addElement('after', content=self.after)
-
- return set_elt
-
- def render(self, element):
- """Embed the DOM representation of this RSM request in the given element.
-
- @param element: Element to contain the RSM request.
- @type element: L{domish.Element}
-
- @return: RSM request element.
- @rtype: L{domish.Element}
- """
- set_elt = self.toElement()
- element.addChild(set_elt)
-
- return set_elt
-
-
-class RSMResponse(object):
- """
- A Result Set Management response.
-
- @ivar first: ID of the first element of the returned page.
- @itype first: C{unicode}
-
- @ivar last: ID of the last element of the returned page.
- @itype last: C{unicode}
-
- @ivar index: starting index of the returned page.
- @itype index: C{int}
-
- @ivar count: total number of items.
- @itype count: C{int}
-
- """
-
- def __init__(self, first=None, last=None, index=None, count=None):
- if first is None:
- assert last is None and index is None
- if last is None:
- assert first is None
- self.first = first
- self.last = last
- if count is not None:
- self.count = int(count)
- else:
- self.count = None
- if index is not None:
- self.index = int(index)
- else:
- self.index = None
-
- def __str__(self):
- return "RSM Request: first={0.first} last={0.last} index={0.index} count={0.count}".format(self)
-
- @classmethod
- def fromElement(cls, element):
- """Parse the given response element.
-
- @param element: response element.
- @type element: L{domish.Element}
-
- @return: RSMResponse instance.
- @rtype: L{RSMResponse}
- """
- try:
- set_elt = element.elements(NS_RSM, 'set').next()
- except StopIteration:
- raise RSMNotFoundError()
-
- try:
- first_elt = set_elt.elements(NS_RSM, 'first').next()
- except StopIteration:
- first = None
- index = None
- else:
- first = unicode(first_elt)
- try:
- index = int(first_elt['index'])
- except KeyError:
- index = None
- except ValueError:
- raise RSMError("bad index in RSM response")
-
- try:
- last_elt = set_elt.elements(NS_RSM, 'last').next()
- except StopIteration:
- if first is not None:
- raise RSMError("RSM response is missing its 'last' element")
- else:
- last = None
- else:
- if first is None:
- raise RSMError("RSM response is missing its 'first' element")
- last = unicode(last_elt)
-
- try:
- count_elt = set_elt.elements(NS_RSM, 'count').next()
- except StopIteration:
- count = None
- else:
- try:
- count = int(unicode(count_elt))
- except ValueError:
- raise RSMError("invalid count in RSM response")
-
- return RSMResponse(first, last, index, count)
-
- def toElement(self):
- """
- Return the DOM representation of this RSM request.
-
- @rtype: L{domish.Element}
- """
- set_elt = domish.Element((NS_RSM, 'set'))
- if self.first is not None:
- first_elt = set_elt.addElement('first', content=self.first)
- if self.index is not None:
- first_elt['index'] = unicode(self.index)
-
- set_elt.addElement('last', content=self.last)
-
- if self.count is not None:
- set_elt.addElement('count', content=unicode(self.count))
-
- return set_elt
-
- def render(self, element):
- """Embed the DOM representation of this RSM response in the given element.
-
- @param element: Element to contain the RSM response.
- @type element: L{domish.Element}
-
- @return: RSM request element.
- @rtype: L{domish.Element}
- """
- set_elt = self.toElement()
- element.addChild(set_elt)
- return set_elt
-
- def toDict(self):
- """Return a dict representation of the object.
-
- @return: a dict of strings.
- @rtype: C{dict} binding C{unicode} to C{unicode}
- """
- result = {}
- for attr in ('first', 'last', 'index', 'count'):
- value = getattr(self, attr)
- if value is not None:
- result[attr] = unicode(value)
- return result
-
-
-class PubSubRequest(pubsub.PubSubRequest):
- """PubSubRequest extension to handle RSM.
-
- @ivar rsm: RSM request instance.
- @type rsm: L{RSMRequest}
- """
-
- rsm = None
- _parameters = copy.deepcopy(pubsub.PubSubRequest._parameters)
- _parameters['items'].append('rsm')
-
- def _parse_rsm(self, verbElement):
- try:
- self.rsm = RSMRequest.fromElement(verbElement.parent)
- except RSMNotFoundError:
- self.rsm = None
-
- def _render_rsm(self, verbElement):
- if self.rsm:
- self.rsm.render(verbElement.parent)
-
-
-class PubSubClient(pubsub.PubSubClient):
- """PubSubClient extension to handle RSM."""
-
- _request_class = PubSubRequest
-
- def items(self, service, nodeIdentifier, maxItems=None, itemIdentifiers=None,
- subscriptionIdentifier=None, sender=None, rsm_request=None):
- """
- Retrieve previously published items from a publish subscribe node.
-
- @param service: The publish subscribe service that keeps the node.
- @type service: L{JID}
-
- @param nodeIdentifier: The identifier of the node.
- @type nodeIdentifier: C{unicode}
-
- @param maxItems: Optional limit on the number of retrieved items.
- @type maxItems: C{int}
-
- @param itemIdentifiers: Identifiers of the items to be retrieved.
- @type itemIdentifiers: C{set}
-
- @param subscriptionIdentifier: Optional subscription identifier. In
- case the node has been subscribed to multiple times, this narrows
- the results to the specific subscription.
- @type subscriptionIdentifier: C{unicode}
-
- @param ext_data: extension data.
- @type ext_data: L{dict}
-
- @return: a Deferred that fires a C{list} of C{tuple} of L{domish.Element}, L{RSMResponse}.
- @rtype: L{defer.Deferred}
- """
- # XXX: we have to copy initial method instead of calling it,
- # as original cb remove all non item elements
- request = self._request_class('items')
- request.recipient = service
- request.nodeIdentifier = nodeIdentifier
- if maxItems:
- request.maxItems = str(int(maxItems))
- request.subscriptionIdentifier = subscriptionIdentifier
- request.sender = sender
- request.itemIdentifiers = itemIdentifiers
- request.rsm = rsm_request
-
- def cb(iq):
- items = []
- pubsub_elt = iq.pubsub
- if pubsub_elt.items:
- for element in pubsub_elt.items.elements(pubsub.NS_PUBSUB, 'item'):
- items.append(element)
-
- try:
- rsm_response = RSMResponse.fromElement(pubsub_elt)
- except RSMNotFoundError:
- rsm_response = None
- return (items, rsm_response)
-
- d = request.send(self.xmlstream)
- d.addCallback(cb)
- return d
-
-
-class PubSubService(pubsub.PubSubService):
- """PubSubService extension to handle RSM."""
-
- _request_class = PubSubRequest
-
- def _toResponse_items(self, elts, resource, request):
- # default method only manage elements
- # but we need to add RSM set element
- rsm_elt = None
- for idx, elt in enumerate(reversed(elts)):
- if elt.name == "set" and elt.uri == NS_RSM:
- rsm_elt = elts.pop(-1-idx)
- break
-
- response = pubsub.PubSubService._toResponse_items(self, elts,
- resource, request)
- if rsm_elt is not None:
- response.addChild(rsm_elt)
-
- return response
diff --git a/src/tmp/wokkel/test/__init__.py b/src/tmp/wokkel/test/__init__.py
deleted file mode 100644
index e69de29b..00000000
diff --git a/src/tmp/wokkel/test/test_pubsub.py b/src/tmp/wokkel/test/test_pubsub.py
deleted file mode 100755
index 275e16a0..00000000
--- a/src/tmp/wokkel/test/test_pubsub.py
+++ /dev/null
@@ -1,4218 +0,0 @@
-# Copyright (c) Ralph Meijer.
-# See LICENSE for details.
-
-"""
-Tests for L{wokkel.pubsub}
-"""
-
-from zope.interface import verify
-
-from twisted.trial import unittest
-from twisted.internet import defer
-from twisted.words.xish import domish
-from twisted.words.protocols.jabber import error
-from twisted.words.protocols.jabber.jid import JID
-from twisted.words.protocols.jabber.xmlstream import toResponse
-
-from wokkel import data_form, disco, iwokkel, shim
-from wokkel.generic import parseXml
-from wokkel.test.helpers import TestableRequestHandlerMixin, XmlStreamStub
-
-from sat.tmp.wokkel import pubsub
-
-NS_PUBSUB = 'http://jabber.org/protocol/pubsub'
-NS_PUBSUB_NODE_CONFIG = 'http://jabber.org/protocol/pubsub#node_config'
-NS_PUBSUB_ERRORS = 'http://jabber.org/protocol/pubsub#errors'
-NS_PUBSUB_EVENT = 'http://jabber.org/protocol/pubsub#event'
-NS_PUBSUB_OWNER = 'http://jabber.org/protocol/pubsub#owner'
-NS_PUBSUB_META_DATA = 'http://jabber.org/protocol/pubsub#meta-data'
-NS_PUBSUB_SUBSCRIBE_OPTIONS = 'http://jabber.org/protocol/pubsub#subscribe_options'
-
-def calledAsync(fn):
- """
- Function wrapper that fires a deferred upon calling the given function.
- """
- d = defer.Deferred()
-
- def func(*args, **kwargs):
- try:
- result = fn(*args, **kwargs)
- except:
- d.errback()
- else:
- d.callback(result)
-
- return d, func
-
-
-class SubscriptionTest(unittest.TestCase):
- """
- Tests for L{pubsub.Subscription}.
- """
-
- def test_fromElement(self):
- """
- fromElement parses a subscription from XML DOM.
- """
- xml = """
-
- """
- subscription = pubsub.Subscription.fromElement(parseXml(xml))
- self.assertEqual('test', subscription.nodeIdentifier)
- self.assertEqual(JID('user@example.org/Home'), subscription.subscriber)
- self.assertEqual('pending', subscription.state)
- self.assertIdentical(None, subscription.subscriptionIdentifier)
-
-
- def test_fromElementWithSubscriptionIdentifier(self):
- """
- A subscription identifier in the subscription should be parsed, too.
- """
- xml = """
-
- """
- subscription = pubsub.Subscription.fromElement(parseXml(xml))
- self.assertEqual('1234', subscription.subscriptionIdentifier)
-
-
- def test_toElement(self):
- """
- Rendering a Subscription should yield the proper attributes.
- """
- subscription = pubsub.Subscription('test',
- JID('user@example.org/Home'),
- 'pending')
- element = subscription.toElement()
- self.assertEqual('subscription', element.name)
- self.assertEqual(None, element.uri)
- self.assertEqual('test', element.getAttribute('node'))
- self.assertEqual('user@example.org/Home', element.getAttribute('jid'))
- self.assertEqual('pending', element.getAttribute('subscription'))
- self.assertFalse(element.hasAttribute('subid'))
-
-
- def test_toElementEmptyNodeIdentifier(self):
- """
- The empty node identifier should not yield a node attribute.
- """
- subscription = pubsub.Subscription('',
- JID('user@example.org/Home'),
- 'pending')
- element = subscription.toElement()
- self.assertFalse(element.hasAttribute('node'))
-
-
- def test_toElementWithSubscriptionIdentifier(self):
- """
- The subscription identifier, if set, is in the subid attribute.
- """
- subscription = pubsub.Subscription('test',
- JID('user@example.org/Home'),
- 'pending',
- subscriptionIdentifier='1234')
- element = subscription.toElement()
- self.assertEqual('1234', element.getAttribute('subid'))
-
-
-
-class PubSubClientTest(unittest.TestCase):
- timeout = 2
-
- def setUp(self):
- self.stub = XmlStreamStub()
- self.protocol = pubsub.PubSubClient()
- self.protocol.xmlstream = self.stub.xmlstream
- self.protocol.connectionInitialized()
-
-
- def test_interface(self):
- """
- Do instances of L{pubsub.PubSubClient} provide L{iwokkel.IPubSubClient}?
- """
- verify.verifyObject(iwokkel.IPubSubClient, self.protocol)
-
-
- def test_eventItems(self):
- """
- Test receiving an items event resulting in a call to itemsReceived.
- """
- message = domish.Element((None, 'message'))
- message['from'] = 'pubsub.example.org'
- message['to'] = 'user@example.org/home'
- event = message.addElement((NS_PUBSUB_EVENT, 'event'))
- items = event.addElement('items')
- items['node'] = 'test'
- item1 = items.addElement('item')
- item1['id'] = 'item1'
- item2 = items.addElement('retract')
- item2['id'] = 'item2'
- item3 = items.addElement('item')
- item3['id'] = 'item3'
-
- def itemsReceived(event):
- self.assertEquals(JID('user@example.org/home'), event.recipient)
- self.assertEquals(JID('pubsub.example.org'), event.sender)
- self.assertEquals('test', event.nodeIdentifier)
- self.assertEquals([item1, item2, item3], event.items)
-
- d, self.protocol.itemsReceived = calledAsync(itemsReceived)
- self.stub.send(message)
- return d
-
-
- def test_eventItemsCollection(self):
- """
- Test receiving an items event resulting in a call to itemsReceived.
- """
- message = domish.Element((None, 'message'))
- message['from'] = 'pubsub.example.org'
- message['to'] = 'user@example.org/home'
- event = message.addElement((NS_PUBSUB_EVENT, 'event'))
- items = event.addElement('items')
- items['node'] = 'test'
-
- headers = shim.Headers([('Collection', 'collection')])
- message.addChild(headers)
-
- def itemsReceived(event):
- self.assertEquals(JID('user@example.org/home'), event.recipient)
- self.assertEquals(JID('pubsub.example.org'), event.sender)
- self.assertEquals('test', event.nodeIdentifier)
- self.assertEquals({'Collection': ['collection']}, event.headers)
-
- d, self.protocol.itemsReceived = calledAsync(itemsReceived)
- self.stub.send(message)
- return d
-
-
- def test_eventItemsError(self):
- """
- An error message with embedded event should not be handled.
-
- This test uses an items event, which should not result in itemsReceived
- being called. In general message.handled should be False.
- """
- message = domish.Element((None, 'message'))
- message['from'] = 'pubsub.example.org'
- message['to'] = 'user@example.org/home'
- message['type'] = 'error'
- event = message.addElement((NS_PUBSUB_EVENT, 'event'))
- items = event.addElement('items')
- items['node'] = 'test'
-
- class UnexpectedCall(Exception):
- pass
-
- def itemsReceived(event):
- raise UnexpectedCall("Unexpected call to itemsReceived")
-
- self.protocol.itemsReceived = itemsReceived
- self.stub.send(message)
- self.assertFalse(message.handled)
-
-
- def test_eventDelete(self):
- """
- Test receiving a delete event resulting in a call to deleteReceived.
- """
- message = domish.Element((None, 'message'))
- message['from'] = 'pubsub.example.org'
- message['to'] = 'user@example.org/home'
- event = message.addElement((NS_PUBSUB_EVENT, 'event'))
- delete = event.addElement('delete')
- delete['node'] = 'test'
-
- def deleteReceived(event):
- self.assertEquals(JID('user@example.org/home'), event.recipient)
- self.assertEquals(JID('pubsub.example.org'), event.sender)
- self.assertEquals('test', event.nodeIdentifier)
-
- d, self.protocol.deleteReceived = calledAsync(deleteReceived)
- self.stub.send(message)
- return d
-
-
- def test_eventDeleteRedirect(self):
- """
- Test receiving a delete event with a redirect URI.
- """
- message = domish.Element((None, 'message'))
- message['from'] = 'pubsub.example.org'
- message['to'] = 'user@example.org/home'
- event = message.addElement((NS_PUBSUB_EVENT, 'event'))
- delete = event.addElement('delete')
- delete['node'] = 'test'
- uri = 'xmpp:pubsub.example.org?;node=test2'
- delete.addElement('redirect')['uri'] = uri
-
- def deleteReceived(event):
- self.assertEquals(JID('user@example.org/home'), event.recipient)
- self.assertEquals(JID('pubsub.example.org'), event.sender)
- self.assertEquals('test', event.nodeIdentifier)
- self.assertEquals(uri, event.redirectURI)
-
- d, self.protocol.deleteReceived = calledAsync(deleteReceived)
- self.stub.send(message)
- return d
-
-
- def test_event_purge(self):
- """
- Test receiving a purge event resulting in a call to purgeReceived.
- """
- message = domish.Element((None, 'message'))
- message['from'] = 'pubsub.example.org'
- message['to'] = 'user@example.org/home'
- event = message.addElement((NS_PUBSUB_EVENT, 'event'))
- items = event.addElement('purge')
- items['node'] = 'test'
-
- def purgeReceived(event):
- self.assertEquals(JID('user@example.org/home'), event.recipient)
- self.assertEquals(JID('pubsub.example.org'), event.sender)
- self.assertEquals('test', event.nodeIdentifier)
-
- d, self.protocol.purgeReceived = calledAsync(purgeReceived)
- self.stub.send(message)
- return d
-
-
- def test_createNode(self):
- """
- Test sending create request.
- """
-
- def cb(nodeIdentifier):
- self.assertEquals('test', nodeIdentifier)
-
- d = self.protocol.createNode(JID('pubsub.example.org'), 'test')
- d.addCallback(cb)
-
- iq = self.stub.output[-1]
- self.assertEquals('pubsub.example.org', iq.getAttribute('to'))
- self.assertEquals('set', iq.getAttribute('type'))
- self.assertEquals('pubsub', iq.pubsub.name)
- self.assertEquals(NS_PUBSUB, iq.pubsub.uri)
- children = list(domish.generateElementsQNamed(iq.pubsub.children,
- 'create', NS_PUBSUB))
- self.assertEquals(1, len(children))
- child = children[0]
- self.assertEquals('test', child['node'])
-
- response = toResponse(iq, 'result')
- self.stub.send(response)
- return d
-
-
- def test_createNodeInstant(self):
- """
- Test sending create request resulting in an instant node.
- """
-
- def cb(nodeIdentifier):
- self.assertEquals('test', nodeIdentifier)
-
- d = self.protocol.createNode(JID('pubsub.example.org'))
- d.addCallback(cb)
-
- iq = self.stub.output[-1]
- children = list(domish.generateElementsQNamed(iq.pubsub.children,
- 'create', NS_PUBSUB))
- child = children[0]
- self.assertFalse(child.hasAttribute('node'))
-
- response = toResponse(iq, 'result')
- command = response.addElement((NS_PUBSUB, 'pubsub'))
- create = command.addElement('create')
- create['node'] = 'test'
- self.stub.send(response)
- return d
-
-
- def test_createNodeRenamed(self):
- """
- Test sending create request resulting in renamed node.
- """
-
- def cb(nodeIdentifier):
- self.assertEquals('test2', nodeIdentifier)
-
- d = self.protocol.createNode(JID('pubsub.example.org'), 'test')
- d.addCallback(cb)
-
- iq = self.stub.output[-1]
- children = list(domish.generateElementsQNamed(iq.pubsub.children,
- 'create', NS_PUBSUB))
- child = children[0]
- self.assertEquals('test', child['node'])
-
- response = toResponse(iq, 'result')
- command = response.addElement((NS_PUBSUB, 'pubsub'))
- create = command.addElement('create')
- create['node'] = 'test2'
- self.stub.send(response)
- return d
-
-
- def test_createNodeWithSender(self):
- """
- Test sending create request from a specific JID.
- """
-
- d = self.protocol.createNode(JID('pubsub.example.org'), 'test',
- sender=JID('user@example.org'))
-
- iq = self.stub.output[-1]
- self.assertEquals('user@example.org', iq['from'])
-
- response = toResponse(iq, 'result')
- self.stub.send(response)
- return d
-
-
- def test_createNodeWithConfig(self):
- """
- Test sending create request with configuration options
- """
-
- options = {
- 'pubsub#title': 'Princely Musings (Atom)',
- 'pubsub#deliver_payloads': True,
- 'pubsub#persist_items': '1',
- 'pubsub#max_items': '10',
- 'pubsub#access_model': 'open',
- 'pubsub#type': 'http://www.w3.org/2005/Atom',
- }
-
- d = self.protocol.createNode(JID('pubsub.example.org'), 'test',
- sender=JID('user@example.org'),
- options=options)
-
- iq = self.stub.output[-1]
-
- # check if there is exactly one configure element
- children = list(domish.generateElementsQNamed(iq.pubsub.children,
- 'configure', NS_PUBSUB))
- self.assertEqual(1, len(children))
-
- # check that it has a configuration form
- form = data_form.findForm(children[0], NS_PUBSUB_NODE_CONFIG)
- self.assertEqual('submit', form.formType)
-
-
- response = toResponse(iq, 'result')
- self.stub.send(response)
- return d
-
-
- def test_deleteNode(self):
- """
- Test sending delete request.
- """
-
- d = self.protocol.deleteNode(JID('pubsub.example.org'), 'test')
-
- iq = self.stub.output[-1]
- self.assertEquals('pubsub.example.org', iq.getAttribute('to'))
- self.assertEquals('set', iq.getAttribute('type'))
- self.assertEquals('pubsub', iq.pubsub.name)
- self.assertEquals(NS_PUBSUB_OWNER, iq.pubsub.uri)
- children = list(domish.generateElementsQNamed(iq.pubsub.children,
- 'delete', NS_PUBSUB_OWNER))
- self.assertEquals(1, len(children))
- child = children[0]
- self.assertEquals('test', child['node'])
-
- response = toResponse(iq, 'result')
- self.stub.send(response)
- return d
-
-
- def test_deleteNodeWithSender(self):
- """
- Test sending delete request.
- """
-
- d = self.protocol.deleteNode(JID('pubsub.example.org'), 'test',
- sender=JID('user@example.org'))
-
- iq = self.stub.output[-1]
- self.assertEquals('user@example.org', iq['from'])
-
- response = toResponse(iq, 'result')
- self.stub.send(response)
- return d
-
-
- def test_publish(self):
- """
- Test sending publish request.
- """
-
- item = pubsub.Item()
- d = self.protocol.publish(JID('pubsub.example.org'), 'test', [item])
-
- iq = self.stub.output[-1]
- self.assertEquals('pubsub.example.org', iq.getAttribute('to'))
- self.assertEquals('set', iq.getAttribute('type'))
- self.assertEquals('pubsub', iq.pubsub.name)
- self.assertEquals(NS_PUBSUB, iq.pubsub.uri)
- children = list(domish.generateElementsQNamed(iq.pubsub.children,
- 'publish', NS_PUBSUB))
- self.assertEquals(1, len(children))
- child = children[0]
- self.assertEquals('test', child['node'])
- items = list(domish.generateElementsQNamed(child.children,
- 'item', NS_PUBSUB))
- self.assertEquals(1, len(items))
- self.assertIdentical(item, items[0])
-
- response = toResponse(iq, 'result')
- self.stub.send(response)
- return d
-
-
- def test_publishNoItems(self):
- """
- Test sending publish request without items.
- """
-
- d = self.protocol.publish(JID('pubsub.example.org'), 'test')
-
- iq = self.stub.output[-1]
- self.assertEquals('pubsub.example.org', iq.getAttribute('to'))
- self.assertEquals('set', iq.getAttribute('type'))
- self.assertEquals('pubsub', iq.pubsub.name)
- self.assertEquals(NS_PUBSUB, iq.pubsub.uri)
- children = list(domish.generateElementsQNamed(iq.pubsub.children,
- 'publish', NS_PUBSUB))
- self.assertEquals(1, len(children))
- child = children[0]
- self.assertEquals('test', child['node'])
-
- response = toResponse(iq, 'result')
- self.stub.send(response)
- return d
-
-
- def test_publishWithSender(self):
- """
- Test sending publish request from a specific JID.
- """
-
- item = pubsub.Item()
- d = self.protocol.publish(JID('pubsub.example.org'), 'test', [item],
- JID('user@example.org'))
-
- iq = self.stub.output[-1]
- self.assertEquals('user@example.org', iq['from'])
-
- response = toResponse(iq, 'result')
- self.stub.send(response)
- return d
-
-
- def test_subscribe(self):
- """
- Test sending subscription request.
- """
- d = self.protocol.subscribe(JID('pubsub.example.org'), 'test',
- JID('user@example.org'))
-
- iq = self.stub.output[-1]
- self.assertEquals('pubsub.example.org', iq.getAttribute('to'))
- self.assertEquals('set', iq.getAttribute('type'))
- self.assertEquals('pubsub', iq.pubsub.name)
- self.assertEquals(NS_PUBSUB, iq.pubsub.uri)
- children = list(domish.generateElementsQNamed(iq.pubsub.children,
- 'subscribe', NS_PUBSUB))
- self.assertEquals(1, len(children))
- child = children[0]
- self.assertEquals('test', child['node'])
- self.assertEquals('user@example.org', child['jid'])
-
- response = toResponse(iq, 'result')
- pubsub = response.addElement((NS_PUBSUB, 'pubsub'))
- subscription = pubsub.addElement('subscription')
- subscription['node'] = 'test'
- subscription['jid'] = 'user@example.org'
- subscription['subscription'] = 'subscribed'
- self.stub.send(response)
- return d
-
-
- def test_subscribeReturnsSubscription(self):
- """
- A successful subscription should return a Subscription instance.
- """
- def cb(subscription):
- self.assertEqual(JID('user@example.org'), subscription.subscriber)
-
- d = self.protocol.subscribe(JID('pubsub.example.org'), 'test',
- JID('user@example.org'))
- d.addCallback(cb)
-
- iq = self.stub.output[-1]
-
- response = toResponse(iq, 'result')
- pubsub = response.addElement((NS_PUBSUB, 'pubsub'))
- subscription = pubsub.addElement('subscription')
- subscription['node'] = 'test'
- subscription['jid'] = 'user@example.org'
- subscription['subscription'] = 'subscribed'
- self.stub.send(response)
- return d
-
-
- def test_subscribePending(self):
- """
- Test sending subscription request that results in a pending
- subscription.
- """
- d = self.protocol.subscribe(JID('pubsub.example.org'), 'test',
- JID('user@example.org'))
-
- iq = self.stub.output[-1]
- response = toResponse(iq, 'result')
- command = response.addElement((NS_PUBSUB, 'pubsub'))
- subscription = command.addElement('subscription')
- subscription['node'] = 'test'
- subscription['jid'] = 'user@example.org'
- subscription['subscription'] = 'pending'
- self.stub.send(response)
- self.assertFailure(d, pubsub.SubscriptionPending)
- return d
-
-
- def test_subscribeUnconfigured(self):
- """
- Test sending subscription request that results in an unconfigured
- subscription.
- """
- d = self.protocol.subscribe(JID('pubsub.example.org'), 'test',
- JID('user@example.org'))
-
- iq = self.stub.output[-1]
- response = toResponse(iq, 'result')
- command = response.addElement((NS_PUBSUB, 'pubsub'))
- subscription = command.addElement('subscription')
- subscription['node'] = 'test'
- subscription['jid'] = 'user@example.org'
- subscription['subscription'] = 'unconfigured'
- self.stub.send(response)
- self.assertFailure(d, pubsub.SubscriptionUnconfigured)
- return d
-
-
- def test_subscribeWithOptions(self):
- options = {'pubsub#deliver': False}
-
- d = self.protocol.subscribe(JID('pubsub.example.org'), 'test',
- JID('user@example.org'),
- options=options)
- iq = self.stub.output[-1]
-
- # Check options present
- childNames = []
- for element in iq.pubsub.elements():
- if element.uri == NS_PUBSUB:
- childNames.append(element.name)
-
- self.assertEqual(['subscribe', 'options'], childNames)
- form = data_form.findForm(iq.pubsub.options,
- NS_PUBSUB_SUBSCRIBE_OPTIONS)
- self.assertEqual('submit', form.formType)
- form.typeCheck({'pubsub#deliver': {'type': 'boolean'}})
- self.assertEqual(options, form.getValues())
-
- # Send response
- response = toResponse(iq, 'result')
- pubsub = response.addElement((NS_PUBSUB, 'pubsub'))
- subscription = pubsub.addElement('subscription')
- subscription['node'] = 'test'
- subscription['jid'] = 'user@example.org'
- subscription['subscription'] = 'subscribed'
- self.stub.send(response)
-
- return d
-
-
- def test_subscribeWithSender(self):
- """
- Test sending subscription request from a specific JID.
- """
- d = self.protocol.subscribe(JID('pubsub.example.org'), 'test',
- JID('user@example.org'),
- sender=JID('user@example.org'))
-
- iq = self.stub.output[-1]
- self.assertEquals('user@example.org', iq['from'])
-
- response = toResponse(iq, 'result')
- pubsub = response.addElement((NS_PUBSUB, 'pubsub'))
- subscription = pubsub.addElement('subscription')
- subscription['node'] = 'test'
- subscription['jid'] = 'user@example.org'
- subscription['subscription'] = 'subscribed'
- self.stub.send(response)
- return d
-
-
- def test_subscribeReturningSubscriptionIdentifier(self):
- """
- Test sending subscription request with subscription identifier.
- """
- def cb(subscription):
- self.assertEqual('1234', subscription.subscriptionIdentifier)
-
- d = self.protocol.subscribe(JID('pubsub.example.org'), 'test',
- JID('user@example.org'))
- d.addCallback(cb)
-
- iq = self.stub.output[-1]
-
- response = toResponse(iq, 'result')
- pubsub = response.addElement((NS_PUBSUB, 'pubsub'))
- subscription = pubsub.addElement('subscription')
- subscription['node'] = 'test'
- subscription['jid'] = 'user@example.org'
- subscription['subscription'] = 'subscribed'
- subscription['subid'] = '1234'
- self.stub.send(response)
- return d
-
-
- def test_unsubscribe(self):
- """
- Test sending unsubscription request.
- """
- d = self.protocol.unsubscribe(JID('pubsub.example.org'), 'test',
- JID('user@example.org'))
-
- iq = self.stub.output[-1]
- self.assertEquals('pubsub.example.org', iq.getAttribute('to'))
- self.assertEquals('set', iq.getAttribute('type'))
- self.assertEquals('pubsub', iq.pubsub.name)
- self.assertEquals(NS_PUBSUB, iq.pubsub.uri)
- children = list(domish.generateElementsQNamed(iq.pubsub.children,
- 'unsubscribe', NS_PUBSUB))
- self.assertEquals(1, len(children))
- child = children[0]
- self.assertEquals('test', child['node'])
- self.assertEquals('user@example.org', child['jid'])
-
- self.stub.send(toResponse(iq, 'result'))
- return d
-
-
- def test_unsubscribeWithSender(self):
- """
- Test sending unsubscription request from a specific JID.
- """
- d = self.protocol.unsubscribe(JID('pubsub.example.org'), 'test',
- JID('user@example.org'),
- sender=JID('user@example.org'))
-
- iq = self.stub.output[-1]
- self.assertEquals('user@example.org', iq['from'])
- self.stub.send(toResponse(iq, 'result'))
- return d
-
-
- def test_unsubscribeWithSubscriptionIdentifier(self):
- """
- Test sending unsubscription request with subscription identifier.
- """
- d = self.protocol.unsubscribe(JID('pubsub.example.org'), 'test',
- JID('user@example.org'),
- subscriptionIdentifier='1234')
-
- iq = self.stub.output[-1]
- child = iq.pubsub.unsubscribe
- self.assertEquals('1234', child['subid'])
-
- self.stub.send(toResponse(iq, 'result'))
- return d
-
-
- def test_items(self):
- """
- Test sending items request.
- """
- def cb(items):
- self.assertEquals([], items)
-
- d = self.protocol.items(JID('pubsub.example.org'), 'test')
- d.addCallback(cb)
-
- iq = self.stub.output[-1]
- self.assertEquals('pubsub.example.org', iq.getAttribute('to'))
- self.assertEquals('get', iq.getAttribute('type'))
- self.assertEquals('pubsub', iq.pubsub.name)
- self.assertEquals(NS_PUBSUB, iq.pubsub.uri)
- children = list(domish.generateElementsQNamed(iq.pubsub.children,
- 'items', NS_PUBSUB))
- self.assertEquals(1, len(children))
- child = children[0]
- self.assertEquals('test', child['node'])
-
- response = toResponse(iq, 'result')
- items = response.addElement((NS_PUBSUB, 'pubsub')).addElement('items')
- items['node'] = 'test'
-
- self.stub.send(response)
-
- return d
-
-
- def test_itemsMaxItems(self):
- """
- Test sending items request, with limit on the number of items.
- """
- def cb(items):
- self.assertEquals(2, len(items))
- self.assertEquals([item1, item2], items)
-
- d = self.protocol.items(JID('pubsub.example.org'), 'test', maxItems=2)
- d.addCallback(cb)
-
- iq = self.stub.output[-1]
- self.assertEquals('pubsub.example.org', iq.getAttribute('to'))
- self.assertEquals('get', iq.getAttribute('type'))
- self.assertEquals('pubsub', iq.pubsub.name)
- self.assertEquals(NS_PUBSUB, iq.pubsub.uri)
- children = list(domish.generateElementsQNamed(iq.pubsub.children,
- 'items', NS_PUBSUB))
- self.assertEquals(1, len(children))
- child = children[0]
- self.assertEquals('test', child['node'])
- self.assertEquals('2', child['max_items'])
-
- response = toResponse(iq, 'result')
- items = response.addElement((NS_PUBSUB, 'pubsub')).addElement('items')
- items['node'] = 'test'
- item1 = items.addElement('item')
- item1['id'] = 'item1'
- item2 = items.addElement('item')
- item2['id'] = 'item2'
-
- self.stub.send(response)
-
- return d
-
-
- def test_itemsWithItemIdentifiers(self):
- """
- Test sending items request with item identifiers.
- """
- def cb(items):
- self.assertEquals(2, len(items))
- self.assertEquals([item1, item2], items)
-
- d = self.protocol.items(JID('pubsub.example.org'), 'test',
- itemIdentifiers=['item1', 'item2'])
- d.addCallback(cb)
-
- iq = self.stub.output[-1]
- self.assertEquals('pubsub.example.org', iq.getAttribute('to'))
- self.assertEquals('get', iq.getAttribute('type'))
- self.assertEquals('pubsub', iq.pubsub.name)
- self.assertEquals(NS_PUBSUB, iq.pubsub.uri)
- children = list(domish.generateElementsQNamed(iq.pubsub.children,
- 'items', NS_PUBSUB))
- self.assertEquals(1, len(children))
- child = children[0]
- self.assertEquals('test', child['node'])
- itemIdentifiers = [item.getAttribute('id') for item in
- domish.generateElementsQNamed(child.children, 'item',
- NS_PUBSUB)]
- self.assertEquals(['item1', 'item2'], itemIdentifiers)
-
- response = toResponse(iq, 'result')
- items = response.addElement((NS_PUBSUB, 'pubsub')).addElement('items')
- items['node'] = 'test'
- item1 = items.addElement('item')
- item1['id'] = 'item1'
- item2 = items.addElement('item')
- item2['id'] = 'item2'
-
- self.stub.send(response)
-
- return d
-
-
- def test_itemsWithSubscriptionIdentifier(self):
- """
- Test sending items request with a subscription identifier.
- """
-
- d = self.protocol.items(JID('pubsub.example.org'), 'test',
- subscriptionIdentifier='1234')
-
- iq = self.stub.output[-1]
- child = iq.pubsub.items
- self.assertEquals('1234', child['subid'])
-
- response = toResponse(iq, 'result')
- items = response.addElement((NS_PUBSUB, 'pubsub')).addElement('items')
- items['node'] = 'test'
-
- self.stub.send(response)
- return d
-
-
- def test_itemsWithSender(self):
- """
- Test sending items request from a specific JID.
- """
-
- d = self.protocol.items(JID('pubsub.example.org'), 'test',
- sender=JID('user@example.org'))
-
- iq = self.stub.output[-1]
- self.assertEquals('user@example.org', iq['from'])
-
- response = toResponse(iq, 'result')
- items = response.addElement((NS_PUBSUB, 'pubsub')).addElement('items')
- items['node'] = 'test'
-
- self.stub.send(response)
- return d
-
-
- def test_retractItems(self):
- """
- Test sending items retraction.
- """
- d = self.protocol.retractItems(JID('pubsub.example.org'), 'test',
- itemIdentifiers=['item1', 'item2'])
-
- iq = self.stub.output[-1]
- self.assertEquals('pubsub.example.org', iq.getAttribute('to'))
- self.assertEquals('set', iq.getAttribute('type'))
- self.assertEquals('pubsub', iq.pubsub.name)
- self.assertEquals(NS_PUBSUB, iq.pubsub.uri)
- children = list(domish.generateElementsQNamed(iq.pubsub.children,
- 'retract', NS_PUBSUB))
- self.assertEquals(1, len(children))
- child = children[0]
- self.assertEquals('test', child['node'])
- itemIdentifiers = [item.getAttribute('id') for item in
- domish.generateElementsQNamed(child.children, 'item',
- NS_PUBSUB)]
- self.assertEquals(['item1', 'item2'], itemIdentifiers)
-
- self.stub.send(toResponse(iq, 'result'))
- return d
-
-
- def test_retractItemsWithSender(self):
- """
- Test retracting items request from a specific JID.
- """
- d = self.protocol.retractItems(JID('pubsub.example.org'), 'test',
- itemIdentifiers=['item1', 'item2'],
- sender=JID('user@example.org'))
-
- iq = self.stub.output[-1]
- self.assertEquals('user@example.org', iq['from'])
-
- self.stub.send(toResponse(iq, 'result'))
- return d
-
-
- def test_getOptions(self):
- def cb(form):
- self.assertEqual('form', form.formType)
- self.assertEqual(NS_PUBSUB_SUBSCRIBE_OPTIONS, form.formNamespace)
- field = form.fields['pubsub#deliver']
- self.assertEqual('boolean', field.fieldType)
- self.assertIdentical(True, field.value)
- self.assertEqual('Enable delivery?', field.label)
-
- d = self.protocol.getOptions(JID('pubsub.example.org'), 'test',
- JID('user@example.org'),
- sender=JID('user@example.org'))
- d.addCallback(cb)
-
- iq = self.stub.output[-1]
- self.assertEqual('pubsub.example.org', iq.getAttribute('to'))
- self.assertEqual('get', iq.getAttribute('type'))
- self.assertEqual('pubsub', iq.pubsub.name)
- self.assertEqual(NS_PUBSUB, iq.pubsub.uri)
- children = list(domish.generateElementsQNamed(iq.pubsub.children,
- 'options', NS_PUBSUB))
- self.assertEqual(1, len(children))
- child = children[0]
- self.assertEqual('test', child['node'])
-
- self.assertEqual(0, len(child.children))
-
- # Send response
- form = data_form.Form('form', formNamespace=NS_PUBSUB_SUBSCRIBE_OPTIONS)
- form.addField(data_form.Field('boolean', var='pubsub#deliver',
- label='Enable delivery?',
- value=True))
- response = toResponse(iq, 'result')
- response.addElement((NS_PUBSUB, 'pubsub'))
- response.pubsub.addElement('options')
- response.pubsub.options.addChild(form.toElement())
- self.stub.send(response)
-
- return d
-
-
- def test_getOptionsWithSubscriptionIdentifier(self):
- """
- Getting options with a subid should have the subid in the request.
- """
-
- d = self.protocol.getOptions(JID('pubsub.example.org'), 'test',
- JID('user@example.org'),
- sender=JID('user@example.org'),
- subscriptionIdentifier='1234')
-
- iq = self.stub.output[-1]
- child = iq.pubsub.options
- self.assertEqual('1234', child['subid'])
-
- # Send response
- form = data_form.Form('form', formNamespace=NS_PUBSUB_SUBSCRIBE_OPTIONS)
- form.addField(data_form.Field('boolean', var='pubsub#deliver',
- label='Enable delivery?',
- value=True))
- response = toResponse(iq, 'result')
- response.addElement((NS_PUBSUB, 'pubsub'))
- response.pubsub.addElement('options')
- response.pubsub.options.addChild(form.toElement())
- self.stub.send(response)
-
- return d
-
-
- def test_setOptions(self):
- """
- setOptions should send out a options-set request.
- """
- options = {'pubsub#deliver': False}
-
- d = self.protocol.setOptions(JID('pubsub.example.org'), 'test',
- JID('user@example.org'),
- options,
- sender=JID('user@example.org'))
-
- iq = self.stub.output[-1]
- self.assertEqual('pubsub.example.org', iq.getAttribute('to'))
- self.assertEqual('set', iq.getAttribute('type'))
- self.assertEqual('pubsub', iq.pubsub.name)
- self.assertEqual(NS_PUBSUB, iq.pubsub.uri)
- children = list(domish.generateElementsQNamed(iq.pubsub.children,
- 'options', NS_PUBSUB))
- self.assertEqual(1, len(children))
- child = children[0]
- self.assertEqual('test', child['node'])
-
- form = data_form.findForm(child, NS_PUBSUB_SUBSCRIBE_OPTIONS)
- self.assertEqual('submit', form.formType)
- form.typeCheck({'pubsub#deliver': {'type': 'boolean'}})
- self.assertEqual(options, form.getValues())
-
- response = toResponse(iq, 'result')
- self.stub.send(response)
-
- return d
-
-
- def test_setOptionsWithSubscriptionIdentifier(self):
- """
- setOptions should send out a options-set request with subid.
- """
- options = {'pubsub#deliver': False}
-
- d = self.protocol.setOptions(JID('pubsub.example.org'), 'test',
- JID('user@example.org'),
- options,
- subscriptionIdentifier='1234',
- sender=JID('user@example.org'))
-
- iq = self.stub.output[-1]
- child = iq.pubsub.options
- self.assertEqual('1234', child['subid'])
-
- form = data_form.findForm(child, NS_PUBSUB_SUBSCRIBE_OPTIONS)
- self.assertEqual('submit', form.formType)
- form.typeCheck({'pubsub#deliver': {'type': 'boolean'}})
- self.assertEqual(options, form.getValues())
-
- response = toResponse(iq, 'result')
- self.stub.send(response)
-
- return d
-
-
-class PubSubRequestTest(unittest.TestCase):
-
- def test_fromElementUnknown(self):
- """
- An unknown verb raises NotImplementedError.
- """
-
- xml = """
-
-
-
-
-
- """
-
- self.assertRaises(NotImplementedError,
- pubsub.PubSubRequest.fromElement, parseXml(xml))
-
-
- def test_fromElementKnownBadCombination(self):
- """
- Multiple verbs in an unknown configuration raises NotImplementedError.
- """
-
- xml = """
-
-
-
-
-
-
- """
-
- self.assertRaises(NotImplementedError,
- pubsub.PubSubRequest.fromElement, parseXml(xml))
-
- def test_fromElementPublish(self):
- """
- Test parsing a publish request.
- """
-
- xml = """
-
-
-
-
-
- """
-
- request = pubsub.PubSubRequest.fromElement(parseXml(xml))
- self.assertEqual('publish', request.verb)
- self.assertEqual(JID('user@example.org'), request.sender)
- self.assertEqual(JID('pubsub.example.org'), request.recipient)
- self.assertEqual('test', request.nodeIdentifier)
- self.assertEqual([], request.items)
-
-
- def test_fromElementPublishItems(self):
- """
- Test parsing a publish request with items.
- """
-
- xml = """
-
-
-
-
-
-
-
-
- """
-
- request = pubsub.PubSubRequest.fromElement(parseXml(xml))
- self.assertEqual(2, len(request.items))
- self.assertEqual(u'item1', request.items[0]["id"])
- self.assertEqual(u'item2', request.items[1]["id"])
-
-
- def test_fromElementPublishItemsOptions(self):
- """
- Test parsing a publish request with items and options.
-
- Note that publishing options are not supported, but passing them
- shouldn't affect processing of the publish request itself.
- """
-
- xml = """
-
-
-
-
-
-
-
-
-
- """
-
- request = pubsub.PubSubRequest.fromElement(parseXml(xml))
- self.assertEqual(2, len(request.items))
- self.assertEqual(u'item1', request.items[0]["id"])
- self.assertEqual(u'item2', request.items[1]["id"])
-
- def test_fromElementPublishNoNode(self):
- """
- A publish request to the root node should raise an exception.
- """
- xml = """
-
-
-
-
-
- """
-
- err = self.assertRaises(error.StanzaError,
- pubsub.PubSubRequest.fromElement,
- parseXml(xml))
- self.assertEqual('bad-request', err.condition)
- self.assertEqual(NS_PUBSUB_ERRORS, err.appCondition.uri)
- self.assertEqual('nodeid-required', err.appCondition.name)
-
-
- def test_fromElementSubscribe(self):
- """
- Test parsing a subscription request.
- """
-
- xml = """
-
-
-
-
-
- """
-
- request = pubsub.PubSubRequest.fromElement(parseXml(xml))
- self.assertEqual('subscribe', request.verb)
- self.assertEqual(JID('user@example.org'), request.sender)
- self.assertEqual(JID('pubsub.example.org'), request.recipient)
- self.assertEqual('test', request.nodeIdentifier)
- self.assertEqual(JID('user@example.org/Home'), request.subscriber)
-
-
- def test_fromElementSubscribeEmptyNode(self):
- """
- Test parsing a subscription request to the root node.
- """
-
- xml = """
-
-
-
-
-
- """
-
- request = pubsub.PubSubRequest.fromElement(parseXml(xml))
- self.assertEqual('', request.nodeIdentifier)
-
-
- def test_fromElementSubscribeNoJID(self):
- """
- Subscribe requests without a JID should raise a bad-request exception.
- """
- xml = """
-
-
-
-
-
- """
- err = self.assertRaises(error.StanzaError,
- pubsub.PubSubRequest.fromElement,
- parseXml(xml))
- self.assertEqual('bad-request', err.condition)
- self.assertEqual(NS_PUBSUB_ERRORS, err.appCondition.uri)
- self.assertEqual('jid-required', err.appCondition.name)
-
-
- def test_fromElementSubscribeWithOptions(self):
- """
- Test parsing a subscription request.
- """
-
- xml = """
-
-
-
-
-
-
- http://jabber.org/protocol/pubsub#subscribe_options
-
-
- 1
-
-
-
-
-
- """
-
- request = pubsub.PubSubRequest.fromElement(parseXml(xml))
- self.assertEqual('subscribe', request.verb)
- request.options.typeCheck({'pubsub#deliver': {'type': 'boolean'}})
- self.assertEqual({'pubsub#deliver': True}, request.options.getValues())
-
-
- def test_fromElementSubscribeWithOptionsBadFormType(self):
- """
- The options form should have the right type.
- """
-
- xml = """
-
-
-
-
-
-
- http://jabber.org/protocol/pubsub#subscribe_options
-
-
- 1
-
-
-
-
-
- """
-
- err = self.assertRaises(error.StanzaError,
- pubsub.PubSubRequest.fromElement,
- parseXml(xml))
- self.assertEqual('bad-request', err.condition)
- self.assertEqual("Unexpected form type 'result'", err.text)
- self.assertEqual(None, err.appCondition)
-
-
- def test_fromElementSubscribeWithOptionsEmpty(self):
- """
- When no (suitable) form is found, the options are empty.
- """
-
- xml = """
-
-
-
-
-
-
- """
-
- request = pubsub.PubSubRequest.fromElement(parseXml(xml))
- self.assertEqual('subscribe', request.verb)
- self.assertEqual({}, request.options.getValues())
-
-
- def test_fromElementUnsubscribe(self):
- """
- Test parsing an unsubscription request.
- """
-
- xml = """
-
-
-
-
-
- """
-
- request = pubsub.PubSubRequest.fromElement(parseXml(xml))
- self.assertEqual('unsubscribe', request.verb)
- self.assertEqual(JID('user@example.org'), request.sender)
- self.assertEqual(JID('pubsub.example.org'), request.recipient)
- self.assertEqual('test', request.nodeIdentifier)
- self.assertEqual(JID('user@example.org/Home'), request.subscriber)
-
-
- def test_fromElementUnsubscribeWithSubscriptionIdentifier(self):
- """
- Test parsing an unsubscription request with subscription identifier.
- """
-
- xml = """
-
-
-
-
-
- """
-
- request = pubsub.PubSubRequest.fromElement(parseXml(xml))
- self.assertEqual('1234', request.subscriptionIdentifier)
-
-
- def test_fromElementUnsubscribeNoJID(self):
- """
- Unsubscribe requests without a JID should raise a bad-request exception.
- """
- xml = """
-
-
-
-
-
- """
- err = self.assertRaises(error.StanzaError,
- pubsub.PubSubRequest.fromElement,
- parseXml(xml))
- self.assertEqual('bad-request', err.condition)
- self.assertEqual(NS_PUBSUB_ERRORS, err.appCondition.uri)
- self.assertEqual('jid-required', err.appCondition.name)
-
-
- def test_fromElementOptionsGet(self):
- """
- Test parsing a request for getting subscription options.
- """
-
- xml = """
-
-
-
-
-
- """
-
- request = pubsub.PubSubRequest.fromElement(parseXml(xml))
- self.assertEqual('optionsGet', request.verb)
- self.assertEqual(JID('user@example.org'), request.sender)
- self.assertEqual(JID('pubsub.example.org'), request.recipient)
- self.assertEqual('test', request.nodeIdentifier)
- self.assertEqual(JID('user@example.org/Home'), request.subscriber)
-
-
- def test_fromElementOptionsGetWithSubscriptionIdentifier(self):
- """
- Test parsing a request for getting subscription options with subid.
- """
-
- xml = """
-
-
-
-
-
- """
-
- request = pubsub.PubSubRequest.fromElement(parseXml(xml))
- self.assertEqual('1234', request.subscriptionIdentifier)
-
-
- def test_fromElementOptionsSet(self):
- """
- Test parsing a request for setting subscription options.
- """
-
- xml = """
-
-
-
-
-
- http://jabber.org/protocol/pubsub#subscribe_options
-
- 1
-
-
-
-
- """
-
- request = pubsub.PubSubRequest.fromElement(parseXml(xml))
- self.assertEqual('optionsSet', request.verb)
- self.assertEqual(JID('user@example.org'), request.sender)
- self.assertEqual(JID('pubsub.example.org'), request.recipient)
- self.assertEqual('test', request.nodeIdentifier)
- self.assertEqual(JID('user@example.org/Home'), request.subscriber)
- self.assertEqual({'pubsub#deliver': '1'}, request.options.getValues())
-
-
- def test_fromElementOptionsSetWithSubscriptionIdentifier(self):
- """
- Test parsing a request for setting subscription options with subid.
- """
-
- xml = """
-
-
-
-
-
- http://jabber.org/protocol/pubsub#subscribe_options
-
- 1
-
-
-
-
- """
-
- request = pubsub.PubSubRequest.fromElement(parseXml(xml))
- self.assertEqual('1234', request.subscriptionIdentifier)
-
-
- def test_fromElementOptionsSetCancel(self):
- """
- Test parsing a request for cancelling setting subscription options.
- """
-
- xml = """
-
-
-
-
-
-
-
- """
-
- request = pubsub.PubSubRequest.fromElement(parseXml(xml))
- self.assertEqual('cancel', request.options.formType)
-
-
- def test_fromElementOptionsSetBadFormType(self):
- """
- On a options set request unknown fields should be ignored.
- """
-
- xml = """
-
-
-
-
-
- http://jabber.org/protocol/pubsub#subscribe_options
-
- 1
-
-
-
-
- """
-
- err = self.assertRaises(error.StanzaError,
- pubsub.PubSubRequest.fromElement,
- parseXml(xml))
- self.assertEqual('bad-request', err.condition)
- self.assertEqual("Unexpected form type 'result'", err.text)
- self.assertEqual(None, err.appCondition)
-
-
- def test_fromElementOptionsSetNoForm(self):
- """
- On a options set request a form is required.
- """
-
- xml = """
-
-
-
-
-
- """
- err = self.assertRaises(error.StanzaError,
- pubsub.PubSubRequest.fromElement,
- parseXml(xml))
- self.assertEqual('bad-request', err.condition)
- self.assertEqual(None, err.appCondition)
-
-
- def test_fromElementSubscriptions(self):
- """
- Test parsing a request for all subscriptions.
- """
-
- xml = """
-
-
-
-
-
- """
-
- request = pubsub.PubSubRequest.fromElement(parseXml(xml))
- self.assertEqual('subscriptions', request.verb)
- self.assertEqual(JID('user@example.org'), request.sender)
- self.assertEqual(JID('pubsub.example.org'), request.recipient)
-
-
- def test_fromElementAffiliations(self):
- """
- Test parsing a request for all affiliations.
- """
-
- xml = """
-
-
-
-
-
- """
-
- request = pubsub.PubSubRequest.fromElement(parseXml(xml))
- self.assertEqual('affiliations', request.verb)
- self.assertEqual(JID('user@example.org'), request.sender)
- self.assertEqual(JID('pubsub.example.org'), request.recipient)
-
-
- def test_fromElementCreate(self):
- """
- Test parsing a request to create a node.
- """
-
- xml = """
-
-
-
-
-
- """
-
- request = pubsub.PubSubRequest.fromElement(parseXml(xml))
- self.assertEqual('create', request.verb)
- self.assertEqual(JID('user@example.org'), request.sender)
- self.assertEqual(JID('pubsub.example.org'), request.recipient)
- self.assertEqual('mynode', request.nodeIdentifier)
- self.assertIdentical(None, request.options)
-
-
- def test_fromElementCreateInstant(self):
- """
- Test parsing a request to create an instant node.
- """
-
- xml = """
-
-
-
-
-
- """
-
- request = pubsub.PubSubRequest.fromElement(parseXml(xml))
- self.assertIdentical(None, request.nodeIdentifier)
-
-
- def test_fromElementCreateConfigureEmpty(self):
- """
- Test parsing a request to create a node with an empty configuration.
- """
-
- xml = """
-
-
-
-
-
-
- """
-
- request = pubsub.PubSubRequest.fromElement(parseXml(xml))
- self.assertEqual({}, request.options.getValues())
- self.assertEqual(u'mynode', request.nodeIdentifier)
-
-
- def test_fromElementCreateConfigureEmptyWrongOrder(self):
- """
- Test parsing a request to create a node and configure, wrong order.
-
- The C{configure} element should come after the C{create} request,
- but we should accept both orders.
- """
-
- xml = """
-
-
-
-
-
-
- """
-
- request = pubsub.PubSubRequest.fromElement(parseXml(xml))
- self.assertEqual({}, request.options.getValues())
- self.assertEqual(u'mynode', request.nodeIdentifier)
-
-
- def test_fromElementCreateConfigure(self):
- """
- Test parsing a request to create a node.
- """
-
- xml = """
-
-
-
-
-
-
- http://jabber.org/protocol/pubsub#node_config
-
- open
- 0
-
-
-
-
- """
-
- request = pubsub.PubSubRequest.fromElement(parseXml(xml))
- values = request.options
- self.assertIn('pubsub#access_model', values)
- self.assertEqual(u'open', values['pubsub#access_model'])
- self.assertIn('pubsub#persist_items', values)
- self.assertEqual(u'0', values['pubsub#persist_items'])
-
-
- def test_fromElementCreateConfigureBadFormType(self):
- """
- The form of a node creation request should have the right type.
- """
-
- xml = """
-
-
-
-
-
-
- http://jabber.org/protocol/pubsub#node_config
-
- open
- 0
-
-
-
-
- """
-
- err = self.assertRaises(error.StanzaError,
- pubsub.PubSubRequest.fromElement,
- parseXml(xml))
- self.assertEqual('bad-request', err.condition)
- self.assertEqual("Unexpected form type 'result'", err.text)
- self.assertEqual(None, err.appCondition)
-
-
- def test_fromElementDefault(self):
- """
- Parsing default node configuration request sets required attributes.
-
- Besides C{verb}, C{sender} and C{recipient}, we expect C{nodeType}
- to be set. If not passed it receives the default C{u'leaf'}.
- """
-
- xml = """
-
-
-
-
-
- """
-
- request = pubsub.PubSubRequest.fromElement(parseXml(xml))
- self.assertEquals(u'default', request.verb)
- self.assertEquals(JID('user@example.org'), request.sender)
- self.assertEquals(JID('pubsub.example.org'), request.recipient)
- self.assertEquals(u'leaf', request.nodeType)
-
-
- def test_fromElementDefaultCollection(self):
- """
- Parsing default request for collection sets nodeType to collection.
- """
-
- xml = """
-
-
-
-
-
- http://jabber.org/protocol/pubsub#node_config
-
-
- collection
-
-
-
-
-
-
- """
-
- request = pubsub.PubSubRequest.fromElement(parseXml(xml))
- self.assertEquals('collection', request.nodeType)
-
-
- def test_fromElementConfigureGet(self):
- """
- Test parsing a node configuration get request.
- """
-
- xml = """
-
-
-
-
-
- """
-
- request = pubsub.PubSubRequest.fromElement(parseXml(xml))
- self.assertEqual('configureGet', request.verb)
- self.assertEqual(JID('user@example.org'), request.sender)
- self.assertEqual(JID('pubsub.example.org'), request.recipient)
- self.assertEqual('test', request.nodeIdentifier)
-
-
- def test_fromElementConfigureSet(self):
- """
- On a node configuration set request the Data Form is parsed.
- """
-
- xml = """
-
-
-
-
-
- http://jabber.org/protocol/pubsub#node_config
-
- 0
- 1
-
-
-
-
- """
-
- request = pubsub.PubSubRequest.fromElement(parseXml(xml))
- self.assertEqual('configureSet', request.verb)
- self.assertEqual(JID('user@example.org'), request.sender)
- self.assertEqual(JID('pubsub.example.org'), request.recipient)
- self.assertEqual('test', request.nodeIdentifier)
- self.assertEqual({'pubsub#deliver_payloads': '0',
- 'pubsub#persist_items': '1'},
- request.options.getValues())
-
-
- def test_fromElementConfigureSetCancel(self):
- """
- The node configuration is cancelled, so no options.
- """
-
- xml = """
-
-
-
-
-
-
-
- """
-
- request = pubsub.PubSubRequest.fromElement(parseXml(xml))
- self.assertEqual('cancel', request.options.formType)
-
-
- def test_fromElementConfigureSetBadFormType(self):
- """
- The form of a node configuraton set request should have the right type.
- """
-
- xml = """
-
-
-
-
-
- http://jabber.org/protocol/pubsub#node_config
-
- 0
- 1
-
-
-
-
- """
-
- err = self.assertRaises(error.StanzaError,
- pubsub.PubSubRequest.fromElement,
- parseXml(xml))
- self.assertEqual('bad-request', err.condition)
- self.assertEqual("Unexpected form type 'result'", err.text)
- self.assertEqual(None, err.appCondition)
-
-
- def test_fromElementConfigureSetNoForm(self):
- """
- On a node configuration set request a form is required.
- """
-
- xml = """
-
-
-
-
-
- """
- err = self.assertRaises(error.StanzaError,
- pubsub.PubSubRequest.fromElement,
- parseXml(xml))
- self.assertEqual('bad-request', err.condition)
- self.assertEqual(None, err.appCondition)
-
-
- def test_fromElementItems(self):
- """
- Test parsing an items request.
- """
- xml = """
-
-
-
-
-
- """
-
- request = pubsub.PubSubRequest.fromElement(parseXml(xml))
- self.assertEqual('items', request.verb)
- self.assertEqual(JID('user@example.org'), request.sender)
- self.assertEqual(JID('pubsub.example.org'), request.recipient)
- self.assertEqual('test', request.nodeIdentifier)
- self.assertIdentical(None, request.maxItems)
- self.assertIdentical(None, request.subscriptionIdentifier)
- self.assertEqual([], request.itemIdentifiers)
-
-
- def test_fromElementItemsSubscriptionIdentifier(self):
- """
- Test parsing an items request with subscription identifier.
- """
- xml = """
-
-
-
-
-
- """
-
- request = pubsub.PubSubRequest.fromElement(parseXml(xml))
- self.assertEqual('1234', request.subscriptionIdentifier)
-
-
- def test_fromElementRetract(self):
- """
- Test parsing a retract request.
- """
-
- xml = """
-
-
-
-
-
-
-
-
- """
-
- request = pubsub.PubSubRequest.fromElement(parseXml(xml))
- self.assertEqual('retract', request.verb)
- self.assertEqual(JID('user@example.org'), request.sender)
- self.assertEqual(JID('pubsub.example.org'), request.recipient)
- self.assertEqual('test', request.nodeIdentifier)
- self.assertEqual(['item1', 'item2'], request.itemIdentifiers)
-
-
- def test_fromElementPurge(self):
- """
- Test parsing a purge request.
- """
-
- xml = """
-
-
-
-
-
- """
-
- request = pubsub.PubSubRequest.fromElement(parseXml(xml))
- self.assertEqual('purge', request.verb)
- self.assertEqual(JID('user@example.org'), request.sender)
- self.assertEqual(JID('pubsub.example.org'), request.recipient)
- self.assertEqual('test', request.nodeIdentifier)
-
-
- def test_fromElementDelete(self):
- """
- Test parsing a delete request.
- """
-
- xml = """
-
-
-
-
-
- """
-
- request = pubsub.PubSubRequest.fromElement(parseXml(xml))
- self.assertEqual('delete', request.verb)
- self.assertEqual(JID('user@example.org'), request.sender)
- self.assertEqual(JID('pubsub.example.org'), request.recipient)
- self.assertEqual('test', request.nodeIdentifier)
-
-
-
-class PubSubServiceTest(unittest.TestCase, TestableRequestHandlerMixin):
- """
- Tests for L{pubsub.PubSubService}.
- """
-
- def setUp(self):
- self.stub = XmlStreamStub()
- self.resource = pubsub.PubSubResource()
- self.service = pubsub.PubSubService(self.resource)
- self.service.send = self.stub.xmlstream.send
-
- def test_interface(self):
- """
- Do instances of L{pubsub.PubSubService} provide L{iwokkel.IPubSubService}?
- """
- verify.verifyObject(iwokkel.IPubSubService, self.service)
-
-
- def test_interfaceIDisco(self):
- """
- Do instances of L{pubsub.PubSubService} provide L{iwokkel.IDisco}?
- """
- verify.verifyObject(iwokkel.IDisco, self.service)
-
-
- def test_connectionMade(self):
- """
- Verify setup of observers in L{pubsub.connectionMade}.
- """
- requests = []
-
- def handleRequest(iq):
- requests.append(iq)
-
- self.service.xmlstream = self.stub.xmlstream
- self.service.handleRequest = handleRequest
- self.service.connectionMade()
-
- for namespace in (NS_PUBSUB, NS_PUBSUB_OWNER):
- for stanzaType in ('get', 'set'):
- iq = domish.Element((None, 'iq'))
- iq['type'] = stanzaType
- iq.addElement((namespace, 'pubsub'))
- self.stub.xmlstream.dispatch(iq)
-
- self.assertEqual(4, len(requests))
-
-
- def test_getDiscoInfo(self):
- """
- Test getDiscoInfo calls getNodeInfo and returns some minimal info.
- """
- def cb(info):
- discoInfo = disco.DiscoInfo()
- for item in info:
- discoInfo.append(item)
- self.assertIn(('pubsub', 'service'), discoInfo.identities)
- self.assertIn(disco.NS_DISCO_ITEMS, discoInfo.features)
-
- d = self.service.getDiscoInfo(JID('user@example.org/home'),
- JID('pubsub.example.org'), '')
- d.addCallback(cb)
- return d
-
-
- def test_getDiscoInfoNodeType(self):
- """
- Test getDiscoInfo with node type.
- """
- def cb(info):
- discoInfo = disco.DiscoInfo()
- for item in info:
- discoInfo.append(item)
- self.assertIn(('pubsub', 'collection'), discoInfo.identities)
-
- def getInfo(requestor, target, nodeIdentifier):
- return defer.succeed({'type': 'collection',
- 'meta-data': {}})
-
- self.resource.getInfo = getInfo
- d = self.service.getDiscoInfo(JID('user@example.org/home'),
- JID('pubsub.example.org'), '')
- d.addCallback(cb)
- return d
-
-
- def test_getDiscoInfoMetaData(self):
- """
- Test getDiscoInfo with returned meta data.
- """
- def cb(info):
- discoInfo = disco.DiscoInfo()
- for item in info:
- discoInfo.append(item)
-
- self.assertIn(('pubsub', 'leaf'), discoInfo.identities)
- self.assertIn(NS_PUBSUB_META_DATA, discoInfo.extensions)
- form = discoInfo.extensions[NS_PUBSUB_META_DATA]
- self.assertIn('pubsub#node_type', form.fields)
-
- def getInfo(requestor, target, nodeIdentifier):
- metaData = [{'var': 'pubsub#persist_items',
- 'label': 'Persist items to storage',
- 'value': True}]
- return defer.succeed({'type': 'leaf', 'meta-data': metaData})
-
- self.resource.getInfo = getInfo
- d = self.service.getDiscoInfo(JID('user@example.org/home'),
- JID('pubsub.example.org'), '')
- d.addCallback(cb)
- return d
-
-
- def test_getDiscoInfoResourceFeatures(self):
- """
- Test getDiscoInfo with the resource features.
- """
- def cb(info):
- discoInfo = disco.DiscoInfo()
- for item in info:
- discoInfo.append(item)
- self.assertIn('http://jabber.org/protocol/pubsub#publish',
- discoInfo.features)
-
- self.resource.features = ['publish']
- d = self.service.getDiscoInfo(JID('user@example.org/home'),
- JID('pubsub.example.org'), '')
- d.addCallback(cb)
- return d
-
-
- def test_getDiscoInfoBadResponse(self):
- """
- If getInfo returns invalid response, it should be logged, then ignored.
- """
- def cb(info):
- self.assertEquals([], info)
- self.assertEqual(1, len(self.flushLoggedErrors(TypeError)))
-
- def getInfo(requestor, target, nodeIdentifier):
- return defer.succeed('bad response')
-
- self.resource.getInfo = getInfo
- d = self.service.getDiscoInfo(JID('user@example.org/home'),
- JID('pubsub.example.org'), 'test')
- d.addCallback(cb)
- return d
-
-
- def test_getDiscoInfoException(self):
- """
- If getInfo returns invalid response, it should be logged, then ignored.
- """
- def cb(info):
- self.assertEquals([], info)
- self.assertEqual(1, len(self.flushLoggedErrors(NotImplementedError)))
-
- def getInfo(requestor, target, nodeIdentifier):
- return defer.fail(NotImplementedError())
-
- self.resource.getInfo = getInfo
- d = self.service.getDiscoInfo(JID('user@example.org/home'),
- JID('pubsub.example.org'), 'test')
- d.addCallback(cb)
- return d
-
-
- def test_getDiscoItemsRoot(self):
- """
- Test getDiscoItems on the root node.
- """
- def getNodes(requestor, service, nodeIdentifier):
- return defer.succeed(['node1', 'node2'])
-
- def cb(items):
- self.assertEqual(2, len(items))
- item1, item2 = items
-
- self.assertEqual(JID('pubsub.example.org'), item1.entity)
- self.assertEqual('node1', item1.nodeIdentifier)
-
- self.assertEqual(JID('pubsub.example.org'), item2.entity)
- self.assertEqual('node2', item2.nodeIdentifier)
-
- self.resource.getNodes = getNodes
- d = self.service.getDiscoItems(JID('user@example.org/home'),
- JID('pubsub.example.org'),
- '')
- d.addCallback(cb)
- return d
-
-
- def test_getDiscoItemsRootHideNodes(self):
- """
- Test getDiscoItems on the root node.
- """
- def getNodes(requestor, service, nodeIdentifier):
- raise Exception("Unexpected call to getNodes")
-
- def cb(items):
- self.assertEqual([], items)
-
- self.service.hideNodes = True
- self.resource.getNodes = getNodes
- d = self.service.getDiscoItems(JID('user@example.org/home'),
- JID('pubsub.example.org'),
- '')
- d.addCallback(cb)
- return d
-
-
- def test_getDiscoItemsNonRoot(self):
- """
- Test getDiscoItems on a non-root node.
- """
- def getNodes(requestor, service, nodeIdentifier):
- return defer.succeed(['node1', 'node2'])
-
- def cb(items):
- self.assertEqual(2, len(items))
-
- self.resource.getNodes = getNodes
- d = self.service.getDiscoItems(JID('user@example.org/home'),
- JID('pubsub.example.org'),
- 'test')
- d.addCallback(cb)
- return d
-
-
- def test_on_publish(self):
- """
- A publish request should result in L{PubSubService.publish} being
- called.
- """
-
- xml = """
-
-
-
-
-
- """
-
- def publish(request):
- return defer.succeed(None)
-
- self.resource.publish = publish
- verify.verifyObject(iwokkel.IPubSubResource, self.resource)
- return self.handleRequest(xml)
-
-
- def test_on_subscribe(self):
- """
- A successful subscription should return the current subscription.
- """
-
- xml = """
-
-
-
-
-
- """
-
- def subscribe(request):
- return defer.succeed(pubsub.Subscription(request.nodeIdentifier,
- request.subscriber,
- 'subscribed'))
-
- def cb(element):
- self.assertEqual('pubsub', element.name)
- self.assertEqual(NS_PUBSUB, element.uri)
- subscription = element.subscription
- self.assertEqual(NS_PUBSUB, subscription.uri)
- self.assertEqual('test', subscription['node'])
- self.assertEqual('user@example.org/Home', subscription['jid'])
- self.assertEqual('subscribed', subscription['subscription'])
-
- self.resource.subscribe = subscribe
- verify.verifyObject(iwokkel.IPubSubResource, self.resource)
- d = self.handleRequest(xml)
- d.addCallback(cb)
- return d
-
-
- def test_on_subscribeEmptyNode(self):
- """
- A successful subscription on root node should return no node attribute.
- """
-
- xml = """
-
-
-
-
-
- """
-
- def subscribe(request):
- return defer.succeed(pubsub.Subscription(request.nodeIdentifier,
- request.subscriber,
- 'subscribed'))
-
- def cb(element):
- self.assertFalse(element.subscription.hasAttribute('node'))
-
- self.resource.subscribe = subscribe
- verify.verifyObject(iwokkel.IPubSubResource, self.resource)
- d = self.handleRequest(xml)
- d.addCallback(cb)
- return d
-
-
- def test_on_subscribeSubscriptionIdentifier(self):
- """
- If a subscription returns a subid, this should be available.
- """
-
- xml = """
-
-
-
-
-
- """
-
- def subscribe(request):
- subscription = pubsub.Subscription(request.nodeIdentifier,
- request.subscriber,
- 'subscribed',
- subscriptionIdentifier='1234')
- return defer.succeed(subscription)
-
- def cb(element):
- self.assertEqual('1234', element.subscription.getAttribute('subid'))
-
- self.resource.subscribe = subscribe
- verify.verifyObject(iwokkel.IPubSubResource, self.resource)
- d = self.handleRequest(xml)
- d.addCallback(cb)
- return d
-
-
- def test_on_unsubscribe(self):
- """
- A successful unsubscription should return an empty response.
- """
-
- xml = """
-
-
-
-
-
- """
-
- def unsubscribe(request):
- return defer.succeed(None)
-
- def cb(element):
- self.assertIdentical(None, element)
-
- self.resource.unsubscribe = unsubscribe
- verify.verifyObject(iwokkel.IPubSubResource, self.resource)
- d = self.handleRequest(xml)
- d.addCallback(cb)
- return d
-
-
- def test_on_unsubscribeSubscriptionIdentifier(self):
- """
- A successful unsubscription with subid should return an empty response.
- """
-
- xml = """
-
-
-
-
-
- """
-
- def unsubscribe(request):
- self.assertEqual('1234', request.subscriptionIdentifier)
- return defer.succeed(None)
-
- def cb(element):
- self.assertIdentical(None, element)
-
- self.resource.unsubscribe = unsubscribe
- verify.verifyObject(iwokkel.IPubSubResource, self.resource)
- d = self.handleRequest(xml)
- d.addCallback(cb)
- return d
-
-
- def test_on_optionsGet(self):
- """
- Getting subscription options is not supported.
- """
-
- xml = """
-
-
-
-
-
- """
-
- def cb(result):
- self.assertEquals('feature-not-implemented', result.condition)
- self.assertEquals('unsupported', result.appCondition.name)
- self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri)
-
- d = self.handleRequest(xml)
- self.assertFailure(d, error.StanzaError)
- d.addCallback(cb)
- return d
-
-
- def test_on_optionsSet(self):
- """
- Setting subscription options is not supported.
- """
-
- xml = """
-
-
-
-
-
- http://jabber.org/protocol/pubsub#subscribe_options
-
- 1
-
-
-
-
- """
-
- def cb(result):
- self.assertEquals('feature-not-implemented', result.condition)
- self.assertEquals('unsupported', result.appCondition.name)
- self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri)
-
- d = self.handleRequest(xml)
- self.assertFailure(d, error.StanzaError)
- d.addCallback(cb)
- return d
-
-
- def test_on_subscriptions(self):
- """
- A subscriptions request should result in
- L{PubSubService.subscriptions} being called and the result prepared
- for the response.
- """
-
- xml = """
-
-
-
-
-
- """
-
- def subscriptions(request):
- subscription = pubsub.Subscription('test', JID('user@example.org'),
- 'subscribed')
- return defer.succeed([subscription])
-
- def cb(element):
- self.assertEqual('pubsub', element.name)
- self.assertEqual(NS_PUBSUB, element.uri)
- self.assertEqual(NS_PUBSUB, element.subscriptions.uri)
- children = list(element.subscriptions.elements())
- self.assertEqual(1, len(children))
- subscription = children[0]
- self.assertEqual('subscription', subscription.name)
- self.assertEqual(NS_PUBSUB, subscription.uri, NS_PUBSUB)
- self.assertEqual('user@example.org', subscription['jid'])
- self.assertEqual('test', subscription['node'])
- self.assertEqual('subscribed', subscription['subscription'])
-
- self.resource.subscriptions = subscriptions
- verify.verifyObject(iwokkel.IPubSubResource, self.resource)
- d = self.handleRequest(xml)
- d.addCallback(cb)
- return d
-
-
- def test_on_subscriptionsWithSubscriptionIdentifier(self):
- """
- A subscriptions request response should include subids, if set.
- """
-
- xml = """
-
-
-
-
-
- """
-
- def subscriptions(request):
- subscription = pubsub.Subscription('test', JID('user@example.org'),
- 'subscribed',
- subscriptionIdentifier='1234')
- return defer.succeed([subscription])
-
- def cb(element):
- subscription = element.subscriptions.subscription
- self.assertEqual('1234', subscription['subid'])
-
- self.resource.subscriptions = subscriptions
- verify.verifyObject(iwokkel.IPubSubResource, self.resource)
- d = self.handleRequest(xml)
- d.addCallback(cb)
- return d
-
-
- def test_on_affiliations(self):
- """
- A subscriptions request should result in
- L{PubSubService.affiliations} being called and the result prepared
- for the response.
- """
-
- xml = """
-
-
-
-
-
- """
-
- def affiliations(request):
- affiliation = ('test', 'owner')
- return defer.succeed([affiliation])
-
- def cb(element):
- self.assertEqual('pubsub', element.name)
- self.assertEqual(NS_PUBSUB, element.uri)
- self.assertEqual(NS_PUBSUB, element.affiliations.uri)
- children = list(element.affiliations.elements())
- self.assertEqual(1, len(children))
- affiliation = children[0]
- self.assertEqual('affiliation', affiliation.name)
- self.assertEqual(NS_PUBSUB, affiliation.uri)
- self.assertEqual('test', affiliation['node'])
- self.assertEqual('owner', affiliation['affiliation'])
-
- self.resource.affiliations = affiliations
- verify.verifyObject(iwokkel.IPubSubResource, self.resource)
- d = self.handleRequest(xml)
- d.addCallback(cb)
- return d
-
-
- def test_on_create(self):
- """
- Replies to create node requests don't return the created node.
- """
-
- xml = """
-
-
-
-
-
- """
-
- def create(request):
- return defer.succeed(request.nodeIdentifier)
-
- def cb(element):
- self.assertIdentical(None, element)
-
- self.resource.create = create
- verify.verifyObject(iwokkel.IPubSubResource, self.resource)
- d = self.handleRequest(xml)
- d.addCallback(cb)
- return d
-
-
- def test_on_createChanged(self):
- """
- Replies to create node requests return the created node if changed.
- """
-
- xml = """
-
-
-
-
-
- """
-
- def create(request):
- return defer.succeed(u'myrenamednode')
-
- def cb(element):
- self.assertEqual('pubsub', element.name)
- self.assertEqual(NS_PUBSUB, element.uri)
- self.assertEqual(NS_PUBSUB, element.create.uri)
- self.assertEqual(u'myrenamednode',
- element.create.getAttribute('node'))
-
- self.resource.create = create
- verify.verifyObject(iwokkel.IPubSubResource, self.resource)
- d = self.handleRequest(xml)
- d.addCallback(cb)
- return d
-
-
- def test_on_createInstant(self):
- """
- Replies to create instant node requests return the created node.
- """
-
- xml = """
-
-
-
-
-
- """
-
- def create(request):
- return defer.succeed(u'random')
-
- def cb(element):
- self.assertEqual('pubsub', element.name)
- self.assertEqual(NS_PUBSUB, element.uri)
- self.assertEqual(NS_PUBSUB, element.create.uri)
- self.assertEqual(u'random', element.create.getAttribute('node'))
-
- self.resource.create = create
- verify.verifyObject(iwokkel.IPubSubResource, self.resource)
- d = self.handleRequest(xml)
- d.addCallback(cb)
- return d
-
-
- def test_on_createWithConfig(self):
- """
- On a node create with configuration request the Data Form is parsed and
- L{PubSubResource.create} is called with the passed options.
- """
-
- xml = """
-
-
-
-
-
-
- http://jabber.org/protocol/pubsub#node_config
-
- 0
- 1
-
-
-
-
- """
-
- def getConfigurationOptions():
- return {
- "pubsub#persist_items":
- {"type": "boolean",
- "label": "Persist items to storage"},
- "pubsub#deliver_payloads":
- {"type": "boolean",
- "label": "Deliver payloads with event notifications"}
- }
-
- def create(request):
- self.assertEqual({'pubsub#deliver_payloads': False,
- 'pubsub#persist_items': True},
- request.options.getValues())
- return defer.succeed(None)
-
- self.resource.getConfigurationOptions = getConfigurationOptions
- self.resource.create = create
- verify.verifyObject(iwokkel.IPubSubResource, self.resource)
- return self.handleRequest(xml)
-
-
- def test_on_default(self):
- """
- A default request returns default options filtered by available fields.
- """
-
- xml = """
-
-
-
-
-
- """
- fieldDefs = {
- "pubsub#persist_items":
- {"type": "boolean",
- "label": "Persist items to storage"},
- "pubsub#deliver_payloads":
- {"type": "boolean",
- "label": "Deliver payloads with event notifications"}
- }
-
- def getConfigurationOptions():
- return fieldDefs
-
- def default(request):
- return defer.succeed({'pubsub#persist_items': 'false',
- 'x-myfield': '1'})
-
- def cb(element):
- self.assertEquals('pubsub', element.name)
- self.assertEquals(NS_PUBSUB_OWNER, element.uri)
- self.assertEquals(NS_PUBSUB_OWNER, element.default.uri)
- form = data_form.Form.fromElement(element.default.x)
- self.assertEquals(NS_PUBSUB_NODE_CONFIG, form.formNamespace)
- form.typeCheck(fieldDefs)
- self.assertIn('pubsub#persist_items', form.fields)
- self.assertFalse(form.fields['pubsub#persist_items'].value)
- self.assertNotIn('x-myfield', form.fields)
-
- self.resource.getConfigurationOptions = getConfigurationOptions
- self.resource.default = default
- verify.verifyObject(iwokkel.IPubSubResource, self.resource)
- d = self.handleRequest(xml)
- d.addCallback(cb)
- return d
-
-
- def test_on_defaultUnknownNodeType(self):
- """
- Unknown node types yield non-acceptable.
-
- Both C{getConfigurationOptions} and C{default} must not be called.
- """
-
- xml = """
-
-
-
-
-
- http://jabber.org/protocol/pubsub#node_config
-
-
- unknown
-
-
-
-
-
-
- """
-
- def getConfigurationOptions():
- self.fail("Unexpected call to getConfigurationOptions")
-
- def default(request):
- self.fail("Unexpected call to default")
-
- def cb(result):
- self.assertEquals('not-acceptable', result.condition)
-
- self.resource.getConfigurationOptions = getConfigurationOptions
- self.resource.default = default
- verify.verifyObject(iwokkel.IPubSubResource, self.resource)
- d = self.handleRequest(xml)
- self.assertFailure(d, error.StanzaError)
- d.addCallback(cb)
- return d
-
-
- def test_on_configureGet(self):
- """
- On a node configuration get
- requestL{PubSubResource.configureGet} is called and results in a
- data form with the configuration.
- """
-
- xml = """
-
-
-
-
-
- """
-
- def getConfigurationOptions():
- return {
- "pubsub#persist_items":
- {"type": "boolean",
- "label": "Persist items to storage"},
- "pubsub#deliver_payloads":
- {"type": "boolean",
- "label": "Deliver payloads with event notifications"},
- "pubsub#owner":
- {"type": "jid-single",
- "label": "Owner of the node"}
- }
-
- def configureGet(request):
- return defer.succeed({'pubsub#deliver_payloads': '0',
- 'pubsub#persist_items': '1',
- 'pubsub#owner': JID('user@example.org'),
- 'x-myfield': 'a'})
-
- def cb(element):
- self.assertEqual('pubsub', element.name)
- self.assertEqual(NS_PUBSUB_OWNER, element.uri)
- self.assertEqual(NS_PUBSUB_OWNER, element.configure.uri)
- form = data_form.Form.fromElement(element.configure.x)
- self.assertEqual(NS_PUBSUB_NODE_CONFIG, form.formNamespace)
- fields = form.fields
-
- self.assertIn('pubsub#deliver_payloads', fields)
- field = fields['pubsub#deliver_payloads']
- self.assertEqual('boolean', field.fieldType)
- field.typeCheck()
- self.assertEqual(False, field.value)
-
- self.assertIn('pubsub#persist_items', fields)
- field = fields['pubsub#persist_items']
- self.assertEqual('boolean', field.fieldType)
- field.typeCheck()
- self.assertEqual(True, field.value)
-
- self.assertIn('pubsub#owner', fields)
- field = fields['pubsub#owner']
- self.assertEqual('jid-single', field.fieldType)
- field.typeCheck()
- self.assertEqual(JID('user@example.org'), field.value)
-
- self.assertNotIn('x-myfield', fields)
-
- self.resource.getConfigurationOptions = getConfigurationOptions
- self.resource.configureGet = configureGet
- verify.verifyObject(iwokkel.IPubSubResource, self.resource)
- d = self.handleRequest(xml)
- d.addCallback(cb)
- return d
-
-
- def test_on_configureSet(self):
- """
- On a node configuration set request the Data Form is parsed and
- L{PubSubResource.configureSet} is called with the passed options.
- """
-
- xml = """
-
-
-
-
-
- http://jabber.org/protocol/pubsub#node_config
-
- 0
- 1
-
-
-
-
- """
-
- def getConfigurationOptions():
- return {
- "pubsub#persist_items":
- {"type": "boolean",
- "label": "Persist items to storage"},
- "pubsub#deliver_payloads":
- {"type": "boolean",
- "label": "Deliver payloads with event notifications"}
- }
-
- def configureSet(request):
- self.assertEqual({'pubsub#deliver_payloads': False,
- 'pubsub#persist_items': True},
- request.options.getValues())
- return defer.succeed(None)
-
- self.resource.getConfigurationOptions = getConfigurationOptions
- self.resource.configureSet = configureSet
- verify.verifyObject(iwokkel.IPubSubResource, self.resource)
- return self.handleRequest(xml)
-
-
- def test_on_configureSetCancel(self):
- """
- The node configuration is cancelled,
- L{PubSubResource.configureSet} not called.
- """
-
- xml = """
-
-
-
-
-
- http://jabber.org/protocol/pubsub#node_config
-
-
-
-
-
- """
-
- def configureSet(request):
- self.fail("Unexpected call to setConfiguration")
-
- self.resource.configureSet = configureSet
- verify.verifyObject(iwokkel.IPubSubResource, self.resource)
- return self.handleRequest(xml)
-
-
- def test_on_configureSetIgnoreUnknown(self):
- """
- On a node configuration set request unknown fields should be ignored.
- """
-
- xml = """
-
-
-
-
-
- http://jabber.org/protocol/pubsub#node_config
-
- 0
- 1
-
-
-
-
- """
-
- def getConfigurationOptions():
- return {
- "pubsub#persist_items":
- {"type": "boolean",
- "label": "Persist items to storage"},
- "pubsub#deliver_payloads":
- {"type": "boolean",
- "label": "Deliver payloads with event notifications"}
- }
-
- def configureSet(request):
- self.assertEquals(['pubsub#deliver_payloads'],
- request.options.keys())
-
- self.resource.getConfigurationOptions = getConfigurationOptions
- self.resource.configureSet = configureSet
- verify.verifyObject(iwokkel.IPubSubResource, self.resource)
- return self.handleRequest(xml)
-
-
- def test_on_configureSetBadFormType(self):
- """
- On a node configuration set request unknown fields should be ignored.
- """
-
- xml = """
-
-
-
-
-
- http://jabber.org/protocol/pubsub#node_config
-
- 0
- 1
-
-
-
-
- """
-
- def cb(result):
- self.assertEquals('bad-request', result.condition)
- self.assertEqual("Unexpected form type 'result'", result.text)
-
- d = self.handleRequest(xml)
- self.assertFailure(d, error.StanzaError)
- d.addCallback(cb)
- return d
-
-
- def test_on_items(self):
- """
- On a items request, return all items for the given node.
- """
- xml = """
-
-
-
-
-
- """
-
- def items(request):
- return defer.succeed([pubsub.Item('current')])
-
- def cb(element):
- self.assertEqual(NS_PUBSUB, element.uri)
- self.assertEqual(NS_PUBSUB, element.items.uri)
- self.assertEqual(1, len(element.items.children))
- item = element.items.children[-1]
- self.assertTrue(domish.IElement.providedBy(item))
- self.assertEqual('item', item.name)
- self.assertEqual(NS_PUBSUB, item.uri)
- self.assertEqual('current', item['id'])
-
- self.resource.items = items
- verify.verifyObject(iwokkel.IPubSubResource, self.resource)
- d = self.handleRequest(xml)
- d.addCallback(cb)
- return d
-
-
- def test_on_retract(self):
- """
- A retract request should result in L{PubSubResource.retract}
- being called.
- """
-
- xml = """
-
-
-
-
-
-
-
-
- """
-
- def retract(request):
- return defer.succeed(None)
-
- self.resource.retract = retract
- verify.verifyObject(iwokkel.IPubSubResource, self.resource)
- return self.handleRequest(xml)
-
-
- def test_on_purge(self):
- """
- A purge request should result in L{PubSubResource.purge} being
- called.
- """
-
- xml = """
-
-
-
-
-
- """
-
- def purge(request):
- return defer.succeed(None)
-
- self.resource.purge = purge
- verify.verifyObject(iwokkel.IPubSubResource, self.resource)
- return self.handleRequest(xml)
-
-
- def test_on_delete(self):
- """
- A delete request should result in L{PubSubResource.delete} being
- called.
- """
-
- xml = """
-
-
-
-
-
- """
-
- def delete(request):
- return defer.succeed(None)
-
- self.resource.delete = delete
- verify.verifyObject(iwokkel.IPubSubResource, self.resource)
- return self.handleRequest(xml)
-
-
- def test_notifyPublish(self):
- """
- Publish notifications are sent to the subscribers.
- """
- subscriber = JID('user@example.org')
- subscriptions = [pubsub.Subscription('test', subscriber, 'subscribed')]
- items = [pubsub.Item('current')]
- notifications = [(subscriber, subscriptions, items)]
- self.service.notifyPublish(JID('pubsub.example.org'), 'test',
- notifications)
- message = self.stub.output[-1]
-
- self.assertEquals('message', message.name)
- self.assertIdentical(None, message.uri)
- self.assertEquals('user@example.org', message['to'])
- self.assertEquals('pubsub.example.org', message['from'])
- self.assertTrue(message.event)
- self.assertEquals(NS_PUBSUB_EVENT, message.event.uri)
- self.assertTrue(message.event.items)
- self.assertEquals(NS_PUBSUB_EVENT, message.event.items.uri)
- self.assertTrue(message.event.items.hasAttribute('node'))
- self.assertEquals('test', message.event.items['node'])
- itemElements = list(domish.generateElementsQNamed(
- message.event.items.children, 'item', NS_PUBSUB_EVENT))
- self.assertEquals(1, len(itemElements))
- self.assertEquals('current', itemElements[0].getAttribute('id'))
-
-
- def test_notifyPublishCollection(self):
- """
- Publish notifications are sent to the subscribers of collections.
-
- The node the item was published to is on the C{items} element, while
- the subscribed-to node is in the C{'Collections'} SHIM header.
- """
- subscriber = JID('user@example.org')
- subscriptions = [pubsub.Subscription('', subscriber, 'subscribed')]
- items = [pubsub.Item('current')]
- notifications = [(subscriber, subscriptions, items)]
- self.service.notifyPublish(JID('pubsub.example.org'), 'test',
- notifications)
- message = self.stub.output[-1]
-
- self.assertTrue(message.event.items.hasAttribute('node'))
- self.assertEquals('test', message.event.items['node'])
- headers = shim.extractHeaders(message)
- self.assertIn('Collection', headers)
- self.assertIn('', headers['Collection'])
-
-
- def test_notifyDelete(self):
- """
- Subscribers should be sent a delete notification.
- """
- subscriptions = [JID('user@example.org')]
- self.service.notifyDelete(JID('pubsub.example.org'), 'test',
- subscriptions)
- message = self.stub.output[-1]
-
- self.assertEquals('message', message.name)
- self.assertIdentical(None, message.uri)
- self.assertEquals('user@example.org', message['to'])
- self.assertEquals('pubsub.example.org', message['from'])
- self.assertTrue(message.event)
- self.assertEqual(NS_PUBSUB_EVENT, message.event.uri)
- self.assertTrue(message.event.delete)
- self.assertEqual(NS_PUBSUB_EVENT, message.event.delete.uri)
- self.assertTrue(message.event.delete.hasAttribute('node'))
- self.assertEqual('test', message.event.delete['node'])
-
-
- def test_notifyDeleteRedirect(self):
- """
- Subscribers should be sent a delete notification with redirect.
- """
- redirectURI = 'xmpp:pubsub.example.org?;node=test2'
- subscriptions = [JID('user@example.org')]
- self.service.notifyDelete(JID('pubsub.example.org'), 'test',
- subscriptions, redirectURI)
- message = self.stub.output[-1]
-
- self.assertEquals('message', message.name)
- self.assertIdentical(None, message.uri)
- self.assertEquals('user@example.org', message['to'])
- self.assertEquals('pubsub.example.org', message['from'])
- self.assertTrue(message.event)
- self.assertEqual(NS_PUBSUB_EVENT, message.event.uri)
- self.assertTrue(message.event.delete)
- self.assertEqual(NS_PUBSUB_EVENT, message.event.delete.uri)
- self.assertTrue(message.event.delete.hasAttribute('node'))
- self.assertEqual('test', message.event.delete['node'])
- self.assertTrue(message.event.delete.redirect)
- self.assertEqual(NS_PUBSUB_EVENT, message.event.delete.redirect.uri)
- self.assertTrue(message.event.delete.redirect.hasAttribute('uri'))
- self.assertEqual(redirectURI, message.event.delete.redirect['uri'])
-
-
- def test_on_subscriptionsGet(self):
- """
- Getting subscription options is not supported.
- """
-
- xml = """
-
-
-
-
-
- """
-
- def cb(result):
- self.assertEquals('feature-not-implemented', result.condition)
- self.assertEquals('unsupported', result.appCondition.name)
- self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri)
- self.assertEquals('manage-subscriptions',
- result.appCondition['feature'])
-
- d = self.handleRequest(xml)
- self.assertFailure(d, error.StanzaError)
- d.addCallback(cb)
- return d
-
-
- def test_on_subscriptionsSet(self):
- """
- Setting subscription options is not supported.
- """
-
- xml = """
-
-
-
-
-
- """
-
- def cb(result):
- self.assertEquals('feature-not-implemented', result.condition)
- self.assertEquals('unsupported', result.appCondition.name)
- self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri)
- self.assertEquals('manage-subscriptions',
- result.appCondition['feature'])
-
- d = self.handleRequest(xml)
- self.assertFailure(d, error.StanzaError)
- d.addCallback(cb)
- return d
-
-
- def test_on_affiliationsGet(self):
- """
- Getting node affiliations should have.
- """
-
- xml = """
-
-
-
-
-
- """
-
- def affiliationsGet(request):
- self.assertEquals('test', request.nodeIdentifier)
- return defer.succeed({JID('user@example.org'): 'owner'})
-
- def cb(element):
- self.assertEquals(u'pubsub', element.name)
- self.assertEquals(NS_PUBSUB_OWNER, element.uri)
- self.assertEquals(NS_PUBSUB_OWNER, element.affiliations.uri)
- self.assertEquals(u'test', element.affiliations[u'node'])
- children = list(element.affiliations.elements())
- self.assertEquals(1, len(children))
- affiliation = children[0]
- self.assertEquals(u'affiliation', affiliation.name)
- self.assertEquals(NS_PUBSUB_OWNER, affiliation.uri)
- self.assertEquals(u'user@example.org', affiliation[u'jid'])
- self.assertEquals(u'owner', affiliation[u'affiliation'])
-
- self.resource.affiliationsGet = affiliationsGet
- verify.verifyObject(iwokkel.IPubSubResource, self.resource)
- d = self.handleRequest(xml)
- d.addCallback(cb)
- return d
-
-
- def test_on_affiliationsGetEmptyNode(self):
- """
- Getting node affiliations without node should assume empty node.
- """
-
- xml = """
-
-
-
-
-
- """
-
- def affiliationsGet(request):
- self.assertEqual('', request.nodeIdentifier)
- return defer.succeed({})
-
- def cb(element):
- self.assertFalse(element.affiliations.hasAttribute(u'node'))
-
- self.resource.affiliationsGet = affiliationsGet
- verify.verifyObject(iwokkel.IPubSubResource, self.resource)
- d = self.handleRequest(xml)
- d.addCallback(cb)
- return d
-
-
- def test_on_affiliationsSet(self):
- """
- Setting node affiliations has the affiliations to be modified.
- """
-
- xml = """
-
-
-
-
-
-
-
- """
-
- def affiliationsSet(request):
- self.assertEquals(u'test', request.nodeIdentifier)
- otherJID = JID(u'other@example.org')
- self.assertIn(otherJID, request.affiliations)
- self.assertEquals(u'publisher', request.affiliations[otherJID])
-
- self.resource.affiliationsSet = affiliationsSet
- return self.handleRequest(xml)
-
-
- def test_on_affiliationsSetBareJID(self):
- """
- Affiliations are always on the bare JID.
- """
-
- xml = """
-
-
-
-
-
-
-
- """
-
- def affiliationsSet(request):
- otherJID = JID(u'other@example.org')
- self.assertIn(otherJID, request.affiliations)
-
- self.resource.affiliationsSet = affiliationsSet
- return self.handleRequest(xml)
-
-
- def test_on_affiliationsSetMultipleForSameEntity(self):
- """
- Setting node affiliations can only have one item per entity.
- """
-
- xml = """
-
-
-
-
-
-
-
-
- """
-
- def cb(result):
- self.assertEquals('bad-request', result.condition)
-
- d = self.handleRequest(xml)
- self.assertFailure(d, error.StanzaError)
- d.addCallback(cb)
- return d
-
-
- def test_on_affiliationsSetMissingJID(self):
- """
- Setting node affiliations must include a JID per affiliation.
- """
-
- xml = """
-
-
-
-
-
-
-
- """
-
- def cb(result):
- self.assertEquals('bad-request', result.condition)
-
- d = self.handleRequest(xml)
- self.assertFailure(d, error.StanzaError)
- d.addCallback(cb)
- return d
-
-
- def test_on_affiliationsSetMissingAffiliation(self):
- """
- Setting node affiliations must include an affiliation.
- """
-
- xml = """
-
-
-
-
-
-
-
- """
-
- def cb(result):
- self.assertEquals('bad-request', result.condition)
-
- d = self.handleRequest(xml)
- self.assertFailure(d, error.StanzaError)
- d.addCallback(cb)
- return d
-
-
-
-class PubSubServiceWithoutResourceTest(unittest.TestCase, TestableRequestHandlerMixin):
-
- def setUp(self):
- self.stub = XmlStreamStub()
- self.service = pubsub.PubSubService()
- self.service.send = self.stub.xmlstream.send
-
-
- def test_getDiscoInfo(self):
- """
- Test getDiscoInfo calls getNodeInfo and returns some minimal info.
- """
- def cb(info):
- discoInfo = disco.DiscoInfo()
- for item in info:
- discoInfo.append(item)
- self.assertIn(('pubsub', 'service'), discoInfo.identities)
- self.assertIn(disco.NS_DISCO_ITEMS, discoInfo.features)
-
- d = self.service.getDiscoInfo(JID('user@example.org/home'),
- JID('pubsub.example.org'), '')
- d.addCallback(cb)
- return d
-
-
- def test_publish(self):
- """
- Non-overridden L{PubSubService.publish} yields unsupported error.
- """
-
- xml = """
-
-
-
-
-
- """
-
- def cb(result):
- self.assertEquals('feature-not-implemented', result.condition)
- self.assertEquals('unsupported', result.appCondition.name)
- self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri)
- self.assertEquals('publish', result.appCondition['feature'])
-
- d = self.handleRequest(xml)
- self.assertFailure(d, error.StanzaError)
- d.addCallback(cb)
- return d
-
-
- def test_subscribe(self):
- """
- Non-overridden L{PubSubService.subscribe} yields unsupported error.
- """
-
- xml = """
-
-
-
-
-
- """
-
- def cb(result):
- self.assertEquals('feature-not-implemented', result.condition)
- self.assertEquals('unsupported', result.appCondition.name)
- self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri)
- self.assertEquals('subscribe', result.appCondition['feature'])
-
- d = self.handleRequest(xml)
- self.assertFailure(d, error.StanzaError)
- d.addCallback(cb)
- return d
-
-
- def test_unsubscribe(self):
- """
- Non-overridden L{PubSubService.unsubscribe} yields unsupported error.
- """
-
- xml = """
-
-
-
-
-
- """
-
- def cb(result):
- self.assertEquals('feature-not-implemented', result.condition)
- self.assertEquals('unsupported', result.appCondition.name)
- self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri)
- self.assertEquals('subscribe', result.appCondition['feature'])
-
- d = self.handleRequest(xml)
- self.assertFailure(d, error.StanzaError)
- d.addCallback(cb)
- return d
-
-
- def test_subscriptions(self):
- """
- Non-overridden L{PubSubService.subscriptions} yields unsupported error.
- """
-
- xml = """
-
-
-
-
-
- """
-
- def cb(result):
- self.assertEquals('feature-not-implemented', result.condition)
- self.assertEquals('unsupported', result.appCondition.name)
- self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri)
- self.assertEquals('retrieve-subscriptions',
- result.appCondition['feature'])
-
- d = self.handleRequest(xml)
- self.assertFailure(d, error.StanzaError)
- d.addCallback(cb)
- return d
-
-
- def test_affiliations(self):
- """
- Non-overridden L{PubSubService.affiliations} yields unsupported error.
- """
-
- xml = """
-
-
-
-
-
- """
-
- def cb(result):
- self.assertEquals('feature-not-implemented', result.condition)
- self.assertEquals('unsupported', result.appCondition.name)
- self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri)
- self.assertEquals('retrieve-affiliations',
- result.appCondition['feature'])
-
- d = self.handleRequest(xml)
- self.assertFailure(d, error.StanzaError)
- d.addCallback(cb)
- return d
-
-
- def test_create(self):
- """
- Non-overridden L{PubSubService.create} yields unsupported error.
- """
-
- xml = """
-
-
-
-
-
- """
-
- def cb(result):
- self.assertEquals('feature-not-implemented', result.condition)
- self.assertEquals('unsupported', result.appCondition.name)
- self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri)
- self.assertEquals('create-nodes', result.appCondition['feature'])
-
- d = self.handleRequest(xml)
- self.assertFailure(d, error.StanzaError)
- d.addCallback(cb)
- return d
-
-
- def test_getDefaultConfiguration(self):
- """
- Non-overridden L{PubSubService.getDefaultConfiguration} yields
- unsupported error.
- """
-
- xml = """
-
-
-
-
-
- """
-
- def cb(result):
- self.assertEquals('feature-not-implemented', result.condition)
- self.assertEquals('unsupported', result.appCondition.name)
- self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri)
- self.assertEquals('retrieve-default', result.appCondition['feature'])
-
- d = self.handleRequest(xml)
- self.assertFailure(d, error.StanzaError)
- d.addCallback(cb)
- return d
-
-
- def test_getConfiguration(self):
- """
- Non-overridden L{PubSubService.getConfiguration} yields unsupported
- error.
- """
-
- xml = """
-
-
-
-
-
- """
-
- def cb(result):
- self.assertEquals('feature-not-implemented', result.condition)
- self.assertEquals('unsupported', result.appCondition.name)
- self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri)
- self.assertEquals('config-node', result.appCondition['feature'])
-
- d = self.handleRequest(xml)
- self.assertFailure(d, error.StanzaError)
- d.addCallback(cb)
- return d
-
-
- def test_setConfiguration(self):
- """
- Non-overridden L{PubSubService.setConfiguration} yields unsupported
- error.
- """
-
- xml = """
-
-
-
-
-
- http://jabber.org/protocol/pubsub#node_config
-
- 0
- 1
-
-
-
-
- """
-
- def cb(result):
- self.assertEquals('feature-not-implemented', result.condition)
- self.assertEquals('unsupported', result.appCondition.name)
- self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri)
- self.assertEquals('config-node', result.appCondition['feature'])
-
- d = self.handleRequest(xml)
- self.assertFailure(d, error.StanzaError)
- d.addCallback(cb)
- return d
-
-
- def test_setConfigurationOptionsDict(self):
- """
- Options should be passed as a dictionary, not a form.
- """
-
- xml = """
-
-
-
-
-
- http://jabber.org/protocol/pubsub#node_config
-
- 0
- 1
-
-
-
-
- """
-
- def getConfigurationOptions():
- return {
- "pubsub#persist_items":
- {"type": "boolean",
- "label": "Persist items to storage"},
- "pubsub#deliver_payloads":
- {"type": "boolean",
- "label": "Deliver payloads with event notifications"}
- }
-
- def setConfiguration(requestor, service, nodeIdentifier, options):
- self.assertIn('pubsub#deliver_payloads', options)
- self.assertFalse(options['pubsub#deliver_payloads'])
- self.assertIn('pubsub#persist_items', options)
- self.assertTrue(options['pubsub#persist_items'])
-
- self.service.getConfigurationOptions = getConfigurationOptions
- self.service.setConfiguration = setConfiguration
- return self.handleRequest(xml)
-
-
- def test_items(self):
- """
- Non-overridden L{PubSubService.items} yields unsupported error.
- """
- xml = """
-
-
-
-
-
- """
-
- def cb(result):
- self.assertEquals('feature-not-implemented', result.condition)
- self.assertEquals('unsupported', result.appCondition.name)
- self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri)
- self.assertEquals('retrieve-items', result.appCondition['feature'])
-
- d = self.handleRequest(xml)
- self.assertFailure(d, error.StanzaError)
- d.addCallback(cb)
- return d
-
-
- def test_retract(self):
- """
- Non-overridden L{PubSubService.retract} yields unsupported error.
- """
- xml = """
-
-
-
-
-
-
-
-
- """
-
- def cb(result):
- self.assertEquals('feature-not-implemented', result.condition)
- self.assertEquals('unsupported', result.appCondition.name)
- self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri)
- self.assertEquals('retract-items', result.appCondition['feature'])
-
- d = self.handleRequest(xml)
- self.assertFailure(d, error.StanzaError)
- d.addCallback(cb)
- return d
-
-
- def test_purge(self):
- """
- Non-overridden L{PubSubService.purge} yields unsupported error.
- """
- xml = """
-
-
-
-
-
- """
-
- def cb(result):
- self.assertEquals('feature-not-implemented', result.condition)
- self.assertEquals('unsupported', result.appCondition.name)
- self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri)
- self.assertEquals('purge-nodes', result.appCondition['feature'])
-
- d = self.handleRequest(xml)
- self.assertFailure(d, error.StanzaError)
- d.addCallback(cb)
- return d
-
-
- def test_delete(self):
- """
- Non-overridden L{PubSubService.delete} yields unsupported error.
- """
- xml = """
-
-
-
-
-
- """
-
- def cb(result):
- self.assertEquals('feature-not-implemented', result.condition)
- self.assertEquals('unsupported', result.appCondition.name)
- self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri)
- self.assertEquals('delete-nodes', result.appCondition['feature'])
-
- d = self.handleRequest(xml)
- self.assertFailure(d, error.StanzaError)
- d.addCallback(cb)
- return d
-
-
- def test_unknown(self):
- """
- Unknown verb yields unsupported error.
- """
- xml = """
-
-
-
-
-
- """
-
- def cb(result):
- self.assertEquals('feature-not-implemented', result.condition)
- self.assertEquals('unsupported', result.appCondition.name)
- self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri)
-
- d = self.handleRequest(xml)
- self.assertFailure(d, error.StanzaError)
- d.addCallback(cb)
- return d
-
-
-
-class PubSubResourceTest(unittest.TestCase):
-
- def setUp(self):
- self.resource = pubsub.PubSubResource()
-
-
- def test_interface(self):
- """
- Do instances of L{pubsub.PubSubResource} provide L{iwokkel.IPubSubResource}?
- """
- verify.verifyObject(iwokkel.IPubSubResource, self.resource)
-
-
- def test_getNodes(self):
- """
- Default getNodes returns an empty list.
- """
- def cb(nodes):
- self.assertEquals([], nodes)
-
- d = self.resource.getNodes(JID('user@example.org/home'),
- JID('pubsub.example.org'),
- '')
- d.addCallback(cb)
- return d
-
-
- def test_publish(self):
- """
- Non-overridden L{PubSubResource.publish} yields unsupported
- error.
- """
-
- def cb(result):
- self.assertEquals('feature-not-implemented', result.condition)
- self.assertEquals('unsupported', result.appCondition.name)
- self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri)
- self.assertEquals('publish', result.appCondition['feature'])
-
- d = self.resource.publish(pubsub.PubSubRequest())
- self.assertFailure(d, error.StanzaError)
- d.addCallback(cb)
- return d
-
-
- def test_subscribe(self):
- """
- Non-overridden subscriptions yields unsupported error.
- """
-
- def cb(result):
- self.assertEquals('feature-not-implemented', result.condition)
- self.assertEquals('unsupported', result.appCondition.name)
- self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri)
- self.assertEquals('subscribe', result.appCondition['feature'])
-
- d = self.resource.subscribe(pubsub.PubSubRequest())
- self.assertFailure(d, error.StanzaError)
- d.addCallback(cb)
- return d
-
-
- def test_unsubscribe(self):
- """
- Non-overridden unsubscribe yields unsupported error.
- """
-
- def cb(result):
- self.assertEquals('feature-not-implemented', result.condition)
- self.assertEquals('unsupported', result.appCondition.name)
- self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri)
- self.assertEquals('subscribe', result.appCondition['feature'])
-
- d = self.resource.unsubscribe(pubsub.PubSubRequest())
- self.assertFailure(d, error.StanzaError)
- d.addCallback(cb)
- return d
-
-
- def test_subscriptions(self):
- """
- Non-overridden subscriptions yields unsupported error.
- """
-
- def cb(result):
- self.assertEquals('feature-not-implemented', result.condition)
- self.assertEquals('unsupported', result.appCondition.name)
- self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri)
- self.assertEquals('retrieve-subscriptions',
- result.appCondition['feature'])
-
- d = self.resource.subscriptions(pubsub.PubSubRequest())
- self.assertFailure(d, error.StanzaError)
- d.addCallback(cb)
- return d
-
-
- def test_affiliations(self):
- """
- Non-overridden affiliations yields unsupported error.
- """
-
- def cb(result):
- self.assertEquals('feature-not-implemented', result.condition)
- self.assertEquals('unsupported', result.appCondition.name)
- self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri)
- self.assertEquals('retrieve-affiliations',
- result.appCondition['feature'])
-
- d = self.resource.affiliations(pubsub.PubSubRequest())
- self.assertFailure(d, error.StanzaError)
- d.addCallback(cb)
- return d
-
-
- def test_create(self):
- """
- Non-overridden create yields unsupported error.
- """
-
- def cb(result):
- self.assertEquals('feature-not-implemented', result.condition)
- self.assertEquals('unsupported', result.appCondition.name)
- self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri)
- self.assertEquals('create-nodes', result.appCondition['feature'])
-
- d = self.resource.create(pubsub.PubSubRequest())
- self.assertFailure(d, error.StanzaError)
- d.addCallback(cb)
- return d
-
-
- def test_default(self):
- """
- Non-overridden default yields unsupported error.
- """
-
- def cb(result):
- self.assertEquals('feature-not-implemented', result.condition)
- self.assertEquals('unsupported', result.appCondition.name)
- self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri)
- self.assertEquals('retrieve-default',
- result.appCondition['feature'])
-
- d = self.resource.default(pubsub.PubSubRequest())
- self.assertFailure(d, error.StanzaError)
- d.addCallback(cb)
- return d
-
-
- def test_configureGet(self):
- """
- Non-overridden configureGet yields unsupported
- error.
- """
-
- def cb(result):
- self.assertEquals('feature-not-implemented', result.condition)
- self.assertEquals('unsupported', result.appCondition.name)
- self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri)
- self.assertEquals('config-node', result.appCondition['feature'])
-
- d = self.resource.configureGet(pubsub.PubSubRequest())
- self.assertFailure(d, error.StanzaError)
- d.addCallback(cb)
- return d
-
-
- def test_configureSet(self):
- """
- Non-overridden configureSet yields unsupported error.
- """
-
- def cb(result):
- self.assertEquals('feature-not-implemented', result.condition)
- self.assertEquals('unsupported', result.appCondition.name)
- self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri)
- self.assertEquals('config-node', result.appCondition['feature'])
-
- d = self.resource.configureSet(pubsub.PubSubRequest())
- self.assertFailure(d, error.StanzaError)
- d.addCallback(cb)
- return d
-
-
- def test_items(self):
- """
- Non-overridden items yields unsupported error.
- """
-
- def cb(result):
- self.assertEquals('feature-not-implemented', result.condition)
- self.assertEquals('unsupported', result.appCondition.name)
- self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri)
- self.assertEquals('retrieve-items', result.appCondition['feature'])
-
- d = self.resource.items(pubsub.PubSubRequest())
- self.assertFailure(d, error.StanzaError)
- d.addCallback(cb)
- return d
-
-
- def test_retract(self):
- """
- Non-overridden retract yields unsupported error.
- """
-
- def cb(result):
- self.assertEquals('feature-not-implemented', result.condition)
- self.assertEquals('unsupported', result.appCondition.name)
- self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri)
- self.assertEquals('retract-items', result.appCondition['feature'])
-
- d = self.resource.retract(pubsub.PubSubRequest())
- self.assertFailure(d, error.StanzaError)
- d.addCallback(cb)
- return d
-
-
- def test_purge(self):
- """
- Non-overridden purge yields unsupported error.
- """
-
- def cb(result):
- self.assertEquals('feature-not-implemented', result.condition)
- self.assertEquals('unsupported', result.appCondition.name)
- self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri)
- self.assertEquals('purge-nodes', result.appCondition['feature'])
-
- d = self.resource.purge(pubsub.PubSubRequest())
- self.assertFailure(d, error.StanzaError)
- d.addCallback(cb)
- return d
-
-
- def test_delete(self):
- """
- Non-overridden delete yields unsupported error.
- """
-
- def cb(result):
- self.assertEquals('feature-not-implemented', result.condition)
- self.assertEquals('unsupported', result.appCondition.name)
- self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri)
- self.assertEquals('delete-nodes', result.appCondition['feature'])
-
- d = self.resource.delete(pubsub.PubSubRequest())
- self.assertFailure(d, error.StanzaError)
- d.addCallback(cb)
- return d
-
-
- def test_affiliationsGet(self):
- """
- Non-overridden owner affiliations get yields unsupported error.
- """
-
- def cb(result):
- self.assertEquals('feature-not-implemented', result.condition)
- self.assertEquals('unsupported', result.appCondition.name)
- self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri)
- self.assertEquals('modify-affiliations',
- result.appCondition['feature'])
-
- d = self.resource.affiliationsGet(pubsub.PubSubRequest())
- self.assertFailure(d, error.StanzaError)
- d.addCallback(cb)
- return d
-
-
- def test_affiliationsSet(self):
- """
- Non-overridden owner affiliations set yields unsupported error.
- """
-
- def cb(result):
- self.assertEquals('feature-not-implemented', result.condition)
- self.assertEquals('unsupported', result.appCondition.name)
- self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri)
- self.assertEquals('modify-affiliations',
- result.appCondition['feature'])
-
- d = self.resource.affiliationsSet(pubsub.PubSubRequest())
- self.assertFailure(d, error.StanzaError)
- d.addCallback(cb)
- return d
diff --git a/src/tmp/wokkel/test/test_rsm.py b/src/tmp/wokkel/test/test_rsm.py
deleted file mode 100644
index 2311fa49..00000000
--- a/src/tmp/wokkel/test/test_rsm.py
+++ /dev/null
@@ -1,662 +0,0 @@
-# Copyright (c) Adrien Cossa.
-# See LICENSE for details.
-
-"""
-Tests for L{wokkel.rsm}.
-"""
-
-from zope.interface import verify
-
-from twisted.trial import unittest
-from twisted.words.xish import domish
-from twisted.words.protocols.jabber.jid import JID
-from twisted.words.protocols.jabber.xmlstream import toResponse
-from twisted.internet import defer
-
-from wokkel.generic import parseXml
-from wokkel import iwokkel
-from wokkel.test.helpers import XmlStreamStub, TestableRequestHandlerMixin
-
-from sat.tmp.wokkel import pubsub
-from sat.tmp.wokkel.rsm import NS_RSM, RSMRequest, RSMResponse, PubSubClient, PubSubService
-
-import uuid
-
-RSMResponse.__eq__ = lambda self, other: self.first == other.first and\
- self.last == other.last and\
- self.index == other.index and\
- self.count == other.count
-
-class RSMRequestTest(unittest.TestCase):
- """
- Tests for L{rsm.RSMRequest}.
- """
-
- def test___init__(self):
- """
- Fail to initialize a RSMRequest with wrong attribute values.
- """
- self.assertRaises(AssertionError, RSMRequest, index=371, after=u'test')
- self.assertRaises(AssertionError, RSMRequest, index=371, before=u'test')
- self.assertRaises(AssertionError, RSMRequest, before=117)
- self.assertRaises(AssertionError, RSMRequest, after=312)
- self.assertRaises(AssertionError, RSMRequest, after=u'117', before=u'312')
-
- def test_parse(self):
- """
- Parse a request element asking for the first page.
- """
- xml = """
-
- Pete
-
- 1
-
-
- """
- request = RSMRequest.fromElement(parseXml(xml))
- self.assertEqual(1, request.max)
- self.assertIdentical(None, request.index)
- self.assertIdentical(None, request.after)
- self.assertIdentical(None, request.before)
-
- def test_parseSecondPage(self):
- """
- Parse a request element asking for a next page.
- """
- xml = """
-
- Pete
-
- 3
- peterpan@neverland.lit
-
-
- """
- request = RSMRequest.fromElement(parseXml(xml))
- self.assertEqual(3, request.max)
- self.assertIdentical(None, request.index)
- self.assertEqual(u'peterpan@neverland.lit', request.after)
- self.assertIdentical(None, request.before)
-
- def test_parsePreviousPage(self):
- """
- Parse a request element asking for a previous page.
- """
- xml = """
-
- Pete
-
- 5
- peterpan@pixyland.org
-
-
- """
- request = RSMRequest.fromElement(parseXml(xml))
- self.assertEqual(5, request.max)
- self.assertIdentical(None, request.index)
- self.assertIdentical(None, request.after)
- self.assertEqual(u'peterpan@pixyland.org', request.before)
-
- def test_parseLastPage(self):
- """
- Parse a request element asking for the last page.
- """
- xml = """
-
- Pete
-
- 7
-
-
-
- """
- request = RSMRequest.fromElement(parseXml(xml))
- self.assertEqual(7, request.max)
- self.assertIdentical(None, request.index)
- self.assertIdentical(None, request.after)
- self.assertEqual('', request.before)
-
- def test_parseOutOfOrderPage(self):
- """
- Parse a request element asking for a page out of order.
- """
- xml = """
-
- Pete
-
- 9
- 371
-
-
- """
- request = RSMRequest.fromElement(parseXml(xml))
- self.assertEqual(9, request.max)
- self.assertEqual(371, request.index)
- self.assertIdentical(None, request.after)
- self.assertIdentical(None, request.before)
-
- def test_parseItemCount(self):
- """
- Parse a request element asking for the items count.
- """
- xml = """
-
- Pete
-
- 0
-
-
- """
- request = RSMRequest.fromElement(parseXml(xml))
- self.assertEqual(0, request.max)
- self.assertIdentical(None, request.index)
- self.assertIdentical(None, request.after)
- self.assertIdentical(None, request.before)
-
- def test_render(self):
- """
- Embed a page request in the element.
- """
- element = domish.Element(('jabber:iq:search', 'query'))
- element.addElement('items')['max_items'] = u'10'
- RSMRequest(1).render(element)
-
- self.assertEqual(u'10', element.items['max_items']) # not changed
-
- self.assertEqual(NS_RSM, element.set.uri)
- self.assertEqual(u'1', ''.join(element.set.max.children))
- self.assertIdentical(None, element.set.after)
- self.assertIdentical(None, element.set.before)
- self.assertIdentical(None, element.set.index)
-
- def test_renderPubSub(self):
- """
- Embed a page request in the pubsub element.
- """
- element = domish.Element((pubsub.NS_PUBSUB, 'pubsub'))
- element.addElement('items')['max_items'] = u'10'
- RSMRequest(3).render(element)
-
- self.assertEqual(u'10', element.items['max_items']) # not changed
-
- self.assertEqual(NS_RSM, element.set.uri)
- self.assertEqual(u'3', ''.join(element.set.max.children))
- self.assertIdentical(None, element.set.after)
- self.assertIdentical(None, element.set.before)
- self.assertIdentical(None, element.set.index)
-
- def test_renderItems(self):
- """
- Embed a page request in the element, specify items.
- """
- element = domish.Element(('jabber:iq:search', 'query'))
- RSMRequest(5, index=127).render(element)
- self.assertEqual(NS_RSM, element.set.uri)
- self.assertEqual(u'5', ''.join(element.set.max.children))
- self.assertIdentical(None, element.set.after)
- self.assertIdentical(None, element.set.before)
- self.assertEqual(u'127', ''.join(element.set.index.children))
-
- def test_renderAfter(self):
- """
- Embed a page request in the element, specify after.
- """
- element = domish.Element(('jabber:iq:search', 'query'))
- RSMRequest(5, after=u'test').render(element)
- self.assertEqual(NS_RSM, element.set.uri)
- self.assertEqual(u'5', ''.join(element.set.max.children))
- self.assertEqual(u'test', ''.join(element.set.after.children))
- self.assertIdentical(None, element.set.before)
- self.assertIdentical(None, element.set.index)
-
- def test_renderBefore(self):
- """
- Embed a page request in the element, specify before.
- """
- element = domish.Element(('jabber:iq:search', 'query'))
- RSMRequest(5, before=u'test').render(element)
- self.assertEqual(NS_RSM, element.set.uri)
- self.assertEqual(u'5', ''.join(element.set.max.children))
- self.assertIdentical(None, element.set.after)
- self.assertEqual(u'test', ''.join(element.set.before.children))
- self.assertIdentical(None, element.set.index)
-
-
-class RSMResponseTest(unittest.TestCase):
- """
- Tests for L{rsm.RSMResponse}.
- """
-
- def test___init__(self):
- """
- Fail to initialize a RSMResponse with wrong attribute values.
- """
- self.assertRaises(AssertionError, RSMResponse, index=127, first=u'127')
- self.assertRaises(AssertionError, RSMResponse, index=127, last=u'351')
-
- def test_parse(self):
- """
- Parse a response element returning a page.
- """
- xml = """
-
-
- stpeter@jabber.org
- peterpan@neverland.lit
- 800
-
-
- """
- response = RSMResponse.fromElement(parseXml(xml))
- self.assertEqual(800, response.count)
- self.assertEqual(20, response.index)
- self.assertEqual(u'stpeter@jabber.org', response.first)
- self.assertEqual(u'peterpan@neverland.lit', response.last)
-
- def test_parseEmptySet(self):
- """
- Parse a response element returning an empty set.
- """
- xml = """
-
-
- 800
-
-
- """
- response = RSMResponse.fromElement(parseXml(xml))
- self.assertEqual(800, response.count)
- self.assertIdentical(None, response.first)
- self.assertIdentical(None, response.last)
- self.assertIdentical(None, response.index)
-
- def test_render(self):
- """
- Embed a page response in the element.
- """
- element = domish.Element(('jabber:iq:search', 'query'))
- RSMResponse(u'stpeter@jabber.org', u'peterpan@neverland.lit', 20, 800).render(element)
-
- self.assertEqual(NS_RSM, element.set.uri)
- self.assertEqual(u'800', ''.join(element.set.count.children))
- self.assertEqual(u'stpeter@jabber.org',
- ''.join(element.set.first.children))
- self.assertEqual(u'peterpan@neverland.lit',
- ''.join(element.set.last.children))
- self.assertEqual(u'20', element.set.first['index'])
-
- def test_renderEmptySet(self):
- """
- Embed a page response in the element, for empty set.
- """
- element = domish.Element(('jabber:iq:search', 'query'))
- RSMResponse(count=800).render(element)
-
- self.assertEqual(NS_RSM, element.set.uri)
- self.assertEqual(u'800', ''.join(element.set.count.children))
- self.assertIdentical(None, element.set.first)
- self.assertIdentical(None, element.set.last)
-
-
-class PubSubClientTest(unittest.TestCase):
- """
- Tests for L{rsm.PubSubClient}.
- """
- timeout = 2
-
- def setUp(self):
- self.stub = XmlStreamStub()
- self.protocol = PubSubClient()
- self.protocol.xmlstream = self.stub.xmlstream
- self.protocol.connectionInitialized()
-
- def test_items(self):
- """
- Test sending items request to get the first page.
- """
- def cb(response):
- items, rsm = response
- self.assertEquals(2, len(items))
- self.assertEquals([item1, item2], items)
- self.assertEquals(rsm, RSMResponse('item1', 'item2', 0, 800))
-
- d = self.protocol.items(JID('pubsub.example.org'), 'test',
- rsm_request=RSMRequest(2))
- d.addCallback(cb)
-
- iq = self.stub.output[-1]
- self.assertEquals('pubsub.example.org', iq.getAttribute('to'))
- self.assertEquals('get', iq.getAttribute('type'))
- self.assertEquals('pubsub', iq.pubsub.name)
- self.assertEquals(pubsub.NS_PUBSUB, iq.pubsub.uri)
- children = list(domish.generateElementsQNamed(iq.pubsub.children,
- 'items', pubsub.NS_PUBSUB))
- self.assertEquals(1, len(children))
- child = children[0]
- self.assertEquals('test', child['node'])
-
- set_elts = list(domish.generateElementsQNamed(iq.pubsub.children,
- 'set', NS_RSM))
- self.assertEquals(1, len(set_elts))
- set_elt = set_elts[0]
- self.assertEquals(u'2', ''.join(set_elt.max.children))
-
- response = toResponse(iq, 'result')
- items = response.addElement((pubsub.NS_PUBSUB,
- 'pubsub')).addElement('items')
- items['node'] = 'test'
- item1 = items.addElement('item')
- item1['id'] = 'item1'
- item2 = items.addElement('item')
- item2['id'] = 'item2'
- RSMResponse(u'item1', u'item2', 0, 800).render(response.pubsub)
- self.stub.send(response)
-
- return d
-
- def test_itemsAfter(self):
- """
- Test sending items request to get the next page.
- """
- def cb(response):
- items, rsm = response
- self.assertEquals(2, len(items))
- self.assertEquals([item1, item2], items)
- self.assertEquals(rsm, RSMResponse('item3', 'item4', 2, 800))
-
- d = self.protocol.items(JID('pubsub.example.org'), 'test',
- rsm_request=RSMRequest(2, after=u'item2'))
- d.addCallback(cb)
-
- iq = self.stub.output[-1]
- self.assertEquals('pubsub.example.org', iq.getAttribute('to'))
- self.assertEquals('get', iq.getAttribute('type'))
- self.assertEquals('pubsub', iq.pubsub.name)
- self.assertEquals(pubsub.NS_PUBSUB, iq.pubsub.uri)
- children = list(domish.generateElementsQNamed(iq.pubsub.children,
- 'items', pubsub.NS_PUBSUB))
- self.assertEquals(1, len(children))
- child = children[0]
- self.assertEquals('test', child['node'])
-
- set_elts = list(domish.generateElementsQNamed(iq.pubsub.children,
- 'set', NS_RSM))
- self.assertEquals(1, len(set_elts))
- set_elt = set_elts[0]
- self.assertEquals(u'2', ''.join(set_elt.max.children))
- self.assertEquals(u'item2', ''.join(set_elt.after.children))
-
- response = toResponse(iq, 'result')
- items = response.addElement((pubsub.NS_PUBSUB,
- 'pubsub')).addElement('items')
- items['node'] = 'test'
- item1 = items.addElement('item')
- item1['id'] = 'item3'
- item2 = items.addElement('item')
- item2['id'] = 'item4'
- RSMResponse(u'item3', u'item4', 2, 800).render(response.pubsub)
- self.stub.send(response)
-
- return d
-
- def test_itemsBefore(self):
- """
- Test sending items request to get the previous page.
- """
- def cb(response):
- items, rsm = response
- self.assertEquals(2, len(items))
- self.assertEquals([item1, item2], items)
- self.assertEquals(rsm, RSMResponse('item1', 'item2', 0, 800))
-
- d = self.protocol.items(JID('pubsub.example.org'), 'test',
- rsm_request=RSMRequest(2, before=u'item3'))
- d.addCallback(cb)
-
- iq = self.stub.output[-1]
- self.assertEquals('pubsub.example.org', iq.getAttribute('to'))
- self.assertEquals('get', iq.getAttribute('type'))
- self.assertEquals('pubsub', iq.pubsub.name)
- self.assertEquals(pubsub.NS_PUBSUB, iq.pubsub.uri)
- children = list(domish.generateElementsQNamed(iq.pubsub.children,
- 'items', pubsub.NS_PUBSUB))
- self.assertEquals(1, len(children))
- child = children[0]
- self.assertEquals('test', child['node'])
-
- set_elts = list(domish.generateElementsQNamed(iq.pubsub.children,
- 'set', NS_RSM))
- self.assertEquals(1, len(set_elts))
- set_elt = set_elts[0]
- self.assertEquals(u'2', ''.join(set_elt.max.children))
- self.assertEquals(u'item3', ''.join(set_elt.before.children))
-
- response = toResponse(iq, 'result')
- items = response.addElement((pubsub.NS_PUBSUB,
- 'pubsub')).addElement('items')
- items['node'] = 'test'
- item1 = items.addElement('item')
- item1['id'] = 'item1'
- item2 = items.addElement('item')
- item2['id'] = 'item2'
- RSMResponse(u'item1', u'item2', 0, 800).render(response.pubsub)
- self.stub.send(response)
-
- return d
-
- def test_itemsIndex(self):
- """
- Test sending items request to get a page out of order.
- """
- def cb(response):
- items, rsm = response
- self.assertEquals(3, len(items))
- self.assertEquals([item1, item2, item3], items)
- self.assertEquals(rsm, RSMResponse('item4', 'item6', 3, 800))
-
- d = self.protocol.items(JID('pubsub.example.org'), 'test',
- rsm_request=RSMRequest(3, index=3))
- d.addCallback(cb)
-
- iq = self.stub.output[-1]
- self.assertEquals('pubsub.example.org', iq.getAttribute('to'))
- self.assertEquals('get', iq.getAttribute('type'))
- self.assertEquals('pubsub', iq.pubsub.name)
- self.assertEquals(pubsub.NS_PUBSUB, iq.pubsub.uri)
- children = list(domish.generateElementsQNamed(iq.pubsub.children,
- 'items', pubsub.NS_PUBSUB))
- self.assertEquals(1, len(children))
- child = children[0]
- self.assertEquals('test', child['node'])
-
- set_elts = list(domish.generateElementsQNamed(iq.pubsub.children,
- 'set', NS_RSM))
- self.assertEquals(1, len(set_elts))
- set_elt = set_elts[0]
- self.assertEquals(u'3', ''.join(set_elt.max.children))
- self.assertEquals(u'3', ''.join(set_elt.index.children))
-
- response = toResponse(iq, 'result')
- items = response.addElement((pubsub.NS_PUBSUB,
- 'pubsub')).addElement('items')
- items['node'] = 'test'
- item1 = items.addElement('item')
- item1['id'] = 'item4'
- item2 = items.addElement('item')
- item2['id'] = 'item5'
- item3 = items.addElement('item')
- item3['id'] = 'item6'
- RSMResponse(u'item4', u'item6', 3, 800).render(response.pubsub)
- self.stub.send(response)
-
- return d
-
- def test_itemsCount(self):
- """
- Test sending items request to count them.
- """
- def cb(response):
- items, rsm = response
- self.assertEquals(0, len(items))
- self.assertEquals(rsm, RSMResponse(count=800))
-
- d = self.protocol.items(JID('pubsub.example.org'), 'test',
- rsm_request=RSMRequest(0))
- d.addCallback(cb)
-
- iq = self.stub.output[-1]
- self.assertEquals('pubsub.example.org', iq.getAttribute('to'))
- self.assertEquals('get', iq.getAttribute('type'))
- self.assertEquals('pubsub', iq.pubsub.name)
- self.assertEquals(pubsub.NS_PUBSUB, iq.pubsub.uri)
- children = list(domish.generateElementsQNamed(iq.pubsub.children,
- 'items', pubsub.NS_PUBSUB))
- self.assertEquals(1, len(children))
- child = children[0]
- self.assertEquals('test', child['node'])
-
- set_elts = list(domish.generateElementsQNamed(iq.pubsub.children,
- 'set', NS_RSM))
- self.assertEquals(1, len(set_elts))
- set_elt = set_elts[0]
- self.assertEquals(u'0', ''.join(set_elt.max.children))
-
- response = toResponse(iq, 'result')
- response.addElement((pubsub.NS_PUBSUB, 'pubsub'))
- RSMResponse(count=800).render(response.pubsub)
- self.stub.send(response)
-
- return d
-
-
-class PubSubServiceTest(unittest.TestCase, TestableRequestHandlerMixin):
-
- def setUp(self):
- self.stub = XmlStreamStub()
- self.resource = pubsub.PubSubResource()
- self.service = PubSubService(self.resource)
- self.service.send = self.stub.xmlstream.send
-
- def test_on_items(self):
- """
- On a items request, return the first item for the given node.
- """
- xml = """
-
-
-
-
-
- 1
-
-
- """
-
- def items(request):
- rsm = RSMResponse(u'item', u'item', 0, 800).toElement()
- return defer.succeed([pubsub.Item('current'), rsm])
-
- def cb(element):
- self.assertEqual(pubsub.NS_PUBSUB, element.uri)
- self.assertEqual(pubsub.NS_PUBSUB, element.items.uri)
- self.assertEqual(1, len(element.items.children))
- item = element.items.children[-1]
- self.assertTrue(domish.IElement.providedBy(item))
- self.assertEqual('item', item.name)
- self.assertEqual(pubsub.NS_PUBSUB, item.uri)
- self.assertEqual('current', item['id'])
- self.assertEqual(NS_RSM, element.set.uri)
- self.assertEqual('800', ''.join(element.set.count.children))
- self.assertEqual('0', element.set.first['index'])
- self.assertEqual('item', ''.join(element.set.first.children))
- self.assertEqual('item', ''.join(element.set.last.children))
-
- self.resource.items = items
- verify.verifyObject(iwokkel.IPubSubResource, self.resource)
- d = self.handleRequest(xml)
- d.addCallback(cb)
- return d
-
- def test_on_itemsIndex(self):
- """
- On a items request, return some items out of order for the given node.
- """
- xml = """
-
-
-
-
-
- 2
- 3
-
-
- """
-
- def items(request):
- rsm = RSMResponse(u'i1', u'i2', 3, 800).toElement()
- return defer.succeed([pubsub.Item('i1'), pubsub.Item('i2'), rsm])
-
- def cb(element):
- self.assertEqual(pubsub.NS_PUBSUB, element.uri)
- self.assertEqual(pubsub.NS_PUBSUB, element.items.uri)
- self.assertEqual(2, len(element.items.children))
- item = element.items.children[0]
- self.assertTrue(domish.IElement.providedBy(item))
- self.assertEqual('item', item.name)
- self.assertEqual(pubsub.NS_PUBSUB, item.uri)
- self.assertEqual('i1', item['id'])
- item = element.items.children[1]
- self.assertTrue(domish.IElement.providedBy(item))
- self.assertEqual('item', item.name)
- self.assertEqual(pubsub.NS_PUBSUB, item.uri)
- self.assertEqual('i2', item['id'])
- self.assertEqual(NS_RSM, element.set.uri)
- self.assertEqual('800', ''.join(element.set.count.children))
- self.assertEqual('3', element.set.first['index'])
- self.assertEqual('i1', ''.join(element.set.first.children))
- self.assertEqual('i2', ''.join(element.set.last.children))
-
- self.resource.items = items
- verify.verifyObject(iwokkel.IPubSubResource, self.resource)
- d = self.handleRequest(xml)
- d.addCallback(cb)
- return d
-
- def test_on_itemsCount(self):
- """
- On a items request, return the items count.
- """
- xml = """
-
-
-
-
-
- 0
-
-
- """
-
- def items(request):
- rsm = RSMResponse(count=800).toElement()
- return defer.succeed([rsm])
-
- def cb(element):
- self.assertEqual(pubsub.NS_PUBSUB, element.uri)
- self.assertEqual(pubsub.NS_PUBSUB, element.items.uri)
- self.assertEqual(0, len(element.items.children))
- self.assertEqual(NS_RSM, element.set.uri)
- self.assertEqual('800', ''.join(element.set.count.children))
- self.assertEqual(None, element.set.first)
- self.assertEqual(None, element.set.last)
-
- self.resource.items = items
- verify.verifyObject(iwokkel.IPubSubResource, self.resource)
- d = self.handleRequest(xml)
- d.addCallback(cb)
- return d