comparison sat_pubsub/backend.py @ 301:05c875a13a62

categories are now stored in a dedicated table if item contain an atom entry: - database creation/update files include the new table - item data are now stored in a ItemData namedtuple
author Goffi <goffi@goffi.org>
date Wed, 25 Nov 2015 18:33:38 +0100
parents c5acb4995fde
children b8b25efae0bc
comparison
equal deleted inserted replaced
300:c5acb4995fde 301:05c875a13a62
79 79
80 from sat_pubsub import error, iidavoll, const 80 from sat_pubsub import error, iidavoll, const
81 from sat_pubsub.iidavoll import IBackendService, ILeafNode 81 from sat_pubsub.iidavoll import IBackendService, ILeafNode
82 82
83 from copy import deepcopy 83 from copy import deepcopy
84 from collections import namedtuple
85
86
87 ItemData = namedtuple('ItemData', ('item', 'access_model', 'config', 'categories'))
84 88
85 89
86 def _getAffiliation(node, entity): 90 def _getAffiliation(node, entity):
87 d = node.getAffiliation(entity) 91 d = node.getAffiliation(entity)
88 d.addCallback(lambda affiliation: (node, affiliation)) 92 d.addCallback(lambda affiliation: (node, affiliation))
243 d.addCallback(check) 247 d.addCallback(check)
244 return d 248 return d
245 249
246 def parseItemConfig(self, item): 250 def parseItemConfig(self, item):
247 """Get and remove item configuration information 251 """Get and remove item configuration information
248 @param item: 252
253 @param item (domish.Element): item to parse
254 @return (tuple[unicode, dict)): (access_model, item_config)
249 """ 255 """
250 item_config = None 256 item_config = None
251 access_model = const.VAL_AMODEL_DEFAULT 257 access_model = const.VAL_AMODEL_DEFAULT
252 for idx, elt in enumerate(item.children): 258 for idx, elt in enumerate(item.children):
253 if elt.uri != 'data_form.NS_X_DATA' or elt.name != 'x': 259 if elt.uri != 'data_form.NS_X_DATA' or elt.name != 'x':
259 break 265 break
260 266
261 if item_config: 267 if item_config:
262 access_model = item_config.get(const.OPT_ACCESS_MODEL, const.VAL_AMODEL_DEFAULT) 268 access_model = item_config.get(const.OPT_ACCESS_MODEL, const.VAL_AMODEL_DEFAULT)
263 return (access_model, item_config) 269 return (access_model, item_config)
270
271 def parseCategories(self, item_elt):
272 """Check if item contain an atom entry, and parse categories if possible
273
274 @param item (domish.Element): item to parse
275 @return (list): list of found categories
276 """
277 categories = []
278 try:
279 entry_elt = item_elt.elements(const.NS_ATOM, "entry").next()
280 except StopIteration:
281 return categories
282
283 for category_elt in entry_elt.elements(const.NS_ATOM, 'category'):
284 category = category_elt.getAttribute('term')
285 if category:
286 categories.append(category)
287
288 return categories
264 289
265 def _checkOverwrite(self, node, itemIdentifiers, publisher): 290 def _checkOverwrite(self, node, itemIdentifiers, publisher):
266 """Check that the itemIdentifiers correspond to items published 291 """Check that the itemIdentifiers correspond to items published
267 by the current publisher""" 292 by the current publisher"""
268 def doCheck(item_pub_map): 293 def doCheck(item_pub_map):
309 if not item.getAttribute("id"): 334 if not item.getAttribute("id"):
310 item["id"] = str(uuid.uuid4()) 335 item["id"] = str(uuid.uuid4())
311 else: 336 else:
312 check_overwrite = True 337 check_overwrite = True
313 access_model, item_config = self.parseItemConfig(item) 338 access_model, item_config = self.parseItemConfig(item)
314 items_data.append((item, access_model, item_config)) 339 categories = self.parseCategories(item)
340 items_data.append(ItemData(item, access_model, item_config, categories))
315 341
316 if persistItems: 342 if persistItems:
317 if check_overwrite and affiliation != 'owner': 343 if check_overwrite and affiliation != 'owner':
318 # we don't want a publisher to overwrite the item 344 # we don't want a publisher to overwrite the item
319 # of an other publisher 345 # of an other publisher
329 return d 355 return d
330 356
331 357
332 def _doNotify(self, result, node, items_data, deliverPayloads, pep, recipient): 358 def _doNotify(self, result, node, items_data, deliverPayloads, pep, recipient):
333 if items_data and not deliverPayloads: 359 if items_data and not deliverPayloads:
334 for access_model, item_config, item in items_data: 360 for item_data in items_data:
335 item.children = [] 361 item_data.item.children = []
336 self.dispatch({'items_data': items_data, 'node': node, 'pep': pep, 'recipient': recipient}, 362 self.dispatch({'items_data': items_data, 'node': node, 'pep': pep, 'recipient': recipient},
337 '//event/pubsub/notify') 363 '//event/pubsub/notify')
338 364
339 365
340 def getNotifications(self, nodeDbId, items_data): 366 def getNotifications(self, nodeDbId, items_data):
573 ext_data): 599 ext_data):
574 node, affiliation = result 600 node, affiliation = result
575 601
576 def append_item_config(items_data): 602 def append_item_config(items_data):
577 ret = [] 603 ret = []
578 for data in items_data: 604 for item, access_model, access_list in items_data:
579 item, access_model, access_list = data
580 if access_model == const.VAL_AMODEL_OPEN: 605 if access_model == const.VAL_AMODEL_OPEN:
581 pass 606 pass
582 elif access_model == const.VAL_AMODEL_ROSTER: 607 elif access_model == const.VAL_AMODEL_ROSTER:
583 form = data_form.Form('submit', formNamespace=const.NS_ITEM_CONFIG) 608 form = data_form.Form('submit', formNamespace=const.NS_ITEM_CONFIG)
584 access = data_form.Field(None, const.OPT_ACCESS_MODEL, value=const.VAL_AMODEL_ROSTER) 609 access = data_form.Field(None, const.OPT_ACCESS_MODEL, value=const.VAL_AMODEL_ROSTER)
734 # we need to get the items before removing them, for the notifications 759 # we need to get the items before removing them, for the notifications
735 760
736 def removeItems(items_data): 761 def removeItems(items_data):
737 """Remove the items and keep only actually removed ones in items_data""" 762 """Remove the items and keep only actually removed ones in items_data"""
738 d = node.removeItems(itemIdentifiers) 763 d = node.removeItems(itemIdentifiers)
739 d.addCallback(lambda removed: [item_data for item_data in items_data if item_data[0]["id"] in removed]) 764 d.addCallback(lambda removed: [item_data for item_data in items_data if item_data.item["id"] in removed])
740 return d 765 return d
741 766
742 d = node.getItemsById(None, True, itemIdentifiers) 767 d = node.getItemsById(None, True, itemIdentifiers)
743 d.addCallback(removeItems) 768 d.addCallback(removeItems)
744 769
943 """ Attach item configuration to this item 968 """ Attach item configuration to this item
944 Used to give item configuration back to node's owner (and *only* to owner) 969 Used to give item configuration back to node's owner (and *only* to owner)
945 """ 970 """
946 #TODO: a test should check that only the owner get the item configuration back 971 #TODO: a test should check that only the owner get the item configuration back
947 972
948 item, access_model, item_config = item_data 973 item, item_config = item_data.item, item_data.config
949 new_item = deepcopy(item) 974 new_item = deepcopy(item)
950 if item_config: 975 if item_config:
951 new_item.addChild(item_config.toElement()) 976 new_item.addChild(item_config.toElement())
952 return new_item 977 return new_item
953 978
1029 notifications, (owner_jid,roster) = result 1054 notifications, (owner_jid,roster) = result
1030 1055
1031 #we filter items not allowed for the subscribers 1056 #we filter items not allowed for the subscribers
1032 notifications_filtered = [] 1057 notifications_filtered = []
1033 1058
1034 for subscriber, subscriptions, _items_data in notifications: 1059 for subscriber, subscriptions, items_data in notifications:
1035 if subscriber == owner_jid: 1060 if subscriber == owner_jid:
1036 # as notification is always sent to owner, 1061 # as notification is always sent to owner,
1037 # we ignore owner if he is here 1062 # we ignore owner if he is here
1038 continue 1063 continue
1039 allowed_items = [] #we keep only item which subscriber can access 1064 allowed_items = [] #we keep only item which subscriber can access
1040 1065
1041 for item, access_model, access_list in _items_data: 1066 for item_data in items_data:
1067 item, access_model = item_data.item, item_data.access_model
1068 access_list = item_data.config
1042 if access_model == const.VAL_AMODEL_OPEN: 1069 if access_model == const.VAL_AMODEL_OPEN:
1043 allowed_items.append(item) 1070 allowed_items.append(item)
1044 elif access_model == const.VAL_AMODEL_ROSTER: 1071 elif access_model == const.VAL_AMODEL_ROSTER:
1045 _subscriber = subscriber.userhostJID() 1072 _subscriber = subscriber.userhostJID()
1046 if not _subscriber in roster: 1073 if not _subscriber in roster: