jp: pubsub options refactoring:
There is now only "use_pubsub", and specification are set using "pubsub_flags" argument when instantiating CommandBase. Options are more Python Zen compliant by using explicit arguments for item, draft, url instead of trying to guess with magic keyword and type detection. Pubsub node and item are now always using respecively "-n" and "-i" even when required, this way shell history can be used to change command more easily, and it's globally less confusing for user. if --pubsub-url is used, elements can be overwritten with individual option (e.g. change item id with --item). New "use_draft" argument in CommandBase, to re-use current draft or open a file path as draft. Item can now be specified when using a draft. If it already exists, its content will be added to current draft (with a separator), to avoid loosing data. common.BaseEdit.getItemPath could be simplified thanks to those changes. Pubsub URI handling has been moved to base.py.
This commit is contained in:
parent
03e9e2b281
commit
6f8834f9da
8 changed files with 268 additions and 296 deletions
|
|
@ -34,9 +34,11 @@ from importlib import import_module
|
|||
from sat_frontends.tools.jid import JID
|
||||
from sat.tools import config
|
||||
from sat.tools.common import dynamic_import
|
||||
from sat.tools.common import uri
|
||||
from sat.core import exceptions
|
||||
import sat_frontends.jp
|
||||
from sat_frontends.jp.constants import Const as C
|
||||
from sat_frontends.tools import misc
|
||||
import xml.etree.ElementTree as ET # FIXME: used temporarily to manage XMLUI
|
||||
import shlex
|
||||
from collections import OrderedDict
|
||||
|
|
@ -316,14 +318,46 @@ class Jp(object):
|
|||
verbose_parent = self.parents['verbose'] = argparse.ArgumentParser(add_help=False)
|
||||
verbose_parent.add_argument('--verbose', '-v', action='count', default=0, help=_(u"Add a verbosity level (can be used multiple times)"))
|
||||
|
||||
for parent_name in ('pubsub', 'pubsub_node_req'):
|
||||
parent = self.parents[parent_name] = argparse.ArgumentParser(add_help=False)
|
||||
parent.add_argument("-s", "--service", type=unicode_decoder, default=u'',
|
||||
help=_(u"JID of the PubSub service (default: PEP service)"))
|
||||
if parent_name == 'pubsub_node_req':
|
||||
parent.add_argument("node", type=unicode_decoder, help=_(u"node to request"))
|
||||
else:
|
||||
parent.add_argument("-n", "--node", type=unicode_decoder, default=u'', help=_(u"node to request"))
|
||||
draft_parent = self.parents['draft'] = argparse.ArgumentParser(add_help=False)
|
||||
draft_group = draft_parent.add_argument_group(_('draft handling'))
|
||||
draft_group.add_argument("-D", "--current", action="store_true", help=_(u"load current draft"))
|
||||
draft_group.add_argument("-F", "--draft-path", type=unicode_decoder, help=_(u"path to a draft file to retrieve"))
|
||||
|
||||
|
||||
def make_pubsub_group(self, flags):
|
||||
"""generate pubsub options according to flags
|
||||
|
||||
@param flags(iterable[unicode]): see [CommandBase.__init__]
|
||||
@return (ArgumentParser): parser to add
|
||||
"""
|
||||
flags = misc.FlagsHandler(flags)
|
||||
parent = argparse.ArgumentParser(add_help=False)
|
||||
pubsub_group = parent.add_argument_group('pubsub')
|
||||
pubsub_group.add_argument("-u", "--pubsub-url", type=unicode_decoder,
|
||||
help=_(u"Pubsub URL (xmpp or http)"))
|
||||
|
||||
service_help = _(u"JID of the PubSub service")
|
||||
if not flags.service:
|
||||
service_help += _(u" (default: PEP service)")
|
||||
pubsub_group.add_argument("-s", "--service", type=unicode_decoder, default=u'',
|
||||
help=service_help)
|
||||
|
||||
node_help = _(u"node to request")
|
||||
if not flags.node:
|
||||
node_help += _(u" (DEFAULT: standard node)")
|
||||
pubsub_group.add_argument("-n", "--node", type=unicode_decoder, default=u'', help=node_help)
|
||||
|
||||
if flags.single_item:
|
||||
pubsub_group.add_argument("-i", "--item", type=unicode_decoder, help=_(u"item to retrieve"))
|
||||
pubsub_group.add_argument("-L", "--last-item", action='store_true', help=_(u'retrieve last item'))
|
||||
elif flags.multi_items:
|
||||
# mutiple items
|
||||
pubsub_group.add_argument("-i", "--item", type=unicode_decoder, action='append', dest='items', default=[], help=_(u"items to retrieve (DEFAULT: all)"))
|
||||
|
||||
if flags:
|
||||
raise exceptions.InternalError('unknowns flags: {flags}'.format(flags=u', '.join(flags)))
|
||||
|
||||
return parent
|
||||
|
||||
def add_parser_options(self):
|
||||
self.parser.add_argument('--version', action='version', version=("%(name)s %(version)s %(copyleft)s" % {'name': PROG_NAME, 'version': self.version, 'copyleft': COPYLEFT}))
|
||||
|
|
@ -402,10 +436,89 @@ class Jp(object):
|
|||
cls = getattr(module, class_name)
|
||||
cls(self)
|
||||
|
||||
def get_xmpp_uri_from_http(self, http_url):
|
||||
"""parse HTML page at http(s) URL, and looks for xmpp: uri"""
|
||||
if http_url.startswith('https'):
|
||||
scheme = u'https'
|
||||
elif http_url.startswith('http'):
|
||||
scheme = u'http'
|
||||
else:
|
||||
raise exceptions.InternalError(u'An HTTP scheme is expected in this method')
|
||||
self.disp(u"{scheme} URL found, trying to find associated xmpp: URI".format(scheme=scheme.upper()),1)
|
||||
# HTTP URL, we try to find xmpp: links
|
||||
try:
|
||||
from lxml import etree
|
||||
except ImportError:
|
||||
self.disp(u"lxml module must be installed to use http(s) scheme, please install it with \"pip install lxml\"", error=True)
|
||||
self.host.quit(1)
|
||||
import urllib2
|
||||
parser = etree.HTMLParser()
|
||||
try:
|
||||
root = etree.parse(urllib2.urlopen(http_url), parser)
|
||||
except etree.XMLSyntaxError as e:
|
||||
self.disp(_(u"Can't parse HTML page : {msg}").format(msg=e))
|
||||
links = []
|
||||
else:
|
||||
links = root.xpath("//link[@rel='alternate' and starts-with(@href, 'xmpp:')]")
|
||||
if not links:
|
||||
self.disp(u'Could not find alternate "xmpp:" URI, can\'t find associated XMPP PubSub node/item', error=True)
|
||||
self.host.quit(1)
|
||||
xmpp_uri = links[0].get('href')
|
||||
return xmpp_uri
|
||||
|
||||
def parse_pubsub_args(self):
|
||||
if self.args.pubsub_url is not None:
|
||||
url = self.args.pubsub_url
|
||||
|
||||
if url.startswith('http'):
|
||||
# http(s) URL, we try to retrieve xmpp one from there
|
||||
url = self.get_xmpp_uri_from_http(url)
|
||||
|
||||
try:
|
||||
uri_data = uri.parseXMPPUri(url)
|
||||
except ValueError:
|
||||
self.parser.error(_(u'invalid XMPP URL: {url}').format(url=url))
|
||||
else:
|
||||
if uri_data[u'type'] == 'pubsub':
|
||||
# URL is alright, we only set data not already set by other options
|
||||
if not self.args.service:
|
||||
self.args.service = uri_data[u'path']
|
||||
if not self.args.node:
|
||||
self.args.node = uri_data[u'node']
|
||||
uri_item = uri_data.get(u'item')
|
||||
if uri_item:
|
||||
try:
|
||||
item, item_magic = self.args.item, self.args.item_magic
|
||||
except AttributeError:
|
||||
if not self.args.items:
|
||||
self.args.items = [uri_item]
|
||||
else:
|
||||
if not item and not item_magic:
|
||||
self.args.item = uri_item
|
||||
else:
|
||||
self.parser.error(_(u'XMPP URL is not a pubsub one: {url}').format(url=url))
|
||||
flags = self.args._cmd._pubsub_flags
|
||||
# we check required arguments here instead of using add_arguments' required option
|
||||
# because the required argument can be set in URL
|
||||
if C.SERVICE in flags and not self.args.service:
|
||||
self.parser.error(_(u"argument -s/--service is required"))
|
||||
if C.NODE in flags and not self.args.node:
|
||||
self.parser.error(_(u"argument -n/--node is required"))
|
||||
|
||||
# FIXME: mutually groups can't be nested in a group and don't support title
|
||||
# so we check conflict here. This may be fixed in Python 3, to be checked
|
||||
try:
|
||||
if self.args.item and self.args.item_last:
|
||||
self.parser.error(_(u"--item and --item-last can't be used at the same time"))
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
def run(self, args=None, namespace=None):
|
||||
self.args = self.parser.parse_args(args, namespace=None)
|
||||
if self.args._cmd._use_pubsub:
|
||||
self.parse_pubsub_args()
|
||||
try:
|
||||
self.args.func()
|
||||
self.args._cmd.run()
|
||||
if self._need_loop or self._auto_loop:
|
||||
self._start_loop()
|
||||
except KeyboardInterrupt:
|
||||
|
|
@ -582,6 +695,14 @@ class CommandBase(object):
|
|||
- use_progress(bool): if True, add progress bar activation option
|
||||
progress* signals will be handled
|
||||
- use_verbose(bool): if True, add verbosity option
|
||||
- use_pubsub(bool): if True, add pubsub options
|
||||
mandatory arguments are controlled by pubsub_req
|
||||
- use_draft(bool): if True, add draft handling options
|
||||
** other arguments **
|
||||
- pubsub_flags(iterable[unicode]): tuple of flags to set pubsub options, can be:
|
||||
C.SERVICE: service is required
|
||||
C.NODE: node is required
|
||||
C.SINGLE_ITEM: only one item is allowed
|
||||
@attribute need_loop(bool): to set by commands when loop is needed
|
||||
"""
|
||||
self.need_loop = False # to be set by commands when loop is needed
|
||||
|
|
@ -632,9 +753,11 @@ class CommandBase(object):
|
|||
else:
|
||||
assert extra_outputs is None
|
||||
|
||||
if 'use_pubsub' in kwargs and 'use_pubsub_node_req' in kwargs:
|
||||
raise exceptions.InternalError(u"use_pubsub and use_pubsub_node_req can't be used at the same time."
|
||||
u"Use the later one when node is required (else an empty string is used as default)")
|
||||
self._use_pubsub = kwargs.pop('use_pubsub', False)
|
||||
if self._use_pubsub:
|
||||
flags = kwargs.pop('pubsub_flags', None)
|
||||
parents.add(self.host.make_pubsub_group(flags))
|
||||
self._pubsub_flags = flags
|
||||
|
||||
# other common options
|
||||
use_opts = {k:v for k,v in kwargs.iteritems() if k.startswith('use_')}
|
||||
|
|
@ -650,7 +773,7 @@ class CommandBase(object):
|
|||
if hasattr(self, "subcommands"):
|
||||
self.subparsers = self.parser.add_subparsers()
|
||||
else:
|
||||
self.parser.set_defaults(func=self.run)
|
||||
self.parser.set_defaults(_cmd=self)
|
||||
self.add_parser_options()
|
||||
|
||||
@property
|
||||
|
|
|
|||
|
|
@ -76,38 +76,28 @@ MB_KEYS = (u"id",
|
|||
OUTPUT_OPT_NO_HEADER = u'no-header'
|
||||
|
||||
|
||||
class BlogCommon(object):
|
||||
def guessSyntaxFromPath(host, sat_conf, path):
|
||||
"""Return syntax guessed according to filename extension
|
||||
|
||||
def __init__(self, host):
|
||||
self.host = host
|
||||
@param sat_conf(ConfigParser.ConfigParser): instance opened on sat configuration
|
||||
@param path(str): path to the content file
|
||||
@return(unicode): syntax to use
|
||||
"""
|
||||
# we first try to guess syntax with extension
|
||||
ext = os.path.splitext(path)[1][1:] # we get extension without the '.'
|
||||
if ext:
|
||||
for k,v in SYNTAX_EXT.iteritems():
|
||||
if k and ext == v:
|
||||
return k
|
||||
|
||||
def addServiceNodeArgs(self):
|
||||
self.parser.add_argument("-n", "--node", type=base.unicode_decoder, default=u'', help=_(u"PubSub node to request (default: microblog namespace)"))
|
||||
self.parser.add_argument("-s", "--service", type=base.unicode_decoder, default=u'', help=_(u"JID of the PubSub service (default: request profile own blog)"))
|
||||
|
||||
def guessSyntaxFromPath(self, sat_conf, path):
|
||||
"""Return syntax guessed according to filename extension
|
||||
|
||||
@param sat_conf(ConfigParser.ConfigParser): instance opened on sat configuration
|
||||
@param path(str): path to the content file
|
||||
@return(unicode): syntax to use
|
||||
"""
|
||||
# we first try to guess syntax with extension
|
||||
ext = os.path.splitext(path)[1][1:] # we get extension without the '.'
|
||||
if ext:
|
||||
for k,v in SYNTAX_EXT.iteritems():
|
||||
if k and ext == v:
|
||||
return k
|
||||
|
||||
# if not found, we use current syntax
|
||||
return self.host.bridge.getParamA("Syntax", "Composition", "value", self.profile)
|
||||
# if not found, we use current syntax
|
||||
return host.bridge.getParamA("Syntax", "Composition", "value", host.profile)
|
||||
|
||||
|
||||
class BlogPublishCommon(object):
|
||||
"""handle common option for publising commands (Set and Edit)"""
|
||||
|
||||
def add_parser_options(self):
|
||||
self.addServiceNodeArgs()
|
||||
self.parser.add_argument("-T", '--title', type=base.unicode_decoder, help=_(u"title of the item"))
|
||||
self.parser.add_argument("-t", '--tag', type=base.unicode_decoder, action='append', help=_(u"tag (category) of your item"))
|
||||
self.parser.add_argument("-C", "--comments", action='store_true', help=_(u"enable comments"))
|
||||
|
|
@ -134,24 +124,22 @@ class BlogPublishCommon(object):
|
|||
mb_data['title'] = self.args.title
|
||||
|
||||
|
||||
class Set(base.CommandBase, BlogCommon, BlogPublishCommon):
|
||||
class Set(base.CommandBase, BlogPublishCommon):
|
||||
|
||||
def __init__(self, host):
|
||||
base.CommandBase.__init__(self, host, 'set', help=_(u'publish a new blog item or update an existing one'))
|
||||
BlogCommon.__init__(self, self.host)
|
||||
base.CommandBase.__init__(self, host, 'set', use_pubsub=True, pubsub_flags={C.SINGLE_ITEM},
|
||||
help=_(u'publish a new blog item or update an existing one'))
|
||||
BlogPublishCommon.__init__(self)
|
||||
self.need_loop=True
|
||||
|
||||
def add_parser_options(self):
|
||||
BlogPublishCommon.add_parser_options(self)
|
||||
self.parser.add_argument("item", type=base.unicode_decoder, nargs='?', default=None, help=_(u"id of the item to publish"))
|
||||
|
||||
def mbSendCb(self):
|
||||
self.disp(u"Item published")
|
||||
self.host.quit(C.EXIT_OK)
|
||||
|
||||
def start(self):
|
||||
common.checkURI(self.args)
|
||||
self.pubsub_item = self.args.item
|
||||
mb_data = {}
|
||||
self.setMbDataFromArgs(mb_data)
|
||||
|
|
@ -169,20 +157,17 @@ class Set(base.CommandBase, BlogCommon, BlogPublishCommon):
|
|||
exit_code=C.EXIT_BRIDGE_ERRBACK))
|
||||
|
||||
|
||||
class Get(base.CommandBase, BlogCommon):
|
||||
class Get(base.CommandBase):
|
||||
TEMPLATE = u"blog/articles.html"
|
||||
|
||||
def __init__(self, host):
|
||||
extra_outputs = {'default': self.default_output,
|
||||
'fancy': self.fancy_output}
|
||||
base.CommandBase.__init__(self, host, 'get', use_verbose=True, use_output=C.OUTPUT_COMPLEX, extra_outputs=extra_outputs, help=_(u'get blog item(s)'))
|
||||
BlogCommon.__init__(self, self.host)
|
||||
base.CommandBase.__init__(self, host, 'get', use_verbose=True, use_pubsub=True, pubsub_flags={C.MULTI_ITEMS},
|
||||
use_output=C.OUTPUT_COMPLEX, extra_outputs=extra_outputs, help=_(u'get blog item(s)'))
|
||||
self.need_loop=True
|
||||
|
||||
def add_parser_options(self):
|
||||
self.addServiceNodeArgs()
|
||||
self.parser.add_argument("-i", "--item", type=base.unicode_decoder, action='append', default=[], dest='items',
|
||||
help=_(u"item(s) id(s) to get (default: request all items)"))
|
||||
self.parser.add_argument("-m", "--max", type=int, default=10, help=_(u"maximum number of items to get ({} to get all items)".format(C.NO_LIMIT)))
|
||||
# TODO: a key(s) argument to select keys to display
|
||||
self.parser.add_argument("-k", "--key", type=base.unicode_decoder, action='append', dest='keys',
|
||||
|
|
@ -339,7 +324,6 @@ class Get(base.CommandBase, BlogCommon):
|
|||
self.host.quit(C.EXIT_BRIDGE_ERRBACK)
|
||||
|
||||
def start(self):
|
||||
common.checkURI(self.args)
|
||||
self.host.bridge.mbGet(
|
||||
self.args.service,
|
||||
self.args.node,
|
||||
|
|
@ -351,19 +335,23 @@ class Get(base.CommandBase, BlogCommon):
|
|||
errback=self.mbGetEb)
|
||||
|
||||
|
||||
class Edit(base.CommandBase, BlogCommon, BlogPublishCommon, common.BaseEdit):
|
||||
class Edit(base.CommandBase, BlogPublishCommon, common.BaseEdit):
|
||||
|
||||
def __init__(self, host):
|
||||
base.CommandBase.__init__(self, host, 'edit', use_verbose=True, help=_(u'edit an existing or new blog post'))
|
||||
BlogCommon.__init__(self, self.host)
|
||||
base.CommandBase.__init__(self, host, 'edit', use_pubsub=True, pubsub_flags={C.SINGLE_ITEM},
|
||||
use_draft=True, use_verbose=True, help=_(u'edit an existing or new blog post'))
|
||||
BlogPublishCommon.__init__(self)
|
||||
common.BaseEdit.__init__(self, self.host, BLOG_TMP_DIR, use_metadata=True)
|
||||
|
||||
@property
|
||||
def current_syntax(self):
|
||||
if self._current_syntax is None:
|
||||
self._current_syntax = self.host.bridge.getParamA("Syntax", "Composition", "value", self.profile)
|
||||
return self._current_syntax
|
||||
|
||||
def add_parser_options(self):
|
||||
BlogPublishCommon.add_parser_options(self)
|
||||
self.parser.add_argument("-P", "--preview", action="store_true", help=_(u"launch a blog preview in parallel"))
|
||||
self.parser.add_argument("item", type=base.unicode_decoder, nargs='?', default=u'new', help=_(u"URL of the item to edit, or keyword"))
|
||||
common.BaseEdit.add_parser_options(self)
|
||||
|
||||
def buildMetadataFile(self, content_file_path, mb_data=None):
|
||||
"""Build a metadata file using json
|
||||
|
|
@ -436,8 +424,6 @@ class Edit(base.CommandBase, BlogCommon, BlogPublishCommon, common.BaseEdit):
|
|||
|
||||
def getTmpSuff(self):
|
||||
# we get current syntax to determine file extension
|
||||
if self.current_syntax is None:
|
||||
self.current_syntax = self.host.bridge.getParamA("Syntax", "Composition", "value", self.profile)
|
||||
return SYNTAX_EXT.get(self.current_syntax, SYNTAX_EXT[''])
|
||||
|
||||
def getItemData(self, service, node, item):
|
||||
|
|
@ -466,26 +452,26 @@ class Edit(base.CommandBase, BlogCommon, BlogPublishCommon, common.BaseEdit):
|
|||
def start(self):
|
||||
# if there are user defined extension, we use them
|
||||
SYNTAX_EXT.update(config.getConfig(self.sat_conf, 'jp', CONF_SYNTAX_EXT, {}))
|
||||
self.current_syntax = self.args.syntax
|
||||
if self.current_syntax is not None:
|
||||
self._current_syntax = self.args.syntax
|
||||
if self._current_syntax is not None:
|
||||
try:
|
||||
self.current_syntax = self.args.syntax = self.host.bridge.syntaxGet(self.current_syntax)
|
||||
self._current_syntax = self.args.syntax = self.host.bridge.syntaxGet(self.current_syntax)
|
||||
except Exception as e:
|
||||
if "NotFound" in unicode(e): # FIXME: there is not good way to check bridge errors
|
||||
self.parser.error(_(u"unknown syntax requested ({syntax})").format(syntax=self.args.syntax))
|
||||
else:
|
||||
raise e
|
||||
|
||||
self.pubsub_service, self.pubsub_node, self.pubsub_item, content_file_path, content_file_obj, mb_data = self.getItemPath(self.args.item)
|
||||
self.pubsub_service, self.pubsub_node, self.pubsub_item, content_file_path, content_file_obj, mb_data = self.getItemPath()
|
||||
|
||||
self.edit(content_file_path, content_file_obj, mb_data=mb_data)
|
||||
|
||||
|
||||
class Preview(base.CommandBase, BlogCommon):
|
||||
class Preview(base.CommandBase):
|
||||
# TODO: need to be rewritten with template output
|
||||
|
||||
def __init__(self, host):
|
||||
base.CommandBase.__init__(self, host, 'preview', use_verbose=True, help=_(u'preview a blog content'))
|
||||
BlogCommon.__init__(self, self.host)
|
||||
|
||||
def add_parser_options(self):
|
||||
self.parser.add_argument("--inotify", type=str, choices=('auto', 'true', 'false'), default=u'auto', help=_(u"use inotify to handle preview"))
|
||||
|
|
@ -626,7 +612,7 @@ class Preview(base.CommandBase, BlogCommon):
|
|||
|
||||
class Import(base.CommandAnswering):
|
||||
def __init__(self, host):
|
||||
super(Import, self).__init__(host, 'import', use_progress=True, help=_(u'import an external blog'))
|
||||
super(Import, self).__init__(host, 'import', use_pubsub=True, use_progress=True, help=_(u'import an external blog'))
|
||||
self.need_loop=True
|
||||
|
||||
def add_parser_options(self):
|
||||
|
|
@ -637,10 +623,6 @@ class Import(base.CommandAnswering):
|
|||
self.parser.add_argument("--ignore-tls-errors", action="store_true", help=_("ignore invalide TLS certificate for uploads"))
|
||||
self.parser.add_argument('-o', '--option', action='append', nargs=2, default=[], metavar=(u'NAME', u'VALUE'),
|
||||
help=_(u"importer specific options (see importer description)"))
|
||||
self.parser.add_argument('--service', type=base.unicode_decoder, default=u'', metavar=u'PUBSUB_SERVICE',
|
||||
help=_(u"PubSub service where the items must be uploaded (default: server)"))
|
||||
self.parser.add_argument('-n', '--node', type=base.unicode_decoder, default=u'', metavar=u'PUBSUB_NODE',
|
||||
help=_(u"PubSub node where the items must be uploaded (default: tickets' defaults)"))
|
||||
self.parser.add_argument("location", type=base.unicode_decoder, nargs='?',
|
||||
help=_(u"importer data location (see importer description), nothing to show importer description"))
|
||||
|
||||
|
|
|
|||
|
|
@ -42,13 +42,13 @@ class Get(base.CommandBase):
|
|||
host,
|
||||
'get',
|
||||
use_output=C.OUTPUT_DICT,
|
||||
use_pubsub_node_req=True,
|
||||
use_pubsub=True, pubsub_flags={C.NODE, C.SINGLE_ITEM},
|
||||
use_verbose=True,
|
||||
help=_(u'get event data'))
|
||||
self.need_loop=True
|
||||
|
||||
def add_parser_options(self):
|
||||
self.parser.add_argument("-i", "--item", type=base.unicode_decoder, default=u'', help=_(u"ID of the PubSub Item"))
|
||||
pass
|
||||
|
||||
def eventInviteeGetCb(self, result):
|
||||
event_date, event_data = result
|
||||
|
|
@ -57,7 +57,6 @@ class Get(base.CommandBase):
|
|||
self.host.quit()
|
||||
|
||||
def start(self):
|
||||
common.checkURI(self.args)
|
||||
self.host.bridge.eventGet(
|
||||
self.args.service,
|
||||
self.args.node,
|
||||
|
|
@ -100,7 +99,7 @@ class EventBase(object):
|
|||
|
||||
class Create(EventBase, base.CommandBase):
|
||||
def __init__(self, host):
|
||||
super(Create, self).__init__(host, 'create', use_pubsub_node_req=True, help=_('create or replace event'))
|
||||
super(Create, self).__init__(host, 'create', use_pubsub=True, pubsub_flags={C.NODE}, help=_('create or replace event'))
|
||||
EventBase.__init__(self)
|
||||
self.need_loop=True
|
||||
|
||||
|
|
@ -126,12 +125,11 @@ class Create(EventBase, base.CommandBase):
|
|||
|
||||
class Modify(EventBase, base.CommandBase):
|
||||
def __init__(self, host):
|
||||
super(Modify, self).__init__(host, 'modify', use_pubsub_node_req=True, help=_('modify an existing event'))
|
||||
super(Modify, self).__init__(host, 'modify', use_pubsub=True, pubsub_flags={C.NODE}, help=_('modify an existing event'))
|
||||
EventBase.__init__(self)
|
||||
self.need_loop=True
|
||||
|
||||
def start(self):
|
||||
common.checkURI(self.args)
|
||||
fields = self.parseFields()
|
||||
date = 0 if not self.args.date else self.parseDate()
|
||||
self.host.bridge.eventModify(
|
||||
|
|
@ -154,7 +152,7 @@ class InviteeGet(base.CommandBase):
|
|||
host,
|
||||
'get',
|
||||
use_output=C.OUTPUT_DICT,
|
||||
use_pubsub_node_req=True,
|
||||
use_pubsub=True, pubsub_flags={C.NODE},
|
||||
use_verbose=True,
|
||||
help=_(u'get event attendance'))
|
||||
self.need_loop=True
|
||||
|
|
@ -167,7 +165,6 @@ class InviteeGet(base.CommandBase):
|
|||
self.host.quit()
|
||||
|
||||
def start(self):
|
||||
common.checkURI(self.args)
|
||||
self.host.bridge.eventInviteeGet(
|
||||
self.args.service,
|
||||
self.args.node,
|
||||
|
|
@ -180,7 +177,7 @@ class InviteeGet(base.CommandBase):
|
|||
|
||||
class InviteeSet(base.CommandBase):
|
||||
def __init__(self, host):
|
||||
super(InviteeSet, self).__init__(host, 'set', use_output=C.OUTPUT_DICT, use_pubsub_node_req=True, help=_('set event attendance'))
|
||||
super(InviteeSet, self).__init__(host, 'set', use_output=C.OUTPUT_DICT, use_pubsub=True, pubsub_flags={C.NODE}, help=_('set event attendance'))
|
||||
self.need_loop=True
|
||||
|
||||
def add_parser_options(self):
|
||||
|
|
@ -188,7 +185,6 @@ class InviteeSet(base.CommandBase):
|
|||
metavar=(u"KEY", u"VALUE"), help=_(u"configuration field to set"))
|
||||
|
||||
def start(self):
|
||||
common.checkURI(self.args)
|
||||
fields = dict(self.args.fields) if self.args.fields else {}
|
||||
self.host.bridge.eventInviteeSet(
|
||||
self.args.service,
|
||||
|
|
@ -210,7 +206,7 @@ class InviteesList(base.CommandBase):
|
|||
'list',
|
||||
use_output=C.OUTPUT_DICT_DICT,
|
||||
extra_outputs=extra_outputs,
|
||||
use_pubsub_node_req=True,
|
||||
use_pubsub=True, pubsub_flags={C.NODE},
|
||||
use_verbose=True,
|
||||
help=_(u'get event attendance'))
|
||||
self.need_loop=True
|
||||
|
|
@ -355,7 +351,6 @@ class InviteesList(base.CommandBase):
|
|||
def start(self):
|
||||
if self.args.no_rsvp and not self.args.missing:
|
||||
self.parser.error(_(u"you need to use --missing if you use --no-rsvp"))
|
||||
common.checkURI(self.args)
|
||||
if self.args.missing:
|
||||
self.host.bridge.psNodeAffiliationsGet(
|
||||
self.args.service,
|
||||
|
|
@ -372,21 +367,19 @@ class InviteesList(base.CommandBase):
|
|||
class InviteeInvite(base.CommandBase):
|
||||
|
||||
def __init__(self, host):
|
||||
base.CommandBase.__init__(self, host, 'invite', use_pubsub_node_req=True, help=_(u'invite someone to the event through email'))
|
||||
base.CommandBase.__init__(self, host, 'invite', use_pubsub=True, pubsub_flags={C.NODE, C.SINGLE_ITEM}, help=_(u'invite someone to the event through email'))
|
||||
self.need_loop=True
|
||||
|
||||
def add_parser_options(self):
|
||||
self.parser.add_argument("-i", "--item", type=base.unicode_decoder, default=u'', help=_(u"ID of the PubSub Item"))
|
||||
self.parser.add_argument("-e", "--email", action="append", type=base.unicode_decoder, default=[], help='email(s) to send the invitation to')
|
||||
self.parser.add_argument("-n", "--name", type=base.unicode_decoder, default='', help='name of the invitee')
|
||||
self.parser.add_argument("-N", "--host-name", type=base.unicode_decoder, default='', help='name of the host')
|
||||
self.parser.add_argument("-N", "--name", type=base.unicode_decoder, default='', help='name of the invitee')
|
||||
self.parser.add_argument("-H", "--host-name", type=base.unicode_decoder, default='', help='name of the host')
|
||||
self.parser.add_argument("-l", "--lang", type=base.unicode_decoder, default='', help='main language spoken by the invitee')
|
||||
self.parser.add_argument("-u", "--url", type=base.unicode_decoder, default='', help='template to construct the URL')
|
||||
self.parser.add_argument("-U", "--url-template", type=base.unicode_decoder, default='', help='template to construct the URL')
|
||||
self.parser.add_argument("-S", "--subject", type=base.unicode_decoder, default='', help='subject of the invitation email (default: generic subject)')
|
||||
self.parser.add_argument("-b", "--body", type=base.unicode_decoder, default='', help='body of the invitation email (default: generic body)')
|
||||
|
||||
def start(self):
|
||||
common.checkURI(self.args)
|
||||
email = self.args.email[0] if self.args.email else None
|
||||
emails_extra = self.args.email[1:]
|
||||
|
||||
|
|
@ -399,7 +392,7 @@ class InviteeInvite(base.CommandBase):
|
|||
self.args.name,
|
||||
self.args.host_name,
|
||||
self.args.lang,
|
||||
self.args.url,
|
||||
self.args.url_template,
|
||||
self.args.subject,
|
||||
self.args.body,
|
||||
self.args.profile,
|
||||
|
|
|
|||
|
|
@ -35,12 +35,11 @@ class Edit(base.CommandBase, common.BaseEdit):
|
|||
use_items=False
|
||||
|
||||
def __init__(self, host):
|
||||
base.CommandBase.__init__(self, host, 'edit', use_pubsub=True, use_verbose=True, help=_(u'edit forums'))
|
||||
base.CommandBase.__init__(self, host, 'edit', use_pubsub=True, use_draft=True, use_verbose=True, help=_(u'edit forums'))
|
||||
common.BaseEdit.__init__(self, self.host, FORUMS_TMP_DIR)
|
||||
self.need_loop=True
|
||||
|
||||
def add_parser_options(self):
|
||||
common.BaseEdit.add_parser_options(self)
|
||||
self.parser.add_argument("-k", "--key", type=base.unicode_decoder, default=u'',
|
||||
help=_(u"forum key (DEFAULT: default forums)"))
|
||||
|
||||
|
|
@ -84,7 +83,6 @@ class Edit(base.CommandBase, common.BaseEdit):
|
|||
exit_code=C.EXIT_BRIDGE_ERRBACK)
|
||||
|
||||
def start(self):
|
||||
common.checkURI(self.args)
|
||||
self.host.bridge.forumsGet(
|
||||
self.args.service,
|
||||
self.args.node,
|
||||
|
|
@ -146,7 +144,6 @@ class Get(base.CommandBase):
|
|||
self.host.quit()
|
||||
|
||||
def start(self):
|
||||
common.checkURI(self.args)
|
||||
self.host.bridge.forumsGet(
|
||||
self.args.service,
|
||||
self.args.node,
|
||||
|
|
|
|||
|
|
@ -20,7 +20,6 @@
|
|||
|
||||
import base
|
||||
from sat.core.i18n import _
|
||||
from sat_frontends.jp import common
|
||||
from sat_frontends.jp.constants import Const as C
|
||||
from functools import partial
|
||||
import os.path
|
||||
|
|
@ -46,7 +45,6 @@ class Set(base.CommandBase):
|
|||
self.host.quit(C.EXIT_OK)
|
||||
|
||||
def start(self):
|
||||
common.checkURI(self.args)
|
||||
repository = os.path.expanduser(os.path.abspath(self.args.repository))
|
||||
extra = {'update': 'true'} if self.args.item else {}
|
||||
self.host.bridge.mergeRequestSet(
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ ALLOWED_SUBSCRIPTIONS_OWNER = ('subscribed', 'pending', 'none')
|
|||
class NodeInfo(base.CommandBase):
|
||||
|
||||
def __init__(self, host):
|
||||
base.CommandBase.__init__(self, host, 'info', use_output=C.OUTPUT_DICT, use_pubsub_node_req=True, help=_(u'retrieve node configuration'))
|
||||
base.CommandBase.__init__(self, host, 'info', use_output=C.OUTPUT_DICT, use_pubsub=True, pubsub_flags={C.NODE}, help=_(u'retrieve node configuration'))
|
||||
self.need_loop=True
|
||||
|
||||
def add_parser_options(self):
|
||||
|
|
@ -71,7 +71,6 @@ class NodeInfo(base.CommandBase):
|
|||
self.host.quit(C.EXIT_BRIDGE_ERRBACK)
|
||||
|
||||
def start(self):
|
||||
common.checkURI(self.args)
|
||||
self.host.bridge.psNodeConfigurationGet(
|
||||
self.args.service,
|
||||
self.args.node,
|
||||
|
|
@ -83,7 +82,7 @@ class NodeInfo(base.CommandBase):
|
|||
class NodeCreate(base.CommandBase):
|
||||
|
||||
def __init__(self, host):
|
||||
base.CommandBase.__init__(self, host, 'create', use_output=C.OUTPUT_DICT, use_pubsub_node_req=True, use_verbose=True, help=_(u'create a node'))
|
||||
base.CommandBase.__init__(self, host, 'create', use_output=C.OUTPUT_DICT, use_pubsub=True, pubsub_flags={C.NODE}, use_verbose=True, help=_(u'create a node'))
|
||||
self.need_loop=True
|
||||
|
||||
def add_parser_options(self):
|
||||
|
|
@ -123,7 +122,7 @@ class NodeCreate(base.CommandBase):
|
|||
class NodeDelete(base.CommandBase):
|
||||
|
||||
def __init__(self, host):
|
||||
base.CommandBase.__init__(self, host, 'delete', use_pubsub_node_req=True, help=_(u'delete a node'))
|
||||
base.CommandBase.__init__(self, host, 'delete', use_pubsub=True, pubsub_flags={C.NODE}, help=_(u'delete a node'))
|
||||
self.need_loop=True
|
||||
|
||||
def add_parser_options(self):
|
||||
|
|
@ -134,7 +133,6 @@ class NodeDelete(base.CommandBase):
|
|||
self.host.quit()
|
||||
|
||||
def start(self):
|
||||
common.checkURI(self.args)
|
||||
if not self.args.force:
|
||||
if not self.args.service:
|
||||
message = _(u"Are you sure to delete pep node [{node_id}] ?").format(
|
||||
|
|
@ -161,7 +159,7 @@ class NodeDelete(base.CommandBase):
|
|||
class NodeSet(base.CommandBase):
|
||||
|
||||
def __init__(self, host):
|
||||
base.CommandBase.__init__(self, host, 'set', use_output=C.OUTPUT_DICT, use_pubsub_node_req=True, use_verbose=True, help=_(u'set node configuration'))
|
||||
base.CommandBase.__init__(self, host, 'set', use_output=C.OUTPUT_DICT, use_pubsub=True, pubsub_flags={C.NODE}, use_verbose=True, help=_(u'set node configuration'))
|
||||
self.need_loop=True
|
||||
|
||||
def add_parser_options(self):
|
||||
|
|
@ -184,7 +182,6 @@ class NodeSet(base.CommandBase):
|
|||
return k
|
||||
|
||||
def start(self):
|
||||
common.checkURI(self.args)
|
||||
self.host.bridge.psNodeConfigurationSet(
|
||||
self.args.service,
|
||||
self.args.node,
|
||||
|
|
@ -197,7 +194,7 @@ class NodeSet(base.CommandBase):
|
|||
class NodeAffiliationsGet(base.CommandBase):
|
||||
|
||||
def __init__(self, host):
|
||||
base.CommandBase.__init__(self, host, 'get', use_output=C.OUTPUT_DICT, use_pubsub_node_req=True, help=_(u'retrieve node affiliations (for node owner)'))
|
||||
base.CommandBase.__init__(self, host, 'get', use_output=C.OUTPUT_DICT, use_pubsub=True, pubsub_flags={C.NODE}, help=_(u'retrieve node affiliations (for node owner)'))
|
||||
self.need_loop=True
|
||||
|
||||
def add_parser_options(self):
|
||||
|
|
@ -213,7 +210,6 @@ class NodeAffiliationsGet(base.CommandBase):
|
|||
self.host.quit(C.EXIT_BRIDGE_ERRBACK)
|
||||
|
||||
def start(self):
|
||||
common.checkURI(self.args)
|
||||
self.host.bridge.psNodeAffiliationsGet(
|
||||
self.args.service,
|
||||
self.args.node,
|
||||
|
|
@ -225,7 +221,7 @@ class NodeAffiliationsGet(base.CommandBase):
|
|||
class NodeAffiliationsSet(base.CommandBase):
|
||||
|
||||
def __init__(self, host):
|
||||
base.CommandBase.__init__(self, host, 'set', use_pubsub_node_req=True, use_verbose=True, help=_(u'set affiliations (for node owner)'))
|
||||
base.CommandBase.__init__(self, host, 'set', use_pubsub=True, pubsub_flags={C.NODE}, use_verbose=True, help=_(u'set affiliations (for node owner)'))
|
||||
self.need_loop=True
|
||||
|
||||
def add_parser_options(self):
|
||||
|
|
@ -251,7 +247,6 @@ class NodeAffiliationsSet(base.CommandBase):
|
|||
self.host.quit(C.EXIT_BRIDGE_ERRBACK)
|
||||
|
||||
def start(self):
|
||||
common.checkURI(self.args)
|
||||
affiliations = dict(self.args.affiliations)
|
||||
self.host.bridge.psNodeAffiliationsSet(
|
||||
self.args.service,
|
||||
|
|
@ -272,7 +267,7 @@ class NodeAffiliations(base.CommandBase):
|
|||
class NodeSubscriptionsGet(base.CommandBase):
|
||||
|
||||
def __init__(self, host):
|
||||
base.CommandBase.__init__(self, host, 'get', use_output=C.OUTPUT_DICT, use_pubsub_node_req=True, help=_(u'retrieve node subscriptions (for node owner)'))
|
||||
base.CommandBase.__init__(self, host, 'get', use_output=C.OUTPUT_DICT, use_pubsub=True, pubsub_flags={C.NODE}, help=_(u'retrieve node subscriptions (for node owner)'))
|
||||
self.need_loop=True
|
||||
|
||||
def add_parser_options(self):
|
||||
|
|
@ -288,7 +283,6 @@ class NodeSubscriptionsGet(base.CommandBase):
|
|||
self.host.quit(C.EXIT_BRIDGE_ERRBACK)
|
||||
|
||||
def start(self):
|
||||
common.checkURI(self.args)
|
||||
self.host.bridge.psNodeSubscriptionsGet(
|
||||
self.args.service,
|
||||
self.args.node,
|
||||
|
|
@ -320,7 +314,7 @@ class StoreSubscriptionAction(argparse.Action):
|
|||
class NodeSubscriptionsSet(base.CommandBase):
|
||||
|
||||
def __init__(self, host):
|
||||
base.CommandBase.__init__(self, host, 'set', use_pubsub_node_req=True, use_verbose=True, help=_(u'set/modify subscriptions (for node owner)'))
|
||||
base.CommandBase.__init__(self, host, 'set', use_pubsub=True, pubsub_flags={C.NODE}, use_verbose=True, help=_(u'set/modify subscriptions (for node owner)'))
|
||||
self.need_loop=True
|
||||
|
||||
def add_parser_options(self):
|
||||
|
|
@ -347,7 +341,6 @@ class NodeSubscriptionsSet(base.CommandBase):
|
|||
self.host.quit(C.EXIT_BRIDGE_ERRBACK)
|
||||
|
||||
def start(self):
|
||||
common.checkURI(self.args)
|
||||
self.host.bridge.psNodeSubscriptionsSet(
|
||||
self.args.service,
|
||||
self.args.node,
|
||||
|
|
@ -367,7 +360,7 @@ class NodeSubscriptions(base.CommandBase):
|
|||
class NodeSchemaSet(base.CommandBase):
|
||||
|
||||
def __init__(self, host):
|
||||
base.CommandBase.__init__(self, host, 'set', use_pubsub_node_req=True, use_verbose=True, help=_(u'set/replace a schema'))
|
||||
base.CommandBase.__init__(self, host, 'set', use_pubsub=True, pubsub_flags={C.NODE}, use_verbose=True, help=_(u'set/replace a schema'))
|
||||
self.need_loop = True
|
||||
|
||||
def add_parser_options(self):
|
||||
|
|
@ -393,12 +386,12 @@ class NodeSchemaEdit(base.CommandBase, common.BaseEdit):
|
|||
use_items=False
|
||||
|
||||
def __init__(self, host):
|
||||
base.CommandBase.__init__(self, host, 'edit', use_pubsub_node_req=True, use_verbose=True, help=_(u'edit a schema'))
|
||||
base.CommandBase.__init__(self, host, 'edit', use_pubsub=True, pubsub_flags={C.NODE}, use_draft=True, use_verbose=True, help=_(u'edit a schema'))
|
||||
common.BaseEdit.__init__(self, self.host, PUBSUB_SCHEMA_TMP_DIR)
|
||||
self.need_loop=True
|
||||
|
||||
def add_parser_options(self):
|
||||
common.BaseEdit.add_parser_options(self)
|
||||
pass
|
||||
|
||||
def psSchemaSetCb(self):
|
||||
self.disp(_(u'schema has been set'), 1)
|
||||
|
|
@ -431,7 +424,6 @@ class NodeSchemaEdit(base.CommandBase, common.BaseEdit):
|
|||
self.runEditor("pubsub_schema_editor_args", content_file_path, content_file_obj)
|
||||
|
||||
def start(self):
|
||||
common.checkURI(self.args)
|
||||
self.host.bridge.psSchemaGet(
|
||||
self.args.service,
|
||||
self.args.node,
|
||||
|
|
@ -445,7 +437,7 @@ class NodeSchemaEdit(base.CommandBase, common.BaseEdit):
|
|||
class NodeSchemaGet(base.CommandBase):
|
||||
|
||||
def __init__(self, host):
|
||||
base.CommandBase.__init__(self, host, 'get', use_output=C.OUTPUT_XML, use_pubsub_node_req=True, use_verbose=True, help=_(u'get schema'))
|
||||
base.CommandBase.__init__(self, host, 'get', use_output=C.OUTPUT_XML, use_pubsub=True, pubsub_flags={C.NODE}, use_verbose=True, help=_(u'get schema'))
|
||||
self.need_loop=True
|
||||
|
||||
def add_parser_options(self):
|
||||
|
|
@ -459,7 +451,6 @@ class NodeSchemaGet(base.CommandBase):
|
|||
self.host.quit()
|
||||
|
||||
def start(self):
|
||||
common.checkURI(self.args)
|
||||
self.host.bridge.psSchemaGet(
|
||||
self.args.service,
|
||||
self.args.node,
|
||||
|
|
@ -487,7 +478,7 @@ class Node(base.CommandBase):
|
|||
class Set(base.CommandBase):
|
||||
|
||||
def __init__(self, host):
|
||||
base.CommandBase.__init__(self, host, 'set', use_pubsub_node_req=True, help=_(u'publish a new item or update an existing one'))
|
||||
base.CommandBase.__init__(self, host, 'set', use_pubsub=True, pubsub_flags={C.NODE}, help=_(u'publish a new item or update an existing one'))
|
||||
self.need_loop=True
|
||||
|
||||
def add_parser_options(self):
|
||||
|
|
@ -506,7 +497,6 @@ class Set(base.CommandBase):
|
|||
except ImportError:
|
||||
self.disp(u"lxml module must be installed to use edit, please install it with \"pip install lxml\"", error=True)
|
||||
self.host.quit(1)
|
||||
common.checkURI(self.args)
|
||||
try:
|
||||
element = etree.parse(sys.stdin).getroot()
|
||||
except Exception as e:
|
||||
|
|
@ -532,12 +522,10 @@ class Set(base.CommandBase):
|
|||
class Get(base.CommandBase):
|
||||
|
||||
def __init__(self, host):
|
||||
base.CommandBase.__init__(self, host, 'get', use_output=C.OUTPUT_LIST_XML, use_pubsub_node_req=True, help=_(u'get pubsub item(s)'))
|
||||
base.CommandBase.__init__(self, host, 'get', use_output=C.OUTPUT_LIST_XML, use_pubsub=True, pubsub_flags={C.NODE, C.MULTI_ITEMS}, help=_(u'get pubsub item(s)'))
|
||||
self.need_loop=True
|
||||
|
||||
def add_parser_options(self):
|
||||
self.parser.add_argument("-i", "--item", type=base.unicode_decoder, action='append', default=[], dest='items',
|
||||
help=_(u"item(s) id(s) to get (default: request all items)"))
|
||||
self.parser.add_argument("-S", "--sub-id", type=base.unicode_decoder, default=u'',
|
||||
help=_(u"subscription id"))
|
||||
self.parser.add_argument("-m", "--max", type=int, default=10, help=_(u"maximum number of items to get ({} to get all items)".format(C.NO_LIMIT)))
|
||||
|
|
@ -555,7 +543,6 @@ class Get(base.CommandBase):
|
|||
self.host.quit(C.EXIT_BRIDGE_ERRBACK)
|
||||
|
||||
def start(self):
|
||||
common.checkURI(self.args)
|
||||
self.host.bridge.psItemsGet(
|
||||
self.args.service,
|
||||
self.args.node,
|
||||
|
|
@ -570,20 +557,18 @@ class Get(base.CommandBase):
|
|||
class Delete(base.CommandBase):
|
||||
|
||||
def __init__(self, host):
|
||||
base.CommandBase.__init__(self, host, 'delete', use_pubsub_node_req=True, help=_(u'delete an item'))
|
||||
base.CommandBase.__init__(self, host, 'delete', use_pubsub=True, pubsub_flags={C.NODE, C.SINGLE_ITEM}, help=_(u'delete an item'))
|
||||
self.need_loop=True
|
||||
|
||||
def add_parser_options(self):
|
||||
self.parser.add_argument("item", nargs='?', type=base.unicode_decoder, help=_(u"item to delete"))
|
||||
self.parser.add_argument("-f", "--force", action='store_true', help=_(u"delete without confirmation"))
|
||||
self.parser.add_argument("-n", "--notify", action='store_true', help=_(u"notify deletion"))
|
||||
self.parser.add_argument("-N", "--notify", action='store_true', help=_(u"notify deletion"))
|
||||
|
||||
def psItemsDeleteCb(self):
|
||||
self.disp(_(u'item {item_id} has been deleted').format(item_id=self.args.item))
|
||||
self.host.quit(C.EXIT_OK)
|
||||
|
||||
def start(self):
|
||||
common.checkURI(self.args)
|
||||
if not self.args.item:
|
||||
self.parser.error(_(u"You need to specify an item to delete"))
|
||||
if not self.args.force:
|
||||
|
|
@ -607,12 +592,12 @@ class Delete(base.CommandBase):
|
|||
class Edit(base.CommandBase, common.BaseEdit):
|
||||
|
||||
def __init__(self, host):
|
||||
base.CommandBase.__init__(self, host, 'edit', use_verbose=True, use_pubsub_node_req=True, help=_(u'edit an existing or new pubsub item'))
|
||||
base.CommandBase.__init__(self, host, 'edit', use_verbose=True, use_pubsub=True,
|
||||
pubsub_flags={C.NODE, C.SINGLE_ITEM}, use_draft=True, help=_(u'edit an existing or new pubsub item'))
|
||||
common.BaseEdit.__init__(self, self.host, PUBSUB_TMP_DIR)
|
||||
|
||||
def add_parser_options(self):
|
||||
self.parser.add_argument("item", type=base.unicode_decoder, nargs='?', default=u'new', help=_(u"URL of the item to edit, or keyword"))
|
||||
common.BaseEdit.add_parser_options(self)
|
||||
pass
|
||||
|
||||
def edit(self, content_file_path, content_file_obj):
|
||||
# we launch editor
|
||||
|
|
@ -644,15 +629,14 @@ class Edit(base.CommandBase, common.BaseEdit):
|
|||
return etree.tostring(payload, encoding="unicode", pretty_print=True), item_id
|
||||
|
||||
def start(self):
|
||||
self.pubsub_service, self.pubsub_node, self.pubsub_item, content_file_path, content_file_obj = self.getItemPath(self.args.item)
|
||||
|
||||
self.pubsub_service, self.pubsub_node, self.pubsub_item, content_file_path, content_file_obj = self.getItemPath()
|
||||
self.edit(content_file_path, content_file_obj)
|
||||
|
||||
|
||||
class Subscribe(base.CommandBase):
|
||||
|
||||
def __init__(self, host):
|
||||
base.CommandBase.__init__(self, host, 'subscribe', use_pubsub_node_req=True, use_verbose=True, help=_(u'subscribe to a node'))
|
||||
base.CommandBase.__init__(self, host, 'subscribe', use_pubsub=True, pubsub_flags={C.NODE}, use_verbose=True, help=_(u'subscribe to a node'))
|
||||
self.need_loop=True
|
||||
|
||||
def add_parser_options(self):
|
||||
|
|
@ -680,7 +664,7 @@ class Unsubscribe(base.CommandBase):
|
|||
# TODO: voir pourquoi NodeNotFound sur subscribe juste après unsubscribe
|
||||
|
||||
def __init__(self, host):
|
||||
base.CommandBase.__init__(self, host, 'unsubscribe', use_pubsub_node_req=True, use_verbose=True, help=_(u'unsubscribe from a node'))
|
||||
base.CommandBase.__init__(self, host, 'unsubscribe', use_pubsub=True, pubsub_flags={C.NODE}, use_verbose=True, help=_(u'unsubscribe from a node'))
|
||||
self.need_loop=True
|
||||
|
||||
def add_parser_options(self):
|
||||
|
|
@ -758,7 +742,8 @@ class Search(base.CommandBase):
|
|||
EXEC_ACTIONS = (u'exec', u'external')
|
||||
|
||||
def __init__(self, host):
|
||||
base.CommandBase.__init__(self, host, 'search', use_output=C.OUTPUT_XML, use_pubsub=True, use_verbose=True, help=_(u'search items corresponding to filters'))
|
||||
base.CommandBase.__init__(self, host, 'search', use_output=C.OUTPUT_XML, use_pubsub=True, pubsub_flags={C.MULTI_ITEMS},
|
||||
use_verbose=True, help=_(u'search items corresponding to filters'))
|
||||
self.need_loop=True
|
||||
|
||||
@property
|
||||
|
|
@ -778,7 +763,6 @@ class Search(base.CommandBase):
|
|||
return (type_, value)
|
||||
|
||||
def add_parser_options(self):
|
||||
self.parser.add_argument("-i", "--item", action="append", default=[], dest='items', type=base.unicode_decoder, help=_(u"item id(s)"))
|
||||
self.parser.add_argument("-D", "--max-depth", type=int, default=0, help=_(u"maximum depth of recursion (will search linked nodes if > 0, default: 0)"))
|
||||
self.parser.add_argument("-m", "--max", type=int, default=30, help=_(u"maximum number of items to get per node ({} to get all items, default: 30)".format(C.NO_LIMIT)))
|
||||
self.parser.add_argument("-N", "--namespace", action='append', nargs=2, default=[],
|
||||
|
|
@ -1082,18 +1066,16 @@ class Search(base.CommandBase):
|
|||
if self.args.filters is None:
|
||||
self.args.filters = []
|
||||
self.args.namespace = dict(self.args.namespace + [('pubsub', "http://jabber.org/protocol/pubsub")])
|
||||
common.checkURI(self.args)
|
||||
self.getItems(0, self.args.service, self.args.node, self.args.items)
|
||||
|
||||
|
||||
class Uri(base.CommandBase):
|
||||
|
||||
def __init__(self, host):
|
||||
base.CommandBase.__init__(self, host, 'uri', use_profile=False, use_pubsub_node_req=True, help=_(u'build URI'))
|
||||
base.CommandBase.__init__(self, host, 'uri', use_profile=False, use_pubsub=True, pubsub_flags={C.NODE, C.SINGLE_ITEM}, help=_(u'build URI'))
|
||||
self.need_loop=True
|
||||
|
||||
def add_parser_options(self):
|
||||
self.parser.add_argument("-i", "--item", type=base.unicode_decoder, help=_(u"item to link"))
|
||||
self.parser.add_argument("-p", "--profile", type=base.unicode_decoder, default=C.PROF_KEY_DEFAULT, help=_(u"profile (used when no server is specified)"))
|
||||
|
||||
def display_uri(self, jid_):
|
||||
|
|
@ -1127,7 +1109,7 @@ class Uri(base.CommandBase):
|
|||
class HookCreate(base.CommandBase):
|
||||
|
||||
def __init__(self, host):
|
||||
base.CommandBase.__init__(self, host, 'create', use_pubsub_node_req=True, help=_(u'create a Pubsub hook'))
|
||||
base.CommandBase.__init__(self, host, 'create', use_pubsub=True, pubsub_flags={C.NODE}, help=_(u'create a Pubsub hook'))
|
||||
self.need_loop=True
|
||||
|
||||
def add_parser_options(self):
|
||||
|
|
@ -1143,7 +1125,6 @@ class HookCreate(base.CommandBase):
|
|||
self.parser.error(_(u"{path} is not a file").format(path=self.args.hook_arg))
|
||||
|
||||
def start(self):
|
||||
common.checkURI(self.args)
|
||||
self.checkArgs(self)
|
||||
self.host.bridge.psHookAdd(
|
||||
self.args.service,
|
||||
|
|
@ -1161,7 +1142,7 @@ class HookCreate(base.CommandBase):
|
|||
class HookDelete(base.CommandBase):
|
||||
|
||||
def __init__(self, host):
|
||||
base.CommandBase.__init__(self, host, 'delete', use_pubsub_node_req=True, help=_(u'delete a Pubsub hook'))
|
||||
base.CommandBase.__init__(self, host, 'delete', use_pubsub=True, pubsub_flags={C.NODE}, help=_(u'delete a Pubsub hook'))
|
||||
self.need_loop=True
|
||||
|
||||
def add_parser_options(self):
|
||||
|
|
@ -1174,7 +1155,6 @@ class HookDelete(base.CommandBase):
|
|||
self.host.quit()
|
||||
|
||||
def start(self):
|
||||
common.checkURI(self.args)
|
||||
HookCreate.checkArgs(self)
|
||||
self.host.bridge.psHookRemove(
|
||||
self.args.service,
|
||||
|
|
|
|||
|
|
@ -21,7 +21,6 @@ from sat_frontends.jp.constants import Const as C
|
|||
from sat.core.i18n import _
|
||||
from sat.core import exceptions
|
||||
from sat.tools.common import regex
|
||||
from sat.tools.common import uri
|
||||
from sat.tools.common.ansi import ANSI as A
|
||||
from sat.tools import config
|
||||
from ConfigParser import NoSectionError, NoOptionError
|
||||
|
|
@ -105,40 +104,12 @@ def parse_args(host, cmd_line, **format_kw):
|
|||
return []
|
||||
|
||||
|
||||
def checkURI(args):
|
||||
"""check if args.node is an URI
|
||||
|
||||
if a valid xmpp: URI is found, args.service, args.node and args.item will be set
|
||||
"""
|
||||
# FIXME: Q&D way to handle xmpp: uris, a generic way is needed
|
||||
# and it should be merged with code in BaseEdit
|
||||
if not args.service and args.node.startswith('xmpp:'):
|
||||
try:
|
||||
uri_data = uri.parseXMPPUri(args.node)
|
||||
except ValueError:
|
||||
pass
|
||||
else:
|
||||
if uri_data[u'type'] == 'pubsub':
|
||||
args.service = uri_data[u'path']
|
||||
args.node = uri_data[u'node']
|
||||
if u'item' in uri_data:
|
||||
try:
|
||||
item = getattr(uri_data, 'item')
|
||||
except AttributeError:
|
||||
pass
|
||||
else:
|
||||
if item is None:
|
||||
args.item = uri_data
|
||||
|
||||
|
||||
class BaseEdit(object):
|
||||
u"""base class for editing commands
|
||||
|
||||
This class allows to edit file for PubSub or something else.
|
||||
It works with temporary files in SàT local_dir, in a "cat_dir" subdir
|
||||
"""
|
||||
# use_items(bool): True if items are used, will then add item related options
|
||||
use_items=True
|
||||
|
||||
def __init__(self, host, cat_dir, use_metadata=False):
|
||||
"""
|
||||
|
|
@ -154,12 +125,6 @@ class BaseEdit(object):
|
|||
self.cat_dir_str = cat_dir.encode('utf-8')
|
||||
self.use_metadata = use_metadata
|
||||
|
||||
def add_parser_options(self):
|
||||
if self.use_items:
|
||||
group = self.parser.add_mutually_exclusive_group()
|
||||
group.add_argument("--force-item", action='store_true', help=_(u"don't use magic and take item argument as an actual item"))
|
||||
group.add_argument("--last-item", action='store_true', help=_(u"take last item instead of creating a new one if no item id is found"))
|
||||
|
||||
def secureUnlink(self, path):
|
||||
"""Unlink given path after keeping it for a while
|
||||
|
||||
|
|
@ -365,145 +330,73 @@ class BaseEdit(object):
|
|||
"""return suffix used for content file"""
|
||||
return u'xml'
|
||||
|
||||
def getItemPath(self, item):
|
||||
def getItemPath(self):
|
||||
"""retrieve item path (i.e. service and node) from item argument
|
||||
|
||||
This method is obviously only useful for edition of PubSub based features
|
||||
service, node and item must be named like this in args
|
||||
@param item(unicode): item to get or url or magic keyword
|
||||
item argument can be used to specify :
|
||||
- HTTP(S) URL
|
||||
- XMPP URL
|
||||
- keyword, which can be:
|
||||
- new: create new item
|
||||
- last: retrieve last published item
|
||||
- current: continue current local draft
|
||||
- file path
|
||||
- item id
|
||||
"""
|
||||
force_item = self.args.force_item
|
||||
if force_item and not item:
|
||||
self.parser.error(_(u"an item id must be specified if you use --force-item"))
|
||||
command = item.lower()
|
||||
pubsub_service = self.args.service
|
||||
pubsub_node = self.args.node
|
||||
pubsub_item = None
|
||||
service = self.args.service
|
||||
node = self.args.node
|
||||
item = self.args.item
|
||||
last_item = self.args.last_item
|
||||
|
||||
if not force_item and command not in ('new', 'last', 'current'):
|
||||
# we have probably an URL, we try to parse it
|
||||
import urlparse
|
||||
url = self.args.item
|
||||
parsed_url = urlparse.urlsplit(url.encode('utf-8'))
|
||||
if parsed_url.scheme.startswith('http'):
|
||||
self.disp(u"{} URL found, trying to find associated xmpp: URI".format(parsed_url.scheme.upper()),1)
|
||||
# HTTP URL, we try to find xmpp: links
|
||||
try:
|
||||
from lxml import etree
|
||||
except ImportError:
|
||||
self.disp(u"lxml module must be installed to use http(s) scheme, please install it with \"pip install lxml\"", error=True)
|
||||
self.host.quit(1)
|
||||
import urllib2
|
||||
parser = etree.HTMLParser()
|
||||
try:
|
||||
root = etree.parse(urllib2.urlopen(url), parser)
|
||||
except etree.XMLSyntaxError as e:
|
||||
self.disp(_(u"Can't parse HTML page : {msg}").format(msg=e))
|
||||
links = []
|
||||
else:
|
||||
links = root.xpath("//link[@rel='alternate' and starts-with(@href, 'xmpp:')]")
|
||||
if not links:
|
||||
self.disp(u'Could not find alternate "xmpp:" URI, can\'t find associated XMPP PubSub node/item', error=True)
|
||||
self.host.quit(1)
|
||||
url = links[0].get('href')
|
||||
parsed_url = urlparse.urlsplit(url)
|
||||
|
||||
if parsed_url.scheme == 'xmpp':
|
||||
if self.args.service or self.args.node:
|
||||
self.parser.error(_(u"You can't use URI and --service or --node at the same time"))
|
||||
|
||||
self.disp(u"XMPP URI used: {}".format(url),2)
|
||||
# XXX: if we have not xmpp: URI here, we'll take the data as a file path
|
||||
pubsub_service = parsed_url.path.decode('utf-8')
|
||||
pubsub_data = urlparse.parse_qs(parsed_url.query)
|
||||
try:
|
||||
pubsub_node = pubsub_data['node'][0].decode('utf-8')
|
||||
except KeyError:
|
||||
self.disp(u'No node found in xmpp: URI, can\'t retrieve item', error=True)
|
||||
self.host.quit(1)
|
||||
pubsub_item = pubsub_data.get('item',[None])[0]
|
||||
if pubsub_item is not None:
|
||||
pubsub_item = pubsub_item.decode('utf-8')
|
||||
if pubsub_item is None and self.args.last_item:
|
||||
command = 'last'
|
||||
elif pubsub_item is not None:
|
||||
command = 'edit' # XXX: edit command is only used internaly, it similar to last, but with the item given in the URL
|
||||
else:
|
||||
command = 'new'
|
||||
|
||||
if self.args.last_item:
|
||||
if pubsub_item is None:
|
||||
command = 'last'
|
||||
elif command != 'last':
|
||||
self.parser.error(_(u"--last-item can't be used with a specified item"))
|
||||
|
||||
if not force_item and command in ('new', 'last', 'edit'):
|
||||
if self.args.current:
|
||||
# user wants to continue current draft
|
||||
content_file_path = self.getCurrentFile(self.profile)
|
||||
self.disp(u'Continuing edition of current draft', 2)
|
||||
content_file_obj = open(content_file_path, 'r+b')
|
||||
# we seek at the end of file in case of an item already exist
|
||||
# this will write content of the existing item at the end of the draft.
|
||||
# This way no data should be lost.
|
||||
content_file_obj.seek(0, os.SEEK_END)
|
||||
elif self.args.draft_path:
|
||||
# there is an existing draft that we use
|
||||
content_file_path = os.path.expanduser(self.args.item)
|
||||
content_file_obj = open(content_file_path, 'r+b')
|
||||
# we seek at the end for the same reason as above
|
||||
content_file_obj.seek(0, os.SEEK_END)
|
||||
else:
|
||||
# we need a temporary file
|
||||
content_file_obj, content_file_path = self.getTmpFile()
|
||||
if command == 'new':
|
||||
self.disp(u'Editing a new item', 2)
|
||||
|
||||
if item or last_item:
|
||||
self.disp(u'Editing requested published item', 2)
|
||||
try:
|
||||
if self.use_metadata:
|
||||
content, metadata, item = self.getItemData(service, node, item)
|
||||
else:
|
||||
content, item = self.getItemData(service, node, item)
|
||||
except Exception as e:
|
||||
# FIXME: ugly but we have not good may to check errors in bridge
|
||||
if u'item-not-found' in unicode(e):
|
||||
# item doesn't exist, we create a new one with requested id
|
||||
metadata = None
|
||||
elif command in ('last', 'edit'):
|
||||
self.disp(u'Editing requested published item', 2)
|
||||
try:
|
||||
if self.use_metadata:
|
||||
content, metadata, pubsub_item = self.getItemData(pubsub_service, pubsub_node, pubsub_item)
|
||||
if last_item:
|
||||
self.disp(_(u'no item found at all, we create a new one'), 2)
|
||||
else:
|
||||
content, pubsub_item = self.getItemData(pubsub_service, pubsub_node, pubsub_item)
|
||||
except Exception as e:
|
||||
self.disp(u"Error while retrieving last item: {}".format(e))
|
||||
self.host.quit(1)
|
||||
self.disp(_(u'item "{item_id}" not found, we create a new item with this id').format(item_id=item), 2)
|
||||
content_file_obj.seek(0)
|
||||
else:
|
||||
self.disp(u"Error while retrieving item: {}".format(e))
|
||||
self.host.quit(C.EXIT_ERROR)
|
||||
else:
|
||||
# item exists, we write content
|
||||
if content_file_obj.tell() != 0:
|
||||
# we already have a draft,
|
||||
# we copy item content after it and add an indicator
|
||||
content_file_obj.write('\n*****\n')
|
||||
content_file_obj.write(content.encode('utf-8'))
|
||||
content_file_obj.seek(0)
|
||||
self.disp(_(u'item "{item_id}" found, we edit it').format(item_id=item), 2)
|
||||
else:
|
||||
self.disp(u'Editing a new item', 2)
|
||||
if self.use_metadata:
|
||||
metadata = None
|
||||
if not force_item and command == 'current':
|
||||
# user wants to continue current draft
|
||||
content_file_path = self.getCurrentFile(self.profile)
|
||||
self.disp(u'Continuing edition of current draft', 2)
|
||||
content_file_obj = open(content_file_path, 'r+b')
|
||||
elif not force_item and os.path.isfile(self.args.item):
|
||||
# there is an existing draft that we use
|
||||
content_file_path = os.path.expanduser(self.args.item)
|
||||
content_file_obj = open(content_file_path, 'r+b')
|
||||
else:
|
||||
# last chance, it should be an item
|
||||
content_file_obj, content_file_path = self.getTmpFile()
|
||||
pubsub_item = self.args.item
|
||||
|
||||
try:
|
||||
# we try to get existing item
|
||||
if self.use_metadata:
|
||||
content, metadata, pubsub_item = self.getItemData(pubsub_service, pubsub_node, self.args.item)
|
||||
else:
|
||||
content, pubsub_item = self.getItemData(pubsub_service, pubsub_node, self.args.item)
|
||||
except Exception as e:
|
||||
# FIXME: ugly but we have not good may to check errors in bridge
|
||||
if u'item-not-found' in unicode(e):
|
||||
# item doesn't exist, we create a new one with requested id
|
||||
metadata = None
|
||||
self.disp(_(u'item "{item_id}" not found, we create a new item with this id').format(item_id=pubsub_item), 2)
|
||||
else:
|
||||
# item exists, we write content if content file
|
||||
content_file_obj.write(content.encode('utf-8'))
|
||||
content_file_obj.seek(0)
|
||||
self.disp(_(u'item "{item_id}" found, we edit it').format(item_id=pubsub_item), 2)
|
||||
|
||||
if self.use_metadata:
|
||||
return pubsub_service, pubsub_node, pubsub_item, content_file_path, content_file_obj, metadata
|
||||
return service, node, item, content_file_path, content_file_obj, metadata
|
||||
else:
|
||||
return pubsub_service, pubsub_node, pubsub_item, content_file_path, content_file_obj
|
||||
return service, node, item, content_file_path, content_file_obj
|
||||
|
||||
|
||||
class Table(object):
|
||||
|
|
|
|||
|
|
@ -36,6 +36,12 @@ class Const(constants.Const):
|
|||
OUTPUT_LIST_XML = u'list_xml' # list of XML nodes (as unicode strings)
|
||||
OUTPUT_TYPES = (OUTPUT_TEXT, OUTPUT_DICT, OUTPUT_LIST, OUTPUT_LIST_DICT, OUTPUT_DICT_DICT, OUTPUT_COMPLEX, OUTPUT_XML, OUTPUT_LIST_XML)
|
||||
|
||||
# Pubsub options flags
|
||||
SERVICE = u'service' # service required
|
||||
NODE = u'node' # node required
|
||||
SINGLE_ITEM = u'single_item' # only one item is allowed
|
||||
MULTI_ITEMS = u'multi_items' # multiple items are allowed
|
||||
|
||||
# ANSI
|
||||
A_HEADER = A.BOLD + A.FG_YELLOW
|
||||
A_SUBHEADER = A.BOLD + A.FG_RED
|
||||
|
|
|
|||
Loading…
Reference in a new issue