From 37b571c55ab00b3107a480027f0ba212831bf7ed Mon Sep 17 00:00:00 2001 From: Nathan Fritz Date: Wed, 21 Apr 2010 23:51:37 -0700 Subject: added pubsub#event stanzas, multi-subtypes iterable stanzas, pubsub#event test coverage --- sleekxmpp/plugins/stanza_pubsub.py | 133 ++++++++++++++++++++++++++++++++----- sleekxmpp/xmlstream/stanzabase.py | 22 ++++-- tests/test_pubsubstanzas.py | 127 +++++++++++++++++++++++++++++++++++ 3 files changed, 260 insertions(+), 22 deletions(-) diff --git a/sleekxmpp/plugins/stanza_pubsub.py b/sleekxmpp/plugins/stanza_pubsub.py index 13345947..6ed84f1e 100644 --- a/sleekxmpp/plugins/stanza_pubsub.py +++ b/sleekxmpp/plugins/stanza_pubsub.py @@ -45,7 +45,7 @@ class Affiliations(ElementBase): interfaces = set(tuple()) plugin_attrib_map = {} plugin_tag_map = {} - subitem = Affiliation + subitem = (Affiliation,) def append(self, affiliation): if not isinstance(affiliation, Affiliation): @@ -64,11 +64,11 @@ class Subscription(ElementBase): plugin_attrib_map = {} plugin_tag_map = {} - def setJid(self, value): - self._setAttr('jid', str(value)) + def setjid(self, value): + self._setattr('jid', str(value)) - def getJid(self): - return JID(self._getAttr('jid')) + def getjid(self): + return jid(self._getattr('jid')) stanzaPlugin(Pubsub, Subscription) @@ -79,7 +79,7 @@ class Subscriptions(ElementBase): interfaces = set(tuple()) plugin_attrib_map = {} plugin_tag_map = {} - subitem = Subscription + subitem = (Subscription,) def __init__(self, *args, **kwargs): ElementBase.__init__(self, *args, **kwargs) @@ -176,7 +176,7 @@ class Items(ElementBase): interfaces = set(tuple()) plugin_attrib_map = {} plugin_tag_map = {} - subitem = Item + subitem = (Item,) stanzaPlugin(Pubsub, Items) @@ -212,7 +212,7 @@ class Publish(Items): interfaces = set(('node',)) plugin_attrib_map = {} plugin_tag_map = {} - subitem = Item + subitem = (Item,) stanzaPlugin(Pubsub, Publish) @@ -238,7 +238,7 @@ class Unsubscribe(ElementBase): self._setAttr('jid', str(value)) def getJid(self): - return JID(self._getAttr('from')) + return JID(self._getAttr('jid')) class Subscribe(ElementBase): namespace = 'http://jabber.org/protocol/pubsub' @@ -433,7 +433,7 @@ class OwnerRedirect(ElementBase): self._setAttr('jid', str(value)) def getJid(self): - return JID(self._getAttr('from')) + return JID(self._getAttr('jid')) stanzaPlugin(OwnerDelete, OwnerRedirect) @@ -475,22 +475,123 @@ class Event(ElementBase): stanzaPlugin(Message, Event) +class EventItem(ElementBase): + namespace = 'http://jabber.org/protocol/pubsub#event' + name = 'item' + plugin_attrib = 'item' + interfaces = set(('id', 'payload')) + plugin_attrib_map = {} + plugin_tag_map = {} + + def setPayload(self, value): + self.xml.append(value) + + def getPayload(self): + childs = self.xml.getchildren() + if len(childs) > 0: + return childs[0] + + def delPayload(self): + for child in self.xml.getchildren(): + self.xml.remove(child) + + +class EventRetract(ElementBase): + namespace = 'http://jabber.org/protocol/pubsub#event' + name = 'retract' + plugin_attrib = 'retract' + interfaces = set(('id',)) + plugin_attrib_map = {} + plugin_tag_map = {} + class EventItems(ElementBase): namespace = 'http://jabber.org/protocol/pubsub#event' name = 'items' plugin_attrib = 'items' - interfaces = set(tuple()) + interfaces = set(('node',)) plugin_attrib_map = {} plugin_tag_map = {} + subitem = (EventItem, EventRetract) stanzaPlugin(Event, EventItems) -class EventItem(ElementBase): +class EventCollection(ElementBase): namespace = 'http://jabber.org/protocol/pubsub#event' - name = 'item' - plugin_attrib = 'item' - interfaces = set(tuple()) + name = 'collection' + plugin_attrib = name + interfaces = set(('node',)) plugin_attrib_map = {} plugin_tag_map = {} -stanzaPlugin(Event, EventItems) +stanzaPlugin(Event, EventCollection) + +class EventAssociate(ElementBase): + namespace = 'http://jabber.org/protocol/pubsub#event' + name = 'associate' + plugin_attrib = name + interfaces = set(('node',)) + plugin_attrib_map = {} + plugin_tag_map = {} + +stanzaPlugin(EventCollection, EventAssociate) + +class EventDisassociate(ElementBase): + namespace = 'http://jabber.org/protocol/pubsub#event' + name = 'disassociate' + plugin_attrib = name + interfaces = set(('node',)) + plugin_attrib_map = {} + plugin_tag_map = {} + +stanzaPlugin(EventCollection, EventDisassociate) + +class EventConfiguration(ElementBase): + namespace = 'http://jabber.org/protocol/pubsub#event' + name = 'configuration' + plugin_attrib = name + interfaces = set(('node', 'config')) + plugin_attrib_map = {} + plugin_tag_map = {} + + def getConfig(self): + config = self.xml.find('{jabber:x:data}x') + form = xep_0004.Form() + if config is not None: + form.fromXML(config) + return form + + def setConfig(self, value): + self.xml.append(value.getXML()) + return self + + def delConfig(self): + config = self.xml.find('{jabber:x:data}x') + self.xml.remove(config) + +stanzaPlugin(Event, EventConfiguration) + +class EventPurge(ElementBase): + namespace = 'http://jabber.org/protocol/pubsub#event' + name = 'purge' + plugin_attrib = name + interfaces = set(('node',)) + plugin_attrib_map = {} + plugin_tag_map = {} + +stanzaPlugin(Event, EventPurge) + +class EventSubscription(ElementBase): + namespace = 'http://jabber.org/protocol/pubsub#event' + name = 'subscription' + plugin_attrib = name + interfaces = set(('node','expiry', 'jid', 'subid', 'subscription')) + plugin_attrib_map = {} + plugin_tag_map = {} + + def setJid(self, value): + self._setAttr('jid', str(value)) + + def getJid(self): + return JID(self._getAttr('jid')) + +stanzaPlugin(Event, EventSubscription) diff --git a/sleekxmpp/xmlstream/stanzabase.py b/sleekxmpp/xmlstream/stanzabase.py index f72aa6e2..ae9e9df7 100644 --- a/sleekxmpp/xmlstream/stanzabase.py +++ b/sleekxmpp/xmlstream/stanzabase.py @@ -60,8 +60,11 @@ class ElementBase(tostring.ToString): for child in self.xml.getchildren(): if child.tag in self.plugin_tag_map: self.plugins[self.plugin_tag_map[child.tag].plugin_attrib] = self.plugin_tag_map[child.tag](xml=child, parent=self) - if self.subitem is not None and child.tag == "{%s}%s" % (self.subitem.namespace, self.subitem.name): - self.iterables.append(self.subitem(xml=child, parent=self)) + if self.subitem is not None: + for sub in self.subitem: + if child.tag == "{%s}%s" % (sub.namespace, sub.name): + self.iterables.append(sub(xml=child, parent=self)) + break @property @@ -263,7 +266,10 @@ class ElementBase(tostring.ToString): for pluginkey in self.plugins: out[pluginkey] = self.plugins[pluginkey].getValues() if self.iterables: - iterables = [x.getValues() for x in self.iterables] + iterables = [] + for stanza in self.iterables: + iterables.append(stanza.getValues()) + iterables[-1].update({'__childtag__': "{%s}%s" % (stanza.namespace, stanza.name)}) out['substanzas'] = iterables return out @@ -271,9 +277,13 @@ class ElementBase(tostring.ToString): for interface in attrib: if interface == 'substanzas': for subdict in attrib['substanzas']: - sub = self.subitem(parent=self) - sub.setValues(subdict) - self.iterables.append(sub) + if '__childtag__' in subdict: + for subclass in self.subitem: + if subdict['__childtag__'] == "{%s}%s" % (subclass.namespace, subclass.name): + sub = subclass(parent=self) + sub.setValues(subdict) + self.iterables.append(sub) + break elif interface in self.interfaces: self[interface] = attrib[interface] elif interface in self.plugin_attrib_map and interface not in self.plugins: diff --git a/tests/test_pubsubstanzas.py b/tests/test_pubsubstanzas.py index 2d1bf3b7..5353f907 100644 --- a/tests/test_pubsubstanzas.py +++ b/tests/test_pubsubstanzas.py @@ -1,6 +1,7 @@ import unittest from xml.etree import cElementTree as ET from sleekxmpp.xmlstream.matcher.stanzapath import StanzaPath +from . import xmlcompare class testpubsubstanzas(unittest.TestCase): @@ -169,4 +170,130 @@ class testpubsubstanzas(unittest.TestCase): config = iq['pubsub']['configure']['config'] self.failUnless(config.getValues() != {}) + def testItemEvent(self): + """Testing message/pubsub_event/items/item""" + msg = self.ps.Message() + item = self.ps.EventItem() + pl = ET.Element('{http://netflint.net/protocol/test}test', {'failed':'3', 'passed':'24'}) + item['payload'] = pl + item['id'] = 'abc123' + msg['pubsub_event']['items'].append(item) + msg['pubsub_event']['items']['node'] = 'cheese' + msg['type'] = 'normal' + xmlstring = """""" + msg2 = self.ps.Message(None, self.ps.ET.fromstring(xmlstring)) + msg3 = self.ps.Message() + msg3.setValues(msg2.getValues()) + self.failUnless(xmlstring == str(msg) == str(msg2) == str(msg3)) + + def testItemsEvent(self): + """Testing multiple message/pubsub_event/items/item""" + msg = self.ps.Message() + item = self.ps.EventItem() + item2 = self.ps.EventItem() + pl = ET.Element('{http://netflint.net/protocol/test}test', {'failed':'3', 'passed':'24'}) + pl2 = ET.Element('{http://netflint.net/protocol/test-other}test', {'total':'27', 'failed':'3'}) + item2['payload'] = pl2 + item['payload'] = pl + item['id'] = 'abc123' + item2['id'] = '123abc' + msg['pubsub_event']['items'].append(item) + msg['pubsub_event']['items'].append(item2) + msg['pubsub_event']['items']['node'] = 'cheese' + msg['type'] = 'normal' + xmlstring = """""" + msg2 = self.ps.Message(None, self.ps.ET.fromstring(xmlstring)) + msg3 = self.ps.Message() + msg3.setValues(msg2.getValues()) + self.failUnless(xmlstring == str(msg) == str(msg2) == str(msg3)) + + def testItemsEvent(self): + """Testing message/pubsub_event/items/item & retract mix""" + msg = self.ps.Message() + item = self.ps.EventItem() + item2 = self.ps.EventItem() + pl = ET.Element('{http://netflint.net/protocol/test}test', {'failed':'3', 'passed':'24'}) + pl2 = ET.Element('{http://netflint.net/protocol/test-other}test', {'total':'27', 'failed':'3'}) + item2['payload'] = pl2 + retract = self.ps.EventRetract() + retract['id'] = 'aabbcc' + item['payload'] = pl + item['id'] = 'abc123' + item2['id'] = '123abc' + msg['pubsub_event']['items'].append(item) + msg['pubsub_event']['items'].append(retract) + msg['pubsub_event']['items'].append(item2) + msg['pubsub_event']['items']['node'] = 'cheese' + msg['type'] = 'normal' + xmlstring = """""" + msg2 = self.ps.Message(None, self.ps.ET.fromstring(xmlstring)) + msg3 = self.ps.Message() + msg3.setValues(msg2.getValues()) + self.failUnless(xmlstring == str(msg) == str(msg2) == str(msg3)) + + def testCollectionAssociate(self): + """Testing message/pubsub_event/collection/associate""" + msg = self.ps.Message() + msg['pubsub_event']['collection']['associate']['node'] = 'cheese' + msg['pubsub_event']['collection']['node'] = 'cheeseburger' + msg['type'] = 'headline' + xmlstring = """""" + msg2 = self.ps.Message(None, self.ps.ET.fromstring(xmlstring)) + msg3 = self.ps.Message() + msg3.setValues(msg2.getValues()) + self.failUnless(xmlstring == str(msg) == str(msg2) == str(msg3)) + + def testCollectionDisassociate(self): + """Testing message/pubsub_event/collection/disassociate""" + msg = self.ps.Message() + msg['pubsub_event']['collection']['disassociate']['node'] = 'cheese' + msg['pubsub_event']['collection']['node'] = 'cheeseburger' + msg['type'] = 'headline' + xmlstring = """""" + msg2 = self.ps.Message(None, self.ps.ET.fromstring(xmlstring)) + msg3 = self.ps.Message() + msg3.setValues(msg2.getValues()) + self.failUnless(xmlstring == str(msg) == str(msg2) == str(msg3)) + + def testEventConfiguration(self): + """Testing message/pubsub_event/configuration/config""" + msg = self.ps.Message() + from sleekxmpp.plugins import xep_0004 + form = xep_0004.Form() + form.addField('pubsub#title', ftype='text-single', value='This thing is awesome') + msg['pubsub_event']['configuration']['node'] = 'cheese' + msg['pubsub_event']['configuration']['config'] = form + msg['type'] = 'headline' + xmlstring = """This thing is awesome""" + msg2 = self.ps.Message(None, self.ps.ET.fromstring(xmlstring)) + msg3 = self.ps.Message() + msg3.setValues(msg2.getValues()) + self.failUnless(xmlstring == str(msg) == str(msg2) == str(msg3)) + + def testEventPurge(self): + """Testing message/pubsub_event/purge""" + msg = self.ps.Message() + msg['pubsub_event']['purge']['node'] = 'pickles' + msg['type'] = 'headline' + xmlstring = """""" + msg2 = self.ps.Message(None, self.ps.ET.fromstring(xmlstring)) + msg3 = self.ps.Message() + msg3.setValues(msg2.getValues()) + self.failUnless(xmlstring == str(msg) == str(msg2) == str(msg3)) + + def testEventSubscription(self): + """Testing message/pubsub_event/subscription""" + msg = self.ps.Message() + msg['pubsub_event']['subscription']['node'] = 'pickles' + msg['pubsub_event']['subscription']['jid'] = 'fritzy@netflint.net/test' + msg['pubsub_event']['subscription']['subid'] = 'aabb1122' + msg['pubsub_event']['subscription']['subscription'] = 'subscribed' + msg['pubsub_event']['subscription']['expiry'] = 'presence' + msg['type'] = 'headline' + xmlstring = """""" + msg2 = self.ps.Message(None, self.ps.ET.fromstring(xmlstring)) + msg3 = self.ps.Message() + msg3.setValues(msg2.getValues()) + self.failUnless(xmlcompare.comparemany([xmlstring, str(msg), str(msg2), str(msg3)])) + suite = unittest.TestLoader().loadTestsFromTestCase(testpubsubstanzas) -- cgit v1.2.3