# HG changeset patch # User Goffi # Date 1658332511 -7200 # Node ID 915fb230cb287ee12cacc6c5d8a44ac0bc8dc5d5 # Parent 59fbb66b292361c2e362b9821860cc3f98dac626 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 diff -r 59fbb66b2923 -r 915fb230cb28 sat_frontends/jp/base.py --- 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 diff -r 59fbb66b2923 -r 915fb230cb28 sat_frontends/jp/cmd_blog.py --- 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__( diff -r 59fbb66b2923 -r 915fb230cb28 sat_frontends/jp/cmd_pubsub.py --- 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,