Browse Source

Admin forms moved to floppyforms. #114

Rafał Pitoń 12 years ago
parent
commit
4b45a5ac11

+ 0 - 17
misago/apps/admin/bans/forms.py

@@ -24,23 +24,6 @@ class BanForm(Form):
     expires = forms.DateField(label=_("Ban Expiration"),
     						  help_text=_("If you want to, you can set this ban's expiration date by entering it here using YYYY-MM-DD format. Otherwhise you can leave this field empty making this ban permanent."),
     						  required=False)
-    layout = (
-               (
-                 _("Ban Details"),
-                 (
-                  ('nested', (('test', {'label': _("Ban Rule"), 'help_text': _("Select ban type from list and define rule by entering it in text field. If you want to ban specific user, enter here either his Username or E-mail address. If you want to define blanket ban, you can use wildcard (\"*\"). For example to forbid all members from using name suggesting that member is an admin, you can set ban that forbids \"Admin*\" as username."), 'width': 25}),
-                  ('ban', {'width': 75}))),
-                  ('expires', {'label': _("Ban Expiration"), 'help_text': _("If you want to, you can set this ban's expiration date by entering it here using YYYY-MM-DD format. Otherwhise you can leave this field empty making this ban permanent.")}),
-                 ),
-                ),
-                (
-                 _("Ban Message"),
-                 (
-                  ('reason_user', {'label': _("User-visible Ban Message"), 'help_text': _("Optional Ban message that will be displayed to banned members.")}),
-                  ('reason_admin', {'label': _("Team-visible Ban Message"), 'help_text': _("Optional Ban message that will be displayed to forum team members.")}),
-                 ),
-                ),
-               )
 
 
 class SearchBansForm(Form):

+ 30 - 42
misago/apps/admin/ranks/forms.py

@@ -6,53 +6,41 @@ from misago.models import Role
 from misago.validators import validate_sluggable
 
 class RankForm(Form):
