comparison src/plugins/plugin_misc_groupblog.py @ 594:e629371a28d3

Fix pep8 support in src/plugins.
author Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
date Fri, 18 Jan 2013 17:55:35 +0100
parents beaf6bec2fcd
children 84a6e83157c2
comparison
equal deleted inserted replaced
593:70bae685d05c 594:e629371a28d3
34 34
35 NS_PUBSUB = 'http://jabber.org/protocol/pubsub' 35 NS_PUBSUB = 'http://jabber.org/protocol/pubsub'
36 NS_GROUPBLOG = 'http://goffi.org/protocol/groupblog' 36 NS_GROUPBLOG = 'http://goffi.org/protocol/groupblog'
37 NS_NODE_PREFIX = 'urn:xmpp:groupblog:' 37 NS_NODE_PREFIX = 'urn:xmpp:groupblog:'
38 #NS_PUBSUB_EXP = 'http://goffi.org/protocol/pubsub' #for non official features 38 #NS_PUBSUB_EXP = 'http://goffi.org/protocol/pubsub' #for non official features
39 NS_PUBSUB_EXP = NS_PUBSUB #XXX: we can't use custom namespace as Wokkel's PubSubService use official NS 39 NS_PUBSUB_EXP = NS_PUBSUB # XXX: we can't use custom namespace as Wokkel's PubSubService use official NS
40 NS_PUBSUB_ITEM_ACCESS = NS_PUBSUB_EXP + "#item-access" 40 NS_PUBSUB_ITEM_ACCESS = NS_PUBSUB_EXP + "#item-access"
41 NS_PUBSUB_CREATOR_JID_CHECK = NS_PUBSUB_EXP + "#creator-jid-check" 41 NS_PUBSUB_CREATOR_JID_CHECK = NS_PUBSUB_EXP + "#creator-jid-check"
42 NS_PUBSUB_ITEM_CONFIG = NS_PUBSUB_EXP + "#item-config" 42 NS_PUBSUB_ITEM_CONFIG = NS_PUBSUB_EXP + "#item-config"
43 NS_PUBSUB_AUTO_CREATE = NS_PUBSUB + "#auto-create" 43 NS_PUBSUB_AUTO_CREATE = NS_PUBSUB + "#auto-create"
44 OPT_ROSTER_GROUPS_ALLOWED = 'pubsub#roster_groups_allowed' 44 OPT_ROSTER_GROUPS_ALLOWED = 'pubsub#roster_groups_allowed'
49 OPT_SUBSCRIPTION_TYPE = 'pubsub#subscription_type' 49 OPT_SUBSCRIPTION_TYPE = 'pubsub#subscription_type'
50 OPT_SUBSCRIPTION_DEPTH = 'pubsub#subscription_depth' 50 OPT_SUBSCRIPTION_DEPTH = 'pubsub#subscription_depth'
51 TYPE_COLLECTION = 'collection' 51 TYPE_COLLECTION = 'collection'
52 52
53 PLUGIN_INFO = { 53 PLUGIN_INFO = {
54 "name": "Group blogging throught collections", 54 "name": "Group blogging throught collections",
55 "import_name": "groupblog", 55 "import_name": "groupblog",
56 "type": "MISC", 56 "type": "MISC",
57 "protocols": [], 57 "protocols": [],
58 "dependencies": ["XEP-0277"], 58 "dependencies": ["XEP-0277"],
59 "main": "GroupBlog", 59 "main": "GroupBlog",
60 "handler": "yes", 60 "handler": "yes",
61 "description": _("""Implementation of microblogging with roster access""") 61 "description": _("""Implementation of microblogging with roster access""")
62 } 62 }
63
63 64
64 class NoCompatiblePubSubServerFound(Exception): 65 class NoCompatiblePubSubServerFound(Exception):
65 pass 66 pass
66 67
68
67 class BadAccessTypeError(Exception): 69 class BadAccessTypeError(Exception):
68 pass 70 pass
69 71
72
70 class BadAccessListError(Exception): 73 class BadAccessListError(Exception):
71 pass 74 pass
72 75
76
73 class UnknownType(Exception): 77 class UnknownType(Exception):
74 pass 78 pass
79
75 80
76 class GroupBlog(object): 81 class GroupBlog(object):
77 """This class use a SàT PubSub Service to manage access on microblog""" 82 """This class use a SàT PubSub Service to manage access on microblog"""
78 83
79 def __init__(self, host): 84 def __init__(self, host):
80 info(_("Group blog plugin initialization")) 85 info(_("Group blog plugin initialization"))
81 self.host = host 86 self.host = host
82 87
83 host.bridge.addMethod("sendGroupBlog", ".plugin", in_sign='sasss', out_sign='', 88 host.bridge.addMethod("sendGroupBlog", ".plugin", in_sign='sasss', out_sign='',
84 method=self.sendGroupBlog) 89 method=self.sendGroupBlog)
85 90
86 host.bridge.addMethod("getLastGroupBlogs", ".plugin", 91 host.bridge.addMethod("getLastGroupBlogs", ".plugin",
87 in_sign='sis', out_sign='aa{ss}', 92 in_sign='sis', out_sign='aa{ss}',
88 method=self.getLastGroupBlogs, 93 method=self.getLastGroupBlogs,
89 async = True) 94 async=True)
90 95
91 host.bridge.addMethod("getMassiveLastGroupBlogs", ".plugin", 96 host.bridge.addMethod("getMassiveLastGroupBlogs", ".plugin",
92 in_sign='sasis', out_sign='a{saa{ss}}', 97 in_sign='sasis', out_sign='a{saa{ss}}',
93 method=self.getMassiveLastGroupBlogs, 98 method=self.getMassiveLastGroupBlogs,
94 async = True) 99 async=True)
95 100
96 host.bridge.addMethod("subscribeGroupBlog", ".plugin", in_sign='ss', out_sign='', 101 host.bridge.addMethod("subscribeGroupBlog", ".plugin", in_sign='ss', out_sign='',
97 method=self.subscribeGroupBlog, 102 method=self.subscribeGroupBlog,
98 async = True) 103 async=True)
99 104
100 host.bridge.addMethod("massiveSubscribeGroupBlogs", ".plugin", in_sign='sass', out_sign='', 105 host.bridge.addMethod("massiveSubscribeGroupBlogs", ".plugin", in_sign='sass', out_sign='',
101 method=self.massiveSubscribeGroupBlogs, 106 method=self.massiveSubscribeGroupBlogs,
102 async = True) 107 async=True)
103 108
104 host.trigger.add("PubSubItemsReceived", self.pubSubItemsReceivedTrigger) 109 host.trigger.add("PubSubItemsReceived", self.pubSubItemsReceivedTrigger)
105
106 110
107 def getHandler(self, profile): 111 def getHandler(self, profile):
108 return GroupBlog_handler() 112 return GroupBlog_handler()
109 113
110 @defer.inlineCallbacks 114 @defer.inlineCallbacks
119 123
120 client = self.host.getClient(profile) 124 client = self.host.getClient(profile)
121 if not client: 125 if not client:
122 error(_('No client for this profile key: %s') % profile_key) 126 error(_('No client for this profile key: %s') % profile_key)
123 raise Exception("Unknown profile") 127 raise Exception("Unknown profile")
124 yield client.client_initialized #we want to be sure that the client is initialized 128 yield client.client_initialized # we want to be sure that the client is initialized
125 129
126 #we first check that we have a item-access pubsub server 130 #we first check that we have a item-access pubsub server
127 if not hasattr(client,"item_access_pubsub"): 131 if not hasattr(client, "item_access_pubsub"):
128 debug(_('Looking for item-access power pubsub server')) 132 debug(_('Looking for item-access power pubsub server'))
129 #we don't have any pubsub server featuring item access yet 133 #we don't have any pubsub server featuring item access yet
130 client.item_access_pubsub = None 134 client.item_access_pubsub = None
131 client._item_access_pubsub_pending = defer.Deferred() 135 client._item_access_pubsub_pending = defer.Deferred()
132 for entity in self.host.memory.getServerServiceEntities("pubsub", "service", profile): 136 for entity in self.host.memory.getServerServiceEntities("pubsub", "service", profile):
135 if set([NS_PUBSUB_AUTO_CREATE, NS_PUBSUB_CREATOR_JID_CHECK]).issubset(_disco.features): 139 if set([NS_PUBSUB_AUTO_CREATE, NS_PUBSUB_CREATOR_JID_CHECK]).issubset(_disco.features):
136 info(_("item-access powered pubsub service found: [%s]") % entity.full()) 140 info(_("item-access powered pubsub service found: [%s]") % entity.full())
137 client.item_access_pubsub = entity 141 client.item_access_pubsub = entity
138 client._item_access_pubsub_pending.callback(None) 142 client._item_access_pubsub_pending.callback(None)
139 143
140 if hasattr(client,"_item_access_pubsub_pending"): 144 if hasattr(client, "_item_access_pubsub_pending"):
141 #XXX: we need to wait for item access pubsub service check 145 #XXX: we need to wait for item access pubsub service check
142 yield client._item_access_pubsub_pending 146 yield client._item_access_pubsub_pending
143 del client._item_access_pubsub_pending 147 del client._item_access_pubsub_pending
144 148
145 if not client.item_access_pubsub: 149 if not client.item_access_pubsub:
155 origin_host = publisher.host.split('.') 159 origin_host = publisher.host.split('.')
156 event_host = event.sender.host.split('.') 160 event_host = event.sender.host.split('.')
157 #FIXME: basic origin check, must be improved 161 #FIXME: basic origin check, must be improved
158 #TODO: automatic security test 162 #TODO: automatic security test
159 if (not (origin_host) 163 if (not (origin_host)
160 or len(event_host) < len(origin_host) 164 or len(event_host) < len(origin_host)
161 or event_host[-len(origin_host):] != origin_host): 165 or event_host[-len(origin_host):] != origin_host):
162 warning("Host incoherence between %s and %s (hack attempt ?)" % (unicode(event.sender), 166 warning("Host incoherence between %s and %s (hack attempt ?)" % (unicode(event.sender),
163 unicode(publisher))) 167 unicode(publisher)))
164 return 168 return
165 for item in event.items: 169 for item in event.items:
166 microblog_data = self.item2gbdata(item) 170 microblog_data = self.item2gbdata(item)
167 171
168 self.host.bridge.personalEvent(publisher.full(), "MICROBLOG", microblog_data, profile) 172 self.host.bridge.personalEvent(publisher.full(), "MICROBLOG", microblog_data, profile)
169 return False 173 return False
170 return True 174 return True
171
172 175
173 def _parseAccessData(self, microblog_data, item): 176 def _parseAccessData(self, microblog_data, item):
174 form_elts = filter(lambda elt: elt.name == "x", item.children) 177 form_elts = filter(lambda elt: elt.name == "x", item.children)
175 for form_elt in form_elts: 178 for form_elt in form_elts:
176 form = data_form.Form.fromElement(form_elt) 179 form = data_form.Form.fromElement(form_elt)
190 """ Convert item to microblog data dictionary + add access data """ 193 """ Convert item to microblog data dictionary + add access data """
191 microblog_data = self.host.plugins["XEP-0277"].item2mbdata(item) 194 microblog_data = self.host.plugins["XEP-0277"].item2mbdata(item)
192 self._parseAccessData(microblog_data, item) 195 self._parseAccessData(microblog_data, item)
193 return microblog_data 196 return microblog_data
194 197
195
196 def getNodeName(self, publisher): 198 def getNodeName(self, publisher):
197 """Retrieve the name of publisher's node 199 """Retrieve the name of publisher's node
198 @param publisher: publisher's jid 200 @param publisher: publisher's jid
199 @return: node's name (string)""" 201 @return: node's name (string)"""
200 return NS_NODE_PREFIX + publisher.userhost() 202 return NS_NODE_PREFIX + publisher.userhost()
201
202
203 203
204 def _publishMblog(self, service, client, access_type, access_list, message): 204 def _publishMblog(self, service, client, access_type, access_list, message):
205 """Actually publish the message on the group blog 205 """Actually publish the message on the group blog
206 @param service: jid of the item-access pubsub service 206 @param service: jid of the item-access pubsub service
207 @param client: SatXMPPClient of the published 207 @param client: SatXMPPClient of the published
208 @param access_type: one of "PUBLIC", "GROUP", "JID" 208 @param access_type: one of "PUBLIC", "GROUP", "JID"
209 @param access_list: set of entities (empty list for all, groups or jids) allowed to see the item 209 @param access_list: set of entities (empty list for all, groups or jids) allowed to see the item
210 @param message: message to publish 210 @param message: message to publish
211 """ 211 """
212 mblog_item = self.host.plugins["XEP-0277"].data2entry({'content':message}, client.profile) 212 mblog_item = self.host.plugins["XEP-0277"].data2entry({'content': message}, client.profile)
213 form = data_form.Form('submit', formNamespace=NS_PUBSUB_ITEM_CONFIG) 213 form = data_form.Form('submit', formNamespace=NS_PUBSUB_ITEM_CONFIG)
214 if access_type == "PUBLIC": 214 if access_type == "PUBLIC":
215 if access_list: 215 if access_list:
216 raise BadAccessListError("access_list must be empty for PUBLIC access") 216 raise BadAccessListError("access_list must be empty for PUBLIC access")
217 access = data_form.Field(None, OPT_ACCESS_MODEL, value="open") 217 access = data_form.Field(None, OPT_ACCESS_MODEL, value="open")
241 list of groups or list of jids) for this item 241 list of groups or list of jids) for this item
242 @param message: microblog 242 @param message: microblog
243 @profile_key: %(doc_profile)s 243 @profile_key: %(doc_profile)s
244 """ 244 """
245 print "sendGroupBlog" 245 print "sendGroupBlog"
246
246 def initialised(result): 247 def initialised(result):
247 profile, client = result 248 profile, client = result
248 if access_type == "PUBLIC": 249 if access_type == "PUBLIC":
249 if access_list: 250 if access_list:
250 raise Exception("Publishers list must be empty when getting microblogs for all contacts") 251 raise Exception("Publishers list must be empty when getting microblogs for all contacts")
251 self._publishMblog(client.item_access_pubsub, client, "PUBLIC", [], message) 252 self._publishMblog(client.item_access_pubsub, client, "PUBLIC", [], message)
252 elif access_type == "GROUP": 253 elif access_type == "GROUP":
253 _groups = set(access_list).intersection(client.roster.getGroups()) #We only keep group which actually exist 254 _groups = set(access_list).intersection(client.roster.getGroups()) # We only keep group which actually exist
254 if not _groups: 255 if not _groups:
255 raise BadAccessListError("No valid group") 256 raise BadAccessListError("No valid group")
256 self._publishMblog(client.item_access_pubsub, client, "GROUP", _groups, message) 257 self._publishMblog(client.item_access_pubsub, client, "GROUP", _groups, message)
257 elif access_type == "JID": 258 elif access_type == "JID":
258 raise NotImplementedError 259 raise NotImplementedError
260 error(_("Unknown access type")) 261 error(_("Unknown access type"))
261 raise BadAccessTypeError 262 raise BadAccessTypeError
262 263
263 self.initialise(profile_key).addCallback(initialised) 264 self.initialise(profile_key).addCallback(initialised)
264 265
265
266
267 def getLastGroupBlogs(self, pub_jid, max_items=10, profile_key='@DEFAULT@'): 266 def getLastGroupBlogs(self, pub_jid, max_items=10, profile_key='@DEFAULT@'):
268 """Get the last published microblogs 267 """Get the last published microblogs
269 @param pub_jid: jid of the publisher 268 @param pub_jid: jid of the publisher
270 @param max_items: how many microblogs we want to get (see XEP-0060 #6.5.7) 269 @param max_items: how many microblogs we want to get (see XEP-0060 #6.5.7)
271 @param profile_key: profile key 270 @param profile_key: profile key
275 def initialised(result): 274 def initialised(result):
276 profile, client = result 275 profile, client = result
277 d = self.host.plugins["XEP-0060"].getItems(client.item_access_pubsub, self.getNodeName(jid.JID(pub_jid)), 276 d = self.host.plugins["XEP-0060"].getItems(client.item_access_pubsub, self.getNodeName(jid.JID(pub_jid)),
278 max_items=max_items, profile_key=profile_key) 277 max_items=max_items, profile_key=profile_key)
279 d.addCallback(lambda items: map(self.item2gbdata, items)) 278 d.addCallback(lambda items: map(self.item2gbdata, items))
280 d.addErrback(lambda ignore: {}) #TODO: more complete error management (log !) 279 d.addErrback(lambda ignore: {}) # TODO: more complete error management (log !)
281 return d 280 return d
282 281
283 #TODO: we need to use the server corresponding the the host of the jid 282 #TODO: we need to use the server corresponding the the host of the jid
284 return self.initialise(profile_key).addCallback(initialised) 283 return self.initialise(profile_key).addCallback(initialised)
285 284
288 @param publishers_type: type of the list of publishers (one of "GROUP" or "JID" or "ALL") 287 @param publishers_type: type of the list of publishers (one of "GROUP" or "JID" or "ALL")
289 @param publishers: list of publishers, according to "publishers_type" (list of groups or list of jids) 288 @param publishers: list of publishers, according to "publishers_type" (list of groups or list of jids)
290 @param max_items: how many microblogs we want to get 289 @param max_items: how many microblogs we want to get
291 @param profile_key: profile key 290 @param profile_key: profile key
292 """ 291 """
292
293 def sendResult(result): 293 def sendResult(result):
294 """send result of DeferredList (list of microblogs to the calling method""" 294 """send result of DeferredList (list of microblogs to the calling method"""
295 295
296 ret = {} 296 ret = {}
297 297
327 dlist = defer.DeferredList(mblogs) 327 dlist = defer.DeferredList(mblogs)
328 dlist.addCallback(sendResult) 328 dlist.addCallback(sendResult)
329 329
330 return dlist 330 return dlist
331 331
332
333 #TODO: custom exception 332 #TODO: custom exception
334 if publishers_type not in ["GROUP", "JID", "ALL"]: 333 if publishers_type not in ["GROUP", "JID", "ALL"]:
335 raise Exception("Bad call, unknown publishers_type") 334 raise Exception("Bad call, unknown publishers_type")
336 if publishers_type=="ALL" and publishers: 335 if publishers_type == "ALL" and publishers:
337 raise Exception("Publishers list must be empty when getting microblogs for all contacts") 336 raise Exception("Publishers list must be empty when getting microblogs for all contacts")
338 return self.initialise(profile_key).addCallback(initialised) 337 return self.initialise(profile_key).addCallback(initialised)
339 #TODO: we need to use the server corresponding the the host of the jid 338 #TODO: we need to use the server corresponding the the host of the jid
340 339
341 def subscribeGroupBlog(self, pub_jid, profile_key='@DEFAULT'): 340 def subscribeGroupBlog(self, pub_jid, profile_key='@DEFAULT'):
345 profile_key=profile_key) 344 profile_key=profile_key)
346 return d 345 return d
347 346
348 #TODO: we need to use the server corresponding the the host of the jid 347 #TODO: we need to use the server corresponding the the host of the jid
349 return self.initialise(profile_key).addCallback(initialised) 348 return self.initialise(profile_key).addCallback(initialised)
350
351 349
352 def massiveSubscribeGroupBlogs(self, publishers_type, publishers, profile_key='@DEFAULT@'): 350 def massiveSubscribeGroupBlogs(self, publishers_type, publishers, profile_key='@DEFAULT@'):
353 """Subscribe microblogs for a list of groups or jids 351 """Subscribe microblogs for a list of groups or jids
354 @param publishers_type: type of the list of publishers (one of "GROUP" or "JID" or "ALL") 352 @param publishers_type: type of the list of publishers (one of "GROUP" or "JID" or "ALL")
355 @param publishers: list of publishers, according to "publishers_type" (list of groups or list of jids) 353 @param publishers: list of publishers, according to "publishers_type" (list of groups or list of jids)
356 @param profile_key: profile key 354 @param profile_key: profile key
357 """ 355 """
356
358 def initialised(result): 357 def initialised(result):
359 profile, client = result 358 profile, client = result
360 359
361 if publishers_type == "ALL": 360 if publishers_type == "ALL":
362 contacts = client.roster.getItems() 361 contacts = client.roster.getItems()
376 profile_key=profile_key) 375 profile_key=profile_key)
377 mblogs.append(d) 376 mblogs.append(d)
378 dlist = defer.DeferredList(mblogs) 377 dlist = defer.DeferredList(mblogs)
379 return dlist 378 return dlist
380 379
381
382 #TODO: custom exception 380 #TODO: custom exception
383 if publishers_type not in ["GROUP", "JID", "ALL"]: 381 if publishers_type not in ["GROUP", "JID", "ALL"]:
384 raise Exception("Bad call, unknown publishers_type") 382 raise Exception("Bad call, unknown publishers_type")
385 if publishers_type=="ALL" and publishers: 383 if publishers_type == "ALL" and publishers:
386 raise Exception("Publishers list must be empty when getting microblogs for all contacts") 384 raise Exception("Publishers list must be empty when getting microblogs for all contacts")
387 return self.initialise(profile_key).addCallback(initialised) 385 return self.initialise(profile_key).addCallback(initialised)
388 #TODO: we need to use the server corresponding the the host of the jid 386 #TODO: we need to use the server corresponding the the host of the jid
389 387
390 388
391
392 class GroupBlog_handler(XMPPHandler): 389 class GroupBlog_handler(XMPPHandler):
393 implements(iwokkel.IDisco) 390 implements(iwokkel.IDisco)
394 391
395 def getDiscoInfo(self, requestor, target, nodeIdentifier=''): 392 def getDiscoInfo(self, requestor, target, nodeIdentifier=''):
396 return [disco.DiscoFeature(NS_GROUPBLOG)] 393 return [disco.DiscoFeature(NS_GROUPBLOG)]
397 394
398 def getDiscoItems(self, requestor, target, nodeIdentifier=''): 395 def getDiscoItems(self, requestor, target, nodeIdentifier=''):
399 return [] 396 return []
400