Commits

xiaq committed 339668f

refactor of apps/frontend/views.py and items/__init__.py modules

Comments (0)

Files changed (2)

MoinMoin/apps/frontend/views.py

+# Copyright: 2012 MoinMoin:CheerXiao
 # Copyright: 2003-2010 MoinMoin:ThomasWaldmann
 # Copyright: 2011 MoinMoin:AkashSinha
 # Copyright: 2011 MoinMoin:ReimarBauer
 from datetime import datetime
 from itertools import chain
 from collections import namedtuple
+from functools import wraps
+
 try:
     import json
 except ImportError:
     return html
 
 
+def presenter(view, add_trail=False, abort404=True):
+    """
+    Decorator to create new "presenter" views.
+
+    Presenter views handle GET requests to locations like
+    +{view}/+<rev>/<item_name> and +{view}/<item_name>, and always try to
+    look up the item before processing.
+
+    :param view: name of view
+    :param add_trail: whether to call flaskg.user.add_trail
+    :param abort404: whether to abort(404) for nonexistent items
+    """
+    def decorator(wrapped):
+        @frontend.route('/+{view}/+<rev>/<itemname:item_name>'.format(view=view))
+        @frontend.route('/+{view}/<itemname:item_name>'.format(view=view), defaults=dict(rev=CURRENT))
+        @wraps(wrapped)
+        def wrapper(item_name, rev):
+            if add_trail:
+                flaskg.user.add_trail(item_name)
+            try:
+                item = Item.create(item_name, rev_id=rev)
+            except AccessDenied:
+                abort(403)
+            if abort404 and isinstance(item, NonExistent):
+                abort(404, item_name)
+            return wrapped(item)
+        return wrapper
+    return decorator
+
+
 @frontend.route('/<itemname:item_name>', defaults=dict(rev=CURRENT), methods=['GET'])
 @frontend.route('/+show/+<rev>/<itemname:item_name>', methods=['GET'])
 def show_item(item_name, rev):
     return redirect(url_for_item(item_name))
 
 
-@frontend.route('/+dom/+<rev>/<itemname:item_name>')
-@frontend.route('/+dom/<itemname:item_name>', defaults=dict(rev=CURRENT))
-def show_dom(item_name, rev):
-    try:
-        item = Item.create(item_name, rev_id=rev)
-    except AccessDenied:
-        abort(403)
+@presenter('dom', abort404=False)
+def show_dom(item):
     if isinstance(item, NonExistent):
         status = 404
     else:
     return Response(content, 200, mimetype='text/plain')
 
 
-@frontend.route('/+highlight/+<rev>/<itemname:item_name>')
-@frontend.route('/+highlight/<itemname:item_name>', defaults=dict(rev=CURRENT))
-def highlight_item(item_name, rev):
-    try:
-        item = Item.create(item_name, rev_id=rev)
-    except AccessDenied:
-        abort(403)
-    if isinstance(item, NonExistent):
-        abort(404, item_name)
+@presenter('highlight')
+def highlight_item(item):
     return render_template('highlight.html',
                            item=item, item_name=item.name,
                            data_text=Markup(item._render_data_highlight()),
                           )
 
 
-@frontend.route('/+meta/<itemname:item_name>', defaults=dict(rev=CURRENT))
-@frontend.route('/+meta/+<rev>/<itemname:item_name>')
-def show_item_meta(item_name, rev):
-    flaskg.user.add_trail(item_name)
-    try:
-        item = Item.create(item_name, rev_id=rev)
-    except AccessDenied:
-        abort(403)
-    if isinstance(item, NonExistent):
-        abort(404, item_name)
-    show_revision = rev != CURRENT
+@presenter('meta', add_trail=True)
+def show_item_meta(item):
+    show_revision = request.view_args['rev'] != CURRENT
     show_navigation = False # TODO
     first_rev = None
     last_rev = None
                            data_rendered=Markup(item._render_data()),
                            )
 
-@frontend.route('/+get/+<rev>/<itemname:item_name>')
-@frontend.route('/+get/<itemname:item_name>', defaults=dict(rev=CURRENT))
-def get_item(item_name, rev):
-    try:
-        item = Item.create(item_name, rev_id=rev)
-    except AccessDenied:
-        abort(403)
+@presenter('get')
+def get_item(item):
     return item.do_get()
 
-@frontend.route('/+download/+<rev>/<itemname:item_name>')
-@frontend.route('/+download/<itemname:item_name>', defaults=dict(rev=CURRENT))
-def download_item(item_name, rev):
-    try:
-        item = Item.create(item_name, rev_id=rev)
-        mimetype = request.values.get("mimetype")
-    except AccessDenied:
-        abort(403)
+@presenter('download')
+def download_item(item):
+    mimetype = request.values.get("mimetype")
     return item.do_get(force_attachment=True, mimetype=mimetype)
 
 @frontend.route('/+convert/<itemname:item_name>')

