jp (blog): added blog/get command:

- blog/get will retrieve and parse blog items on specified service/node and can request only one or more specific items according to ids of max value
    - it takes profit of outputs and the new extra_outputs: a default output display microblogs as key/value, a fancy one display it in a more confortable way for reading it the terminal
    - for default output, keys can be filtered using --key argument
This commit is contained in:
Goffi 2017-02-16 01:02:33 +01:00
commit bb6d71d857

View file

@ -20,7 +20,8 @@
import base
from sat.core.i18n import _
from sat.core.constants import Const as C
from sat_frontends.jp.constants import Const as C
from sat.tools.common.ansi import ANSI as A
from sat.tools import config
from ConfigParser import NoSectionError, NoOptionError
import json
@ -63,8 +64,25 @@ KEY_TO_REMOVE_METADATA = ('id','content', 'content_xhtml', 'comments_node', 'com
URL_REDIRECT_PREFIX = 'url_redirect_'
INOTIFY_INSTALL = '"pip install inotify"'
SECURE_UNLINK_MAX = 10 * 2 # we double value has there are 2 files per draft (content and metadata)
SECURE_UNLINK_MAX = 10 * 2 # we double value as there are 2 files per draft (content and metadata)
SECURE_UNLINK_DIR = ".backup"
HEADER_ANSI = A.BOLD + A.FG_YELLOW
NS_MICROBLOG = u'urn:xmpp:microblog:0'
MB_KEYS = (u"id",
u"atom_id",
u"updated",
u"published",
u"comments", # this key is used for all comments* keys
u"tags", # this key is used for all tag* keys
u"author",
u"author_jid",
u"author_email",
u"author_jid_verified",
u"content",
u"content_xhtml",
u"title",
u"title_xhtml")
OUTPUT_OPT_NO_HEADER = u'no-header'
class BlogCommon(object):
@ -169,6 +187,145 @@ class BlogCommon(object):
return []
class Get(base.CommandBase):
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='complex', extra_outputs=extra_outputs, help=_(u'get blog item(s)'))
self.need_loop=True
def add_parser_options(self):
self.parser.add_argument("-n", "--node", type=base.unicode_decoder, default=NS_MICROBLOG, help=_(u"PubSub node to request"))
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',
help=_(u"microblog data key(s) to display (default: depend of verbosity)"))
self.parser.add_argument("service", type=base.unicode_decoder, nargs='?', default=u'',
help=_(u"JID of the PubSub service (default: request profile own blog)"))
# TODO: add MAM filters
def format_comments(self, item, keys):
comments_data = data_format.dict2iterdict(u'comments', item, (u'node', u'service'), pop=True)
lines = []
for data in comments_data:
lines.append(data[u'comments'])
for k in (u'node', u'service'):
if OUTPUT_OPT_NO_HEADER in self.args.output_opts:
header = u''
else:
header = HEADER_ANSI + k + u': ' + A.RESET
lines.append(header + data[k])
return u'\n'.join(lines)
def format_tags(self, item, keys):
tags = data_format.dict2iter('tag', item, pop=True)
return u', '.join(tags)
def get_keys(self):
"""return keys to display according to verbosity or explicit key request"""
verbosity = self.args.verbose
if self.args.keys:
if not set(MB_KEYS).issuperset(self.args.keys):
self.disp(u"following keys are invalid: {invalid}.\n"
u"Valid keys are: {valid}.".format(
invalid = u', '.join(set(self.args.keys).difference(MB_KEYS)),
valid = u', '.join(sorted(MB_KEYS))),
error=True)
self.host.quit(C.EXIT_BAD_ARG)
return self.args.keys
else:
if verbosity == 0:
return (u'title', u'content')
elif verbosity == 1:
return (u"title", u"tags", u"author", u"author_jid", u"author_email", u"author_jid_verified", u"content")
else:
return MB_KEYS
def default_output(self, data):
"""simple key/value output"""
items, metadata = data
keys = self.get_keys()
# k_cb use format_[key] methods for complex formattings
k_cb = {}
for k in keys:
try:
callback = getattr(self, "format_" + k)
except AttributeError:
pass
else:
k_cb[k] = callback
for idx, item in enumerate(items):
for k in keys:
if k not in item and k not in k_cb:
continue
if OUTPUT_OPT_NO_HEADER in self.args.output_opts:
header = ''
else:
header = u"{k_fmt}{key}:{k_fmt_e} {sep}".format(
k_fmt = HEADER_ANSI,
key = k,
k_fmt_e = A.RESET,
sep = u'\n' if 'content' in k else u'')
value = k_cb[k](item, keys) if k in k_cb else item[k]
print header + value
# we want a separation line after each item but the last one
if idx < len(items)-1:
print(u'')
def fancy_output(self, data):
"""display blog is a nice to read way
this output doesn't use keys filter
"""
# thanks to http://stackoverflow.com/a/943921
rows, columns = map(int, os.popen('stty size', 'r').read().split())
items, metadata = data
sep = A.color(A.FG_BLUE, columns * u'▬')
if items:
print(u'\n' + sep + '\n')
for idx, item in enumerate(items):
title = item.get(u'title')
tags = list(data_format.dict2iter('tag', item, pop=True))
content = item.get(u'content')
if title:
print(A.color(A.BOLD, A.FG_CYAN, item[u'title']))
if tags:
print(A.color(A.FG_YELLOW, u', '.join(tags)))
if (title or tags) and content:
print("")
if content:
print content
print(u'\n' + sep + '\n')
def mbGetCb(self, mb_result):
self.output(mb_result)
self.host.quit(C.EXIT_OK)
def mbGetEb(self, failure_):
self.disp(u"can't get blog items: {reason}".format(
reason=failure_), error=True)
self.host.quit(C.EXIT_BRIDGE_ERRBACK)
def start(self):
self.host.bridge.mbGet(
self.args.service,
self.args.node,
self.args.max,
self.args.items,
{},
self.profile,
callback=self.mbGetCb,
errback=self.mbGetEb)
class Edit(base.CommandBase, BlogCommon):
def __init__(self, host):
@ -654,7 +811,7 @@ class Import(base.CommandAnswering):
class Blog(base.CommandBase):
subcommands = (Edit, Preview, Import)
subcommands = (Get, Edit, Preview, Import)
def __init__(self, host):
super(Blog, self).__init__(host, 'blog', use_profile=False, help=_('blog/microblog management'))