changeset 3519:02eec2a5b5f9

plugin XEP-0060, XEP-0277: new rename methods (`psItemRename`, `mbRename`): Those methods recreate an item to given new ID, and if successful, delete the former one.
author Goffi <goffi@goffi.org>
date Sat, 01 May 2021 18:37:57 +0200
parents b258dce27d6d
children 8acaf857cd0a
files sat/plugins/plugin_xep_0060.py sat/plugins/plugin_xep_0277.py
diffstat 2 files changed, 86 insertions(+), 5 deletions(-) [+]
line wrap: on
line diff
--- a/sat/plugins/plugin_xep_0060.py	Sat May 01 18:36:13 2021 +0200
+++ b/sat/plugins/plugin_xep_0060.py	Sat May 01 18:37:57 2021 +0200
@@ -17,6 +17,7 @@
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 
+from typing import Optional
 from collections import namedtuple
 import urllib.request, urllib.parse, urllib.error
 from functools import reduce
@@ -34,6 +35,7 @@
 from sat.core.i18n import _
 from sat.core.constants import Const as C
 from sat.core.log import getLogger
+from sat.core.xmpp import SatXMPPEntity
 from sat.core import exceptions
 from sat.tools import sat_defer
 from sat.tools import xml_tools
@@ -233,6 +235,14 @@
             async_=True,
         )
         host.bridge.addMethod(
+            "psItemRename",
+            ".plugin",
+            in_sign="sssss",
+            out_sign="",
+            method=self._renameItem,
+            async_=True,
+        )
+        host.bridge.addMethod(
             "psSubscribe",
             ".plugin",
             in_sign="ssa{ss}s",
@@ -1031,26 +1041,61 @@
     def _retractItems(
         self, service_s, nodeIdentifier, itemIdentifiers, notify, profile_key
     ):
+        client = self.host.getClient(profile_key)
         return self.retractItems(
+            client,
             jid.JID(service_s) if service_s else None,
             nodeIdentifier,
             itemIdentifiers,
             notify,
-            profile_key,
         )
 
     def retractItems(
         self,
+        client,
         service,
         nodeIdentifier,
         itemIdentifiers,
         notify=True,
+    ):
+        return client.pubsub_client.retractItems(
+            service, nodeIdentifier, itemIdentifiers, notify=True
+        )
+
+    def _renameItem(
+        self,
+        service,
+        node,
+        item_id,
+        new_id,
         profile_key=C.PROF_KEY_NONE,
     ):
         client = self.host.getClient(profile_key)
-        return client.pubsub_client.retractItems(
-            service, nodeIdentifier, itemIdentifiers, notify=True
-        )
+        service = jid.JID(service) if service else None
+        return defer.ensureDeferred(self.renameItem(
+            client, service, node, item_id, new_id
+        ))
+
+    async def renameItem(
+        self,
+        client: SatXMPPEntity,
+        service: Optional[jid.JID],
+        node: str,
+        item_id: str,
+        new_id: str
+    ) -> None:
+        """Rename an item by recreating it then deleting it
+
+        we have to recreate then delete because there is currently no rename operation
+        with PubSub
+        """
+        if not item_id or not new_id:
+            raise ValueError("item_id and new_id must not be empty")
+        # retract must be done last, so if something goes wrong, the exception will stop
+        # the workflow and no accidental delete should happen
+        item_elt = (await self.getItems(client, service, node, item_ids=[item_id]))[0][0]
+        await self.sendItem(client, service, node, item_elt.firstChildElement(), new_id)
+        await self.retractItems(client, service, node, [item_id])
 
     def _subscribe(self, service, nodeIdentifier, options, profile_key=C.PROF_KEY_NONE):
         client = self.host.getClient(profile_key)
--- a/sat/plugins/plugin_xep_0277.py	Sat May 01 18:36:13 2021 +0200
+++ b/sat/plugins/plugin_xep_0277.py	Sat May 01 18:37:57 2021 +0200
@@ -124,6 +124,14 @@
             async_=True,
         )
         host.bridge.addMethod(
+            "mbRename",
+            ".plugin",
+            in_sign="sssss",
+            out_sign="",
+            method=self._mbRename,
+            async_=True,
+        )
+        host.bridge.addMethod(
             "mbSetAccess",
             ".plugin",
             in_sign="ss",
@@ -813,7 +821,14 @@
 
     def friendlyId(self, data):
         """Generate a user friendly id from title or content"""
-        id_base = regex.urlFriendlyText(data.get('title') or data.get('content', ''))
+        # TODO: rich content should be converted to plain text
+        id_base = regex.urlFriendlyText(
+            data.get('title')
+            or data.get('title_rich')
+            or data.get('content')
+            or data.get('content_rich')
+            or ''
+        )
         return f"{id_base}-{token_urlsafe(3)}"
 
     def _mbSend(self, service, node, data, profile_key):
@@ -954,6 +969,27 @@
             items_data, partial(self.item2mbdata, client, service=service, node=node))
         defer.returnValue(mb_data)
 
+    def _mbRename(self, service, node, item_id, new_id, profile_key):
+        return defer.ensureDeferred(self.mbRename(
+            self.host.getClient(profile_key),
+            jid.JID(service) if service else None,
+            node or None,
+            item_id,
+            new_id
+        ))
+
+    async def mbRename(
+        self,
+        client: SatXMPPEntity,
+        service: Optional[jid.JID],
+        node: Optional[str],
+        item_id: str,
+        new_id: str
+    ) -> None:
+        if not node:
+            node = NS_MICROBLOG
+        await self._p.renameItem(client, service, node, item_id, new_id)
+
     def parseCommentUrl(self, node_url):
         """Parse a XMPP URI