MoinMoin/items/__init__.py

+# Copyright: 2012 MoinMoin:CheerXiao
 # Copyright: 2009 MoinMoin:ThomasWaldmann
 # Copyright: 2009-2011 MoinMoin:ReimarBauer
 # Copyright: 2009 MoinMoin:ChristopherDenter
         if not flaskg.user.may.create(self.name):
             abort(403)
 
-        # XXX think about and add item template support
         return render_template('modify_show_type_selection.html',
                                item_name=self.name,
                                contenttype_groups=CONTENTTYPE_GROUPS,
         revs = flaskg.storage.search(query, sortedby=NAME_EXACT, limit=None)
         return [rev.meta[NAME] for rev in revs]
 
+    from MoinMoin.apps.frontend.views import CommentForm
+    class ModifyForm(CommentForm):
+        """Base class for ModifyForm of Binary's subclasses."""
+        meta_text = String.using(optional=False).with_properties(placeholder=L_("MetaData (JSON)")).validated_by(ValidJSON())
+        data_file = FileStorage.using(optional=True, label=L_('Upload file:'))
+
+        def _load(self):
+            item = self.item
+            self['meta_text'] = item.meta_dict_to_text(item.prepare_meta_for_modify(item.meta))
+
+        extra_template_args = {}
+
+        @classmethod
+        def from_item(cls, item):
+            method = request.method
+            if method == 'GET':
+                form = cls.from_defaults()
+                TextCha(form).amend_form()
+                form.item = item
+                form._load()
+            elif method == 'POST':
+                form = cls.from_flat(request.form.items() + request.files.items())
+                form.item = item
+                TextCha(form).amend_form()
+                form.validate()
+            else:
+                raise ValueError("Request method '%s' not supported" % method)
+            return form
+
     def do_modify(self, contenttype, template_name):
-        # XXX think about and add item template support
-        #if template_name is None and isinstance(self.rev, DummyRev):
-        #    return self._do_modify_show_templates()
-        from MoinMoin.apps.frontend.views import CommentForm
-        class ModifyForm(CommentForm):
-            meta_text = String.using(optional=False).with_properties(placeholder=L_("MetaData (JSON)")).validated_by(ValidJSON())
-            data_file = FileStorage.using(optional=True, label=L_('Upload file:'))
+        method = request.method
+        if method == 'GET' and template_name is None and isinstance(self.rev, DummyRev):
+            return self._do_modify_show_templates()
 
-        if request.method == 'GET':
-            form = ModifyForm.from_defaults()
-            TextCha(form).amend_form()
-            form['meta_text'] = self.meta_dict_to_text(self.prepare_meta_for_modify(self.meta))
-        elif request.method == 'POST':
-            form = ModifyForm.from_flat(request.form.items() + request.files.items())
-            TextCha(form).amend_form()
-            if form.validate():
-                try:
-                    self.modify() # XXX
-                except AccessDenied:
-                    abort(403)
-                else:
-                    return redirect(url_for_item(self.name))
+        if template_name:
+            item = Item.create(template_name)
+
+        form = self.ModifyForm.from_item(self)
+        if method == 'POST' and form.validate():
+            try:
+                self.modify() # XXX
+            except AccessDenied:
+                abort(403)
+            else:
+                return redirect(url_for_item(self.name))
         return render_template(self.template,
                                item_name=self.name,
                                rows_meta=str(ROWS_META), cols=str(COLS),
                                help=self.modify_help,
                                form=form,
                                search_form=None,
+                               **form.extra_template_args
                               )
 
     def _render_data_diff(self, oldrev, newrev):
     """ Base class for text/* """
     template = "modify_text.html"
 
+    class ModifyForm(Binary.ModifyForm):
+        data_text = String.using(strip=False, optional=True).with_properties(placeholder=L_("Type your text here"))
+
+        def _load(self):
+            super(Text.ModifyForm, self)._load()
+            item = self.item
+            self['data_text'] = item.data_storage_to_internal(item.data)
+
+        extra_template_args = {'rows_data': str(ROWS_DATA)}
+
     # text/plain mandates crlf - but in memory, we want lf only
     def data_internal_to_form(self, text):
         """ convert data from memory format to form format """
         doc = html_conv(doc)
         return conv_serialize(doc, {html.namespace: ''})
 
-    def do_modify(self, contenttype, template_name):
-        # XXX think about and add item template support
-        #if template_name is None and isinstance(self.rev, DummyRev):
-        #    return self._do_modify_show_templates()
-        from MoinMoin.apps.frontend.views import CommentForm
-        class ModifyForm(CommentForm):
-            meta_text = String.using(optional=False).with_properties(placeholder=L_("MetaData (JSON)")).validated_by(ValidJSON())
-            data_text = String.using(strip=False, optional=True).with_properties(placeholder=L_("Type your text here"))
-            data_file = FileStorage.using(optional=True, label=L_('Upload file:'))
-
-        if request.method == 'GET':
-            if template_name is None and isinstance(self.rev, DummyRev):
-                return self._do_modify_show_templates()
-            form = ModifyForm.from_defaults()
-            TextCha(form).amend_form()
-            if template_name:
-                item = Item.create(template_name)
-                form['data_text'] = self.data_storage_to_internal(item.data)
-            else:
-                form['data_text'] = self.data_storage_to_internal(self.data)
-            form['meta_text'] = self.meta_dict_to_text(self.prepare_meta_for_modify(self.meta))
-        elif request.method == 'POST':
-            form = ModifyForm.from_flat(request.form.items() + request.files.items())
-            TextCha(form).amend_form()
-            if form.validate():
-                try:
-                    self.modify() # XXX
-                except AccessDenied:
-                    abort(403)
-                else:
-                    return redirect(url_for_item(self.name))
-        return render_template(self.template,
-                               item_name=self.name,
-                               rows_data=str(ROWS_DATA), rows_meta=str(ROWS_META), cols=str(COLS),
-                               help=self.modify_help,
-                               form=form,
-                               search_form=None,
-                              )
-
 item_registry.register(Text._factory, Type('text/*'))
 
 
 item_registry.register(DocBook._factory, Type('application/docbook+xml'))
 
 
-class TWikiDraw(TarMixin, Image):
+class Draw(TarMixin, Image):
+    """
+    Base class for *Draw that use special Java/Javascript applets to modify and store data in a tar file.
+    """
+    class ModifyForm(Binary.ModifyForm):
+        pass
+
+    def do_modify(self, contenttype, template_name):
+        # XXX think about and add item template support
+        #if template_name is None and isinstance(self.rev, DummyRev):
+        #    return self._do_modify_show_templates()
+        form = self.ModifyForm.from_item(self)
+        # XXX we don't validate the form as the POST comes from *Draw applets
+        # XXX as the "saving" POSTs come from *Draw (not the form), editing meta_text doesn't work
+        if request.method == 'POST':
+            try:
+                self.modify() # XXX
+            except AccessDenied:
+                abort(403)
+            else:
+                # *Draw Applets POSTs more than once, redirecting would break them
+                return "OK"
+        return render_template(self.template,
+                               item_name=self.name,
+                               rows_meta=str(ROWS_META), cols=str(COLS),
+                               help=self.modify_help,
+                               form=form,
+                               search_form=None,
+                               **form.extra_template_args
+                              )
+
+
+class TWikiDraw(Draw):
     """
     drawings by TWikiDraw applet. It creates three files which are stored as tar file.
     """
         self.put_member('drawing' + ext, filecontent, content_length,
                         expected_members=set(['drawing.draw', 'drawing.map', 'drawing.png']))
 
-    def do_modify(self, contenttype, template_name):
-        # XXX think about and add item template support
-        #if template_name is None and isinstance(self.rev, DummyRev):
-        #    return self._do_modify_show_templates()
-        from MoinMoin.apps.frontend.views import CommentForm
-        class ModifyForm(CommentForm):
-            # XXX as the "saving" POSTs come from TWikiDraw (not the form), editing meta_text doesn't work
-            meta_text = String.using(optional=False).with_properties(placeholder=L_("MetaData (JSON)")).validated_by(ValidJSON())
-            data_file = FileStorage.using(optional=True, label=L_('Upload file:'))
-
-        if request.method == 'GET':
-            form = ModifyForm.from_defaults()
-            TextCha(form).amend_form()
-            # XXX currently this is rather pointless, as the form does not get POSTed:
-            form['meta_text'] = self.meta_dict_to_text(self.prepare_meta_for_modify(self.meta))
-        elif request.method == 'POST':
-            # this POST comes directly from TWikiDraw (not from Browser), thus no validation
-            try:
-                self.modify() # XXX
-            except AccessDenied:
-                abort(403)
-            else:
-                # TWikiDraw POSTs more than once, redirecting would break them
-                return "OK"
-        return render_template(self.template,
-                               item_name=self.name,
-                               rows_meta=str(ROWS_META), cols=str(COLS),
-                               help=self.modify_help,
-                               form=form,
-                               search_form=None,
-                              )
-
     def _render_data(self):
         # TODO: this could be a converter -> dom, then transcluding this kind
         # of items and also rendering them with the code in base class could work
 item_registry.register(TWikiDraw._factory, Type('application/x-twikidraw'))
 
 
-class AnyWikiDraw(TarMixin, Image):
+class AnyWikiDraw(Draw):
     """
     drawings by AnyWikiDraw applet. It creates three files which are stored as tar file.
     """
     modify_help = ""
     template = "modify_anywikidraw.html"
 
+    class ModifyForm(Draw.ModifyForm):
+        @property
+        def extra_template_args(self):
+            try:
+                drawing_exists = 'drawing.svg' in item.list_members()
+            except:
+                drawing_exists = False
+            return {'drawing_exists': drawing_exists}
+
     def modify(self):
         # called from modify UI/POST
         file_upload = request.files.get('filepath')
         self.put_member('drawing' + ext, filecontent, content_length,
                         expected_members=set(['drawing.svg', 'drawing.map', 'drawing.png']))
 
-    def do_modify(self, contenttype, template_name):
-        # XXX think about and add item template support
-        #if template_name is None and isinstance(self.rev, DummyRev):
-        #    return self._do_modify_show_templates()
-        from MoinMoin.apps.frontend.views import CommentForm
-        class ModifyForm(CommentForm):
-            # XXX as the "saving" POSTs come from AnyWikiDraw (not the form), editing meta_text doesn't work
-            meta_text = String.using(optional=False).with_properties(placeholder=L_("MetaData (JSON)")).validated_by(ValidJSON())
-            data_file = FileStorage.using(optional=True, label=L_('Upload file:'))
-
-        if request.method == 'GET':
-            form = ModifyForm.from_defaults()
-            TextCha(form).amend_form()
-            # XXX currently this is rather pointless, as the form does not get POSTed:
-            form['meta_text'] = self.meta_dict_to_text(self.prepare_meta_for_modify(self.meta))
-        elif request.method == 'POST':
-            # this POST comes directly from AnyWikiDraw (not from Browser), thus no validation
-            try:
-                self.modify() # XXX
-            except AccessDenied:
-                abort(403)
-            else:
-                # AnyWikiDraw POSTs more than once, redirecting would break them
-                return "OK"
-        try:
-            drawing_exists = 'drawing.svg' in self.list_members()
-        except:
-            drawing_exists = False
-        return render_template(self.template,
-                               item_name=self.name,
-                               rows_meta=str(ROWS_META), cols=str(COLS),
-                               help=self.modify_help,
-                               drawing_exists=drawing_exists,
-                               form=form,
-                               search_form=None,
-                              )
-
     def _render_data(self):
         # TODO: this could be a converter -> dom, then transcluding this kind
         # of items and also rendering them with the code in base class could work
 item_registry.register(AnyWikiDraw._factory, Type('application/x-anywikidraw'))
 
 
-class SvgDraw(TarMixin, Image):
+class SvgDraw(Draw):
     """ drawings by svg-edit. It creates two files (svg, png) which are stored as tar file. """
     modify_help = ""
     template = "modify_svg-edit.html"
         self.put_member("drawing.png", png_content, content_length,
                         expected_members=set(['drawing.svg', 'drawing.png']))
 
-    def do_modify(self, contenttype, template_name):
-        # XXX think about and add item template support
-        #if template_name is None and isinstance(self.rev, DummyRev):
-        #    return self._do_modify_show_templates()
-        from MoinMoin.apps.frontend.views import CommentForm
-        class ModifyForm(CommentForm):
-            # XXX as the "saving" POSTs come from SvgDraw (not the form), editing meta_text doesn't work
-            meta_text = String.using(optional=False).with_properties(placeholder=L_("MetaData (JSON)")).validated_by(ValidJSON())
-            data_file = FileStorage.using(optional=True, label=L_('Upload file:'))
-
-        if request.method == 'GET':
-            form = ModifyForm.from_defaults()
-            TextCha(form).amend_form()
-            # XXX currently this is rather pointless, as the form does not get POSTed:
-            form['meta_text'] = self.meta_dict_to_text(self.prepare_meta_for_modify(self.meta))
-        elif request.method == 'POST':
-            # this POST comes directly from SvgDraw (not from Browser), thus no validation
-            try:
-                self.modify() # XXX
-            except AccessDenied:
-                abort(403)
-            else:
-                # SvgDraw POSTs more than once, redirecting would break them
-                return "OK"
-        return render_template(self.template,
-                               item_name=self.name,
-                               rows_meta=str(ROWS_META), cols=str(COLS),
-                               help=self.modify_help,
-                               form=form,
-                               search_form=None,
-                              )
-
     def _render_data(self):
         # TODO: this could be a converter -> dom, then transcluding this kind
         # of items and also rendering them with the code in base class could work
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.