diff --git a/doc/libervia-cli/forums.rst b/doc/libervia-cli/forums.rst index d44dcbd5..577b6c51 100644 --- a/doc/libervia-cli/forums.rst +++ b/doc/libervia-cli/forums.rst @@ -28,6 +28,22 @@ Get structure of French forums in JSON:: $ li forums get -k fr -O json +set +=== + +Set forums from JSON, the JSON must be given as input. + +Check :ref:`libervia-cli_blog_edit` for the data format. + +example +------- + +Set the forums structure from a ``forums.json`` file:: + + $ li forums set < forums.json + + +.. _libervia-cli_forums_edit: edit ==== @@ -51,6 +67,8 @@ metadata are set. You can use the following metadata: ``uri`` URI to the PubSub node containing the messages of the topic (it's actually a blog node with suitable permissions). URI must only be set for topic, not for categories. + If ``uri`` is empty, a node will be created automatically and the ``uri`` will be filled + accordingly. ``sub-forums`` list of object with the same metadata (i.e. other topics or categories) diff --git a/libervia/backend/plugins/plugin_misc_forums.py b/libervia/backend/plugins/plugin_misc_forums.py index 252f4bd6..52be4cdf 100644 --- a/libervia/backend/plugins/plugin_misc_forums.py +++ b/libervia/backend/plugins/plugin_misc_forums.py @@ -17,6 +17,8 @@ # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . +from typing import Iterable +from libervia.backend.core.core_types import SatXMPPEntity from libervia.backend.core.i18n import _ from libervia.backend.core.constants import Const as C from libervia.backend.core import exceptions @@ -80,8 +82,15 @@ class forums(object): method=self._create_topic, async_=True) - @defer.inlineCallbacks - def _create_forums(self, client, forums, service, node, forums_elt=None, names=None): + async def _create_forums( + self, + client: SatXMPPEntity, + forums: list[dict], + service: jid.JID, + node: str, + forums_elt: domish.Element|None = None, + names: Iterable = None + ) -> domish.Element: """Recursively create element(s) @param forums(list): forums which may have subforums @@ -111,10 +120,10 @@ class forums(object): for key, value in forum.items(): if key == 'name' and key in names: raise exceptions.ConflictError(_("following forum name is not unique: {name}").format(name=key)) - if key == 'uri' and not value.strip(): + if key == 'uri' and value is None or not value.strip(): log.info(_("creating missing forum node")) forum_node = FORUM_TOPICS_NODE_TPL.format(node=node, uuid=shortuuid.uuid()) - yield self._p.createNode(client, service, forum_node, self._node_options) + await self._p.createNode(client, service, forum_node, self._node_options) value = uri.build_xmpp_uri('pubsub', path=service.full(), node=forum_node) @@ -123,8 +132,9 @@ class forums(object): elif key in FORUM_SUB_ELTS: forum_elt.addElement(key, content=value) elif key == 'sub-forums': + assert isinstance(value, list) sub_forums_elt = forum_elt.addElement('forums') - yield self._create_forums(client, value, service, node, sub_forums_elt, names=names) + await self._create_forums(client, value, service, node, sub_forums_elt, names=names) else: log.warning(_("Unknown forum attribute: {key}").format(key=key)) if not forum_elt.getAttribute('title'): @@ -135,7 +145,7 @@ class forums(object): raise ValueError(_("forum need a title or a name")) if not forum_elt.getAttribute('uri') and not forum_elt.children: raise ValueError(_("forum need uri or sub-forums")) - defer.returnValue(forums_elt) + return forums_elt def _parse_forums(self, parent_elt=None, forums=None): """Recursivly parse a elements and return corresponding forums data diff --git a/libervia/cli/cmd_forums.py b/libervia/cli/cmd_forums.py index 83b8e90c..a3176a73 100644 --- a/libervia/cli/cmd_forums.py +++ b/libervia/cli/cmd_forums.py @@ -18,11 +18,13 @@ # along with this program. If not, see . +import sys from . import base from libervia.backend.core.i18n import _ from libervia.cli.constants import Const as C from libervia.cli import common from libervia.backend.tools.common.ansi import ANSI as A +from libervia.frontends.bridge.bridge_frontend import BridgeException import codecs import json @@ -82,7 +84,7 @@ class Edit(base.CommandBase, common.BaseEdit): self.args.key, self.profile, ) - except Exception as e: + except BridgeException as e: if e.classname == "NotFound": forums_json = "" else: @@ -169,11 +171,51 @@ class Get(base.CommandBase): self.host.quit(1) forums = json.loads(forums_raw) await self.output(forums) + + +class Set(base.CommandBase): + + def __init__(self, host): + base.CommandBase.__init__( + self, + host, + "set", + use_pubsub=True, + help=_("set forums"), + ) + + def add_parser_options(self): + self.parser.add_argument( + "-k", + "--key", + default="", + help=_("forum key (DEFAULT: default forums)"), + ) + + async def start(self): + forums_raw = sys.stdin.read() + try: + json.loads(forums_raw) + except Exception as e: + self.parser.error(f"Invalid JSON, a valid JSON must be used as input: {e}") + try: + await self.host.bridge.forums_set( + forums_raw, + self.args.service, + self.args.node, + self.args.key, + self.profile, + ) + except Exception as e: + self.disp(f"can't set forums: {e}", error=True) + self.host.quit(C.EXIT_BRIDGE_ERRBACK) + else: + self.disp(_("forums have been set")) self.host.quit() class Forums(base.CommandBase): - subcommands = (Get, Edit) + subcommands = (Get, Set, Edit) def __init__(self, host): super(Forums, self).__init__(