Commits

Jaiditya committed 0b7ae26 Merge

merged

  • Participants
  • Parent commits cb93c42, ed2bfcc

Comments (0)

Files changed (11)

MoinMoin/_tests/__init__.py

         data = data.encode(config.charset)
     item = flaskg.storage[name]
 
+    meta = meta.copy()
     if NAME not in meta:
         meta[NAME] = name
     if CONTENTTYPE not in meta:

MoinMoin/items/_tests/test_Blog.py

+# Copyright: 2012 MoinMoin:PavelSviderski
+# License: GNU GPL v2 (or any later version), see LICENSE.txt for details.
+
+"""
+    MoinMoin - MoinMoin.items.blog Tests
+"""
+
+import re
+
+from flask import url_for
+
+from MoinMoin._tests import become_trusted, update_item
+from MoinMoin.items import Item
+from MoinMoin.config import CONTENTTYPE, ITEMTYPE, PTIME, ACL
+from MoinMoin.items.blog import ITEMTYPE_BLOG, ITEMTYPE_BLOG_ENTRY
+from MoinMoin.items.blog import Blog, BlogEntry
+
+
+class TestView(object):
+    def _test_view(self, item_name, data_tokens=[], exclude_data_tokens=[], regex=None):
+        with self.app.test_client() as c:
+            rv = c.get(url_for('frontend.show_item', item_name=item_name))
+            for data in data_tokens:
+                assert data in rv.data
+            for data in exclude_data_tokens:
+                assert data not in rv.data
+            if regex:
+                assert regex.search(rv.data)
+
+
+class TestBlog(TestView):
+    NO_ENTRIES_MSG = u"There are no entries in this blog"
+
+    name = u'NewBlogItem'
+    contenttype = u'text/x.moin.wiki'
+    data = u"This is the header item of this blog"
+    meta = {CONTENTTYPE: contenttype, ITEMTYPE: ITEMTYPE_BLOG}
+    comment = u'saved it'
+    entries = [{'name': name + u'/NewBlogEntryItem1', 'data': u"First blog entry"},
+               {'name': name + u'/NewBlogEntryItem2', 'data': u"Second blog entry"},
+               {'name': name + u'/NewBlogEntryItem3', 'data': u"Third blog entry"},
+               {'name': name + u'/NewBlogEntryItem4', 'data': u"Fourth blog entry"}, ]
+    entry_meta = {CONTENTTYPE: contenttype, ITEMTYPE: ITEMTYPE_BLOG_ENTRY}
+
+    def test_create(self):
+        item = Item.create(self.name, itemtype=ITEMTYPE_BLOG)
+        item._save(self.meta, self.data, comment=self.comment)
+        # check save result
+        item = Item.create(self.name)
+        assert isinstance(item, Blog)
+        assert item.itemtype == ITEMTYPE_BLOG
+        assert item.meta[CONTENTTYPE] == self.contenttype
+
+    def test_do_show_empty(self):
+        item = Item.create(self.name, itemtype=ITEMTYPE_BLOG)
+        item._save(self.meta, self.data, comment=self.comment)
+        # empty blog page without any entries
+        data_tokens = [self.data, self.NO_ENTRIES_MSG, ]
+        self._test_view(self.name, data_tokens=data_tokens)
+
+    def test_do_show_entries(self):
+        item = Item.create(self.name, itemtype=ITEMTYPE_BLOG)
+        item._save(self.meta, self.data, comment=self.comment)
+        # store some unpublished entries
+        for entry in self.entries:
+            item = Item.create(entry['name'], itemtype=ITEMTYPE_BLOG_ENTRY)
+            item._save(self.entry_meta, entry['data'], comment=self.comment)
+        # still empty blog
+        data_tokens = [self.data, self.NO_ENTRIES_MSG, ]
+        self._test_view(self.name, data_tokens=data_tokens)
+        # publish the first three entries
+        entry_meta = self.entry_meta.copy()
+        entry_meta[PTIME] = 1000 # unix timestamp
+        update_item(self.entries[0]['name'], entry_meta, self.entries[0]['data'])
+        entry_meta[PTIME] = 3000
+        update_item(self.entries[1]['name'], entry_meta, self.entries[1]['data'])
+        entry_meta[PTIME] = 2000
+        update_item(self.entries[2]['name'], entry_meta, self.entries[2]['data'])
+        # the blog is not empty and the 4th entry is not published
+        exclude_data_tokens = [self.NO_ENTRIES_MSG, self.entries[3]['data'], ]
+        self._test_view(self.name, exclude_data_tokens=exclude_data_tokens)
+        # blog entries are published in reverse order relative to their PTIMEs
+        ordered_data = [self.data,
+                        self.entries[1]['data'],
+                        self.entries[2]['data'],
+                        self.entries[0]['data'], ]
+        regex = re.compile(r'{0}.*{1}.*{2}.*{3}'.format(*ordered_data), re.DOTALL)
+        self._test_view(self.name, regex=regex)
+
+    def test_entries_acls(self):
+        item = Item.create(self.name, itemtype=ITEMTYPE_BLOG)
+        item._save(self.meta, self.data, comment=self.comment)
+        # store some unpublished entries
+        for entry in self.entries:
+            item = Item.create(entry['name'], itemtype=ITEMTYPE_BLOG_ENTRY)
+            item._save(self.entry_meta, entry['data'], comment=self.comment)
+        # publish the first three entries with specific ACLs
+        entry_meta = self.entry_meta.copy()
+        entry_meta[PTIME] = 1000 # unix timestamp
+        # we are "anonymous"
+        entry_meta[ACL] = u"anonymous:read"
+        update_item(self.entries[0]['name'], entry_meta, self.entries[0]['data'])
+        entry_meta[PTIME] = 3000
+        entry_meta[ACL] = u"anonymous:read"
+        update_item(self.entries[1]['name'], entry_meta, self.entries[1]['data'])
+        entry_meta[PTIME] = 2000
+        # specify no rights on the 3rd entry
+        entry_meta[ACL] = u"anonymous:"
+        update_item(self.entries[2]['name'], entry_meta, self.entries[2]['data'])
+        # the blog is not empty and the 3rd entry is not displayed
+        exclude_data_tokens = [self.NO_ENTRIES_MSG, self.entries[2]['data'], ]
+        self._test_view(self.name, exclude_data_tokens=exclude_data_tokens)
+        ordered_data = [self.data,
+                        self.entries[1]['data'],
+                        self.entries[0]['data'], ]
+        regex = re.compile(r'{0}.*{1}.*{2}'.format(*ordered_data), re.DOTALL)
+        self._test_view(self.name, regex=regex)
+
+
+class TestBlogEntry(TestView):
+    blog_name = u'NewBlogItem'
+    contenttype = u'text/x.moin.wiki'
+    blog_data = u"This is the header item of this blog"
+    blog_meta = {CONTENTTYPE: contenttype, ITEMTYPE: ITEMTYPE_BLOG}
+    comment = u'saved it'
+    entry_name = blog_name + u'/NewBlogEntryItem'
+    entry_data = u"Blog entry data"
+    entry_meta = {CONTENTTYPE: contenttype, ITEMTYPE: ITEMTYPE_BLOG_ENTRY}
+
+    def test_create(self):
+        # create a blog item
+        item = Item.create(self.blog_name, itemtype=ITEMTYPE_BLOG)
+        item._save(self.blog_meta, self.blog_data, comment=self.comment)
+        # create a blog entry item
+        item = Item.create(self.entry_name, itemtype=ITEMTYPE_BLOG_ENTRY)
+        item._save(self.entry_meta, self.entry_data, comment=self.comment)
+        # check save result
+        item = Item.create(self.entry_name)
+        assert isinstance(item, BlogEntry)
+        assert item.itemtype == ITEMTYPE_BLOG_ENTRY
+        assert item.meta[CONTENTTYPE] == self.contenttype
+
+    def test_do_show(self):
+        # create a blog item
+        item = Item.create(self.blog_name, itemtype=ITEMTYPE_BLOG)
+        item._save(self.blog_meta, self.blog_data, comment=self.comment)
+        # create a blog entry item
+        item = Item.create(self.entry_name, itemtype=ITEMTYPE_BLOG_ENTRY)
+        item._save(self.entry_meta, self.entry_data, comment=self.comment)
+
+        data_tokens = [self.blog_data, self.entry_data, ]
+        self._test_view(self.entry_name, data_tokens=data_tokens)

