Mercurial > libervia-backend
comparison sat_frontends/jp/cmd_blog.py @ 3568:04283582966f
core, frontends: fix invalid translatable strings.
Some f-strings where used in translatable text, this has been fixed by using explicit
`format()` call (using a script based on `tokenize`).
As tokenize messes with spaces, a reformating tool (`black`) has been applied to some
files afterwards.
author | Goffi <goffi@goffi.org> |
---|---|
date | Mon, 14 Jun 2021 18:35:12 +0200 |
parents | 62f490eff51c |
children | 5f65f4e9f8cb 82e616b70a2a |
comparison
equal
deleted
inserted
replaced
3567:a240748ed686 | 3568:04283582966f |
---|---|
98 if ext: | 98 if ext: |
99 for k, v in SYNTAX_EXT.items(): | 99 for k, v in SYNTAX_EXT.items(): |
100 if k and ext == v: | 100 if k and ext == v: |
101 return k | 101 return k |
102 | 102 |
103 # if not found, we use current syntax | 103 # if not found, we use current syntax |
104 return await host.bridge.getParamA("Syntax", "Composition", "value", host.profile) | 104 return await host.bridge.getParamA("Syntax", "Composition", "value", host.profile) |
105 | 105 |
106 | 106 |
107 class BlogPublishCommon(object): | 107 class BlogPublishCommon(object): |
108 """handle common option for publising commands (Set and Edit)""" | 108 """handle common option for publising commands (Set and Edit)""" |
123 try: | 123 try: |
124 syntax = await self.host.bridge.syntaxGet(self.args.syntax) | 124 syntax = await self.host.bridge.syntaxGet(self.args.syntax) |
125 self.current_syntax = self.args.syntax = syntax | 125 self.current_syntax = self.args.syntax = syntax |
126 except Exception as e: | 126 except Exception as e: |
127 if e.classname == "NotFound": | 127 if e.classname == "NotFound": |
128 self.parser.error(_(f"unknown syntax requested ({self.args.syntax})")) | 128 self.parser.error( |
129 _("unknown syntax requested ({syntax})").format( | |
130 syntax=self.args.syntax | |
131 ) | |
132 ) | |
129 else: | 133 else: |
130 raise e | 134 raise e |
131 return self.args.syntax | 135 return self.args.syntax |
132 | 136 |
133 def add_parser_options(self): | 137 def add_parser_options(self): |
134 self.parser.add_argument( | 138 self.parser.add_argument("-T", "--title", help=_("title of the item")) |
135 "-T", "--title", help=_("title of the item") | |
136 ) | |
137 self.parser.add_argument( | 139 self.parser.add_argument( |
138 "-t", | 140 "-t", |
139 "--tag", | 141 "--tag", |
140 action="append", | 142 action="append", |
141 help=_("tag (category) of your item"), | 143 help=_("tag (category) of your item"), |
146 help=_("language of the item (ISO 639 code)"), | 148 help=_("language of the item (ISO 639 code)"), |
147 ) | 149 ) |
148 | 150 |
149 comments_group = self.parser.add_mutually_exclusive_group() | 151 comments_group = self.parser.add_mutually_exclusive_group() |
150 comments_group.add_argument( | 152 comments_group.add_argument( |
151 "-C", "--comments", action="store_const", const=True, dest="comments", | 153 "-C", |
152 help=_("enable comments (default: comments not enabled except if they " | 154 "--comments", |
153 "already exist)") | 155 action="store_const", |
156 const=True, | |
157 dest="comments", | |
158 help=_( | |
159 "enable comments (default: comments not enabled except if they " | |
160 "already exist)" | |
161 ), | |
154 ) | 162 ) |
155 comments_group.add_argument( | 163 comments_group.add_argument( |
156 "--no-comments", action="store_const", const=False, dest="comments", | 164 "--no-comments", |
157 help=_("disable comments (will remove comments node if it exist)") | 165 action="store_const", |
166 const=False, | |
167 dest="comments", | |
168 help=_("disable comments (will remove comments node if it exist)"), | |
158 ) | 169 ) |
159 | 170 |
160 self.parser.add_argument( | 171 self.parser.add_argument( |
161 "-S", | 172 "-S", |
162 "--syntax", | 173 "--syntax", |
180 if metadata already exist, it will be overwritten | 191 if metadata already exist, it will be overwritten |
181 """ | 192 """ |
182 if self.args.comments is not None: | 193 if self.args.comments is not None: |
183 mb_data["allow_comments"] = self.args.comments | 194 mb_data["allow_comments"] = self.args.comments |
184 if self.args.tag: | 195 if self.args.tag: |
185 mb_data['tags'] = self.args.tag | 196 mb_data["tags"] = self.args.tag |
186 if self.args.title is not None: | 197 if self.args.title is not None: |
187 mb_data["title"] = self.args.title | 198 mb_data["title"] = self.args.title |
188 if self.args.language is not None: | 199 if self.args.language is not None: |
189 mb_data["language"] = self.args.language | 200 mb_data["language"] = self.args.language |
190 | 201 |
220 self.args.node, | 231 self.args.node, |
221 data_format.serialise(mb_data), | 232 data_format.serialise(mb_data), |
222 self.profile, | 233 self.profile, |
223 ) | 234 ) |
224 except Exception as e: | 235 except Exception as e: |
225 self.disp( | 236 self.disp(f"can't send item: {e}", error=True) |
226 f"can't send item: {e}", error=True | |
227 ) | |
228 self.host.quit(C.EXIT_BRIDGE_ERRBACK) | 237 self.host.quit(C.EXIT_BRIDGE_ERRBACK) |
229 else: | 238 else: |
230 self.disp("Item published") | 239 self.disp("Item published") |
231 self.host.quit(C.EXIT_OK) | 240 self.host.quit(C.EXIT_OK) |
232 | 241 |
259 ) | 268 ) |
260 # TODO: add MAM filters | 269 # TODO: add MAM filters |
261 | 270 |
262 def template_data_mapping(self, data): | 271 def template_data_mapping(self, data): |
263 items, blog_items = data | 272 items, blog_items = data |
264 blog_items['items'] = items | 273 blog_items["items"] = items |
265 return {"blog_items": blog_items} | 274 return {"blog_items": blog_items} |
266 | 275 |
267 def format_comments(self, item, keys): | 276 def format_comments(self, item, keys): |
268 lines = [] | 277 lines = [] |
269 for data in item.get('comments', []): | 278 for data in item.get("comments", []): |
270 lines.append(data["uri"]) | 279 lines.append(data["uri"]) |
271 for k in ("node", "service"): | 280 for k in ("node", "service"): |
272 if OUTPUT_OPT_NO_HEADER in self.args.output_opts: | 281 if OUTPUT_OPT_NO_HEADER in self.args.output_opts: |
273 header = "" | 282 header = "" |
274 else: | 283 else: |
275 header = f"{C.A_HEADER}comments_{k}: {A.RESET}" | 284 header = f"{C.A_HEADER}comments_{k}: {A.RESET}" |
276 lines.append(header + data[k]) | 285 lines.append(header + data[k]) |
277 return "\n".join(lines) | 286 return "\n".join(lines) |
278 | 287 |
279 def format_tags(self, item, keys): | 288 def format_tags(self, item, keys): |
280 tags = item.pop('tags', []) | 289 tags = item.pop("tags", []) |
281 return ", ".join(tags) | 290 return ", ".join(tags) |
282 | 291 |
283 def format_updated(self, item, keys): | 292 def format_updated(self, item, keys): |
284 return self.format_time(item["updated"]) | 293 return self.format_time(item["updated"]) |
285 | 294 |
357 ) | 366 ) |
358 value = k_cb[k](item, keys) if k in k_cb else item[k] | 367 value = k_cb[k](item, keys) if k in k_cb else item[k] |
359 if isinstance(value, bool): | 368 if isinstance(value, bool): |
360 value = str(value).lower() | 369 value = str(value).lower() |
361 self.disp(header + value) | 370 self.disp(header + value) |
362 # we want a separation line after each item but the last one | 371 # we want a separation line after each item but the last one |
363 if idx < len(items) - 1: | 372 if idx < len(items) - 1: |
364 print("") | 373 print("") |
365 | 374 |
366 def format_time(self, timestamp): | 375 def format_time(self, timestamp): |
367 """return formatted date for timestamp | 376 """return formatted date for timestamp |
391 author = item["author"] | 400 author = item["author"] |
392 published, updated = item["published"], item.get("updated") | 401 published, updated = item["published"], item.get("updated") |
393 else: | 402 else: |
394 author = published = updated = None | 403 author = published = updated = None |
395 if verbosity > 1: | 404 if verbosity > 1: |
396 tags = item.pop('tags', []) | 405 tags = item.pop("tags", []) |
397 else: | 406 else: |
398 tags = None | 407 tags = None |
399 content = item.get("content") | 408 content = item.get("content") |
400 | 409 |
401 if title: | 410 if title: |
426 self.args.service, | 435 self.args.service, |
427 self.args.node, | 436 self.args.node, |
428 self.args.max, | 437 self.args.max, |
429 self.args.items, | 438 self.args.items, |
430 self.getPubsubExtra(), | 439 self.getPubsubExtra(), |
431 self.profile | 440 self.profile, |
432 ) | 441 ) |
433 ) | 442 ) |
434 except Exception as e: | 443 except Exception as e: |
435 self.disp(f"can't get blog items: {e}", error=True) | 444 self.disp(f"can't get blog items: {e}", error=True) |
436 self.host.quit(C.EXIT_BRIDGE_ERRBACK) | 445 self.host.quit(C.EXIT_BRIDGE_ERRBACK) |
437 else: | 446 else: |
438 items = mb_data.pop('items') | 447 items = mb_data.pop("items") |
439 await self.output((items, mb_data)) | 448 await self.output((items, mb_data)) |
440 self.host.quit(C.EXIT_OK) | 449 self.host.quit(C.EXIT_OK) |
441 | 450 |
442 | 451 |
443 class Edit(base.CommandBase, BlogPublishCommon, common.BaseEdit): | 452 class Edit(base.CommandBase, BlogPublishCommon, common.BaseEdit): |
481 and path to temporary metadata file | 490 and path to temporary metadata file |
482 """ | 491 """ |
483 # we first construct metadata from edited item ones and CLI argumments | 492 # we first construct metadata from edited item ones and CLI argumments |
484 # or re-use the existing one if it exists | 493 # or re-use the existing one if it exists |
485 meta_file_path = content_file_path.with_name( | 494 meta_file_path = content_file_path.with_name( |
486 content_file_path.stem + common.METADATA_SUFF) | 495 content_file_path.stem + common.METADATA_SUFF |
496 ) | |
487 if meta_file_path.exists(): | 497 if meta_file_path.exists(): |
488 self.disp("Metadata file already exists, we re-use it") | 498 self.disp("Metadata file already exists, we re-use it") |
489 try: | 499 try: |
490 with meta_file_path.open("rb") as f: | 500 with meta_file_path.open("rb") as f: |
491 mb_data = json.load(f) | 501 mb_data = json.load(f) |
497 ) | 507 ) |
498 self.host.quit(1) | 508 self.host.quit(1) |
499 else: | 509 else: |
500 mb_data = {} if mb_data is None else mb_data.copy() | 510 mb_data = {} if mb_data is None else mb_data.copy() |
501 | 511 |
502 # in all cases, we want to remove unwanted keys | 512 # in all cases, we want to remove unwanted keys |
503 for key in KEY_TO_REMOVE_METADATA: | 513 for key in KEY_TO_REMOVE_METADATA: |
504 try: | 514 try: |
505 del mb_data[key] | 515 del mb_data[key] |
506 except KeyError: | 516 except KeyError: |
507 pass | 517 pass |
508 # and override metadata with command-line arguments | 518 # and override metadata with command-line arguments |
509 self.setMbDataFromArgs(mb_data) | 519 self.setMbDataFromArgs(mb_data) |
510 | 520 |
511 if self.args.no_publish: | 521 if self.args.no_publish: |
512 mb_data["publish"] = False | 522 mb_data["publish"] = False |
513 | 523 |
514 # then we create the file and write metadata there, as JSON dict | 524 # then we create the file and write metadata there, as JSON dict |
515 # XXX: if we port jp one day on Windows, O_BINARY may need to be added here | 525 # XXX: if we port jp one day on Windows, O_BINARY may need to be added here |
516 with os.fdopen( | 526 with os.fdopen( |
517 os.open(meta_file_path, os.O_RDWR | os.O_CREAT | os.O_TRUNC, 0o600), "w+b" | 527 os.open(meta_file_path, os.O_RDWR | os.O_CREAT | os.O_TRUNC, 0o600), "w+b" |
518 ) as f: | 528 ) as f: |
519 # we need to use an intermediate unicode buffer to write to the file | 529 # we need to use an intermediate unicode buffer to write to the file |
520 # unicode without escaping characters | 530 # unicode without escaping characters |
554 stdout=DEVNULL, | 564 stdout=DEVNULL, |
555 stderr=DEVNULL, | 565 stderr=DEVNULL, |
556 ) | 566 ) |
557 ) | 567 ) |
558 | 568 |
559 # we launch editor | 569 # we launch editor |
560 coroutines.append( | 570 coroutines.append( |
561 self.runEditor( | 571 self.runEditor( |
562 "blog_editor_args", | 572 "blog_editor_args", |
563 content_file_path, | 573 content_file_path, |
564 content_file_obj, | 574 content_file_obj, |
588 | 598 |
589 async def getItemData(self, service, node, item): | 599 async def getItemData(self, service, node, item): |
590 items = [item] if item else [] | 600 items = [item] if item else [] |
591 | 601 |
592 mb_data = data_format.deserialise( | 602 mb_data = data_format.deserialise( |
593 await self.host.bridge.mbGet( | 603 await self.host.bridge.mbGet(service, node, 1, items, {}, self.profile) |
594 service, node, 1, items, {}, self.profile | 604 ) |
595 ) | 605 item = mb_data["items"][0] |
596 ) | |
597 item = mb_data['items'][0] | |
598 | 606 |
599 try: | 607 try: |
600 content = item["content_xhtml"] | 608 content = item["content_xhtml"] |
601 except KeyError: | 609 except KeyError: |
602 content = item["content"] | 610 content = item["content"] |
610 content, SYNTAX_XHTML, self.current_syntax, False, self.profile | 618 content, SYNTAX_XHTML, self.current_syntax, False, self.profile |
611 ) | 619 ) |
612 | 620 |
613 if content and self.current_syntax == SYNTAX_XHTML: | 621 if content and self.current_syntax == SYNTAX_XHTML: |
614 content = content.strip() | 622 content = content.strip() |
615 if not content.startswith('<div>'): | 623 if not content.startswith("<div>"): |
616 content = '<div>' + content + '</div>' | 624 content = "<div>" + content + "</div>" |
617 try: | 625 try: |
618 from lxml import etree | 626 from lxml import etree |
619 except ImportError: | 627 except ImportError: |
620 self.disp(_("You need lxml to edit pretty XHTML")) | 628 self.disp(_("You need lxml to edit pretty XHTML")) |
621 else: | 629 else: |
628 async def start(self): | 636 async def start(self): |
629 # if there are user defined extension, we use them | 637 # if there are user defined extension, we use them |
630 SYNTAX_EXT.update(config.getConfig(self.sat_conf, "jp", CONF_SYNTAX_EXT, {})) | 638 SYNTAX_EXT.update(config.getConfig(self.sat_conf, "jp", CONF_SYNTAX_EXT, {})) |
631 self.current_syntax = await self.get_current_syntax() | 639 self.current_syntax = await self.get_current_syntax() |
632 | 640 |
633 (self.pubsub_service, self.pubsub_node, self.pubsub_item, content_file_path, | 641 ( |
634 content_file_obj, mb_data,) = await self.getItemPath() | 642 self.pubsub_service, |
643 self.pubsub_node, | |
644 self.pubsub_item, | |
645 content_file_path, | |
646 content_file_obj, | |
647 mb_data, | |
648 ) = await self.getItemPath() | |
635 | 649 |
636 await self.edit(content_file_path, content_file_obj, mb_data=mb_data) | 650 await self.edit(content_file_path, content_file_obj, mb_data=mb_data) |
637 self.host.quit() | 651 self.host.quit() |
638 | 652 |
639 | 653 |
640 class Rename(base.CommandBase): | 654 class Rename(base.CommandBase): |
641 | |
642 def __init__(self, host): | 655 def __init__(self, host): |
643 base.CommandBase.__init__( | 656 base.CommandBase.__init__( |
644 self, | 657 self, |
645 host, | 658 host, |
646 "rename", | 659 "rename", |
648 pubsub_flags={C.SINGLE_ITEM}, | 661 pubsub_flags={C.SINGLE_ITEM}, |
649 help=_("rename an blog item"), | 662 help=_("rename an blog item"), |
650 ) | 663 ) |
651 | 664 |
652 def add_parser_options(self): | 665 def add_parser_options(self): |
653 self.parser.add_argument( | 666 self.parser.add_argument("new_id", help=_("new item id to use")) |
654 "new_id", | |
655 help=_("new item id to use") | |
656 ) | |
657 | 667 |
658 async def start(self): | 668 async def start(self): |
659 try: | 669 try: |
660 await self.host.bridge.mbRename( | 670 await self.host.bridge.mbRename( |
661 self.args.service, | 671 self.args.service, |
663 self.args.item, | 673 self.args.item, |
664 self.args.new_id, | 674 self.args.new_id, |
665 self.profile, | 675 self.profile, |
666 ) | 676 ) |
667 except Exception as e: | 677 except Exception as e: |
668 self.disp( | 678 self.disp(f"can't rename item: {e}", error=True) |
669 f"can't rename item: {e}", error=True | |
670 ) | |
671 self.host.quit(C.EXIT_BRIDGE_ERRBACK) | 679 self.host.quit(C.EXIT_BRIDGE_ERRBACK) |
672 else: | 680 else: |
673 self.disp("Item renamed") | 681 self.disp("Item renamed") |
674 self.host.quit(C.EXIT_OK) | 682 self.host.quit(C.EXIT_OK) |
683 | |
675 | 684 |
676 class Preview(base.CommandBase, common.BaseEdit): | 685 class Preview(base.CommandBase, common.BaseEdit): |
677 # TODO: need to be rewritten with template output | 686 # TODO: need to be rewritten with template output |
678 | 687 |
679 def __init__(self, host): | 688 def __init__(self, host): |
733 ) | 742 ) |
734 | 743 |
735 xhtml = ( | 744 xhtml = ( |
736 f'<html xmlns="http://www.w3.org/1999/xhtml">' | 745 f'<html xmlns="http://www.w3.org/1999/xhtml">' |
737 f'<head><meta http-equiv="Content-Type" content="text/html;charset=utf-8" />' | 746 f'<head><meta http-equiv="Content-Type" content="text/html;charset=utf-8" />' |
738 f'</head>' | 747 f"</head>" |
739 f'<body>{content}</body>' | 748 f"<body>{content}</body>" |
740 f'</html>' | 749 f"</html>" |
741 ) | 750 ) |
742 | 751 |
743 with open(self.preview_file_path, "wb") as f: | 752 with open(self.preview_file_path, "wb") as f: |
744 f.write(xhtml.encode("utf-8")) | 753 f.write(xhtml.encode("utf-8")) |
745 | 754 |
789 if self.update_cb_cmd is None: | 798 if self.update_cb_cmd is None: |
790 update_cb = self.showPreview | 799 update_cb = self.showPreview |
791 else: | 800 else: |
792 update_cb = self.updatePreviewExt | 801 update_cb = self.updatePreviewExt |
793 | 802 |
794 # which file do we need to edit? | 803 # which file do we need to edit? |
795 if self.args.file == "current": | 804 if self.args.file == "current": |
796 self.content_file_path = self.getCurrentFile(self.profile) | 805 self.content_file_path = self.getCurrentFile(self.profile) |
797 else: | 806 else: |
798 try: | 807 try: |
799 self.content_file_path = Path(self.args.file).resolve(strict=True) | 808 self.content_file_path = Path(self.args.file).resolve(strict=True) |
800 except FileNotFoundError: | 809 except FileNotFoundError: |
801 self.disp(_(f'File "{self.args.file}" doesn\'t exist!')) | 810 self.disp(_('File "{file}" doesn\'t exist!').format(file=self.args.file)) |
802 self.host.quit(C.EXIT_NOT_FOUND) | 811 self.host.quit(C.EXIT_NOT_FOUND) |
803 | 812 |
804 self.syntax = await guessSyntaxFromPath( | 813 self.syntax = await guessSyntaxFromPath( |
805 self.host, sat_conf, self.content_file_path) | 814 self.host, sat_conf, self.content_file_path |
815 ) | |
806 | 816 |
807 # at this point the syntax is converted, we can display the preview | 817 # at this point the syntax is converted, we can display the preview |
808 preview_file = tempfile.NamedTemporaryFile(suffix=".xhtml", delete=False) | 818 preview_file = tempfile.NamedTemporaryFile(suffix=".xhtml", delete=False) |
809 self.preview_file_path = preview_file.name | 819 self.preview_file_path = preview_file.name |
810 preview_file.close() | 820 preview_file.close() |
823 await open_cb() | 833 await open_cb() |
824 watcher = aionotify.Watcher() | 834 watcher = aionotify.Watcher() |
825 watcher_kwargs = { | 835 watcher_kwargs = { |
826 # Watcher don't accept Path so we convert to string | 836 # Watcher don't accept Path so we convert to string |
827 "path": str(self.content_file_path), | 837 "path": str(self.content_file_path), |
828 "alias": 'content_file', | 838 "alias": "content_file", |
829 "flags": aionotify.Flags.CLOSE_WRITE | 839 "flags": aionotify.Flags.CLOSE_WRITE |
830 | aionotify.Flags.DELETE_SELF | 840 | aionotify.Flags.DELETE_SELF |
831 | aionotify.Flags.MOVE_SELF, | 841 | aionotify.Flags.MOVE_SELF, |
832 } | 842 } |
833 watcher.watch(**watcher_kwargs) | 843 watcher.watch(**watcher_kwargs) |
834 | 844 |
835 loop = asyncio.get_event_loop() | 845 loop = asyncio.get_event_loop() |
836 await watcher.setup(loop) | 846 await watcher.setup(loop) |
837 | 847 |
838 try: | 848 try: |
839 while True: | 849 while True: |
840 event = await watcher.get_event() | 850 event = await watcher.get_event() |
841 self.disp("Content updated", 1) | 851 self.disp("Content updated", 1) |
842 if event.flags & (aionotify.Flags.DELETE_SELF | 852 if event.flags & ( |
843 | aionotify.Flags.MOVE_SELF): | 853 aionotify.Flags.DELETE_SELF | aionotify.Flags.MOVE_SELF |
854 ): | |
844 self.disp( | 855 self.disp( |
845 "DELETE/MOVE event catched, changing the watch", | 856 "DELETE/MOVE event catched, changing the watch", |
846 2, | 857 2, |
847 ) | 858 ) |
848 try: | 859 try: |
849 watcher.unwatch('content_file') | 860 watcher.unwatch("content_file") |
850 except IOError as e: | 861 except IOError as e: |
851 self.disp( | 862 self.disp( |
852 f"Can't remove the watch: {e}", | 863 f"Can't remove the watch: {e}", |
853 2, | 864 2, |
854 ) | 865 ) |
867 self.disp("The file seems to have been deleted.", error=True) | 878 self.disp("The file seems to have been deleted.", error=True) |
868 self.host.quit(C.EXIT_NOT_FOUND) | 879 self.host.quit(C.EXIT_NOT_FOUND) |
869 finally: | 880 finally: |
870 os.unlink(self.preview_file_path) | 881 os.unlink(self.preview_file_path) |
871 try: | 882 try: |
872 watcher.unwatch('content_file') | 883 watcher.unwatch("content_file") |
873 except IOError as e: | 884 except IOError as e: |
874 self.disp( | 885 self.disp( |
875 f"Can't remove the watch: {e}", | 886 f"Can't remove the watch: {e}", |
876 2, | 887 2, |
877 ) | 888 ) |
891 self.parser.add_argument( | 902 self.parser.add_argument( |
892 "importer", | 903 "importer", |
893 nargs="?", | 904 nargs="?", |
894 help=_("importer name, nothing to display importers list"), | 905 help=_("importer name, nothing to display importers list"), |
895 ) | 906 ) |
896 self.parser.add_argument( | 907 self.parser.add_argument("--host", help=_("original blog host")) |
897 "--host", help=_("original blog host") | |
898 ) | |
899 self.parser.add_argument( | 908 self.parser.add_argument( |
900 "--no-images-upload", | 909 "--no-images-upload", |
901 action="store_true", | 910 action="store_true", |
902 help=_("do *NOT* upload images (default: do upload images)"), | 911 help=_("do *NOT* upload images (default: do upload images)"), |
903 ) | 912 ) |
952 ), | 961 ), |
953 ] | 962 ] |
954 ) | 963 ) |
955 self.disp( | 964 self.disp( |
956 _( | 965 _( |
957 f"\nTo redirect old URLs to new ones, put the following lines in your" | 966 "\nTo redirect old URLs to new ones, put the following lines in your" |
958 f" sat.conf file, in [libervia] section:\n\n{conf}" | 967 " sat.conf file, in [libervia] section:\n\n{conf}" |
959 ) | 968 ).format(conf=conf) |
960 ) | 969 ) |
961 | 970 |
962 async def onProgressError(self, error_msg): | 971 async def onProgressError(self, error_msg): |
963 self.disp(_(f"Error while uploading blog: {error_msg}"), error=True) | 972 self.disp( |
973 _("Error while uploading blog: {error_msg}").format(error_msg=error_msg), | |
974 error=True, | |
975 ) | |
964 | 976 |
965 async def start(self): | 977 async def start(self): |
966 if self.args.location is None: | 978 if self.args.location is None: |
967 for name in ("option", "service", "no_images_upload"): | 979 for name in ("option", "service", "no_images_upload"): |
968 if getattr(self.args, name): | 980 if getattr(self.args, name): |
969 self.parser.error( | 981 self.parser.error( |
970 _( | 982 _( |
971 f"{name} argument can't be used without location argument" | 983 "{name} argument can't be used without location argument" |
972 ) | 984 ).format(name=name) |
973 ) | 985 ) |
974 if self.args.importer is None: | 986 if self.args.importer is None: |
975 self.disp( | 987 self.disp( |
976 "\n".join( | 988 "\n".join( |
977 [ | 989 [ |
1020 self.args.node, | 1032 self.args.node, |
1021 self.profile, | 1033 self.profile, |
1022 ) | 1034 ) |
1023 except Exception as e: | 1035 except Exception as e: |
1024 self.disp( | 1036 self.disp( |
1025 _(f"Error while trying to import a blog: {e}"), | 1037 _("Error while trying to import a blog: {e}").format(e=e), |
1026 error=True, | 1038 error=True, |
1027 ) | 1039 ) |
1028 self.host.quit(1) | 1040 self.host.quit(1) |
1029 | 1041 |
1030 await self.set_progress_id(progress_id) | 1042 await self.set_progress_id(progress_id) |
1031 | 1043 |
1044 | |
1032 class Blog(base.CommandBase): | 1045 class Blog(base.CommandBase): |
1033 subcommands = (Set, Get, Edit, Rename, Preview, Import) | 1046 subcommands = (Set, Get, Edit, Rename, Preview, Import) |
1034 | 1047 |
1035 def __init__(self, host): | 1048 def __init__(self, host): |
1036 super(Blog, self).__init__( | 1049 super(Blog, self).__init__( |