Mercurial > libervia-backend
comparison src/plugins/plugin_misc_groupblog.py @ 1459:4c4f88d7b156
plugins xep-0060, xep-0163, xep-0277, groupblog: bloging improvments (huge patch, sorry):
/!\ not everything is working yet, and specially groupblogs are broken /!\
- renamed bridge api to use prefixed methods (e.g. psSubscribeToMany instead of subscribeToMany in PubSub)
- (xep-0060): try to find a default PubSub service, and put it in client.pubsub_service
- (xep-0060): extra dictionary can be used in bridge method for RSM and other options
- (xep-0060): XEP_0060.addManagedNode and XEP_0060.removeManagedNode allow to easily catch notifications for a specific node
- (xep-0060): retractItem manage "notify" attribute
- (xep-0060): new signal psEvent will be used to transmit notifications to frontends
- (xep-0060, constants): added a bunch of useful constants
- (xep-0163): removed personalEvent in favor of psEvent
- (xep-0163): addPEPEvent now filter non PEP events for in_callback
- (xep-0277): use of new XEP-0060 plugin's addManagedNode
- (xep-0277): fixed author handling for incoming blogs: author is the human readable name, author_jid it jid, and author_jid_verified is set to True is the jid is checked
- (xep-0277): reworked data2entry with Twisted instead of feed, item_id can now be specified, <content/> is changed to <title/> if there is only content
- (xep-0277): comments are now managed here (core removed from groupblog)
- (xep-0277): (comments) node is created if needed, default pubsub service is used if available, else PEP
- (xep-0277): retract is managed
author | Goffi <goffi@goffi.org> |
---|---|
date | Sun, 16 Aug 2015 00:39:44 +0200 |
parents | 4e2fab4de195 |
children | 9fcc16ef163a |
comparison
equal
deleted
inserted
replaced
1458:832846fefe85 | 1459:4c4f88d7b156 |
---|---|
27 from sat.core import exceptions | 27 from sat.core import exceptions |
28 from wokkel import disco, data_form, iwokkel | 28 from wokkel import disco, data_form, iwokkel |
29 from wokkel import rsm | 29 from wokkel import rsm |
30 from zope.interface import implements | 30 from zope.interface import implements |
31 from feed import date | 31 from feed import date |
32 import uuid | 32 # import uuid |
33 import urllib | |
34 | 33 |
35 try: | 34 try: |
36 from twisted.words.protocols.xmlstream import XMPPHandler | 35 from twisted.words.protocols.xmlstream import XMPPHandler |
37 except ImportError: | 36 except ImportError: |
38 from wokkel.subprotocols import XMPPHandler | 37 from wokkel.subprotocols import XMPPHandler |
39 | 38 |
40 NS_PUBSUB = 'http://jabber.org/protocol/pubsub' | 39 NS_PUBSUB = 'http://jabber.org/protocol/pubsub' |
41 NS_GROUPBLOG = 'http://goffi.org/protocol/groupblog' | 40 NS_GROUPBLOG = 'http://goffi.org/protocol/groupblog' |
42 NS_NODE_PREFIX = 'urn:xmpp:groupblog:' | 41 NS_NODE_PREFIX = 'urn:xmpp:groupblog:' |
43 NS_COMMENT_PREFIX = 'urn:xmpp:comments:' | |
44 #NS_PUBSUB_EXP = 'http://goffi.org/protocol/pubsub' #for non official features | 42 #NS_PUBSUB_EXP = 'http://goffi.org/protocol/pubsub' #for non official features |
45 NS_PUBSUB_EXP = NS_PUBSUB # XXX: we can't use custom namespace as Wokkel's PubSubService use official NS | 43 NS_PUBSUB_EXP = NS_PUBSUB # XXX: we can't use custom namespace as Wokkel's PubSubService use official NS |
46 NS_PUBSUB_ITEM_ACCESS = NS_PUBSUB_EXP + "#item-access" | 44 NS_PUBSUB_ITEM_ACCESS = NS_PUBSUB_EXP + "#item-access" |
47 NS_PUBSUB_CREATOR_JID_CHECK = NS_PUBSUB_EXP + "#creator-jid-check" | 45 NS_PUBSUB_CREATOR_JID_CHECK = NS_PUBSUB_EXP + "#creator-jid-check" |
48 NS_PUBSUB_ITEM_CONFIG = NS_PUBSUB_EXP + "#item-config" | 46 NS_PUBSUB_ITEM_CONFIG = NS_PUBSUB_EXP + "#item-config" |
135 | 133 |
136 # host.bridge.addMethod("subscribeGroupBlog", ".plugin", in_sign='ss', out_sign='', | 134 # host.bridge.addMethod("subscribeGroupBlog", ".plugin", in_sign='ss', out_sign='', |
137 # method=self.subscribeGroupBlog, | 135 # method=self.subscribeGroupBlog, |
138 # async=True) | 136 # async=True) |
139 | 137 |
140 host.trigger.add("PubSubItemsReceived", self.pubSubItemsReceivedTrigger) | 138 # host.trigger.add("PubSubItemsReceived", self.pubSubItemsReceivedTrigger) |
141 | 139 |
142 ## plugin management methods ## | 140 ## plugin management methods ## |
143 | 141 |
144 def getHandler(self, profile): | 142 def getHandler(self, profile): |
145 return GroupBlog_handler() | 143 return GroupBlog_handler() |
170 log.error(_(u"No item-access powered pubsub server found, can't use group blog")) | 168 log.error(_(u"No item-access powered pubsub server found, can't use group blog")) |
171 raise NoCompatiblePubSubServerFound | 169 raise NoCompatiblePubSubServerFound |
172 | 170 |
173 defer.returnValue((profile, client)) | 171 defer.returnValue((profile, client)) |
174 | 172 |
175 def pubSubItemsReceivedTrigger(self, event, profile): | 173 # def pubSubItemsReceivedTrigger(self, event, profile): |
176 """"Trigger which catch groupblogs events""" | 174 # """"Trigger which catch groupblogs events""" |
177 | 175 |
178 if event.nodeIdentifier.startswith(NS_NODE_PREFIX): | 176 # if event.nodeIdentifier.startswith(NS_NODE_PREFIX): |
179 # Microblog | 177 # # Microblog |
180 publisher = jid.JID(event.nodeIdentifier[len(NS_NODE_PREFIX):]) | 178 # publisher = jid.JID(event.nodeIdentifier[len(NS_NODE_PREFIX):]) |
181 origin_host = publisher.host.split('.') | 179 # origin_host = publisher.host.split('.') |
182 event_host = event.sender.host.split('.') | 180 # event_host = event.sender.host.split('.') |
183 #FIXME: basic origin check, must be improved | 181 # #FIXME: basic origin check, must be improved |
184 #TODO: automatic security test | 182 # #TODO: automatic security test |
185 if (not (origin_host) | 183 # if (not (origin_host) |
186 or len(event_host) < len(origin_host) | 184 # or len(event_host) < len(origin_host) |
187 or event_host[-len(origin_host):] != origin_host): | 185 # or event_host[-len(origin_host):] != origin_host): |
188 log.warning(u"Host incoherence between %s and %s (hack attempt ?)" % (unicode(event.sender), | 186 # log.warning(u"Host incoherence between %s and %s (hack attempt ?)" % (unicode(event.sender), |
189 unicode(publisher))) | 187 # unicode(publisher))) |
190 return False | 188 # return False |
191 | 189 |
192 client = self.host.getClient(profile) | 190 # client = self.host.getClient(profile) |
193 | 191 |
194 def gbdataManagementMicroblog(gbdata): | 192 # def gbdataManagementMicroblog(gbdata): |
195 for gbdatum in gbdata: | 193 # for gbdatum in gbdata: |
196 self.host.bridge.personalEvent(publisher.full(), "MICROBLOG", gbdatum, profile) | 194 # self.host.bridge.personalEvent(publisher.full(), "MICROBLOG", gbdatum, profile) |
197 | 195 |
198 d = self._itemsConstruction(event.items, publisher, client) | 196 # d = self._itemsConstruction(event.items, publisher, client) |
199 d.addCallback(gbdataManagementMicroblog) | 197 # d.addCallback(gbdataManagementMicroblog) |
200 return False | 198 # return False |
201 | 199 |
202 elif event.nodeIdentifier.startswith(NS_COMMENT_PREFIX): | 200 # elif event.nodeIdentifier.startswith(NS_COMMENT_PREFIX): |
203 # Comment | 201 # # Comment |
204 def gbdataManagementComments(gbdata): | 202 # def gbdataManagementComments(gbdata): |
205 for gbdatum in gbdata: | 203 # for gbdatum in gbdata: |
206 publisher = None # FIXME: see below (_handleCommentsItems) | 204 # publisher = None # FIXME: see below (_handleCommentsItems) |
207 self.host.bridge.personalEvent(publisher.full() if publisher else gbdatum["author"], "MICROBLOG", gbdatum, profile) | 205 # self.host.bridge.personalEvent(publisher.full() if publisher else gbdatum["author"], "MICROBLOG", gbdatum, profile) |
208 d = self._handleCommentsItems(event.items, event.sender, event.nodeIdentifier) | 206 # d = self._handleCommentsItems(event.items, event.sender, event.nodeIdentifier) |
209 d.addCallback(gbdataManagementComments) | 207 # d.addCallback(gbdataManagementComments) |
210 return False | 208 # return False |
211 return True | 209 # return True |
212 | 210 |
213 ## internal helping methodes ## | 211 ## internal helping methodes ## |
214 | 212 |
215 def _handleCommentsItems(self, items, service, node_identifier): | 213 def _handleCommentsItems(self, items, service, node_identifier): |
216 """ Convert comments items to groupblog data, and send them as signals | 214 """ Convert comments items to groupblog data, and send them as signals |
336 | 334 |
337 entry_d = self.host.plugins["XEP-0277"].data2entry(mblog_data, client.profile) | 335 entry_d = self.host.plugins["XEP-0277"].data2entry(mblog_data, client.profile) |
338 entry_d.addCallback(itemCreated) | 336 entry_d.addCallback(itemCreated) |
339 return entry_d | 337 return entry_d |
340 | 338 |
341 def _fillCommentsElement(self, mblog_data, entry_id, node_name, service_jid): | 339 # def _fillCommentsElement(self, mblog_data, entry_id, node_name, service_jid): |
342 """ | 340 # """ |
343 @param mblog_data: dict containing the microblog data | 341 # @param mblog_data: dict containing the microblog data |
344 @param entry_id: unique identifier of the entry | 342 # @param entry_id: unique identifier of the entry |
345 @param node_name: the pubsub node name | 343 # @param node_name: the pubsub node name |
346 @param service_jid: the JID of the pubsub service | 344 # @param service_jid: the JID of the pubsub service |
347 @return: the comments node string | 345 # @return: the comments node string |
348 """ | 346 # """ |
349 if entry_id is None: | 347 # if entry_id is None: |
350 entry_id = unicode(uuid.uuid4()) | 348 # entry_id = unicode(uuid.uuid4()) |
351 comments_node = "%s_%s__%s" % (NS_COMMENT_PREFIX, entry_id, node_name) | 349 # comments_node = "%s_%s__%s" % (NS_COMMENT_PREFIX, entry_id, node_name) |
352 mblog_data['comments'] = "xmpp:%(service)s?%(query)s" % {'service': service_jid.userhost(), | 350 # mblog_data['comments'] = "xmpp:%(service)s?%(query)s" % {'service': service_jid.userhost(), |
353 'query': urllib.urlencode([('node', comments_node.encode('utf-8'))])} | 351 # 'query': urllib.urlencode([('node', comments_node.encode('utf-8'))])} |
354 return comments_node | 352 # return comments_node |
355 | 353 |
356 def _mblogPublicationFailed(self, failure): | 354 def _mblogPublicationFailed(self, failure): |
357 #TODO | 355 #TODO |
358 return failure | 356 return failure |
359 | 357 |