comparison frontends/src/jp/cmd_blog.py @ 1925:53b51866747f

jp (blog/edit): HTTP(S) and XMPP URLs can now be directly used in blog/edit command
author Goffi <goffi@goffi.org>
date Thu, 24 Mar 2016 18:38:04 +0100
parents 70b1a29e1338
children 55a7328fafb6
comparison
equal deleted inserted replaced
1924:70b1a29e1338 1925:53b51866747f
247 unicode_dump = json.dumps(mb_data, ensure_ascii=False, indent=4, separators=(',', ': '), sort_keys=True) 247 unicode_dump = json.dumps(mb_data, ensure_ascii=False, indent=4, separators=(',', ': '), sort_keys=True)
248 f.write(unicode_dump.encode('utf-8')) 248 f.write(unicode_dump.encode('utf-8'))
249 249
250 return mb_data, meta_file_path 250 return mb_data, meta_file_path
251 251
252 def edit(self, sat_conf, content_file_path, content_file_obj, mb_data=None): 252 def edit(self, sat_conf, content_file_path, content_file_obj,
253 pubsub_service, pubsub_node, mb_data=None):
253 """Edit the file contening the content using editor, and publish it""" 254 """Edit the file contening the content using editor, and publish it"""
254 item_ori_mb_data = mb_data 255 item_ori_mb_data = mb_data
255 # we first create metadata file 256 # we first create metadata file
256 meta_ori, meta_file_path = self.buildMetadataFile(content_file_path, item_ori_mb_data) 257 meta_ori, meta_file_path = self.buildMetadataFile(content_file_path, item_ori_mb_data)
257 258
327 328
328 if item_ori_mb_data is not None: 329 if item_ori_mb_data is not None:
329 mb_data['id'] = item_ori_mb_data['id'] 330 mb_data['id'] = item_ori_mb_data['id']
330 331
331 try: 332 try:
332 self.host.bridge.mbSend('', '', mb_data, self.profile) 333 self.host.bridge.mbSend(pubsub_service, pubsub_node, mb_data, self.profile)
333 except Exception as e: 334 except Exception as e:
334 self.disp(u"Error while sending your blog, the temporary files have been kept at {content_path} and {meta_path}: {reason}".format( 335 self.disp(u"Error while sending your blog, the temporary files have been kept at {content_path} and {meta_path}: {reason}".format(
335 content_path=content_file_path, meta_path=meta_file_path, reason=e), error=True) 336 content_path=content_file_path, meta_path=meta_file_path, reason=e), error=True)
336 self.host.quit(1) 337 self.host.quit(1)
337 else: 338 else:
339 340
340 self.secureUnlink(sat_conf, content_file_path) 341 self.secureUnlink(sat_conf, content_file_path)
341 self.secureUnlink(sat_conf, meta_file_path) 342 self.secureUnlink(sat_conf, meta_file_path)
342 343
343 def start(self): 344 def start(self):
344 item_lower = self.args.item.lower() 345 command = self.args.item.lower()
345 sat_conf = config.parseMainConf() 346 sat_conf = config.parseMainConf()
346 # if there are user defined extension, we use them 347 # if there are user defined extension, we use them
347 SYNTAX_EXT.update(config.getConfig(sat_conf, 'jp', CONF_SYNTAX_EXT, {})) 348 SYNTAX_EXT.update(config.getConfig(sat_conf, 'jp', CONF_SYNTAX_EXT, {}))
348 current_syntax = None 349 current_syntax = None
349 350 pubsub_service = pubsub_node = ''
350 if item_lower in ('new', 'last'): 351 pubsub_item = None
352
353 if command not in ('new', 'last', 'current'):
354 # we have probably an URL, we try to parse it
355 import urlparse
356 url = self.args.item
357 parsed_url = urlparse.urlsplit(url)
358 if parsed_url.scheme.startswith('http'):
359 self.disp(u"{} URL found, trying to find associated xmpp: URI".format(parsed_url.scheme.upper()),1)
360 # HTTP URL, we try to find xmpp: links
361 try:
362 from lxml import etree
363 except ImportError:
364 self.disp(u"lxml module must be installed to use http(s) scheme, please install it with \"pip install lxml\"", error=True)
365 self.host.quit(1)
366 parser = etree.HTMLParser()
367 root = etree.parse(url, parser)
368 links = root.xpath("//link[@rel='alternate' and starts-with(@href, 'xmpp:')]")
369 if not links:
370 self.disp(u'Could not find alternate "xmpp:" URI, can\'t find associated XMPP PubSub node/item', error=True)
371 self.host.quit(1)
372 url = links[0].get('href')
373 parsed_url = urlparse.urlsplit(url)
374
375 if parsed_url.scheme == 'xmpp':
376 self.disp(u"XMPP URI used: {}".format(url),2)
377 # XXX: if we have not xmpp: URI here, we'll take the data as a file path
378 pubsub_service = parsed_url.path
379 pubsub_data = urlparse.parse_qs(parsed_url.query)
380 try:
381 pubsub_node = pubsub_data['node'][0]
382 except KeyError:
383 self.disp(u'No node found in xmpp: URI, can\'t retrieve item', error=True)
384 self.host.quit(1)
385 pubsub_item = pubsub_data.get('item',[None])[0]
386 if pubsub_item is not None:
387 command = 'edit' # XXX: edit command is only used internaly, it similar to last, but with the item given in the URL
388 else:
389 command = 'new'
390
391 if command in ('new', 'last', 'edit'):
351 # we get current syntax to determine file extension 392 # we get current syntax to determine file extension
352 current_syntax = self.host.bridge.getParamA("Syntax", "Composition", "value", self.profile) 393 current_syntax = self.host.bridge.getParamA("Syntax", "Composition", "value", self.profile)
353 # we now create a temporary file 394 # we now create a temporary file
354 tmp_suff = '.' + SYNTAX_EXT.get(current_syntax, SYNTAX_EXT['']) 395 tmp_suff = '.' + SYNTAX_EXT.get(current_syntax, SYNTAX_EXT[''])
355 content_file_obj, content_file_path = self.getTmpFile(sat_conf, tmp_suff) 396 content_file_obj, content_file_path = self.getTmpFile(sat_conf, tmp_suff)
356 if item_lower == 'new': 397 if command == 'new':
357 self.disp(u'Editing a new blog item', 2) 398 self.disp(u'Editing a new blog item', 2)
358 mb_data = None 399 mb_data = None
359 elif item_lower == 'last': 400 elif command in ('last', 'edit'):
360 self.disp(u'Editing last published item', 2) 401 self.disp(u'Editing requested published item', 2)
361 try: 402 try:
362 mb_data = self.host.bridge.mbGet('', '', 1, [], {}, self.profile)[0][0] 403 items_ids = [pubsub_item] if pubsub_item is not None else []
404 mb_data = self.host.bridge.mbGet(pubsub_service, pubsub_node, 1, items_ids, {}, self.profile)[0][0]
363 except Exception as e: 405 except Exception as e:
364 self.disp(u"Error while retrieving last item: {}".format(e)) 406 self.disp(u"Error while retrieving last item: {}".format(e))
365 self.host.quit(1) 407 self.host.quit(1)
366 408
367 content = mb_data['content_xhtml'] 409 content = mb_data['content_xhtml']
369 content = self.host.bridge.syntaxConvert(content, 'XHTML', current_syntax, False, self.profile) 411 content = self.host.bridge.syntaxConvert(content, 'XHTML', current_syntax, False, self.profile)
370 content_file_obj.write(content.encode('utf-8')) 412 content_file_obj.write(content.encode('utf-8'))
371 content_file_obj.seek(0) 413 content_file_obj.seek(0)
372 else: 414 else:
373 mb_data = None 415 mb_data = None
374 if item_lower == 'current': 416 if command == 'current':
375 # use wants to continue current draft 417 # use wants to continue current draft
376 content_file_path = self.getCurrentFile(sat_conf, self.profile) 418 content_file_path = self.getCurrentFile(sat_conf, self.profile)
377 self.disp(u'Continuing edition of current draft', 2) 419 self.disp(u'Continuing edition of current draft', 2)
378 else: 420 else:
379 # for now we taxe the item as a file path 421 # we consider the item as a file path
380 content_file_path = os.path.expanduser(self.args.item) 422 content_file_path = os.path.expanduser(self.args.item)
381 content_file_obj = open(content_file_path, 'r+b') 423 content_file_obj = open(content_file_path, 'r+b')
382 current_syntax = self.guessSyntaxFromPath(sat_conf, content_file_path) 424 current_syntax = self.guessSyntaxFromPath(sat_conf, content_file_path)
383 425
384 self.disp(u"Syntax used: {}".format(current_syntax), 1) 426 self.disp(u"Syntax used: {}".format(current_syntax), 1)
385 self.edit(sat_conf, content_file_path, content_file_obj, mb_data=mb_data) 427 self.edit(sat_conf, content_file_path, content_file_obj, pubsub_service, pubsub_node, mb_data=mb_data)
386 428
387 429
388 class Preview(base.CommandBase, BlogCommon): 430 class Preview(base.CommandBase, BlogCommon):
389 431
390 def __init__(self, host): 432 def __init__(self, host):