changeset 2804:710de41da2f2

jp (pubsub/node): new "import" command, to publish many nodes from an XML file
author Goffi <goffi@goffi.org>
date Fri, 15 Feb 2019 22:13:43 +0100
parents d4a9a60bc650
children dfba1301e61c
files sat_frontends/jp/cmd_pubsub.py sat_frontends/jp/xml_tools.py
diffstat 2 files changed, 92 insertions(+), 1 deletions(-) [+]
line wrap: on
line diff
--- a/sat_frontends/jp/cmd_pubsub.py	Fri Feb 15 22:13:43 2019 +0100
+++ b/sat_frontends/jp/cmd_pubsub.py	Fri Feb 15 22:13:43 2019 +0100
@@ -315,6 +315,92 @@
         )
 
 
+class NodeImport(base.CommandBase):
+
+    def __init__(self, host):
+        super(NodeImport, self).__init__(
+            host,
+            "import",
+            use_pubsub=True,
+            pubsub_flags={C.NODE},
+            help=_(u"import raw XML to a node"),
+        )
+        self.need_loop = True
+
+    def add_parser_options(self):
+        self.parser.add_argument(
+            "--admin",
+            action="store_true",
+            help=_(u"do a pubsub admin request, needed to change publisher"),
+        )
+        self.parser.add_argument(
+            "import_file",
+            type=file,
+            help=_(u"path to the XML file with data to import. The file must contain "
+                   u"whole XML of each item to import."),
+        )
+
+    def psItemsSendCb(self, item_ids):
+        self.disp(_(u'items published with id(s) {item_ids}').format(
+            item_ids=u', '.join(item_ids)))
+        self.host.quit()
+
+    def start(self):
+        try:
+            element, etree = xml_tools.etreeParse(self, self.args.import_file,
+                                                  reraise=True)
+        except Exception as e:
+            from lxml.etree import XMLSyntaxError
+            if isinstance(e, XMLSyntaxError) and e.code == 5:
+                # we have extra content, this probaby means that item are not wrapped
+                # so we wrap them here and try again
+                self.args.import_file.seek(0)
+                xml_buf = "<import>" + self.args.import_file.read() + "</import>"
+                element, etree = xml_tools.etreeParse(self, xml_buf)
+
+        # we reverse element as we expect to have most recently published element first
+        # TODO: make this more explicit and add an option
+        element[:] = reversed(element)
+
+        if not all([i.tag == '{http://jabber.org/protocol/pubsub}item' for i in element]):
+            self.disp(
+                _(u"You are not using list of pubsub items, we can't import this file"),
+                error=True)
+            self.host.quit(C.EXIT_DATA_ERROR)
+
+        items = [etree.tostring(i, encoding="utf-8") for i in element]
+        if self.args.admin:
+            self.host.bridge.psAdminItemsSend(
+                self.args.service,
+                self.args.node,
+                items,
+                u"",
+                self.profile,
+                callback=partial(self.psItemsSendCb),
+                errback=partial(
+                    self.errback,
+                    msg=_(u"can't send item: {}"),
+                    exit_code=C.EXIT_BRIDGE_ERRBACK,
+                ),
+            )
+        else:
+            self.disp(_(u"Items are imported without using admin mode, publisher can't "
+                        u"be changed"))
+            self.host.bridge.psItemsSend(
+                self.args.service,
+                self.args.node,
+                items,
+                u"",
+                self.profile,
+                callback=partial(self.psItemsSendCb),
+                errback=partial(
+                    self.errback,
+                    msg=_(u"can't send item: {}"),
+                    exit_code=C.EXIT_BRIDGE_ERRBACK,
+                ),
+            )
+
+
 class NodeAffiliationsGet(base.CommandBase):
     def __init__(self, host):
         base.CommandBase.__init__(
@@ -696,6 +782,7 @@
         NodePurge,
         NodeDelete,
         NodeSet,
+        NodeImport,
         NodeAffiliations,
         NodeSubscriptions,
         NodeSchema,
--- a/sat_frontends/jp/xml_tools.py	Fri Feb 15 22:13:43 2019 +0100
+++ b/sat_frontends/jp/xml_tools.py	Fri Feb 15 22:13:43 2019 +0100
@@ -20,11 +20,13 @@
 from sat.core.i18n import _
 from sat_frontends.jp.constants import Const as C
 
-def etreeParse(cmd, raw_xml):
+def etreeParse(cmd, raw_xml, reraise=False):
     """Import lxml and parse raw XML
 
     @param cmd(CommandBase): current command instance
     @param raw_xml(file, str): an XML bytestring, string or file-like object
+    @param reraise(bool): if True, re raise exception on parse error instead of doing a
+        parser.error (which terminate the execution)
     @return (tuple(etree.Element, module): parsed element, etree module
     """
     try:
@@ -42,6 +44,8 @@
         else:
             element = etree.parse(raw_xml).getroot()
     except Exception as e:
+        if reraise:
+            raise e
         cmd.parser.error(
             _(u"Can't parse the payload XML in input: {msg}").format(msg=e)
         )