Commits

Roger Haase committed ef3c90f Merge

merge

Comments (0)

Files changed (8)

 ^.settings
 ^MANIFEST$
 .DS_Store
+^\.cache/
+^\.idea/
 .sqlite$
 .orig$
 .rej$
     clock.stop('create_app load config')
     clock.start('create_app register')
     # register converters
-    from werkzeug.routing import PathConverter
-    app.url_map.converters['itemname'] = PathConverter
+    from werkzeug.routing import BaseConverter
+
+    class ItemNameConverter(BaseConverter):
+        """Like the default :class:`UnicodeConverter`, but it also matches
+        slashes (except at the beginning AND end).
+        This is useful for wikis and similar applications::
+
+            Rule('/<itemname:wikipage>')
+            Rule('/<itemname:wikipage>/edit')
+
+        :param map: the :class:`Map`.
+        """
+        regex = '[^/].*?[^/]'
+        weight = 200
+
+    app.url_map.converters['itemname'] = ItemNameConverter
     # register modules, before/after request functions
     from MoinMoin.apps.frontend import frontend
     frontend.before_request(before_wiki)

MoinMoin/apps/frontend/views.py

     return item.do_show(rev)
 
 
+@frontend.route('/<itemname:item_name>/')  # note: unwanted trailing slash
 @frontend.route('/+show/<itemname:item_name>')
 def redirect_show_item(item_name):
     return redirect(url_for_item(item_name))

MoinMoin/items/content.py

         return doc
 
     def _render_data(self):
-        from MoinMoin.converter import default_registry as reg
-        # TODO: Real output format
-        doc = self.internal_representation()
-        doc = self._expand_document(doc)
-        flaskg.clock.start('conv_dom_html')
-        html_conv = reg.get(type_moin_document, Type('application/x-xhtml-moin-page'))
-        doc = html_conv(doc)
-        flaskg.clock.stop('conv_dom_html')
-        rendered_data = conv_serialize(doc, {html.namespace: ''})
+        try:
+            from MoinMoin.converter import default_registry as reg
+            # TODO: Real output format
+            doc = self.internal_representation()
+            doc = self._expand_document(doc)
+            flaskg.clock.start('conv_dom_html')
+            html_conv = reg.get(type_moin_document, Type('application/x-xhtml-moin-page'))
+            doc = html_conv(doc)
+            flaskg.clock.stop('conv_dom_html')
+            rendered_data = conv_serialize(doc, {html.namespace: ''})
+        except Exception:
+            # we really want to make sure that invalid data or a malfunctioning
+            # converter does not crash the item view (otherwise a user might
+            # not be able to fix it from the UI).
+            import time, uuid
+            error_id = uuid.uuid4()
+            logging.exception("An exception happened in _render_data (error_id = %s ):" % error_id)
+            rendered_data = render_template('crash.html',
+                                            server_time=time.strftime("%Y-%m-%d %H:%M:%S %Z"),
+                                            url=request.url,
+                                            error_id=error_id)
         return rendered_data
 
     def _render_data_xml(self):
             mt = MimeType(filename=filename)
             content_length = None
             file_to_send = self.get_member(member)
+            # force attachment download, so it uses attachment_filename
+            # otherwise it will use the itemname from the URL for saving
+            force_attachment = True
         else: # content = item revision
             rev = self.rev
             filename = rev.item.name
         raise NotImplementedError
 
 
-@register
-class TWikiDraw(Draw):
+class DrawPNGMap(Draw):
     """
-    drawings by TWikiDraw applet. It creates three files which are stored as tar file.
+    Base class for drawings that have a png with click map
     """
-    contenttype = 'application/x-twikidraw'
-    display_name = 'TDRAW'
+    def _read_map(self):
+        mapfile = self.get_member('drawing.map')
+        try:
+            image_map = mapfile.read()
+            mapfile.close()
+        except (IOError, OSError):
+            image_map = ''
+        return image_map
 