MoinMoin/static/css/stylus/ticket.styl

+#moin-ticket-form
+    dd
+        width 80%
+        margin-top 0.1em
+        input
+            width auto
+    dt
+        width 15%
+        margin-top 0.1em

MoinMoin/static/css/ticket.css

+#moin-ticket-form dd{width:80%;margin-top:.1em;}
+#moin-ticket-form dd input{width:auto}
+#moin-ticket-form dt{width:15%;margin-top:.1em}
+

MoinMoin/templates/blog_layout.html

     {% endif %}
     <h1><a href="{{ url_for('frontend.show_item', item_name=entry_item.name) }}"
         title="{{ title }}" class="moin-blog-entry-link">{{ title }}</a></h1>
+    {% if user.may.write(entry_item.name) %}
+        <div class="moin-blog-entry-modify">
+            <span class="moin-blog-icon">&#x2710;</span>
+            <a href="{{ url_for('frontend.modify_item', item_name=entry_item.name) }}">{{ _("Modify entry") }}</a>
+        </div>
+    {% endif %}
     <div class="moin-blog-entry-info">
         {% set publish_time = entry_item.meta['ptime'] %}
         {% if publish_time %}
                     {{ blog_header }}
                 {% endif %}
             </div>
-            <div id="moin-blog-content">
-            {% block blog_content %}<br />{% endblock %}
+            <div id="moin-blog-body">
+                <div id="moin-blog-content">
+                {% block blog_content %}<br />{% endblock %}
+                </div>
+                {% if blog_name and supertags %}
+                    <div id="moin-blog-sidebar">
+                        {{ widget_supertags(blog_name, supertags) }}
+                    </div>
+                {% endif %}
             </div>
