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`).
This commit is contained in:
Goffi 2026-10-26 18:39:04 +01:00
commit fa04667152

View file

@ -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"]