cli (blog): add --comments-from to target an item comments node:
- add `--comments-from <item_id>` and `--comments-from-last` to automatically retrieve the
comments node of a blog post.
- ⚠️`--draft-path` short option moved from `-F` to `-d` (so `-F` can be used for
`--comments-from`).
This commit is contained in:
parent
45112fb22e
commit
25f1aa9178
2 changed files with 111 additions and 10 deletions
|
|
@ -439,7 +439,7 @@ class LiberviaCli:
|
||||||
"-D", "--current", action="store_true", help=_("load current draft")
|
"-D", "--current", action="store_true", help=_("load current draft")
|
||||||
)
|
)
|
||||||
draft_group.add_argument(
|
draft_group.add_argument(
|
||||||
"-F", "--draft-path", type=Path, help=_("path to a draft file to retrieve")
|
"-d", "--draft-path", type=Path, help=_("path to a draft file to retrieve")
|
||||||
)
|
)
|
||||||
|
|
||||||
def make_pubsub_group(self, flags, defaults):
|
def make_pubsub_group(self, flags, defaults):
|
||||||
|
|
|
||||||
|
|
@ -143,11 +143,31 @@ class AltLinkAction(argparse.Action):
|
||||||
alt_links.append(alt_link)
|
alt_links.append(alt_link)
|
||||||
|
|
||||||
|
|
||||||
class BlogPublishCommon:
|
class CommentsFromCommon:
|
||||||
"""handle common option for publising commands (Set and Edit)"""
|
"""handle the --comments-from option"""
|
||||||
|
|
||||||
async def get_existing_item(self, service, node, item):
|
def add_comments_from_options(self):
|
||||||
"""Fetch the data of an existing item from the pubsub service.
|
"""Add the --comments-from options to the parser"""
|
||||||
|
group = self.parser.add_mutually_exclusive_group()
|
||||||
|
group.add_argument(
|
||||||
|
"-F",
|
||||||
|
"--comments-from",
|
||||||
|
nargs="?",
|
||||||
|
const="",
|
||||||
|
default=None,
|
||||||
|
metavar="PARENT_ITEM_ID",
|
||||||
|
help=_(
|
||||||
|
"target the comments node of the given item (or URL item if provided)"
|
||||||
|
),
|
||||||
|
)
|
||||||
|
group.add_argument(
|
||||||
|
"--comments-from-last",
|
||||||
|
action="store_true",
|
||||||
|
help=_("target the comments node of the last item of the node"),
|
||||||
|
)
|
||||||
|
|
||||||
|
async def get_item(self, service, node, item):
|
||||||
|
"""Fetch an existing item from a pubsub service
|
||||||
|
|
||||||
@param service: JID of the pubsub service (None for PEP)
|
@param service: JID of the pubsub service (None for PEP)
|
||||||
@param node: identifier of the pubsub node (None for the default one)
|
@param node: identifier of the pubsub node (None for the default one)
|
||||||
|
|
@ -163,6 +183,76 @@ class BlogPublishCommon:
|
||||||
)
|
)
|
||||||
return mb_data["items"][0]
|
return mb_data["items"][0]
|
||||||
|
|
||||||
|
def get_url_item(self):
|
||||||
|
"""Return the item ID from the -u URL, if any
|
||||||
|
|
||||||
|
@return: item ID from the URL, None if there is no URL or no item in it
|
||||||
|
"""
|
||||||
|
url = self.args.pubsub_url
|
||||||
|
if not url:
|
||||||
|
return None
|
||||||
|
if url.startswith("http"):
|
||||||
|
url = self.host.get_xmpp_uri_from_http(url)
|
||||||
|
return uri.parse_xmpp_uri(url).get("item")
|
||||||
|
|
||||||
|
def resolve_comments_args(self):
|
||||||
|
"""Adjust the parsed args for the --comments-from option
|
||||||
|
|
||||||
|
The item from the -u URL is the parent item, not an item to process: the base
|
||||||
|
class merged it in the item options, we retrieve it here.
|
||||||
|
"""
|
||||||
|
self.args.url_item = self.get_url_item()
|
||||||
|
if self.args.comments_from == "" and not self.args.url_item:
|
||||||
|
self.parser.error(
|
||||||
|
_(
|
||||||
|
"--comments-from without item ID can only be used "
|
||||||
|
"with a -u URL containing an item"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
if self.args.url_item:
|
||||||
|
if hasattr(self.args, "item"):
|
||||||
|
if self.args.item == self.args.url_item:
|
||||||
|
self.args.item = ""
|
||||||
|
elif self.args.items == [self.args.url_item]:
|
||||||
|
self.args.items = []
|
||||||
|
|
||||||
|
async def resolve_comments_from(self):
|
||||||
|
"""Resolve the comments node and update the service and node args
|
||||||
|
|
||||||
|
The service/node options then locate the parent item, not the comments node.
|
||||||
|
"""
|
||||||
|
if self.args.comments_from is None and not self.args.comments_from_last:
|
||||||
|
return
|
||||||
|
self.resolve_comments_args()
|
||||||
|
self.args.service, self.args.node = await self.resolve_comments_target()
|
||||||
|
|
||||||
|
async def resolve_comments_target(self):
|
||||||
|
"""Return the (service, node) of the parent item's comments node."""
|
||||||
|
if self.args.comments_from_last:
|
||||||
|
parent_item = None
|
||||||
|
else:
|
||||||
|
parent_item = self.args.comments_from or self.args.url_item
|
||||||
|
try:
|
||||||
|
parent = await self.get_item(self.args.service, self.args.node, parent_item)
|
||||||
|
except BridgeException as e:
|
||||||
|
if e.classname == "NotFound":
|
||||||
|
self.disp(f"parent item {parent_item!r} not found", error=True)
|
||||||
|
self.host.quit(C.EXIT_NOT_FOUND)
|
||||||
|
self.disp(f"can't get parent item: {e}", error=True)
|
||||||
|
self.host.quit(C.EXIT_BRIDGE_ERRBACK)
|
||||||
|
comments = parent.get("comments")
|
||||||
|
if not comments:
|
||||||
|
self.disp(
|
||||||
|
"parent item has no comments node (comments disabled?)",
|
||||||
|
error=True,
|
||||||
|
)
|
||||||
|
self.host.quit(C.EXIT_DATA_ERROR)
|
||||||
|
return comments[0]["service"], comments[0]["node"]
|
||||||
|
|
||||||
|
|
||||||
|
class BlogPublishCommon(CommentsFromCommon):
|
||||||
|
"""handle common option for publising commands (Set and Edit)"""
|
||||||
|
|
||||||
async def get_current_syntax(self):
|
async def get_current_syntax(self):
|
||||||
"""Retrieve current_syntax
|
"""Retrieve current_syntax
|
||||||
|
|
||||||
|
|
@ -191,6 +281,7 @@ class BlogPublishCommon:
|
||||||
return self.args.syntax
|
return self.args.syntax
|
||||||
|
|
||||||
def add_parser_options(self):
|
def add_parser_options(self):
|
||||||
|
self.add_comments_from_options()
|
||||||
self.parser.add_argument("-T", "--title", help=_("title of the item"))
|
self.parser.add_argument("-T", "--title", help=_("title of the item"))
|
||||||
self.parser.add_argument(
|
self.parser.add_argument(
|
||||||
"-t",
|
"-t",
|
||||||
|
|
@ -382,6 +473,7 @@ class Set(base.CommandBase, BlogPublishCommon):
|
||||||
|
|
||||||
async def start(self):
|
async def start(self):
|
||||||
self.current_syntax = await self.get_current_syntax()
|
self.current_syntax = await self.get_current_syntax()
|
||||||
|
await self.resolve_comments_from()
|
||||||
self.pubsub_item = self.args.item
|
self.pubsub_item = self.args.item
|
||||||
if self.args.replace and not self.pubsub_item:
|
if self.args.replace and not self.pubsub_item:
|
||||||
self.parser.error("--replace can only be used with -i")
|
self.parser.error("--replace can only be used with -i")
|
||||||
|
|
@ -390,11 +482,11 @@ class Set(base.CommandBase, BlogPublishCommon):
|
||||||
# start from the existing item data, so fields not given on the command line
|
# start from the existing item data, so fields not given on the command line
|
||||||
# (tags, attachments, publication date, etc.) are kept
|
# (tags, attachments, publication date, etc.) are kept
|
||||||
try:
|
try:
|
||||||
existing = await self.get_existing_item(
|
existing = await self.get_item(
|
||||||
self.args.service, self.args.node, self.pubsub_item
|
self.args.service, self.args.node, self.pubsub_item
|
||||||
)
|
)
|
||||||
except BridgeException as e:
|
except BridgeException as e:
|
||||||
if e.condition == "item-not-found":
|
if e.classname == "NotFound":
|
||||||
self.disp(f"item {self.pubsub_item!r} not found, creating a new one")
|
self.disp(f"item {self.pubsub_item!r} not found, creating a new one")
|
||||||
else:
|
else:
|
||||||
self.disp(f"can't get item: {e}", error=True)
|
self.disp(f"can't get item: {e}", error=True)
|
||||||
|
|
@ -425,7 +517,7 @@ class Set(base.CommandBase, BlogPublishCommon):
|
||||||
self.host.quit(C.EXIT_OK)
|
self.host.quit(C.EXIT_OK)
|
||||||
|
|
||||||
|
|
||||||
class Get(base.CommandBase):
|
class Get(base.CommandBase, CommentsFromCommon):
|
||||||
TEMPLATE = "blog/articles.html"
|
TEMPLATE = "blog/articles.html"
|
||||||
|
|
||||||
def __init__(self, host):
|
def __init__(self, host):
|
||||||
|
|
@ -443,7 +535,8 @@ class Get(base.CommandBase):
|
||||||
)
|
)
|
||||||
|
|
||||||
def add_parser_options(self):
|
def add_parser_options(self):
|
||||||
# TODO: a key(s) argument to select keys to display
|
self.add_comments_from_options()
|
||||||
|
# TODO: a key(s) argument to select keys to display
|
||||||
self.parser.add_argument(
|
self.parser.add_argument(
|
||||||
"-k",
|
"-k",
|
||||||
"--key",
|
"--key",
|
||||||
|
|
@ -607,6 +700,7 @@ class Get(base.CommandBase):
|
||||||
print(("\n" + sep + "\n"))
|
print(("\n" + sep + "\n"))
|
||||||
|
|
||||||
async def start(self):
|
async def start(self):
|
||||||
|
await self.resolve_comments_from()
|
||||||
try:
|
try:
|
||||||
mb_data = data_format.deserialise(
|
mb_data = data_format.deserialise(
|
||||||
await self.host.bridge.mb_get(
|
await self.host.bridge.mb_get(
|
||||||
|
|
@ -777,7 +871,7 @@ class Edit(base.CommandBase, BlogPublishCommon, common.BaseEdit):
|
||||||
return SYNTAX_EXT.get(self.current_syntax, SYNTAX_EXT[""])
|
return SYNTAX_EXT.get(self.current_syntax, SYNTAX_EXT[""])
|
||||||
|
|
||||||
async def get_item_data(self, service, node, item):
|
async def get_item_data(self, service, node, item):
|
||||||
item = await self.get_existing_item(service, node, item)
|
item = await self.get_item(service, node, item)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
content = item["content_xhtml"]
|
content = item["content_xhtml"]
|
||||||
|
|
@ -812,6 +906,13 @@ class Edit(base.CommandBase, BlogPublishCommon, common.BaseEdit):
|
||||||
# if there are user defined extension, we use them
|
# if there are user defined extension, we use them
|
||||||
SYNTAX_EXT.update(self.host.cli_settings.syntax_ext)
|
SYNTAX_EXT.update(self.host.cli_settings.syntax_ext)
|
||||||
self.current_syntax = await self.get_current_syntax()
|
self.current_syntax = await self.get_current_syntax()
|
||||||
|
if self.args.comments_from is not None or self.args.comments_from_last:
|
||||||
|
self.resolve_comments_args()
|
||||||
|
if not self.args.item and not self.args.last_item:
|
||||||
|
self.parser.error(
|
||||||
|
_("edit with --comments-from requires -i (comment ID) or -L")
|
||||||
|
)
|
||||||
|
self.args.service, self.args.node = await self.resolve_comments_target()
|
||||||
|
|
||||||
(
|
(
|
||||||
self.pubsub_service,
|
self.pubsub_service,
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue