comparison frontends/src/jp/cmd_blog.py @ 2458:4841ad6a5db4

jp (blog): added "set" command to publish content from stdin without editing
author Goffi <goffi@goffi.org>
date Tue, 12 Dec 2017 00:12:44 +0100
parents 8b37a62336c3
children 0046283a285d
comparison
equal deleted inserted replaced
2457:49aa1e3a90b8 2458:4841ad6a5db4
25 from sat.tools.common.ansi import ANSI as A 25 from sat.tools.common.ansi import ANSI as A
26 from sat.tools.common import data_objects 26 from sat.tools.common import data_objects
27 from sat.tools.common import uri 27 from sat.tools.common import uri
28 from sat.tools import config 28 from sat.tools import config
29 from ConfigParser import NoSectionError, NoOptionError 29 from ConfigParser import NoSectionError, NoOptionError
30 from functools import partial
30 import json 31 import json
31 import sys 32 import sys
32 import os.path 33 import os.path
33 import os 34 import os
34 import time 35 import time
35 import tempfile 36 import tempfile
36 import subprocess 37 import subprocess
38 import codecs
37 from sat.tools.common import data_format 39 from sat.tools.common import data_format
38 40
39 __commands__ = ["Blog"] 41 __commands__ = ["Blog"]
40 42
41 SYNTAX_XHTML = u'xhtml' 43 SYNTAX_XHTML = u'xhtml'
97 if k and ext == v: 99 if k and ext == v:
98 return k 100 return k
99 101
100 # if not found, we use current syntax 102 # if not found, we use current syntax
101 return self.host.bridge.getParamA("Syntax", "Composition", "value", self.profile) 103 return self.host.bridge.getParamA("Syntax", "Composition", "value", self.profile)
104
105
106 class BlogPublishCommon(object):
107 """handle common option for publising commands (Set and Edit)"""
108
109 def add_parser_options(self):
110 self.addServiceNodeArgs()
111 self.parser.add_argument("-T", '--title', type=base.unicode_decoder, help=_(u"title of the item"))
112 self.parser.add_argument("-t", '--tag', type=base.unicode_decoder, action='append', help=_(u"tag (category) of your item"))
113 self.parser.add_argument("-C", "--comments", action='store_true', help=_(u"enable comments"))
114 self.parser.add_argument("-S", '--syntax', type=base.unicode_decoder, help=_(u"syntax to use (default: get profile's default syntax)"))
115
116 def setMbDataContent(self, content, mb_data):
117 if self.args.syntax is None:
118 # default syntax has been used
119 mb_data['content_rich'] = content
120 elif self.current_syntax == SYNTAX_XHTML:
121 mb_data['content_xhtml'] = content
122 else:
123 mb_data['content_xhtml'] = self.host.bridge.syntaxConvert(content, self.current_syntax, SYNTAX_XHTML, False, self.profile)
124
125 def setMbDataFromArgs(self, mb_data):
126 """set microblog metadata according to command line options
127
128 if metadata already exist, it will be overwritten
129 """
130 mb_data['allow_comments'] = C.boolConst(self.args.comments)
131 if self.args.tag:
132 data_format.iter2dict('tag', self.args.tag, mb_data, check_conflict=False)
133 if self.args.title is not None:
134 mb_data['title'] = self.args.title
135
136
137 class Set(base.CommandBase, BlogCommon, BlogPublishCommon):
138
139 def __init__(self, host):
140 base.CommandBase.__init__(self, host, 'set', help=_(u'publish a new blog item or update an existing one'))
141 BlogCommon.__init__(self, self.host)
142 BlogPublishCommon.__init__(self)
143 self.need_loop=True
144
145 def add_parser_options(self):
146 BlogPublishCommon.add_parser_options(self)
147 self.parser.add_argument("item", type=base.unicode_decoder, nargs='?', default=None, help=_(u"id of the item to publish"))
148
149 def mbSendCb(self):
150 self.disp(u"Item published")
151 self.host.quit(C.EXIT_OK)
152
153 def start(self):
154 common.checkURI(self.args)
155 self.pubsub_item = self.args.item
156 mb_data = {}
157 self.setMbDataFromArgs(mb_data)
158 content = codecs.getreader('utf-8')(sys.stdin).read()
159 self.setMbDataContent(content, mb_data)
160
161 self.host.bridge.mbSend(
162 self.args.service,
163 self.args.node,
164 mb_data,
165 self.profile,
166 callback=self.exitCb,
167 errback=partial(self.errback,
168 msg=_(u"can't send item: {}"),
169 exit_code=C.EXIT_BRIDGE_ERRBACK))
102 170
103 171
104 class Get(base.CommandBase, BlogCommon): 172 class Get(base.CommandBase, BlogCommon):
105 TEMPLATE = u"blog/articles.html" 173 TEMPLATE = u"blog/articles.html"
106 174
281 self.profile, 349 self.profile,
282 callback=self.mbGetCb, 350 callback=self.mbGetCb,
283 errback=self.mbGetEb) 351 errback=self.mbGetEb)
284 352
285 353
286 class Edit(base.CommandBase, BlogCommon, common.BaseEdit): 354 class Edit(base.CommandBase, BlogCommon, BlogPublishCommon, common.BaseEdit):
287 355
288 def __init__(self, host): 356 def __init__(self, host):
289 base.CommandBase.__init__(self, host, 'edit', use_verbose=True, help=_(u'edit an existing or new blog post')) 357 base.CommandBase.__init__(self, host, 'edit', use_verbose=True, help=_(u'edit an existing or new blog post'))
290 BlogCommon.__init__(self, self.host) 358 BlogCommon.__init__(self, self.host)
359 BlogPublishCommon.__init__(self)
291 common.BaseEdit.__init__(self, self.host, BLOG_TMP_DIR, use_metadata=True) 360 common.BaseEdit.__init__(self, self.host, BLOG_TMP_DIR, use_metadata=True)
292 361
293 def add_parser_options(self): 362 def add_parser_options(self):
294 self.addServiceNodeArgs() 363 BlogPublishCommon.add_parser_options(self)
364 self.parser.add_argument("-P", "--preview", action="store_true", help=_(u"launch a blog preview in parallel"))
295 self.parser.add_argument("item", type=base.unicode_decoder, nargs='?', default=u'new', help=_(u"URL of the item to edit, or keyword")) 365 self.parser.add_argument("item", type=base.unicode_decoder, nargs='?', default=u'new', help=_(u"URL of the item to edit, or keyword"))
296 self.parser.add_argument("-P", "--preview", action="store_true", help=_(u"launch a blog preview in parallel"))
297 self.parser.add_argument("-T", '--title', type=base.unicode_decoder, help=_(u"title of the item"))
298 self.parser.add_argument("-t", '--tag', type=base.unicode_decoder, action='append', help=_(u"tag (category) of your item"))
299 self.parser.add_argument("--no-comment", action='store_true', help=_(u"disable comments"))
300 self.parser.add_argument("-S", '--syntax', type=base.unicode_decoder, help=_(u"syntax to use (default: get profile's default syntax)"))
301 common.BaseEdit.add_parser_options(self) 366 common.BaseEdit.add_parser_options(self)
302 367
303 def buildMetadataFile(self, content_file_path, mb_data=None): 368 def buildMetadataFile(self, content_file_path, mb_data=None):
304 """Build a metadata file using json 369 """Build a metadata file using json
305 370
329 try: 394 try:
330 del mb_data[key] 395 del mb_data[key]
331 except KeyError: 396 except KeyError:
332 pass 397 pass
333 # and override metadata with command-line arguments 398 # and override metadata with command-line arguments
334 mb_data['allow_comments'] = C.boolConst(not self.args.no_comment) 399 self.setMbDataFromArgs(mb_data)
335 if self.args.tag:
336 data_format.iter2dict('tag', self.args.tag, mb_data, check_conflict=False)
337 if self.args.title is not None:
338 mb_data['title'] = self.args.title
339 400
340 # then we create the file and write metadata there, as JSON dict 401 # then we create the file and write metadata there, as JSON dict
341 # XXX: if we port jp one day on Windows, O_BINARY may need to be added here 402 # XXX: if we port jp one day on Windows, O_BINARY may need to be added here
342 with os.fdopen(os.open(meta_file_path, os.O_RDWR | os.O_CREAT | os.O_TRUNC,0o600), 'w+b') as f: 403 with os.fdopen(os.open(meta_file_path, os.O_RDWR | os.O_CREAT | os.O_TRUNC,0o600), 'w+b') as f:
343 # we need to use an intermediate unicode buffer to write to the file unicode without escaping characters 404 # we need to use an intermediate unicode buffer to write to the file unicode without escaping characters
362 423
363 # we launch editor 424 # we launch editor
364 self.runEditor("blog_editor_args", content_file_path, content_file_obj, meta_file_path=meta_file_path, meta_ori=meta_ori) 425 self.runEditor("blog_editor_args", content_file_path, content_file_obj, meta_file_path=meta_file_path, meta_ori=meta_ori)
365 426
366 def publish(self, content, mb_data): 427 def publish(self, content, mb_data):
367 if self.args.syntax is None: 428 self.setMbDataContent(content, mb_data)
368 # default syntax has been used
369 mb_data['content_rich'] = content
370 elif self.current_syntax == SYNTAX_XHTML:
371 mb_data['content_xhtml'] = content
372 else:
373 mb_data['content_xhtml'] = self.host.bridge.syntaxConvert(content, self.current_syntax, SYNTAX_XHTML, False, self.profile)
374 429
375 if self.pubsub_item is not None: 430 if self.pubsub_item is not None:
376 mb_data['id'] = self.pubsub_item 431 mb_data['id'] = self.pubsub_item
377 432
378 self.host.bridge.mbSend(self.pubsub_service, self.pubsub_node, mb_data, self.profile) 433 self.host.bridge.mbSend(self.pubsub_service, self.pubsub_node, mb_data, self.profile)
379 self.disp(u"Blog item published") 434 self.disp(u"Blog item published")
435
380 436
381 def getTmpSuff(self): 437 def getTmpSuff(self):
382 # we get current syntax to determine file extension 438 # we get current syntax to determine file extension
383 if self.current_syntax is None: 439 if self.current_syntax is None:
384 self.current_syntax = self.host.bridge.getParamA("Syntax", "Composition", "value", self.profile) 440 self.current_syntax = self.host.bridge.getParamA("Syntax", "Composition", "value", self.profile)
646 self.host.bridge.blogImport(self.args.importer, self.args.location, options, self.args.service, self.args.node, self.profile, 702 self.host.bridge.blogImport(self.args.importer, self.args.location, options, self.args.service, self.args.node, self.profile,
647 callback=gotId, errback=self.error) 703 callback=gotId, errback=self.error)
648 704
649 705
650 class Blog(base.CommandBase): 706 class Blog(base.CommandBase):
651 subcommands = (Get, Edit, Preview, Import) 707 subcommands = (Set, Get, Edit, Preview, Import)
652 708
653 def __init__(self, host): 709 def __init__(self, host):
654 super(Blog, self).__init__(host, 'blog', use_profile=False, help=_('blog/microblog management')) 710 super(Blog, self).__init__(host, 'blog', use_profile=False, help=_('blog/microblog management'))