changeset 707:890fbf2d7fdd

plugin XEP-0277, groupblog: rich text management for receiving microblogs
author Goffi <goffi@goffi.org>
date Thu, 14 Nov 2013 18:36:02 +0100
parents 80e9d3ecb272
children 6aa71c853bf5
files src/plugins/plugin_misc_groupblog.py src/plugins/plugin_xep_0277.py
diffstat 2 files changed, 63 insertions(+), 21 deletions(-) [+]
line wrap: on
line diff
--- a/src/plugins/plugin_misc_groupblog.py	Thu Nov 14 18:35:51 2013 +0100
+++ b/src/plugins/plugin_misc_groupblog.py	Thu Nov 14 18:36:02 2013 +0100
@@ -176,22 +176,30 @@
                     or event_host[-len(origin_host):] != origin_host):
                 warning("Host incoherence between %s and %s (hack attempt ?)" % (unicode(event.sender),
                                                                                  unicode(publisher)))
-                return
+                return False
 
             client = self.host.getClient(profile)
 
-            for gbdata in self._itemsConstruction(event.items, publisher, client):
-                self.host.bridge.personalEvent(publisher.full(), "MICROBLOG", gbdata, profile)
+            def gbdataManagementMicroblog(gbdata):
+                for gbdatum in gbdata:
+                    self.host.bridge.personalEvent(publisher.full(), "MICROBLOG", gbdatum, profile)
+
+            d = self._itemsConstruction(event.items, publisher, client)
+            d.addCallback(gbdataManagementMicroblog)
             return False
 
         elif event.nodeIdentifier.startswith(NS_COMMENT_PREFIX):
             # Comment
-            for microblog_data in self._handleCommentsItems(event.items, event.sender, event.nodeIdentifier):
-                publisher = None # FIXME: see below (_handleCommentsItems)
-                self.host.bridge.personalEvent(publisher.full() if publisher else microblog_data["author"], "MICROBLOG", microblog_data, profile)
+            def gbdataManagementComments(gbdata):
+                for gbdatum in gbdata:
+                    publisher = None # FIXME: see below (_handleCommentsItems)
+                    self.host.bridge.personalEvent(publisher.full() if publisher else gbdatum["author"], "MICROBLOG", gbdatum, profile)
+            d = self._handleCommentsItems(event.items, event.sender, event.nodeIdentifier)
+            d.addCallback(gbdataManagementComments)
             return False
         return True
 
+    @defer.inlineCallbacks
     def _handleCommentsItems(self, items, service, node_identifier):
         """ Convert comments items to groupblog data, and send them as signals
         @param items: comments items
@@ -204,12 +212,12 @@
             publisher = "" # FIXME: publisher attribute for item in SàT pubsub is not managed yet, so
                            #        publisher is not checked and can be easily spoofed. This need to be fixed
                            #        quickly.
-            microblog_data = self.item2gbdata(item, "comment")
+            microblog_data = yield self.item2gbdata(item, "comment")
             microblog_data["service"] = service.userhost()
             microblog_data["node"] = node_identifier
             microblog_data["verified_publisher"] = "true" if publisher else "false"
             ret.append(microblog_data)
-        return ret
+        defer.returnValue(ret)
 
     def _parseAccessData(self, microblog_data, item):
         P = self.host.plugins["XEP-0060"]
@@ -228,12 +236,13 @@
 
                 break
 
+    @defer.inlineCallbacks
     def item2gbdata(self, item, _type="main_item"):
         """ Convert item to microblog data dictionary + add access data """
-        microblog_data = self.host.plugins["XEP-0277"].item2mbdata(item)
+        microblog_data = yield self.host.plugins["XEP-0277"].item2mbdata(item)
         microblog_data["type"] = _type
         self._parseAccessData(microblog_data, item)
-        return microblog_data
+        defer.returnValue(microblog_data)
 
     def getNodeName(self, publisher):
         """Retrieve the name of publisher's node
@@ -359,16 +368,17 @@
         entry_d.addCallback(lambda mblog_item: self.host.plugins["XEP-0060"].publish(service, node, items=[mblog_item], profile_key=profile))
         return entry_d
 
+    @defer.inlineCallbacks
     def _itemsConstruction(self, items, pub_jid, client):
         """ Transforms items to group blog data and manage comments node
         @param items: iterable of items
         @param pub_jid: jid of the publisher or None to use items data
         @param client: SatXMPPClient instance
-        @return: list of group blog data """
+        @return: deferred which fire list of group blog data """
         # TODO: use items data when pub_jid is None
         ret = []
         for item in items:
-            gbdata = self.item2gbdata(item)
+            gbdata = yield self.item2gbdata(item)
             ret.append(gbdata)
             # if there is a comments node, we subscribe to it
             if "comments_node" in gbdata:
@@ -379,7 +389,7 @@
                                                                 profile_key=client.profile)
                 except KeyError:
                     warning("Missing key for comments")
-        return ret
+        defer.returnValue(ret)
 
     def getLastGroupBlogs(self, pub_jid_s, max_items=10, profile_key='@NONE@'):
         """Get the last published microblogs
