changeset 4191:5d056d524298

core, doc, cli (forums): new `forums set` commands + doc: - document the fact that if an empty `uri` is used, the forum node is created automatically - new `forums/set` CLI commands and its documentation
author Goffi <goffi@goffi.org>
date Mon, 11 Dec 2023 18:10:27 +0100
parents 92551baea115
children 1d24ff583794
files doc/libervia-cli/forums.rst libervia/backend/plugins/plugin_misc_forums.py libervia/cli/cmd_forums.py
diffstat 3 files changed, 78 insertions(+), 8 deletions(-) [+]
line wrap: on
line diff
--- a/doc/libervia-cli/forums.rst	Mon Dec 11 18:07:58 2023 +0100
+++ b/doc/libervia-cli/forums.rst	Mon Dec 11 18:10:27 2023 +0100
@@ -28,6 +28,22 @@
 
   $ 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 @@
 ``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)
 
--- a/libervia/backend/plugins/plugin_misc_forums.py	Mon Dec 11 18:07:58 2023 +0100
+++ b/libervia/backend/plugins/plugin_misc_forums.py	Mon Dec 11 18:10:27 2023 +0100
@@ -17,6 +17,8 @@
 # You should have received a copy of the GNU Affero General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
+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 @@
                               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 <forums> element(s)
 
         @param forums(list): forums which may have subforums
@@ -111,10 +120,10 @@
             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 @@
                 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 @@
                     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 <forums> elements and return corresponding forums data
--- a/libervia/cli/cmd_forums.py	Mon Dec 11 18:07:58 2023 +0100
+++ b/libervia/cli/cmd_forums.py	Mon Dec 11 18:10:27 2023 +0100
@@ -18,11 +18,13 @@
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 
+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 @@
                 self.args.key,
                 self.profile,
             )
-        except Exception as e:
+        except BridgeException as e:
             if e.classname == "NotFound":
                 forums_json = ""
             else:
@@ -169,11 +171,51 @@
                 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__(