# HG changeset patch # User Goffi # Date 1457026133 -3600 # Node ID 658824755a0c40d4f058bec0abec327fc53e3451 # Parent 6ec54626610c39bb4fd793318891d2e55bf5b199 jp (blog): preview command, first draft diff -r 6ec54626610c -r 658824755a0c frontends/src/jp/cmd_blog.py --- a/frontends/src/jp/cmd_blog.py Thu Mar 03 17:02:23 2016 +0100 +++ b/frontends/src/jp/cmd_blog.py Thu Mar 03 18:28:53 2016 +0100 @@ -30,6 +30,7 @@ import tempfile import subprocess import shlex +import glob from sat.tools import common __commands__ = ["Blog"] @@ -54,12 +55,23 @@ CONF_SYNTAX_EXT = 'syntax_ext_dict' BLOG_TMP_DIR="blog" +METADATA_SUFF = '_metadata.json' # key to remove from metadata tmp file if they exist KEY_TO_REMOVE_METADATA = ('id','content', 'content_xhtml', 'comments_node', 'comments_service') URL_REDIRECT_PREFIX = 'url_redirect_' +def getTmpDir(sat_conf): + """Return directory used to store temporary files + + @param sat_conf(ConfigParser.ConfigParser): instance opened on sat configuration + @return (str): path to the dir + """ + local_dir = config.getConfig(sat_conf, '', 'local_dir', Exception) + return os.path.join(local_dir, BLOG_TMP_DIR) + + class Edit(base.CommandBase): def __init__(self, host): @@ -67,7 +79,7 @@ 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")) - self.parser.add_argument("-T", '--title', type=base.unicode_decoder, help=_(u"Title of the item")) + 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("--no-comment", action='store_true', help=_(u"disable comments")) @@ -78,8 +90,7 @@ @param tmp_suff (str): suffix to use for the filename @return (tuple(file, str)): opened (w+b) file object and file path """ - local_dir = config.getConfig(sat_conf, '', 'local_dir', Exception) - tmp_dir = os.path.join(local_dir, BLOG_TMP_DIR) + tmp_dir = getTmpDir(sat_conf) if not os.path.exists(tmp_dir): try: os.makedirs(tmp_dir) @@ -119,7 +130,7 @@ mb_data['title'] = self.args.title # the we create the file and write metadata there, as JSON dict - meta_file_path = os.path.splitext(content_file_path)[0] + '_metadata.json' + meta_file_path = os.path.splitext(content_file_path)[0] + METADATA_SUFF # XXX: if we port jp one day on Windows, O_BINARY may need to be added here if os.path.exists(meta_file_path): self.disp(u"metadata file {} already exists, this should not happen! Cancelling...", error=True) @@ -244,6 +255,61 @@ self.edit(sat_conf, content_file_path, content_file_obj, mb_data=mb_data) +class Preview(base.CommandBase): + + def __init__(self, host): + super(Preview, self).__init__(host, 'preview', use_verbose=True, help=_(u'preview a blog content')) + + def add_parser_options(self): + self.parser.add_argument("file", type=base.unicode_decoder, nargs='?', default=u'current', help=_(u"path to the content file")) + + def start(self): + sat_conf = config.parseMainConf() + + # which file do we need to edit? + if self.args.file == 'current': + # we guess the blog item currently edited by choosing + # the most recent file corresponding to temp file pattern + # in tmp_dir, excluding metadata files + tmp_dir = getTmpDir(sat_conf) + available = [path for path in glob.glob(os.path.join(tmp_dir, 'blog_*')) if not path.endswith(METADATA_SUFF)] + if not available: + self.disp(u"Counldn't find any content draft in {path}".format(path=tmp_dir), error=True) + self.host.quit(1) + current_path = max(available, key=lambda path: os.stat(path).st_mtime) + else: + current_path = os.path.abspath(self.args.file) + + # we first try to guess syntax with extension + SYNTAX_EXT.update(config.getConfig(sat_conf, 'jp', CONF_SYNTAX_EXT, {})) + ext = os.path.splitext(current_path)[1][1:] # we get extension without the '.' + syntax = None + if ext: + for k,v in SYNTAX_EXT.iteritems(): + if ext == v: + syntax = k + break + + # if not found, we use current syntax + if syntax is None: + syntax = self.host.bridge.getParamA("Syntax", "Composition", "value", self.profile) + if syntax != 'XHTML': + with open(current_path, 'rb') as f: + content_xhtml = self.host.bridge.syntaxConvert(f.read(), syntax, 'XHTML', False, self.profile) + import webbrowser + import urllib + with tempfile.NamedTemporaryFile(suffix='.xhtml', delete=False) as f: + # XXX: we don't delete file automatically because browser need it (and webbrowser.open can return before it is read) + self.disp(u'temporary file created at {}\nthis file will NOT BE DELETED AUTOMATICALLY, please delete it yourself when you have finished'.format(f.name)) + xhtml = (u'' + + u''+ + '{}' + + u'').format(content_xhtml) + f.write(xhtml.encode('utf-8')) + url = 'file:{}'.format(urllib.quote(f.name)) + webbrowser.open_new_tab(url) + + class Import(base.CommandAnswering): def __init__(self, host): super(Import, self).__init__(host, 'import', use_progress=True, help=_(u'import an external blog')) @@ -322,7 +388,7 @@ class Blog(base.CommandBase): - subcommands = (Edit, Import) + subcommands = (Edit, Preview, Import) def __init__(self, host): super(Blog, self).__init__(host, 'blog', use_profile=False, help=_('blog/microblog management'))