@@ -458,11 +468,13 @@
 
             mblogs = []
 
+
             for jid_s in jids:
                 _jid = jid.JID(jid_s)
                 d = self.host.plugins["XEP-0060"].getItems(client.item_access_pubsub, self.getNodeName(_jid),
                                                            max_items=max_items, profile_key=profile_key)
-                d.addCallback(lambda items, source_jid: (source_jid, self._itemsConstruction(items, _jid, client)), jid_s)
+                d.addCallback(self._itemsConstruction, _jid, client)
+                d.addCallback(lambda gbdata, source_jid: (source_jid, gbdata), jid_s)
 
                 mblogs.append(d)
             dlist = defer.DeferredList(mblogs)
--- a/src/plugins/plugin_xep_0277.py	Thu Nov 14 18:35:51 2013 +0100
+++ b/src/plugins/plugin_xep_0277.py	Thu Nov 14 18:36:02 2013 +0100
@@ -83,6 +83,7 @@
 
         return (service, node)
 
+    @defer.inlineCallbacks
     def item2mbdata(self, item):
         """Convert an XML Item to microblog data used in bridge API
         @param item: domish.Element of microblog item
@@ -91,11 +92,20 @@
             entry_elt = [child for child in item.elements() if child.name == "entry"][0]
         except IndexError:
             warning(_('No entry element in microblog item'))
-            return
+            raise exceptions.DataError('no entry found')
         _entry = atom.Entry().import_xml(entry_elt.toXml().encode('utf-8'))
         microblog_data = {}
         try:
-            microblog_data['content'] = _entry.title.text
+            try:
+                content_type =_entry.title.attrs['type'].lower()
+            except KeyError:
+                content_type = 'text'
+            if content_type == 'xhtml':
+                # TODO: proper check of body namespace
+                microblog_data['xhtml'] = yield self.host.plugins["TEXT-SYNTAXES"].clean_xhtml(_entry.title.text)
+                microblog_data['content'] = _entry.title.text # FIXME: must use text version of the microblog, or convert XHTML to text if not available
+            else:
+                microblog_data['content'] = _entry.title.text
             if len(_entry.authors):
                 microblog_data['author'] = _entry.authors[0].name.text
             microblog_data['timestamp'] = str(int(_entry.updated.tf))
@@ -114,7 +124,7 @@
 
         except (AttributeError, KeyError):
             error(_('Error while parsing atom entry for microblogging event'))
-            return {}
+            raise exceptions.DataError
 
         ##XXX: workaround for Jappix behaviour
         if not 'author' in microblog_data:
@@ -126,12 +136,21 @@
             except:
                 error(_('Cannot find author'))
         ##end workaround Jappix
-        return microblog_data
+
+        defer.returnValue(microblog_data)
 
     def microblogCB(self, itemsEvent, profile):
+        d = defer.Deferred()
+
+        def manageItem(microblog_data):
+            self.host.bridge.personalEvent(itemsEvent.sender.full(), "MICROBLOG", microblog_data, profile)
+
         for item in itemsEvent.items:
-            microblog_data = self.item2mbdata(item)
-            self.host.bridge.personalEvent(itemsEvent.sender.full(), "MICROBLOG", microblog_data, profile)
+            d.addCallback(lambda ignore: self.item2mbdata(item))
+            d.addCallback(manageItem)
+
+        d.callback(None)
+        return d
 
     @defer.inlineCallbacks
     def data2entry(self, data, profile):
@@ -188,8 +207,19 @@
         @param max_items: how many microblogs we want to get
         @param profile_key: profile key
         """
+        def resultToArray(result):
+            ret = []
+            for (success, value) in result:
+                if success:
+                    ret.append(value)
+                else:
+                    error('Error while getting last microblog')
+            return ret
+
         d = self.host.plugins["XEP-0060"].getItems(jid.JID(pub_jid), NS_MICROBLOG, max_items=max_items, profile_key=profile_key)
-        d.addCallback(lambda items: map(self.item2mbdata, items))
+        d.addCallback(lambda items: defer.DeferredList(map(self.item2mbdata, items)))
+        d.addCallback(resultToArray)
+        return d
 
     def setMicroblogAccess(self, access="presence", profile_key='@DEFAULT@'):
         """Create a microblog node on PEP with given access