-    name = forms.CharField(max_length=255, validators=[validate_sluggable(
+    name = forms.CharField(label=_("Rank Name"),
+    					   help_text=_("Rank Name is used to identify rank in Admin Control Panel and is used as page and tab title if you decide to make this rank act as tab on users list."),
+    					   max_length=255, validators=[validate_sluggable(
                                                                           _("Rank name must contain alphanumeric characters."),
                                                                           _("Rank name is too long.")
                                                                           )])
-    description = forms.CharField(widget=forms.Textarea, required=False)
-    title = forms.CharField(max_length=255, required=False)
-    style = forms.CharField(max_length=255, required=False)
-    special = forms.BooleanField(widget=YesNoSwitch, required=False)
-    as_tab = forms.BooleanField(widget=YesNoSwitch, required=False)
-    on_index = forms.BooleanField(widget=YesNoSwitch, required=False)
-    criteria = forms.CharField(max_length=255, initial='0', validators=[RegexValidator(regex='^(\d+)(%?)$', message=_('This is incorrect rank match rule.'))], required=False)
+    description = forms.CharField(label=_("Rank Description"),
+    							  help_text=_("If this rank acts as tab on users list, here you can enter optional description that will be displayed above list of users with this rank."),
+    							  widget=forms.Textarea, required=False)
+    title = forms.CharField(label=_("Rank Title"),
+    						help_text=_("Short description of rank's bearer role in your community."),
+    						max_length=255, required=False)
+    style = forms.CharField(label=_("Rank CSS Class"),
+    						help_text=_("Optional CSS class that will be added to different elements displaying rank's owner or his content, allowing you to make them stand out from other members."),
+    						max_length=255, required=False)
+    special = forms.BooleanField(label=_("Special Rank"),
+    							 help_text=_("Special ranks are ignored during updates of user ranking, making them unattainable without admin ingerention."),
+    							 widget=YesNoSwitch, required=False)
+    as_tab = forms.BooleanField(label=_("As Tab on Users List"),
+    							help_text=_("Should this rank have its own page on users list, containing rank's description and list of users that have it? This is good option for rank used by forum team members or members that should be visible and easily reachable."),
+    							widget=YesNoSwitch, required=False)
+    on_index = forms.BooleanField(label=_("Display members online"),
+    							  help_text=_("Should users online with this rank be displayed on board index?"),
+    							  widget=YesNoSwitch, required=False)
+    criteria = forms.CharField(label=_("Rank Criteria"),
+    						   help_text=_("This setting allows you to limit number of users that can attain this rank. Enter 0 to assign this rank to all members (good for default rank). To give this rank to 10% of most active members, enter \"10%\". To give this rank to 10 most active members, enter \"10\". This setting is ignored for special ranks as they don't participate in user's ranking updates."),
+    						   max_length=255, initial='0', validators=[RegexValidator(regex='^(\d+)(%?)$', message=_('This is incorrect rank match rule.'))], required=False)
     roles = False
 
-    layout = (
-              (
-               _("Basic Rank Options"),
-               (
-                ('name', {'label': _("Rank Name"), 'help_text': _("Rank Name is used to identify rank in Admin Control Panel and is used as page and tab title if you decide to make this rank act as tab on users list.")}),
-                ('description', {'label': _("Rank Description"), 'help_text': _("If this rank acts as tab on users list, here you can enter optional description that will be displayed above list of users with this rank.")}),
-                ('as_tab', {'label': _("As Tab on Users List"), 'help_text': _("Should this rank have its own page on users list, containing rank's description and list of users that have it? This is good option for rank used by forum team members or members that should be visible and easily reachable.")}),
-                ('on_index', {'label': _("Display members online"), 'help_text': _("Should users online with this rank be displayed on board index?")}),
-                )
-               ),
-              (
-               _("Rank Roles"),
-               (
-                ('roles', {'label': _("Rank Roles"), 'help_text': _("You can grant users with this rank extra roles to serve either as rewards or signs of trust to active members.")}),
-                )
-               ),
-              (
-               _("Rank Looks"),
-               (
-                ('title', {'label': _("Rank Title"), 'help_text': _("Short description of rank's bearer role in your community.")}),
-                ('style', {'label': _("Rank CSS Class"), 'help_text': _("Optional CSS class that will be added to different elements displaying rank's owner or his content, allowing you to make them stand out from other members.")}),
-                )
-               ),
-              (
-               _("Rank Attainability"),
-               (
-                ('special', {'label': _("Special Rank"), 'help_text': _("Special ranks are ignored during updates of user ranking, making them unattainable without admin ingerention.")}),
-                ('criteria', {'label': _("Rank Criteria"), 'help_text': _("This setting allows you to limit number of users that can attain this rank. Enter 0 to assign this rank to all members (good for default rank). To give this rank to 10% of most active members, enter \"10%\". To give this rank to 10 most active members, enter \"10\". This setting is ignored for special ranks as they don't participate in user's ranking updates.")}),
-                ),
-               ),
-              )
-
     def finalize_form(self):
         if self.request.user.is_god():
-            self.fields['roles'] = forms.ModelMultipleChoiceField(widget=forms.CheckboxSelectMultiple, queryset=Role.objects.order_by('name').all(), required=False)
+            self.add_field('roles', forms.ModelMultipleChoiceField(label=_("Rank Roles"),
+            													   help_text=_("You can grant users with this rank extra roles to serve either as rewards or signs of trust to active members."),
+            			   										   widget=forms.CheckboxSelectMultiple, queryset=Role.objects.order_by('name').all(), required=False))
         else:
-            self.fields['roles'] = forms.ModelMultipleChoiceField(widget=forms.CheckboxSelectMultiple, queryset=Role.objects.filter(protected__exact=False).order_by('name').all(), required=False)
+            self.add_field('roles', forms.ModelMultipleChoiceField(label=_("Rank Roles"),
+            													   help_text=_("You can grant users with this rank extra roles to serve either as rewards or signs of trust to active members."),
+            			   										   widget=forms.CheckboxSelectMultiple, queryset=Role.objects.filter(protected__exact=False).order_by('name').all(), required=False))

+ 72 - 66
misago/apps/admin/users/forms.py

@@ -8,20 +8,46 @@ from misago.models import Rank, Role, User
 from misago.validators import validate_username, validate_password, validate_email
 
 class UserForm(Form):
-    username = forms.CharField(max_length=255)
-    title = forms.CharField(max_length=255, required=False)
-    rank = forms.ModelChoiceField(queryset=Rank.objects.order_by('order').all(), required=False, empty_label=_('No rank assigned'))
+    username = forms.CharField(label=_("Username"),
+                               help_text=_("Username is name under which user is known to other users. Between 3 and 15 characters, only letters and digits are allowed."),
+                               max_length=255)
+    title = forms.CharField(label=_("User Title"),
+                            help_text=_("To override user title with custom one, enter it here."),
+                            max_length=255, required=False)
+    rank = forms.ModelChoiceField(label=_("User Rank"),
+                                  help_text=_("This user rank."),
+                                  queryset=Rank.objects.order_by('order').all(), required=False, empty_label=_('No rank assigned'))
     roles = False
-    email = forms.EmailField(max_length=255)
-    new_password = forms.CharField(max_length=255, required=False, widget=forms.PasswordInput)
-    signature = forms.CharField(widget=forms.Textarea, required=False)
-    avatar_custom = forms.CharField(max_length=255, required=False)
-    avatar_ban = forms.BooleanField(widget=YesNoSwitch, required=False)
-    avatar_ban_reason_user = forms.CharField(widget=forms.Textarea, required=False)
-    avatar_ban_reason_admin = forms.CharField(widget=forms.Textarea, required=False)
-    signature_ban = forms.BooleanField(widget=YesNoSwitch, required=False)
-    signature_ban_reason_user = forms.CharField(widget=forms.Textarea, required=False)
-    signature_ban_reason_admin = forms.CharField(widget=forms.Textarea, required=False)
+    email = forms.EmailField(label=_("E-mail Address"),
+                             help_text=_("Member e-mail address."),
+                             max_length=255)
+    new_password = forms.CharField(label=_("Change User Password"),
+                                   help_text=_("If you wish to change user password, enter here new password. Otherwhise leave this field blank."),
+                                   max_length=255, required=False, widget=forms.PasswordInput)
+    avatar_custom = forms.CharField(label=_("Set Non-Standard Avatar"),
+                                    help_text=_("You can make this member use special avatar by entering name of image file located in avatars directory here."),
+                                    max_length=255, required=False)
+    avatar_ban = forms.BooleanField(label=_("Lock Member's Avatar"),
+                                    help_text=_("If you set this field to yes, this member's avatar will be deleted and replaced with random one selected from _removed gallery and member will not be able to change his avatar."),
+                                    widget=YesNoSwitch, required=False)
+    avatar_ban_reason_user = forms.CharField(label=_("User-visible reason for lock"),
+                                             help_text=_("You can leave message to member explaining why he or she is unable to change his avatar anymore. This message will be displayed to member in his control panel."),
+                                             widget=forms.Textarea, required=False)
+    avatar_ban_reason_admin = forms.CharField(label=_("Forum Team-visible reason for lock"),
+                                              help_text=_("You can leave message to other forum team members exmplaining why this member's avatar has been locked."),
+                                              widget=forms.Textarea, required=False)
+    signature = forms.CharField(label=_("Signature"),
+                                help_text=_("Signature is short message attached at end of member's messages."),
+                                widget=forms.Textarea, required=False)
+    signature_ban = forms.BooleanField(label=_("Lock Member's Signature"),
+                                       help_text=_("If you set this field to yes, this member will not be able to change his signature."),
+                                       widget=YesNoSwitch, required=False)
+    signature_ban_reason_user = forms.CharField(label=_("User-visible reason for lock"),
+                                                help_text=_("You can leave message to member explaining why he or she is unable to edit his signature anymore. This message will be displayed to member in his control panel."),
+                                                widget=forms.Textarea, required=False)
+    signature_ban_reason_admin = forms.CharField(label=_("Forum Team-visible reason for lock"),
+                                                 help_text=_("You can leave message to other forum team members exmplaining why this member's signature has been locked."),
+                                                 widget=forms.Textarea, required=False)
 
     def __init__(self, user=None, *args, **kwargs):
         self.request = kwargs['request']
@@ -68,15 +94,18 @@ class UserForm(Form):
 
         # Roles list
         if self.request.user.is_god():
-            self.fields['roles'] = forms.ModelMultipleChoiceField(widget=forms.CheckboxSelectMultiple, queryset=Role.objects.order_by('name').all(), error_messages={'required': _("User must have at least one role assigned.")})
+            self.add_field('roles', forms.ModelMultipleChoiceField(label=_("User Roles"),
+                                                                   help_text=_("This user roles. Roles are sets of user permissions"),
+                                                                   widget=forms.CheckboxSelectMultiple, queryset=Role.objects.order_by('name').all(), error_messages={'required': _("User must have at least one role assigned.")}))
         else:
-            self.fields['roles'] = forms.ModelMultipleChoiceField(widget=forms.CheckboxSelectMultiple, queryset=Role.objects.filter(protected__exact=False).order_by('name').all(), required=False)
+            self.add_field('roles', forms.ModelMultipleChoiceField(label=_("User Roles"),
+                                                                   help_text=_("This user roles. Roles are sets of user permissions"),
+                                                                   widget=forms.CheckboxSelectMultiple, queryset=Role.objects.filter(protected__exact=False).order_by('name').all(), required=False))
 
         # Keep non-gods from editing protected members sign-in credentials
         if self.user.is_protected() and not self.request.user.is_god() and self.user.pk != self.request.user.pk:
             del self.fields['email']
             del self.fields['new_password']
-            del self.layout[1]
 
     def clean_username(self):
         org_username = self.user.username
@@ -119,42 +148,32 @@ class UserForm(Form):
 
 
 class NewUserForm(Form):
-    username = forms.CharField(max_length=255)
-    title = forms.CharField(max_length=255, required=False)
-    rank = forms.ModelChoiceField(queryset=Rank.objects.order_by('order').all(), required=False, empty_label=_('No rank assigned'))
+    username = forms.CharField(label=_("Username"),
+                               help_text=_("Username is name under which user is known to other users. Between 3 and 15 characters, only letters and digits are allowed."),
+                               max_length=255)
+    title = forms.CharField(label=_("User Title"),
+                            help_text=_("To override user title with custom one, enter it here."),
+                            max_length=255, required=False)
+    rank = forms.ModelChoiceField(label=_("User Rank"),
+                                  help_text=_("This user rank."),
+                                  queryset=Rank.objects.order_by('order').all(), required=False, empty_label=_('No rank assigned'))
     roles = False
-    email = forms.EmailField(max_length=255)
-    password = forms.CharField(max_length=255, widget=forms.PasswordInput)
-
-    layout = [
-              [
-               _("Basic Account Settings"),
-               [
-                ('username', {'label': _("Username"), 'help_text': _("Username is name under which user is known to other users. Between 3 and 15 characters, only letters and digits are allowed.")}),
-                ('title', {'label': _("User Title"), 'help_text': _("To override user title with custom one, enter it here.")}),
-                ('rank', {'label': _("User Rank"), 'help_text': _("This user rank.")}),
-                ('roles', {'label': _("User Roles"), 'help_text': _("This user roles. Roles are sets of user permissions")}),
-                ],
-               ],
-              [
-               _("Sign-in Credentials"),
-               [
-                ('email', {'label': _("E-mail Address"), 'help_text': _("Member e-mail address.")}),
-                ('password', {'label': _("User Password"), 'help_text': _("Member password."), 'has_value': False}),
-                ],
-               ],
-              ]
-
-    def __init__(self, *args, **kwargs):
-        self.request = kwargs['request']
+    email = forms.EmailField(label=_("E-mail Address"),
+                             help_text=_("Member e-mail address."),
+                             max_length=255)
+    password = forms.CharField(label=_("User Password"),
+                               help_text=_("Member password."),
+                               max_length=255, widget=forms.PasswordInput)
 
-        # Roles list
+    def finalize_form(self):
         if self.request.user.is_god():
-            self.base_fields['roles'] = forms.ModelMultipleChoiceField(widget=forms.CheckboxSelectMultiple, queryset=Role.objects.order_by('name').all(), error_messages={'required': _("User must have at least one role assigned.")})
+            self.add_field('roles', forms.ModelMultipleChoiceField(label=_("User Roles"),
+                                                                   help_text=_("This user roles. Roles are sets of user permissions"),
+                                                                   widget=forms.CheckboxSelectMultiple, queryset=Role.objects.order_by('name').all(), error_messages={'required': _("User must have at least one role assigned.")}))
         else:
-            self.base_fields['roles'] = forms.ModelMultipleChoiceField(widget=forms.CheckboxSelectMultiple, queryset=Role.objects.filter(protected__exact=False).order_by('name').all(), required=False)
-
-        super(NewUserForm, self).__init__(*args, **kwargs)
+            self.add_field('roles', forms.ModelMultipleChoiceField(label=_("User Roles"),
+                                                                   help_text=_("This user roles. Roles are sets of user permissions"),
+                                                                   widget=forms.CheckboxSelectMultiple, queryset=Role.objects.filter(protected__exact=False).order_by('name').all(), required=False))
 
     def clean_username(self):
         validate_username(self.cleaned_data['username'])
@@ -187,21 +206,8 @@ class NewUserForm(Form):
 
 
 class SearchUsersForm(Form):
-    username = forms.CharField(max_length=255, required=False)
-    email = forms.CharField(max_length=255, required=False)
-    activation = forms.TypedMultipleChoiceField(widget=forms.CheckboxSelectMultiple, choices=((0, _("Already Active")), (1, _("By User")), (2, _("By Administrator"))), coerce=int, required=False)
-    rank = forms.ModelMultipleChoiceField(widget=forms.CheckboxSelectMultiple, queryset=Rank.objects.order_by('order').all(), required=False)
-    role = forms.ModelMultipleChoiceField(widget=forms.CheckboxSelectMultiple, queryset=Role.objects.order_by('name').all(), required=False)
-
-    layout = (
-              (
-               _("Search Users"),
-               (
-                ('username', {'label': _("Username"), 'attrs': {'placeholder': _("Username contains...")}}),
-                ('email', {'label': _("E-mail Address"), 'attrs': {'placeholder': _("E-mail address contains...")}}),
-                ('activation', {'label': _("Activation Requirement")}),
-                ('rank', {'label': _("Rank is")}),
-                ('role', {'label': _("Has Role")}),
-                ),
-               ),
-              )
+    username = forms.CharField(label=_("Username"), max_length=255, required=False)
+    email = forms.CharField(label=_("E-mail Address"), max_length=255, required=False)
+    activation = forms.TypedMultipleChoiceField(label=_("Activation Requirement"), widget=forms.CheckboxSelectMultiple, choices=((0, _("Already Active")), (1, _("By User")), (2, _("By Administrator"))), coerce=int, required=False)
+    rank = forms.ModelMultipleChoiceField(label=_("Rank is"), widget=forms.CheckboxSelectMultiple, queryset=Rank.objects.order_by('order').all(), required=False)
+    role = forms.ModelMultipleChoiceField(label=_("Has Role"), widget=forms.CheckboxSelectMultiple, queryset=Role.objects.order_by('name').all(), required=False)

+ 373 - 373
misago/apps/admin/users/views.py

@@ -1,373 +1,373 @@
-from django.core.urlresolvers import reverse as django_reverse
-from django.db.models import Q
-from django.shortcuts import redirect
-from django.utils.translation import ugettext as _
-from misago.admin import site
-from misago.apps.admin.widgets import *
-from misago.conf import settings
-from misago.markdown import signature_markdown
-from misago.models import Forum, User
-from misago.monitor import monitor, UpdatingMonitor
-from misago.utils.strings import random_string
-from misago.apps.admin.users.forms import UserForm, NewUserForm, SearchUsersForm
-
-def reverse(route, target=None):
-    if target:
-        return django_reverse(route, kwargs={'target': target.pk, 'slug': target.username_slug})
-    return django_reverse(route)
-
-
-"""
-Views
-"""
-class List(ListWidget):
-    admin = site.get_action('users')
-    id = 'list'
-    columns = (
-               ('username_slug', _("User Name"), 35),
-               ('join_date', _("Join Date")),
-               )
-    default_sorting = 'username'
-    sortables = {
-                 'username_slug': 1,
-                 'join_date': 0,
-                }
-    pagination = 25
-    search_form = SearchUsersForm
-    nothing_checked_message = _('You have to check at least one user.')
-    actions = (
-               ('activate', _("Activate users"), _("Are you sure you want to activate selected members?")),
-               ('deactivate', _("Request e-mail validation"), _("Are you sure you want to deactivate selected members and request them to revalidate their e-mail addresses?")),
-               ('remove_av', _("Remove and lock avatars"), _("Are you sure you want to remove selected members avatars and their ability to change them?")),
-               ('remove_sig', _("Remove and lock signatures"), _("Are you sure you want to remove selected members signatures and their ability to edit them?")),
-               ('remove_locks', _("Remove locks from avatars and signatures"), _("Are you sure you want to remove locks from selected members avatars and signatures?")),
-               ('reset', _("Reset passwords"), _("Are you sure you want to reset selected members passwords?")),
-               ('delete_content', _("Delete users with content"), _("Are you sure you want to delete selected users and their content?")),
-               ('delete', _("Delete users"), _("Are you sure you want to delete selected users?")),
-               )
-
-    def set_filters(self, model, filters):
-        if 'role' in filters:
-            model = model.filter(roles__in=filters['role']).distinct()
-        if 'rank' in filters:
-            model = model.filter(rank__in=filters['rank'])
-        if 'username' in filters:
-            if ',' in filters['username']:
-                qs = None
-                for name in filters['username'].split(','):
-                    name = name.strip().lower()
-                    if name:
-                        if qs:
-                            qs = qs | Q(username_slug__contains=name)
-                        else:
-                            qs = Q(username_slug__contains=name)
-                if qs:
-                    model = model.filter(qs)
-            else:
-                model = model.filter(username_slug__contains=filters['username'])
-        if 'email' in filters:
-            if ',' in filters['email']:
-                qs = None
-                for name in filters['email'].split(','):
-                    name = name.strip().lower()
-                    if name:
-                        if qs:
-                            qs = qs | Q(email__contains=name)
-                        else:
-                            qs = Q(email__contains=name)
-                if qs:
-                    model = model.filter(qs)
-            else:
-                model = model.filter(email__contains=filters['email'])
-        if 'activation' in filters:
-            model = model.filter(activation__in=filters['activation'])
-        return model
-
-    def prefetch_related(self, items):
-        return items.prefetch_related('roles')
-
-    def get_item_actions(self, item):
-        return (
-                self.action('pencil', _("Edit User Details"), reverse('admin_users_edit', item)),
-                self.action('remove', _("Delete User"), reverse('admin_users_delete', item), post=True, prompt=_("Are you sure you want to delete this user account?")),
-                )
-
-    def action_activate(self, items, checked):
-        for user in items:
-            if user.pk in checked and user.activation > 0:
-                with UpdatingMonitor() as cm:
-                    monitor.decrease('users_inactive')
-                user.activation = user.ACTIVATION_NONE
-                user.save(force_update=True)
-                user.email_user(
-                                self.request,
-                                'users/activation/admin_done',
-                                _("Your Account has been activated"),
-                                )
-
-        return Message(_('Selected users accounts have been activated.'), 'success'), reverse('admin_users')
-
-    def action_deactivate(self, items, checked):
-        # First loop - check for errors
-        for user in items:
-            if user.pk in checked:
-                if user.is_protected() and not self.request.user.is_god():
-                    return Message(_('You cannot force validation of protected members e-mails.'), 'error'), reverse('admin_users')
-
-        # Second loop - reset passwords
-        for user in items:
-            if user.pk in checked:
-                user.activation = user.ACTIVATION_USER
-                user.token = token = random_string(12)
-                user.save(force_update=True)
-                user.email_user(
-                                self.request,
-                                'users/activation/invalidated',
-                                _("Account Activation"),
-                                )
-
-        return Message(_('Selected users accounts have been deactivated and new activation links have been sent to them.'), 'success'), reverse('admin_users')
-
-    def action_remove_av(self, items, checked):
-        # First loop - check for errors
-        for user in items:
-            if user.pk in checked:
-                if user.is_protected() and not self.request.user.is_god():
-                    return Message(_('You cannot remove and block protected members avatars.'), 'error'), reverse('admin_users')
-
-        # Second loop - reset passwords
-        for user in items:
-            if user.pk in checked:
-                user.lock_avatar()
-                user.save(force_update=True)
-
-        return Message(_('Selected users avatars were deleted and locked.'), 'success'), reverse('admin_users')
-
-    def action_remove_sig(self, items, checked):
-        # First loop - check for errors
-        for user in items:
-            if user.pk in checked:
-                if user.is_protected() and not self.request.user.is_god():
-                    return Message(_('You cannot remove and block protected members signatures.'), 'error'), reverse('admin_users')
-
-        # Second loop - reset passwords
-        for user in items:
-            if user.pk in checked:
-                user.signature_ban = True
-                user.signature = ''
-                user.signature_preparsed = ''
-                user.save(force_update=True)
-
-        return Message(_('Selected users signatures were deleted and locked.'), 'success'), reverse('admin_users')
-
-    def action_remove_locks(self, items, checked):
-        for user in items:
-            if user.pk in checked:
-                user.default_avatar()
-                user.avatar_ban = False
-                user.signature_ban = False
-                user.save(force_update=True)
-
-        return Message(_('Selected users can now edit their avatars and signatures.'), 'success'), reverse('admin_users')
-
-    def action_reset(self, items, checked):
-        # First loop - check for errors
-        for user in items:
-            if user.pk in checked:
-                if user.is_protected() and not self.request.user.is_god():
-                    return Message(_('You cannot reset protected members passwords.'), 'error'), reverse('admin_users')
-
-        # Second loop - reset passwords
-        for user in items:
-            if user.pk in checked:
-                new_password = random_string(8)
-                user.set_password(new_password)
-                user.save(force_update=True)
-                user.email_user(
-                                self.request,
-                                'users/password/new_admin',
-                                _("Your New Password"),
-                                {
-                                 'password': new_password,
-                                 },
-                                )
-
-        return Message(_('Selected users passwords have been reset successfully.'), 'success'), reverse('admin_users')
-
-    def action_delete_content(self, items, checked):
-        for user in items:
-            if user.pk in checked:
-                if user.pk == self.request.user.id:
-                    return Message(_('You cannot delete yourself.'), 'error'), reverse('admin_users')
-                if user.is_protected():
-                    return Message(_('You cannot delete protected members.'), 'error'), reverse('admin_users')
-
-        for user in items:
-            if user.pk in checked:
-                user.delete_content()
-                user.delete()
-
-        for forum in Forum.objects.all():
-            forum.sync()
-            forum.save(force_update=True)
-        
-        User.objects.resync_monitor()
-        return Message(_('Selected users and their content have been deleted successfully.'), 'success'), reverse('admin_users')
-
-    def action_delete(self, items, checked):
-        for user in items:
-            if user.pk in checked:
-                if user.pk == self.request.user.id:
-                    return Message(_('You cannot delete yourself.'), 'error'), reverse('admin_users')
-                if user.is_protected():
-                    return Message(_('You cannot delete protected members.'), 'error'), reverse('admin_users')
-
-        for user in items:
-            if user.pk in checked:
-                user.delete()
-
-        User.objects.resync_monitor()
-        return Message(_('Selected users have been deleted successfully.'), 'success'), reverse('admin_users')
-
-
-class New(FormWidget):
-    admin = site.get_action('users')
-    id = 'new'
-    fallback = 'admin_users'
-    form = NewUserForm
-    submit_button = _("Save User")
-
-    def get_new_link(self, model):
-        return reverse('admin_users_new')
-
-    def get_edit_link(self, model):
-        return reverse('admin_users_edit', model)
-
-    def submit_form(self, form, target):
-        new_user = User.objects.create_user(
-                                            form.cleaned_data['username'],
-                                            form.cleaned_data['email'],
-                                            form.cleaned_data['password'],
-                                            settings.default_timezone,
-                                            self.request.META['REMOTE_ADDR'],
-                                            no_roles=True,
-                                            request=self.request,
-                                            )
-        new_user.title = form.cleaned_data['title']
-        new_user.rank = form.cleaned_data['rank']
-
-        for role in form.cleaned_data['roles']:
-            new_user.roles.add(role)
-        new_user.make_acl_key(True)
-        new_user.save(force_update=True)
-
-        return new_user, Message(_('New User has been created.'), 'success')
-
-
-class Edit(FormWidget):
-    admin = site.get_action('users')
-    id = 'edit'
-    name = _("Edit User")
-    fallback = 'admin_users'
-    form = UserForm
-    tabbed = True
-    target_name = 'username'
-    notfound_message = _('Requested User could not be found.')
-    submit_fallback = True
-
-    def get_form_instance(self, form, model, initial, post=False):
-        if post:
-            return form(model, self.request.POST, request=self.request, initial=self.get_initial_data(model))
-        return form(model, request=self.request, initial=self.get_initial_data(model))
-
-    def get_link(self, model):
-        return reverse('admin_users_edit', model)
-
-    def get_edit_link(self, model):
-        return self.get_link(model)
-
-    def get_initial_data(self, model):
-        return {
-                'username': model.username,
-                'title': model.title,
-                'email': model.email,
-                'rank': model.rank,
-                'roles': model.roles.all(),
-                'avatar_ban': model.avatar_ban,
-                'avatar_ban_reason_user': model.avatar_ban_reason_user,
-                'avatar_ban_reason_admin': model.avatar_ban_reason_admin,
-                'signature': model.signature,
-                'signature_ban': model.signature_ban,
-                'signature_ban_reason_user': model.signature_ban_reason_user,
-                'signature_ban_reason_admin': model.signature_ban_reason_admin,
-                }
-
-    def submit_form(self, form, target):
-        target.title = form.cleaned_data['title']
-        target.rank = form.cleaned_data['rank']
-        target.avatar_ban_reason_user = form.cleaned_data['avatar_ban_reason_user']
-        target.avatar_ban_reason_admin = form.cleaned_data['avatar_ban_reason_admin']
-        target.signature_ban = form.cleaned_data['signature_ban']
-        target.signature_ban_reason_user = form.cleaned_data['signature_ban_reason_user']
-        target.signature_ban_reason_admin = form.cleaned_data['signature_ban_reason_admin']
-
-        # Sync username?
-        if target.username != self.original_name:
-            target.sync_username()
-
-        # Do signature mumbo-jumbo
-        if form.cleaned_data['signature']:
-            target.signature = form.cleaned_data['signature']
-            target.signature_preparsed = signature_markdown(target.acl(self.request),
-                                                            form.cleaned_data['signature'])
-        else:
-            target.signature = None
-            target.signature_preparsed = None
-
-        # Do avatar ban mumbo-jumbo
-        if target.avatar_ban != form.cleaned_data['avatar_ban']:
-            if form.cleaned_data['avatar_ban']:
-                target.lock_avatar()
-            else:
-                target.default_avatar()
-        target.avatar_ban = form.cleaned_data['avatar_ban']
-
-        # Set custom avatar
-        if form.cleaned_data['avatar_custom']:
-            target.delete_avatar()
-            target.avatar_image = form.cleaned_data['avatar_custom']
-            target.avatar_type = 'gallery'
-
-        # Update user roles
-        if self.request.user.is_god():
-            target.roles.clear()
-        else:
-            target.roles.remove(*target.roles.filter(protected=False))
-        for role in form.cleaned_data['roles']:
-            target.roles.add(role)
-
-        target.make_acl_key(True)
-        target.save(force_update=True)
-        return target, Message(_('Changes in user\'s "%(name)s" account have been saved.') % {'name': self.original_name}, 'success')
-
-
-class Delete(ButtonWidget):
-    admin = site.get_action('users')
-    id = 'delete'
-    fallback = 'admin_users'
-    notfound_message = _('Requested User account could not be found.')
-
-    def action(self, target):
-        if target.pk == self.request.user.id:
-            return Message(_('You cannot delete yourself.'), 'error'), False
-        if target.is_protected():
-            return Message(_('You cannot delete protected member.'), 'error'), False
-        target.delete()
-        User.objects.resync_monitor()
-        return Message(_('User "%(name)s" has been deleted.') % {'name': target.username}, 'success'), False
-
-
-def inactive(request):
-    token = 'list_filter_users.User'
-    request.session[token] = {'activation': [1, 2, 3]}
-    return redirect(reverse('admin_users'))
+from django.core.urlresolvers import reverse as django_reverse
+from django.db.models import Q
+from django.shortcuts import redirect
+from django.utils.translation import ugettext as _
+from misago.admin import site
+from misago.apps.admin.widgets import *
+from misago.conf import settings
+from misago.markdown import signature_markdown
+from misago.models import Forum, User
+from misago.monitor import monitor, UpdatingMonitor
+from misago.utils.strings import random_string
+from misago.apps.admin.users.forms import UserForm, NewUserForm, SearchUsersForm
+
+def reverse(route, target=None):
+    if target:
+        return django_reverse(route, kwargs={'target': target.pk, 'slug': target.username_slug})
+    return django_reverse(route)
+
+
+"""
+Views
+"""
+class List(ListWidget):
+    admin = site.get_action('users')
+    id = 'list'
+    columns = (
+               ('username_slug', _("User Name"), 35),
+               ('join_date', _("Join Date")),
+               )
+    default_sorting = 'username'
+    sortables = {
+                 'username_slug': 1,
+                 'join_date': 0,
+                }
+    pagination = 25
+    search_form = SearchUsersForm
+    nothing_checked_message = _('You have to check at least one user.')
+    actions = (
+               ('activate', _("Activate users"), _("Are you sure you want to activate selected members?")),
+               ('deactivate', _("Request e-mail validation"), _("Are you sure you want to deactivate selected members and request them to revalidate their e-mail addresses?")),
+               ('remove_av', _("Remove and lock avatars"), _("Are you sure you want to remove selected members avatars and their ability to change them?")),
+               ('remove_sig', _("Remove and lock signatures"), _("Are you sure you want to remove selected members signatures and their ability to edit them?")),
+               ('remove_locks', _("Remove locks from avatars and signatures"), _("Are you sure you want to remove locks from selected members avatars and signatures?")),
+               ('reset', _("Reset passwords"), _("Are you sure you want to reset selected members passwords?")),
+               ('delete_content', _("Delete users with content"), _("Are you sure you want to delete selected users and their content?")),
+               ('delete', _("Delete users"), _("Are you sure you want to delete selected users?")),
+               )
+
+    def set_filters(self, model, filters):
+        if 'role' in filters:
+            model = model.filter(roles__in=filters['role']).distinct()
+        if 'rank' in filters:
+            model = model.filter(rank__in=filters['rank'])
+        if 'username' in filters:
+            if ',' in filters['username']:
+                qs = None
+                for name in filters['username'].split(','):
+                    name = name.strip().lower()
+                    if name:
+                        if qs:
+                            qs = qs | Q(username_slug__contains=name)
+                        else:
+                            qs = Q(username_slug__contains=name)
+                if qs:
+                    model = model.filter(qs)
+            else:
+                model = model.filter(username_slug__contains=filters['username'])
+        if 'email' in filters:
+            if ',' in filters['email']:
+                qs = None
+                for name in filters['email'].split(','):
+                    name = name.strip().lower()
+                    if name:
+                        if qs:
+                            qs = qs | Q(email__contains=name)
+                        else:
+                            qs = Q(email__contains=name)
+                if qs:
+                    model = model.filter(qs)
+            else:
+                model = model.filter(email__contains=filters['email'])
+        if 'activation' in filters:
+            model = model.filter(activation__in=filters['activation'])
+        return model
+
+    def prefetch_related(self, items):
+        return items.prefetch_related('roles')
+
+    def get_item_actions(self, item):
+        return (
+                self.action('pencil', _("Edit User Details"), reverse('admin_users_edit', item)),
+                self.action('remove', _("Delete User"), reverse('admin_users_delete', item), post=True, prompt=_("Are you sure you want to delete this user account?")),
+                )
+
+    def action_activate(self, items, checked):
+        for user in items:
+            if user.pk in checked and user.activation > 0:
+                with UpdatingMonitor() as cm:
+                    monitor.decrease('users_inactive')
+                user.activation = user.ACTIVATION_NONE
+                user.save(force_update=True)
+                user.email_user(
+                                self.request,
+                                'users/activation/admin_done',
+                                _("Your Account has been activated"),
+                                )
+
+        return Message(_('Selected users accounts have been activated.'), 'success'), reverse('admin_users')
+
+    def action_deactivate(self, items, checked):
+        # First loop - check for errors
+        for user in items:
+            if user.pk in checked:
+                if user.is_protected() and not self.request.user.is_god():
+                    return Message(_('You cannot force validation of protected members e-mails.'), 'error'), reverse('admin_users')
+
+        # Second loop - reset passwords
+        for user in items:
+            if user.pk in checked:
+                user.activation = user.ACTIVATION_USER
+                user.token = token = random_string(12)
+                user.save(force_update=True)
+                user.email_user(
+                                self.request,
+                                'users/activation/invalidated',
+                                _("Account Activation"),
+                                )
+
+        return Message(_('Selected users accounts have been deactivated and new activation links have been sent to them.'), 'success'), reverse('admin_users')
+
+    def action_remove_av(self, items, checked):
+        # First loop - check for errors
+        for user in items:
+            if user.pk in checked:
+                if user.is_protected() and not self.request.user.is_god():
+                    return Message(_('You cannot remove and block protected members avatars.'), 'error'), reverse('admin_users')
+
+        # Second loop - reset passwords
+        for user in items:
+            if user.pk in checked:
+                user.lock_avatar()
+                user.save(force_update=True)
+
+        return Message(_('Selected users avatars were deleted and locked.'), 'success'), reverse('admin_users')
+
+    def action_remove_sig(self, items, checked):
+        # First loop - check for errors
+        for user in items:
+            if user.pk in checked:
+                if user.is_protected() and not self.request.user.is_god():
+                    return Message(_('You cannot remove and block protected members signatures.'), 'error'), reverse('admin_users')
+
+        # Second loop - reset passwords
+        for user in items:
+            if user.pk in checked:
+                user.signature_ban = True
+                user.signature = ''
+                user.signature_preparsed = ''
+                user.save(force_update=True)
+
+        return Message(_('Selected users signatures were deleted and locked.'), 'success'), reverse('admin_users')
+
+    def action_remove_locks(self, items, checked):
+        for user in items:
+            if user.pk in checked:
+                user.default_avatar()
+                user.avatar_ban = False
+                user.signature_ban = False
+                user.save(force_update=True)
+
+        return Message(_('Selected users can now edit their avatars and signatures.'), 'success'), reverse('admin_users')
+
+    def action_reset(self, items, checked):
+        # First loop - check for errors
+        for user in items:
+            if user.pk in checked:
+                if user.is_protected() and not self.request.user.is_god():
+                    return Message(_('You cannot reset protected members passwords.'), 'error'), reverse('admin_users')
+
+        # Second loop - reset passwords
+        for user in items:
+            if user.pk in checked:
+                new_password = random_string(8)
+                user.set_password(new_password)
+                user.save(force_update=True)
+                user.email_user(
+                                self.request,
+                                'users/password/new_admin',
+                                _("Your New Password"),
+                                {
+                                 'password': new_password,
+                                 },
+                                )
+
+        return Message(_('Selected users passwords have been reset successfully.'), 'success'), reverse('admin_users')
+
+    def action_delete_content(self, items, checked):
+        for user in items:
+            if user.pk in checked:
+                if user.pk == self.request.user.id:
+                    return Message(_('You cannot delete yourself.'), 'error'), reverse('admin_users')
+                if user.is_protected():
+                    return Message(_('You cannot delete protected members.'), 'error'), reverse('admin_users')
+
+        for user in items:
+            if user.pk in checked:
+                user.delete_content()
+                user.delete()
+
+        for forum in Forum.objects.all():
+            forum.sync()
+            forum.save(force_update=True)
+
+        User.objects.resync_monitor()
+        return Message(_('Selected users and their content have been deleted successfully.'), 'success'), reverse('admin_users')
+
+    def action_delete(self, items, checked):
+        for user in items:
+            if user.pk in checked:
+                if user.pk == self.request.user.id:
+                    return Message(_('You cannot delete yourself.'), 'error'), reverse('admin_users')
+                if user.is_protected():
+                    return Message(_('You cannot delete protected members.'), 'error'), reverse('admin_users')
+
+        for user in items:
+            if user.pk in checked:
+                user.delete()
+
+        User.objects.resync_monitor()
+        return Message(_('Selected users have been deleted successfully.'), 'success'), reverse('admin_users')
+
+
+class New(FormWidget):
+    admin = site.get_action('users')
+    id = 'new'
+    fallback = 'admin_users'
+    form = NewUserForm
+    template = 'new'
+    submit_button = _("Save User")
+
+    def get_new_link(self, model):
+        return reverse('admin_users_new')
+
+    def get_edit_link(self, model):
+        return reverse('admin_users_edit', model)
+
+    def submit_form(self, form, target):
+        new_user = User.objects.create_user(
+                                            form.cleaned_data['username'],
+                                            form.cleaned_data['email'],
+                                            form.cleaned_data['password'],
+                                            settings.default_timezone,
+                                            self.request.META['REMOTE_ADDR'],
+                                            no_roles=True,
+                                            request=self.request,
+                                            )
+        new_user.title = form.cleaned_data['title']
+        new_user.rank = form.cleaned_data['rank']
+
+        for role in form.cleaned_data['roles']:
+            new_user.roles.add(role)
+        new_user.make_acl_key(True)
+        new_user.save(force_update=True)
+
+        return new_user, Message(_('New User has been created.'), 'success')
+
+
+class Edit(FormWidget):
+    admin = site.get_action('users')
+    id = 'edit'
+    name = _("Edit User")
+    fallback = 'admin_users'
+    form = UserForm
+    target_name = 'username'
+    notfound_message = _('Requested User could not be found.')
+    submit_fallback = True
+
+    def get_form_instance(self, form, model, initial, post=False):
+        if post:
+            return form(model, self.request.POST, request=self.request, initial=self.get_initial_data(model))
+        return form(model, request=self.request, initial=self.get_initial_data(model))
+
+    def get_link(self, model):
+        return reverse('admin_users_edit', model)
+
+    def get_edit_link(self, model):
+        return self.get_link(model)
+
+    def get_initial_data(self, model):
+        return {
+                'username': model.username,
+                'title': model.title,
+                'email': model.email,
+                'rank': model.rank,
+                'roles': model.roles.all(),
+                'avatar_ban': model.avatar_ban,
+                'avatar_ban_reason_user': model.avatar_ban_reason_user,
+                'avatar_ban_reason_admin': model.avatar_ban_reason_admin,
+                'signature': model.signature,
+                'signature_ban': model.signature_ban,
+                'signature_ban_reason_user': model.signature_ban_reason_user,
+                'signature_ban_reason_admin': model.signature_ban_reason_admin,
+                }
+
+    def submit_form(self, form, target):
+        target.title = form.cleaned_data['title']
+        target.rank = form.cleaned_data['rank']
+        target.avatar_ban_reason_user = form.cleaned_data['avatar_ban_reason_user']
+        target.avatar_ban_reason_admin = form.cleaned_data['avatar_ban_reason_admin']
+        target.signature_ban = form.cleaned_data['signature_ban']
+        target.signature_ban_reason_user = form.cleaned_data['signature_ban_reason_user']
+        target.signature_ban_reason_admin = form.cleaned_data['signature_ban_reason_admin']
+
+        # Sync username?
+        if target.username != self.original_name:
+            target.sync_username()
+
+        # Do signature mumbo-jumbo
+        if form.cleaned_data['signature']:
+            target.signature = form.cleaned_data['signature']
+            target.signature_preparsed = signature_markdown(target.acl(self.request),
+                                                            form.cleaned_data['signature'])
+        else:
+            target.signature = None
+            target.signature_preparsed = None
+
+        # Do avatar ban mumbo-jumbo
+        if target.avatar_ban != form.cleaned_data['avatar_ban']:
+            if form.cleaned_data['avatar_ban']:
+                target.lock_avatar()
+            else:
+                target.default_avatar()
+        target.avatar_ban = form.cleaned_data['avatar_ban']
+
+        # Set custom avatar
+        if form.cleaned_data['avatar_custom']:
+            target.delete_avatar()
+            target.avatar_image = form.cleaned_data['avatar_custom']
+            target.avatar_type = 'gallery'
+
+        # Update user roles
+        if self.request.user.is_god():
+            target.roles.clear()
+        else:
+            target.roles.remove(*target.roles.filter(protected=False))
+        for role in form.cleaned_data['roles']:
+            target.roles.add(role)
+
+        target.make_acl_key(True)
+        target.save(force_update=True)
+        return target, Message(_('Changes in user\'s "%(name)s" account have been saved.') % {'name': self.original_name}, 'success')
+
+
+class Delete(ButtonWidget):
+    admin = site.get_action('users')
+    id = 'delete'
+    fallback = 'admin_users'
+    notfound_message = _('Requested User account could not be found.')
+
+    def action(self, target):
+        if target.pk == self.request.user.id:
+            return Message(_('You cannot delete yourself.'), 'error'), False
+        if target.is_protected():
+            return Message(_('You cannot delete protected member.'), 'error'), False
+        target.delete()
+        User.objects.resync_monitor()
+        return Message(_('User "%(name)s" has been deleted.') % {'name': target.username}, 'success'), False
+
+
+def inactive(request):
+    token = 'list_filter_users.User'
+    request.session[token] = {'activation': [1, 2, 3]}
+    return redirect(reverse('admin_users'))

+ 26 - 0
templates/admin/ranks/form.html

@@ -0,0 +1,26 @@
+{% extends "admin/admin/form.html" %}
+{% import "forms.html" as form_theme with context %}
+
+{% block form %}
+<fieldset>
+  <legend>{% trans %}Basic Rank Options{% endtrans %}</legend>
+  {{ form_theme.row(form.name, attrs={'class': 'span12'}) }}
+  {{ form_theme.row(form.description, attrs={'class': 'span12', 'rows': 3}) }}
+  {{ form_theme.row(form.as_tab) }}
+  {{ form_theme.row(form.on_index) }}
+</fieldset>
+<fieldset>
+  <legend>{% trans %}Rank Roles{% endtrans %}</legend>
+  {{ form_theme.row(form.roles, attrs={'class': 'span12'}) }}
+</fieldset>
+<fieldset>
+  <legend>{% trans %}Rank Looks{% endtrans %}</legend>
+  {{ form_theme.row(form.title, attrs={'class': 'span12'}) }}
+  {{ form_theme.row(form.style, attrs={'class': 'span12'}) }}
+</fieldset>
+<fieldset>
+  <legend>{% trans %}Rank Attainability{% endtrans %}</legend>
+  {{ form_theme.row(form.special) }}
+  {{ form_theme.row(form.criteria, attrs={'class': 'span12'}) }}
+</fieldset>
+{% endblock %}

+ 3 - 3
templates/admin/ranks/list.html

@@ -1,5 +1,5 @@
 {% extends "admin/admin/list.html" %}
-{% import "_forms.html" as form_theme with context %}
+{% import "forms.html" as form_theme with context %}
 
 {% block table_head scoped %}
   {{ super() }}
@@ -11,6 +11,6 @@
   	<strong>{{ _(item.name) }}</strong>{% if item.special %} <span class="label label-info">{% trans %}Special{% endtrans %}</span>{% endif %}{% if item.as_tab %} <span class="label label-inverse">{% trans %}Tab{% endtrans %}</span>{% endif %}{% if item.on_index %} <span class="label label-orange">{% trans %}On Index{% endtrans %}</span>{% endif %}
   </td>
   <td class="span2">
-  	{{ form_theme.field_widget(table_form['pos_' + item.pk|string], attrs={'form': 'table_form'}, width=2) }}
+  	{{ form_theme.field(table_form['pos_' + item.pk|string], attrs={'form': 'table_form', 'class': 'span2'}) }}
   </td>
-{% endblock%}
+{% endblock%}

+ 31 - 0
templates/admin/users/form.html

@@ -0,0 +1,31 @@
+{% extends "admin/admin/form.html" %}
+{% import "forms.html" as form_theme with context %}
+
+{% block form %}
+<fieldset>
+  <legend>{% trans %}Basic Account Settings{% endtrans %}</legend>
+  {{ form_theme.row(form.username, attrs={'class': 'span12'}) }}
+  {{ form_theme.row(form.title, attrs={'class': 'span12'}) }}
+  {{ form_theme.row(form.rank, attrs={'class': 'span12'}) }}
+  {{ form_theme.row(form.roles, attrs={'class': 'span12'}) }}
+</fieldset>
+<fieldset>
+  <legend>{% trans %}Sign-in Credentials{% endtrans %}</legend>
+  {{ form_theme.row(form.email, attrs={'class': 'span12'}) }}
+  {{ form_theme.row(form.new_password, attrs={'class': 'span12'}) }}
+</fieldset>
+<fieldset>
+  <legend>{% trans %}User Avatar{% endtrans %}</legend>
+  {{ form_theme.row(form.avatar_custom, attrs={'class': 'span12'}) }}
+  {{ form_theme.row(form.avatar_ban) }}
+  {{ form_theme.row(form.avatar_ban_reason_user, attrs={'class': 'span12', 'rows': 4}) }}
+  {{ form_theme.row(form.avatar_ban_reason_admin, attrs={'class': 'span12', 'rows': 4}) }}
+</fieldset>
+<fieldset>
+  <legend>{% trans %}User Signature{% endtrans %}</legend>
+  {{ form_theme.row(form.signature, attrs={'class': 'span12', 'rows': 4}) }}
+  {{ form_theme.row(form.signature_ban) }}
+  {{ form_theme.row(form.signature_ban_reason_user, attrs={'class': 'span12', 'rows': 4}) }}
+  {{ form_theme.row(form.signature_ban_reason_admin, attrs={'class': 'span12', 'rows': 4}) }}
+</fieldset>
+{% endblock %}

+ 8 - 0
templates/admin/users/list.html

@@ -33,3 +33,11 @@
 	{{ item.join_date|date("DATETIME_FORMAT") }}
   </td>
 {% endblock%}
+
+{% block search_form %}
+{{ form_theme.row(search_form.username, attrs={'class': 'span3', 'placeholder': _("Username contains...")}) }}
+{{ form_theme.row(search_form.email, attrs={'class': 'span3', 'placeholder': _("E-mail address contains...")}) }}
+{{ form_theme.row(search_form.activation, attrs={'class': 'span3'}) }}
+{{ form_theme.row(search_form.rank, attrs={'class': 'span3'}) }}
+{{ form_theme.row(search_form.role, attrs={'class': 'span3'}) }}
+{% endblock %}

+ 17 - 0
templates/admin/users/new.html

@@ -0,0 +1,17 @@
+{% extends "admin/admin/form.html" %}
+{% import "forms.html" as form_theme with context %}
+
+{% block form %}
+<fieldset>
+  <legend>{% trans %}Basic Account Settings{% endtrans %}</legend>
+  {{ form_theme.row(form.username, attrs={'class': 'span12'}) }}
+  {{ form_theme.row(form.title, attrs={'class': 'span12'}) }}
+  {{ form_theme.row(form.rank, attrs={'class': 'span12'}) }}
+  {{ form_theme.row(form.roles, attrs={'class': 'span12'}) }}
+</fieldset>
+<fieldset>
+  <legend>{% trans %}Sign-in Credentials{% endtrans %}</legend>
+  {{ form_theme.row(form.email, attrs={'class': 'span12'}) }}
+  {{ form_theme.row(form.password, attrs={'class': 'span12'}) }}
+</fieldset>
+{% endblock %}