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