diff libervia/backend/plugins/plugin_xep_0060.py @ 4327:554a87ae17a6

plugin XEP-0048, XEP-0402; CLI (bookmarks): implement XEP-0402 (PEP Native Bookmarks): - Former bookmarks implementation is now labeled as "legacy". - XEP-0402 is now used for bookmarks when relevant namespaces are found, and it fallbacks to legacy XEP-0048/XEP-0049 bookmarks otherwise. - CLI legacy bookmark commands have been moved to `bookmarks legacy` - CLI bookmarks commands now use the new XEP-0402 (with fallback to legacy one automatically used if necessary).
author Goffi <goffi@goffi.org>
date Wed, 20 Nov 2024 11:43:27 +0100
parents a0ed5c976bf8
children 111dce64dcb5
line wrap: on
line diff
--- a/libervia/backend/plugins/plugin_xep_0060.py	Wed Nov 20 11:38:44 2024 +0100
+++ b/libervia/backend/plugins/plugin_xep_0060.py	Wed Nov 20 11:43:27 2024 +0100
@@ -102,6 +102,7 @@
     ID_SINGLETON = "current"
     EXTRA_PUBLISH_OPTIONS = "publish_options"
     EXTRA_ON_PRECOND_NOT_MET = "on_precondition_not_met"
+    EXTRA_AUTOCREATE = "autocreate"
     # extra disco needed for RSM, cf. XEP-0060 ยง 6.5.4
     DISCO_RSM = "http://jabber.org/protocol/pubsub#rsm"
 
@@ -608,6 +609,8 @@
                 * publish_without_options: re-publish without the publish-options.
                     A warning will be logged showing that the publish-options could not
                     be used
+            - self.EXTRA_AUTOCREATE(bool): Create the node if it's not found, and the
+              service doesn't do autocreate itself.
         @return: ids of the created items
         """
         if extra is None:
@@ -631,7 +634,25 @@
                 sender=sender,
             )
         except error.StanzaError as e:
-            if (
+            if e.condition == "item-not-found":
+                if extra.get(self.EXTRA_AUTOCREATE, False):
+                    # Autocreate is requested, we create the requested node.
+                    await self.createNode(
+                        client, service, nodeIdentifier, publish_options
+                    )
+                    # And we try again.
+                    iq_result = await self.publish(
+                        client,
+                        service,
+                        nodeIdentifier,
+                        parsed_items,
+                        options=publish_options,
+                        sender=sender,
+                    )
+                else:
+                    raise e
+
+            elif (
                 e.condition == "conflict"
                 and e.appCondition
                 and e.appCondition.name == "precondition-not-met"
@@ -690,15 +711,15 @@
         client: SatXMPPEntity,
         service: jid.JID,
         nodeIdentifier: str,
-        items: Optional[List[domish.Element]] = None,
-        options: Optional[dict] = None,
-        sender: Optional[jid.JID] = None,
-        extra: Optional[Dict[str, Any]] = None,
+        items: list[pubsub.Item]|None = None,
+        options: dict|None = None,
+        sender: jid.JID|None = None,
+        extra: dict[str, Any]|None = None,
     ) -> domish.Element:
         """Publish pubsub items
 
         @param sender: sender of the request,
-            client.jid will be used if nto set
+            client.jid will be used if not set
         @param extra: extra data
             not used directly by ``publish``, but may be used in triggers
         @return: IQ result stanza
@@ -786,26 +807,26 @@
     async def get_items(
         self,
         client: SatXMPPEntity,
-        service: Optional[jid.JID],
+        service: jid.JID|None,
         node: str,
-        max_items: Optional[int] = None,
-        item_ids: Optional[List[str]] = None,
-        sub_id: Optional[str] = None,
-        rsm_request: Optional[rsm.RSMRequest] = None,
-        extra: Optional[dict] = None,
-    ) -> Tuple[List[domish.Element], dict]:
+        max_items: int|None = None,
+        item_ids: list[str]|None = None,
+        sub_id: str|None = None,
+        rsm_request: rsm.RSMRequest|None = None,
+        extra: dict|None = None,
+    ) -> tuple[list[domish.Element], dict]:
         """Retrieve pubsub items from a node.
 
-        @param service (JID, None): pubsub service.
-        @param node (str): node id.
-        @param max_items (int): optional limit on the number of retrieved items.
+        @param service: pubsub service.
+        @param node: node id.
+        @param max_items: optional limit on the number of retrieved items.
         @param item_ids (list[str]): identifiers of the items to be retrieved (can't be
              used with rsm_request). If requested items don't exist, they won't be
              returned, meaning that we can have an empty list as result (NotFound
              exception is NOT raised).
-        @param sub_id (str): optional subscription identifier.
-        @param rsm_request (rsm.RSMRequest): RSM request data
-        @return: a deferred couple (list[dict], dict) containing:
+        @param sub_id : optional subscription identifier.
+        @param rsm_request: RSM request data
+        @return: a deferred tuple containing:
             - list of items
             - metadata with the following keys:
                 - rsm_first, rsm_last, rsm_count, rsm_index: first, last, count and index
@@ -980,11 +1001,11 @@
 
     def createNode(
         self,
-        client: SatXMPPClient,
+        client: SatXMPPEntity,
         service: jid.JID,
         nodeIdentifier: Optional[str] = None,
         options: Optional[Dict[str, str]] = None,
-    ) -> str:
+    ) -> defer.Deferred[str]:
         """Create a new node
 
         @param service: PubSub service,
@@ -1234,7 +1255,7 @@
 
     def retract_items(
         self,
-        client: SatXMPPClient,
+        client: SatXMPPEntity,
         service: jid.JID,
         nodeIdentifier: str,
         itemIdentifiers: Iterable[str],