From fa04667152a6b1efb0623c7e3a3f77bf18d14699 Mon Sep 17 00:00:00 2001 From: Goffi Date: Mon, 26 Oct 2026 18:39:04 +0100 Subject: [PATCH] cli (blog): preserve existing item fields on `set -i` + attachments fixes: - `set -i` was replacing all fields of any existing item, losing tags, attachments, publication date, etc. It now fetches the existing item if any, and starts from its data. `-r/--replace` can be used to force a full replacement (and avoid fetching old item). - `--attachment` uses `action="extend"` so multiple `-a` can be used. - Fix attachement data key (`url` -> `sources`). --- libervia/cli/cmd_blog.py | 67 +++++++++++++++++++++++++++++++--------- 1 file changed, 53 insertions(+), 14 deletions(-) diff --git a/libervia/cli/cmd_blog.py b/libervia/cli/cmd_blog.py index e663e276..8cbc17fc 100644 --- a/libervia/cli/cmd_blog.py +++ b/libervia/cli/cmd_blog.py @@ -39,6 +39,7 @@ from libervia.backend.tools.common import data_format from libervia.backend.tools.common.ansi import ANSI as A from libervia.cli import common from libervia.cli.constants import Const as C +from libervia.frontends.bridge.bridge_frontend import BridgeException from . import base, cmd_pubsub @@ -145,6 +146,23 @@ class AltLinkAction(argparse.Action): class BlogPublishCommon: """handle common option for publising commands (Set and Edit)""" + async def get_existing_item(self, service, node, item): + """Fetch the data of an existing item from the pubsub service. + + @param service: JID of the pubsub service (None for PEP) + @param node: identifier of the pubsub node (None for the default one) + @param item: ID of the item to fetch (None for the latest item) + @return: deserialised data of the item + @raise BridgeException: if the item can't be fetched (e.g. "item-not-found") + """ + items = [item] if item else [] + mb_data = data_format.deserialise( + await self.host.bridge.mb_get( + service, node, 1, items, data_format.serialise({}), self.profile + ) + ) + return mb_data["items"][0] + async def get_current_syntax(self): """Retrieve current_syntax @@ -190,6 +208,7 @@ class BlogPublishCommon: "-a", "--attachment", dest="attachments", + action="extend", nargs="+", help=_("attachment in the form URL [metadata_name=value]"), ) @@ -282,13 +301,13 @@ class BlogPublishCommon: f" accepted): {arg}" ) if attachment: - # if we hae a new URL, we have a new attachment + # if we have a new URL, we have a new attachment attachments.append(attachment) attachment = {} - attachment["url"] = arg + attachment["sources"] = [{"url": arg}] else: # we should have a metadata - if "url" not in attachment: + if "sources" not in attachment: self.parser.error( "you must to specify an URL before any metadata in " "--attachment" @@ -351,13 +370,40 @@ class Set(base.CommandBase, BlogPublishCommon): def add_parser_options(self): BlogPublishCommon.add_parser_options(self) + self.parser.add_argument( + "-r", + "--replace", + action="store_true", + help=_( + "don't fetch the existing item, replace all its fields with " + "the given ones (only used with -i)" + ), + ) async def start(self): self.current_syntax = await self.get_current_syntax() self.pubsub_item = self.args.item - mb_data = { - "service": self.args.service or None, - } + if self.args.replace and not self.pubsub_item: + self.parser.error("--replace can only be used with -i") + mb_data = {} + if self.pubsub_item and not self.args.replace: + # start from the existing item data, so fields not given on the command line + # (tags, attachments, publication date, etc.) are kept + try: + existing = await self.get_existing_item( + self.args.service, self.args.node, self.pubsub_item + ) + except BridgeException as e: + if e.condition == "item-not-found": + self.disp(f"item {self.pubsub_item!r} not found, creating a new one") + else: + self.disp(f"can't get item: {e}", error=True) + self.host.quit(C.EXIT_BRIDGE_ERRBACK) + else: + for key in KEY_TO_REMOVE_METADATA: + existing.pop(key, None) + mb_data.update(existing) + mb_data["service"] = self.args.service or None if self.args.node: mb_data["node"] = self.args.node self.set_mb_data_from_args(mb_data) @@ -731,14 +777,7 @@ class Edit(base.CommandBase, BlogPublishCommon, common.BaseEdit): return SYNTAX_EXT.get(self.current_syntax, SYNTAX_EXT[""]) async def get_item_data(self, service, node, item): - items = [item] if item else [] - - mb_data = data_format.deserialise( - await self.host.bridge.mb_get( - service, node, 1, items, data_format.serialise({}), self.profile - ) - ) - item = mb_data["items"][0] + item = await self.get_existing_item(service, node, item) try: content = item["content_xhtml"]