-    class ModifyForm(Draw.ModifyForm):
-        template = "modify_twikidraw.html"
-        help = ""
+    def _transform_map(self, image_map, title):
+        raise NotImplementedError
+
+    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
+        png_url = url_for('frontend.get_item', item_name=self.name, member='drawing.png', rev=self.rev.revid)
+        title = _('Edit drawing %(filename)s (opens in new window)', filename=self.name)
+        image_map = self._read_map()
+        if image_map:
+            mapid, image_map = self._transform_map(image_map, title)
+            title = _('Clickable drawing: %(filename)s', filename=self.name)
+            return Markup(image_map + u'<img src="{0}" alt="{1}" usemap="#{2}" />'.format(png_url, title, mapid))
+        else:
+            return Markup(u'<img src="{0}" alt="{1}" />'.format(png_url, title))
+
+
+class DrawAWDTWDBase(DrawPNGMap):
+    """
+    Shared code between TWikiDraw and AnyWikiDraw
+    """
+    _expected_members = set()
 
     def handle_post(self):
         # called from modify UI/POST
         filename = request.form['filename']
         basepath, basename = os.path.split(filename)
         basename, ext = os.path.splitext(basename)
-
         filecontent = file_upload.stream
         content_length = None
-        if ext == '.draw': # TWikiDraw POSTs this first
+        if ext in ['.svg', '.draw', ]:  # handle AWD (svg) and TWD (draw)
             filecontent = filecontent.read() # read file completely into memory
             filecontent = filecontent.replace("\r", "")
         elif ext == '.map':
             # XXX gives -1 for wsgiref, gives 0 for werkzeug :(
             # If this is fixed, we could use the file obj, without reading it into memory completely:
             filecontent = filecontent.read()
-
         self.put_member('drawing' + ext, filecontent, content_length,
-                        expected_members=set(['drawing.draw', 'drawing.map', 'drawing.png']))
-
-    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_name = self.name
-        drawing_url = url_for('frontend.get_item', item_name=item_name, member='drawing.draw', rev=self.rev.revid)
-        png_url = url_for('frontend.get_item', item_name=item_name, member='drawing.png', rev=self.rev.revid)
-        title = _('Edit drawing %(filename)s (opens in new window)', filename=item_name)
-
-        mapfile = self.get_member('drawing.map')
-        try:
-            image_map = mapfile.read()
-            mapfile.close()
-        except (IOError, OSError):
-            image_map = ''
-        if image_map:
-            # we have a image map. inline it and add a map ref to the img tag
-            mapid = 'ImageMapOf' + item_name
-            image_map = image_map.replace('%MAPNAME%', mapid)
-            # add alt and title tags to areas
-            image_map = re.sub(r'href\s*=\s*"((?!%TWIKIDRAW%).+?)"', r'href="\1" alt="\1" title="\1"', image_map)
-            image_map = image_map.replace('%TWIKIDRAW%"', '{0}" alt="{1}" title="{2}"'.format((drawing_url, title, title)))
-            title = _('Clickable drawing: %(filename)s', filename=item_name)
-
-            return Markup(image_map + u'<img src="{0}" alt="{1}" usemap="#{2}" />'.format(png_url, title, mapid))
-        else:
-            return Markup(u'<img src="{0}" alt="{1}" />'.format(png_url, title))
+                        expected_members=self._expected_members)
 
 
 @register
