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:
parent
97cf0e6e01
commit
bb6d71d857
1 changed files with 160 additions and 3 deletions
|
|
@ -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'))
|
||||
|
|
|
|||
Loading…
Reference in a new issue