changeset 3866:915fb230cb28

cli (blog, pubsub): new `attachments` subcommands: `pubsub/attachments` subcommands has a `get` and a `set` subcommand to manage attachments of a pubsub item. `blog` has the same subcommands, the only difference is that if `--node` is not specified, the default blog namespace will be used. rel 370
author Goffi <goffi@goffi.org>
date Wed, 20 Jul 2022 17:55:11 +0200
parents 59fbb66b2923
children c3e6c54660da
files sat_frontends/jp/base.py sat_frontends/jp/cmd_blog.py sat_frontends/jp/cmd_pubsub.py
diffstat 3 files changed, 189 insertions(+), 4 deletions(-) [+]
line wrap: on
line diff
--- a/sat_frontends/jp/base.py	Wed Jul 20 17:53:12 2022 +0200
+++ b/sat_frontends/jp/base.py	Wed Jul 20 17:55:11 2022 +0200
@@ -34,7 +34,7 @@
 import termios
 from pathlib import Path
 from glob import iglob
-from typing import Optional
+from typing import Optional, Set
 from importlib import import_module
 from sat_frontends.tools.jid import JID
 from sat.tools import config
@@ -1319,6 +1319,14 @@
         for cls in subcommands:
             cls(self)
 
+    def overridePubsubFlags(self, new_flags: Set[str]) -> None:
+        """Replace pubsub_flags given in __init__
+
+        useful when a command is extending an other command (e.g. blog command which does
+        the same as pubsub command, but with a default node)
+        """
+        self._pubsub_flags = new_flags
+
     async def run(self):
         """this method is called when a command is actually run
 
--- a/sat_frontends/jp/cmd_blog.py	Wed Jul 20 17:53:12 2022 +0200
+++ b/sat_frontends/jp/cmd_blog.py	Wed Jul 20 17:55:11 2022 +0200
@@ -27,7 +27,7 @@
 import asyncio
 from asyncio.subprocess import DEVNULL
 from pathlib import Path
-from . import base
+from . import base, cmd_pubsub
 from sat.core.i18n import _
 from sat_frontends.jp.constants import Const as C
 from sat_frontends.jp import common
@@ -1070,12 +1070,63 @@
                     error=True,
                 )
                 self.host.quit(1)
+            else:
+                await self.set_progress_id(progress_id)
 
-            await self.set_progress_id(progress_id)
+
+class AttachmentGet(cmd_pubsub.AttachmentGet):
+
+    def __init__(self, host):
+        super().__init__(host)
+        self.overridePubsubFlags({C.SERVICE, C.SINGLE_ITEM})
+
+
+    async def start(self):
+        if not self.args.node:
+            namespaces = await self.host.bridge.namespacesGet()
+            try:
+                ns_microblog = namespaces["microblog"]
+            except KeyError:
+                self.disp("XEP-0277 plugin is not loaded", error=True)
+                self.host.quit(C.EXIT_MISSING_FEATURE)
+            else:
+                self.args.node = ns_microblog
+        return await super().start()
+
+
+class AttachmentSet(cmd_pubsub.AttachmentSet):
+
+    def __init__(self, host):
+        super().__init__(host)
+        self.overridePubsubFlags({C.SERVICE, C.SINGLE_ITEM})
+
+    async def start(self):
+        if not self.args.node:
+            namespaces = await self.host.bridge.namespacesGet()
+            try:
+                ns_microblog = namespaces["microblog"]
+            except KeyError:
+                self.disp("XEP-0277 plugin is not loaded", error=True)
+                self.host.quit(C.EXIT_MISSING_FEATURE)
+            else:
+                self.args.node = ns_microblog
+        return await super().start()
+
+
+class Attachments(base.CommandBase):
+    subcommands = (AttachmentGet, AttachmentSet)
+
+    def __init__(self, host):
+        super().__init__(
+            host,
+            "attachments",
+            use_profile=False,
+            help=_("set or retrieve blog attachments"),
+        )
 
 
 class Blog(base.CommandBase):
-    subcommands = (Set, Get, Edit, Rename, Repeat, Preview, Import)
+    subcommands = (Set, Get, Edit, Rename, Repeat, Preview, Import, Attachments)
 
     def __init__(self, host):
         super(Blog, self).__init__(
--- a/sat_frontends/jp/cmd_pubsub.py	Wed Jul 20 17:53:12 2022 +0200
+++ b/sat_frontends/jp/cmd_pubsub.py	Wed Jul 20 17:55:11 2022 +0200
@@ -2419,6 +2419,131 @@
             self.display_uri(None)
 
 
+class AttachmentGet(base.CommandBase):
+    def __init__(self, host):
+        super().__init__(
+            host,
+            "get",
+            use_output=C.OUTPUT_LIST_DICT,
+            use_pubsub=True,
+            pubsub_flags={C.SERVICE, C.NODE, C.SINGLE_ITEM},
+            help=_("get data attached to an item"),
+        )
+
+    def add_parser_options(self):
+        self.parser.add_argument(
+            "-j",
+            "--jid",
+            action="append",
+            dest="jids",
+            help=_(
+                "get attached data published only by those JIDs (DEFAULT: get all "
+                "attached data)"
+            )
+        )
+
+    async def start(self):
+        try:
+            attached_data, __ = await self.host.bridge.psAttachmentsGet(
+                self.args.service,
+                self.args.node,
+                self.args.item,
+                self.args.jids or [],
+                "",
+                self.profile,
+            )
+        except Exception as e:
+            self.disp(f"can't get attached data: {e}", error=True)
+            self.host.quit(C.EXIT_BRIDGE_ERRBACK)
+        else:
+            attached_data = data_format.deserialise(attached_data, type_check=list)
+            await self.output(attached_data)
+            self.host.quit(C.EXIT_OK)
+
+
+class AttachmentSet(base.CommandBase):
+    def __init__(self, host):
+        super().__init__(
+            host,
+            "set",
+            use_pubsub=True,
+            pubsub_flags={C.SERVICE, C.NODE, C.SINGLE_ITEM},
+            help=_("attach data to an item"),
+        )
+
+    def add_parser_options(self):
+        self.parser.add_argument(
+            "-R",
+            "--replace",
+            action="store_true",
+            help=_(
+                "replace previous versions of attachments (DEFAULT: update previous "
+                "version)"
+            )
+        )
+        self.parser.add_argument(
+            "-N",
+            "--noticed",
+            metavar="BOOLEAN",
+            nargs="?",
+            default="keep",
+            help=_("mark item as (un)noticed (DEFAULT: keep current value))")
+        )
+        self.parser.add_argument(
+            "-r",
+            "--reactions",
+            # FIXME: to be replace by "extend" when we stop supporting python 3.7
+            action="append",
+            help=_("add emojis to react to an item")
+        )
+
+    async def start(self):
+        mb_data = {
+            "service": self.args.service,
+            "node": self.args.node,
+            "id": self.args.item,
+            "extra": {}
+        }
+        operation = "replace" if self.args.replace else "update"
+        if self.args.noticed != "keep":
+            if self.args.noticed is None:
+                self.args.noticed = C.BOOL_TRUE
+            mb_data["extra"]["noticed"] = C.bool(self.args.noticed)
+
+        if self.args.reactions is not None:
+            mb_data["extra"]["reaction"] = {
+                "operation": operation,
+                "reactions": [r for emojis in self.args.reactions for r in emojis]
+            }
+
+        if not mb_data["extra"]:
+            self.parser.error(_("At leat one attachment must be specified."))
+
+        try:
+            await self.host.bridge.psAttachmentsSet(
+                data_format.serialise(mb_data),
+                self.profile,
+            )
+        except Exception as e:
+            self.disp(f"can't attach data to item: {e}", error=True)
+            self.host.quit(C.EXIT_BRIDGE_ERRBACK)
+        else:
+            self.disp("data attached")
+            self.host.quit(C.EXIT_OK)
+
+
+class Attachments(base.CommandBase):
+    subcommands = (AttachmentGet, AttachmentSet)
+
+    def __init__(self, host):
+        super().__init__(
+            host,
+            "attachments",
+            use_profile=False,
+            help=_("set or retrieve items attachments"),
+        )
+
+
 class HookCreate(base.CommandBase):
     def __init__(self, host):
         base.CommandBase.__init__(
@@ -2580,6 +2705,7 @@
         Reference,
         Search,
         Transform,
+        Attachments,
         Hook,
         Uri,
         Node,