-            {% if blog_name and supertags %}
-                <div id="moin-blog-sidebar">
-                    {{ widget_supertags(blog_name, supertags) }}
-                </div>
-            {% endif %}
         </div>
     {% endblock %}
 {% endblock %}

MoinMoin/templates/forms.html

 {% macro _valued_label(field, value, contents=none) %}
   {# XXX Patch <label>'s `for` attribute with value when element referred to is
      checkbox or radio. See: https://bitbucket.org/jek/flatland/issue/9 #}
-  {{ gen.label(field, for='f_{0}_{1}'.format(field.flattened_name(), value), contents=contents) }}
+  {{ gen.label(field, for='f_{0}_{1}'.format(field.flattened_name(), value), contents=contents, **kwargs) }}
 {% endmacro %}
 
 {% macro _checkbox_label(field) %}
-  {{ _valued_label(field, '1') }}
+  {{ _valued_label(field, '1', **kwargs) }}
 {% endmacro %}
 
 {% macro _radio_label(field, value) %}
-  {{ _valued_label(field, value, value) }}
+  {{ _valued_label(field, value, value, **kwargs) }}
 {% endmacro %}
 
 {% macro inline_checkbox(field) %}
   {{ raw_input(field, 'checkbox') }}
-  {{ _checkbox_label(field) }}
+  {{ _checkbox_label(field, class='moin-inline-label') }}
   {{ render_errors(field) }}
   {% if field.properties.helper is defined %}
     <span class="helper-text">
 {% endmacro %}
 
 {% macro small_natural(field) %}
-    {{ gen.label(field) }}
+    <dt>
+        {{ gen.label(field) }}
+    </dt>
     <dd>
         {% for i in range(field.properties.lower, field.properties.upper+1) %}
             {{ gen.input(field, type='radio', value=i|string) }}
-            {{ _radio_label(field, value=i|string) }}
+            {{ _radio_label(field, value=i|string, class='moin-inline-label') }}
         {% endfor %}
     </dd>
 {% endmacro %}

MoinMoin/templates/ticket.html

     {% set title = _("Ticket: %(item_name)s", item_name=item_name) %}
 {% endif %}
 
+{% block head %}
+    {{ super() }}
+    <link media="all" rel="stylesheet" href="{{ url_for('static', filename='css/ticket.css') }}" />
+{% endblock %}
+
 {% block content %}
 <h1>{{ title }}</h1>
-<div class="moin-form">
+<div class="moin-form" id="moin-ticket-form">
     {{ gen.form.open(form, method='post', enctype='multipart/form-data') }}
 
     {% if data_rendered %}

MoinMoin/themes/foobar/static/css/common.css

 article, aside, canvas, details, figcaption, figure, footer, header, hgroup,
 menu, nav, section, summary, time, mark, audio,
 video { margin: 0; padding: 0; border: 0; outline: 0;
-          font-size: 100%; vertical-align: baseline; background: transparent; }
+            font-size: 100%; vertical-align: baseline; background: transparent; }
 body { line-height: 1; }
 article, aside, details, figcaption, figure, footer, header, hgroup, menu, nav,
 section { display: block; }
 .moin-history-rename:before{content:url("../img/moin-renamed.png")}
 .moin-history-copy:before{content:url("../img/moin-new.png")}
 .moin-integer{width:2%}
