Mercurial > libervia-backend
comparison frontends/src/jp/cmd_blog.py @ 1866:397ef87958b9
jp (blog): edit command, first draft:
- can edit a new or existing item, by default edit a new item
- item are selected with a shortcut, for now only "new" and "last" are handled. URI handling is planed, specially xmpp: URIs
- file are edited using EDITOR env variable, or editor in [jp] section in sat.conf
- current syntax is used, file extension is choosed according to syntax, to make syntax coloration and other goodies in editor available
- if file is empty or not modified, nothing is published
- for now, title, tags and commend desactivation are handled with optional arguments, but other are planed, and a metadata system should come soon
author | Goffi <goffi@goffi.org> |
---|---|
date | Tue, 01 Mar 2016 01:54:21 +0100 |
parents | 96ba685162f6 |
children | 28b29381db75 |
comparison
equal
deleted
inserted
replaced
1865:fc6eeacf31bc | 1866:397ef87958b9 |
---|---|
19 | 19 |
20 | 20 |
21 import base | 21 import base |
22 from sat.core.i18n import _ | 22 from sat.core.i18n import _ |
23 from sat.core.constants import Const as C | 23 from sat.core.constants import Const as C |
24 from sat.tools import config | |
24 import json | 25 import json |
26 import os.path | |
27 import os | |
28 import time | |
29 import tempfile | |
30 import subprocess | |
31 from sat.tools import common | |
32 | |
33 __commands__ = ["Blog"] | |
34 | |
35 SYNTAX_EXT = { '': 'txt', # used when the syntax is not found | |
36 "XHTML": "xhtml", | |
37 "markdown": "md" | |
38 } | |
39 CONF_SYNTAX_EXT = 'syntax_ext_dict' | |
40 BLOG_TMP_DIR="blog" | |
41 | |
25 URL_REDIRECT_PREFIX = 'url_redirect_' | 42 URL_REDIRECT_PREFIX = 'url_redirect_' |
26 | 43 |
27 __commands__ = ["Blog"] | 44 |
45 class Edit(base.CommandBase): | |
46 | |
47 def __init__(self, host): | |
48 super(Edit, self).__init__(host, 'edit', use_verbose=True, help=_(u'edit an existing or new blog post')) | |
49 | |
50 def add_parser_options(self): | |
51 self.parser.add_argument("item", type=base.unicode_decoder, nargs='?', default=u'new', help=_(u"URL of the item to edit, or keyword")) | |
52 self.parser.add_argument("-T", '--title', type=base.unicode_decoder, help=_(u"Title of the item")) | |
53 self.parser.add_argument("-t", '--tag', type=base.unicode_decoder, action='append', help=_(u"tag (category) of your item")) | |
54 self.parser.add_argument("--no-comment", action='store_true', help=_(u"disable comments")) | |
55 | |
56 def getTmpFile(self, sat_conf, tmp_suff): | |
57 local_dir = config.getConfig(sat_conf, '', 'local_dir', Exception) | |
58 tmp_dir = os.path.join(local_dir, BLOG_TMP_DIR) | |
59 if not os.path.exists(tmp_dir): | |
60 try: | |
61 os.makedirs(tmp_dir) | |
62 except OSError as e: | |
63 self.disp(u"Can't create {path} directory: {reason}".format( | |
64 path=tmp_dir, reason=e), error=True) | |
65 self.host.quit(1) | |
66 | |
67 try: | |
68 return tempfile.mkstemp(suffix=tmp_suff, | |
69 prefix=time.strftime('blog_%Y-%m-%d_%H:%M:%S_'), | |
70 dir=tmp_dir, text=True) | |
71 except OSError as e: | |
72 self.disp(u"Can't create temporary file: {reason}".format(reason=e), error=True) | |
73 self.host.quit(1) | |
74 | |
75 def edit(self, sat_conf, tmp_file, tmp_file_obj, item_id=None): | |
76 """Edit the file contening the content using editor, and publish it""" | |
77 # we first calculate hash to check for modifications | |
78 import hashlib | |
79 tmp_file_obj.seek(0) | |
80 ori_hash = hashlib.sha1(tmp_file_obj.read()).digest() | |
81 tmp_file_obj.close() | |
82 | |
83 # the we launch editor | |
84 editor = config.getConfig(sat_conf, 'jp', 'editor') or os.getenv('EDITOR', 'vi') | |
85 editor_exit = subprocess.call([editor, tmp_file]) | |
86 | |
87 # we send the file if edition was a success | |
88 if editor_exit != 0: | |
89 self.disp(u"Editor exited with an error code, so temporary file has not be deleted, and blog item is not published.\nTou can find temporary file at {path}".format( | |
90 path=tmp_file), error=True) | |
91 else: | |
92 with open(tmp_file, 'rb') as f: | |
93 content = f.read() | |
94 | |
95 if len(content) == 0: | |
96 self.disp(u"Content is empty, cancelling the blog edition") | |
97 | |
98 # time to re-check the hash | |
99 elif ori_hash == hashlib.sha1(content).digest(): | |
100 self.disp(u"The content has not been modified, cancelling the blog edition") | |
101 | |
102 else: | |
103 # we can now send the blog | |
104 mb_data = { | |
105 'content_rich': content.decode('utf-8'), | |
106 'allow_comments': C.boolConst(not self.args.no_comment), | |
107 } | |
108 if item_id: | |
109 mb_data['id'] = item_id | |
110 if self.args.tag: | |
111 common.iter2dict('tag', self.args.tag, mb_data) | |
112 | |
113 if self.args.title is not None: | |
114 mb_data['title'] = self.args.title | |
115 try: | |
116 self.host.bridge.mbSend('', '', mb_data, self.profile) | |
117 except Exception as e: | |
118 self.disp(u"Error while sending your blog, the temporary file has been kept at {path}: {reason}".format( | |
119 path=tmp_file, reason=e), error=True) | |
120 self.host.quit(1) | |
121 | |
122 os.unlink(tmp_file) | |
123 | |
124 def start(self): | |
125 # we get current syntax to determine file extension | |
126 current_syntax = self.host.bridge.getParamA("Syntax", "Composition", "value", self.profile) | |
127 self.disp(u"Current syntax: {}".format(current_syntax), 1) | |
128 sat_conf = config.parseMainConf() | |
129 # if there are user defined extension, we use them | |
130 SYNTAX_EXT.update(config.getConfig(sat_conf, 'jp', CONF_SYNTAX_EXT, {})) | |
131 | |
132 # we now create a temporary file | |
133 tmp_suff = '.' + SYNTAX_EXT.get(current_syntax, SYNTAX_EXT['']) | |
134 fd, tmp_file = self.getTmpFile(sat_conf, tmp_suff) | |
135 | |
136 item_lower = self.args.item.lower() | |
137 if item_lower == 'new': | |
138 self.disp(u'Editing a new blog item', 2) | |
139 self.edit(sat_conf, tmp_file, os.fdopen(fd)) | |
140 elif item_lower == 'last': | |
141 self.disp(u'Editing last published item', 2) | |
142 try: | |
143 mb_data = self.host.bridge.mbGet('', '', 1, [], {}, self.profile)[0][0] | |
144 except Exception as e: | |
145 self.disp(u"Error while retrieving last comment: {}".format(e)) | |
146 self.host.quit(1) | |
147 | |
148 content = mb_data['content_xhtml'] | |
149 if current_syntax != 'XHTML': | |
150 content = self.host.bridge.syntaxConvert(content, 'XHTML', current_syntax, False, self.profile) | |
151 f = os.fdopen(fd, 'w+b') | |
152 f.write(content.encode('utf-8')) | |
153 f.seek(0) | |
154 self.edit(sat_conf, tmp_file, f, mb_data['id']) | |
28 | 155 |
29 | 156 |
30 class Import(base.CommandAnswering): | 157 class Import(base.CommandAnswering): |
31 def __init__(self, host): | 158 def __init__(self, host): |
32 super(Import, self).__init__(host, 'import', use_progress=True, help=_(u'import an external blog')) | 159 super(Import, self).__init__(host, 'import', use_progress=True, help=_(u'import an external blog')) |