Просмотр исходного кода

- Dropped QATest functionality
- Implemented final banning functionality
- Small improvement in List admin widget - you may declare search_form = FORM attribute on List class instead of "get_search_form" method
- Markdown filter |markdown() implemented. It accepts one optional argument - HTML standard it should follow, which defaults to "html5"
- Form's template no longer uses dirty hack to count horizontal form inputs length's

Ralfp 12 лет назад
Родитель
Сommit
e1c85c2a73

+ 5 - 3
misago/admin/widgets.py

@@ -33,7 +33,7 @@ class BaseWidget(object):
         return obj(request, **kwargs)
         return obj(request, **kwargs)
     
     
     def get_token(self, token):
     def get_token(self, token):
-        return '%s_%s_%s' % (self.id, token, str('%s.%s' % (self.admin.model.__module__, self.admin.model.__class__.__name__)))
+        return '%s_%s_%s' % (self.id, token, str('%s.%s' % (self.admin.model.__module__, self.admin.model.__name__)))
         
         
     def get_url(self):
     def get_url(self):
         return reverse(self.admin.get_action_attr(self.id, 'route'))
         return reverse(self.admin.get_action_attr(self.id, 'route'))
@@ -49,6 +49,7 @@ class BaseWidget(object):
          
          
     def get_templates(self, template):
     def get_templates(self, template):
         return ('%s/%s/%s.html' % (str(self.admin.model.__module__).split('.')[1], str(self.admin.route).lower(), template),
         return ('%s/%s/%s.html' % (str(self.admin.model.__module__).split('.')[1], str(self.admin.route).lower(), template),
+                '%s/%s.html' % (str(self.admin.model.__module__).split('.')[1], template),
                 'admin/%s.html' % template)
                 'admin/%s.html' % template)
             
             
     def get_fallback_url(self, request):
     def get_fallback_url(self, request):
@@ -83,6 +84,7 @@ class ListWidget(BaseWidget):
     columns = []
     columns = []
     sortables = {}
     sortables = {}
     default_sorting = None
     default_sorting = None
+    search_form = None
     is_filtering = False
     is_filtering = False
     pagination = None
     pagination = None
     template = 'list'
     template = 'list'
@@ -117,7 +119,7 @@ class ListWidget(BaseWidget):
         """
         """
         Build a form object with items search
         Build a form object with items search
         """
         """
-        return None
+        return self.search_form
             
             
     def set_filters(self, model, filters):
     def set_filters(self, model, filters):
         """
         """
@@ -275,7 +277,7 @@ class ListWidget(BaseWidget):
                         message = BasicMessage(_("Search form contains errors."))
                         message = BasicMessage(_("Search form contains errors."))
                     message.type = 'error'
                     message.type = 'error'
                 else:
                 else:
-                        search_form = SearchForm(request=request)
+                    search_form = SearchForm(request=request)
                     
                     
                 # Kill search
                 # Kill search
                 if request.POST.get('origin') == 'clear' and self.is_filtering and request.csrf.request_secure(request):
                 if request.POST.get('origin') == 'clear' and self.is_filtering and request.csrf.request_secure(request):

+ 3 - 3
misago/auth/forms.py