-class AnyWikiDraw(Draw):
+class TWikiDraw(DrawAWDTWDBase):
+    """
+    drawings by TWikiDraw applet. It creates three files which are stored as tar file.
+    """
+    contenttype = 'application/x-twikidraw'
+    display_name = 'TDRAW'
+    _expected_members = set(['drawing.draw', 'drawing.map', 'drawing.png'])
+
+    class ModifyForm(Draw.ModifyForm):
+        template = "modify_twikidraw.html"
+        help = ""
+
+    def _transform_map(self, image_map, title):
+        mapid = 'ImageMapOf' + self.name  # TODO: make it unique
+        image_map = image_map.replace('%MAPNAME%', mapid)
+        # add alt and title tags to areas
+        image_map = re.sub(r'href\s*=\s*"((?!%TWIKIDRAW%).+?)"',
+                           r'href="\1" alt="\1" title="\1"', image_map)
+        drawing_url = url_for('frontend.get_item', item_name=self.name, member='drawing.draw', rev=self.rev.revid)
+        image_map = image_map.replace('%TWIKIDRAW%"', '{0}" alt="{1}" title="{2}"'.format(drawing_url, title, title))
+        return mapid, image_map
+
+
+@register
+class AnyWikiDraw(DrawAWDTWDBase):
     """
     drawings by AnyWikiDraw applet. It creates three files which are stored as tar file.
     """
     contenttype = 'application/x-anywikidraw'
     display_name = 'ADRAW'
+    _expected_members = set(['drawing.svg', 'drawing.map', 'drawing.png'])
 
     class ModifyForm(Draw.ModifyForm):
         template = "modify_anywikidraw.html"
                 drawing_exists = False
             self.drawing_exists = drawing_exists
 
-    def handle_post(self):
-        # called from modify UI/POST
-        file_upload = request.files.get('filepath')
-        filename = request.form['filename']
-        basepath, basename = os.path.split(filename)
-        basename, ext = os.path.splitext(basename)
-        filecontent = file_upload.stream
-        content_length = None
-        if ext == '.svg':
-            filecontent = filecontent.read() # read file completely into memory
-            filecontent = filecontent.replace("\r", "")
-        elif ext == '.map':
-            filecontent = filecontent.read() # read file completely into memory
-            filecontent = filecontent.strip()
-        elif ext == '.png':
-            #content_length = file_upload.content_length
-            # XXX gives -1 for wsgiref, gives 0 for werkzeug :(
-            # If this is fixed, we could use the file obj, without reading it into memory completely:
-            filecontent = filecontent.read()
-        self.put_member('drawing' + ext, filecontent, content_length,
-                        expected_members=set(['drawing.svg', 'drawing.map', 'drawing.png']))
-
-    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_name = self.name
-        drawing_url = url_for('frontend.get_item', item_name=item_name, member='drawing.svg', rev=self.rev.revid)
-        png_url = url_for('frontend.get_item', item_name=item_name, member='drawing.png', rev=self.rev.revid)
-        title = _('Edit drawing %(filename)s (opens in new window)', filename=self.name)
-
-        mapfile = self.get_member('drawing.map')
-        try:
-            image_map = mapfile.read()
-            mapfile.close()
-        except (IOError, OSError):
-            image_map = ''
-        if image_map:
-            # ToDo mapid must become uniq
-            # we have a image map. inline it and add a map ref to the img tag
-            # we have also to set a unique ID
-            mapid = 'ImageMapOf' + self.name
-            image_map = image_map.replace(u'id="drawing.svg"', '')
-            image_map = image_map.replace(u'name="drawing.svg"', u'name="{0}"'.format(mapid))
-            # unxml, because 4.01 concrete will not validate />
-            image_map = image_map.replace(u'/>', u'>')
-            title = _('Clickable drawing: %(filename)s', filename=self.name)
-            return Markup(image_map + u'<img src="{0}" alt="{1}" usemap="#{2}" />'.format(png_url, title, mapid))
-        else:
-            return Markup(u'<img src="{0}" alt="{1}" />'.format(png_url, title))
+    def _transform_map(self, image_map, title):
+        #drawing_url = url_for('frontend.get_item', item_name=self.name, member='drawing.svg', rev=self.rev.revid)
+        mapid = 'ImageMapOf' + self.name  # TODO: make it unique
+        image_map = image_map.replace(u'id="drawing.svg"', '')
+        image_map = image_map.replace(u'name="drawing.svg"', u'name="{0}"'.format(mapid))
+        # unxml, because 4.01 concrete will not validate />
+        image_map = image_map.replace(u'/>', u'>')
+        return mapid, image_map
 
 
 @register
         # called from modify UI/POST
         png_upload = request.values.get('png_data')
         svg_upload = request.values.get('filepath')