+.moin-inline-label{display:inline}
 .moin-history-links{width:5%;}
 .moin-history-links a{display:block}
 .moin-history-editortext,.moin-history-links span,.moin-history-comment span{color:#d6d5d0;display:block;margin-bottom:5px}
 ol.moin-lowerroman-list{list-style-type:lower-roman}
 ul.moin-tags{list-style:none;}
 ul.moin-tags li{display:inline;}
-ul.moin-tags li.weight0{font-size:.4822530864197532em}
+ul.moin-tags li.weight0{font-size:.4822530864197531em}
 ul.moin-tags li.weight1{font-size:.5787037037037037em}
-ul.moin-tags li.weight2{font-size:.6944444444444445em}
+ul.moin-tags li.weight2{font-size:.6944444444444444em}
 ul.moin-tags li.weight3{font-size:.8333333333333334em}
 ul.moin-tags li.weight4{font-size:1em}
 ul.moin-tags li.weight5{font-size:1.2em}
 ul.moin-tags li.weight6{font-size:1.44em}
-ul.moin-tags li.weight7{font-size:1.7279999999999998em}
+ul.moin-tags li.weight7{font-size:1.728em}
 ul.moin-tags li.weight8{font-size:2.0736em}
-ul.moin-tags li.weight9{font-size:2.4883199999999994em}
-h1{font-size:1.7279999999999998em;margin:.5787037037037038em 0;border-bottom:3px solid #ccc;padding-bottom:3px}
+ul.moin-tags li.weight9{font-size:2.48832em}
+h1{font-size:1.728em;margin:.5787037037037037em 0;border-bottom:3px solid #ccc;padding-bottom:3px}
 h2{font-size:1.44em;margin:.6944444444444444em 0;border-bottom:3px solid #ccc;padding-bottom:3px}
 h3{font-size:1.2em;margin:.8333333333333334em 0;border-bottom:2px solid #ccc;padding-bottom:2px}
 h4{font-size:1em;margin:1em 0;border-bottom:2px solid #ccc;padding-bottom:2px}
 h5{font-size:.8333333333333334em;margin:1.2em 0;border-bottom:1px solid #ccc;padding-bottom:1px}
-h6{font-size:.6944444444444445em;margin:1.4399999999999997em 0;border-bottom:1px solid #ccc;padding-bottom:1px}
+h6{font-size:.6944444444444444em;margin:1.44em 0;border-bottom:1px solid #ccc;padding-bottom:1px}
 a.permalink{display:none;cursor:pointer;margin-left:.1em;color:#616161;}
 a.permalink:hover{color:#000}
 h1:hover .permalink,h2:hover .permalink,h3:hover .permalink,h4:hover .permalink,h5:hover .permalink,h6:hover .permalink{display:inline;text-decoration:none}

MoinMoin/themes/foobar/static/css/stylus/main.styl

 .moin-integer
     width 2%
 
+.moin-inline-label
+    display inline
+
 .moin-history-links
     width 5%
     a

MoinMoin/themes/modernized/static/css/common.css

 /*
 /* common.css - MoinMoin Default Styles
 
-  Copyright: 2001, 2002, 2003 MoinMoin:JuergenHermann
-  Copyright: 2010 MoinMoin:DiogenesAugusto
-  Copyright: 2010 MoinMoin:RogerHaase
-  License: GNU GPL v2 or later, see COPYING for details.
+    Copyright: 2001, 2002, 2003 MoinMoin:JuergenHermann
+    Copyright: 2010 MoinMoin:DiogenesAugusto
+    Copyright: 2010 MoinMoin:RogerHaase
+    License: GNU GPL v2 or later, see COPYING for details.
 */
 /*
 Copied from:  http://code.google.com/p/html5resetcss/
 article, aside, canvas, details, figcaption, figure, footer, header, hgroup,
 menu, nav, section, summary, time, mark, audio,
 video { margin: 0; padding: 0; border: 0; outline: 0;
-          font-size: 100%; vertical-align: baseline; background: transparent; }
+            font-size: 100%; vertical-align: baseline; background: transparent; }
 body { line-height: 1; }
 article, aside, details, figcaption, figure, footer, header, hgroup, menu, nav,
 section { display: block; }
 .moin-big{font-size:1.17em}
 .moin-small{font-size:.83em}
 .moin-integer{text-align:right;padding-right:1em}
+.moin-inline-label{display:inline}
 h1{font-size:2em;margin:.67em 0;border-bottom:5px solid #4e7da9;padding-bottom:5px}
 h2{font-size:1.5em;margin:.75em 0;padding-bottom:4px}
 h3{font-size:1.17em;margin:.83em 0;padding-bottom:3px}
 .moin-hist-rev input{float:left}
 .moin-hist-rev{margin:0}
 #moin-blog-header{margin:1em 0 -1em 0}
-#moin-blog-content{padding:0 2em 0 0;display:table-cell}
-#moin-blog-sidebar{width:15em;display:table-cell}
+#moin-blog-body{display:table;width:100%}
+#moin-blog-content{padding:0 2em 0 0;display:table-cell;width:80%}
+#moin-blog-sidebar{display:table-cell;width:20%}
+.moin-blog-icon{font-size:1.6em}
 .moin-blog-entry-info{font-size:.8em;color:#737373}
 .moin-blog-entry-bottominfo{font-size:.8em;color:#737373;padding:0 1em;border:1px solid #4e7da9}
+.moin-blog-entry-modify{font-size:.8em;margin:0;float:right}
 ul.moin-blog-entry-tags{list-style:none;display:inline;margin:0;}
 ul.moin-blog-entry-tags li{display:inline;}
 ul.moin-blog-entry-tags li:after{content:","}

MoinMoin/themes/modernized/static/css/stylus/main.styl

     text-align right
     padding-right 1em
 
+.moin-inline-label
+    display inline
+
 h1
     font-size 2em
     margin .67em 0
 #moin-blog-header
     margin 1em 0 -1em 0
 
+#moin-blog-body
+    display table
+    width 100%
+
 #moin-blog-content
     padding 0 2em 0 0
     display table-cell
+    width 80%
 
 #moin-blog-sidebar
-    width 15em
     display table-cell
+    width 20%
+
+.moin-blog-icon
+    font-size 1.6em
 
 .moin-blog-entry-info
     font-size 0.8em
     padding 0em 1em
     border border_style
 
+.moin-blog-entry-modify
+    font-size 0.8em
+    margin 0
+    float right
+
 ul.moin-blog-entry-tags
     list-style none
     display inline