# HG changeset patch # User Goffi # Date 1627934297 -7200 # Node ID 0b5233981671a2d1b53ab7f3e14c9e7bb562c076 # Parent 7f1394bb96db31ca06d0f25486fa63607a145816 backend: fix `delete` notification + add `purge` notification diff -r 7f1394bb96db -r 0b5233981671 sat_pubsub/backend.py --- a/sat_pubsub/backend.py Mon Aug 02 21:56:43 2021 +0200 +++ b/sat_pubsub/backend.py Mon Aug 02 21:58:17 2021 +0200 @@ -222,7 +222,6 @@ def __init__(self, storage, config): utility.EventDispatcher.__init__(self) self.storage = storage - self._callbackList = [] self.config = config self.admins = config['admins_jids_list'] d = self.storage.getFTSLanguages() @@ -597,6 +596,12 @@ def registerRetractNotifier(self, observerfn, *args, **kwargs): self.addObserver('//event/pubsub/retract', observerfn, *args, **kwargs) + def registerDeleteNotifier(self, observerfn, *args, **kwargs): + self.addObserver('//event/pubsub/delete', observerfn, *args, **kwargs) + + def registerPurgeNotifier(self, observerfn, *args, **kwargs): + self.addObserver('//event/pubsub/purge', observerfn, *args, **kwargs) + def subscribe(self, nodeIdentifier, subscriber, requestor, pep, recipient): subscriberEntity = subscriber.userhostJID() if subscriberEntity != requestor.userhostJID(): @@ -1242,14 +1247,9 @@ 'recipient': recipient}, '//event/pubsub/retract') - def purgeNode(self, nodeIdentifier, requestor, pep, recipient): - d = self.storage.getNode(nodeIdentifier, pep, recipient) - d.addCallback(_getAffiliation, requestor) - d.addCallback(self._doPurge, requestor) - return d - - def _doPurge(self, result, requestor): - node, affiliation = result + async def purgeNode(self, nodeIdentifier, requestor, pep, recipient): + node = await self.storage.getNode(nodeIdentifier, pep, recipient) + node, affiliation = await _getAffiliation(node, requestor) persistItems = node.getConfiguration()[const.OPT_PERSIST_ITEMS] if affiliation != 'owner' and not self.isAdmin(requestor): @@ -1258,15 +1258,20 @@ if not persistItems: raise error.NodeNotPersistent() - d = node.purge() - d.addCallback(self._doNotifyPurge, node.nodeIdentifier) - return d + await node.purge() + + subscribers = await self.getSubscribers(nodeIdentifier, pep, recipient) - def _doNotifyPurge(self, result, nodeIdentifier): - self.dispatch(nodeIdentifier, '//event/pubsub/purge') - - def registerPreDelete(self, preDeleteFn): - self._callbackList.append(preDeleteFn) + # now we can send notifications + self.dispatch( + { + 'node': node, + 'pep': pep, + 'recipient': recipient, + 'subscribers': subscribers, + }, + '//event/pubsub/purge' + ) def getSubscribers(self, nodeIdentifier, pep, recipient): def cb(subscriptions): @@ -1277,26 +1282,22 @@ d.addCallback(cb) return d - async def deleteNode(self, nodeIdentifier, requestor, pep, recipient, redirectURI=None): + async def deleteNode( + self, + nodeIdentifier: str, + requestor: jid.JID, + pep: bool, + recipient: jid.JID, + redirectURI: str = None + ) -> None: node = await self.storage.getNode(nodeIdentifier, pep, recipient) node, affiliation = await _getAffiliation(node, requestor) if affiliation != 'owner' and not self.isAdmin(requestor): raise error.Forbidden() - data = { - 'node': node, - 'redirectURI': redirectURI - } - - d = defer.DeferredList([cb(data, pep, recipient) - for cb in self._callbackList], - consumeErrors=1) - result = await d - dl = [] - for succeeded, r in result: - if succeeded and r: - dl.extend(r) + # we have to get subscribers (for notifications) before the node is deleted + subscribers = await self.getSubscribers(nodeIdentifier, pep, recipient) await self.storage.deleteNodeByDbId(node.nodeDbId) @@ -1307,8 +1308,17 @@ if submitted_node is not None: await submitted_node.setSchema(None) - for d in dl: - d.callback(None) + # now we can send notifications + self.dispatch( + { + 'node': node, + 'pep': pep, + 'recipient': recipient, + 'redirectURI': redirectURI, + 'subscribers': subscribers, + }, + '//event/pubsub/delete' + ) class PubSubResourceFromBackend(pubsub.PubSubResource): @@ -1376,7 +1386,8 @@ self.backend.registerPublishNotifier(self._notifyPublish) self.backend.registerRetractNotifier(self._notifyRetract) - self.backend.registerPreDelete(self._preDelete) + self.backend.registerDeleteNotifier(self._notifyDelete) + self.backend.registerPurgeNotifier(self._notifyPurge) if self.backend.supportsAutoCreate(): self.features.append("auto-create") @@ -1567,16 +1578,52 @@ defer.returnValue((owners, notifications_filtered)) - def _preDelete(self, data, pep, recipient): + async def _aNotifyDelete(self, data): nodeIdentifier = data['node'].nodeIdentifier + pep = data['pep'] + recipient = data['recipient'] redirectURI = data.get('redirectURI', None) - d = self.backend.getSubscribers(nodeIdentifier, pep, recipient) - d.addCallback(lambda subscribers: self.pubsubService.notifyDelete( - self.serviceJID, - nodeIdentifier, - subscribers, - redirectURI)) - return d + subscribers = data['subscribers'] + if pep: + self.backend.privilege.notifyDelete( + recipient, + nodeIdentifier, + subscribers, + redirectURI + ) + else: + self.pubsubService.notifyDelete( + self.serviceJID, + nodeIdentifier, + subscribers, + redirectURI + ) + + def _notifyDelete(self, data): + d = defer.ensureDeferred(self._aNotifyDelete(data)) + d.addErrback(log.err) + + async def _aNotifyPurge(self, data): + nodeIdentifier = data['node'].nodeIdentifier + pep = data['pep'] + recipient = data['recipient'] + subscribers = data['subscribers'] + if pep: + self.backend.privilege.notifyPurge( + recipient, + nodeIdentifier, + subscribers, + ) + else: + self.pubsubService.notifyPurge( + self.serviceJID, + nodeIdentifier, + subscribers, + ) + + def _notifyPurge(self, data): + d = defer.ensureDeferred(self._aNotifyPurge(data)) + d.addErrback(log.err) def _mapErrors(self, failure): e = failure.trap(*list(self._errorMap.keys())) @@ -1826,10 +1873,12 @@ return d.addErrback(self._mapErrors) def purge(self, request): - d = self.backend.purgeNode(request.nodeIdentifier, + d = defer.ensureDeferred( + self.backend.purgeNode(request.nodeIdentifier, request.sender, self._isPep(request), request.recipient) + ) return d.addErrback(self._mapErrors) def delete(self, request): diff -r 7f1394bb96db -r 0b5233981671 sat_pubsub/privilege.py --- a/sat_pubsub/privilege.py Mon Aug 02 21:56:43 2021 +0200 +++ b/sat_pubsub/privilege.py Mon Aug 02 21:58:17 2021 +0200 @@ -186,39 +186,55 @@ def notifyPublish(self, pep_jid, nodeIdentifier, notifications): """Do notifications using privileges""" for subscriber, subscriptions, items in notifications: - message = self._pubsub_service._createNotification('items', pep_jid, - nodeIdentifier, subscriber, - subscriptions) + message = self._pubsub_service._createNotification( + 'items', + pep_jid, + nodeIdentifier, + subscriber, + subscriptions + ) for item in items: item.uri = pubsub.NS_PUBSUB_EVENT message.event.items.addChild(item) self.sendMessage(message) - def notifyRetract(self, pep_jid, nodeIdentifier, notifications): for subscriber, subscriptions, items in notifications: - message = self._pubsub_service._createNotification('items', pep_jid, - nodeIdentifier, subscriber, - subscriptions) + message = self._pubsub_service._createNotification( + 'items', + pep_jid, + nodeIdentifier, + subscriber, + subscriptions + ) for item in items: retract = domish.Element((None, "retract")) retract['id'] = item['id'] message.event.items.addChild(retract) self.sendMessage(message) + def notifyDelete(self, pep_jid, nodeIdentifier, subscribers, redirectURI=None): + for subscriber in subscribers: + message = self._pubsub_service._createNotification( + 'delete', + pep_jid, + nodeIdentifier, + subscriber + ) + if redirectURI: + redirect = message.event.delete.addElement('redirect') + redirect['uri'] = redirectURI + self.sendMessage(message) - # def notifyDelete(self, service, nodeIdentifier, subscribers, - # redirectURI=None): - # # TODO - # for subscriber in subscribers: - # message = self._createNotification('delete', service, - # nodeIdentifier, - # subscriber) - # if redirectURI: - # redirect = message.event.delete.addElement('redirect') - # redirect['uri'] = redirectURI - # self.send(message) - + def notifyPurge(self, pep_jid, nodeIdentifier, subscribers): + for subscriber in subscribers: + message = self._pubsub_service._createNotification( + 'purge', + pep_jid, + nodeIdentifier, + subscriber + ) + self.sendMessage(message) ## presence ##