-        filename = request.form['filename']
         png_content = png_upload.decode('base_64')
         png_content = base64.urlsafe_b64decode(png_content.split(',')[1])
         svg_content = svg_upload.decode('base_64')
     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_name = self.name
-        drawing_url = url_for('frontend.get_item', item_name=item_name, member='drawing.svg', rev=self.rev.revid)
-        png_url = url_for('frontend.get_item', item_name=item_name, member='drawing.png', rev=self.rev.revid)
+        drawing_url = url_for('frontend.get_item', item_name=self.name, member='drawing.svg', rev=self.rev.revid)
+        png_url = url_for('frontend.get_item', item_name=self.name, member='drawing.png', rev=self.rev.revid)
         return Markup(u'<img src="{0}" alt="{1}" />'.format(png_url, drawing_url))

MoinMoin/templates/crash.html

+<h1>{{ _("Oops!") }}</h1>
+<p>
+    {{ _("An error happened while processing your request.") }}
+</p>
+<p>
+    {{ _("More details have been logged. The following data is helpful for locating the corresponding log entries:") }}
+</p>
+<dl>
+    <dt>{{ _("Error ID") }}</dt>
+    <dd>{{ error_id }}</dd>
+    <dt>{{ _("Server time") }}</dt>
+    <dd>{{ server_time }}</dd>
+    <dt>{{ _("URL") }}</dt>
+    <dd>{{ url }} </dd>
+</dl>

MoinMoin/templates/utils.html

     </ul>
 {% endmacro %}
 
-{% macro render_subitem_navigation(itemname, newtab) %}
-    {% set subitems = theme_supp.subitem_index(itemname) %}
+{% macro render_subitem_navigation(itemname, newtab, subitems=None) %}
+    {% if not subitems %}
+        {% set subitems = theme_supp.subitem_index(itemname) %}
+    {% endif %}
     {% if caller %}
         {% set mycaller = caller %}
     {% endif %}

MoinMoin/themes/foobar/templates/show.html

             </ul>
         </li>
         {% endif %}
+        {% set subitems = theme_supp.subitem_index(item_name) %}
+        {% if subitems %}
         <li>
             {% block subitem_navigation %}
-            {{ utils.render_subitem_navigation(item_name, False) }}
+            {{ utils.render_subitem_navigation(item_name, False, subitems=subitems) }}
             {% endblock %}
         </li>
+        {% endif %}
     </ul>
 {% endblock %}
 
         'https://bitbucket.org/thomaswaldmann/whoosh/get/2.4x.tar.gz#egg=Whoosh-2.4.99dev',
         # fixed flask-themes, 0.1.3 does not work for flask 0.8.x, thus we use a faked 0.1.3.1:
         'https://bitbucket.org/thomaswaldmann/flask-themes/get/24dcc703953f.tar.gz#egg=Flask-Themes-0.1.3.1',
-        'https://bitbucket.org/thomaswaldmann/emeraldtree/get/tip.tar.gz#egg=emeraldtree-0.9.1',
+        'https://bitbucket.org/thomaswaldmann/emeraldtree/get/tip.tar.gz#egg=emeraldtree-0.9.2',
     ],
     install_requires=[
         'blinker>=1.1', # event signalling (e.g. for change notification trigger)
         'Flask-Cache>=0.3.4', # caching support
         'Flask-Script>=0.3.3', # scripting support
         'Flask-Themes>=0.1.3.1', # theme support
-        'emeraldtree>=0.9.1', # xml processing
+        'emeraldtree>=0.9.2', # xml processing
         'flatland==dev', # repo checkout at revision 269:6c5d262d7eff works
         'Jinja2>=2.6', # template engine
         'pygments>=1.4', # src code / text file highlighting