jp (pubsub/node): new "import" command, to publish many nodes from an XML file

This commit is contained in:
Goffi 2019-02-15 22:13:43 +01:00
commit bb5a2befc5
2 changed files with 92 additions and 1 deletions

View file

@ -315,6 +315,92 @@ class NodeSet(base.CommandBase):
)
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 @@ class Node(base.CommandBase):
NodePurge,
NodeDelete,
NodeSet,
NodeImport,
NodeAffiliations,
NodeSubscriptions,
NodeSchema,

View file

@ -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 @@ def etreeParse(cmd, raw_xml):
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)
)