Mercurial > libervia-backend
comparison frontends/src/jp/cmd_blog.py @ 1874:658824755a0c
jp (blog): preview command, first draft
author | Goffi <goffi@goffi.org> |
---|---|
date | Thu, 03 Mar 2016 18:28:53 +0100 |
parents | 6ec54626610c |
children | 1088bf7b28e7 |
comparison
equal
deleted
inserted
replaced
1873:6ec54626610c | 1874:658824755a0c |
---|---|
28 import os | 28 import os |
29 import time | 29 import time |
30 import tempfile | 30 import tempfile |
31 import subprocess | 31 import subprocess |
32 import shlex | 32 import shlex |
33 import glob | |
33 from sat.tools import common | 34 from sat.tools import common |
34 | 35 |
35 __commands__ = ["Blog"] | 36 __commands__ = ["Blog"] |
36 | 37 |
37 # extensions to use with known syntaxes | 38 # extensions to use with known syntaxes |
52 'nano': ' -F {content_file} {metadata_file}', | 53 'nano': ' -F {content_file} {metadata_file}', |
53 } | 54 } |
54 | 55 |
55 CONF_SYNTAX_EXT = 'syntax_ext_dict' | 56 CONF_SYNTAX_EXT = 'syntax_ext_dict' |
56 BLOG_TMP_DIR="blog" | 57 BLOG_TMP_DIR="blog" |
58 METADATA_SUFF = '_metadata.json' | |
57 # key to remove from metadata tmp file if they exist | 59 # key to remove from metadata tmp file if they exist |
58 KEY_TO_REMOVE_METADATA = ('id','content', 'content_xhtml', 'comments_node', 'comments_service') | 60 KEY_TO_REMOVE_METADATA = ('id','content', 'content_xhtml', 'comments_node', 'comments_service') |
59 | 61 |
60 URL_REDIRECT_PREFIX = 'url_redirect_' | 62 URL_REDIRECT_PREFIX = 'url_redirect_' |
61 | 63 |
62 | 64 |
65 def getTmpDir(sat_conf): | |
66 """Return directory used to store temporary files | |
67 | |
68 @param sat_conf(ConfigParser.ConfigParser): instance opened on sat configuration | |
69 @return (str): path to the dir | |
70 """ | |
71 local_dir = config.getConfig(sat_conf, '', 'local_dir', Exception) | |
72 return os.path.join(local_dir, BLOG_TMP_DIR) | |
73 | |
74 | |
63 class Edit(base.CommandBase): | 75 class Edit(base.CommandBase): |
64 | 76 |
65 def __init__(self, host): | 77 def __init__(self, host): |
66 super(Edit, self).__init__(host, 'edit', use_verbose=True, help=_(u'edit an existing or new blog post')) | 78 super(Edit, self).__init__(host, 'edit', use_verbose=True, help=_(u'edit an existing or new blog post')) |
67 | 79 |
68 def add_parser_options(self): | 80 def add_parser_options(self): |
69 self.parser.add_argument("item", type=base.unicode_decoder, nargs='?', default=u'new', help=_(u"URL of the item to edit, or keyword")) | 81 self.parser.add_argument("item", type=base.unicode_decoder, nargs='?', default=u'new', help=_(u"URL of the item to edit, or keyword")) |
70 self.parser.add_argument("-T", '--title', type=base.unicode_decoder, help=_(u"Title of the item")) | 82 self.parser.add_argument("-T", '--title', type=base.unicode_decoder, help=_(u"title of the item")) |
71 self.parser.add_argument("-t", '--tag', type=base.unicode_decoder, action='append', help=_(u"tag (category) of your item")) | 83 self.parser.add_argument("-t", '--tag', type=base.unicode_decoder, action='append', help=_(u"tag (category) of your item")) |
72 self.parser.add_argument("--no-comment", action='store_true', help=_(u"disable comments")) | 84 self.parser.add_argument("--no-comment", action='store_true', help=_(u"disable comments")) |
73 | 85 |
74 def getTmpFile(self, sat_conf, tmp_suff): | 86 def getTmpFile(self, sat_conf, tmp_suff): |
75 """Create a temporary file to received blog item body | 87 """Create a temporary file to received blog item body |
76 | 88 |
77 @param sat_conf(ConfigParser.ConfigParser): instance opened on sat configuration | 89 @param sat_conf(ConfigParser.ConfigParser): instance opened on sat configuration |
78 @param tmp_suff (str): suffix to use for the filename | 90 @param tmp_suff (str): suffix to use for the filename |
79 @return (tuple(file, str)): opened (w+b) file object and file path | 91 @return (tuple(file, str)): opened (w+b) file object and file path |
80 """ | 92 """ |
81 local_dir = config.getConfig(sat_conf, '', 'local_dir', Exception) | 93 tmp_dir = getTmpDir(sat_conf) |
82 tmp_dir = os.path.join(local_dir, BLOG_TMP_DIR) | |
83 if not os.path.exists(tmp_dir): | 94 if not os.path.exists(tmp_dir): |
84 try: | 95 try: |
85 os.makedirs(tmp_dir) | 96 os.makedirs(tmp_dir) |
86 except OSError as e: | 97 except OSError as e: |
87 self.disp(u"Can't create {path} directory: {reason}".format( | 98 self.disp(u"Can't create {path} directory: {reason}".format( |
117 common.iter2dict('tag', self.args.tag, mb_data) | 128 common.iter2dict('tag', self.args.tag, mb_data) |
118 if self.args.title is not None: | 129 if self.args.title is not None: |
119 mb_data['title'] = self.args.title | 130 mb_data['title'] = self.args.title |
120 | 131 |
121 # the we create the file and write metadata there, as JSON dict | 132 # the we create the file and write metadata there, as JSON dict |
122 meta_file_path = os.path.splitext(content_file_path)[0] + '_metadata.json' | 133 meta_file_path = os.path.splitext(content_file_path)[0] + METADATA_SUFF |
123 # XXX: if we port jp one day on Windows, O_BINARY may need to be added here | 134 # XXX: if we port jp one day on Windows, O_BINARY may need to be added here |
124 if os.path.exists(meta_file_path): | 135 if os.path.exists(meta_file_path): |
125 self.disp(u"metadata file {} already exists, this should not happen! Cancelling...", error=True) | 136 self.disp(u"metadata file {} already exists, this should not happen! Cancelling...", error=True) |
126 with os.fdopen(os.open(meta_file_path, os.O_RDWR | os.O_CREAT ,0o600), 'w+b') as f: | 137 with os.fdopen(os.open(meta_file_path, os.O_RDWR | os.O_CREAT ,0o600), 'w+b') as f: |
127 # we need to use an intermediate unicode buffer to write to the file unicode without escaping characters | 138 # we need to use an intermediate unicode buffer to write to the file unicode without escaping characters |
240 if current_syntax != 'XHTML': | 251 if current_syntax != 'XHTML': |
241 content = self.host.bridge.syntaxConvert(content, 'XHTML', current_syntax, False, self.profile) | 252 content = self.host.bridge.syntaxConvert(content, 'XHTML', current_syntax, False, self.profile) |
242 content_file_obj.write(content.encode('utf-8')) | 253 content_file_obj.write(content.encode('utf-8')) |
243 content_file_obj.seek(0) | 254 content_file_obj.seek(0) |
244 self.edit(sat_conf, content_file_path, content_file_obj, mb_data=mb_data) | 255 self.edit(sat_conf, content_file_path, content_file_obj, mb_data=mb_data) |
256 | |
257 | |
258 class Preview(base.CommandBase): | |
259 | |
260 def __init__(self, host): | |
261 super(Preview, self).__init__(host, 'preview', use_verbose=True, help=_(u'preview a blog content')) | |
262 | |
263 def add_parser_options(self): | |
264 self.parser.add_argument("file", type=base.unicode_decoder, nargs='?', default=u'current', help=_(u"path to the content file")) | |
265 | |
266 def start(self): | |
267 sat_conf = config.parseMainConf() | |
268 | |
269 # which file do we need to edit? | |
270 if self.args.file == 'current': | |
271 # we guess the blog item currently edited by choosing | |
272 # the most recent file corresponding to temp file pattern | |
273 # in tmp_dir, excluding metadata files | |
274 tmp_dir = getTmpDir(sat_conf) | |
275 available = [path for path in glob.glob(os.path.join(tmp_dir, 'blog_*')) if not path.endswith(METADATA_SUFF)] | |
276 if not available: | |
277 self.disp(u"Counldn't find any content draft in {path}".format(path=tmp_dir), error=True) | |
278 self.host.quit(1) | |
279 current_path = max(available, key=lambda path: os.stat(path).st_mtime) | |
280 else: | |
281 current_path = os.path.abspath(self.args.file) | |
282 | |
283 # we first try to guess syntax with extension | |
284 SYNTAX_EXT.update(config.getConfig(sat_conf, 'jp', CONF_SYNTAX_EXT, {})) | |
285 ext = os.path.splitext(current_path)[1][1:] # we get extension without the '.' | |
286 syntax = None | |
287 if ext: | |
288 for k,v in SYNTAX_EXT.iteritems(): | |
289 if ext == v: | |
290 syntax = k | |
291 break | |
292 | |
293 # if not found, we use current syntax | |
294 if syntax is None: | |
295 syntax = self.host.bridge.getParamA("Syntax", "Composition", "value", self.profile) | |
296 if syntax != 'XHTML': | |
297 with open(current_path, 'rb') as f: | |
298 content_xhtml = self.host.bridge.syntaxConvert(f.read(), syntax, 'XHTML', False, self.profile) | |
299 import webbrowser | |
300 import urllib | |
301 with tempfile.NamedTemporaryFile(suffix='.xhtml', delete=False) as f: | |
302 # XXX: we don't delete file automatically because browser need it (and webbrowser.open can return before it is read) | |
303 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)) | |
304 xhtml = (u'<html xmlns="http://www.w3.org/1999/xhtml">' + | |
305 u'<head><meta http-equiv="Content-Type" content="text/html;charset=utf-8" /></head>'+ | |
306 '<body>{}</body>' + | |
307 u'</html>').format(content_xhtml) | |
308 f.write(xhtml.encode('utf-8')) | |
309 url = 'file:{}'.format(urllib.quote(f.name)) | |
310 webbrowser.open_new_tab(url) | |
245 | 311 |
246 | 312 |
247 class Import(base.CommandAnswering): | 313 class Import(base.CommandAnswering): |
248 def __init__(self, host): | 314 def __init__(self, host): |
249 super(Import, self).__init__(host, 'import', use_progress=True, help=_(u'import an external blog')) | 315 super(Import, self).__init__(host, 'import', use_progress=True, help=_(u'import an external blog')) |
320 self.host.bridge.blogImport(self.args.importer, self.args.location, options, self.args.service, self.profile, | 386 self.host.bridge.blogImport(self.args.importer, self.args.location, options, self.args.service, self.profile, |
321 callback=gotId, errback=self.error) | 387 callback=gotId, errback=self.error) |
322 | 388 |
323 | 389 |
324 class Blog(base.CommandBase): | 390 class Blog(base.CommandBase): |
325 subcommands = (Edit, Import) | 391 subcommands = (Edit, Preview, Import) |
326 | 392 |
327 def __init__(self, host): | 393 def __init__(self, host): |
328 super(Blog, self).__init__(host, 'blog', use_profile=False, help=_('blog/microblog management')) | 394 super(Blog, self).__init__(host, 'blog', use_profile=False, help=_('blog/microblog management')) |