comparison MoinMoin/items/content.py @ 1801:f6afb9aeb861

Replace CONTENTTYPE_GROUPS with information collected in content_registry.
author Cheer Xiao <xiaqqaix@gmail.com>
date Sat, 29 Sep 2012 23:55:59 +0800
parents 19b19d4d9291
children 38632887ca57
comparison
equal deleted inserted replaced
1800:54062fc0ca97 1801:f6afb9aeb861
22 import zipfile 22 import zipfile
23 import tempfile 23 import tempfile
24 from StringIO import StringIO 24 from StringIO import StringIO
25 from array import array 25 from array import array
26 from collections import namedtuple 26 from collections import namedtuple
27 from operator import attrgetter
27 28
28 from flask import current_app as app 29 from flask import current_app as app
29 from flask import g as flaskg 30 from flask import g as flaskg
30 from flask import request, url_for, Response, abort, escape 31 from flask import request, url_for, Response, abort, escape
31 32
58 from MoinMoin.util.tree import moin_page, html, xlink, docbook 59 from MoinMoin.util.tree import moin_page, html, xlink, docbook
59 from MoinMoin.util.iri import Iri 60 from MoinMoin.util.iri import Iri
60 from MoinMoin.util.crypto import cache_key 61 from MoinMoin.util.crypto import cache_key
61 from MoinMoin.util.clock import timed 62 from MoinMoin.util.clock import timed
62 from MoinMoin.forms import File 63 from MoinMoin.forms import File
64 from MoinMoin.constants.contenttypes import (
65 GROUP_MARKUP_TEXT, GROUP_OTHER_TEXT, GROUP_IMAGE, GROUP_AUDIO, GROUP_VIDEO,
66 GROUP_DRAWING, GROUP_OTHER,
67 )
63 from MoinMoin.constants.keys import ( 68 from MoinMoin.constants.keys import (
64 NAME, NAME_EXACT, WIKINAME, CONTENTTYPE, SIZE, TAGS, HASH_ALGORITHM 69 NAME, NAME_EXACT, WIKINAME, CONTENTTYPE, SIZE, TAGS, HASH_ALGORITHM
65 ) 70 )
66 71
67 72
68 COLS = 80 73 COLS = 80
69 ROWS_DATA = 20 74 ROWS_DATA = 20
70 75
71 76
72 class RegistryContent(RegistryBase): 77 class RegistryContent(RegistryBase):
73 class Entry(namedtuple('Entry', 'factory content_type priority')): 78 class Entry(namedtuple('Entry', 'factory content_type default_contenttype_params display_name ingroup_order priority')):
74 def __call__(self, content_type, *args, **kw): 79 def __call__(self, content_type, *args, **kw):
75 if self.content_type.issupertype(Type(content_type)): 80 if self.content_type.issupertype(Type(content_type)):
76 return self.factory(content_type, *args, **kw) 81 return self.factory(content_type, *args, **kw)
77 82
78 def __lt__(self, other): 83 def __lt__(self, other):
82 if self.content_type != other.content_type: 87 if self.content_type != other.content_type:
83 return other.content_type.issupertype(self.content_type) 88 return other.content_type.issupertype(self.content_type)
84 return False 89 return False
85 return NotImplemented 90 return NotImplemented
86 91
87 def register(self, factory, content_type, priority=RegistryBase.PRIORITY_MIDDLE): 92 def __init__(self, group_names):
93 super(RegistryContent, self).__init__()
94 self.group_names = group_names
95 self.groups = dict([(g, []) for g in group_names])
96
97 def register(self, factory, contenttype, default_contenttype_params, display_name, group, ingroup_order, priority=RegistryBase.PRIORITY_MIDDLE):
88 """ 98 """
89 Register a factory 99 Register a factory
90 100
91 :param factory: Factory to register. Callable, must return an object. 101 :param factory: Factory to register. Callable, must return an object.
92 """ 102 """
93 return self._register(self.Entry(factory, content_type, priority)) 103 e = self.Entry(factory, contenttype, default_contenttype_params, display_name, ingroup_order, priority)
94 104 # If group is specified and contenttype is not a wildcard one
95 105 if group and contenttype.type and contenttype.subtype:
96 content_registry = RegistryContent() 106 if group not in self.groups:
107 raise ValueError('Unknown group name: {0}'.format(group))
108 self.groups[group].append(e)
109 self.groups[group].sort(key=attrgetter('ingroup_order'))
110 return self._register(e)
111
112
113 content_registry = RegistryContent([
114 GROUP_MARKUP_TEXT,
115 GROUP_OTHER_TEXT,
116 GROUP_IMAGE,
117 GROUP_AUDIO,
118 GROUP_VIDEO,
119 GROUP_DRAWING,
120 GROUP_OTHER
121 ])
97 122
98 def register(cls): 123 def register(cls):
99 content_registry.register(cls._factory, Type(cls.contenttype)) 124 content_registry.register(cls._factory, Type(cls.contenttype), cls.default_contenttype_params, cls.display_name, cls.group, cls.ingroup_order)
100 return cls 125 return cls
101 126
102 127
103 @timed() 128 @timed()
104 def conv_serialize(doc, namespaces, method='polyglot'): 129 def conv_serialize(doc, namespaces, method='polyglot'):
111 class Content(object): 136 class Content(object):
112 """ 137 """
113 Base for content classes defining some helpers, agnostic about content 138 Base for content classes defining some helpers, agnostic about content
114 data. 139 data.
115 """ 140 """
141 # placeholder values for registry entry properties
142 contenttype = None
143 default_contenttype_params = {}
144 display_name = None
145 group = GROUP_OTHER
146 ingroup_order = 0
147
116 @classmethod 148 @classmethod
117 def _factory(cls, *args, **kw): 149 def _factory(cls, *args, **kw):
118 return cls(*args, **kw) 150 return cls(*args, **kw)
119 151
120 @classmethod 152 @classmethod
239 271
240 @register 272 @register
241 class NonExistentContent(Content): 273 class NonExistentContent(Content):
242 """Dummy Content to use with NonExistent.""" 274 """Dummy Content to use with NonExistent."""
243 contenttype = 'application/x-nonexistent' 275 contenttype = 'application/x-nonexistent'
276 group = None
244 277
245 def do_get(self, force_attachment=False, mimetype=None): 278 def do_get(self, force_attachment=False, mimetype=None):
246 abort(404) 279 abort(404)
247 280
248 def _convert(self, doc): 281 def _convert(self, doc):
337 return send_file(file=file_to_send, 370 return send_file(file=file_to_send,
338 mimetype=content_type, 371 mimetype=content_type,
339 as_attachment=as_attachment, attachment_filename=filename, 372 as_attachment=as_attachment, attachment_filename=filename,
340 cache_timeout=10, # wiki data can change rapidly 373 cache_timeout=10, # wiki data can change rapidly
341 add_etags=True, etag=hash, conditional=True) 374 add_etags=True, etag=hash, conditional=True)
375
376
377 @register
378 class OctetStream(Binary):
379 """
380 Fallback Content for uploaded file of unknown contenttype.
381 """
382 contenttype = 'application/octet-stream'
383 display_name = 'binary file'
342 384
343 385
344 class RenderableBinary(Binary): 386 class RenderableBinary(Binary):
345 """ Base class for some binary stuff that renders with a object tag. """ 387 """ Base class for some binary stuff that renders with a object tag. """
346 388
421 class ApplicationXTar(TarMixin, Application): 463 class ApplicationXTar(TarMixin, Application):
422 """ 464 """
423 Tar items 465 Tar items
424 """ 466 """
425 contenttype = 'application/x-tar' 467 contenttype = 'application/x-tar'
468 display_name = 'TAR'
426 469
427 470
428 @register 471 @register
429 class ApplicationXGTar(ApplicationXTar): 472 class ApplicationXGTar(ApplicationXTar):
430 """ 473 """
431 Compressed tar items 474 Compressed tar items
432 """ 475 """
433 contenttype = 'application/x-gtar' 476 contenttype = 'application/x-gtar'
477 display_name = 'TGZ'
434 478
435 479
436 class ZipMixin(object): 480 class ZipMixin(object):
437 """ 481 """
438 ZipMixin offers additional functionality for zip-like items to list and 482 ZipMixin offers additional functionality for zip-like items to list and
464 class ApplicationZip(ZipMixin, Application): 508 class ApplicationZip(ZipMixin, Application):
465 """ 509 """
466 Zip items 510 Zip items
467 """ 511 """
468 contenttype = 'application/zip' 512 contenttype = 'application/zip'
513 display_name = 'ZIP'
469 514
470 515
471 @register 516 @register
472 class PDF(Application): 517 class PDF(Application):
473 """ PDF """ 518 """ PDF """
474 contenttype = 'application/pdf' 519 contenttype = 'application/pdf'
520 display_name = 'PDF'
475 521
476 522
477 @register 523 @register
478 class Video(Binary): 524 class Video(Binary):
479 """ Base class for video/* """ 525 """ Base class for video/* """
480 contenttype = 'video/*' 526 contenttype = 'video/*'
527 group = GROUP_VIDEO
528
529
530 @register
531 class OGGVideo(Video):
532 contenttype = 'video/ogg'
533 display_name = 'OGG'
534
535
536 @register
537 class WebMVideo(Video):
538 contenttype = 'video/webm'
539 display_name = 'WebM'
540
541
542 @register
543 class MP4(Video):
544 contenttype = 'video/mp4'
545 display_name = 'MP4'
481 546
482 547
483 @register 548 @register
484 class Audio(Binary): 549 class Audio(Binary):
485 """ Base class for audio/* """ 550 """ Base class for audio/* """
486 contenttype = 'audio/*' 551 contenttype = 'audio/*'
552 group = GROUP_AUDIO
553
554
555 @register
556 class WAV(Audio):
557 contenttype = 'audio/wave'
558 display_name = 'WAV'
559
560
561 @register
562 class OGGAudio(Audio):
563 contenttype = 'audio/ogg'
564 display_name = 'OGG'
565
566
567 @register
568 class MP3(Audio):
569 contenttype = 'audio/mpeg'
570 display_name = 'MP3'
571
572
573 @register
574 class WebMAudio(Audio):
575 contenttype = 'audio/webm'
576 display_name = 'WebM'
487 577
488 578
489 @register 579 @register
490 class Image(Binary): 580 class Image(Binary):
491 """ Base class for image/* """ 581 """ Base class for image/* """
492 contenttype = 'image/*' 582 contenttype = 'image/*'
493 583
494 584
495 class RenderableImage(RenderableBinary): 585 class RenderableImage(RenderableBinary):
496 """ Base class for renderable Image mimetypes """ 586 """ Base class for renderable Image mimetypes """
587 group = GROUP_IMAGE
497 588
498 589
499 @register 590 @register
500 class SvgImage(RenderableImage): 591 class SvgImage(RenderableImage):
501 """ SVG images use <object> tag mechanism from RenderableBinary base class """ 592 """ SVG images use <object> tag mechanism from RenderableBinary base class """
502 contenttype = 'image/svg+xml' 593 contenttype = 'image/svg+xml'
594 display_name = 'SVG'
503 595
504 596
505 class RenderableBitmapImage(RenderableImage): 597 class RenderableBitmapImage(RenderableImage):
506 """ PNG/JPEG/GIF images use <img> tag (better browser support than <object>) """ 598 """ PNG/JPEG/GIF images use <img> tag (better browser support than <object>) """
507 # if mimetype is also transformable, please register in TransformableImage ONLY! 599 # if mimetype is also transformable, please register in TransformableImage ONLY!
663 755
664 @register 756 @register
665 class PNG(TransformableBitmapImage): 757 class PNG(TransformableBitmapImage):
666 """ PNG image. """ 758 """ PNG image. """
667 contenttype = 'image/png' 759 contenttype = 'image/png'
760 display_name = 'PNG'
668 761
669 762
670 @register 763 @register
671 class JPEG(TransformableBitmapImage): 764 class JPEG(TransformableBitmapImage):
672 """ JPEG image. """ 765 """ JPEG image. """
673 contenttype = 'image/jpeg' 766 contenttype = 'image/jpeg'
767 display_name = 'JPEG'
674 768
675 769
676 @register 770 @register
677 class GIF(TransformableBitmapImage): 771 class GIF(TransformableBitmapImage):
678 """ GIF image. """ 772 """ GIF image. """
679 contenttype = 'image/gif' 773 contenttype = 'image/gif'
774 display_name = 'GIF'
680 775
681 776
682 @register 777 @register
683 class Text(Binary): 778 class Text(Binary):
684 """ Base class for text/* """ 779 """ Base class for text/* """
685 contenttype = 'text/*' 780 contenttype = 'text/*'
781 default_contenttype_params = dict(charset='utf-8')
782 group = GROUP_OTHER_TEXT
686 783
687 class ModifyForm(Binary.ModifyForm): 784 class ModifyForm(Binary.ModifyForm):
688 template = 'modify_text.html' 785 template = 'modify_text.html'
689 data_text = String.using(strip=False, optional=True).with_properties(placeholder=L_("Type your text here")) 786 data_text = String.using(strip=False, optional=True).with_properties(placeholder=L_("Type your text here"))
690 rows = ROWS_DATA 787 rows = ROWS_DATA
769 class MarkupItem(Text): 866 class MarkupItem(Text):
770 """ 867 """
771 some kind of item with markup 868 some kind of item with markup
772 (internal links and transcluded items) 869 (internal links and transcluded items)
773 """ 870 """
871 group = GROUP_MARKUP_TEXT
774 872
775 873
776 @register 874 @register
777 class MoinWiki(MarkupItem): 875 class MoinWiki(MarkupItem):
778 """ MoinMoin wiki markup """ 876 """ MoinMoin wiki markup """
779 contenttype = 'text/x.moin.wiki' 877 contenttype = 'text/x.moin.wiki'
878 display_name = 'Wiki (MoinMoin)'
780 879
781 880
782 @register 881 @register
783 class CreoleWiki(MarkupItem): 882 class CreoleWiki(MarkupItem):
784 """ Creole wiki markup """ 883 """ Creole wiki markup """
785 contenttype = 'text/x.moin.creole' 884 contenttype = 'text/x.moin.creole'
885 display_name = 'Wiki (Creole)'
786 886
787 887
788 @register 888 @register
789 class MediaWiki(MarkupItem): 889 class MediaWiki(MarkupItem):
790 """ MediaWiki markup """ 890 """ MediaWiki markup """
791 contenttype = 'text/x-mediawiki' 891 contenttype = 'text/x-mediawiki'
892 display_name = 'Wiki (MediaWiki)'
792 893
793 894
794 @register 895 @register
795 class ReST(MarkupItem): 896 class ReST(MarkupItem):
796 """ ReStructured Text markup """ 897 """ ReStructured Text markup """
797 contenttype = 'text/x-rst' 898 contenttype = 'text/x-rst'
899 display_name = 'ReST'
798 900
799 901
800 @register 902 @register
801 class Markdown(MarkupItem): 903 class Markdown(MarkupItem):
802 """ Markdown markup """ 904 """ Markdown markup """
803 contenttype = 'text/x-markdown' 905 contenttype = 'text/x-markdown'
804 906 display_name = 'Markdown'
805 907
806 @register 908
807 class HTML(Text): 909 @register
910 class HTML(MarkupItem):
808 """ 911 """
809 HTML markup 912 HTML markup
810 913
811 Note: As we use html_in converter to convert this to DOM and later some 914 Note: As we use html_in converter to convert this to DOM and later some
812 output converterter to produce output format (e.g. html_out for html 915 output converterter to produce output format (e.g. html_out for html
813 output), all(?) unsafe stuff will get lost. 916 output), all(?) unsafe stuff will get lost.
814 917
815 Note: If raw revision data is accessed, unsafe stuff might be present! 918 Note: If raw revision data is accessed, unsafe stuff might be present!
816 """ 919 """
817 contenttype = 'text/html' 920 contenttype = 'text/html'
921 display_name = 'HTML'
818 922
819 class ModifyForm(Text.ModifyForm): 923 class ModifyForm(Text.ModifyForm):
820 template = "modify_text_html.html" 924 template = "modify_text_html.html"
821 925
822 926
823 @register 927 @register
824 class DocBook(MarkupItem): 928 class DocBook(MarkupItem):
825 """ DocBook Document """ 929 """ DocBook Document """
826 contenttype = 'application/docbook+xml' 930 contenttype = 'application/docbook+xml'
931 display_name = 'DocBook'
827 932
828 def _convert(self, doc): 933 def _convert(self, doc):
829 from emeraldtree import ElementTree as ET 934 from emeraldtree import ElementTree as ET
830 from MoinMoin.converter import default_registry as reg 935 from MoinMoin.converter import default_registry as reg
831 936
867 as_attachment=as_attachment, attachment_filename=None, 972 as_attachment=as_attachment, attachment_filename=None,
868 cache_timeout=10, # wiki data can change rapidly 973 cache_timeout=10, # wiki data can change rapidly
869 add_etags=False, etag=None, conditional=True) 974 add_etags=False, etag=None, conditional=True)
870 975
871 976
977 @register
978 class PlainText(Text):
979 contenttype = 'text/plain'
980 display_name = 'plain text'
981
982
983 @register
984 class Diff(Text):
985 contenttype = 'text/x-diff'
986 display_name = 'diff/patch'
987
988
989 @register
990 class PythonCode(Text):
991 contenttype = 'text/x-python'
992 display_name = 'python code'
993
994
995 @register
996 class CSV(Text):
997 contenttype = 'text/csv'
998 display_name = 'csv'
999
1000
1001 @register
1002 class IRCLog(Text):
1003 contenttype = 'text/x-irclog'
1004 display_name = 'IRC log'
1005
1006
872 class Draw(TarMixin, Image): 1007 class Draw(TarMixin, Image):
873 """ 1008 """
874 Base class for *Draw that use special Java/Javascript applets to modify and store data in a tar file. 1009 Base class for *Draw that use special Java/Javascript applets to modify and store data in a tar file.
875 """ 1010 """
1011 group = GROUP_DRAWING
1012
876 class ModifyForm(Binary.ModifyForm): 1013 class ModifyForm(Binary.ModifyForm):
877 # Set the workaround flag respected in modify.html 1014 # Set the workaround flag respected in modify.html
878 is_draw = True 1015 is_draw = True
879 1016
880 def handle_post(): 1017 def handle_post():
885 class TWikiDraw(Draw): 1022 class TWikiDraw(Draw):
886 """ 1023 """
887 drawings by TWikiDraw applet. It creates three files which are stored as tar file. 1024 drawings by TWikiDraw applet. It creates three files which are stored as tar file.
888 """ 1025 """
889 contenttype = 'application/x-twikidraw' 1026 contenttype = 'application/x-twikidraw'
1027 display_name = 'TDRAW'
890 1028
891 class ModifyForm(Draw.ModifyForm): 1029 class ModifyForm(Draw.ModifyForm):
892 template = "modify_twikidraw.html" 1030 template = "modify_twikidraw.html"
893 help = "" 1031 help = ""
894 1032
948 class AnyWikiDraw(Draw): 1086 class AnyWikiDraw(Draw):
949 """ 1087 """
950 drawings by AnyWikiDraw applet. It creates three files which are stored as tar file. 1088 drawings by AnyWikiDraw applet. It creates three files which are stored as tar file.
951 """ 1089 """
952 contenttype = 'application/x-anywikidraw' 1090 contenttype = 'application/x-anywikidraw'
1091 display_name = 'ADRAW'
953 1092
954 class ModifyForm(Draw.ModifyForm): 1093 class ModifyForm(Draw.ModifyForm):
955 template = "modify_anywikidraw.html" 1094 template = "modify_anywikidraw.html"
956 help = "" 1095 help = ""
957 def _load(self, item): 1096 def _load(self, item):
1015 1154
1016 @register 1155 @register
1017 class SvgDraw(Draw): 1156 class SvgDraw(Draw):
1018 """ drawings by svg-edit. It creates two files (svg, png) which are stored as tar file. """ 1157 """ drawings by svg-edit. It creates two files (svg, png) which are stored as tar file. """
1019 contenttype = 'application/x-svgdraw' 1158 contenttype = 'application/x-svgdraw'
1159 display_name = 'SVGDRAW'
1020 1160
1021 class ModifyForm(Draw.ModifyForm): 1161 class ModifyForm(Draw.ModifyForm):
1022 template = "modify_svg-edit.html" 1162 template = "modify_svg-edit.html"
1023 help = "" 1163 help = ""
1024 1164