@@ -29,12 +29,12 @@ class UserRegisterForm(Form):
     layout = [
     layout = [
                  (
                  (
                      None,
                      None,
-                     [('username', {'placeholder': _("Enter your desired username")})]
+                     [('username', {'attrs': {'placeholder': _("Enter your desired username")}})]
                  ),
                  ),
                  (
                  (
                      None,
                      None,
-                     [('nested', [('email', {'placeholder': _("Enter your e-mail"), 'width': 50}), ('email_rep', {'placeholder': _("Repeat your e-mail"), 'width': 50})]), 
-                      ('nested', [('password', {'has_value': False, 'placeholder': _("Enter your password"), 'width': 50}), ('password_rep', {'has_value': False, 'placeholder': _("Repeat your password"), 'width': 50})])]
+                     [('nested', [('email', {'label': _('E-mail address'), 'attrs': {'placeholder': _("Enter your e-mail")}, 'width': 50}), ('email_rep', {'attrs': {'placeholder': _("Repeat your e-mail")}, 'width': 50})]), 
+                      ('nested', [('password', {'label': _('Password'), 'has_value': False, 'attrs': {'placeholder': _("Enter your password")}, 'width': 50}), ('password_rep', {'has_value': False, 'attrs': {'placeholder': _("Repeat your password")}, 'width': 50})])]
                  ),
                  ),
                  (
                  (
                      None,
                      None,

+ 12 - 1
misago/banning/models.py

@@ -56,7 +56,18 @@ class BanCache(object):
         if (self.version < request.monitor['bans_version']
         if (self.version < request.monitor['bans_version']
             or (self.expires != None and self.expires < timezone.now())):
             or (self.expires != None and self.expires < timezone.now())):
             self.version = request.monitor['bans_version']
             self.version = request.monitor['bans_version']
-            ban = check_ban(ip=request.session.get_ip(request))
+            
+            # Check Ban
+            if request.user.is_authenticated():
+                ban = check_ban(
+                                ip=request.session.get_ip(request),
+                                username=request.user.username,
+                                email=request.user.email
+                                )
+            else:
+                ban = check_ban(ip=request.session.get_ip(request))
+                
+            # Update ban cache
             if ban:
             if ban:
                 self.banned = True
                 self.banned = True
                 self.reason = ban.reason_user
                 self.reason = ban.reason_user

+ 0 - 1
misago/forms/__init__.py

@@ -1,7 +1,6 @@
 from django import forms
 from django import forms
 from django.utils.translation import ugettext_lazy as _
 from django.utils.translation import ugettext_lazy as _
 from misago.forms.layouts import *
 from misago.forms.layouts import *
-from misago.security.models import QATest
 from recaptcha.client.captcha import submit as recaptcha_submit
 from recaptcha.client.captcha import submit as recaptcha_submit
 
 
 class Form(forms.Form):
 class Form(forms.Form):

+ 0 - 51
misago/security/admin/__init__.py

@@ -1,51 +0,0 @@
-from django.conf.urls import patterns, include, url
-from django.utils.translation import ugettext_lazy as _
-from misago.admin import AdminAction
-from misago.security.models import QATest
-
-ADMIN_ACTIONS=(
-   AdminAction(
-               section='system',
-               id='qa',
-               name=_("Q&A Tests"),
-               help=_("Question & Answer Tests"),
-               icon='question-sign',
-               model=QATest,
-               actions=[
-                        {
-                         'id': 'list',
-                         'icon': 'list-alt',
-                         'name': _("Browse Tests"),
-                         'help': _("Browse all Question & Answer Tests"),
-                         'route': 'admin_qa'
-                         },
-                        {
-                         'id': 'new',
-                         'icon': 'plus',
-                         'name': _("New Test"),
-                         'help': _("Crete new Q&A Test"),
-                         'route': 'admin_qa_new'
-                         },
-                        ],
-               route='admin_qa',
-               urlpatterns=patterns('misago.security.admin.qatest.views',
-                        url(r'^$', 'List', name='admin_qa'),
-                        url(r'^(?P<page>\d+)/$', 'List', name='admin_qa'),
-                        url(r'^new/$', 'New', name='admin_qa_new'),
-                        url(r'^edit/(?P<slug>([a-zA-Z0-9]|-)+)\.(?P<target>\d+)/$', 'Edit', name='admin_qa_edit'),
-                        url(r'^delete/(?P<slug>([a-zA-Z0-9]|-)+)\.(?P<target>\d+)/$', 'Delete', name='admin_qa_delete'),
-                    ),
-               after='settings',
-               ),
-   AdminAction(
-               section='system',
-               id='api',
-               name=_("API Keys"),
-               help=_("Connect other apps with your forums"),
-               icon='barcode',
-               route='admin_api',
-               urlpatterns=patterns('misago.security.admin.views',
-                        url(r'^$', 'api_list', name='admin_api'),
-                    ),
-               ),
-)

+ 0 - 0
misago/security/admin/qatest/__init__.py


+ 0 - 26
misago/security/admin/qatest/forms.py

@@ -1,26 +0,0 @@
-from django.utils.translation import ugettext_lazy as _
-from django import forms
-from misago.forms import Form
-
-class QATestForm(Form):
-    """
-    New/Edit QA Test form
-    """
-    question = forms.CharField(max_length=255)
-    helptext = forms.CharField(max_length=255, required=False)
-    answers = forms.CharField(widget=forms.Textarea)
-    layout = (
-               (
-                 _("Question and Help"),
-                 (
-                  ('question', {'label': _("Test Question"), 'help_text': _("Question that is displayed to user.")}),
-                  ('helptext', {'label': _("Test Help"), 'help_text': _("Optional help text that is displayed next to question.")}),
-                 ),
-                ),
-                (
-                 _("Answers"),
-                 (
-                  ('answers', {'label': _("Test Answers"), 'help_text': _("Enter accepted answers to this question. Every answer should be entered in new line. Answers are case-insensitive.")}),
-                 ),
-                ),
-               )

+ 0 - 0
misago/security/admin/qatest/helpers.py


+ 0 - 124
misago/security/admin/qatest/views.py

@@ -1,124 +0,0 @@
-from django.core.urlresolvers import reverse as django_reverse
-from django.utils.translation import ugettext as _
-from misago.admin import site
-from misago.admin.widgets import *
-from misago.utils import slugify
-from misago.security.admin.qatest.forms import QATestForm
-from misago.security.models import QATest
-
-def reverse(route, target=None):
-    if target:
-        return django_reverse(route, kwargs={'target': target.pk, 'slug': slugify(target.question)})
-    return django_reverse(route)
-
-"""
-Views
-"""
-class List(ListWidget):
-    """
-    List QA Tests
-    """
-    admin = site.get_action('qa')
-    id = 'list'
-    columns=(
-             ('question', _("Question"), 50),
-             ('helptext', _("Help")),
-             )
-    default_sorting = 'question'
-    sortables={
-               'question': 1,
-               'helptext': 1,
-              }
-    filters = ['question', 'helptext']
-    filters_layout = []
-    empty_message = _('No Question and Answer tests have been found. Change search criteria and try again.')
-    nothing_checked_message = _('You have to check at least one test.')
-    actions=(
-             ('delete', _("Delete selected"), _("Are you sure you want to delete selected questions?")),
-             )
-    
-    def get_item_actions(self, request, item):
-        return (
-                self.action('pencil', _("Edit Test"), reverse('admin_qa_edit', item)),
-                self.action('remove', _("Delete Test"), reverse('admin_qa_delete', item), post=True, prompt=_("Are you sure you want to delete this test?")),
-                )
-
-    def action_delete(self, request, items, checked):
-        QATest.objects.filter(id__in=checked).delete()
-        return BasicMessage(_('Selected Q&A Tests have been deleted successfully.'), 'success'), reverse('admin_qa')
-    
-
-class New(FormWidget):
-    """
-    Create New QA Test
-    """
-    admin = site.get_action('qa')
-    id = 'new'
-    fallback = 'admin_qa' 
-    form = QATestForm
-    submit_button = _("Save Test")
-        
-    def get_new_url(self, request, model):
-        return reverse('admin_qa_new')
-    
-    def get_edit_url(self, request, model):
-        return reverse('admin_qa_edit', model)
-    
-    def submit_form(self, request, form, target):
-        new_test = QATest(
-                          question=form.cleaned_data['question'],
-                          helptext=form.cleaned_data['helptext'],
-                          answers=form.cleaned_data['answers'],
-                          )
-        new_test.save(force_insert=True)
-        return new_test, BasicMessage(_('New Q&A Test "%(name)s" has been saved.' % {'name': form.cleaned_data['question']}), 'success')
-    
-   
-class Edit(FormWidget):
-    """
-    Edit QA Test
-    """
-    admin = site.get_action('qa')
-    id = 'edit'
-    name = _("Edit QA Test")
-    fallback = 'admin_qa'
-    form = QATestForm
-    target_name = 'question'
-    notfound_message = _('Requested Question and Answer test could not be found.')
-    submit_fallback = True
-    
-    def get_url(self, request, model):
-        return reverse('admin_qa_edit', model)
-    
-    def get_edit_url(self, request, model):
-        return self.get_url(request, model)
-    
-    def get_initial_data(self, request, model):
-        return {
-                'question': model.question,
-                'helptext': model.helptext,
-                'answers': model.answers,
-                }
-    
-    def submit_form(self, request, form, target):
-        old_question = target.question
-        target.question = form.cleaned_data['question']
-        target.helptext = form.cleaned_data['helptext']
-        target.answers = form.cleaned_data['answers']
-        target.save(force_update=True)
-        return target, BasicMessage(_('Changes in Q&A Test "%(name)s" have been saved.' % {'name': old_question}), 'success')
-
-
-class Delete(ButtonWidget):
-    """
-    Delete QA Test
-    """
-    admin = site.get_action('qa')
-    id = 'delete'
-    fallback = 'admin_qa'
-    notfound_message = _('Requested Question and Answer test could not be found.')
-    
-    def action(self, request, target):
-        target.delete()
-        return BasicMessage(_('Q&A Test "%(name)s" has been deleted.' % {'name': target.question}), 'success'), False
-        

+ 1 - 22
misago/security/models.py

@@ -51,25 +51,4 @@ class JamCache(object):
         return False
         return False
     
     
     def is_jammed(self):
     def is_jammed(self):
-        return self.jammed
-
- 
-"""
-Question-Answer Tests
-"""
-class QATestManager(models.Manager):
-    def random(self):
-        count = self.aggregate(count=models.Count('id'))['count']
-        random_index = randint(0, count - 1)
-        return self.all()[random_index]
-
-    
-class QATest(models.Model):
-    question = models.CharField(_("Question"),max_length=255)
-    helptext = models.TextField(null=True,blank=True)
-    answers = models.TextField()
-    
-    objects = QATestManager()
-    
-    def is_answer_correct(self, answer):
-        return unicode(answer).lower() in (name.lower() for name in unicode(self.answers).splitlines())
+        return self.jammed

+ 9 - 2
misago/template/templatetags/django2jinja.py

@@ -1,13 +1,20 @@
+import math
 import urllib
 import urllib
 from coffin.template import Library
 from coffin.template import Library
 register = Library()
 register = Library()
 
 
 @register.object(name='widthratio')
 @register.object(name='widthratio')
 def widthratio(min=0, max=100, range=100):
 def widthratio(min=0, max=100, range=100):
-    return int(float(min) / float(max) * int(range))
+    return int(math.ceil(float(float(min) / float(max) * int(range))))
 
 
 
 
 @register.object(name='query')
 @register.object(name='query')
 def query_string(**kwargs):
 def query_string(**kwargs):
     query = urllib.urlencode(kwargs)
     query = urllib.urlencode(kwargs)
-    return '?%s' % query if kwargs else ''
+    return '?%s' % (query if kwargs else '')
+
+
+@register.filter(name='markdown')
+def parse_markdown(value, format="html5"):
+    import markdown
+    return markdown.markdown(value, safe_mode='escape', output_format=format)

+ 23 - 2
misago/users/admin/__init__.py

@@ -1,6 +1,7 @@
 from django.conf.urls import patterns, include, url
 from django.conf.urls import patterns, include, url
 from django.utils.translation import ugettext_lazy as _
 from django.utils.translation import ugettext_lazy as _
 from misago.admin import AdminSection, AdminAction
 from misago.admin import AdminSection, AdminAction
+from misago.banning.models import Ban
 from misago.users.models import User
 from misago.users.models import User
 
 
 ADMIN_SECTIONS=(
 ADMIN_SECTIONS=(
@@ -60,9 +61,29 @@ ADMIN_ACTIONS=(
                name=_("Banning"),
                name=_("Banning"),
                help=_("Ban or unban users from forums."),
                help=_("Ban or unban users from forums."),
                icon='lock',
                icon='lock',
+               model=Ban,
+               actions=[
+                        {
+                         'id': 'list',
+                         'icon': 'list-alt',
+                         'name': _("Browse Bans"),
+                         'help': _("Browse all existing bans"),
+                         'route': 'admin_users_bans'
+                         },
+                        {
+                         'id': 'new',
+                         'icon': 'plus',
+                         'name': _("Set Ban"),
+                         'help': _("Set new Ban"),
+                         'route': 'admin_users_bans_new'
+                         },
+                        ],
                route='admin_users_bans',
                route='admin_users_bans',
-               urlpatterns=patterns('misago.admin.views',
-                        url(r'^$', 'todo', name='admin_users_bans'),
+               urlpatterns=patterns('misago.banning.admin.views',
+                        url(r'^$', 'List', name='admin_users_bans'),
+                        url(r'^new/$', 'New', name='admin_users_bans_new'),
+                        url(r'^edit/(?P<target>\d+)/$', 'Edit', name='admin_users_bans_edit'),
+                        url(r'^delete/(?P<target>\d+)/$', 'Delete', name='admin_users_bans_delete'),
                     ),
                     ),
                ),
                ),
    AdminAction(
    AdminAction(

+ 0 - 3
misago/users/admin/users/forms.py

@@ -3,9 +3,6 @@ from django import forms
 from misago.forms import Form
 from misago.forms import Form
 
 
 class SearchUsersForm(Form):
 class SearchUsersForm(Form):
-    """
-    Search Users
-    """
     username = forms.CharField(max_length=255, required=False)
     username = forms.CharField(max_length=255, required=False)
     email = forms.CharField(max_length=255, required=False)
     email = forms.CharField(max_length=255, required=False)
     activation = forms.MultipleChoiceField(widget=forms.CheckboxSelectMultiple,choices=(('0', _("Already Active")), ('1', _("By User")), ('2', _("By Administrator"))),required=False)
     activation = forms.MultipleChoiceField(widget=forms.CheckboxSelectMultiple,choices=(('0', _("Already Active")), ('1', _("By User")), ('2', _("By Administrator"))),required=False)

+ 2 - 4
misago/users/admin/users/views.py

@@ -29,7 +29,8 @@ class List(ListWidget):
                'username_slug': 1,
                'username_slug': 1,
                'join_date': 0,
                'join_date': 0,
               }
               }
-    pagination = 15
+    pagination = 25
+    search_form = SearchUsersForm
     nothing_checked_message = _('You have to check at least one user.')
     nothing_checked_message = _('You have to check at least one user.')
     actions=(
     actions=(
              ('reset', _("Reset passwords"), _("Are you sure you want to reset selected members passwords?")),
              ('reset', _("Reset passwords"), _("Are you sure you want to reset selected members passwords?")),
@@ -37,9 +38,6 @@ class List(ListWidget):
              ('delete', _("Delete selected"), _("Are you sure you want to delete selected users?")),
              ('delete', _("Delete selected"), _("Are you sure you want to delete selected users?")),
              )
              )
     
     
-    def get_search_form(self, request):
-        return SearchUsersForm
-    
     def set_filters(self, model, filters):
     def set_filters(self, model, filters):
         if 'username' in filters:
         if 'username' in filters:
             model = model.filter(username_slug__contains=filters['username'])
             model = model.filter(username_slug__contains=filters['username'])

+ 4 - 4
templates/_forms.html

@@ -101,7 +101,7 @@
 {%- macro input_date(field, attrs={}, classes=[], horizontal=false, width=12, nested=false) -%}
 {%- macro input_date(field, attrs={}, classes=[], horizontal=false, width=12, nested=false) -%}
 {%- do field.attrs.update(attrs) -%}
 {%- do field.attrs.update(attrs) -%}
 {%- if horizontal -%}
 {%- if horizontal -%}
-  {%- do classes.append('span' ~ widthratio(field.width, 140, width)) -%}
+  {%- do classes.append('span' ~ (widthratio(field.width, 100, width) - 2)) -%}
 {%- else -%}
 {%- else -%}
   {%- do classes.append('span' ~ widthratio(field.width, 100, width)) -%}
   {%- do classes.append('span' ~ widthratio(field.width, 100, width)) -%}
 {%- endif -%}
 {%- endif -%}
@@ -144,7 +144,7 @@ RECAPTCHA!
 {%- macro input_select(field, attrs={}, classes=[], horizontal=false, width=12, nested=false) -%}
 {%- macro input_select(field, attrs={}, classes=[], horizontal=false, width=12, nested=false) -%}
 {%- do field.attrs.update(attrs) -%}
 {%- do field.attrs.update(attrs) -%}
 {%- if horizontal %}
 {%- if horizontal %}
-  {%- do classes.append('span' ~ widthratio(field.width, 140, width)) -%}
+  {%- do classes.append('span' ~ (widthratio(field.width, 100, width) - 2)) -%}
 {%- else -%}
 {%- else -%}
   {%- do classes.append('span' ~ widthratio(field.width, 100, width)) -%}
   {%- do classes.append('span' ~ widthratio(field.width, 100, width)) -%}
 {%- endif -%}
 {%- endif -%}
@@ -158,7 +158,7 @@ RECAPTCHA!
 {%- macro input_text(field, attrs={}, classes=[], horizontal=false, width=12, nested=false) -%}
 {%- macro input_text(field, attrs={}, classes=[], horizontal=false, width=12, nested=false) -%}
 {%- do field.attrs.update(attrs) -%}
 {%- do field.attrs.update(attrs) -%}
 {%- if horizontal -%}
 {%- if horizontal -%}
-  {%- do classes.append('span' ~ widthratio(field.width, 140, width)) -%}
+  {%- do classes.append('span' ~ (widthratio(field.width, 100, width) - 2)) -%}
 {%- else -%}
 {%- else -%}
   {%- do classes.append('span' ~ widthratio(field.width, 100, width)) -%}
   {%- do classes.append('span' ~ widthratio(field.width, 100, width)) -%}
 {%- endif -%}
 {%- endif -%}
@@ -170,7 +170,7 @@ RECAPTCHA!
 {%- macro input_textarea(field, attrs={'rows': 4}, classes=[], horizontal=false, width=12, nested=false) -%}
 {%- macro input_textarea(field, attrs={'rows': 4}, classes=[], horizontal=false, width=12, nested=false) -%}
 {%- do field.attrs.update(attrs) -%}
 {%- do field.attrs.update(attrs) -%}
 {%- if horizontal -%}
 {%- if horizontal -%}
-  {%- do classes.append('span' ~ widthratio(field.width, 140, width)) -%}
+  {%- do classes.append('span' ~ (widthratio(field.width, 100, width) - 2)) -%}
 {%- else -%}
 {%- else -%}
   {%- do classes.append('span' ~ widthratio(field.width, 100, width)) -%}
   {%- do classes.append('span' ~ widthratio(field.width, 100, width)) -%}
 {%- endif -%}
 {%- endif -%}

+ 8 - 7
templates/_message/banned.html

@@ -2,17 +2,18 @@
 {% load i18n %}
 {% load i18n %}
 
 
 {% block content %}
 {% block content %}
-{% if message.user.is_authorized() %}
-  {% if message.ban.reason %}
-  <p>{% trans username=message.user.username %}{{ username }}, your account has been locked for following reason:{% endtrans %}</p>
-  <p>{{ message.ban.reason }}</p>
+{% if message.user.is_authenticated() %}
+  <div class="alert-icon"><span><i class="icon-remove icon-white"></i></span></div>
+  {% if message.ban.reason_user %}
+  <p>{% trans username=message.user.username %}{{ username }}, your account has been banned for following reason:{% endtrans %}</p>
+  {{ message.ban.reason_user|markdown|safe }}
   {% else %}
   {% else %}
-  <p>{% trans username=message.user.username %}{{ username }}, your account has been locked by board administrator.{% endtrans %}</p>
+  <p>{% trans username=message.user.username %}{{ username }}, your account has been banned by board administrator.{% endtrans %}</p>
   {% endif %}
   {% endif %}
 {% else %}
 {% else %}
-  {% if message.ban.reason %}
+  {% if message.ban.reason_user %}
   <p>{% trans %}Dear guest, your access to this page has been forbidden for following reason:{% endtrans %}</p>
   <p>{% trans %}Dear guest, your access to this page has been forbidden for following reason:{% endtrans %}</p>
-  <p>{{ message.ban.reason }}</p>
+  {{ message.ban.reason_user|markdown|safe }}
   {% else %}
   {% else %}
   <p>{% trans %}Dear guest, your access to this page has been forbidden.{% endtrans %}</p>
   <p>{% trans %}Dear guest, your access to this page has been forbidden.{% endtrans %}</p>
   {% endif %}
   {% endif %}

+ 1 - 1
templates/admin/admin/form.html

@@ -15,7 +15,7 @@
   	<button name="save_edit" type="submit" class="btn btn-warning">{% trans %}Save and Edit{% endtrans %}</button>
   	<button name="save_edit" type="submit" class="btn btn-warning">{% trans %}Save and Edit{% endtrans %}</button>
   	{%- endif %}
   	{%- endif %}
   	{% if action.get_new_url -%}
   	{% if action.get_new_url -%}
-  	<button name="save_new" type="submit" class="btn btn-success">{% trans %}Save and Add New{% endtrans %}</button>
+  	<button name="save_new" type="submit" class="btn btn-success">{% trans %}Save and Add Another{% endtrans %}</button>
   	{%- endif %}
   	{%- endif %}
   	{% if fallback %}<a href="{{ fallback }}" class="btn">{% trans %}Cancel{% endtrans %}</a>{% endif %}
   	{% if fallback %}<a href="{{ fallback }}" class="btn">{% trans %}Cancel{% endtrans %}</a>{% endif %}
   </div>
   </div>

+ 17 - 0
templates/admin/banning/list.html

@@ -0,0 +1,17 @@
+{% extends "admin/admin/list.html" %}
+{% load i18n %}
+{% load l10n %}
+{% load url from future %}
+
+{% block table_row scoped %}
+  <td class="lead-cell">
+  	<strong>{{ item.ban }}</strong> <span class="label {% if item.type == 0 -%}label-inverse">{% trans %}Username and E-mail{% endtrans %}
+  	{%- elif item.type == 1 -%}label-important">{% trans %}Username and E-mail{% endtrans %}
+  	{%- elif item.type == 2 -%}label-warning">{% trans %}Username{% endtrans %}
+  	{%- else -%}label-info">{% trans %}IP Address{% endtrans %}
+  	{%- endif %}</span>
+  </td>
+  <td>
+  	{% if item.expires %}{{ item.expires|date(f.DATE_FORMAT) }}{% else %}<em>{% trans %}Permanent ban{% endtrans %}</em>{% endif %}
+  </td>
+{% endblock%}