Mercurial > libervia-backend
diff sat/plugins/plugin_exp_events.py @ 3462:12dc234f698c
plugin invitation: pubsub invitations:
- new Pubsub invitation plugin, to have a generic way to manage invitation on Pubsub based
features
- `invitePreflight` and `onInvitationPreflight` method can be implemented to customise
invitation for a namespace
- refactored events invitations to use the new plugin
- a Pubsub invitation can now be for a whole node instead of a specific item
- if invitation is for a node, a namespace can be specified to indicate what this node is
about. It is then added in `extra` data
- an element (domish.Element) can be added in `extra` data, it will then be added in the
invitation
- some code modernisation
author | Goffi <goffi@goffi.org> |
---|---|
date | Fri, 19 Feb 2021 15:50:22 +0100 |
parents | 559a625a236b |
children | be6d91572633 |
line wrap: on
line diff
--- a/sat/plugins/plugin_exp_events.py Fri Feb 19 15:49:59 2021 +0100 +++ b/sat/plugins/plugin_exp_events.py Fri Feb 19 15:50:22 2021 +0100 @@ -17,11 +17,13 @@ # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see <http://www.gnu.org/licenses/>. +from typing import Optional import shortuuid from sat.core.i18n import _ from sat.core import exceptions from sat.core.constants import Const as C from sat.core.log import getLogger +from sat.core.xmpp import SatXMPPEntity from sat.tools import utils from sat.tools.common import uri as xmpp_uri from sat.tools.common import date_utils @@ -41,7 +43,7 @@ C.PI_IMPORT_NAME: "EVENTS", C.PI_TYPE: "EXP", C.PI_PROTOCOLS: [], - C.PI_DEPENDENCIES: ["XEP-0060", "INVITATION", "LIST_INTEREST"], + C.PI_DEPENDENCIES: ["XEP-0060", "INVITATION", "PUBSUB_INVITATION", "LIST_INTEREST"], C.PI_RECOMMENDATIONS: ["XEP-0277", "EMAIL_INVITATION"], C.PI_MAIN: "Events", C.PI_HANDLER: "yes", @@ -61,8 +63,7 @@ self._i = self.host.plugins.get("EMAIL_INVITATION") self._b = self.host.plugins.get("XEP-0277") self.host.registerNamespace("event", NS_EVENT) - self.host.plugins["INVITATION"].registerNamespace(NS_EVENT, - self.register) + self.host.plugins["PUBSUB_INVITATION"].register(NS_EVENT, self) host.bridge.addMethod( "eventGet", ".plugin", @@ -232,32 +233,6 @@ raise exceptions.NotFound(_("No event with this id has been found")) defer.returnValue(event_elt) - def register(self, client, name, extra, service, node, event_id, item_elt, - creator=False): - """Register evenement in personal events list - - @param service(jid.JID): pubsub service of the event - @param node(unicode): event node - @param event_id(unicode): event id - @param event_elt(domish.Element): event element - note that this element will be modified in place - @param creator(bool): True if client's profile is the creator of the node - """ - event_elt = item_elt.event - link_elt = event_elt.addElement("link") - link_elt["service"] = service.full() - link_elt["node"] = node - link_elt["item"] = event_id - __, event_data = self._parseEventElt(event_elt) - name = event_data.get('name') - if 'image' in event_data: - extra = {'thumb_url': event_data['image']} - else: - extra = None - return self.host.plugins['LIST_INTEREST'].registerPubsub( - client, NS_EVENT, service, node, event_id, creator, - name=name, element=event_elt, extra=extra) - def _eventGet(self, service, node, id_="", profile_key=C.PROF_KEY_NONE): service = jid.JID(service) if service else None node = node if node else NS_EVENT @@ -289,10 +264,11 @@ node = node or None client = self.host.getClient(profile_key) data["register"] = C.bool(data.get("register", C.BOOL_FALSE)) - return self.eventCreate(client, timestamp, data, service, node, id_ or NS_EVENT) + return defer.ensureDeferred( + self.eventCreate(client, timestamp, data, service, node, id_ or NS_EVENT) + ) - @defer.inlineCallbacks - def eventCreate(self, client, timestamp, data, service, node=None, event_id=NS_EVENT): + async def eventCreate(self, client, timestamp, data, service, node=None, event_id=NS_EVENT): """Create or replace an event @param service(jid.JID, None): PubSub service @@ -341,8 +317,8 @@ del data[k] if key not in data: # FIXME: affiliate invitees - uri_node = yield self._p.createNode(client, service) - yield self._p.setConfiguration( + uri_node = await self._p.createNode(client, service) + await self._p.setConfiguration( client, service, uri_node, @@ -372,17 +348,23 @@ item_elt = pubsub.Item(id=event_id, payload=event_elt) try: # TODO: check auto-create, no need to create node first if available - node = yield self._p.createNode(client, service, nodeIdentifier=node) + node = await self._p.createNode(client, service, nodeIdentifier=node) except error.StanzaError as e: if e.condition == "conflict": log.debug(_("requested node already exists")) - yield self._p.publish(client, service, node, items=[item_elt]) + await self._p.publish(client, service, node, items=[item_elt]) if register: - yield self.register( - client, None, {}, service, node, event_id, item_elt, creator=True) - defer.returnValue(node) + extra = {} + self.onInvitationPreflight( + client, "", extra, service, node, event_id, item_elt + ) + await self.host.plugins['LIST_INTEREST'].registerPubsub( + client, NS_EVENT, service, node, event_id, True, + extra.pop("name", ""), extra.pop("element"), extra + ) + return node def _eventModify(self, service, node, id_, timestamp_update, data_update, profile_key=C.PROF_KEY_NONE): @@ -390,12 +372,14 @@ if not node: raise ValueError(_("missing node")) client = self.host.getClient(profile_key) - return self.eventModify( - client, service, node, id_ or NS_EVENT, timestamp_update or None, data_update + return defer.ensureDeferred( + self.eventModify( + client, service, node, id_ or NS_EVENT, timestamp_update or None, + data_update + ) ) - @defer.inlineCallbacks - def eventModify( + async def eventModify( self, client, service, node, id_=NS_EVENT, timestamp_update=None, data_update=None ): """Update an event @@ -403,13 +387,13 @@ Similar as create instead that it update existing item instead of creating or replacing it. Params are the same as for [eventCreate]. """ - event_timestamp, event_metadata = yield self.eventGet(client, service, node, id_) + event_timestamp, event_metadata = await self.eventGet(client, service, node, id_) new_timestamp = event_timestamp if timestamp_update is None else timestamp_update new_data = event_metadata if data_update: for k, v in data_update.items(): new_data[k] = v - yield self.eventCreate(client, new_timestamp, new_data, service, node, id_) + await self.eventCreate(client, new_timestamp, new_data, service, node, id_) def _eventsListSerialise(self, events): for timestamp, data in events: @@ -543,52 +527,40 @@ invitees[item["id"]] = data defer.returnValue(invitees) - def _invite(self, invitee_jid, service, node, item_id, profile): - client = self.host.getClient(profile) - service = jid.JID(service) if service else None - node = node or None - item_id = item_id or None - invitee_jid = jid.JID(invitee_jid) - return self.invite(client, invitee_jid, service, node, item_id) - - @defer.inlineCallbacks - def invite(self, client, invitee_jid, service, node, item_id=NS_EVENT): - """Invite an entity to the event - - This will set permission to let the entity access everything needed - @pararm invitee_jid(jid.JID): entity to invite - @param service(jid.JID, None): pubsub service - None to use client's PEP - @param node(unicode): event node - @param item_id(unicode): event id - """ - # FIXME: handle name and extra - name = '' - extra = {} + async def invitePreflight( + self, + client: SatXMPPEntity, + invitee_jid: jid.JID, + service: jid.JID, + node: str, + item_id: Optional[str] = None, + name: str = '', + extra: Optional[dict] = None, + ) -> None: if self._b is None: raise exceptions.FeatureNotFound( _('"XEP-0277" (blog) plugin is needed for this feature') ) if item_id is None: - item_id = NS_EVENT + item_id = extra["default_item_id"] = NS_EVENT - # first we authorize our invitee to see the nodes of interest - yield self._p.setNodeAffiliations(client, service, node, {invitee_jid: "member"}) - log.debug(_("affiliation set on event node")) - __, event_data = yield self.eventGet(client, service, node, item_id) + __, event_data = await self.eventGet(client, service, node, item_id) log.debug(_("got event data")) invitees_service = jid.JID(event_data["invitees_service"]) invitees_node = event_data["invitees_node"] blog_service = jid.JID(event_data["blog_service"]) blog_node = event_data["blog_node"] - yield self._p.setNodeAffiliations( + await self._p.setNodeAffiliations( client, invitees_service, invitees_node, {invitee_jid: "publisher"} ) - log.debug(_("affiliation set on invitee node")) - yield self._p.setNodeAffiliations( + log.debug( + f"affiliation set on invitee node (jid: {invitees_service}, " + f"node: {invitees_node!r})" + ) + await self._p.setNodeAffiliations( client, blog_service, blog_node, {invitee_jid: "member"} ) - blog_items, __ = yield self._b.mbGet(client, blog_service, blog_node, None) + blog_items, __ = await self._b.mbGet(client, blog_service, blog_node, None) for item in blog_items: try: @@ -601,15 +573,15 @@ ) ) else: - yield self._p.setNodeAffiliations( + await self._p.setNodeAffiliations( client, comments_service, comments_node, {invitee_jid: "publisher"} ) log.debug(_("affiliation set on blog and comments nodes")) - # now we send the invitation - pubsub_invitation = self.host.plugins['INVITATION'] - pubsub_invitation.sendPubsubInvitation(client, invitee_jid, service, node, - item_id, name, extra) + def _invite(self, invitee_jid, service, node, item_id, profile): + return self.host.plugins["PUBSUB_INVITATION"]._sendPubsubInvitation( + invitee_jid, service, node, item_id or NS_EVENT, profile_key=profile + ) def _inviteByEmail(self, service, node, id_=NS_EVENT, email="", emails_extra=None, name="", host_name="", language="", url_template="", @@ -631,12 +603,11 @@ ): value = locals()[key] kwargs[key] = str(value) - return self.inviteByEmail( + return defer.ensureDeferred(self.inviteByEmail( client, jid.JID(service) if service else None, node, id_ or NS_EVENT, **kwargs - ) + )) - @defer.inlineCallbacks - def inviteByEmail(self, client, service, node, id_=NS_EVENT, **kwargs): + async def inviteByEmail(self, client, service, node, id_=NS_EVENT, **kwargs): """High level method to create an email invitation to an event @param service(unicode, None): PubSub service @@ -656,11 +627,37 @@ "pubsub", path=service.full(), node=node, item=id_ ) kwargs["extra"] = {"event_uri": event_uri} - invitation_data = yield self._i.create(**kwargs) + invitation_data = await self._i.create(**kwargs) invitee_jid = invitation_data["jid"] log.debug(_("invitation created")) # now that we have a jid, we can send normal invitation - yield self.invite(client, invitee_jid, service, node, id_) + await self.invite(client, invitee_jid, service, node, id_) + + def onInvitationPreflight( + self, + client: SatXMPPEntity, + name: str, + extra: dict, + service: jid.JID, + node: str, + item_id: Optional[str], + item_elt: domish.Element + ) -> None: + event_elt = item_elt.event + link_elt = event_elt.addElement("link") + link_elt["service"] = service.full() + link_elt["node"] = node + link_elt["item"] = item_id + __, event_data = self._parseEventElt(event_elt) + try: + name = event_data["name"] + except KeyError: + pass + else: + extra["name"] = name + if 'image' in event_data: + extra["thumb_url"] = event_data['image'] + extra["element"] = event_elt @implementer(iwokkel.IDisco)