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

Ran pyDev formatters on Misago .py files.

Ralfp 12 лет назад
Родитель
Сommit
dc7004227a
177 измененных файлов с 1533 добавлено и 1544 удалено
  1. 6 6
      deployment/settings.py
  2. 1 1
      misago/__init__.py
  3. 6 6
      misago/acl/builder.py
  4. 1 1
      misago/acl/context_processors.py
  5. 1 1
      misago/acl/fixtures.py
  6. 2 2
      misago/acl/middleware.py
  7. 2 2
      misago/acl/panels.py
  8. 1 1
      misago/acl/utils.py
  9. 5 5
      misago/activation/forms.py
  10. 1 1
      misago/activation/urls.py
  11. 13 13
      misago/activation/views.py
  12. 31 31
      misago/admin/__init__.py
  13. 5 5
      misago/admin/acl.py
  14. 1 1
      misago/admin/context_processors.py
  15. 6 6
      misago/admin/fixtures.py
  16. 2 2
      misago/admin/layout/forums.py
  17. 3 3
      misago/admin/layout/overview.py
  18. 2 2
      misago/admin/layout/perms.py
  19. 2 2
      misago/admin/layout/sections.py
  20. 2 2
      misago/admin/layout/system.py
  21. 2 2
      misago/admin/layout/users.py
  22. 2 2
      misago/admin/views.py
  23. 68 68
      misago/admin/widgets.py
  24. 1 1
      misago/alerts/management/commands/clearalerts.py
  25. 10 10
      misago/alerts/models.py
  26. 2 2
      misago/alerts/views.py
  27. 1 1
      misago/authn/decorators.py
  28. 3 3
      misago/authn/fixtures.py
  29. 4 4
      misago/authn/forms.py
  30. 9 9
      misago/authn/methods.py
  31. 1 1
      misago/authn/urls.py
  32. 11 11
      misago/authn/views.py
  33. 1 1
      misago/banning/context_processors.py
  34. 1 1
      misago/banning/decorators.py
  35. 1 1
      misago/banning/fixtures.py
  36. 3 3
      misago/banning/forms.py
  37. 1 1
      misago/banning/middleware.py
  38. 13 13
      misago/banning/models.py
  39. 23 23
      misago/banning/views.py
  40. 1 1
      misago/bruteforce/context_processors.py
  41. 1 1
      misago/bruteforce/decorators.py
  42. 3 3
      misago/bruteforce/fixtures.py
  43. 1 1
      misago/bruteforce/management/commands/clearattempts.py
  44. 1 1
      misago/bruteforce/middleware.py
  45. 8 8
      misago/bruteforce/models.py
  46. 1 1
      misago/captcha/fixtures.py
  47. 1 1
      misago/context_processors.py
  48. 6 6
      misago/cookie_jar/cookie_jar.py
  49. 2 2
      misago/cookie_jar/middleware.py
  50. 1 1
      misago/csrf/context_processors.py
  51. 1 1
      misago/csrf/decorators.py
  52. 1 1
      misago/csrf/middleware.py
  53. 5 5
      misago/firewalls/firewalls.py
  54. 2 2
      misago/firewalls/middleware.py
  55. 22 22
      misago/forms/__init__.py
  56. 39 40
      misago/forms/layouts.py
  57. 6 6
      misago/forumroles/fixtures.py
  58. 3 3
      misago/forumroles/forms.py
  59. 7 7
      misago/forumroles/models.py
  60. 28 28
      misago/forumroles/views.py
  61. 11 11
      misago/forums/acl.py
  62. 12 12
      misago/forums/fixtures.py
  63. 51 51
      misago/forums/forms.py
  64. 2 2
      misago/forums/management/commands/resetdeltas.py
  65. 35 35
      misago/forums/models.py
  66. 83 83
      misago/forums/views.py
  67. 1 1
      misago/markdown/__init__.py
  68. 1 1
      misago/markdown/extensions/ats.py
  69. 1 1
      misago/markdown/extensions/quotes.py
  70. 10 10
      misago/markdown/factory.py
  71. 1 1
      misago/markdown/views.py
  72. 5 5
      misago/messages/__init__.py
  73. 1 1
      misago/messages/context_processors.py
  74. 1 1
      misago/messages/middleware.py
  75. 1 1
      misago/monitor/context_processors.py
  76. 2 2
      misago/monitor/fixtures.py
  77. 1 1
      misago/monitor/middleware.py
  78. 1 1
      misago/monitor/models.py
  79. 5 5
      misago/monitor/monitor.py
  80. 11 11
      misago/newsletters/forms.py
  81. 7 7
      misago/newsletters/models.py
  82. 32 32
      misago/newsletters/views.py
  83. 1 1
      misago/profiles/urls.py
  84. 12 12
      misago/profiles/views.py
  85. 14 15
      misago/prune/forms.py
  86. 9 9
      misago/prune/models.py
  87. 41 41
      misago/prune/views.py
  88. 7 7
      misago/ranks/fixtures.py
  89. 18 19
      misago/ranks/forms.py
  90. 5 5
      misago/ranks/management/commands/updateranking.py
  91. 13 13
      misago/ranks/models.py
  92. 36 36
      misago/ranks/views.py
  93. 2 2
      misago/sessions/forms.py
  94. 1 1
      misago/sessions/management/commands/clearsessions.py
  95. 1 1
      misago/sessions/management/commands/cleartokens.py
  96. 3 3
      misago/sessions/middleware.py
  97. 2 2
      misago/sessions/models.py
  98. 31 31
      misago/sessions/sessions.py
  99. 13 13
      misago/sessions/views.py
  100. 1 1
      misago/settings/context_processors.py
  101. 10 10
      misago/settings/fixtures.py
  102. 1 1
      misago/settings/forms.py
  103. 2 2
      misago/settings/middleware.py
  104. 19 20
      misago/settings/models.py
  105. 7 7
      misago/settings/settings.py
  106. 8 8
      misago/settings/views.py
  107. 1 1
      misago/settings_base.py
  108. 2 2
      misago/setup/fixtures.py
  109. 1 1
      misago/setup/management/commands/about.py
  110. 2 2
      misago/setup/management/commands/loadfixtures.py
  111. 1 1
      misago/setup/management/commands/updatefixtures.py
  112. 3 3
      misago/stats/forms.py
  113. 15 16
      misago/stats/views.py
  114. 2 2
      misago/stopwatch/middleware.py
  115. 3 3
      misago/team/views.py
  116. 5 5
      misago/template/templatetags/django2jinja.py
  117. 1 1
      misago/themes/middleware.py
  118. 9 9
      misago/themes/theme.py
  119. 47 48
      misago/threads/acl.py
  120. 4 4
      misago/threads/fixtures.py
  121. 25 25
      misago/threads/forms.py
  122. 1 1
      misago/threads/management/commands/updatethreadranking.py
  123. 37 38
      misago/threads/models.py
  124. 1 1
      misago/threads/urls.py
  125. 2 2
      misago/threads/views/base.py
  126. 11 12
      misago/threads/views/changelog.py
  127. 7 7
      misago/threads/views/delete.py
  128. 7 7
      misago/threads/views/jumps.py
  129. 28 28
      misago/threads/views/list.py
  130. 30 30
      misago/threads/views/posting.py
  131. 38 38
      misago/threads/views/thread.py
  132. 2 2
      misago/timezones/__init__.py
  133. 3 3
      misago/tos/fixtures.py
  134. 1 1
      misago/tos/views.py
  135. 2 2
      misago/urls.py
  136. 17 17
      misago/usercp/acl.py
  137. 4 4
      misago/usercp/avatar/forms.py
  138. 1 1
      misago/usercp/avatar/urls.py
  139. 1 1
      misago/usercp/avatar/usercp.py
  140. 15 15
      misago/usercp/avatar/views.py
  141. 1 1
      misago/usercp/blocked/urls.py
  142. 1 1
      misago/usercp/blocked/usercp.py
  143. 1 1
      misago/usercp/blocked/views.py
  144. 9 9
      misago/usercp/credentials/forms.py
  145. 1 1
      misago/usercp/credentials/urls.py
  146. 1 1
      misago/usercp/credentials/usercp.py
  147. 3 4
      misago/usercp/credentials/views.py
  148. 3 3
      misago/usercp/fixtures.py
  149. 1 1
      misago/usercp/models.py
  150. 2 2
      misago/usercp/options/forms.py
  151. 1 1
      misago/usercp/options/urls.py
  152. 1 1
      misago/usercp/options/usercp.py
  153. 4 4
      misago/usercp/options/views.py
  154. 3 3
      misago/usercp/signature/forms.py
  155. 1 1
      misago/usercp/signature/urls.py
  156. 1 1
      misago/usercp/signature/usercp.py
  157. 3 3
      misago/usercp/signature/views.py
  158. 2 3
      misago/usercp/template.py
  159. 1 1
      misago/usercp/urls.py
  160. 5 5
      misago/usercp/username/forms.py
  161. 1 1
      misago/usercp/username/urls.py
  162. 1 1
      misago/usercp/username/usercp.py
  163. 7 7
      misago/usercp/username/views.py
  164. 1 1
      misago/users/context_processors.py
  165. 1 1
      misago/users/fixtures.py
  166. 34 35
      misago/users/forms.py
  167. 4 4
      misago/users/management/commands/adduser.py
  168. 5 5
      misago/users/management/commands/genavatars.py
  169. 1 1
      misago/users/management/commands/syncusermonitor.py
  170. 2 2
      misago/users/middleware.py
  171. 101 101
      misago/users/models.py
  172. 2 2
      misago/users/validators.py
  173. 57 57
      misago/users/views.py
  174. 12 12
      misago/utils/__init__.py
  175. 2 2
      misago/utils/avatars.py
  176. 2 2
      misago/utils/validators.py
  177. 4 4
      misago/views.py

+ 6 - 6
deployment/settings.py

@@ -21,11 +21,11 @@ ADMINS = ()
 DATABASES = {
 DATABASES = {
     'default': {
     'default': {
         'ENGINE': 'django.db.backends.', # Add 'postgresql_psycopg2', 'mysql', 'sqlite3' or 'oracle'.
         'ENGINE': 'django.db.backends.', # Add 'postgresql_psycopg2', 'mysql', 'sqlite3' or 'oracle'.
-        'NAME': '',                      # Or path to database file if using sqlite3.
-        'USER': '',                      # Not used with sqlite3.
-        'PASSWORD': '',                  # Not used with sqlite3.
-        'HOST': '',                      # Set to empty string for localhost. Not used with sqlite3.
-        'PORT': '',                      # Set to empty string for default. Not used with sqlite3.
+        'NAME': '', # Or path to database file if using sqlite3.
+        'USER': '', # Not used with sqlite3.
+        'PASSWORD': '', # Not used with sqlite3.
+        'HOST': '', # Set to empty string for localhost. Not used with sqlite3.
+        'PORT': '', # Set to empty string for default. Not used with sqlite3.
     }
     }
 }
 }
 
 
@@ -120,7 +120,7 @@ TEMPLATE_DIRS = (
 
 
 # List of installed themes
 # List of installed themes
 INSTALLED_THEMES = (
 INSTALLED_THEMES = (
-    'sora',  # Default style always first
+    'sora', # Default style always first
     'admin', # Admin theme always last
     'admin', # Admin theme always last
 )
 )
 
 

+ 1 - 1
misago/__init__.py

@@ -20,4 +20,4 @@ def get_version(version=None):
         mapping = {'alpha': 'a', 'beta': 'b', 'rc': 'c'}
         mapping = {'alpha': 'a', 'beta': 'b', 'rc': 'c'}
         sub = mapping[version[3]] + str(version[4])
         sub = mapping[version[3]] + str(version[4])
 
 
-    return main + sub
+    return main + sub

+ 6 - 6
misago/acl/builder.py

@@ -29,7 +29,7 @@ def build_forum_form(request, role):
 class BaseACL(object):
 class BaseACL(object):
     def __init__(self):
     def __init__(self):
         self.acl = {}
         self.acl = {}
-        
+
     def __repr__(self):
     def __repr__(self):
         return '%s (%s)' % (self.__class__.__name__[0:-3], self.__class__.__module__)
         return '%s (%s)' % (self.__class__.__name__[0:-3], self.__class__.__module__)
 
 
@@ -50,13 +50,13 @@ def build_acl(request, roles):
     forums = Forum.objects.get(token='root').get_descendants().order_by('lft')
     forums = Forum.objects.get(token='root').get_descendants().order_by('lft')
     perms = []
     perms = []
     forum_roles = {}
     forum_roles = {}
-    
+
     for role in roles:
     for role in roles:
         perms.append(role.get_permissions())
         perms.append(role.get_permissions())
-    
+
     for role in ForumRole.objects.all():
     for role in ForumRole.objects.all():
         forum_roles[role.pk] = role.get_permissions()
         forum_roles[role.pk] = role.get_permissions()
-    
+
     for provider in settings.PERMISSION_PROVIDERS:
     for provider in settings.PERMISSION_PROVIDERS:
         app_module = import_module(provider)
         app_module = import_module(provider)
         try:
         try:
@@ -67,7 +67,7 @@ def build_acl(request, roles):
             app_module.build_forums(acl, perms, forums, forum_roles)
             app_module.build_forums(acl, perms, forums, forum_roles)
         except AttributeError:
         except AttributeError:
             pass
             pass
-        
+
     for provider in settings.PERMISSION_PROVIDERS:
     for provider in settings.PERMISSION_PROVIDERS:
         app_module = import_module(provider)
         app_module = import_module(provider)
         try:
         try:
@@ -75,4 +75,4 @@ def build_acl(request, roles):
         except AttributeError:
         except AttributeError:
             pass
             pass
 
 
-    return acl
+    return acl

+ 1 - 1
misago/acl/context_processors.py

@@ -1,4 +1,4 @@
 def acl(request):
 def acl(request):
     return {
     return {
         'acl': request.acl,
         'acl': request.acl,
-    }
+    }

+ 1 - 1
misago/acl/fixtures.py

@@ -6,4 +6,4 @@ monitor_fixtures = {
 
 
 
 
 def load_fixtures():
 def load_fixtures():
-    load_monitor_fixture(monitor_fixtures)
+    load_monitor_fixture(monitor_fixtures)

+ 2 - 2
misago/acl/middleware.py

@@ -11,11 +11,11 @@ class ACLMiddleware(object):
         except (AttributeError, InvalidCacheBackendError):
         except (AttributeError, InvalidCacheBackendError):
             user_acl = build_acl(request, request.user.get_roles())
             user_acl = build_acl(request, request.user.get_roles())
             cache.set(acl_key, user_acl, 2592000)
             cache.set(acl_key, user_acl, 2592000)
-        
+
         request.acl = user_acl
         request.acl = user_acl
         if request.user.is_authenticated() and (request.acl.team or request.user.is_god()) != request.user.is_team:
         if request.user.is_authenticated() and (request.acl.team or request.user.is_god()) != request.user.is_team:
             request.user.is_team = (request.acl.team or request.user.is_god())
             request.user.is_team = (request.acl.team or request.user.is_god())
             request.user.save(force_update=True)
             request.user.save(force_update=True)
         if request.session.team != request.user.is_team:
         if request.session.team != request.user.is_team:
             request.session.team = request.user.is_team
             request.session.team = request.user.is_team
-            request.session.save()
+            request.session.save()

+ 2 - 2
misago/acl/panels.py

@@ -17,8 +17,8 @@ class MisagoACLDebugPanel(DebugPanel):
 
 
     def process_request(self, request):
     def process_request(self, request):
         self.request = request
         self.request = request
-        
+
     def content(self):
     def content(self):
         context = self.context.copy()
         context = self.context.copy()
         context['acl'] = self.request.acl
         context['acl'] = self.request.acl
-        return render_to_string('debug_toolbar/panels/acl.html', context)
+        return render_to_string('debug_toolbar/panels/acl.html', context)

+ 1 - 1
misago/acl/utils.py

@@ -14,4 +14,4 @@ def acl_errors(f):
             return error403(args[0], e.message)
             return error403(args[0], e.message)
         except ACLError404 as e:
         except ACLError404 as e:
             return error404(args[0], e.message)
             return error404(args[0], e.message)
-    return decorator
+    return decorator

+ 5 - 5
misago/activation/forms.py

@@ -5,14 +5,14 @@ from django.utils.translation import ugettext_lazy as _
 from misago.forms import Form
 from misago.forms import Form
 from misago import captcha
 from misago import captcha
 from misago.users.models import User
 from misago.users.models import User
-    
-    
+
+
 class UserSendActivationMailForm(Form):
 class UserSendActivationMailForm(Form):
     email = forms.EmailField(max_length=255)
     email = forms.EmailField(max_length=255)
     captcha_qa = captcha.QACaptchaField()
     captcha_qa = captcha.QACaptchaField()
     recaptcha = captcha.ReCaptchaField()
     recaptcha = captcha.ReCaptchaField()
     error_source = 'email'
     error_source = 'email'
-    
+
     layout = [
     layout = [
               (
               (
                None,
                None,
@@ -23,7 +23,7 @@ class UserSendActivationMailForm(Form):
                ['captcha_qa', 'recaptcha']
                ['captcha_qa', 'recaptcha']
                ),
                ),
               ]
               ]
-    
+
     def clean_email(self):
     def clean_email(self):
         try:
         try:
             email = self.cleaned_data['email'].lower()
             email = self.cleaned_data['email'].lower()
@@ -31,4 +31,4 @@ class UserSendActivationMailForm(Form):
             self.found_user = User.objects.get(email_hash=email_hash)
             self.found_user = User.objects.get(email_hash=email_hash)
         except User.DoesNotExist:
         except User.DoesNotExist:
             raise ValidationError(_("There is no user with such e-mail address."))
             raise ValidationError(_("There is no user with such e-mail address."))
-        return email
+        return email

+ 1 - 1
misago/activation/urls.py

@@ -3,4 +3,4 @@ from django.conf.urls import patterns, url
 urlpatterns = patterns('misago.activation.views',
 urlpatterns = patterns('misago.activation.views',
     url(r'^request/$', 'form', name="send_activation"),
     url(r'^request/$', 'form', name="send_activation"),
     url(r'^(?P<username>[a-z0-9]+)-(?P<user>\d+)/(?P<token>[a-zA-Z0-9]+)/$', 'activate', name="activate"),
     url(r'^(?P<username>[a-z0-9]+)-(?P<user>\d+)/(?P<token>[a-zA-Z0-9]+)/$', 'activate', name="activate"),
-)
+)

+ 13 - 13
misago/activation/views.py

@@ -23,16 +23,16 @@ def form(request):
         if form.is_valid():
         if form.is_valid():
             user = form.found_user
             user = form.found_user
             user_ban = check_ban(username=user.username, email=user.email)
             user_ban = check_ban(username=user.username, email=user.email)
-            
+
             if user_ban:
             if user_ban:
                 return error_banned(request, user, user_ban)
                 return error_banned(request, user, user_ban)
-            
+
             if user.activation == User.ACTIVATION_NONE:
             if user.activation == User.ACTIVATION_NONE:
                 return redirect_message(request, Message(_("%(username)s, your account is already active.") % {'username': user.username}), 'info')
                 return redirect_message(request, Message(_("%(username)s, your account is already active.") % {'username': user.username}), 'info')
-            
+
             if user.activation == User.ACTIVATION_ADMIN:
             if user.activation == User.ACTIVATION_ADMIN:
                 return redirect_message(request, Message(_("%(username)s, only board administrator can activate your account.") % {'username': user.username}), 'info')
                 return redirect_message(request, Message(_("%(username)s, only board administrator can activate your account.") % {'username': user.username}), 'info')
-        
+
             user.email_user(
             user.email_user(
                             request,
                             request,
                             'users/activation/resend',
                             'users/activation/resend',
@@ -56,35 +56,35 @@ def form(request):
 @block_jammed
 @block_jammed
 def activate(request, username="", user="0", token=""):
 def activate(request, username="", user="0", token=""):
     user = int(user)
     user = int(user)
-    
+
     try:
     try:
         user = User.objects.get(pk=user)
         user = User.objects.get(pk=user)
         current_activation = user.activation
         current_activation = user.activation
-        
+
         # Run checks
         # Run checks
         user_ban = check_ban(username=user.username, email=user.email)
         user_ban = check_ban(username=user.username, email=user.email)
         if user_ban:
         if user_ban:
             return error_banned(request, user, user_ban)
             return error_banned(request, user, user_ban)
-        
+
         if user.activation == User.ACTIVATION_NONE:
         if user.activation == User.ACTIVATION_NONE:
             return redirect_message(request, Message(_("%(username)s, your account is already active.") % {'username': user.username}), 'info')
             return redirect_message(request, Message(_("%(username)s, your account is already active.") % {'username': user.username}), 'info')
-            
+
         if user.activation == User.ACTIVATION_ADMIN:
         if user.activation == User.ACTIVATION_ADMIN:
             return redirect_message(request, Message(_("%(username)s, only board administrator can activate your account.") % {'username': user.username}), 'info')
             return redirect_message(request, Message(_("%(username)s, only board administrator can activate your account.") % {'username': user.username}), 'info')
-        
+
         if not token or not user.token or user.token != token:
         if not token or not user.token or user.token != token:
             return redirect_message(request, Message(_("%(username)s, your activation link is invalid. Try again or request new activation e-mail.") % {'username': user.username}), 'error')
             return redirect_message(request, Message(_("%(username)s, your activation link is invalid. Try again or request new activation e-mail.") % {'username': user.username}), 'error')
-        
+
         # Activate and sign in our member
         # Activate and sign in our member
         user.activation = User.ACTIVATION_NONE
         user.activation = User.ACTIVATION_NONE
         sign_user_in(request, user)
         sign_user_in(request, user)
-        
+
         # Update monitor
         # Update monitor
         User.objects.resync_monitor(request.monitor)
         User.objects.resync_monitor(request.monitor)
-        
+
         if current_activation == User.ACTIVATION_CREDENTIALS:
         if current_activation == User.ACTIVATION_CREDENTIALS:
             return redirect_message(request, Message(_("%(username)s, your account has been successfully reactivated after change of sign-in credentials.") % {'username': user.username}), 'success')
             return redirect_message(request, Message(_("%(username)s, your account has been successfully reactivated after change of sign-in credentials.") % {'username': user.username}), 'success')
         else:
         else:
             return redirect_message(request, Message(_("%(username)s, your account has been successfully activated. Welcome aboard!") % {'username': user.username}), 'success')
             return redirect_message(request, Message(_("%(username)s, your account has been successfully activated. Welcome aboard!") % {'username': user.username}), 'success')
     except User.DoesNotExist:
     except User.DoesNotExist:
-        return error404(request)
+        return error404(request)

+ 31 - 31
misago/admin/__init__.py

@@ -14,7 +14,7 @@ if settings.ADMIN_PATH:
     while ADMIN_PATH[-1:] == '/':
     while ADMIN_PATH[-1:] == '/':
         ADMIN_PATH = ADMIN_PATH[:-1]
         ADMIN_PATH = ADMIN_PATH[:-1]
     ADMIN_PATH += '/'
     ADMIN_PATH += '/'
-    
+
 
 
 """
 """
 Admin lists sorter for admin sections and actions
 Admin lists sorter for admin sections and actions
@@ -22,7 +22,7 @@ Admin lists sorter for admin sections and actions
 class SortList(object):
 class SortList(object):
     def __init__(self, unsorted):
     def __init__(self, unsorted):
         self.unsorted = unsorted
         self.unsorted = unsorted
-        
+
     def sort(self):
     def sort(self):
         # Sort and return sorted list
         # Sort and return sorted list
         order = []
         order = []
@@ -53,8 +53,8 @@ class SortList(object):
                     sorted.append(object)
                     sorted.append(object)
                     break
                     break
         return sorted
         return sorted
-        
-            
+
+
 """
 """
 Admin site section
 Admin site section
 """
 """
@@ -68,8 +68,8 @@ class AdminSiteItem(object):
         self.target = target
         self.target = target
         self.route = route
         self.route = route
         self.sorted = False
         self.sorted = False
-    
-    
+
+
 """
 """
 Admin site action
 Admin site action
 """
 """
@@ -81,13 +81,13 @@ class AdminAction(AdminSiteItem):
         self.messages = messages
         self.messages = messages
         self.urlpatterns = urlpatterns
         self.urlpatterns = urlpatterns
         super(AdminAction, self).__init__(**kwargs)
         super(AdminAction, self).__init__(**kwargs)
-    
+
     def get_action_attr(self, id, attr):
     def get_action_attr(self, id, attr):
         for action in self.actions:
         for action in self.actions:
             if action['id'] == id:
             if action['id'] == id:
                 return action[attr]
                 return action[attr]
         return None
         return None
-    
+
     def is_active(self, full_path, section=None):
     def is_active(self, full_path, section=None):
         if section:
         if section:
             action_path = '/%s%s/%s/' % (ADMIN_PATH, section, self.id)
             action_path = '/%s%s/%s/' % (ADMIN_PATH, section, self.id)
@@ -105,7 +105,7 @@ class AdminSection(AdminSiteItem):
         self.actions = []
         self.actions = []
         self.last = None
         self.last = None
         super(AdminSection, self).__init__(**kwargs)
         super(AdminSection, self).__init__(**kwargs)
-        
+
     def get_routes(self):
     def get_routes(self):
         routes = []
         routes = []
         first_action = True
         first_action = True
@@ -116,7 +116,7 @@ class AdminSection(AdminSiteItem):
             else:
             else:
                 routes += patterns('', url(('^%s/' % action.id), include(action.urlpatterns)))
                 routes += patterns('', url(('^%s/' % action.id), include(action.urlpatterns)))
         return routes
         return routes
-            
+
     def is_active(self, full_path):
     def is_active(self, full_path):
         action_path = '/%s%s/' % (ADMIN_PATH, self.id)
         action_path = '/%s%s/' % (ADMIN_PATH, self.id)
         # Paths overlap = active action
         # Paths overlap = active action
@@ -131,7 +131,7 @@ class AdminSite(object):
     routes = []
     routes = []
     sections = []
     sections = []
     sections_index = {}
     sections_index = {}
-    
+
     def discover(self):
     def discover(self):
         """
         """
         Build admin site structure
         Build admin site structure
@@ -139,19 +139,19 @@ class AdminSite(object):
         # Return discovered admin routes, so we dont repeat ourself
         # Return discovered admin routes, so we dont repeat ourself
         if self.routes:
         if self.routes:
             return self.routes
             return self.routes
-        
+
         # Found actions
         # Found actions
         actions = []
         actions = []
-        
+
         # Orphan actions that have no section yet
         # Orphan actions that have no section yet
         late_actions = []
         late_actions = []
-        
+
         # Load default admin site
         # Load default admin site
         from misago.admin.layout.sections import ADMIN_SECTIONS
         from misago.admin.layout.sections import ADMIN_SECTIONS
         for section in ADMIN_SECTIONS:
         for section in ADMIN_SECTIONS:
             self.sections.append(section)
             self.sections.append(section)
             self.sections_index[section.id] = section
             self.sections_index[section.id] = section
-            
+
             # Loop section actions
             # Loop section actions
             section_actions = import_module('misago.admin.layout.%s' % section.id)
             section_actions = import_module('misago.admin.layout.%s' % section.id)
             for action in section_actions.ADMIN_ACTIONS:
             for action in section_actions.ADMIN_ACTIONS:
@@ -160,12 +160,12 @@ class AdminSite(object):
                      action.after = self.sections_index[section.id].last
                      action.after = self.sections_index[section.id].last
                 actions.append(action)
                 actions.append(action)
                 self.sections_index[section.id].last = action.after
                 self.sections_index[section.id].last = action.after
-        
+
         # Iterate over installed applications
         # Iterate over installed applications
         for app_name in settings.INSTALLED_APPS:
         for app_name in settings.INSTALLED_APPS:
             try:
             try:
                 app = import_module(app_name + '.admin')
                 app = import_module(app_name + '.admin')
-                
+
                 # Attempt to import sections
                 # Attempt to import sections
                 try:
                 try:
                     for section in app.ADMIN_SECTIONS:
                     for section in app.ADMIN_SECTIONS:
@@ -173,7 +173,7 @@ class AdminSite(object):
                         self.sections_index[section.id] = section
                         self.sections_index[section.id] = section
                 except AttributeError:
                 except AttributeError:
                     pass
                     pass
-                
+
                 # Attempt to import actions
                 # Attempt to import actions
                 try:
                 try:
                     for action in app.ADMIN_ACTIONS:
                     for action in app.ADMIN_ACTIONS:
@@ -189,20 +189,20 @@ class AdminSite(object):
                     pass
                     pass
             except ImportError:
             except ImportError:
                 pass
                 pass
-                
+
         # So actions and late actions
         # So actions and late actions
         actions += late_actions
         actions += late_actions
-        
+
         # Sorth sections and actions
         # Sorth sections and actions
         sort_sections = SortList(self.sections)
         sort_sections = SortList(self.sections)
         sort_actions = SortList(actions)
         sort_actions = SortList(actions)
         self.sections = sort_sections.sort()
         self.sections = sort_sections.sort()
         actions = sort_actions.sort()
         actions = sort_actions.sort()
-        
+
         # Put actions in sections
         # Put actions in sections
         for action in actions:
         for action in actions:
             self.sections_index[action.section].actions.append(action)
             self.sections_index[action.section].actions.append(action)
-        
+
         # Return ready admin routing
         # Return ready admin routing
         first_section = True
         first_section = True
         for section in self.sections:
         for section in self.sections:
@@ -212,19 +212,19 @@ class AdminSite(object):
             else:
             else:
                 self.routes += patterns('', url(('^%s/' % section.id), include(section.get_routes())))
                 self.routes += patterns('', url(('^%s/' % section.id), include(section.get_routes())))
         return self.routes
         return self.routes
-    
+
     def get_action(self, action):
     def get_action(self, action):
         """
         """
         Get admin action
         Get admin action
         """
         """
         return self.actions_index.get(action)
         return self.actions_index.get(action)
-            
+
     def get_admin_index(self):
     def get_admin_index(self):
         """
         """
         Return admin index route - first action of first section
         Return admin index route - first action of first section
         """
         """
         return self.sections[0].actions[0].route
         return self.sections[0].actions[0].route
-            
+
     def get_admin_navigation(self, request):
     def get_admin_navigation(self, request):
         """
         """
         Find and return current admin navigation
         Find and return current admin navigation
@@ -233,7 +233,7 @@ class AdminSite(object):
         actions = []
         actions = []
         active_section = False
         active_section = False
         active_action = False
         active_action = False
-        
+
         # Loop sections, build list of sections and find active section
         # Loop sections, build list of sections and find active section
         for section in self.sections:
         for section in self.sections:
             is_active = section.is_active(request.path)
             is_active = section.is_active(request.path)
@@ -245,12 +245,12 @@ class AdminSite(object):
                              })
                              })
             if is_active:
             if is_active:
                 active_section = section
                 active_section = section
-        
+
         # If no section was found to be active, default to first one
         # If no section was found to be active, default to first one
         if not active_section:
         if not active_section:
             active_section = self.sections[0]
             active_section = self.sections[0]
             sections[0]['is_active'] = True
             sections[0]['is_active'] = True
-            
+
         # Loop active section actions
         # Loop active section actions
         for action in active_section.actions:
         for action in active_section.actions:
             is_active = action.is_active(request.path, active_section.id if active_section != self.sections[0] else None)
             is_active = action.is_active(request.path, active_section.id if active_section != self.sections[0] else None)
@@ -263,12 +263,12 @@ class AdminSite(object):
                              })
                              })
             if is_active:
             if is_active:
                 active_action = action
                 active_action = action
-        
+
         # If no action was found to be active, default to first one
         # If no action was found to be active, default to first one
         if not active_action:
         if not active_action:
             active_action = active_section.actions[0]
             active_action = active_section.actions[0]
             actions[0]['is_active'] = True
             actions[0]['is_active'] = True
-        
+
         # Return admin navigation for this location
         # Return admin navigation for this location
         return {
         return {
                 'sections': sections,
                 'sections': sections,
@@ -277,4 +277,4 @@ class AdminSite(object):
                 }
                 }
 
 
 
 
-site = AdminSite();
+site = AdminSite();

+ 5 - 5
misago/admin/acl.py

@@ -5,7 +5,7 @@ from misago.forms import YesNoSwitch
 
 
 def make_form(request, role, form):
 def make_form(request, role, form):
     if not role.token and request.user.is_god():
     if not role.token and request.user.is_god():
-        form.base_fields['can_use_acp'] = forms.BooleanField(widget=YesNoSwitch,initial=False,required=False)
+        form.base_fields['can_use_acp'] = forms.BooleanField(widget=YesNoSwitch, initial=False, required=False)
         form.layout.append((
         form.layout.append((
                             _("Admin Control Panel"),
                             _("Admin Control Panel"),
                             (('can_use_acp', {'label': _("Can use Admin Control Panel"), 'help_text': _("Change this permission to yes to grant admin access for users with this role.")}),),
                             (('can_use_acp', {'label': _("Can use Admin Control Panel"), 'help_text': _("Change this permission to yes to grant admin access for users with this role.")}),),
@@ -15,15 +15,15 @@ def make_form(request, role, form):
 class AdminACL(BaseACL):
 class AdminACL(BaseACL):
     def is_admin(self):
     def is_admin(self):
         return self.acl['can_use_acp']
         return self.acl['can_use_acp']
-    
+
 
 
 def build(acl, roles):
 def build(acl, roles):
     acl.admin = AdminACL()
     acl.admin = AdminACL()
     acl.admin.acl['can_use_acp'] = False
     acl.admin.acl['can_use_acp'] = False
-    
+
     for role in roles:
     for role in roles:
         if 'can_use_acp' in role and role['can_use_acp'] > acl.admin.acl['can_use_acp']:
         if 'can_use_acp' in role and role['can_use_acp'] > acl.admin.acl['can_use_acp']:
             acl.admin.acl['can_use_acp'] = role['can_use_acp']
             acl.admin.acl['can_use_acp'] = role['can_use_acp']
-            
+
     if acl.admin.acl['can_use_acp']:
     if acl.admin.acl['can_use_acp']:
-        acl.team = True
+        acl.team = True

+ 1 - 1
misago/admin/context_processors.py

@@ -1,4 +1,4 @@
 from misago.admin import site
 from misago.admin import site
 
 
 def admin(request):
 def admin(request):
-    return site.get_admin_navigation(request)
+    return site.get_admin_navigation(request)

+ 6 - 6
misago/admin/fixtures.py

@@ -2,7 +2,7 @@ import base64
 from misago.admin.models import Section, Action
 from misago.admin.models import Section, Action
 from misago.utils import ugettext_lazy as _
 from misago.utils import ugettext_lazy as _
 from misago.utils import get_msgid
 from misago.utils import get_msgid
-    
+
 admin_fixtures = {
 admin_fixtures = {
     # Overview
     # Overview
     'overview': {
     'overview': {
@@ -10,32 +10,32 @@ admin_fixtures = {
         'icon': 'signal',
         'icon': 'signal',
         'pos': 0,
         'pos': 0,
     },
     },
-    
+
     # Users
     # Users
     'users': {
     'users': {
         'name': _('Users'),
         'name': _('Users'),
         'icon': 'user',
         'icon': 'user',
         'pos': 100,
         'pos': 100,
     },
     },
-    
+
     # Forums
     # Forums
     'forums': {
     'forums': {
         'name': _('Forums'),
         'name': _('Forums'),
         'icon': 'comment',
         'icon': 'comment',
         'pos': 200,
         'pos': 200,
     },
     },
-    
+
     # Permissions
     # Permissions
     'permissions': {
     'permissions': {
         'name': _('Permissions'),
         'name': _('Permissions'),
         'icon': 'adjust',
         'icon': 'adjust',
         'pos': 300,
         'pos': 300,
     },
     },
-    
+
     # System
     # System
     'system': {
     'system': {
         'name': _('System'),
         'name': _('System'),
         'icon': 'wrench',
         'icon': 'wrench',
         'pos': 400,
         'pos': 400,
     },
     },
-} 
+}

+ 2 - 2
misago/admin/layout/forums.py

@@ -3,7 +3,7 @@ from django.utils.translation import ugettext_lazy as _
 from misago.admin import AdminAction
 from misago.admin import AdminAction
 from misago.forums.models import Forum
 from misago.forums.models import Forum
 
 
-ADMIN_ACTIONS=(
+ADMIN_ACTIONS = (
    AdminAction(
    AdminAction(
                section='forums',
                section='forums',
                id='forums',
                id='forums',
@@ -93,4 +93,4 @@ ADMIN_ACTIONS=(
                         url(r'^$', 'todo', name='admin_forums_attachments'),
                         url(r'^$', 'todo', name='admin_forums_attachments'),
                     ),
                     ),
                ),
                ),
-)
+)

+ 3 - 3
misago/admin/layout/overview.py

@@ -4,7 +4,7 @@ from misago.admin import AdminAction
 from misago.sessions.models import Session
 from misago.sessions.models import Session
 from misago.users.models import User
 from misago.users.models import User
 
 
-ADMIN_ACTIONS=(
+ADMIN_ACTIONS = (
    AdminAction(
    AdminAction(
                section='overview',
                section='overview',
                id='home',
                id='home',
@@ -43,7 +43,7 @@ ADMIN_ACTIONS=(
                          'route': 'admin_online'
                          'route': 'admin_online'
                          },
                          },
                         ],
                         ],
-               route='admin_online', 
+               route='admin_online',
                urlpatterns=patterns('misago.sessions.views',
                urlpatterns=patterns('misago.sessions.views',
                         url(r'^$', 'List', name='admin_online'),
                         url(r'^$', 'List', name='admin_online'),
                         url(r'^(?P<page>\d+)/$', 'List', name='admin_online'),
                         url(r'^(?P<page>\d+)/$', 'List', name='admin_online'),
@@ -69,4 +69,4 @@ ADMIN_ACTIONS=(
                         url(r'^$', 'List', name='admin_team'),
                         url(r'^$', 'List', name='admin_team'),
                     ),
                     ),
                ),
                ),
-)
+)

+ 2 - 2
misago/admin/layout/perms.py

@@ -5,7 +5,7 @@ from misago.roles.models import Role
 from misago.forumroles.models import ForumRole
 from misago.forumroles.models import ForumRole
 
 
 
 
-ADMIN_ACTIONS=(
+ADMIN_ACTIONS = (
    AdminAction(
    AdminAction(
                section='perms',
                section='perms',
                id='roles',
                id='roles',
@@ -67,4 +67,4 @@ ADMIN_ACTIONS=(
                         url(r'^delete/(?P<slug>([a-z0-9]|-)+)-(?P<target>\d+)/$', 'Delete', name='admin_roles_forums_delete'),
                         url(r'^delete/(?P<slug>([a-z0-9]|-)+)-(?P<target>\d+)/$', 'Delete', name='admin_roles_forums_delete'),
                     ),
                     ),
                ),
                ),
-)
+)

+ 2 - 2
misago/admin/layout/sections.py

@@ -1,7 +1,7 @@
 from django.utils.translation import ugettext_lazy as _
 from django.utils.translation import ugettext_lazy as _
 from misago.admin import AdminSection
 from misago.admin import AdminSection
 
 
-ADMIN_SECTIONS=(
+ADMIN_SECTIONS = (
     AdminSection(
     AdminSection(
                  id='overview',
                  id='overview',
                  name=_("Overview"),
                  name=_("Overview"),
@@ -27,4 +27,4 @@ ADMIN_SECTIONS=(
                  name=_("System"),
                  name=_("System"),
                  icon='cog',
                  icon='cog',
                  ),
                  ),
-)
+)

+ 2 - 2
misago/admin/layout/system.py

@@ -2,7 +2,7 @@ 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 AdminAction
 from misago.admin import AdminAction
 
 
-ADMIN_ACTIONS=(
+ADMIN_ACTIONS = (
    AdminAction(
    AdminAction(
                section='system',
                section='system',
                id='settings',
                id='settings',
@@ -16,4 +16,4 @@ ADMIN_ACTIONS=(
                         url(r'^(?P<group_slug>([a-z0-9]|-)+)-(?P<group_id>\d+)/$', 'settings', name='admin_settings')
                         url(r'^(?P<group_slug>([a-z0-9]|-)+)-(?P<group_id>\d+)/$', 'settings', name='admin_settings')
                     ),
                     ),
                ),
                ),
-)
+)

+ 2 - 2
misago/admin/layout/users.py

@@ -7,7 +7,7 @@ from misago.prune.models import Policy
 from misago.ranks.models import Rank
 from misago.ranks.models import Rank
 from misago.users.models import User
 from misago.users.models import User
 
 
-ADMIN_ACTIONS=(
+ADMIN_ACTIONS = (
    AdminAction(
    AdminAction(
                section='users',
                section='users',
                id='users',
                id='users',
@@ -159,4 +159,4 @@ ADMIN_ACTIONS=(
                         url(r'^delete/(?P<target>\d+)/$', 'Delete', name='admin_newsletters_delete'),
                         url(r'^delete/(?P<target>\d+)/$', 'Delete', name='admin_newsletters_delete'),
                     ),
                     ),
                ),
                ),
-)
+)

+ 2 - 2
misago/admin/views.py

@@ -10,6 +10,6 @@ def home(request):
         'admins': Session.objects.filter(user__isnull=False).filter(admin=1).order_by('user__username_slug').select_related(depth=1),
         'admins': Session.objects.filter(user__isnull=False).filter(admin=1).order_by('user__username_slug').select_related(depth=1),
         }, context_instance=RequestContext(request));
         }, context_instance=RequestContext(request));
 
 
- 
+
 def todo(request):
 def todo(request):
-    return request.theme.render_to_response('todo.html', context_instance=RequestContext(request));
+    return request.theme.render_to_response('todo.html', context_instance=RequestContext(request));

+ 68 - 68
misago/admin/widgets.py

@@ -24,7 +24,7 @@ class BaseWidget(object):
     name = None
     name = None
     help = None
     help = None
     notfound_message = None
     notfound_message = None
-    
+
     def __new__(cls, request, **kwargs):
     def __new__(cls, request, **kwargs):
         obj = super(BaseWidget, cls).__new__(cls)
         obj = super(BaseWidget, cls).__new__(cls)
         if not obj.name:
         if not obj.name:
@@ -32,35 +32,35 @@ class BaseWidget(object):
         if not obj.help:
         if not obj.help:
             obj.help = obj.get_help()
             obj.help = obj.get_help()
         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.__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'))
-    
+
     def get_name(self):
     def get_name(self):
         return self.admin.get_action_attr(self.id, 'name')
         return self.admin.get_action_attr(self.id, 'name')
-    
+
     def get_help(self):
     def get_help(self):
         return self.admin.get_action_attr(self.id, 'help')
         return self.admin.get_action_attr(self.id, 'help')
-    
+
     def get_id(self):
     def get_id(self):
         return 'admin_%s' % self.id
         return 'admin_%s' % self.id
-         
+
     def get_template(self):
     def get_template(self):
         return ('%s/%s.html' % (self.admin.id, self.template),
         return ('%s/%s.html' % (self.admin.id, self.template),
                 'admin/%s.html' % self.template)
                 'admin/%s.html' % self.template)
-    
+
     def add_template_variables(self, variables):
     def add_template_variables(self, variables):
         return variables
         return variables
-            
+
     def get_fallback_url(self):
     def get_fallback_url(self):
         return reverse(self.fallback)
         return reverse(self.fallback)
-        
+
     def get_target(self, model):
     def get_target(self, model):
         pass
         pass
-    
+
     def get_target_name(self, model):
     def get_target_name(self, model):
         try:
         try:
             if self.translate_target_name:
             if self.translate_target_name:
@@ -68,7 +68,7 @@ class BaseWidget(object):
             return model.__dict__[self.target_name]
             return model.__dict__[self.target_name]
         except AttributeError:
         except AttributeError:
             return None
             return None
-        
+
     def get_and_validate_target(self, target):
     def get_and_validate_target(self, target):
         try:
         try:
             model = self.admin.model.objects.select_related().get(pk=target)
             model = self.admin.model.objects.select_related().get(pk=target)
@@ -85,7 +85,7 @@ class ListWidget(BaseWidget):
     """
     """
     Items list widget
     Items list widget
     """
     """
-    actions =[]
+    actions = []
     columns = []
     columns = []
     sortables = {}
     sortables = {}
     default_sorting = None
     default_sorting = None
@@ -99,14 +99,14 @@ class ListWidget(BaseWidget):
     empty_search_message = _('Search has returned no items')
     empty_search_message = _('Search has returned no items')
     nothing_checked_message = _('You have to select at least one item.')
     nothing_checked_message = _('You have to select at least one item.')
     prompt_select = False
     prompt_select = False
-    
+
     def get_item_actions(self, item):
     def get_item_actions(self, item):
         """
         """
         Provides request and item, should return list of tuples with item actions in following format:
         Provides request and item, should return list of tuples with item actions in following format:
         (id, name, help, icon, link)
         (id, name, help, icon, link)
         """
         """
         return []
         return []
-    
+
     def action(self, icon=None, name=None, url=None, post=False, prompt=None):
     def action(self, icon=None, name=None, url=None, post=False, prompt=None):
         """
         """
         Function call to make hash with item actions
         Function call to make hash with item actions
@@ -120,31 +120,31 @@ class ListWidget(BaseWidget):
                 'post': post,
                 'post': post,
                 'prompt': prompt,
                 'prompt': prompt,
                 }
                 }
-        
+
     def get_search_form(self):
     def get_search_form(self):
         """
         """
         Build a form object with items search
         Build a form object with items search
         """
         """
         return self.search_form
         return self.search_form
-            
+
     def set_filters(self, model, filters):
     def set_filters(self, model, filters):
         """
         """
         Set filters on model using filters from session
         Set filters on model using filters from session
         """
         """
         return None
         return None
-    
+
     def get_table_form(self, page_items):
     def get_table_form(self, page_items):
         """
         """
         Build a form object with list of all items fields
         Build a form object with list of all items fields
         """
         """
         return None
         return None
-    
+
     def table_action(self, page_items, cleaned_data):
     def table_action(self, page_items, cleaned_data):
         """
         """
         Handle table form submission, return tuple containing message and redirect link/false
         Handle table form submission, return tuple containing message and redirect link/false
         """
         """
         return None
         return None
-    
+
     def get_actions_form(self, page_items):
     def get_actions_form(self, page_items):
         """
         """
         Build a form object with list of all items actions
         Build a form object with list of all items actions
@@ -159,9 +159,9 @@ class ListWidget(BaseWidget):
         list_choices = []
         list_choices = []
         for item in page_items:
         for item in page_items:
             list_choices.append((item.pk, None))
             list_choices.append((item.pk, None))
-        form_fields['list_items'] = forms.MultipleChoiceField(choices=list_choices,widget=forms.CheckboxSelectMultiple)
+        form_fields['list_items'] = forms.MultipleChoiceField(choices=list_choices, widget=forms.CheckboxSelectMultiple)
         return type('AdminListForm', (Form,), form_fields)
         return type('AdminListForm', (Form,), form_fields)
-        
+
     def get_sorting(self):
     def get_sorting(self):
         """
         """
         Return list sorting method.
         Return list sorting method.
@@ -173,7 +173,7 @@ class ListWidget(BaseWidget):
         sorting_method = None
         sorting_method = None
         if self.request.session.get(self.get_token('sort')) and self.request.session.get(self.get_token('sort'))[0] in self.sortables:
         if self.request.session.get(self.get_token('sort')) and self.request.session.get(self.get_token('sort'))[0] in self.sortables:
             sorting_method = self.request.session.get(self.get_token('sort'))
             sorting_method = self.request.session.get(self.get_token('sort'))
-            
+
         if self.request.GET.get('sort') and self.request.GET.get('sort') in self.sortables:
         if self.request.GET.get('sort') and self.request.GET.get('sort') in self.sortables:
             new_sorting = self.request.GET.get('sort')
             new_sorting = self.request.GET.get('sort')
             sorting_dir = int(self.request.GET.get('dir')) == 1
             sorting_dir = int(self.request.GET.get('dir')) == 1
@@ -183,7 +183,7 @@ class ListWidget(BaseWidget):
                     new_sorting if sorting_dir else '-%s' % new_sorting
                     new_sorting if sorting_dir else '-%s' % new_sorting
                    ]
                    ]
             self.request.session[self.get_token('sort')] = sorting_method
             self.request.session[self.get_token('sort')] = sorting_method
-            
+
         if not sorting_method:
         if not sorting_method:
             if self.sortables:
             if self.sortables:
                 new_sorting = self.sortables.keys()[0]
                 new_sorting = self.sortables.keys()[0]
@@ -201,13 +201,13 @@ class ListWidget(BaseWidget):
                         '-id'
                         '-id'
                        ]
                        ]
         return sorting_method
         return sorting_method
-    
+
     def sort_items(self, page_items, sorting_method):
     def sort_items(self, page_items, sorting_method):
         return page_items.order_by(sorting_method[2])
         return page_items.order_by(sorting_method[2])
-    
+
     def get_pagination_url(self, page):
     def get_pagination_url(self, page):
         return reverse(self.admin.get_action_attr(self.id, 'route'), kwargs={'page': page})
         return reverse(self.admin.get_action_attr(self.id, 'route'), kwargs={'page': page})
-    
+
     def get_pagination(self, total, page):
     def get_pagination(self, total, page):
         """
         """
         Return list pagination.
         Return list pagination.
@@ -222,86 +222,86 @@ class ListWidget(BaseWidget):
         if not self.pagination or total < 0:
         if not self.pagination or total < 0:
             # Dont do anything if we are not paging
             # Dont do anything if we are not paging
             return None
             return None
-        
+
         # Set basic pagination, use either Session cache or new page value
         # Set basic pagination, use either Session cache or new page value
-        pagination = {'start': 0, 'stop': 0, 'prev': -1, 'next': -1}
+        pagination = {'start': 0, 'stop': 0, 'prev':-1, 'next':-1}
         if self.request.session.get(self.get_token('pagination')):
         if self.request.session.get(self.get_token('pagination')):
             pagination['start'] = self.request.session.get(self.get_token('pagination'))
             pagination['start'] = self.request.session.get(self.get_token('pagination'))
         page = int(page)
         page = int(page)
         if page > 0:
         if page > 0:
             pagination['start'] = (page - 1) * self.pagination
             pagination['start'] = (page - 1) * self.pagination
-            
+
         # Set page and total stat
         # Set page and total stat
         pagination['page'] = int(pagination['start'] / self.pagination) + 1
         pagination['page'] = int(pagination['start'] / self.pagination) + 1
         pagination['total'] = int(math.ceil(total / float(self.pagination)))
         pagination['total'] = int(math.ceil(total / float(self.pagination)))
-            
+
         # Fix too large offset
         # Fix too large offset
         if pagination['start'] > total:
         if pagination['start'] > total:
             pagination['start'] = 0
             pagination['start'] = 0
-            
+
         # Allow prev/next?
         # Allow prev/next?
         if total > self.pagination:
         if total > self.pagination:
             if pagination['page'] > 1:
             if pagination['page'] > 1:
                 pagination['prev'] = pagination['page'] - 1
                 pagination['prev'] = pagination['page'] - 1
             if pagination['page'] < pagination['total']:
             if pagination['page'] < pagination['total']:
                 pagination['next'] = pagination['page'] + 1
                 pagination['next'] = pagination['page'] + 1
-                
+
         # Set stop offset
         # Set stop offset
         pagination['stop'] = pagination['start'] + self.pagination
         pagination['stop'] = pagination['start'] + self.pagination
         return pagination
         return pagination
-    
+
     def get_items(self):
     def get_items(self):
         if self.request.session.get(self.get_token('filter')):
         if self.request.session.get(self.get_token('filter')):
             self.is_filtering = True
             self.is_filtering = True
             return self.set_filters(self.admin.model.objects, self.request.session.get(self.get_token('filter')))
             return self.set_filters(self.admin.model.objects, self.request.session.get(self.get_token('filter')))
         return self.admin.model.objects
         return self.admin.model.objects
-            
+
     def __call__(self, request, page=0):
     def __call__(self, request, page=0):
         """
         """
         Use widget as view
         Use widget as view
         """
         """
         self.request = request
         self.request = request
-        
+
         # Get basic list items
         # Get basic list items
         items_total = self.get_items()
         items_total = self.get_items()
-            
+
         # Set extra filters?
         # Set extra filters?
         try:
         try:
             items_total = self.select_items(items_total).count()
             items_total = self.select_items(items_total).count()
         except AttributeError:
         except AttributeError:
             items_total = items_total.count()
             items_total = items_total.count()
-            
+
         # Set sorting and paginating
         # Set sorting and paginating
         sorting_method = self.get_sorting()
         sorting_method = self.get_sorting()
         paginating_method = self.get_pagination(items_total, page)
         paginating_method = self.get_pagination(items_total, page)
-        
+
         # List items
         # List items
         items = self.get_items()
         items = self.get_items()
         if not request.session.get(self.get_token('filter')):
         if not request.session.get(self.get_token('filter')):
             items = items.all()
             items = items.all()
-         
+
         # Set extra filters?
         # Set extra filters?
         try:
         try:
             items = self.select_items(items)
             items = self.select_items(items)
         except AttributeError:
         except AttributeError:
             pass
             pass
-                  
+
         # Sort them
         # Sort them
         items = self.sort_items(items, sorting_method);
         items = self.sort_items(items, sorting_method);
-        
+
         # Set pagination
         # Set pagination
         if self.pagination:
         if self.pagination:
             items = items[paginating_method['start']:paginating_method['stop']]
             items = items[paginating_method['start']:paginating_method['stop']]
-        
+
         # Prefetch related?
         # Prefetch related?
         try:
         try:
             items = self.prefetch_related(items)
             items = self.prefetch_related(items)
         except AttributeError:
         except AttributeError:
             pass
             pass
-        
+
         # Default message
         # Default message
         message = None
         message = None
-        
+
         # See if we should make and handle search form
         # See if we should make and handle search form
         search_form = None
         search_form = None
         SearchForm = self.get_search_form()
         SearchForm = self.get_search_form()
@@ -325,7 +325,7 @@ class ListWidget(BaseWidget):
                     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):
                     request.session[self.get_token('filter')] = None
                     request.session[self.get_token('filter')] = None
@@ -336,7 +336,7 @@ class ListWidget(BaseWidget):
                     search_form = SearchForm(request=request, initial=request.session.get(self.get_token('filter')))
                     search_form = SearchForm(request=request, initial=request.session.get(self.get_token('filter')))
                 else:
                 else:
                     search_form = SearchForm(request=request)
                     search_form = SearchForm(request=request)
-        
+
         # See if we sould make and handle tab form
         # See if we sould make and handle tab form
         table_form = None
         table_form = None
         TableForm = self.get_table_form(items)
         TableForm = self.get_table_form(items)
@@ -352,7 +352,7 @@ class ListWidget(BaseWidget):
                     message = Message(table_form.non_field_errors()[0], 'error')
                     message = Message(table_form.non_field_errors()[0], 'error')
             else:
             else:
                 table_form = TableForm(request=request)
                 table_form = TableForm(request=request)
-        
+
         # See if we should make and handle list form
         # See if we should make and handle list form
         list_form = None
         list_form = None
         ListForm = self.get_actions_form(items)
         ListForm = self.get_actions_form(items)
@@ -378,12 +378,12 @@ class ListWidget(BaseWidget):
                 message.type = 'error'
                 message.type = 'error'
             else:
             else:
                 list_form = ListForm(request=request)
                 list_form = ListForm(request=request)
-        
+
         # Little hax to keep counters correct 
         # Little hax to keep counters correct 
         items_shown = len(items)
         items_shown = len(items)
         if items_total < items_shown:
         if items_total < items_shown:
             items_total = items_shown
             items_total = items_shown
-                
+
         # Render list
         # Render list
         return request.theme.render_to_response(self.get_template(),
         return request.theme.render_to_response(self.get_template(),
                                                 self.add_template_variables({
                                                 self.add_template_variables({
@@ -405,7 +405,7 @@ class ListWidget(BaseWidget):
                                                 }),
                                                 }),
                                                 context_instance=RequestContext(request));
                                                 context_instance=RequestContext(request));
 
 
-                                                
+
 class FormWidget(BaseWidget):
 class FormWidget(BaseWidget):
     """
     """
     Form page widget
     Form page widget
@@ -419,35 +419,35 @@ class FormWidget(BaseWidget):
     translate_target_name = False
     translate_target_name = False
     original_name = None
     original_name = None
     submit_fallback = False
     submit_fallback = False
-    
+
     def get_url(self, model):
     def get_url(self, model):
         return reverse(self.admin.get_action_attr(self.id, 'route'))
         return reverse(self.admin.get_action_attr(self.id, 'route'))
-    
+
     def get_form(self, target):
     def get_form(self, target):
         return self.form
         return self.form
-    
+
     def get_form_instance(self, form, target, initial, post=False):
     def get_form_instance(self, form, target, initial, post=False):
         if post:
         if post:
             return form(self.request.POST, request=self.request, initial=self.get_initial_data(target))
             return form(self.request.POST, request=self.request, initial=self.get_initial_data(target))
         return form(request=self.request, initial=self.get_initial_data(target))
         return form(request=self.request, initial=self.get_initial_data(target))
-    
+
     def get_layout(self, form, model):
     def get_layout(self, form, model):
         if self.layout:
         if self.layout:
             return self.layout
             return self.layout
         return form.layout
         return form.layout
-    
+
     def get_initial_data(self, model):
     def get_initial_data(self, model):
         return {}
         return {}
-    
+
     def submit_form(self, form, model):
     def submit_form(self, form, model):
         """
         """
         Handle form submission, ALWAYS return tuple with model and message
         Handle form submission, ALWAYS return tuple with model and message
         """
         """
         pass
         pass
-    
+
     def __call__(self, request, target=None, slug=None):
     def __call__(self, request, target=None, slug=None):
         self.request = request
         self.request = request
-        
+
         # Fetch target?
         # Fetch target?
         model = None
         model = None
         if target:
         if target:
@@ -456,10 +456,10 @@ class FormWidget(BaseWidget):
             if not model:
             if not model:
                 return redirect(self.get_fallback_url())
                 return redirect(self.get_fallback_url())
         original_model = model
         original_model = model
-        
+
         # Get form type to instantiate
         # Get form type to instantiate
         FormType = self.get_form(model)
         FormType = self.get_form(model)
-        
+
         #Submit form
         #Submit form
         message = None
         message = None
         if request.method == 'POST':
         if request.method == 'POST':
@@ -492,7 +492,7 @@ class FormWidget(BaseWidget):
                 message = Message(form.non_field_errors()[0], 'error')
                 message = Message(form.non_field_errors()[0], 'error')
         else:
         else:
             form = self.get_form_instance(FormType, model, self.get_initial_data(model))
             form = self.get_form_instance(FormType, model, self.get_initial_data(model))
-            
+
         # Render form
         # Render form
         return request.theme.render_to_response(self.get_template(),
         return request.theme.render_to_response(self.get_template(),
                                                 self.add_template_variables({
                                                 self.add_template_variables({
@@ -510,7 +510,7 @@ class FormWidget(BaseWidget):
                                                 }),
                                                 }),
                                                 context_instance=RequestContext(request));
                                                 context_instance=RequestContext(request));
 
 
-                                        
+
 class ButtonWidget(BaseWidget):
 class ButtonWidget(BaseWidget):
     """
     """
     Button Action Widget
     Button Action Widget
@@ -522,7 +522,7 @@ class ButtonWidget(BaseWidget):
     """
     """
     def __call__(self, request, target=None, slug=None):
     def __call__(self, request, target=None, slug=None):
         self.request = request
         self.request = request
-        
+
         # Fetch target?
         # Fetch target?
         model = None
         model = None
         if target:
         if target:
@@ -530,23 +530,23 @@ class ButtonWidget(BaseWidget):
             if not model:
             if not model:
                 return redirect(self.get_fallback_url())
                 return redirect(self.get_fallback_url())
         original_model = model
         original_model = model
-            
+
         # Crash if this is invalid request
         # Crash if this is invalid request
         if not request.csrf.request_secure(request):
         if not request.csrf.request_secure(request):
             request.messages.set_flash(Message(_("Action authorization is invalid.")), 'error', self.admin.id)
             request.messages.set_flash(Message(_("Action authorization is invalid.")), 'error', self.admin.id)
             return redirect(self.get_fallback_url())
             return redirect(self.get_fallback_url())
-        
+
         # Do something
         # Do something
         message, url = self.action(model)
         message, url = self.action(model)
         request.messages.set_flash(message, message.type, self.admin.id)
         request.messages.set_flash(message, message.type, self.admin.id)
         if url:
         if url:
             return redirect(url)
             return redirect(url)
         return redirect(self.get_fallback_url())
         return redirect(self.get_fallback_url())
-        
+
     def action(self, target):
     def action(self, target):
         """
         """
         Action to be executed when button is pressed
         Action to be executed when button is pressed
         Define custom one in your Admin action.
         Define custom one in your Admin action.
         It should return response and message objects 
         It should return response and message objects 
         """
         """
-        pass
+        pass

+ 1 - 1
misago/alerts/management/commands/clearalerts.py

@@ -10,4 +10,4 @@ class Command(BaseCommand):
     help = 'Clears old alerts'
     help = 'Clears old alerts'
     def handle(self, *args, **options):
     def handle(self, *args, **options):
         Alert.objects.filter(date__lte=timezone.now() - timedelta(days=14)).delete()
         Alert.objects.filter(date__lte=timezone.now() - timedelta(days=14)).delete()
-        self.stdout.write('Old Alerts have been cleared.\n')        
+        self.stdout.write('Old Alerts have been cleared.\n')

+ 10 - 10
misago/alerts/models.py

@@ -10,14 +10,14 @@ class Alert(models.Model):
     user = models.ForeignKey('users.User')
     user = models.ForeignKey('users.User')
     date = models.DateTimeField()
     date = models.DateTimeField()
     message = models.TextField()
     message = models.TextField()
-    variables = models.TextField(null=True,blank=True)
-    
+    variables = models.TextField(null=True, blank=True)
+
     def vars(self):
     def vars(self):
         try:
         try:
             return pickle.loads(base64.decodestring(self.variables))
             return pickle.loads(base64.decodestring(self.variables))
         except Exception:
         except Exception:
             return {}
             return {}
-    
+
     def text(self, var, value):
     def text(self, var, value):
         value = cgi.escape(value, True)
         value = cgi.escape(value, True)
         try:
         try:
@@ -25,7 +25,7 @@ class Alert(models.Model):
         except AttributeError:
         except AttributeError:
             self.vars_raw = {var: value}
             self.vars_raw = {var: value}
         return self
         return self
-    
+
     def url(self, var, value, href, attrs=None):
     def url(self, var, value, href, attrs=None):
         url = '<a href="%s"' % cgi.escape(href, True)
         url = '<a href="%s"' % cgi.escape(href, True)
         if attrs:
         if attrs:
@@ -37,27 +37,27 @@ class Alert(models.Model):
         except AttributeError:
         except AttributeError:
             self.vars_raw = {var: url}
             self.vars_raw = {var: url}
         return self
         return self
-    
+
     def profile(self, var, user):
     def profile(self, var, user):
         from django.core.urlresolvers import reverse
         from django.core.urlresolvers import reverse
         return self.url(var, user.username, reverse('user', kwargs={'user': user.pk, 'username': user.username_slug}))
         return self.url(var, user.username, reverse('user', kwargs={'user': user.pk, 'username': user.username_slug}))
-    
+
     def thread(self, var, thread):
     def thread(self, var, thread):
         from django.core.urlresolvers import reverse
         from django.core.urlresolvers import reverse
         return self.url(var, thread.name, reverse('thread', kwargs={'thread': thread.pk, 'slug': thread.slug}))
         return self.url(var, thread.name, reverse('thread', kwargs={'thread': thread.pk, 'slug': thread.slug}))
-    
+
     def post(self, var, thread, post):
     def post(self, var, thread, post):
         from django.core.urlresolvers import reverse
         from django.core.urlresolvers import reverse
         return self.url(var, thread.name, reverse('thread_find', kwargs={'thread': thread.pk, 'slug': thread.slug, 'post': post.pk}))
         return self.url(var, thread.name, reverse('thread_find', kwargs={'thread': thread.pk, 'slug': thread.slug, 'post': post.pk}))
-    
+
     def save_all(self, *args, **kwargs):
     def save_all(self, *args, **kwargs):
         self.save(force_insert=True)
         self.save(force_insert=True)
         self.user.save(force_update=True)
         self.user.save(force_update=True)
-        
+
     def save(self, *args, **kwargs):
     def save(self, *args, **kwargs):
         try:
         try:
             self.variables = base64.encodestring(pickle.dumps(self.vars_raw, pickle.HIGHEST_PROTOCOL))
             self.variables = base64.encodestring(pickle.dumps(self.vars_raw, pickle.HIGHEST_PROTOCOL))
         except AttributeError:
         except AttributeError:
             self.variables = base64.encodestring(pickle.dumps({}, pickle.HIGHEST_PROTOCOL))
             self.variables = base64.encodestring(pickle.dumps({}, pickle.HIGHEST_PROTOCOL))
         super(Alert, self).save(*args, **kwargs)
         super(Alert, self).save(*args, **kwargs)
-        return self.user
+        return self.user

+ 2 - 2
misago/alerts/views.py

@@ -38,7 +38,7 @@ def show_alerts(request):
                 alerts['older'].append(alert)
                 alerts['older'].append(alert)
             except KeyError:
             except KeyError:
                 alerts['older'] = [alert]
                 alerts['older'] = [alert]
-    
+
     new_alerts = request.user.alerts
     new_alerts = request.user.alerts
     request.user.alerts = 0
     request.user.alerts = 0
     request.user.alerts_date = now
     request.user.alerts_date = now
@@ -48,4 +48,4 @@ def show_alerts(request):
                                              'new_alerts': new_alerts,
                                              'new_alerts': new_alerts,
                                              'alerts': alerts,
                                              'alerts': alerts,
                                              },
                                              },
-                                            context_instance=RequestContext(request));
+                                            context_instance=RequestContext(request));

+ 1 - 1
misago/authn/decorators.py

@@ -17,4 +17,4 @@ def block_guest(f):
             from misago.views import error403
             from misago.views import error403
             return error403(request, _("Dear Guest, only signed in members are allowed to access this page. Please sign in or register and try again."))
             return error403(request, _("Dear Guest, only signed in members are allowed to access this page. Please sign in or register and try again."))
         return f(*args, **kwargs)
         return f(*args, **kwargs)
-    return decorator
+    return decorator

+ 3 - 3
misago/authn/fixtures.py

@@ -45,7 +45,7 @@ settings_fixtures = (
 
 
 def load_fixtures():
 def load_fixtures():
     load_settings_fixture(settings_fixtures)
     load_settings_fixture(settings_fixtures)
-    
-    
+
+
 def update_fixtures():
 def update_fixtures():
-    update_settings_fixture(settings_fixtures)
+    update_settings_fixture(settings_fixtures)

+ 4 - 4
misago/authn/forms.py

@@ -6,7 +6,7 @@ class SignInForm(Form):
     user_email = forms.EmailField(max_length=255, label=_("Your email"))
     user_email = forms.EmailField(max_length=255, label=_("Your email"))
     user_password = forms.CharField(widget=forms.PasswordInput, max_length=255, label=_("Your password"))
     user_password = forms.CharField(widget=forms.PasswordInput, max_length=255, label=_("Your password"))
     user_remember_me = forms.BooleanField(label=_("Stay Signed In"), help_text=_("Sign me In automatically next time"), required=False)
     user_remember_me = forms.BooleanField(label=_("Stay Signed In"), help_text=_("Sign me In automatically next time"), required=False)
-    
+
     layout = [
     layout = [
               (
               (
                None,
                None,
@@ -20,11 +20,11 @@ class SignInForm(Form):
                ['user_remember_me'],
                ['user_remember_me'],
                ),
                ),
               ]
               ]
-    
+
     def __init__(self, *args, **kwargs):
     def __init__(self, *args, **kwargs):
         show_remember_me = kwargs['show_remember_me']
         show_remember_me = kwargs['show_remember_me']
         del kwargs['show_remember_me']
         del kwargs['show_remember_me']
-        
+
         super(SignInForm, self).__init__(*args, **kwargs)
         super(SignInForm, self).__init__(*args, **kwargs)
         if not show_remember_me:
         if not show_remember_me:
-            del self.fields['user_remember_me']
+            del self.fields['user_remember_me']

+ 9 - 9
misago/authn/methods.py

@@ -6,7 +6,7 @@ from misago.banning.models import check_ban
 from misago.bruteforce.models import SignInAttempt
 from misago.bruteforce.models import SignInAttempt
 from misago.sessions.models import Token
 from misago.sessions.models import Token
 from misago.users.models import User
 from misago.users.models import User
-    
+
 """
 """
 Exception constants
 Exception constants
 """
 """
@@ -27,11 +27,11 @@ class AuthException(Exception):
         self.password = password
         self.password = password
         self.activation = activation
         self.activation = activation
         self.ban = ban
         self.ban = ban
-        
+
     def __str__(self):
     def __str__(self):
         return self.error
         return self.error
-      
-    
+
+
 def get_user(email, password, admin=False):
 def get_user(email, password, admin=False):
     """
     """
     Fetch user from DB using email/pass pair, scream if either of data is incorrect
     Fetch user from DB using email/pass pair, scream if either of data is incorrect
@@ -47,7 +47,7 @@ def get_user(email, password, admin=False):
             if user.activation != User.ACTIVATION_NONE:
             if user.activation != User.ACTIVATION_NONE:
                 # You have to activate your account - new member
                 # You have to activate your account - new member
                 raise AuthException(ACTIVATION_USER, _("You have to activate your account before you will be able to sign-in."), activation=True)
                 raise AuthException(ACTIVATION_USER, _("You have to activate your account before you will be able to sign-in."), activation=True)
-    
+
     except User.DoesNotExist:
     except User.DoesNotExist:
         raise AuthException(CREDENTIALS, _("Your e-mail address or password is incorrect. Please try again."), password=True)
         raise AuthException(CREDENTIALS, _("Your e-mail address or password is incorrect. Please try again."), password=True)
     return user;
     return user;
@@ -85,17 +85,17 @@ def auth_remember(request, ip):
         except Token.DoesNotExist:
         except Token.DoesNotExist:
             request.cookie_jar.delete('TOKEN')
             request.cookie_jar.delete('TOKEN')
             raise AuthException()
             raise AuthException()
-        
+
         # See if token is not expired
         # See if token is not expired
         token_expires = timezone.now() - timedelta(days=request.settings['remember_me_lifetime'])
         token_expires = timezone.now() - timedelta(days=request.settings['remember_me_lifetime'])
         if request.settings['remember_me_extensible'] and token_rk.accessed < token_expires:
         if request.settings['remember_me_extensible'] and token_rk.accessed < token_expires:
             # Token expired because it's last use is smaller than expiration date
             # Token expired because it's last use is smaller than expiration date
             raise AuthException()
             raise AuthException()
-        
+
         if not request.settings['remember_me_extensible'] and token_rk.created < token_expires:
         if not request.settings['remember_me_extensible'] and token_rk.created < token_expires:
             # Token expired because it was created before expiration date
             # Token expired because it was created before expiration date
             raise AuthException()
             raise AuthException()
-        
+
         # Update token date
         # Update token date
         token_rk.accessed = timezone.now()
         token_rk.accessed = timezone.now()
         token_rk.save(force_update=True)
         token_rk.save(force_update=True)
@@ -122,4 +122,4 @@ def sign_user_in(request, user):
                         )
                         )
     user.save(force_update=True)
     user.save(force_update=True)
     request.session.set_user(user)
     request.session.set_user(user)
-    request.session.set_hidden(user.hide_activity > 0)
+    request.session.set_hidden(user.hide_activity > 0)

+ 1 - 1
misago/authn/urls.py

@@ -10,4 +10,4 @@ urlpatterns = patterns('misago.authn.views',
 if ADMIN_PATH:
 if ADMIN_PATH:
     urlpatterns += patterns('misago.authn.views',
     urlpatterns += patterns('misago.authn.views',
         url(r'^' + ADMIN_PATH + 'signout/$', 'signout', name="admin_sign_out"),
         url(r'^' + ADMIN_PATH + 'signout/$', 'signout', name="admin_sign_out"),
-    )
+    )

+ 11 - 11
misago/authn/views.py

@@ -24,15 +24,15 @@ def signin(request):
     message = request.messages.get_message('security')
     message = request.messages.get_message('security')
     bad_password = False
     bad_password = False
     not_active = False
     not_active = False
-    banned_account = False   
-    
+    banned_account = False
+
     if request.method == 'POST':
     if request.method == 'POST':
         form = SignInForm(
         form = SignInForm(
                           request.POST,
                           request.POST,
                           show_remember_me=not request.firewall.admin and request.settings['remember_me_allow'],
                           show_remember_me=not request.firewall.admin and request.settings['remember_me_allow'],
                           request=request
                           request=request
                           )
                           )
-        
+
         if form.is_valid():
         if form.is_valid():
             try:
             try:
                 # Configure correct auth and redirect links
                 # Configure correct auth and redirect links
@@ -42,17 +42,17 @@ def signin(request):
                 else:
                 else:
                     auth_method = auth_forum
                     auth_method = auth_forum
                     success_redirect = reverse('index')
                     success_redirect = reverse('index')
-                
+
                 # Authenticate user
                 # Authenticate user
                 user = auth_method(
                 user = auth_method(
                                   request,
                                   request,
                                   form.cleaned_data['user_email'],
                                   form.cleaned_data['user_email'],
                                   form.cleaned_data['user_password'],
                                   form.cleaned_data['user_password'],
                                   )
                                   )
-                
-                sign_user_in(request, user)     
+
+                sign_user_in(request, user)
                 remember_me_token = False
                 remember_me_token = False
-                
+
                 if not request.firewall.admin and request.settings['remember_me_allow'] and form.cleaned_data['user_remember_me']:
                 if not request.firewall.admin and request.settings['remember_me_allow'] and form.cleaned_data['user_remember_me']:
                     remember_me_token = get_random_string(42)
                     remember_me_token = get_random_string(42)
                     remember_me = Token(
                     remember_me = Token(
@@ -71,11 +71,11 @@ def signin(request):
                 bad_password = e.password
                 bad_password = e.password
                 banned_account = e.ban
                 banned_account = e.ban
                 not_active = e.activation
                 not_active = e.activation
-                
+
                 # If not in Admin, register failed attempt
                 # If not in Admin, register failed attempt
                 if not request.firewall.admin and e.type == auth.CREDENTIALS:
                 if not request.firewall.admin and e.type == auth.CREDENTIALS:
                     SignInAttempt.objects.register_attempt(request.session.get_ip(request))
                     SignInAttempt.objects.register_attempt(request.session.get_ip(request))
-                    
+
                     # Have we jammed our account?
                     # Have we jammed our account?
                     if SignInAttempt.objects.is_jammed(request.settings, request.session.get_ip(request)):
                     if SignInAttempt.objects.is_jammed(request.settings, request.session.get_ip(request)):
                         request.jam.expires = timezone.now()
                         request.jam.expires = timezone.now()
@@ -94,7 +94,7 @@ def signin(request):
                                              'banned_account': banned_account,
                                              'banned_account': banned_account,
                                              'not_active': not_active,
                                              'not_active': not_active,
                                              'form': FormLayout(form),
                                              'form': FormLayout(form),
-                                             'hide_signin': True, 
+                                             'hide_signin': True,
                                              },
                                              },
                                             context_instance=RequestContext(request));
                                             context_instance=RequestContext(request));
 
 
@@ -107,4 +107,4 @@ def signout(request):
     request.messages.set_flash(Message(_("You have been signed out.")), 'info', 'security')
     request.messages.set_flash(Message(_("You have been signed out.")), 'info', 'security')
     if request.firewall.admin:
     if request.firewall.admin:
         return redirect(reverse(site.get_admin_index()))
         return redirect(reverse(site.get_admin_index()))
-    return redirect(reverse('index'))
+    return redirect(reverse('index'))

+ 1 - 1
misago/banning/context_processors.py

@@ -3,4 +3,4 @@ def banning(request):
         return {}
         return {}
     return {
     return {
         'is_banned': request.ban.is_banned(),
         'is_banned': request.ban.is_banned(),
-    }
+    }

+ 1 - 1
misago/banning/decorators.py

@@ -9,4 +9,4 @@ def block_banned(f):
         except AttributeError:
         except AttributeError:
             pass
             pass
         return f(*args, **kwargs)
         return f(*args, **kwargs)
-    return decorator
+    return decorator

+ 1 - 1
misago/banning/fixtures.py

@@ -1,4 +1,4 @@
 from misago.monitor.fixtures import load_monitor_fixture
 from misago.monitor.fixtures import load_monitor_fixture
 
 
 def load_fixtures():
 def load_fixtures():
-    load_monitor_fixture({'bans_version': 0})
+    load_monitor_fixture({'bans_version': 0})

+ 3 - 3
misago/banning/forms.py

@@ -12,8 +12,8 @@ class BanForm(Form):
                                       (2, _('Ban E-mail address')),
                                       (2, _('Ban E-mail address')),
                                       (3, _('Ban IP Address'))
                                       (3, _('Ban IP Address'))
                                       ))
                                       ))
-    reason_user = forms.CharField(widget=forms.Textarea,required=False)
-    reason_admin = forms.CharField(widget=forms.Textarea,required=False)
+    reason_user = forms.CharField(widget=forms.Textarea, required=False)
+    reason_admin = forms.CharField(widget=forms.Textarea, required=False)
     ban = forms.CharField(max_length=255)
     ban = forms.CharField(max_length=255)
     expires = forms.DateField(required=False)
     expires = forms.DateField(required=False)
     layout = (
     layout = (
@@ -53,4 +53,4 @@ class SearchBansForm(Form):
                 ('type', {'label': _("Type")}),
                 ('type', {'label': _("Type")}),
                ),
                ),
               ),
               ),
-             )
+             )

+ 1 - 1
misago/banning/middleware.py

@@ -14,4 +14,4 @@ class BanningMiddleware(object):
             request.ban.check_for_updates(request)
             request.ban.check_for_updates(request)
             # Make sure banned session is downgraded to guest level
             # Make sure banned session is downgraded to guest level
             if request.ban.is_banned():
             if request.ban.is_banned():
-                request.session.sign_out(request)
+                request.session.sign_out(request)

+ 13 - 13
misago/banning/models.py

@@ -12,11 +12,11 @@ BAN_IP = 3
 class Ban(models.Model):
 class Ban(models.Model):
     type = models.PositiveIntegerField(default=BAN_NAME_EMAIL)
     type = models.PositiveIntegerField(default=BAN_NAME_EMAIL)
     ban = models.CharField(max_length=255)
     ban = models.CharField(max_length=255)
-    reason_user = models.TextField(null=True,blank=True)
-    reason_admin = models.TextField(null=True,blank=True)
-    expires = models.DateTimeField(null=True,blank=True,db_index=True)
+    reason_user = models.TextField(null=True, blank=True)
+    reason_admin = models.TextField(null=True, blank=True)
+    expires = models.DateTimeField(null=True, blank=True, db_index=True)
+
 
 
-    
 def check_ban(ip=False, username=False, email=False):
 def check_ban(ip=False, username=False, email=False):
     bans_model = Ban.objects.filter(Q(expires=None) | Q(expires__gt=timezone.now()))
     bans_model = Ban.objects.filter(Q(expires=None) | Q(expires__gt=timezone.now()))
     if not (ip and username and email):
     if not (ip and username and email):
@@ -32,13 +32,13 @@ def check_ban(ip=False, username=False, email=False):
         if (
         if (
             # Check user name
             # Check user name
             ((username and (ban.type == BAN_NAME_EMAIL or ban.type == BAN_NAME))
             ((username and (ban.type == BAN_NAME_EMAIL or ban.type == BAN_NAME))
-            and re.search('^'+re.escape(ban.ban).replace('\*', '(.*?)')+'$', username, flags=re.IGNORECASE))
+            and re.search('^' + re.escape(ban.ban).replace('\*', '(.*?)') + '$', username, flags=re.IGNORECASE))
             or # Check user email
             or # Check user email
             ((email and (ban.type == BAN_NAME_EMAIL or ban.type == BAN_EMAIL))
             ((email and (ban.type == BAN_NAME_EMAIL or ban.type == BAN_EMAIL))
-            and re.search('^'+re.escape(ban.ban).replace('\*', '(.*?)')+'$', email, flags=re.IGNORECASE))
+            and re.search('^' + re.escape(ban.ban).replace('\*', '(.*?)') + '$', email, flags=re.IGNORECASE))
             or # Check IP address
             or # Check IP address
             (ip and ban.type == BAN_IP
             (ip and ban.type == BAN_IP
-            and re.search('^'+re.escape(ban.ban).replace('\*', '(.*?)')+'$', ip, flags=re.IGNORECASE))):
+            and re.search('^' + re.escape(ban.ban).replace('\*', '(.*?)') + '$', ip, flags=re.IGNORECASE))):
                 return ban
                 return ban
     return False
     return False
 
 
@@ -50,12 +50,12 @@ class BanCache(object):
         self.expires = None
         self.expires = None
         self.reason_user = None
         self.reason_user = None
         self.version = 0
         self.version = 0
-        
+
     def check_for_updates(self, request):
     def check_for_updates(self, request):
         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']
-            
+
             # Check Ban
             # Check Ban
             if request.user.is_authenticated():
             if request.user.is_authenticated():
                 ban = check_ban(
                 ban = check_ban(
@@ -65,7 +65,7 @@ class BanCache(object):
                                 )
                                 )
             else:
             else:
                 ban = check_ban(ip=request.session.get_ip(request))
                 ban = check_ban(ip=request.session.get_ip(request))
-                
+
             # Update ban cache
             # Update ban cache
             if ban:
             if ban:
                 self.banned = True
                 self.banned = True
@@ -78,7 +78,7 @@ class BanCache(object):
                 self.expires = None
                 self.expires = None
                 self.type = None
                 self.type = None
             return True
             return True
-        return False    
-    
+        return False
+
     def is_banned(self):
     def is_banned(self):
-        return self.banned
+        return self.banned

+ 23 - 23
misago/banning/views.py

@@ -40,12 +40,12 @@ class List(ListWidget):
     """
     """
     admin = site.get_action('bans')
     admin = site.get_action('bans')
     id = 'list'
     id = 'list'
-    columns=(
+    columns = (
              ('ban', _("Ban"), 50),
              ('ban', _("Ban"), 50),
              ('expires', _("Expires")),
              ('expires', _("Expires")),
              )
              )
     default_sorting = 'expires'
     default_sorting = 'expires'
-    sortables={
+    sortables = {
                'ban': 1,
                'ban': 1,
                'expires': 0,
                'expires': 0,
               }
               }
@@ -54,10 +54,10 @@ class List(ListWidget):
     empty_message = _('No bans are currently set.')
     empty_message = _('No bans are currently set.')
     empty_search_message = _('No bans have been found.')
     empty_search_message = _('No bans have been found.')
     nothing_checked_message = _('You have to check at least one ban.')
     nothing_checked_message = _('You have to check at least one ban.')
-    actions=(
+    actions = (
              ('delete', _("Lift selected bans"), _("Are you sure you want to lift selected bans?")),
              ('delete', _("Lift selected bans"), _("Are you sure you want to lift selected bans?")),
              )
              )
-    
+
     def set_filters(self, model, filters):
     def set_filters(self, model, filters):
         if 'ban' in filters:
         if 'ban' in filters:
             model = model.filter(ban__contains=filters['ban'])
             model = model.filter(ban__contains=filters['ban'])
@@ -66,7 +66,7 @@ class List(ListWidget):
         if 'type' in filters:
         if 'type' in filters:
             model = model.filter(type__in=filters['type'])
             model = model.filter(type__in=filters['type'])
         return model
         return model
-    
+
     def get_item_actions(self, item):
     def get_item_actions(self, item):
         return (
         return (
                 self.action('pencil', _("Edit Ban"), reverse('admin_bans_edit', item)),
                 self.action('pencil', _("Edit Ban"), reverse('admin_bans_edit', item)),
@@ -77,7 +77,7 @@ class List(ListWidget):
         Ban.objects.filter(id__in=checked).delete()
         Ban.objects.filter(id__in=checked).delete()
         self.request.monitor['bans_version'] = int(self.request.monitor['bans_version']) + 1
         self.request.monitor['bans_version'] = int(self.request.monitor['bans_version']) + 1
         return Message(_('Selected bans have been lifted successfully.'), 'success'), reverse('admin_bans')
         return Message(_('Selected bans have been lifted successfully.'), 'success'), reverse('admin_bans')
-    
+
 
 
 class New(FormWidget):
 class New(FormWidget):
     """
     """
@@ -85,29 +85,29 @@ class New(FormWidget):
     """
     """
     admin = site.get_action('bans')
     admin = site.get_action('bans')
     id = 'new'
     id = 'new'
-    fallback = 'admin_bans' 
+    fallback = 'admin_bans'
     form = BanForm
     form = BanForm
     submit_button = _("Set Ban")
     submit_button = _("Set Ban")
-        
+
     def get_new_url(self, model):
     def get_new_url(self, model):
         return reverse('admin_bans_new')
         return reverse('admin_bans_new')
-    
+
     def get_edit_url(self, model):
     def get_edit_url(self, model):
         return reverse('admin_bans_edit', model)
         return reverse('admin_bans_edit', model)
-    
+
     def submit_form(self, form, target):
     def submit_form(self, form, target):
         new_ban = Ban(
         new_ban = Ban(
-                      type = form.cleaned_data['type'],
-                      ban = form.cleaned_data['ban'],
-                      reason_user = form.cleaned_data['reason_user'],
-                      reason_admin = form.cleaned_data['reason_admin'],
-                      expires = form.cleaned_data['expires']
+                      type=form.cleaned_data['type'],
+                      ban=form.cleaned_data['ban'],
+                      reason_user=form.cleaned_data['reason_user'],
+                      reason_admin=form.cleaned_data['reason_admin'],
+                      expires=form.cleaned_data['expires']
                      )
                      )
         new_ban.save(force_insert=True)
         new_ban.save(force_insert=True)
         self.request.monitor['bans_version'] = int(self.request.monitor['bans_version']) + 1
         self.request.monitor['bans_version'] = int(self.request.monitor['bans_version']) + 1
         return new_ban, Message(_('New Ban has been set.'), 'success')
         return new_ban, Message(_('New Ban has been set.'), 'success')
-    
-   
+
+
 class Edit(FormWidget):
 class Edit(FormWidget):
     """
     """
     Edit Ban
     Edit Ban
@@ -120,13 +120,13 @@ class Edit(FormWidget):
     target_name = 'ban'
     target_name = 'ban'
     notfound_message = _('Requested Ban could not be found.')
     notfound_message = _('Requested Ban could not be found.')
     submit_fallback = True
     submit_fallback = True
-    
+
     def get_url(self, model):
     def get_url(self, model):
         return reverse('admin_bans_edit', model)
         return reverse('admin_bans_edit', model)
-    
+
     def get_edit_url(self, model):
     def get_edit_url(self, model):
         return self.get_url(model)
         return self.get_url(model)
-    
+
     def get_initial_data(self, model):
     def get_initial_data(self, model):
         return {
         return {
                 'type': model.type,
                 'type': model.type,
@@ -135,7 +135,7 @@ class Edit(FormWidget):
                 'reason_admin': model.reason_admin,
                 'reason_admin': model.reason_admin,
                 'expires': model.expires,
                 'expires': model.expires,
                 }
                 }
-    
+
     def submit_form(self, form, target):
     def submit_form(self, form, target):
         target.type = form.cleaned_data['type']
         target.type = form.cleaned_data['type']
         target.ban = form.cleaned_data['ban']
         target.ban = form.cleaned_data['ban']
@@ -155,7 +155,7 @@ class Delete(ButtonWidget):
     id = 'delete'
     id = 'delete'
     fallback = 'admin_bans'
     fallback = 'admin_bans'
     notfound_message = _('Requested Ban could not be found.')
     notfound_message = _('Requested Ban could not be found.')
-    
+
     def action(self, target):
     def action(self, target):
         target.delete()
         target.delete()
         self.request.monitor['bans_version'] = int(self.request.monitor['bans_version']) + 1
         self.request.monitor['bans_version'] = int(self.request.monitor['bans_version']) + 1
@@ -166,4 +166,4 @@ class Delete(ButtonWidget):
         if target.type == 2:
         if target.type == 2:
             return Message(_('E-mail Ban "%(ban)s" has been lifted.') % {'ban': target.ban}, 'success'), False
             return Message(_('E-mail Ban "%(ban)s" has been lifted.') % {'ban': target.ban}, 'success'), False
         if target.type == 3:
         if target.type == 3:
-            return Message(_('IP Ban "%(ban)s" has been lifted.') % {'ban': target.ban}, 'success'), False        
+            return Message(_('IP Ban "%(ban)s" has been lifted.') % {'ban': target.ban}, 'success'), False

+ 1 - 1
misago/bruteforce/context_processors.py

@@ -3,4 +3,4 @@ def is_jammed(request):
         return {}
         return {}
     return {
     return {
         'is_jammed': request.jam.is_jammed(),
         'is_jammed': request.jam.is_jammed(),
-    }
+    }

+ 1 - 1
misago/bruteforce/decorators.py

@@ -7,4 +7,4 @@ def block_jammed(f):
         if not request.firewall.admin and request.jam.is_jammed():
         if not request.firewall.admin and request.jam.is_jammed():
             return error403(request, _("You have used up allowed attempts quota and we temporarily banned you from accessing this page."))
             return error403(request, _("You have used up allowed attempts quota and we temporarily banned you from accessing this page."))
         return f(*args, **kwargs)
         return f(*args, **kwargs)
-    return decorator
+    return decorator

+ 3 - 3
misago/bruteforce/fixtures.py

@@ -40,7 +40,7 @@ settings_fixtures = (
 
 
 def load_fixtures():
 def load_fixtures():
     load_settings_fixture(settings_fixtures)
     load_settings_fixture(settings_fixtures)
-    
-    
+
+
 def update_fixtures():
 def update_fixtures():
-    update_settings_fixture(settings_fixtures)
+    update_settings_fixture(settings_fixtures)

+ 1 - 1
misago/bruteforce/management/commands/clearattempts.py

@@ -9,4 +9,4 @@ class Command(BaseCommand):
     help = 'Clears sign-in attempts log'
     help = 'Clears sign-in attempts log'
     def handle(self):
     def handle(self):
         SignInAttempt.objects.filter(date__lte=timezone.now() - timedelta(hours=24)).delete()
         SignInAttempt.objects.filter(date__lte=timezone.now() - timedelta(hours=24)).delete()
-        self.stdout.write('Failed Sign-In attempts older than 24h have been removed.\n')
+        self.stdout.write('Failed Sign-In attempts older than 24h have been removed.\n')

+ 1 - 1
misago/bruteforce/middleware.py

@@ -10,4 +10,4 @@ class JamMiddleware(object):
             request.jam = JamCache()
             request.jam = JamCache()
             request.session['jam'] = request.jam
             request.session['jam'] = request.jam
         if not request.firewall.admin:
         if not request.firewall.admin:
-            request.jam.check_for_updates(request)
+            request.jam.check_for_updates(request)

+ 8 - 8
misago/bruteforce/models.py

@@ -17,7 +17,7 @@ class SignInAttemptsManager(models.Manager):
     def register_attempt(self, ip):
     def register_attempt(self, ip):
         attempt = SignInAttempt(ip=ip, date=timezone.now())
         attempt = SignInAttempt(ip=ip, date=timezone.now())
         attempt.save(force_insert=True)
         attempt.save(force_insert=True)
-        
+
     def is_jammed(self, settings, ip):
     def is_jammed(self, settings, ip):
         # Limit is off, dont jam IPs?
         # Limit is off, dont jam IPs?
         if settings['attempts_limit'] == 0:
         if settings['attempts_limit'] == 0:
@@ -31,15 +31,15 @@ class SignInAttemptsManager(models.Manager):
         else:
         else:
             attempts = SignInAttempt.objects.filter(ip=ip)
             attempts = SignInAttempt.objects.filter(ip=ip)
         return attempts.count() > settings['attempts_limit']
         return attempts.count() > settings['attempts_limit']
-    
-    
+
+
 class SignInAttempt(models.Model):
 class SignInAttempt(models.Model):
     ip = models.GenericIPAddressField(db_index=True)
     ip = models.GenericIPAddressField(db_index=True)
     date = models.DateTimeField()
     date = models.DateTimeField()
-    
+
     objects = SignInAttemptsManager()
     objects = SignInAttemptsManager()
-    
-    
+
+
 class JamCache(object):
 class JamCache(object):
     jammed = False
     jammed = False
     expires = timezone.now()
     expires = timezone.now()
@@ -49,6 +49,6 @@ class JamCache(object):
             self.expires = timezone.now() + timedelta(minutes=request.settings['jams_lifetime'])
             self.expires = timezone.now() + timedelta(minutes=request.settings['jams_lifetime'])
             return True
             return True
         return False
         return False
-    
+
     def is_jammed(self):
     def is_jammed(self):
-        return self.jammed
+        return self.jammed

+ 1 - 1
misago/captcha/fixtures.py

@@ -66,4 +66,4 @@ def load_fixtures():
 
 
 
 
 def update_fixtures():
 def update_fixtures():
-    update_settings_fixture(settings_fixtures)
+    update_settings_fixture(settings_fixtures)

+ 1 - 1
misago/context_processors.py

@@ -6,4 +6,4 @@ def core(request):
     return {
     return {
         'board_address': settings.BOARD_ADDRESS,
         'board_address': settings.BOARD_ADDRESS,
         'version': get_version(),
         'version': get_version(),
-    }
+    }

+ 6 - 6
misago/cookie_jar/cookie_jar.py

@@ -1,11 +1,11 @@
 from datetime import datetime, timedelta
 from datetime import datetime, timedelta
 from django.conf import settings
 from django.conf import settings
 
 
-class CookieJar(object):    
+class CookieJar(object):
     def __init__(self):
     def __init__(self):
         self._set_cookies = []
         self._set_cookies = []
         self._delete_cookies = []
         self._delete_cookies = []
-    
+
     def set(self, cookie, value, permanent=False):
     def set(self, cookie, value, permanent=False):
         if permanent:
         if permanent:
             # 360 days
             # 360 days
@@ -18,10 +18,10 @@ class CookieJar(object):
                                   'value': value,
                                   'value': value,
                                   'max_age': max_age,
                                   'max_age': max_age,
                                   })
                                   })
-        
+
     def delete(self, cookie):
     def delete(self, cookie):
         self._delete_cookies.append(cookie)
         self._delete_cookies.append(cookie)
-        
+
     def flush(self, response):
     def flush(self, response):
         for cookie in self._set_cookies:
         for cookie in self._set_cookies:
             response.set_cookie(
             response.set_cookie(
@@ -32,10 +32,10 @@ class CookieJar(object):
                                 domain=settings.COOKIES_DOMAIN,
                                 domain=settings.COOKIES_DOMAIN,
                                 secure=settings.COOKIES_SECURE
                                 secure=settings.COOKIES_SECURE
                                 )
                                 )
-        
+
         for cookie in self._delete_cookies:
         for cookie in self._delete_cookies:
             response.delete_cookie(
             response.delete_cookie(
                                    settings.COOKIES_PREFIX + cookie,
                                    settings.COOKIES_PREFIX + cookie,
                                    path=settings.COOKIES_PATH,
                                    path=settings.COOKIES_PATH,
                                    domain=settings.COOKIES_DOMAIN,
                                    domain=settings.COOKIES_DOMAIN,
-                                   )
+                                   )

+ 2 - 2
misago/cookie_jar/middleware.py

@@ -3,10 +3,10 @@ from misago.cookie_jar.cookie_jar import CookieJar
 class CookieJarMiddleware(object):
 class CookieJarMiddleware(object):
     def process_request(self, request):
     def process_request(self, request):
         request.cookie_jar = CookieJar()
         request.cookie_jar = CookieJar()
-                    
+
     def process_response(self, request, response):
     def process_response(self, request, response):
         try:
         try:
             request.cookie_jar.flush(response)
             request.cookie_jar.flush(response)
         except AttributeError:
         except AttributeError:
             pass
             pass
-        return response
+        return response

+ 1 - 1
misago/csrf/context_processors.py

@@ -4,4 +4,4 @@ def csrf(request):
     return {
     return {
         'csrf_id': request.csrf.csrf_id,
         'csrf_id': request.csrf.csrf_id,
         'csrf_token': request.csrf.csrf_token,
         'csrf_token': request.csrf.csrf_token,
-    }
+    }

+ 1 - 1
misago/csrf/decorators.py

@@ -7,4 +7,4 @@ def check_csrf(f):
             from misago.views import error403
             from misago.views import error403
             return error403(request, _("Request authorization is invalid. Please try again."))
             return error403(request, _("Request authorization is invalid. Please try again."))
         return f(*args, **kwargs)
         return f(*args, **kwargs)
-    return decorator
+    return decorator

+ 1 - 1
misago/csrf/middleware.py

@@ -10,4 +10,4 @@ class CSRFMiddleware(object):
         else:
         else:
             csrf_token = get_random_string(16);
             csrf_token = get_random_string(16);
             request.session['csrf_token'] = csrf_token
             request.session['csrf_token'] = csrf_token
-        request.csrf = CSRFProtection(csrf_token)
+        request.csrf = CSRFProtection(csrf_token)

+ 5 - 5
misago/firewalls/firewalls.py

@@ -16,14 +16,14 @@ class FirewallForum(object):
         Firewall test, it checks if requested path is behind firewall
         Firewall test, it checks if requested path is behind firewall
         """
         """
         return path[:len(self.prefix)] == self.prefix
         return path[:len(self.prefix)] == self.prefix
-    
+
     def process_view(self, request, callback, callback_args, callback_kwargs):
     def process_view(self, request, callback, callback_args, callback_kwargs):
         return None
         return None
-    
-    
+
+
 class FirewallAdmin(FirewallForum):
 class FirewallAdmin(FirewallForum):
     admin = True
     admin = True
-    prefix = '/' + ADMIN_PATH    
+    prefix = '/' + ADMIN_PATH
     def process_view(self, request, callback, callback_args, callback_kwargs):
     def process_view(self, request, callback, callback_args, callback_kwargs):
         # Block all crawlers with 403
         # Block all crawlers with 403
         if request.user.is_crawler():
         if request.user.is_crawler():
@@ -36,4 +36,4 @@ class FirewallAdmin(FirewallForum):
             elif not request.user.is_god() and not request.acl.admin.is_admin():
             elif not request.user.is_god() and not request.acl.admin.is_admin():
                 request.messages.set_message(Message(_("Your account does not have admin privileges")), 'error', 'security')
                 request.messages.set_message(Message(_("Your account does not have admin privileges")), 'error', 'security')
                 return signin(request)
                 return signin(request)
-            return None
+            return None

+ 2 - 2
misago/firewalls/middleware.py

@@ -5,7 +5,7 @@ from misago.themes.theme import Theme
 class FirewallMiddleware(object):
 class FirewallMiddleware(object):
     firewall_admin = FirewallAdmin()
     firewall_admin = FirewallAdmin()
     firewall_forum = FirewallForum()
     firewall_forum = FirewallForum()
-    
+
     def process_request(self, request):
     def process_request(self, request):
         if settings.ADMIN_PATH and self.firewall_admin.behind_firewall(request.path_info):
         if settings.ADMIN_PATH and self.firewall_admin.behind_firewall(request.path_info):
             request.firewall = self.firewall_admin
             request.firewall = self.firewall_admin
@@ -14,4 +14,4 @@ class FirewallMiddleware(object):
             request.firewall = self.firewall_forum
             request.firewall = self.firewall_forum
 
 
     def process_view(self, request, callback, callback_args, callback_kwargs):
     def process_view(self, request, callback, callback_args, callback_kwargs):
-        return request.firewall.process_view(request, callback, callback_args, callback_kwargs)
+        return request.firewall.process_view(request, callback, callback_args, callback_kwargs)

+ 22 - 22
misago/forms/__init__.py

@@ -14,13 +14,13 @@ class Form(forms.Form):
     error_source = None
     error_source = None
     def __init__(self, data=None, file=None, request=None, *args, **kwargs):
     def __init__(self, data=None, file=None, request=None, *args, **kwargs):
         self.request = request
         self.request = request
-                
+
         # Extract request from first argument
         # Extract request from first argument
         if data != None:
         if data != None:
             super(Form, self).__init__(data, file, *args, **kwargs)
             super(Form, self).__init__(data, file, *args, **kwargs)
         else:
         else:
             super(Form, self).__init__(*args, **kwargs)
             super(Form, self).__init__(*args, **kwargs)
-            
+
         # Kill captcha fields
         # Kill captcha fields
         try:
         try:
             if self.request.settings['bots_registration'] != 'recaptcha' or self.request.session.get('captcha_passed'):
             if self.request.settings['bots_registration'] != 'recaptcha' or self.request.session.get('captcha_passed'):
@@ -36,18 +36,18 @@ class Form(forms.Form):
                 self.fields['captcha_qa'].help_text = self.request.settings['qa_test_help']
                 self.fields['captcha_qa'].help_text = self.request.settings['qa_test_help']
         except KeyError:
         except KeyError:
             pass
             pass
-        
+
         # Let forms do mumbo-jumbo with fields removing
         # Let forms do mumbo-jumbo with fields removing
         self.finalize_form()
         self.finalize_form()
-     
+
     def finalize_form(self):
     def finalize_form(self):
         pass
         pass
-        
+
     def full_clean(self):
     def full_clean(self):
         """
         """
         Trim inputs and strip newlines
         Trim inputs and strip newlines
         """
         """
-        self.data = self.data.copy() 
+        self.data = self.data.copy()
         for key, field in self.fields.iteritems():
         for key, field in self.fields.iteritems():
             try:
             try:
                 if field.__class__.__name__ in ['ModelChoiceField', 'TreeForeignKey'] and self.data[key]:
                 if field.__class__.__name__ in ['ModelChoiceField', 'TreeForeignKey'] and self.data[key]:
@@ -68,7 +68,7 @@ class Form(forms.Form):
             except (KeyError, AttributeError):
             except (KeyError, AttributeError):
                 pass
                 pass
         super(Form, self).full_clean()
         super(Form, self).full_clean()
-     
+
     def clean(self):
     def clean(self):
         """
         """
         Clean data, do magic checks and stuff
         Clean data, do magic checks and stuff
@@ -76,7 +76,7 @@ class Form(forms.Form):
         cleaned_data = super(Form, self).clean()
         cleaned_data = super(Form, self).clean()
         self._check_all()
         self._check_all()
         return cleaned_data
         return cleaned_data
-         
+
     def clean_recaptcha(self):
     def clean_recaptcha(self):
         """
         """
         Test reCaptcha, scream if it went wrong
         Test reCaptcha, scream if it went wrong
@@ -91,25 +91,25 @@ class Form(forms.Form):
             raise forms.ValidationError(_("Entered words are incorrect. Please try again."))
             raise forms.ValidationError(_("Entered words are incorrect. Please try again."))
         self.request.session['captcha_passed'] = True
         self.request.session['captcha_passed'] = True
         return ''
         return ''
-    
+
     def clean_captcha_qa(self):
     def clean_captcha_qa(self):
         """
         """
         Test QA Captcha, scream if it went wrong
         Test QA Captcha, scream if it went wrong
         """
         """
-        
+
         if not unicode(self.cleaned_data['captcha_qa']).lower() in (name.lower() for name in unicode(self.request.settings['qa_test_answers']).splitlines()):
         if not unicode(self.cleaned_data['captcha_qa']).lower() in (name.lower() for name in unicode(self.request.settings['qa_test_answers']).splitlines()):
             raise forms.ValidationError(_("The answer you entered is incorrect."))
             raise forms.ValidationError(_("The answer you entered is incorrect."))
         self.request.session['captcha_passed'] = True
         self.request.session['captcha_passed'] = True
         return self.cleaned_data['captcha_qa']
         return self.cleaned_data['captcha_qa']
-    
+
     def _check_all(self):
     def _check_all(self):
         # Check repeated fields
         # Check repeated fields
         self._check_repeats()
         self._check_repeats()
         # Check CSRF, we dont allow un-csrf'd forms in Misago
         # Check CSRF, we dont allow un-csrf'd forms in Misago
         self._check_csrf()
         self._check_csrf()
         # Check if we have any errors from fields, if we do, we will set fancy form-wide error message
         # Check if we have any errors from fields, if we do, we will set fancy form-wide error message
-        self._check_fields_errors()    
-       
+        self._check_fields_errors()
+
     def _check_repeats(self):
     def _check_repeats(self):
         for index, repeat in enumerate(self.validate_repeats):
         for index, repeat in enumerate(self.validate_repeats):
             # Check empty fields
             # Check empty fields
@@ -118,15 +118,15 @@ class Form(forms.Form):
                     try:
                     try:
                         if len(repeat) == 2:
                         if len(repeat) == 2:
                             self.errors['_'.join(repeat)] = [self.repeats_errors[index]['fill_both']]
                             self.errors['_'.join(repeat)] = [self.repeats_errors[index]['fill_both']]
-                        else: 
+                        else:
                             self.errors['_'.join(repeat)] = [self.repeats_errors[index]['fill_all']]
                             self.errors['_'.join(repeat)] = [self.repeats_errors[index]['fill_all']]
                     except (IndexError, KeyError):
                     except (IndexError, KeyError):
                         if len(repeat) == 2:
                         if len(repeat) == 2:
                             self.errors['_'.join(repeat)] = [_("You have to fill in both fields.")]
                             self.errors['_'.join(repeat)] = [_("You have to fill in both fields.")]
-                        else: 
+                        else:
                             self.errors['_'.join(repeat)] = [_("You have to fill in all fields.")]
                             self.errors['_'.join(repeat)] = [_("You have to fill in all fields.")]
                     break
                     break
-                    
+
             else:
             else:
                 # Check different fields
                 # Check different fields
                 past_field = self.data[repeat[0]]
                 past_field = self.data[repeat[0]]
@@ -138,22 +138,22 @@ class Form(forms.Form):
                             self.errors['_'.join(repeat)] = [_("Entered values differ from each other.")]
                             self.errors['_'.join(repeat)] = [_("Entered values differ from each other.")]
                         break
                         break
                     past_field = self.data[field]
                     past_field = self.data[field]
-            
-        
+
+
     def _check_csrf(self):
     def _check_csrf(self):
         if not self.request.csrf.request_secure(self.request):
         if not self.request.csrf.request_secure(self.request):
             raise forms.ValidationError(_("Request authorization is invalid. Please resubmit your form."))
             raise forms.ValidationError(_("Request authorization is invalid. Please resubmit your form."))
-        
+
     def _check_fields_errors(self):
     def _check_fields_errors(self):
         if self.errors:
         if self.errors:
             if self.error_source and self.error_source in self.errors:
             if self.error_source and self.error_source in self.errors:
                 field_error, self.errors[self.error_source] = self.errors[self.error_source][0], []
                 field_error, self.errors[self.error_source] = self.errors[self.error_source][0], []
                 raise forms.ValidationError(field_error)
                 raise forms.ValidationError(field_error)
             raise forms.ValidationError(_("Form contains errors."))
             raise forms.ValidationError(_("Form contains errors."))
-        
-        
+
+
 class YesNoSwitch(forms.CheckboxInput):
 class YesNoSwitch(forms.CheckboxInput):
     """
     """
     Custom Yes-No switch as fancier alternative to checkboxes
     Custom Yes-No switch as fancier alternative to checkboxes
     """
     """
-    pass
+    pass

+ 39 - 40
misago/forms/layouts.py

@@ -5,12 +5,12 @@ class FormLayout(object):
     def __init__(self, form, fieldsets=False):
     def __init__(self, form, fieldsets=False):
         scaffold_fields = FormFields(form)
         scaffold_fields = FormFields(form)
         scaffold_fieldsets = FormFieldsets(form, scaffold_fields.fields, fieldsets)
         scaffold_fieldsets = FormFieldsets(form, scaffold_fields.fields, fieldsets)
-        
+
         self.multipart_form = scaffold_fields.multipart_form
         self.multipart_form = scaffold_fields.multipart_form
         self.fieldsets = scaffold_fieldsets.fieldsets
         self.fieldsets = scaffold_fieldsets.fieldsets
         self.fields = scaffold_fields.fields
         self.fields = scaffold_fields.fields
         self.hidden = scaffold_fields.hidden
         self.hidden = scaffold_fields.hidden
-    
+
 class FormFields(object):
 class FormFields(object):
     """
     """
     Hydrator that builds fields list from form and blueprint
     Hydrator that builds fields list from form and blueprint
@@ -19,14 +19,14 @@ class FormFields(object):
         self.multipart_form = False
         self.multipart_form = False
         self.fields = {}
         self.fields = {}
         self.hidden = []
         self.hidden = []
-        
+
         # Extract widgets from meta
         # Extract widgets from meta
         self.meta_widgets = {}
         self.meta_widgets = {}
         try:
         try:
             self.meta_widgets = form.Meta.widgets
             self.meta_widgets = form.Meta.widgets
         except AttributeError:
         except AttributeError:
             pass
             pass
-                
+
         # Find out field input types
         # Find out field input types
         for field in form.fields.keys():
         for field in form.fields.keys():
             widget = self._get_widget(field, form.fields[field])
             widget = self._get_widget(field, form.fields[field])
@@ -56,11 +56,11 @@ class FormFields(object):
                          'widget': '',
                          'widget': '',
                          'choices': [],
                          'choices': [],
                         }
                         }
-            
+
             # Set multipart form
             # Set multipart form
             if widget.needs_multipart_form:
             if widget.needs_multipart_form:
                 self.multipart_form = True
                 self.multipart_form = True
-            
+
             # Get errors?
             # Get errors?
             if form.is_bound:
             if form.is_bound:
                 for error in bound_field._errors():
                 for error in bound_field._errors():
@@ -71,14 +71,14 @@ class FormFields(object):
                             blueprint['errors'].append(error)
                             blueprint['errors'].append(error)
                 except KeyError:
                 except KeyError:
                     pass
                     pass
-            
+
             # Use clean value instead?
             # Use clean value instead?
             try:
             try:
                 if field in form.cleaned_data:
                 if field in form.cleaned_data:
                     blueprint['value'] = form.cleaned_data[field]
                     blueprint['value'] = form.cleaned_data[field]
             except AttributeError:
             except AttributeError:
                 pass
                 pass
-            
+
             # TextInput
             # TextInput
             if widget_name in ['TextInput', 'PasswordInput', 'Textarea']:
             if widget_name in ['TextInput', 'PasswordInput', 'Textarea']:
                 blueprint['widget'] = 'text'
                 blueprint['widget'] = 'text'
@@ -87,15 +87,15 @@ class FormFields(object):
                     blueprint['attrs']['maxlength'] = bound_field.field.max_length
                     blueprint['attrs']['maxlength'] = bound_field.field.max_length
                 except AttributeError:
                 except AttributeError:
                     pass
                     pass
-            
+
             # PasswordInput
             # PasswordInput
             if widget_name == 'PasswordInput':
             if widget_name == 'PasswordInput':
                 blueprint['attrs']['type'] = 'password'
                 blueprint['attrs']['type'] = 'password'
-              
+
             # Textarea      
             # Textarea      
             if widget_name == 'Textarea':
             if widget_name == 'Textarea':
                 blueprint['widget'] = 'textarea'
                 blueprint['widget'] = 'textarea'
-                
+
             # ReCaptcha      
             # ReCaptcha      
             if widget_name == 'ReCaptchaWidget':
             if widget_name == 'ReCaptchaWidget':
                 from recaptcha.client.captcha import displayhtml
                 from recaptcha.client.captcha import displayhtml
@@ -105,26 +105,26 @@ class FormFields(object):
                                                           form.request.settings['recaptcha_ssl'],
                                                           form.request.settings['recaptcha_ssl'],
                                                           bound_field.field.api_error,
                                                           bound_field.field.api_error,
                                                           )}
                                                           )}
-                
+
             # HiddenInput
             # HiddenInput
             if widget_name == 'HiddenInput':
             if widget_name == 'HiddenInput':
                 blueprint['widget'] = 'hidden'
                 blueprint['widget'] = 'hidden'
-                
+
             # MultipleHiddenInput
             # MultipleHiddenInput
             if widget_name == 'MultipleHiddenInput':
             if widget_name == 'MultipleHiddenInput':
                 blueprint['widget'] = 'multiple_hidden'
                 blueprint['widget'] = 'multiple_hidden'
                 blueprint['attrs'] = {
                 blueprint['attrs'] = {
                                       'choices': widget.choices
                                       'choices': widget.choices
                                      }
                                      }
-            
+
             # FileInput
             # FileInput
             if widget_name == 'FileInput':
             if widget_name == 'FileInput':
                 blueprint['widget'] = 'file'
                 blueprint['widget'] = 'file'
-            
+
             # ClearableFileInput
             # ClearableFileInput
             if widget_name == 'ClearableFileInput':
             if widget_name == 'ClearableFileInput':
                 blueprint['widget'] = 'file_clearable'
                 blueprint['widget'] = 'file_clearable'
-                
+
             # DateInput
             # DateInput
             if widget_name == 'DateInput':
             if widget_name == 'DateInput':
                 blueprint['widget'] = 'date'
                 blueprint['widget'] = 'date'
@@ -132,7 +132,7 @@ class FormFields(object):
                     blueprint['value'] = blueprint['value'].strftime('%Y-%m-%d')
                     blueprint['value'] = blueprint['value'].strftime('%Y-%m-%d')
                 except AttributeError as e:
                 except AttributeError as e:
                     pass
                     pass
-            
+
             # DateTimeInput
             # DateTimeInput
             if widget_name == 'DateTimeInput':
             if widget_name == 'DateTimeInput':
                 blueprint['widget'] = 'datetime'
                 blueprint['widget'] = 'datetime'
@@ -140,7 +140,7 @@ class FormFields(object):
                     blueprint['value'] = blueprint['value'].strftime('%Y-%m-%d %H:%M')
                     blueprint['value'] = blueprint['value'].strftime('%Y-%m-%d %H:%M')
                 except AttributeError as e:
                 except AttributeError as e:
                     pass
                     pass
-            
+
             # TimeInput
             # TimeInput
             if widget_name == 'TimeInput':
             if widget_name == 'TimeInput':
                 blueprint['widget'] = 'time'
                 blueprint['widget'] = 'time'
@@ -148,87 +148,87 @@ class FormFields(object):
                     blueprint['value'] = blueprint['value'].strftime('%H:%M')
                     blueprint['value'] = blueprint['value'].strftime('%H:%M')
                 except AttributeError as e:
                 except AttributeError as e:
                     pass
                     pass
-                
+
             # CheckboxInput
             # CheckboxInput
             if widget_name == 'CheckboxInput':
             if widget_name == 'CheckboxInput':
                 blueprint['widget'] = 'checkbox'
                 blueprint['widget'] = 'checkbox'
-                
+
             # Select, NullBooleanSelect, SelectMultiple, RadioSelect, CheckboxSelectMultiple
             # Select, NullBooleanSelect, SelectMultiple, RadioSelect, CheckboxSelectMultiple
             if widget_name in ['Select', 'NullBooleanSelect', 'SelectMultiple', 'RadioSelect', 'CheckboxSelectMultiple']:
             if widget_name in ['Select', 'NullBooleanSelect', 'SelectMultiple', 'RadioSelect', 'CheckboxSelectMultiple']:
                 blueprint['choices'] = widget.choices
                 blueprint['choices'] = widget.choices
-                
+
             # Yes-no radio select
             # Yes-no radio select
             if widget_name == 'YesNoSwitch':
             if widget_name == 'YesNoSwitch':
                 blueprint['widget'] = 'yes_no_switch'
                 blueprint['widget'] = 'yes_no_switch'
-            
+
             # Select
             # Select
             if widget_name == 'Select':
             if widget_name == 'Select':
                 blueprint['widget'] = 'select'
                 blueprint['widget'] = 'select'
                 if not blueprint['value']:
                 if not blueprint['value']:
                     blueprint['value'] = u''
                     blueprint['value'] = u''
-                
+
             # NullBooleanSelect
             # NullBooleanSelect
             if widget_name == 'NullBooleanSelect':
             if widget_name == 'NullBooleanSelect':
                 blueprint['widget'] = 'null_boolean_select'
                 blueprint['widget'] = 'null_boolean_select'
-                
+
             # SelectMultiple
             # SelectMultiple
             if widget_name == 'SelectMultiple':
             if widget_name == 'SelectMultiple':
                 blueprint['widget'] = 'select_multiple'
                 blueprint['widget'] = 'select_multiple'
-                
+
             # RadioSelect
             # RadioSelect
             if widget_name == 'RadioSelect':
             if widget_name == 'RadioSelect':
                 blueprint['widget'] = 'radio_select'
                 blueprint['widget'] = 'radio_select'
                 if not blueprint['value']:
                 if not blueprint['value']:
                     blueprint['value'] = u''
                     blueprint['value'] = u''
-                
+
             # CheckboxSelectMultiple
             # CheckboxSelectMultiple
             if widget_name == 'CheckboxSelectMultiple':
             if widget_name == 'CheckboxSelectMultiple':
                 blueprint['widget'] = 'checkbox_select_multiple'
                 blueprint['widget'] = 'checkbox_select_multiple'
-            
+
             # MultiWidget
             # MultiWidget
             if widget_name == 'MultiWidget':
             if widget_name == 'MultiWidget':
                 blueprint['widget'] = 'multi'
                 blueprint['widget'] = 'multi'
-            
+
             # SplitDateTimeWidget
             # SplitDateTimeWidget
             if widget_name == 'SplitDateTimeWidget':
             if widget_name == 'SplitDateTimeWidget':
                 blueprint['widget'] = 'split_datetime'
                 blueprint['widget'] = 'split_datetime'
-            
+
             # SplitHiddenDateTimeWidget
             # SplitHiddenDateTimeWidget
             if widget_name == 'SplitHiddenDateTimeWidget':
             if widget_name == 'SplitHiddenDateTimeWidget':
                 blueprint['widget'] = 'split_hidden_datetime'
                 blueprint['widget'] = 'split_hidden_datetime'
-            
+
             # SelectDateWidget
             # SelectDateWidget
             if widget_name == 'SelectDateWidget':
             if widget_name == 'SelectDateWidget':
                 blueprint['widget'] = 'select_date'
                 blueprint['widget'] = 'select_date'
                 blueprint['years'] = widget.years
                 blueprint['years'] = widget.years
-                
+
             # Store field in either of collections
             # Store field in either of collections
             if blueprint['hidden']:
             if blueprint['hidden']:
                 blueprint['attrs']['type'] = 'hidden'
                 blueprint['attrs']['type'] = 'hidden'
                 self.hidden.append(blueprint)
                 self.hidden.append(blueprint)
             else:
             else:
                 self.fields[field] = blueprint
                 self.fields[field] = blueprint
-                                
+
     def _get_widget(self, name, field):
     def _get_widget(self, name, field):
         if name in self.meta_widgets:
         if name in self.meta_widgets:
             return self.meta_widgets[name]
             return self.meta_widgets[name]
         return field.widget
         return field.widget
-    
-    
+
+
 class FormFieldsets(object):
 class FormFieldsets(object):
     """
     """
     Hydrator that builds fieldset from form and blueprint
     Hydrator that builds fieldset from form and blueprint
     """
     """
     def __init__(self, form, fields, fieldsets=None):
     def __init__(self, form, fields, fieldsets=None):
         self.fieldsets = []
         self.fieldsets = []
-        
+
         # Use form layout
         # Use form layout
         if not fieldsets:
         if not fieldsets:
             try:
             try:
                 fieldsets = form.layout
                 fieldsets = form.layout
             except AttributeError:
             except AttributeError:
                 pass
                 pass
-        
+
         # Build fieldsets data
         # Build fieldsets data
         if fieldsets:
         if fieldsets:
             for blueprint in fieldsets:
             for blueprint in fieldsets:
@@ -268,7 +268,7 @@ class FormFieldsets(object):
                             if not subfields['help_text']:
                             if not subfields['help_text']:
                                 subfields['help_text'] = subfields['nested'][0]['help_text']
                                 subfields['help_text'] = subfields['nested'][0]['help_text']
                             try:
                             try:
-                                subfields['errors'] = form.errors["_".join(subfiels_ids)] 
+                                subfields['errors'] = form.errors["_".join(subfiels_ids)]
                             except KeyError:
                             except KeyError:
                                 pass
                                 pass
                             fieldset['fields'].append(subfields)
                             fieldset['fields'].append(subfields)
@@ -291,10 +291,9 @@ class FormFieldsets(object):
                     fieldset['help'] = blueprint[2]
                     fieldset['help'] = blueprint[2]
                 except IndexError:
                 except IndexError:
                     pass
                     pass
-                
+
                 # Append complete fieldset
                 # Append complete fieldset
                 if fieldset['fields']:
                 if fieldset['fields']:
                     self.fieldsets.append(fieldset)
                     self.fieldsets.append(fieldset)
             self.fieldsets[-1]['last'] = True
             self.fieldsets[-1]['last'] = True
-        
-        
+

+ 6 - 6
misago/forumroles/fixtures.py

@@ -41,7 +41,7 @@ def load_fixtures():
                           'can_delete_attachments': True,
                           'can_delete_attachments': True,
                           })
                           })
     role.save(force_insert=True)
     role.save(force_insert=True)
-    
+
     role = ForumRole()
     role = ForumRole()
     role.name = _('Standard Access and Upload').message
     role.name = _('Standard Access and Upload').message
     role.set_permissions({
     role.set_permissions({
@@ -63,7 +63,7 @@ def load_fixtures():
                           'attachment_limit': 3,
                           'attachment_limit': 3,
                           })
                           })
     role.save(force_insert=True)
     role.save(force_insert=True)
-    
+
     role = ForumRole()
     role = ForumRole()
     role.name = _('Standard Access').message
     role.name = _('Standard Access').message
     role.set_permissions({
     role.set_permissions({
@@ -82,7 +82,7 @@ def load_fixtures():
                           'can_download_attachments': True,
                           'can_download_attachments': True,
                           })
                           })
     role.save(force_insert=True)
     role.save(force_insert=True)
-    
+
     role = ForumRole()
     role = ForumRole()
     role.name = _('Read and Download').message
     role.name = _('Read and Download').message
     role.set_permissions({
     role.set_permissions({
@@ -92,7 +92,7 @@ def load_fixtures():
                           'can_download_attachments': True,
                           'can_download_attachments': True,
                           })
                           })
     role.save(force_insert=True)
     role.save(force_insert=True)
-    
+
     role = ForumRole()
     role = ForumRole()
     role.name = _('Threads list only').message
     role.name = _('Threads list only').message
     role.set_permissions({
     role.set_permissions({
@@ -100,7 +100,7 @@ def load_fixtures():
                           'can_see_forum_contents': True,
                           'can_see_forum_contents': True,
                           })
                           })
     role.save(force_insert=True)
     role.save(force_insert=True)
-    
+
     role = ForumRole()
     role = ForumRole()
     role.name = _('Read only').message
     role.name = _('Read only').message
     role.set_permissions({
     role.set_permissions({
@@ -108,4 +108,4 @@ def load_fixtures():
                           'can_see_forum_contents': True,
                           'can_see_forum_contents': True,
                           'can_read_threads': '2',
                           'can_read_threads': '2',
                           })
                           })
-    role.save(force_insert=True)
+    role.save(force_insert=True)

+ 3 - 3
misago/forumroles/forms.py

@@ -4,11 +4,11 @@ from misago.forms import Form
 from misago.utils.validators import validate_sluggable
 from misago.utils.validators import validate_sluggable
 
 
 class ForumRoleForm(Form):
 class ForumRoleForm(Form):
-    name = forms.CharField(max_length=255,validators=[validate_sluggable(
+    name = forms.CharField(max_length=255, validators=[validate_sluggable(
                                                                          _("Role name must be sluggable."),
                                                                          _("Role name must be sluggable."),
                                                                          _("Role name is too long.")
                                                                          _("Role name is too long.")
                                                                          )])
                                                                          )])
-    
+
     def finalize_form(self):
     def finalize_form(self):
         self.layout = (
         self.layout = (
                        (
                        (
@@ -17,4 +17,4 @@ class ForumRoleForm(Form):
                          ('name', {'label': _("Role Name"), 'help_text': _("Role Name is used to identify this role in Admin Control Panel.")}),
                          ('name', {'label': _("Role Name"), 'help_text': _("Role Name is used to identify this role in Admin Control Panel.")}),
                          ),
                          ),
                         ),
                         ),
-                       )
+                       )

+ 7 - 7
misago/forumroles/models.py

@@ -12,25 +12,25 @@ class ForumRole(models.Model):
     Misago User Role model
     Misago User Role model
     """
     """
     name = models.CharField(max_length=255)
     name = models.CharField(max_length=255)
-    permissions = models.TextField(null=True,blank=True)
+    permissions = models.TextField(null=True, blank=True)
     permissions_cache = {}
     permissions_cache = {}
-    
+
     def __unicode__(self):
     def __unicode__(self):
         return unicode(_(self.name))
         return unicode(_(self.name))
-    
+
     def get_permissions(self):
     def get_permissions(self):
         if self.permissions_cache:
         if self.permissions_cache:
             return self.permissions_cache
             return self.permissions_cache
-        
+
         try:
         try:
             self.permissions_cache = pickle.loads(base64.decodestring(self.permissions))
             self.permissions_cache = pickle.loads(base64.decodestring(self.permissions))
         except Exception:
         except Exception:
             # ValueError, SuspiciousOperation, unpickling exceptions. If any of
             # ValueError, SuspiciousOperation, unpickling exceptions. If any of
             # these happen, just return an empty dictionary (an empty permissions list).
             # these happen, just return an empty dictionary (an empty permissions list).
             self.permissions_cache = {}
             self.permissions_cache = {}
-            
+
         return self.permissions_cache
         return self.permissions_cache
-    
+
     def set_permissions(self, permissions):
     def set_permissions(self, permissions):
         self.permissions_cache = permissions
         self.permissions_cache = permissions
-        self.permissions = base64.encodestring(pickle.dumps(permissions, pickle.HIGHEST_PROTOCOL))
+        self.permissions = base64.encodestring(pickle.dumps(permissions, pickle.HIGHEST_PROTOCOL))

+ 28 - 28
misago/forumroles/views.py

@@ -1,7 +1,7 @@
 import copy
 import copy
 from django.core.urlresolvers import reverse as django_reverse
 from django.core.urlresolvers import reverse as django_reverse
 from django.utils.translation import ugettext as _
 from django.utils.translation import ugettext as _
-from misago.acl.builder import build_forum_form 
+from misago.acl.builder import build_forum_form
 from misago.admin import site
 from misago.admin import site
 from misago.admin.widgets import *
 from misago.admin.widgets import *
 from misago.utils import slugify
 from misago.utils import slugify
@@ -20,17 +20,17 @@ Views
 class List(ListWidget):
 class List(ListWidget):
     admin = site.get_action('roles_forums')
     admin = site.get_action('roles_forums')
     id = 'list'
     id = 'list'
-    columns=(
-             ('role', _("Role")),
-             )
+    columns = (
+               ('role', _("Role")),
+               )
     nothing_checked_message = _('You have to check at least one role.')
     nothing_checked_message = _('You have to check at least one role.')
-    actions=(
-             ('delete', _("Delete selected forum roles"), _("Are you sure you want to delete selected roles?")),
-             )
-    
+    actions = (
+               ('delete', _("Delete selected forum roles"), _("Are you sure you want to delete selected roles?")),
+               )
+
     def sort_items(self, page_items, sorting_method):
     def sort_items(self, page_items, sorting_method):
         return page_items.order_by('name')
         return page_items.order_by('name')
-    
+
     def get_item_actions(self, item):
     def get_item_actions(self, item):
         return (
         return (
                 self.action('adjust', _("Role Permissions"), reverse('admin_roles_forums_acl', item)),
                 self.action('adjust', _("Role Permissions"), reverse('admin_roles_forums_acl', item)),
@@ -47,24 +47,24 @@ class List(ListWidget):
 class New(FormWidget):
 class New(FormWidget):
     admin = site.get_action('roles_forums')
     admin = site.get_action('roles_forums')
     id = 'new'
     id = 'new'
-    fallback = 'admin_roles_forums' 
+    fallback = 'admin_roles_forums'
     form = ForumRoleForm
     form = ForumRoleForm
     submit_button = _("Save Role")
     submit_button = _("Save Role")
-        
+
     def get_new_url(self, model):
     def get_new_url(self, model):
         return reverse('admin_roles_forums_new')
         return reverse('admin_roles_forums_new')
-    
+
     def get_edit_url(self, model):
     def get_edit_url(self, model):
         return reverse('admin_roles_forums_edit', model)
         return reverse('admin_roles_forums_edit', model)
-    
+
     def submit_form(self, form, target):
     def submit_form(self, form, target):
         new_role = ForumRole(
         new_role = ForumRole(
-                      name = form.cleaned_data['name'],
+                      name=form.cleaned_data['name'],
                      )
                      )
         new_role.save(force_insert=True)
         new_role.save(force_insert=True)
         return new_role, Message(_('New Forum Role has been created.'), 'success')
         return new_role, Message(_('New Forum Role has been created.'), 'success')
-    
-   
+
+
 class Edit(FormWidget):
 class Edit(FormWidget):
     admin = site.get_action('roles_forums')
     admin = site.get_action('roles_forums')
     id = 'edit'
     id = 'edit'
@@ -74,18 +74,18 @@ class Edit(FormWidget):
     target_name = 'name'
     target_name = 'name'
     notfound_message = _('Requested Forum Role could not be found.')
     notfound_message = _('Requested Forum Role could not be found.')
     submit_fallback = True
     submit_fallback = True
-    
+
     def get_url(self, model):
     def get_url(self, model):
         return reverse('admin_roles_forums_edit', model)
         return reverse('admin_roles_forums_edit', model)
-    
+
     def get_edit_url(self, model):
     def get_edit_url(self, model):
         return self.get_url(model)
         return self.get_url(model)
-    
+
     def get_initial_data(self, model):
     def get_initial_data(self, model):
         return {
         return {
                 'name': model.name,
                 'name': model.name,
                 }
                 }
-    
+
     def submit_form(self, form, target):
     def submit_form(self, form, target):
         target.name = form.cleaned_data['name']
         target.name = form.cleaned_data['name']
         target.save(force_update=True)
         target.save(force_update=True)
@@ -101,17 +101,17 @@ class ACL(FormWidget):
     notfound_message = _('Requested Forum Role could not be found.')
     notfound_message = _('Requested Forum Role could not be found.')
     submit_fallback = True
     submit_fallback = True
     template = 'acl_form'
     template = 'acl_form'
-    
+
     def get_form(self, target):
     def get_form(self, target):
         self.form = build_forum_form(self.request, target)
         self.form = build_forum_form(self.request, target)
         return self.form
         return self.form
-    
+
     def get_url(self, model):
     def get_url(self, model):
         return reverse('admin_roles_forums_acl', model)
         return reverse('admin_roles_forums_acl', model)
-    
+
     def get_edit_url(self, model):
     def get_edit_url(self, model):
         return self.get_url(model)
         return self.get_url(model)
-    
+
     def get_initial_data(self, model):
     def get_initial_data(self, model):
         raw_acl = model.get_permissions()
         raw_acl = model.get_permissions()
         initial = {}
         initial = {}
@@ -119,7 +119,7 @@ class ACL(FormWidget):
             if field in raw_acl:
             if field in raw_acl:
                 initial[field] = raw_acl[field]
                 initial[field] = raw_acl[field]
         return initial
         return initial
-    
+
     def submit_form(self, form, target):
     def submit_form(self, form, target):
         raw_acl = target.get_permissions()
         raw_acl = target.get_permissions()
         for perm in form.cleaned_data:
         for perm in form.cleaned_data:
@@ -127,7 +127,7 @@ class ACL(FormWidget):
         target.set_permissions(raw_acl)
         target.set_permissions(raw_acl)
         target.save(force_update=True)
         target.save(force_update=True)
         self.request.monitor['acl_version'] = int(self.request.monitor['acl_version']) + 1
         self.request.monitor['acl_version'] = int(self.request.monitor['acl_version']) + 1
-        
+
         return target, Message(_('Forum Role "%(name)s" permissions have been changed.') % {'name': self.original_name}, 'success')
         return target, Message(_('Forum Role "%(name)s" permissions have been changed.') % {'name': self.original_name}, 'success')
 
 
 
 
@@ -136,8 +136,8 @@ class Delete(ButtonWidget):
     id = 'delete'
     id = 'delete'
     fallback = 'admin_roles_forums'
     fallback = 'admin_roles_forums'
     notfound_message = _('Requested Forum Role could not be found.')
     notfound_message = _('Requested Forum Role could not be found.')
-    
+
     def action(self, target):
     def action(self, target):
         target.delete()
         target.delete()
         self.request.monitor['acl_version'] = int(self.request.monitor['acl_version']) + 1
         self.request.monitor['acl_version'] = int(self.request.monitor['acl_version']) + 1
-        return Message(_('Forum Role "%(name)s" has been deleted.') % {'name': _(target.name)}, 'success'), False
+        return Message(_('Forum Role "%(name)s" has been deleted.') % {'name': _(target.name)}, 'success'), False

+ 11 - 11
misago/forums/acl.py

@@ -5,27 +5,27 @@ from misago.acl.utils import ACLError403, ACLError404
 from misago.forms import YesNoSwitch
 from misago.forms import YesNoSwitch
 
 
 def make_forum_form(request, role, form):
 def make_forum_form(request, role, form):
-    form.base_fields['can_see_forum'] = forms.BooleanField(widget=YesNoSwitch,initial=False,required=False)
-    form.base_fields['can_see_forum_contents'] = forms.BooleanField(widget=YesNoSwitch,initial=False,required=False)
+    form.base_fields['can_see_forum'] = forms.BooleanField(widget=YesNoSwitch, initial=False, required=False)
+    form.base_fields['can_see_forum_contents'] = forms.BooleanField(widget=YesNoSwitch, initial=False, required=False)
     form.layout.append((
     form.layout.append((
                         _("Forums Permissions"),
                         _("Forums Permissions"),
                         (
                         (
                          ('can_see_forum', {'label': _("Can see forum")}),
                          ('can_see_forum', {'label': _("Can see forum")}),
                          ('can_see_forum_contents', {'label': _("Can see forum contents")}),
                          ('can_see_forum_contents', {'label': _("Can see forum contents")}),
-                        ),
-                       ))
-    
+                         ),
+                        ))
+
 
 
 class ForumsACL(BaseACL):
 class ForumsACL(BaseACL):
     def known_forums(self):
     def known_forums(self):
         return self.acl['can_see']
         return self.acl['can_see']
-    
+
     def can_see(self, forum):
     def can_see(self, forum):
         try:
         try:
             return forum.pk in self.acl['can_see']
             return forum.pk in self.acl['can_see']
         except AttributeError:
         except AttributeError:
             return long(forum) in self.acl['can_see']
             return long(forum) in self.acl['can_see']
-        
+
     def can_browse(self, forum):
     def can_browse(self, forum):
         if self.can_see(forum):
         if self.can_see(forum):
             try:
             try:
@@ -33,7 +33,7 @@ class ForumsACL(BaseACL):
             except AttributeError:
             except AttributeError:
                 return long(forum) in self.acl['can_browse']
                 return long(forum) in self.acl['can_browse']
         return False
         return False
-    
+
     def allow_forum_view(self, forum):
     def allow_forum_view(self, forum):
         if not self.can_see(forum):
         if not self.can_see(forum):
             raise ACLError404()
             raise ACLError404()
@@ -45,7 +45,7 @@ def build_forums(acl, perms, forums, forum_roles):
     acl.forums = ForumsACL()
     acl.forums = ForumsACL()
     acl.forums.acl['can_see'] = []
     acl.forums.acl['can_see'] = []
     acl.forums.acl['can_browse'] = []
     acl.forums.acl['can_browse'] = []
-    
+
     for forum in forums:
     for forum in forums:
         for perm in perms:
         for perm in perms:
             try:
             try:
@@ -63,7 +63,7 @@ def cleanup(acl, perms, forums):
         if forum.pk in acl.forums.acl['can_browse'] and not forum.pk in acl.forums.acl['can_see']:
         if forum.pk in acl.forums.acl['can_browse'] and not forum.pk in acl.forums.acl['can_see']:
             # First burp: we can read forum but we cant see forum
             # First burp: we can read forum but we cant see forum
             del acl.forums.acl['can_browse'][acl.forums.acl['can_browse'].index(forum.pk)]
             del acl.forums.acl['can_browse'][acl.forums.acl['can_browse'].index(forum.pk)]
-            
+
         if forum.level > 1:
         if forum.level > 1:
             if forum.parent_id not in acl.forums.acl['can_see'] or forum.parent_id not in acl.forums.acl['can_browse']:
             if forum.parent_id not in acl.forums.acl['can_see'] or forum.parent_id not in acl.forums.acl['can_browse']:
                 # Second burp: we cant see or read parent forum
                 # Second burp: we cant see or read parent forum
@@ -74,4 +74,4 @@ def cleanup(acl, perms, forums):
                 try:
                 try:
                     del acl.forums.acl['can_browse'][acl.forums.acl['can_browse'].index(forum.pk)]
                     del acl.forums.acl['can_browse'][acl.forums.acl['can_browse'].index(forum.pk)]
                 except ValueError:
                 except ValueError:
-                    pass
+                    pass

+ 12 - 12
misago/forums/fixtures.py

@@ -5,19 +5,19 @@ from misago.threads.models import Thread, Post
 from misago.utils import slugify
 from misago.utils import slugify
 
 
 def load_fixtures():
 def load_fixtures():
-    Forum(token='annoucements', name='annoucements', slug='annoucements', type='forum').insert_at(None,save=True)
-    Forum(token='private', name='private', slug='private', type='forum').insert_at(None,save=True)
-    Forum(token='reports', name='reports', slug='reports', type='forum').insert_at(None,save=True)
-    
+    Forum(token='annoucements', name='annoucements', slug='annoucements', type='forum').insert_at(None, save=True)
+    Forum(token='private', name='private', slug='private', type='forum').insert_at(None, save=True)
+    Forum(token='reports', name='reports', slug='reports', type='forum').insert_at(None, save=True)
+
     root = Forum(token='root', name='root', slug='root')
     root = Forum(token='root', name='root', slug='root')
-    root.insert_at(None,save=True)
+    root.insert_at(None, save=True)
     cat = Forum(type='category', name='First Category', slug='first-category')
     cat = Forum(type='category', name='First Category', slug='first-category')
-    cat.insert_at(root,save=True)
+    cat.insert_at(root, save=True)
     forum = Forum(type='forum', name='First Forum', slug='first-forum', threads=1, posts=1)
     forum = Forum(type='forum', name='First Forum', slug='first-forum', threads=1, posts=1)
-    forum.insert_at(cat,save=True)
-    Forum(type='redirect', name='Project Homepage', slug='project-homepage', redirect='http://misago-project.org').insert_at(cat,position='last-child',save=True)
+    forum.insert_at(cat, save=True)
+    Forum(type='redirect', name='Project Homepage', slug='project-homepage', redirect='http://misago-project.org').insert_at(cat, position='last-child', save=True)
     Forum.objects.populate_tree(True)
     Forum.objects.populate_tree(True)
-    
+
     now = timezone.now()
     now = timezone.now()
     thread = Thread.objects.create(
     thread = Thread.objects.create(
                                    forum=forum,
                                    forum=forum,
@@ -50,9 +50,9 @@ def load_fixtures():
     forum.last_poster = thread.last_poster
     forum.last_poster = thread.last_poster
     forum.last_poster_name = thread.last_poster_name
     forum.last_poster_name = thread.last_poster_name
     forum.last_poster_slug = thread.last_poster_slug
     forum.last_poster_slug = thread.last_poster_slug
-    forum.save(force_update=True)    
-    
+    forum.save(force_update=True)
+
     load_monitor_fixture({
     load_monitor_fixture({
                           'threads': 1,
                           'threads': 1,
                           'posts': 1,
                           'posts': 1,
-                          })
+                          })

+ 51 - 51
misago/forums/forms.py

@@ -8,20 +8,20 @@ from misago.utils.validators import validate_sluggable
 class CategoryForm(Form):
 class CategoryForm(Form):
     parent = False
     parent = False
     perms = False
     perms = False
-    name = forms.CharField(max_length=255,validators=[validate_sluggable(
-                                                                         _("Category name must be sluggable."),
-                                                                         _("Category name is too long.")
-                                                                         )])
-    description = forms.CharField(widget=forms.Textarea,required=False)
-    closed = forms.BooleanField(widget=YesNoSwitch,required=False)
-    style = forms.CharField(max_length=255,required=False)
+    name = forms.CharField(max_length=255, validators=[validate_sluggable(
+                                                                          _("Category name must be sluggable."),
+                                                                          _("Category name is too long.")
+                                                                          )])
+    description = forms.CharField(widget=forms.Textarea, required=False)
+    closed = forms.BooleanField(widget=YesNoSwitch, required=False)
+    style = forms.CharField(max_length=255, required=False)
     template = forms.ChoiceField(choices=(
     template = forms.ChoiceField(choices=(
                                           ('row', _('One forum per row')),
                                           ('row', _('One forum per row')),
                                           ('half', _('Two forums per row')),
                                           ('half', _('Two forums per row')),
                                           ('quarter', _('Four forums per row')),
                                           ('quarter', _('Four forums per row')),
                                           ))
                                           ))
-    show_details = forms.BooleanField(widget=YesNoSwitch,required=False)
-    
+    show_details = forms.BooleanField(widget=YesNoSwitch, required=False)
+
     layout = (
     layout = (
               (
               (
                _("Basic Options"),
                _("Basic Options"),
@@ -42,31 +42,31 @@ class CategoryForm(Form):
                 ),
                 ),
               ),
               ),
              )
              )
-    
+
     def finalize_form(self):
     def finalize_form(self):
-        self.fields['parent'] = TreeNodeChoiceField(queryset=Forum.tree.get(token='root').get_descendants(include_self=True),level_indicator=u'- - ')
-        self.fields['perms'] = TreeNodeChoiceField(queryset=Forum.tree.get(token='root').get_descendants(),level_indicator=u'- - ',required=False,empty_label=_("Don't copy permissions"))
-    
+        self.fields['parent'] = TreeNodeChoiceField(queryset=Forum.tree.get(token='root').get_descendants(include_self=True), level_indicator=u'- - ')
+        self.fields['perms'] = TreeNodeChoiceField(queryset=Forum.tree.get(token='root').get_descendants(), level_indicator=u'- - ', required=False, empty_label=_("Don't copy permissions"))
+
 
 
 class ForumForm(Form):
 class ForumForm(Form):
     parent = False
     parent = False
     perms = False
     perms = False
-    name = forms.CharField(max_length=255,validators=[validate_sluggable(
-                                                                         _("Forum name must be sluggable."),
-                                                                         _("Forum name is too long.")
-                                                                         )])
-    description = forms.CharField(widget=forms.Textarea,required=False)
-    closed = forms.BooleanField(widget=YesNoSwitch,required=False)
-    style = forms.CharField(max_length=255,required=False)
-    prune_start = forms.IntegerField(min_value=0,initial=0)
-    prune_last = forms.IntegerField(min_value=0,initial=0)
+    name = forms.CharField(max_length=255, validators=[validate_sluggable(
+                                                                          _("Forum name must be sluggable."),
+                                                                          _("Forum name is too long.")
+                                                                          )])
+    description = forms.CharField(widget=forms.Textarea, required=False)
+    closed = forms.BooleanField(widget=YesNoSwitch, required=False)
+    style = forms.CharField(max_length=255, required=False)
+    prune_start = forms.IntegerField(min_value=0, initial=0)
+    prune_last = forms.IntegerField(min_value=0, initial=0)
     template = forms.ChoiceField(choices=(
     template = forms.ChoiceField(choices=(
                                           ('row', _('One forum per row')),
                                           ('row', _('One forum per row')),
                                           ('half', _('Two forums per row')),
                                           ('half', _('Two forums per row')),
                                           ('quarter', _('Four forums per row')),
                                           ('quarter', _('Four forums per row')),
                                           ))
                                           ))
-    show_details = forms.BooleanField(widget=YesNoSwitch,required=False)
-    
+    show_details = forms.BooleanField(widget=YesNoSwitch, required=False)
+
     layout = (
     layout = (
               (
               (
                _("Basic Options"),
                _("Basic Options"),
@@ -77,14 +77,14 @@ class ForumForm(Form):
                 ('description', {'label': _("Forum Description")}),
                 ('description', {'label': _("Forum Description")}),
                 ('closed', {'label': _("Closed Forum")}),
                 ('closed', {'label': _("Closed Forum")}),
                 ),
                 ),
-              ),
+               ),
               (
               (
                _("Prune Forum"),
                _("Prune Forum"),
                (
                (
                 ('prune_start', {'label': _("Delete threads with first post older than"), 'help_text': _('Enter number of days since thread start after which thread will be deleted or zero to don\'t delete threads.')}),
                 ('prune_start', {'label': _("Delete threads with first post older than"), 'help_text': _('Enter number of days since thread start after which thread will be deleted or zero to don\'t delete threads.')}),
                 ('prune_last', {'label': _("Delete threads with last post older than"), 'help_text': _('Enter number of days since since last reply in thread after which thread will be deleted or zero to don\'t delete threads.')}),
                 ('prune_last', {'label': _("Delete threads with last post older than"), 'help_text': _('Enter number of days since since last reply in thread after which thread will be deleted or zero to don\'t delete threads.')}),
                 ),
                 ),
-              ),
+               ),
               (
               (
                _("Display Options"),
                _("Display Options"),
                (
                (
@@ -92,25 +92,25 @@ class ForumForm(Form):
                 ('show_details', {'label': _("Show Subforums Details"), 'help_text': _("Allows you to prevent this forum's subforums from displaying statistics, last post data, etc. ect. on subforums list.")}),
                 ('show_details', {'label': _("Show Subforums Details"), 'help_text': _("Allows you to prevent this forum's subforums from displaying statistics, last post data, etc. ect. on subforums list.")}),
                 ('style', {'label': _("Forum Style"), 'help_text': _('You can add custom CSS classess to this forum to change way it looks on forums lists.')}),
                 ('style', {'label': _("Forum Style"), 'help_text': _('You can add custom CSS classess to this forum to change way it looks on forums lists.')}),
                 ),
                 ),
-              ),
-             )
-    
+               ),
+              )
+
     def finalize_form(self):
     def finalize_form(self):
-        self.fields['parent'] = TreeNodeChoiceField(queryset=Forum.tree.get(token='root').get_descendants(),level_indicator=u'- - ')
-        self.fields['perms'] = TreeNodeChoiceField(queryset=Forum.tree.get(token='root').get_descendants(),level_indicator=u'- - ',required=False,empty_label=_("Don't copy permissions"))
-        
+        self.fields['parent'] = TreeNodeChoiceField(queryset=Forum.tree.get(token='root').get_descendants(), level_indicator=u'- - ')
+        self.fields['perms'] = TreeNodeChoiceField(queryset=Forum.tree.get(token='root').get_descendants(), level_indicator=u'- - ', required=False, empty_label=_("Don't copy permissions"))
+
 
 
 class RedirectForm(Form):
 class RedirectForm(Form):
     parent = False
     parent = False
     perms = False
     perms = False
-    name = forms.CharField(max_length=255,validators=[validate_sluggable(
-                                                                         _("Redirect name must be sluggable."),
-                                                                         _("Redirect name is too long.")
-                                                                         )])
-    description = forms.CharField(widget=forms.Textarea,required=False)
+    name = forms.CharField(max_length=255, validators=[validate_sluggable(
+                                                                          _("Redirect name must be sluggable."),
+                                                                          _("Redirect name is too long.")
+                                                                          )])
+    description = forms.CharField(widget=forms.Textarea, required=False)
     redirect = forms.URLField(max_length=255)
     redirect = forms.URLField(max_length=255)
-    style = forms.CharField(max_length=255,required=False)
-    
+    style = forms.CharField(max_length=255, required=False)
+
     layout = (
     layout = (
               (
               (
                _("Basic Options"),
                _("Basic Options"),
@@ -121,31 +121,31 @@ class RedirectForm(Form):
                 ('redirect', {'label': _("Redirect URL")}),
                 ('redirect', {'label': _("Redirect URL")}),
                 ('description', {'label': _("Redirect Description")}),
                 ('description', {'label': _("Redirect Description")}),
                 ),
                 ),
-              ),
+               ),
               (
               (
                _("Display Options"),
                _("Display Options"),
                (
                (
                 ('style', {'label': _("Redirect Style"), 'help_text': _('You can add custom CSS classess to this redirect to change way it looks on forums lists.')}),
                 ('style', {'label': _("Redirect Style"), 'help_text': _('You can add custom CSS classess to this redirect to change way it looks on forums lists.')}),
                 ),
                 ),
-              ),
-             )
-    
+               ),
+              )
+
     def finalize_form(self):
     def finalize_form(self):
-        self.fields['parent'] = TreeNodeChoiceField(queryset=Forum.tree.get(token='root').get_descendants(),level_indicator=u'- - ')
-        self.fields['perms'] = TreeNodeChoiceField(queryset=Forum.tree.get(token='root').get_descendants(),level_indicator=u'- - ',required=False,empty_label=_("Don't copy permissions"))
-    
+        self.fields['parent'] = TreeNodeChoiceField(queryset=Forum.tree.get(token='root').get_descendants(), level_indicator=u'- - ')
+        self.fields['perms'] = TreeNodeChoiceField(queryset=Forum.tree.get(token='root').get_descendants(), level_indicator=u'- - ', required=False, empty_label=_("Don't copy permissions"))
+
 
 
 class DeleteForm(Form):
 class DeleteForm(Form):
     parent = False
     parent = False
-   
+
     layout = (
     layout = (
               (
               (
                _("Delete Options"),
                _("Delete Options"),
                (
                (
                 ('parent', {'label': _("Move deleted Forum contents to")}),
                 ('parent', {'label': _("Move deleted Forum contents to")}),
                 ),
                 ),
-              ),
-             )
-        
+               ),
+              )
+
     def finalize_form(self):
     def finalize_form(self):
-        self.fields['parent'] = TreeNodeChoiceField(queryset=Forum.tree.get(token='root').get_descendants(),required=False,empty_label=_("Remove with forum"),level_indicator=u'- - ')
+        self.fields['parent'] = TreeNodeChoiceField(queryset=Forum.tree.get(token='root').get_descendants(), required=False, empty_label=_("Remove with forum"), level_indicator=u'- - ')

+ 2 - 2
misago/forums/management/commands/resetdeltas.py

@@ -7,5 +7,5 @@ class Command(BaseCommand):
     """
     """
     help = 'Clears users sessions'
     help = 'Clears users sessions'
     def handle(self, *args, **options):
     def handle(self, *args, **options):
-        Forum.objects.all().update(threads_delta=0,posts_delta=0,redirects_delta=0)
-        self.stdout.write('Forums deltas have been reset.\n')
+        Forum.objects.all().update(threads_delta=0, posts_delta=0, redirects_delta=0)
+        self.stdout.write('Forums deltas have been reset.\n')

+ 35 - 35
misago/forums/models.py

@@ -2,19 +2,19 @@ from django.conf import settings
 from django.core.cache import cache
 from django.core.cache import cache
 from django.db import models
 from django.db import models
 from django.utils.translation import ugettext_lazy as _
 from django.utils.translation import ugettext_lazy as _
-from mptt.models import MPTTModel,TreeForeignKey
+from mptt.models import MPTTModel, TreeForeignKey
 from misago.roles.models import Role
 from misago.roles.models import Role
 
 
 class ForumManager(models.Manager):
 class ForumManager(models.Manager):
     forums_tree = None
     forums_tree = None
-    
+
     def token_to_pk(self, token):
     def token_to_pk(self, token):
         self.populate_tree()
         self.populate_tree()
         try:
         try:
             return self.forums_tree[token].pk
             return self.forums_tree[token].pk
         except KeyError:
         except KeyError:
             return 0
             return 0
-    
+
     def populate_tree(self, force=False):
     def populate_tree(self, force=False):
         if not self.forums_tree:
         if not self.forums_tree:
             self.forums_tree = cache.get('forums_tree')
             self.forums_tree = cache.get('forums_tree')
@@ -25,7 +25,7 @@ class ForumManager(models.Manager):
                 if forum.token:
                 if forum.token:
                     self.forums_tree[forum.token] = forum
                     self.forums_tree[forum.token] = forum
             cache.set('forums_tree', self.forums_tree)
             cache.set('forums_tree', self.forums_tree)
-    
+
     def forum_parents(self, forum, include_self=False):
     def forum_parents(self, forum, include_self=False):
         self.populate_tree()
         self.populate_tree()
         parents = []
         parents = []
@@ -36,7 +36,7 @@ class ForumManager(models.Manager):
             parent = self.forums_tree[parent.parent_id]
             parent = self.forums_tree[parent.parent_id]
             parents.append(parent)
             parents.append(parent)
         return reversed(parents)
         return reversed(parents)
-        
+
     def parents_aware_forum(self, forum):
     def parents_aware_forum(self, forum):
         self.populate_tree()
         self.populate_tree()
         proxy = Forum()
         proxy = Forum()
@@ -52,17 +52,17 @@ class ForumManager(models.Manager):
                 proxy.closed = True
                 proxy.closed = True
                 return proxy
                 return proxy
         return proxy
         return proxy
-        
+
     def treelist(self, acl, parent=None, tracker=None):
     def treelist(self, acl, parent=None, tracker=None):
         complete_list = []
         complete_list = []
         forums_list = []
         forums_list = []
         parents = {}
         parents = {}
-        
+
         if parent:
         if parent:
             queryset = Forum.objects.filter(pk__in=acl.known_forums).filter(lft__gt=parent.lft).filter(rght__lt=parent.rght).order_by('lft')
             queryset = Forum.objects.filter(pk__in=acl.known_forums).filter(lft__gt=parent.lft).filter(rght__lt=parent.rght).order_by('lft')
         else:
         else:
             queryset = Forum.objects.filter(pk__in=acl.known_forums).order_by('lft')
             queryset = Forum.objects.filter(pk__in=acl.known_forums).order_by('lft')
-            
+
         for forum in queryset:
         for forum in queryset:
             forum.subforums = []
             forum.subforums = []
             forum.is_read = False
             forum.is_read = False
@@ -74,7 +74,7 @@ class ForumManager(models.Manager):
                 parents[forum.parent_id].subforums.append(forum)
                 parents[forum.parent_id].subforums.append(forum)
             else:
             else:
                 forums_list.append(forum)
                 forums_list.append(forum)
-        
+
         # Second iteration - sum up forum counters
         # Second iteration - sum up forum counters
         for forum in reversed(complete_list):
         for forum in reversed(complete_list):
             if forum.parent_id in parents and parents[forum.parent_id].type != 'redirect':
             if forum.parent_id in parents and parents[forum.parent_id].type != 'redirect':
@@ -100,49 +100,49 @@ class ForumManager(models.Manager):
 
 
 
 
 class Forum(MPTTModel):
 class Forum(MPTTModel):
-    parent = TreeForeignKey('self',null=True,blank=True,related_name='children')
+    parent = TreeForeignKey('self', null=True, blank=True, related_name='children')
     type = models.CharField(max_length=12)
     type = models.CharField(max_length=12)
-    token = models.CharField(max_length=255,null=True,blank=True)
+    token = models.CharField(max_length=255, null=True, blank=True)
     name = models.CharField(max_length=255)
     name = models.CharField(max_length=255)
     slug = models.SlugField(max_length=255)
     slug = models.SlugField(max_length=255)
-    description = models.TextField(null=True,blank=True)
-    description_preparsed = models.TextField(null=True,blank=True)
+    description = models.TextField(null=True, blank=True)
+    description_preparsed = models.TextField(null=True, blank=True)
     threads = models.PositiveIntegerField(default=0)
     threads = models.PositiveIntegerField(default=0)
     threads_delta = models.PositiveIntegerField(default=0)
     threads_delta = models.PositiveIntegerField(default=0)
     posts = models.PositiveIntegerField(default=0)
     posts = models.PositiveIntegerField(default=0)
     posts_delta = models.IntegerField(default=0)
     posts_delta = models.IntegerField(default=0)
     redirects = models.PositiveIntegerField(default=0)
     redirects = models.PositiveIntegerField(default=0)
     redirects_delta = models.IntegerField(default=0)
     redirects_delta = models.IntegerField(default=0)
-    last_thread = models.ForeignKey('threads.Thread',related_name='+',null=True,blank=True,on_delete=models.SET_NULL)
-    last_thread_name = models.CharField(max_length=255,null=True,blank=True)
-    last_thread_slug = models.SlugField(max_length=255,null=True,blank=True)
-    last_thread_date = models.DateTimeField(null=True,blank=True)
-    last_poster = models.ForeignKey('users.User',related_name='+',null=True,blank=True,on_delete=models.SET_NULL)
-    last_poster_name = models.CharField(max_length=255,null=True,blank=True)
-    last_poster_slug = models.SlugField(max_length=255,null=True,blank=True)
-    last_poster_style = models.CharField(max_length=255,null=True,blank=True)
+    last_thread = models.ForeignKey('threads.Thread', related_name='+', null=True, blank=True, on_delete=models.SET_NULL)
+    last_thread_name = models.CharField(max_length=255, null=True, blank=True)
+    last_thread_slug = models.SlugField(max_length=255, null=True, blank=True)
+    last_thread_date = models.DateTimeField(null=True, blank=True)
+    last_poster = models.ForeignKey('users.User', related_name='+', null=True, blank=True, on_delete=models.SET_NULL)
+    last_poster_name = models.CharField(max_length=255, null=True, blank=True)
+    last_poster_slug = models.SlugField(max_length=255, null=True, blank=True)
+    last_poster_style = models.CharField(max_length=255, null=True, blank=True)
     prune_start = models.PositiveIntegerField(default=0)
     prune_start = models.PositiveIntegerField(default=0)
     prune_last = models.PositiveIntegerField(default=0)
     prune_last = models.PositiveIntegerField(default=0)
-    redirect = models.CharField(max_length=255,null=True,blank=True)
-    template = models.CharField(default='row',max_length=255,null=True,blank=True)
+    redirect = models.CharField(max_length=255, null=True, blank=True)
+    template = models.CharField(default='row', max_length=255, null=True, blank=True)
     show_details = models.BooleanField(default=True)
     show_details = models.BooleanField(default=True)
-    style = models.CharField(max_length=255,null=True,blank=True)
+    style = models.CharField(max_length=255, null=True, blank=True)
     closed = models.BooleanField(default=False)
     closed = models.BooleanField(default=False)
-    
-    objects = ForumManager()   
-    
+
+    objects = ForumManager()
+
     def __unicode__(self):
     def __unicode__(self):
         if self.token == 'root':
         if self.token == 'root':
-           return unicode(_('Root Category')) 
+           return unicode(_('Root Category'))
         return unicode(self.name)
         return unicode(self.name)
-        
+
     def set_description(self, description):
     def set_description(self, description):
         self.description = description.strip()
         self.description = description.strip()
         self.description_preparsed = ''
         self.description_preparsed = ''
         if self.description:
         if self.description:
             import markdown
             import markdown
-            self.description_preparsed = markdown.markdown(description,safe_mode='escape',output_format=settings.OUTPUT_FORMAT)
-       
+            self.description_preparsed = markdown.markdown(description, safe_mode='escape', output_format=settings.OUTPUT_FORMAT)
+
     def copy_permissions(self, target):
     def copy_permissions(self, target):
         if target.pk != self.pk:
         if target.pk != self.pk:
             for role in Role.objects.all():
             for role in Role.objects.all():
@@ -153,10 +153,10 @@ class Forum(MPTTModel):
                     role.save(force_update=True)
                     role.save(force_update=True)
                 except KeyError:
                 except KeyError:
                     pass
                     pass
-        
+
     def move_content(self, target):
     def move_content(self, target):
         pass
         pass
-    
+
     def sync(self):
     def sync(self):
         self.threads = self.thread_set.filter(moderated=False).filter(deleted=False).count()
         self.threads = self.thread_set.filter(moderated=False).filter(deleted=False).count()
         self.posts = self.post_set.filter(moderated=False).filter(deleted=False).count()
         self.posts = self.post_set.filter(moderated=False).filter(deleted=False).count()
@@ -181,6 +181,6 @@ class Forum(MPTTModel):
             self.last_thread_slug = last_thread.slug
             self.last_thread_slug = last_thread.slug
         except (IndexError, AttributeError):
         except (IndexError, AttributeError):
             pass
             pass
-    
+
     def prune(self):
     def prune(self):
-        pass
+        pass

+ 83 - 83
misago/forums/views.py

@@ -20,22 +20,22 @@ Views
 class List(ListWidget):
 class List(ListWidget):
     admin = site.get_action('forums')
     admin = site.get_action('forums')
     id = 'list'
     id = 'list'
-    columns=(
-             ('forum', _("Forum")),
-             )
+    columns = (
+               ('forum', _("Forum")),
+               )
     nothing_checked_message = _('You have to select at least one forum.')
     nothing_checked_message = _('You have to select at least one forum.')
-    actions=(
-             ('resync', _("Resynchronise forums")),
-             ('prune', _("Prune forums"), _("Are you sure you want to delete all content from selected forums?")),
-             )
+    actions = (
+               ('resync', _("Resynchronise forums")),
+               ('prune', _("Prune forums"), _("Are you sure you want to delete all content from selected forums?")),
+               )
     empty_message = _('No forums are currently defined.')
     empty_message = _('No forums are currently defined.')
-    
+
     def get_items(self):
     def get_items(self):
         return self.admin.model.objects.get(token='root').get_descendants()
         return self.admin.model.objects.get(token='root').get_descendants()
-    
+
     def sort_items(self, page_items, sorting_method):
     def sort_items(self, page_items, sorting_method):
         return page_items.order_by('lft')
         return page_items.order_by('lft')
-    
+
     def get_item_actions(self, item):
     def get_item_actions(self, item):
         if item.type == 'category':
         if item.type == 'category':
             return (
             return (
@@ -44,7 +44,7 @@ class List(ListWidget):
                     self.action('pencil', _("Edit Category"), reverse('admin_forums_edit', item)),
                     self.action('pencil', _("Edit Category"), reverse('admin_forums_edit', item)),
                     self.action('remove', _("Delete Category"), reverse('admin_forums_delete', item)),
                     self.action('remove', _("Delete Category"), reverse('admin_forums_delete', item)),
                     )
                     )
-            
+
         if item.type == 'forum':
         if item.type == 'forum':
             return (
             return (
                     self.action('chevron-up', _("Move Forum Up"), reverse('admin_forums_up', item), post=True),
                     self.action('chevron-up', _("Move Forum Up"), reverse('admin_forums_up', item), post=True),
@@ -52,7 +52,7 @@ class List(ListWidget):
                     self.action('pencil', _("Edit Forum"), reverse('admin_forums_edit', item)),
                     self.action('pencil', _("Edit Forum"), reverse('admin_forums_edit', item)),
                     self.action('remove', _("Delete Forum"), reverse('admin_forums_delete', item)),
                     self.action('remove', _("Delete Forum"), reverse('admin_forums_delete', item)),
                     )
                     )
-            
+
         return (
         return (
                 self.action('chevron-up', _("Move Redirect Up"), reverse('admin_forums_up', item), post=True),
                 self.action('chevron-up', _("Move Redirect Up"), reverse('admin_forums_up', item), post=True),
                 self.action('chevron-down', _("Move Redirect Down"), reverse('admin_forums_down', item), post=True),
                 self.action('chevron-down', _("Move Redirect Down"), reverse('admin_forums_down', item), post=True),
@@ -70,70 +70,70 @@ class List(ListWidget):
 class NewCategory(FormWidget):
 class NewCategory(FormWidget):
     admin = site.get_action('forums')
     admin = site.get_action('forums')
     id = 'new_category'
     id = 'new_category'
-    fallback = 'admin_forums' 
+    fallback = 'admin_forums'
     form = CategoryForm
     form = CategoryForm
     submit_button = _("Save Category")
     submit_button = _("Save Category")
-        
+
     def get_new_url(self, model):
     def get_new_url(self, model):
         return reverse('admin_forums_new_category')
         return reverse('admin_forums_new_category')
-    
+
     def get_edit_url(self, model):
     def get_edit_url(self, model):
         return reverse('admin_forums_edit', model)
         return reverse('admin_forums_edit', model)
-    
+
     def submit_form(self, form, target):
     def submit_form(self, form, target):
         new_forum = Forum(
         new_forum = Forum(
-                     name=form.cleaned_data['name'],
-                     slug=slugify(form.cleaned_data['name']),
-                     type='category',
-                     template=form.cleaned_data['template'],
-                     show_details=form.cleaned_data['show_details'],
-                     style=form.cleaned_data['style'],
-                     closed=form.cleaned_data['closed'],
-                     )
+                          name=form.cleaned_data['name'],
+                          slug=slugify(form.cleaned_data['name']),
+                          type='category',
+                          template=form.cleaned_data['template'],
+                          show_details=form.cleaned_data['show_details'],
+                          style=form.cleaned_data['style'],
+                          closed=form.cleaned_data['closed'],
+                          )
         new_forum.set_description(form.cleaned_data['description'])
         new_forum.set_description(form.cleaned_data['description'])
         new_forum.insert_at(form.cleaned_data['parent'], position='last-child', save=True)
         new_forum.insert_at(form.cleaned_data['parent'], position='last-child', save=True)
         Forum.objects.populate_tree(True)
         Forum.objects.populate_tree(True)
-        
+
         if form.cleaned_data['perms']:
         if form.cleaned_data['perms']:
             new_forum.copy_permissions(form.cleaned_data['perms'])
             new_forum.copy_permissions(form.cleaned_data['perms'])
             self.request.monitor['acl_version'] = int(self.request.monitor['acl_version']) + 1
             self.request.monitor['acl_version'] = int(self.request.monitor['acl_version']) + 1
-            
+
         return new_forum, Message(_('New Category has been created.'), 'success')
         return new_forum, Message(_('New Category has been created.'), 'success')
 
 
 
 
 class NewForum(FormWidget):
 class NewForum(FormWidget):
     admin = site.get_action('forums')
     admin = site.get_action('forums')
     id = 'new_forum'
     id = 'new_forum'
-    fallback = 'admin_forums' 
+    fallback = 'admin_forums'
     form = ForumForm
     form = ForumForm
     submit_button = _("Save Forum")
     submit_button = _("Save Forum")
-        
+
     def get_new_url(self, model):
     def get_new_url(self, model):
         return reverse('admin_forums_new_forum')
         return reverse('admin_forums_new_forum')
-    
+
     def get_edit_url(self, model):
     def get_edit_url(self, model):
         return reverse('admin_forums_edit', model)
         return reverse('admin_forums_edit', model)
-    
+
     def submit_form(self, form, target):
     def submit_form(self, form, target):
         new_forum = Forum(
         new_forum = Forum(
-                     name=form.cleaned_data['name'],
-                     slug=slugify(form.cleaned_data['name']),
-                     type='forum',
-                     template=form.cleaned_data['template'],
-                     show_details=form.cleaned_data['show_details'],
-                     style=form.cleaned_data['style'],
-                     closed=form.cleaned_data['closed'],
-                     prune_start=form.cleaned_data['prune_start'],
-                     prune_last=form.cleaned_data['prune_last'],
-                     )
+                          name=form.cleaned_data['name'],
+                          slug=slugify(form.cleaned_data['name']),
+                          type='forum',
+                          template=form.cleaned_data['template'],
+                          show_details=form.cleaned_data['show_details'],
+                          style=form.cleaned_data['style'],
+                          closed=form.cleaned_data['closed'],
+                          prune_start=form.cleaned_data['prune_start'],
+                          prune_last=form.cleaned_data['prune_last'],
+                          )
         new_forum.set_description(form.cleaned_data['description'])
         new_forum.set_description(form.cleaned_data['description'])
         new_forum.insert_at(form.cleaned_data['parent'], position='last-child', save=True)
         new_forum.insert_at(form.cleaned_data['parent'], position='last-child', save=True)
         Forum.objects.populate_tree(True)
         Forum.objects.populate_tree(True)
-        
+
         if form.cleaned_data['perms']:
         if form.cleaned_data['perms']:
             new_forum.copy_permissions(form.cleaned_data['perms'])
             new_forum.copy_permissions(form.cleaned_data['perms'])
             self.request.monitor['acl_version'] = int(self.request.monitor['acl_version']) + 1
             self.request.monitor['acl_version'] = int(self.request.monitor['acl_version']) + 1
-            
+
         return new_forum, Message(_('New Forum has been created.'), 'success')
         return new_forum, Message(_('New Forum has been created.'), 'success')
 
 
     def __call__(self, request):
     def __call__(self, request):
@@ -146,34 +146,34 @@ class NewForum(FormWidget):
 class NewRedirect(FormWidget):
 class NewRedirect(FormWidget):
     admin = site.get_action('forums')
     admin = site.get_action('forums')
     id = 'new_redirect'
     id = 'new_redirect'
-    fallback = 'admin_forums' 
+    fallback = 'admin_forums'
     form = RedirectForm
     form = RedirectForm
     submit_button = _("Save Forum")
     submit_button = _("Save Forum")
-        
+
     def get_new_url(self, model):
     def get_new_url(self, model):
         return reverse('admin_forums_new_redirect')
         return reverse('admin_forums_new_redirect')
-    
+
     def get_edit_url(self, model):
     def get_edit_url(self, model):
         return reverse('admin_forums_edit', model)
         return reverse('admin_forums_edit', model)
-    
+
     def submit_form(self, form, target):
     def submit_form(self, form, target):
         new_forum = Forum(
         new_forum = Forum(
-                     name=form.cleaned_data['name'],
-                     slug=slugify(form.cleaned_data['name']),
-                     redirect=form.cleaned_data['redirect'],
-                     style=form.cleaned_data['style'],
-                     type='redirect',
-                     )
+                          name=form.cleaned_data['name'],
+                          slug=slugify(form.cleaned_data['name']),
+                          redirect=form.cleaned_data['redirect'],
+                          style=form.cleaned_data['style'],
+                          type='redirect',
+                          )
         new_forum.set_description(form.cleaned_data['description'])
         new_forum.set_description(form.cleaned_data['description'])
         new_forum.insert_at(form.cleaned_data['parent'], position='last-child', save=True)
         new_forum.insert_at(form.cleaned_data['parent'], position='last-child', save=True)
         Forum.objects.populate_tree(True)
         Forum.objects.populate_tree(True)
-        
+
         if form.cleaned_data['perms']:
         if form.cleaned_data['perms']:
             new_forum.copy_permissions(form.cleaned_data['perms'])
             new_forum.copy_permissions(form.cleaned_data['perms'])
             self.request.monitor['acl_version'] = int(self.request.monitor['acl_version']) + 1
             self.request.monitor['acl_version'] = int(self.request.monitor['acl_version']) + 1
-            
+
         return new_forum, Message(_('New Redirect has been created.'), 'success')
         return new_forum, Message(_('New Redirect has been created.'), 'success')
-    
+
     def __call__(self, request):
     def __call__(self, request):
         if self.admin.model.objects.get(token='root').get_descendants().count() == 0:
         if self.admin.model.objects.get(token='root').get_descendants().count() == 0:
             request.messages.set_flash(Message(_("You have to create at least one category before you will be able to create redirects.")), 'error', self.admin.id)
             request.messages.set_flash(Message(_("You have to create at least one category before you will be able to create redirects.")), 'error', self.admin.id)
@@ -186,7 +186,7 @@ class Up(ButtonWidget):
     id = 'up'
     id = 'up'
     fallback = 'admin_forums'
     fallback = 'admin_forums'
     notfound_message = _('Requested Forum could not be found.')
     notfound_message = _('Requested Forum could not be found.')
-    
+
     def action(self, target):
     def action(self, target):
         previous_sibling = target.get_previous_sibling()
         previous_sibling = target.get_previous_sibling()
         if previous_sibling:
         if previous_sibling:
@@ -200,15 +200,15 @@ class Down(ButtonWidget):
     id = 'down'
     id = 'down'
     fallback = 'admin_forums'
     fallback = 'admin_forums'
     notfound_message = _('Requested Forum could not be found.')
     notfound_message = _('Requested Forum could not be found.')
-    
+
     def action(self, target):
     def action(self, target):
         next_sibling = target.get_next_sibling()
         next_sibling = target.get_next_sibling()
         if next_sibling:
         if next_sibling:
             target.move_to(next_sibling, 'right')
             target.move_to(next_sibling, 'right')
             return Message(_('Forum "%(name)s" has been moved down.') % {'name': target.name}, 'success'), False
             return Message(_('Forum "%(name)s" has been moved down.') % {'name': target.name}, 'success'), False
         return Message(_('Forum "%(name)s" is last child of its parent node and cannot be moved down.') % {'name': target.name}, 'info'), False
         return Message(_('Forum "%(name)s" is last child of its parent node and cannot be moved down.') % {'name': target.name}, 'info'), False
-  
-   
+
+
 class Edit(FormWidget):
 class Edit(FormWidget):
     admin = site.get_action('forums')
     admin = site.get_action('forums')
     id = 'edit'
     id = 'edit'
@@ -218,13 +218,13 @@ class Edit(FormWidget):
     target_name = 'name'
     target_name = 'name'
     notfound_message = _('Requested Forum could not be found.')
     notfound_message = _('Requested Forum could not be found.')
     submit_fallback = True
     submit_fallback = True
-    
+
     def get_url(self, model):
     def get_url(self, model):
         return reverse('admin_forums_edit', model)
         return reverse('admin_forums_edit', model)
-    
+
     def get_edit_url(self, model):
     def get_edit_url(self, model):
         return self.get_url(model)
         return self.get_url(model)
-    
+
     def get_form(self, target):
     def get_form(self, target):
         if target.type == 'category':
         if target.type == 'category':
             self.name = _("Edit Category")
             self.name = _("Edit Category")
@@ -233,20 +233,20 @@ class Edit(FormWidget):
             self.name = _("Edit Redirect")
             self.name = _("Edit Redirect")
             self.form = RedirectForm
             self.form = RedirectForm
         return self.form
         return self.form
-    
+
     def get_form_instance(self, form, target, initial, post=False):
     def get_form_instance(self, form, target, initial, post=False):
         form_inst = super(Edit, self).get_form_instance(form, target, initial, post)
         form_inst = super(Edit, self).get_form_instance(form, target, initial, post)
         valid_targets = Forum.tree.get(token='root').get_descendants(include_self=target.type == 'category').exclude(Q(lft__gte=target.lft) & Q(rght__lte=target.rght))
         valid_targets = Forum.tree.get(token='root').get_descendants(include_self=target.type == 'category').exclude(Q(lft__gte=target.lft) & Q(rght__lte=target.rght))
-        form_inst.fields['parent'] = TreeNodeChoiceField(queryset=valid_targets,level_indicator=u'- - ')
+        form_inst.fields['parent'] = TreeNodeChoiceField(queryset=valid_targets, level_indicator=u'- - ')
         return form_inst
         return form_inst
-    
+
     def get_initial_data(self, model):
     def get_initial_data(self, model):
         initial = {
         initial = {
                    'parent': model.parent,
                    'parent': model.parent,
                    'name': model.name,
                    'name': model.name,
                    'description': model.description,
                    'description': model.description,
                    }
                    }
-            
+
         if model.type == 'redirect':
         if model.type == 'redirect':
             initial['redirect'] = model.redirect
             initial['redirect'] = model.redirect
         else:
         else:
@@ -254,13 +254,13 @@ class Edit(FormWidget):
             initial['show_details'] = model.show_details
             initial['show_details'] = model.show_details
             initial['style'] = model.style
             initial['style'] = model.style
             initial['closed'] = model.closed
             initial['closed'] = model.closed
-            
+
         if model.type == 'forum':
         if model.type == 'forum':
             initial['prune_start'] = model.prune_start
             initial['prune_start'] = model.prune_start
             initial['prune_last'] = model.prune_last
             initial['prune_last'] = model.prune_last
-        
+
         return initial
         return initial
-    
+
     def submit_form(self, form, target):
     def submit_form(self, form, target):
         target.name = form.cleaned_data['name']
         target.name = form.cleaned_data['name']
         target.slug = slugify(form.cleaned_data['name'])
         target.slug = slugify(form.cleaned_data['name'])
@@ -272,25 +272,25 @@ class Edit(FormWidget):
             target.show_details = form.cleaned_data['show_details']
             target.show_details = form.cleaned_data['show_details']
             target.style = form.cleaned_data['style']
             target.style = form.cleaned_data['style']
             target.closed = form.cleaned_data['closed']
             target.closed = form.cleaned_data['closed']
-            
+
         if target.type == 'forum':
         if target.type == 'forum':
             target.prune_start = form.cleaned_data['prune_start']
             target.prune_start = form.cleaned_data['prune_start']
             target.prune_last = form.cleaned_data['prune_last']
             target.prune_last = form.cleaned_data['prune_last']
-            
+
         if form.cleaned_data['parent'].pk != target.parent.pk:
         if form.cleaned_data['parent'].pk != target.parent.pk:
             print 'MOVE FORUM!'
             print 'MOVE FORUM!'
             target.move_to(form.cleaned_data['parent'], 'last-child')
             target.move_to(form.cleaned_data['parent'], 'last-child')
             self.request.monitor['acl_version'] = int(self.request.monitor['acl_version']) + 1
             self.request.monitor['acl_version'] = int(self.request.monitor['acl_version']) + 1
-            
+
         target.save(force_update=True)
         target.save(force_update=True)
         Forum.objects.populate_tree(True)
         Forum.objects.populate_tree(True)
-            
+
         if form.cleaned_data['perms']:
         if form.cleaned_data['perms']:
             target.copy_permissions(form.cleaned_data['perms'])
             target.copy_permissions(form.cleaned_data['perms'])
-        
+
         if form.cleaned_data['parent'].pk != target.parent.pk or form.cleaned_data['perms']:
         if form.cleaned_data['parent'].pk != target.parent.pk or form.cleaned_data['perms']:
             self.request.monitor['acl_version'] = int(self.request.monitor['acl_version']) + 1
             self.request.monitor['acl_version'] = int(self.request.monitor['acl_version']) + 1
-        
+
         return target, Message(_('Changes in forum "%(name)s" have been saved.') % {'name': self.original_name}, 'success')
         return target, Message(_('Changes in forum "%(name)s" have been saved.') % {'name': self.original_name}, 'success')
 
 
 
 
@@ -304,23 +304,23 @@ class Delete(FormWidget):
     target_name = 'name'
     target_name = 'name'
     notfound_message = _('Requested Forum could not be found.')
     notfound_message = _('Requested Forum could not be found.')
     submit_fallback = True
     submit_fallback = True
-    
+
     def get_url(self, model):
     def get_url(self, model):
         return reverse('admin_forums_delete', model)
         return reverse('admin_forums_delete', model)
-   
+
     def get_form(self, target):
     def get_form(self, target):
         if target.type == 'category':
         if target.type == 'category':
-            self.name= _("Delete Category")
+            self.name = _("Delete Category")
         if target.type == 'redirect':
         if target.type == 'redirect':
-            self.name= _("Delete Redirect")
+            self.name = _("Delete Redirect")
         return self.form
         return self.form
-    
+
     def get_form_instance(self, form, target, initial, post=False):
     def get_form_instance(self, form, target, initial, post=False):
         form_inst = super(Edit, self).get_form_instance(form, target, initial, post)
         form_inst = super(Edit, self).get_form_instance(form, target, initial, post)
         valid_targets = Forum.tree.get(token='root').get_descendants(include_self=target.type == 'category').exclude(Q(lft__gte=target.lft) & Q(rght__lte=target.rght))
         valid_targets = Forum.tree.get(token='root').get_descendants(include_self=target.type == 'category').exclude(Q(lft__gte=target.lft) & Q(rght__lte=target.rght))
-        self.form_inst.fields['parent'] = TreeNodeChoiceField(queryset=valid_targets,required=False,empty_label=_("Remove with forum"),level_indicator=u'- - ')
+        self.form_inst.fields['parent'] = TreeNodeChoiceField(queryset=valid_targets, required=False, empty_label=_("Remove with forum"), level_indicator=u'- - ')
         return form_inst
         return form_inst
-        
+
     def submit_form(self, form, target):
     def submit_form(self, form, target):
         new_parent = form.cleaned_data['parent']
         new_parent = form.cleaned_data['parent']
         if new_parent:
         if new_parent:
@@ -333,4 +333,4 @@ class Delete(FormWidget):
                 child.delete()
                 child.delete()
         target.delete()
         target.delete()
         Forum.objects.populate_tree(True)
         Forum.objects.populate_tree(True)
-        return target, Message(_('Forum "%(name)s" has been deleted.') % {'name': self.original_name}, 'success')
+        return target, Message(_('Forum "%(name)s" has been deleted.') % {'name': self.original_name}, 'success')

+ 1 - 1
misago/markdown/__init__.py

@@ -1 +1 @@
-from misago.markdown.factory import *
+from misago.markdown.factory import *

+ 1 - 1
misago/markdown/extensions/ats.py

@@ -31,4 +31,4 @@ class AtsPostprocessor(markdown.postprocessors.Postprocessor):
     def run(self, text):
     def run(self, text):
         text = text.replace('&lt;%s:username&gt;' % self.markdown.mi_token, '<username>')
         text = text.replace('&lt;%s:username&gt;' % self.markdown.mi_token, '<username>')
         text = text.replace('&lt;/%s:username&gt;' % self.markdown.mi_token, '</username>')
         text = text.replace('&lt;/%s:username&gt;' % self.markdown.mi_token, '</username>')
-        return text
+        return text

+ 1 - 1
misago/markdown/extensions/quotes.py

@@ -49,4 +49,4 @@ class QuoteTitlesPostprocessor(markdown.postprocessors.Postprocessor):
     def run(self, text):
     def run(self, text):
         text = text.replace('&lt;%s:quotetitle&gt;' % self.markdown.mi_token, '<h3><quotetitle>')
         text = text.replace('&lt;%s:quotetitle&gt;' % self.markdown.mi_token, '<h3><quotetitle>')
         text = text.replace('&lt;/%s:quotetitle&gt;' % self.markdown.mi_token, '</quotetitle></h3>')
         text = text.replace('&lt;/%s:quotetitle&gt;' % self.markdown.mi_token, '</quotetitle></h3>')
-        return text
+        return text

+ 10 - 10
misago/markdown/factory.py

@@ -11,22 +11,22 @@ def remove_unsupported(md):
     del md.inlinePatterns['reference']
     del md.inlinePatterns['reference']
     del md.inlinePatterns['image_reference']
     del md.inlinePatterns['image_reference']
     del md.inlinePatterns['short_reference']
     del md.inlinePatterns['short_reference']
-    
+
 
 
 def signature_markdown(acl, text):
 def signature_markdown(acl, text):
     md = markdown.Markdown(
     md = markdown.Markdown(
                            safe_mode='escape',
                            safe_mode='escape',
                            output_format=settings.OUTPUT_FORMAT,
                            output_format=settings.OUTPUT_FORMAT,
                            extensions=['nl2br'])
                            extensions=['nl2br'])
-    
+
     remove_unsupported(md)
     remove_unsupported(md)
-    
+
     if not acl.usercp.allow_signature_links():
     if not acl.usercp.allow_signature_links():
         del md.inlinePatterns['link']
         del md.inlinePatterns['link']
         del md.inlinePatterns['autolink']
         del md.inlinePatterns['autolink']
     if not acl.usercp.allow_signature_images():
     if not acl.usercp.allow_signature_images():
         del md.inlinePatterns['image_link']
         del md.inlinePatterns['image_link']
-        
+
     del md.parser.blockprocessors['hashheader']
     del md.parser.blockprocessors['hashheader']
     del md.parser.blockprocessors['setextheader']
     del md.parser.blockprocessors['setextheader']
     del md.parser.blockprocessors['code']
     del md.parser.blockprocessors['code']
@@ -34,7 +34,7 @@ def signature_markdown(acl, text):
     del md.parser.blockprocessors['hr']
     del md.parser.blockprocessors['hr']
     del md.parser.blockprocessors['olist']
     del md.parser.blockprocessors['olist']
     del md.parser.blockprocessors['ulist']
     del md.parser.blockprocessors['ulist']
-    
+
     return md.convert(text)
     return md.convert(text)
 
 
 
 
@@ -43,7 +43,7 @@ def post_markdown(request, text):
                            safe_mode='escape',
                            safe_mode='escape',
                            output_format=settings.OUTPUT_FORMAT,
                            output_format=settings.OUTPUT_FORMAT,
                            extensions=['nl2br', 'fenced_code'])
                            extensions=['nl2br', 'fenced_code'])
-    
+
     remove_unsupported(md)
     remove_unsupported(md)
     md.mi_token = get_random_string(16)
     md.mi_token = get_random_string(16)
     for extension in settings.MARKDOWN_EXTENSIONS:
     for extension in settings.MARKDOWN_EXTENSIONS:
@@ -54,14 +54,14 @@ def post_markdown(request, text):
         ext = attr()
         ext = attr()
         ext.extendMarkdown(md)
         ext.extendMarkdown(md)
     text = md.convert(text)
     text = md.convert(text)
-    
+
     # Final cleanups
     # Final cleanups
     text = text.replace('<p><h3><quotetitle>', '<h3><quotetitle>')
     text = text.replace('<p><h3><quotetitle>', '<h3><quotetitle>')
     text = text.replace('</quotetitle></h3></p>', '</quotetitle></h3>')
     text = text.replace('</quotetitle></h3></p>', '</quotetitle></h3>')
     text = text.replace('</quotetitle></h3><br>\n', '</quotetitle></h3>\n<p>')
     text = text.replace('</quotetitle></h3><br>\n', '</quotetitle></h3>\n<p>')
     text = text.replace('\n<p></p>', '')
     text = text.replace('\n<p></p>', '')
     def trans_quotetitle(match):
     def trans_quotetitle(match):
-        return _("Posted by %(user)s") % {'user': match.group('content')} 
+        return _("Posted by %(user)s") % {'user': match.group('content')}
     text = re.sub(r'<quotetitle>(?P<content>.+)</quotetitle>', trans_quotetitle, text)
     text = re.sub(r'<quotetitle>(?P<content>.+)</quotetitle>', trans_quotetitle, text)
-    
-    return text
+
+    return text

+ 1 - 1
misago/markdown/views.py

@@ -4,4 +4,4 @@ from misago.markdown import post_markdown
 def preview(request):
 def preview(request):
     if request.POST.get('raw'):
     if request.POST.get('raw'):
         return HttpResponse(post_markdown(request, request.POST.get('raw')))
         return HttpResponse(post_markdown(request, request.POST.get('raw')))
-    return HttpResponse('')
+    return HttpResponse('')

+ 5 - 5
misago/messages/__init__.py

@@ -3,23 +3,23 @@ class Messages(object):
         self.session = session
         self.session = session
         self.messages = session.get('messages_list', [])
         self.messages = session.get('messages_list', [])
         self.session['messages_list'] = []
         self.session['messages_list'] = []
-        
+
     def set_message(self, message, type='info', owner=None):
     def set_message(self, message, type='info', owner=None):
         message.type = type
         message.type = type
         message.owner = owner
         message.owner = owner
         self.messages.append(message)
         self.messages.append(message)
-    
+
     def set_flash(self, message, type='info', owner=None):
     def set_flash(self, message, type='info', owner=None):
         self.set_message(message, type, owner)
         self.set_message(message, type, owner)
         self.session['messages_list'].append(message)
         self.session['messages_list'].append(message)
-        
+
     def get_message(self, owner=None):
     def get_message(self, owner=None):
         for index, message in enumerate(self.messages):
         for index, message in enumerate(self.messages):
             if message.owner == owner:
             if message.owner == owner:
                 del self.messages[index]
                 del self.messages[index]
                 return message
                 return message
         return None
         return None
-        
+
     def get_messages(self, owner=None):
     def get_messages(self, owner=None):
         orphans = []
         orphans = []
         messages = []
         messages = []
@@ -36,4 +36,4 @@ class Message(object):
     def __init__(self, message=None, type='info', owner=None):
     def __init__(self, message=None, type='info', owner=None):
         self.type = type
         self.type = type
         self.message = message
         self.message = message
-        self.owner = owner
+        self.owner = owner

+ 1 - 1
misago/messages/context_processors.py

@@ -1,4 +1,4 @@
 def messages(request):
 def messages(request):
     return {
     return {
         'messages' : request.messages.messages,
         'messages' : request.messages.messages,
-    }
+    }

+ 1 - 1
misago/messages/middleware.py

@@ -2,4 +2,4 @@ from misago.messages import Messages
 
 
 class MessagesMiddleware(object):
 class MessagesMiddleware(object):
     def process_request(self, request):
     def process_request(self, request):
-        request.messages = Messages(request.session)
+        request.messages = Messages(request.session)

+ 1 - 1
misago/monitor/context_processors.py

@@ -1,4 +1,4 @@
 def monitor(request):
 def monitor(request):
     return {
     return {
         'monitor' : request.monitor,
         'monitor' : request.monitor,
-    }
+    }

+ 2 - 2
misago/monitor/fixtures.py

@@ -1,6 +1,6 @@
 from django.utils import timezone
 from django.utils import timezone
 from misago.monitor.models import Item
 from misago.monitor.models import Item
-    
+
 def load_monitor_fixture(fixture):
 def load_monitor_fixture(fixture):
     for id in fixture.keys():
     for id in fixture.keys():
         item = Item(
         item = Item(
@@ -8,4 +8,4 @@ def load_monitor_fixture(fixture):
                     value=fixture[id],
                     value=fixture[id],
                     updated=timezone.now()
                     updated=timezone.now()
                     )
                     )
-        item.save(force_insert=True)
+        item.save(force_insert=True)

+ 1 - 1
misago/monitor/middleware.py

@@ -2,4 +2,4 @@ from misago.monitor.monitor import Monitor
 
 
 class MonitorMiddleware(object):
 class MonitorMiddleware(object):
     def process_request(self, request):
     def process_request(self, request):
-        request.monitor = Monitor()
+        request.monitor = Monitor()

+ 1 - 1
misago/monitor/models.py

@@ -3,4 +3,4 @@ from django.db import models
 class Item(models.Model):
 class Item(models.Model):
     id = models.CharField(max_length=255, primary_key=True)
     id = models.CharField(max_length=255, primary_key=True)
     value = models.TextField(blank=True, null=True)
     value = models.TextField(blank=True, null=True)
-    updated = models.DateTimeField(blank=True, null=True)
+    updated = models.DateTimeField(blank=True, null=True)

+ 5 - 5
misago/monitor/monitor.py

@@ -7,7 +7,7 @@ class Monitor(object):
         self._cache_deleted = False
         self._cache_deleted = False
         self._items = {}
         self._items = {}
         self.refresh()
         self.refresh()
-            
+
     def refresh(self):
     def refresh(self):
         self._items = cache.get('misago.monitor')
         self._items = cache.get('misago.monitor')
         if not self._items:
         if not self._items:
@@ -28,20 +28,20 @@ class Monitor(object):
         sync_item = Item(id=key, value=value, updated=timezone.now())
         sync_item = Item(id=key, value=value, updated=timezone.now())
         sync_item.save(force_update=True)
         sync_item.save(force_update=True)
         return value
         return value
-        
+
     def __delitem__(self, key):
     def __delitem__(self, key):
         pass
         pass
-        
+
     def get(self, key, default=None):
     def get(self, key, default=None):
         if not key in self._items:
         if not key in self._items:
             return default
             return default
         return self._items[key][0]
         return self._items[key][0]
-    
+
     def get_updated(self, key):
     def get_updated(self, key):
         if key in self._items:
         if key in self._items:
             return self._items[key][1]
             return self._items[key][1]
         return None
         return None
-        
+
     def has_key(self, key):
     def has_key(self, key):
         return key in self._items
         return key in self._items
 
 

+ 11 - 11
misago/newsletters/forms.py

@@ -6,16 +6,16 @@ from misago.ranks.models import Rank
 from misago.utils.validators import validate_sluggable
 from misago.utils.validators import validate_sluggable
 
 
 class NewsletterForm(Form):
 class NewsletterForm(Form):
-    name = forms.CharField(max_length=255,validators=[validate_sluggable(
-                                                                         _("Newsletter name must be sluggable."),
-                                                                         _("Newsletter name is too long.")
-                                                                         )])
-    step_size = forms.IntegerField(initial=300,min_value=1)
+    name = forms.CharField(max_length=255, validators=[validate_sluggable(
+                                                                          _("Newsletter name must be sluggable."),
+                                                                          _("Newsletter name is too long.")
+                                                                          )])
+    step_size = forms.IntegerField(initial=300, min_value=1)
     content_html = forms.CharField(widget=forms.Textarea)
     content_html = forms.CharField(widget=forms.Textarea)
     content_plain = forms.CharField(widget=forms.Textarea)
     content_plain = forms.CharField(widget=forms.Textarea)
-    ignore_subscriptions = forms.BooleanField(widget=YesNoSwitch,required=False) 
-    ranks = forms.ModelMultipleChoiceField(widget=forms.CheckboxSelectMultiple,queryset=Rank.objects.order_by('name').all(),required=False)
-    
+    ignore_subscriptions = forms.BooleanField(widget=YesNoSwitch, required=False)
+    ranks = forms.ModelMultipleChoiceField(widget=forms.CheckboxSelectMultiple, queryset=Rank.objects.order_by('name').all(), required=False)
+
     layout = (
     layout = (
               (
               (
                _("Newsletter Options"),
                _("Newsletter Options"),
@@ -36,12 +36,12 @@ class NewsletterForm(Form):
              )
              )
 
 
 
 
-class SearchNewslettersForm(Form):    
+class SearchNewslettersForm(Form):
     name = forms.CharField(max_length=255, required=False)
     name = forms.CharField(max_length=255, required=False)
     contains = forms.CharField(max_length=255, required=False)
     contains = forms.CharField(max_length=255, required=False)
     type = forms.MultipleChoiceField(widget=forms.CheckboxSelectMultiple, choices=(('0', _("Only to subscribers")), ('1', _("To every member"))), required=False)
     type = forms.MultipleChoiceField(widget=forms.CheckboxSelectMultiple, choices=(('0', _("Only to subscribers")), ('1', _("To every member"))), required=False)
     rank = forms.ModelMultipleChoiceField(widget=forms.CheckboxSelectMultiple, queryset=Rank.objects.order_by('order').all(), required=False)
     rank = forms.ModelMultipleChoiceField(widget=forms.CheckboxSelectMultiple, queryset=Rank.objects.order_by('order').all(), required=False)
-    
+
     layout = (
     layout = (
               (
               (
                _("Search Newsletters"),
                _("Search Newsletters"),
@@ -52,4 +52,4 @@ class SearchNewslettersForm(Form):
                 ('rank', {'label': _("Recipient Rank")}),
                 ('rank', {'label': _("Recipient Rank")}),
                ),
                ),
               ),
               ),
-             )
+             )

+ 7 - 7
misago/newsletters/models.py

@@ -6,28 +6,28 @@ class Newsletter(models.Model):
     token = models.CharField(max_length=32)
     token = models.CharField(max_length=32)
     step_size = models.PositiveIntegerField(default=0)
     step_size = models.PositiveIntegerField(default=0)
     progress = models.PositiveIntegerField(default=0)
     progress = models.PositiveIntegerField(default=0)
-    content_html = models.TextField(null=True,blank=True)
-    content_plain = models.TextField(null=True,blank=True)
+    content_html = models.TextField(null=True, blank=True)
+    content_plain = models.TextField(null=True, blank=True)
     ignore_subscriptions = models.BooleanField(default=False)
     ignore_subscriptions = models.BooleanField(default=False)
     ranks = models.ManyToManyField('ranks.Rank')
     ranks = models.ManyToManyField('ranks.Rank')
-    
+
     def generate_token(self):
     def generate_token(self):
         self.token = get_random_string(32)
         self.token = get_random_string(32)
-    
+
     def parse_name(self, tokens):
     def parse_name(self, tokens):
         name = self.name
         name = self.name
         for key in tokens:
         for key in tokens:
             name = name.replace(key, tokens[key])
             name = name.replace(key, tokens[key])
         return name
         return name
-    
+
     def parse_html(self, tokens):
     def parse_html(self, tokens):
         content_html = self.content_html
         content_html = self.content_html
         for key in tokens:
         for key in tokens:
             content_html = content_html.replace(key, tokens[key])
             content_html = content_html.replace(key, tokens[key])
         return content_html
         return content_html
-    
+
     def parse_plain(self, tokens):
     def parse_plain(self, tokens):
         content_plain = self.content_plain
         content_plain = self.content_plain
         for key in tokens:
         for key in tokens:
             content_plain = content_plain.replace(key, tokens[key])
             content_plain = content_plain.replace(key, tokens[key])
-        return content_plain
+        return content_plain

+ 32 - 32
misago/newsletters/views.py

@@ -23,19 +23,19 @@ Views
 class List(ListWidget):
 class List(ListWidget):
     admin = site.get_action('newsletters')
     admin = site.get_action('newsletters')
     id = 'list'
     id = 'list'
-    columns=(
+    columns = (
              ('newsletter', _("Newsletter")),
              ('newsletter', _("Newsletter")),
              )
              )
     nothing_checked_message = _('You have to check at least one newsletter.')
     nothing_checked_message = _('You have to check at least one newsletter.')
-    actions=(
+    actions = (
              ('delete', _("Delete selected newsletters"), _("Are you sure you want to delete selected newsletters?")),
              ('delete', _("Delete selected newsletters"), _("Are you sure you want to delete selected newsletters?")),
              )
              )
     pagination = 20
     pagination = 20
     search_form = SearchNewslettersForm
     search_form = SearchNewslettersForm
-    
+
     def sort_items(self, page_items, sorting_method):
     def sort_items(self, page_items, sorting_method):
         return page_items.order_by('-id')
         return page_items.order_by('-id')
-    
+
     def set_filters(self, model, filters):
     def set_filters(self, model, filters):
         if 'rank' in filters:
         if 'rank' in filters:
             model = model.filter(ranks__in=filters['rank']).distinct()
             model = model.filter(ranks__in=filters['rank']).distinct()
@@ -46,7 +46,7 @@ class List(ListWidget):
         if 'content' in filters:
         if 'content' in filters:
             model = model.filter(Q(content_html__icontains=filters['content']) | Q(content_plain__icontains=filters['content']))
             model = model.filter(Q(content_html__icontains=filters['content']) | Q(content_plain__icontains=filters['content']))
         return model
         return model
-    
+
     def get_item_actions(self, item):
     def get_item_actions(self, item):
         return (
         return (
                 self.action('envelope', _("Send Newsletter"), reverse('admin_newsletters_send', item)),
                 self.action('envelope', _("Send Newsletter"), reverse('admin_newsletters_send', item)),
@@ -62,35 +62,35 @@ class List(ListWidget):
 class New(FormWidget):
 class New(FormWidget):
     admin = site.get_action('newsletters')
     admin = site.get_action('newsletters')
     id = 'new'
     id = 'new'
-    fallback = 'admin_newsletters' 
+    fallback = 'admin_newsletters'
     form = NewsletterForm
     form = NewsletterForm
     submit_button = _("Save Newsletter")
     submit_button = _("Save Newsletter")
     tabbed = True
     tabbed = True
-        
+
     def get_new_url(self, model):
     def get_new_url(self, model):
         return reverse('admin_newsletters_new')
         return reverse('admin_newsletters_new')
-    
+
     def get_edit_url(self, model):
     def get_edit_url(self, model):
         return reverse('admin_newsletters_edit', model)
         return reverse('admin_newsletters_edit', model)
-    
+
     def submit_form(self, form, target):
     def submit_form(self, form, target):
         new_newsletter = Newsletter(
         new_newsletter = Newsletter(
-                      name = form.cleaned_data['name'],
-                      step_size = form.cleaned_data['step_size'],
-                      content_html = form.cleaned_data['content_html'],
-                      content_plain = form.cleaned_data['content_plain'],
-                      ignore_subscriptions = form.cleaned_data['ignore_subscriptions'],
+                      name=form.cleaned_data['name'],
+                      step_size=form.cleaned_data['step_size'],
+                      content_html=form.cleaned_data['content_html'],
+                      content_plain=form.cleaned_data['content_plain'],
+                      ignore_subscriptions=form.cleaned_data['ignore_subscriptions'],
                      )
                      )
         new_newsletter.generate_token()
         new_newsletter.generate_token()
         new_newsletter.save(force_insert=True)
         new_newsletter.save(force_insert=True)
-        
+
         for rank in form.cleaned_data['ranks']:
         for rank in form.cleaned_data['ranks']:
             new_newsletter.ranks.add(rank)
             new_newsletter.ranks.add(rank)
         new_newsletter.save(force_update=True)
         new_newsletter.save(force_update=True)
-        
+
         return new_newsletter, Message(_('New Newsletter has been created.'), 'success')
         return new_newsletter, Message(_('New Newsletter has been created.'), 'success')
-    
-   
+
+
 class Edit(FormWidget):
 class Edit(FormWidget):
     admin = site.get_action('newsletters')
     admin = site.get_action('newsletters')
     id = 'edit'
     id = 'edit'
@@ -101,13 +101,13 @@ class Edit(FormWidget):
     notfound_message = _('Requested Newsletter could not be found.')
     notfound_message = _('Requested Newsletter could not be found.')
     submit_fallback = True
     submit_fallback = True
     tabbed = True
     tabbed = True
-    
+
     def get_url(self, model):
     def get_url(self, model):
         return reverse('admin_newsletters_edit', model)
         return reverse('admin_newsletters_edit', model)
-    
+
     def get_edit_url(self, model):
     def get_edit_url(self, model):
         return self.get_url(model)
         return self.get_url(model)
-    
+
     def get_initial_data(self, model):
     def get_initial_data(self, model):
         return {
         return {
                 'name': model.name,
                 'name': model.name,
@@ -117,7 +117,7 @@ class Edit(FormWidget):
                 'content_plain': model.content_plain,
                 'content_plain': model.content_plain,
                 'ranks': model.ranks.all(),
                 'ranks': model.ranks.all(),
                 }
                 }
-    
+
     def submit_form(self, form, target):
     def submit_form(self, form, target):
         target.name = form.cleaned_data['name']
         target.name = form.cleaned_data['name']
         target.step_size = form.cleaned_data['step_size']
         target.step_size = form.cleaned_data['step_size']
@@ -125,11 +125,11 @@ class Edit(FormWidget):
         target.content_html = form.cleaned_data['content_html']
         target.content_html = form.cleaned_data['content_html']
         target.content_plain = form.cleaned_data['content_plain']
         target.content_plain = form.cleaned_data['content_plain']
         target.generate_token()
         target.generate_token()
-        
+
         target.ranks.clear()
         target.ranks.clear()
         for rank in form.cleaned_data['ranks']:
         for rank in form.cleaned_data['ranks']:
             target.ranks.add(rank)
             target.ranks.add(rank)
-            
+
         target.save(force_update=True)
         target.save(force_update=True)
         return target, Message(_('Changes in newsletter "%(name)s" have been saved.') % {'name': self.original_name}, 'success')
         return target, Message(_('Changes in newsletter "%(name)s" have been saved.') % {'name': self.original_name}, 'success')
 
 
@@ -139,29 +139,29 @@ class Delete(ButtonWidget):
     id = 'delete'
     id = 'delete'
     fallback = 'admin_newsletters'
     fallback = 'admin_newsletters'
     notfound_message = _('Requested newsletter could not be found.')
     notfound_message = _('Requested newsletter could not be found.')
-    
+
     def action(self, target):
     def action(self, target):
         target.delete()
         target.delete()
         return Message(_('Newsletter "%(name)s"" has been deleted.') % {'name': target.name}, 'success'), False
         return Message(_('Newsletter "%(name)s"" has been deleted.') % {'name': target.name}, 'success'), False
-    
+
 
 
 def send(request, target, token):
 def send(request, target, token):
     try:
     try:
         newsletter = Newsletter.objects.get(pk=target, token=token)
         newsletter = Newsletter.objects.get(pk=target, token=token)
-        
+
         # Build recipients selector
         # Build recipients selector
         recipients = User.objects
         recipients = User.objects
         if newsletter.ranks.all():
         if newsletter.ranks.all():
             recipients.filter(rank__in=[x.pk for x in newsletter.ranks.all()])
             recipients.filter(rank__in=[x.pk for x in newsletter.ranks.all()])
         if not newsletter.ignore_subscriptions:
         if not newsletter.ignore_subscriptions:
             recipients.filter(receive_newsletters=1)
             recipients.filter(receive_newsletters=1)
-        
+
         recipients_total = recipients
         recipients_total = recipients
         recipients_total = recipients_total.count()
         recipients_total = recipients_total.count()
         if recipients_total < 1:
         if recipients_total < 1:
             request.messages.set_flash(Message(_('No recipients for newsletter "%(newsletter)s" could be found.') % {'newsletter': newsletter.name}), 'error', 'newsletters')
             request.messages.set_flash(Message(_('No recipients for newsletter "%(newsletter)s" could be found.') % {'newsletter': newsletter.name}), 'error', 'newsletters')
             return redirect(reverse('admin_newsletters'))
             return redirect(reverse('admin_newsletters'))
-       
+
         for user in recipients.all()[newsletter.progress:(newsletter.progress + newsletter.step_size)]:
         for user in recipients.all()[newsletter.progress:(newsletter.progress + newsletter.step_size)]:
             tokens = {
             tokens = {
               '{{ board_name }}': request.settings.board_name,
               '{{ board_name }}': request.settings.board_name,
@@ -179,13 +179,13 @@ def send(request, target, token):
             newsletter.progress += 1
             newsletter.progress += 1
         newsletter.generate_token()
         newsletter.generate_token()
         newsletter.save(force_update=True)
         newsletter.save(force_update=True)
-        
+
         if newsletter.progress >= recipients_total:
         if newsletter.progress >= recipients_total:
             newsletter.progress = 0
             newsletter.progress = 0
             newsletter.save(force_update=True)
             newsletter.save(force_update=True)
             request.messages.set_flash(Message(_('Newsletter "%(newsletter)s" has been sent.') % {'newsletter': newsletter.name}), 'success', 'newsletters')
             request.messages.set_flash(Message(_('Newsletter "%(newsletter)s" has been sent.') % {'newsletter': newsletter.name}), 'success', 'newsletters')
             return redirect(reverse('admin_newsletters'))
             return redirect(reverse('admin_newsletters'))
-        
+
         # Render Progress
         # Render Progress
         response = request.theme.render_to_response('processing.html', {
         response = request.theme.render_to_response('processing.html', {
                 'task_name': _('Sending Newsletter'),
                 'task_name': _('Sending Newsletter'),
@@ -198,4 +198,4 @@ def send(request, target, token):
         return response
         return response
     except Newsletter.DoesNotExist:
     except Newsletter.DoesNotExist:
         request.messages.set_flash(Message(_('Requested Newsletter could not be found.')), 'error', 'newsletters')
         request.messages.set_flash(Message(_('Requested Newsletter could not be found.')), 'error', 'newsletters')
-        return redirect(reverse('admin_newsletters'))
+        return redirect(reverse('admin_newsletters'))

+ 1 - 1
misago/profiles/urls.py

@@ -8,4 +8,4 @@ urlpatterns = patterns('misago.profiles.views',
     url(r'^(?P<username>\w+)-(?P<user>\d+)/followiers/$', 'profile', name="user_followers", kwargs={'tab': 'followers'}),
     url(r'^(?P<username>\w+)-(?P<user>\d+)/followiers/$', 'profile', name="user_followers", kwargs={'tab': 'followers'}),
     url(r'^(?P<username>\w+)-(?P<user>\d+)/details/$', 'profile', name="user_details", kwargs={'tab': 'details'}),
     url(r'^(?P<username>\w+)-(?P<user>\d+)/details/$', 'profile', name="user_details", kwargs={'tab': 'details'}),
     url(r'^(?P<rank_slug>(\w|-)+)/$', 'list', name="users"),
     url(r'^(?P<rank_slug>(\w|-)+)/$', 'list', name="users"),
-)
+)

+ 12 - 12
misago/profiles/views.py

@@ -12,7 +12,7 @@ from misago.views import error404
 
 
 def list(request, rank_slug=None):
 def list(request, rank_slug=None):
     ranks = Rank.objects.filter(as_tab=1).order_by('order')
     ranks = Rank.objects.filter(as_tab=1).order_by('order')
-    
+
     # Find active rank
     # Find active rank
     active_rank = None
     active_rank = None
     if rank_slug:
     if rank_slug:
@@ -23,12 +23,12 @@ def list(request, rank_slug=None):
             return error404(request)
             return error404(request)
     elif ranks:
     elif ranks:
         active_rank = ranks[0]
         active_rank = ranks[0]
-    
+
     # Empty Defaults
     # Empty Defaults
     message = None
     message = None
     users = []
     users = []
     in_search = False
     in_search = False
-    
+
     # Users search?
     # Users search?
     if request.method == 'POST':
     if request.method == 'POST':
         in_search = True
         in_search = True
@@ -42,7 +42,7 @@ def list(request, rank_slug=None):
                 return redirect(reverse('user', args=(user.username_slug, user.pk)))
                 return redirect(reverse('user', args=(user.username_slug, user.pk)))
             except User.DoesNotExist:
             except User.DoesNotExist:
                 pass
                 pass
-            
+
             # Looks like well have to find near match
             # Looks like well have to find near match
             if len(username) > 6:
             if len(username) > 6:
                 username = username[0:-3]
                 username = username[0:-3]
@@ -51,7 +51,7 @@ def list(request, rank_slug=None):
             elif len(username) > 4:
             elif len(username) > 4:
                 username = username[0:-1]
                 username = username[0:-1]
             username = slugify(username.strip())
             username = slugify(username.strip())
-            
+
             # Go for rought match
             # Go for rought match
             if len(username) > 0:
             if len(username) > 0:
                 users = User.objects.filter(username_slug__startswith=username).order_by('username_slug')[:10]
                 users = User.objects.filter(username_slug__startswith=username).order_by('username_slug')[:10]
@@ -63,7 +63,7 @@ def list(request, rank_slug=None):
         search_form = QuickFindUserForm(request=request)
         search_form = QuickFindUserForm(request=request)
         if active_rank:
         if active_rank:
             users = User.objects.filter(rank=active_rank).order_by('username_slug')
             users = User.objects.filter(rank=active_rank).order_by('username_slug')
-    
+
     return request.theme.render_to_response('profiles/list.html',
     return request.theme.render_to_response('profiles/list.html',
                                         {
                                         {
                                          'message': message,
                                          'message': message,
@@ -86,7 +86,7 @@ def profile(request, user, username, tab='posts'):
         return globals()['profile_%s' % tab](request, user)
         return globals()['profile_%s' % tab](request, user)
     except User.DoesNotExist:
     except User.DoesNotExist:
         return error404(request)
         return error404(request)
-    
+
 
 
 def profile_posts(request, user):
 def profile_posts(request, user):
     return request.theme.render_to_response('profiles/profile.html',
     return request.theme.render_to_response('profiles/profile.html',
@@ -95,7 +95,7 @@ def profile_posts(request, user):
                                              'tab': 'posts',
                                              'tab': 'posts',
                                             },
                                             },
                                             context_instance=RequestContext(request));
                                             context_instance=RequestContext(request));
-    
+
 
 
 def profile_threads(request, user):
 def profile_threads(request, user):
     return request.theme.render_to_response('profiles/profile.html',
     return request.theme.render_to_response('profiles/profile.html',
@@ -104,7 +104,7 @@ def profile_threads(request, user):
                                              'tab': 'threads',
                                              'tab': 'threads',
                                             },
                                             },
                                             context_instance=RequestContext(request));
                                             context_instance=RequestContext(request));
-    
+
 
 
 def profile_following(request, user):
 def profile_following(request, user):
     return request.theme.render_to_response('profiles/profile.html',
     return request.theme.render_to_response('profiles/profile.html',
@@ -113,7 +113,7 @@ def profile_following(request, user):
                                              'tab': 'following',
                                              'tab': 'following',
                                             },
                                             },
                                             context_instance=RequestContext(request));
                                             context_instance=RequestContext(request));
-    
+
 
 
 def profile_followers(request, user):
 def profile_followers(request, user):
     return request.theme.render_to_response('profiles/profile.html',
     return request.theme.render_to_response('profiles/profile.html',
@@ -122,7 +122,7 @@ def profile_followers(request, user):
                                              'tab': 'followers',
                                              'tab': 'followers',
                                             },
                                             },
                                             context_instance=RequestContext(request));
                                             context_instance=RequestContext(request));
-    
+
 
 
 def profile_details(request, user):
 def profile_details(request, user):
     return request.theme.render_to_response('profiles/details.html',
     return request.theme.render_to_response('profiles/details.html',
@@ -130,4 +130,4 @@ def profile_details(request, user):
                                              'profile': user,
                                              'profile': user,
                                              'tab': 'details',
                                              'tab': 'details',
                                             },
                                             },
-                                            context_instance=RequestContext(request));
+                                            context_instance=RequestContext(request));

+ 14 - 15
misago/prune/forms.py

@@ -4,22 +4,22 @@ from misago.forms import Form
 from misago.utils.validators import validate_sluggable
 from misago.utils.validators import validate_sluggable
 
 
 class PolicyForm(Form):
 class PolicyForm(Form):
-    name = forms.CharField(max_length=255,validators=[validate_sluggable(
-                                                                         _("Policy name must be sluggable."),
-                                                                         _("Policy name is too long.")
-                                                                         )])
-    email = forms.CharField(max_length=255,required=False)
-    posts = forms.IntegerField(min_value=0,initial=0)
-    registered = forms.IntegerField(min_value=0,initial=0)
-    last_visit = forms.IntegerField(min_value=0,initial=0)
-    
+    name = forms.CharField(max_length=255, validators=[validate_sluggable(
+                                                                          _("Policy name must be sluggable."),
+                                                                          _("Policy name is too long.")
+                                                                          )])
+    email = forms.CharField(max_length=255, required=False)
+    posts = forms.IntegerField(min_value=0, initial=0)
+    registered = forms.IntegerField(min_value=0, initial=0)
+    last_visit = forms.IntegerField(min_value=0, initial=0)
+
     layout = (
     layout = (
               (
               (
                _("Basic Policy Options"),
                _("Basic Policy Options"),
                (
                (
                 ('name', {'label': _("Policy Name"), 'help_text': _("Short, descriptive name of this pruning policy.")}),
                 ('name', {'label': _("Policy Name"), 'help_text': _("Short, descriptive name of this pruning policy.")}),
-               )
-              ),
+                )
+               ),
               (
               (
                _("Pruning Policy Criteria"),
                _("Pruning Policy Criteria"),
                (
                (
@@ -27,7 +27,6 @@ class PolicyForm(Form):
                 ('posts', {'label': _("Member has no more posts than"), 'help_text': _("Maximum number of posts member is allowed to have to fall under policy. For example if you enter in 10 posts and make this only criteria, every user that has less than 10 posts will be deleted. Enter zero to dont use this criteria")}),
                 ('posts', {'label': _("Member has no more posts than"), 'help_text': _("Maximum number of posts member is allowed to have to fall under policy. For example if you enter in 10 posts and make this only criteria, every user that has less than 10 posts will be deleted. Enter zero to dont use this criteria")}),
                 ('registered', {'label': _("User is member for no more than"), 'help_text': _("Maximal number of days user is member for. For exmaple if you enter in 15 days and make this only criteria, every user who is member for less than 15 days will be deleted. Enter zero to dont use this criteria.")}),
                 ('registered', {'label': _("User is member for no more than"), 'help_text': _("Maximal number of days user is member for. For exmaple if you enter in 15 days and make this only criteria, every user who is member for less than 15 days will be deleted. Enter zero to dont use this criteria.")}),
                 ('last_visit', {'label': _("User last visit was before"), 'help_text': _("Maximal allowed inactivity period in days. For example if you enter in 300 days and make this only criteria for deleting users, every member who did not signed into forums in last 300 days will be deleted. Enter zero to dont use this criteria.")}),
                 ('last_visit', {'label': _("User last visit was before"), 'help_text': _("Maximal allowed inactivity period in days. For example if you enter in 300 days and make this only criteria for deleting users, every member who did not signed into forums in last 300 days will be deleted. Enter zero to dont use this criteria.")}),
-               )
-              ),
-             )
-    
+                )
+               ),
+              )

+ 9 - 9
misago/prune/models.py

@@ -11,18 +11,18 @@ class Policy(models.Model):
     Pruning policy
     Pruning policy
     """
     """
     name = models.CharField(max_length=255)
     name = models.CharField(max_length=255)
-    email = models.CharField(max_length=255,null=True,blank=True)
+    email = models.CharField(max_length=255, null=True, blank=True)
     posts = models.PositiveIntegerField(default=0)
     posts = models.PositiveIntegerField(default=0)
     registered = models.PositiveIntegerField(default=0)
     registered = models.PositiveIntegerField(default=0)
     last_visit = models.PositiveIntegerField(default=0)
     last_visit = models.PositiveIntegerField(default=0)
-    
+
     def clean(self):
     def clean(self):
         if not (self.email and self.posts and self.registered and self.last_visit):
         if not (self.email and self.posts and self.registered and self.last_visit):
             raise ValidationError(_("Pruning policy must have at least one pruning criteria set to be valid."))
             raise ValidationError(_("Pruning policy must have at least one pruning criteria set to be valid."))
-        
+
     def get_model(self):
     def get_model(self):
         model = User.objects
         model = User.objects
-        
+
         if self.email:
         if self.email:
             if ',' in self.email:
             if ',' in self.email:
                 qs = None
                 qs = None
@@ -37,16 +37,16 @@ class Policy(models.Model):
                     model = model.filter(qs)
                     model = model.filter(qs)
             else:
             else:
                 model = model.filter(email__iendswith=self.email)
                 model = model.filter(email__iendswith=self.email)
-                
+
         if self.posts:
         if self.posts:
             model = model.filter(posts__lt=self.posts)
             model = model.filter(posts__lt=self.posts)
-            
+
         if self.registered:
         if self.registered:
             date = timezone.now() - timedelta(days=self.registered)
             date = timezone.now() - timedelta(days=self.registered)
             model = model.filter(join_date__gte=date)
             model = model.filter(join_date__gte=date)
-            
+
         if self.last_visit:
         if self.last_visit:
             date = timezone.now() - timedelta(days=self.last_visit)
             date = timezone.now() - timedelta(days=self.last_visit)
             model = model.filter(last_date__gte=date)
             model = model.filter(last_date__gte=date)
-            
-        return model
+
+        return model

+ 41 - 41
misago/prune/views.py

@@ -19,17 +19,17 @@ Views
 class List(ListWidget):
 class List(ListWidget):
     admin = site.get_action('prune_users')
     admin = site.get_action('prune_users')
     id = 'list'
     id = 'list'
-    columns=(
-             ('name', _("Pruning Policy")),
-             )
+    columns = (
+               ('name', _("Pruning Policy")),
+               )
     nothing_checked_message = _('You have to check at least one policy.')
     nothing_checked_message = _('You have to check at least one policy.')
-    actions=(
-             ('delete', _("Delete selected policies"), _("Are you sure you want to delete selected policies?")),
-             )
-    
+    actions = (
+               ('delete', _("Delete selected policies"), _("Are you sure you want to delete selected policies?")),
+               )
+
     def sort_items(self, page_items, sorting_method):
     def sort_items(self, page_items, sorting_method):
         return page_items.order_by('name')
         return page_items.order_by('name')
-    
+
     def get_item_actions(self, item):
     def get_item_actions(self, item):
         return (
         return (
                 self.action('filter', _("Apply Policy"), reverse('admin_prune_users_apply', item)),
                 self.action('filter', _("Apply Policy"), reverse('admin_prune_users_apply', item)),
@@ -40,7 +40,7 @@ class List(ListWidget):
     def action_delete(self, items, checked):
     def action_delete(self, items, checked):
         if not self.request.user.is_god():
         if not self.request.user.is_god():
             return Message(_('Only system administrators can delete pruning policies.'), 'error'), reverse('admin_prune_users')
             return Message(_('Only system administrators can delete pruning policies.'), 'error'), reverse('admin_prune_users')
-        
+
         Policy.objects.filter(id__in=checked).delete()
         Policy.objects.filter(id__in=checked).delete()
         return Message(_('Selected pruning policies have been deleted successfully.'), 'success'), reverse('admin_prune_users')
         return Message(_('Selected pruning policies have been deleted successfully.'), 'success'), reverse('admin_prune_users')
 
 
@@ -48,37 +48,37 @@ class List(ListWidget):
 class New(FormWidget):
 class New(FormWidget):
     admin = site.get_action('prune_users')
     admin = site.get_action('prune_users')
     id = 'new'
     id = 'new'
-    fallback = 'admin_prune_users' 
+    fallback = 'admin_prune_users'
     form = PolicyForm
     form = PolicyForm
     submit_button = _("Save Policy")
     submit_button = _("Save Policy")
-        
+
     def get_new_url(self, model):
     def get_new_url(self, model):
         return reverse('admin_prune_users_new')
         return reverse('admin_prune_users_new')
-    
+
     def get_edit_url(self, model):
     def get_edit_url(self, model):
         return reverse('admin_prune_users_edit', model)
         return reverse('admin_prune_users_edit', model)
-    
+
     def submit_form(self, form, target):
     def submit_form(self, form, target):
         new_policy = Policy(
         new_policy = Policy(
-                      name = form.cleaned_data['name'],
-                      email = form.cleaned_data['email'],
-                      posts = form.cleaned_data['posts'],
-                      registered = form.cleaned_data['registered'],
-                      last_visit = form.cleaned_data['last_visit'],
+                      name=form.cleaned_data['name'],
+                      email=form.cleaned_data['email'],
+                      posts=form.cleaned_data['posts'],
+                      registered=form.cleaned_data['registered'],
+                      last_visit=form.cleaned_data['last_visit'],
                      )
                      )
         new_policy.clean()
         new_policy.clean()
         new_policy.save(force_insert=True)
         new_policy.save(force_insert=True)
-        
+
         return new_policy, Message(_('New Pruning Policy has been created.'), 'success')
         return new_policy, Message(_('New Pruning Policy has been created.'), 'success')
-    
+
     def __call__(self, request, *args, **kwargs):
     def __call__(self, request, *args, **kwargs):
         if not request.user.is_god():
         if not request.user.is_god():
             request.messages.set_flash(Message(_('Only system administrators can set new pruning policies.')), 'error', self.admin.id)
             request.messages.set_flash(Message(_('Only system administrators can set new pruning policies.')), 'error', self.admin.id)
             return redirect(reverse('admin_prune_users'))
             return redirect(reverse('admin_prune_users'))
-        
+
         return super(New, self).__call__(request, *args, **kwargs)
         return super(New, self).__call__(request, *args, **kwargs)
 
 
-  
+
 class Edit(FormWidget):
 class Edit(FormWidget):
     admin = site.get_action('prune_users')
     admin = site.get_action('prune_users')
     id = 'edit'
     id = 'edit'
@@ -88,13 +88,13 @@ class Edit(FormWidget):
     target_name = 'name'
     target_name = 'name'
     notfound_message = _('Requested pruning policy could not be found.')
     notfound_message = _('Requested pruning policy could not be found.')
     submit_fallback = True
     submit_fallback = True
-    
+
     def get_url(self, model):
     def get_url(self, model):
         return reverse('admin_prune_users_edit', model)
         return reverse('admin_prune_users_edit', model)
-    
+
     def get_edit_url(self, model):
     def get_edit_url(self, model):
         return self.get_url(model)
         return self.get_url(model)
-    
+
     def get_initial_data(self, model):
     def get_initial_data(self, model):
         return {
         return {
                 'name': model.name,
                 'name': model.name,
@@ -103,7 +103,7 @@ class Edit(FormWidget):
                 'registered': model.registered,
                 'registered': model.registered,
                 'last_visit': model.last_visit,
                 'last_visit': model.last_visit,
                 }
                 }
-    
+
     def submit_form(self, form, target):
     def submit_form(self, form, target):
         target.name = form.cleaned_data['name']
         target.name = form.cleaned_data['name']
         target.email = form.cleaned_data['email']
         target.email = form.cleaned_data['email']
@@ -112,14 +112,14 @@ class Edit(FormWidget):
         target.last_visit = form.cleaned_data['last_visit']
         target.last_visit = form.cleaned_data['last_visit']
         target.clean()
         target.clean()
         target.save(force_update=True)
         target.save(force_update=True)
-        
+
         return target, Message(_('Changes in policy "%(name)s" have been saved.') % {'name': self.original_name}, 'success')
         return target, Message(_('Changes in policy "%(name)s" have been saved.') % {'name': self.original_name}, 'success')
-    
+
     def __call__(self, request, *args, **kwargs):
     def __call__(self, request, *args, **kwargs):
         if not request.user.is_god():
         if not request.user.is_god():
             request.messages.set_flash(Message(_('Only system administrators can edit pruning policies.')), 'error', self.admin.id)
             request.messages.set_flash(Message(_('Only system administrators can edit pruning policies.')), 'error', self.admin.id)
             return redirect(reverse('admin_prune_users'))
             return redirect(reverse('admin_prune_users'))
-        
+
         return super(Edit, self).__call__(request, *args, **kwargs)
         return super(Edit, self).__call__(request, *args, **kwargs)
 
 
 
 
@@ -128,14 +128,14 @@ class Delete(ButtonWidget):
     id = 'delete'
     id = 'delete'
     fallback = 'admin_prune_users'
     fallback = 'admin_prune_users'
     notfound_message = _('Requested pruning policy could not be found.')
     notfound_message = _('Requested pruning policy could not be found.')
-    
+
     def action(self, target):
     def action(self, target):
         if not self.request.user.is_god():
         if not self.request.user.is_god():
             return Message(_('Only system administrators can delete pruning policies.'), 'error'), False
             return Message(_('Only system administrators can delete pruning policies.'), 'error'), False
-        
+
         target.delete()
         target.delete()
         return Message(_('Pruning policy "%(name)s" has been deleted.') % {'name': target.name}, 'success'), False
         return Message(_('Pruning policy "%(name)s" has been deleted.') % {'name': target.name}, 'success'), False
-    
+
 
 
 class Apply(FormWidget):
 class Apply(FormWidget):
     admin = site.get_action('prune_users')
     admin = site.get_action('prune_users')
@@ -147,13 +147,13 @@ class Apply(FormWidget):
     notfound_message = _('Requested pruning policy could not be found.')
     notfound_message = _('Requested pruning policy could not be found.')
     submit_fallback = True
     submit_fallback = True
     template = 'apply'
     template = 'apply'
-    
+
     def get_url(self, model):
     def get_url(self, model):
         return reverse('admin_prune_users_apply', model)
         return reverse('admin_prune_users_apply', model)
-    
+
     def __call__(self, request, target=None, slug=None):
     def __call__(self, request, target=None, slug=None):
         self.request = request
         self.request = request
-        
+
         # Fetch target
         # Fetch target
         model = None
         model = None
         if target:
         if target:
@@ -162,16 +162,16 @@ class Apply(FormWidget):
             if not model:
             if not model:
                 return redirect(self.get_fallback_url())
                 return redirect(self.get_fallback_url())
         original_model = model
         original_model = model
-                
+
         # Set filter
         # Set filter
-        users = model.get_model() 
+        users = model.get_model()
         total_users = users
         total_users = users
         total_users = total_users.count()
         total_users = total_users.count()
-        
+
         if not total_users:
         if not total_users:
             request.messages.set_flash(Message(_('Policy "%(name)s" does not apply to any users.') % {'name': model.name}), 'error', self.admin.id)
             request.messages.set_flash(Message(_('Policy "%(name)s" does not apply to any users.') % {'name': model.name}), 'error', self.admin.id)
             return redirect(reverse('admin_prune_users'))
             return redirect(reverse('admin_prune_users'))
-        
+
         message = None
         message = None
         if request.method == 'POST':
         if request.method == 'POST':
             deleted = 0
             deleted = 0
@@ -194,7 +194,7 @@ class Apply(FormWidget):
                 return redirect(reverse('admin_prune_users'))
                 return redirect(reverse('admin_prune_users'))
             else:
             else:
                 message = Message(_("Request authorization is invalid. Please resubmit your form."), 'error')
                 message = Message(_("Request authorization is invalid. Please resubmit your form."), 'error')
-        
+
         return request.theme.render_to_response(self.get_template(),
         return request.theme.render_to_response(self.get_template(),
                                                 {
                                                 {
                                                  'admin': self.admin,
                                                  'admin': self.admin,
@@ -209,4 +209,4 @@ class Apply(FormWidget):
                                                  'target': self.get_target_name(original_model),
                                                  'target': self.get_target_name(original_model),
                                                  'target_model': original_model,
                                                  'target_model': original_model,
                                                 },
                                                 },
-                                                context_instance=RequestContext(request));
+                                                context_instance=RequestContext(request));

+ 7 - 7
misago/ranks/fixtures.py

@@ -13,7 +13,7 @@ def load_fixtures():
                         as_tab=True,
                         as_tab=True,
                         on_index=True,
                         on_index=True,
                         )
                         )
-    
+
     Rank.objects.create(
     Rank.objects.create(
                         name=_("Most Valuable Posters").message,
                         name=_("Most Valuable Posters").message,
                         name_slug='most-valuable-posters',
                         name_slug='most-valuable-posters',
@@ -23,26 +23,26 @@ def load_fixtures():
                         order=1,
                         order=1,
                         as_tab=True,
                         as_tab=True,
                         )
                         )
-    
+
     Rank.objects.create(
     Rank.objects.create(
                         name=_("Lurkers").message,
                         name=_("Lurkers").message,
                         name_slug='lurkers',
                         name_slug='lurkers',
                         order=1,
                         order=1,
                         criteria="100%"
                         criteria="100%"
                         )
                         )
-    
+
     Rank.objects.create(
     Rank.objects.create(
                         name=_("Members").message,
                         name=_("Members").message,
-                        name_slug='members'
+                        name_slug='members',
                         order=2,
                         order=2,
                         criteria="75%"
                         criteria="75%"
                         )
                         )
-    
+
     Rank.objects.create(
     Rank.objects.create(
                         name=_("Active Members").message,
                         name=_("Active Members").message,
-                        name_slug='active-members'
+                        name_slug='active-members',
                         style='rank-active',
                         style='rank-active',
                         order=3,
                         order=3,
                         criteria="10%",
                         criteria="10%",
                         as_tab=True,
                         as_tab=True,
-                        )
+                        )

+ 18 - 19
misago/ranks/forms.py

@@ -5,18 +5,18 @@ from misago.forms import Form, YesNoSwitch
 from misago.utils.validators import validate_sluggable
 from misago.utils.validators import validate_sluggable
 
 
 class RankForm(Form):
 class RankForm(Form):
-    name = forms.CharField(max_length=255,validators=[validate_sluggable(
-                                                                         _("Rank name must be sluggable."),
-                                                                         _("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)
-    
+    name = forms.CharField(max_length=255, validators=[validate_sluggable(
+                                                                          _("Rank name must be sluggable."),
+                                                                          _("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)
+
     layout = (
     layout = (
               (
               (
                _("Basic Rank Options"),
                _("Basic Rank Options"),
@@ -25,21 +25,20 @@ class RankForm(Form):
                 ('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.")}),
                 ('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.")}),
                 ('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?")}),
                 ('on_index', {'label': _("Display members online"), 'help_text': _("Should users online with this rank be displayed on board index?")}),
-               )
-              ),
+                )
+               ),
               (
               (
                _("Rank Looks"),
                _("Rank Looks"),
                (
                (
                 ('title', {'label': _("Rank Title"), 'help_text': _("Short description of rank's bearer role in your community.")}),
                 ('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.")}),
                 ('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"),
                _("Rank Attainability"),
                (
                (
                 ('special', {'label': _("Special Rank"), 'help_text': _("Special ranks are ignored during updates of user ranking, making them unattainable without admin ingerention.")}),
                 ('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.")}),
                 ('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.")}),
+                ),
                ),
                ),
-              ),
-             )
-    
+              )

+ 5 - 5
misago/ranks/management/commands/updateranking.py

@@ -13,10 +13,10 @@ class Command(BaseCommand):
         special_ranks = []
         special_ranks = []
         for rank in Rank.objects.filter(special=1):
         for rank in Rank.objects.filter(special=1):
             special_ranks.append(str(rank.pk))
             special_ranks.append(str(rank.pk))
-        
+
         # Count users that are in ranking
         # Count users that are in ranking
         users_total = User.objects.exclude(rank__in=special_ranks).count()
         users_total = User.objects.exclude(rank__in=special_ranks).count()
-        
+
         # Update Ranking
         # Update Ranking
         defaulted_ranks = False
         defaulted_ranks = False
         for rank in Rank.objects.filter(special=0).order_by('order'):
         for rank in Rank.objects.filter(special=0).order_by('order'):
@@ -27,8 +27,8 @@ class Command(BaseCommand):
                 # Set default rank first
                 # Set default rank first
                 User.objects.exclude(rank__in=special_ranks).update(rank=rank)
                 User.objects.exclude(rank__in=special_ranks).update(rank=rank)
                 defaulted_ranks = True
                 defaulted_ranks = True
-        
+
         # Inflate scores
         # Inflate scores
         User.objects.all().update(score=F('score') * 0.95) # TODO: Ranking system SETTINGS!
         User.objects.all().update(score=F('score') * 0.95) # TODO: Ranking system SETTINGS!
-        
-        self.stdout.write('Users ranking for has been updated.\n')
+
+        self.stdout.write('Users ranking for has been updated.\n')

+ 13 - 13
misago/ranks/models.py

@@ -8,24 +8,24 @@ class Rank(models.Model):
     Ranks are ready style/title pairs that are assigned to users either by admin (special ranks) or as result of user activity.
     Ranks are ready style/title pairs that are assigned to users either by admin (special ranks) or as result of user activity.
     """
     """
     name = models.CharField(max_length=255)
     name = models.CharField(max_length=255)
-    name_slug = models.CharField(max_length=255,null=True,blank=True)
-    description = models.TextField(null=True,blank=True)
-    style = models.CharField(max_length=255,null=True,blank=True)
-    title = models.CharField(max_length=255,null=True,blank=True)
+    name_slug = models.CharField(max_length=255, null=True, blank=True)
+    description = models.TextField(null=True, blank=True)
+    style = models.CharField(max_length=255, null=True, blank=True)
+    title = models.CharField(max_length=255, null=True, blank=True)
     special = models.BooleanField(default=False)
     special = models.BooleanField(default=False)
     as_tab = models.BooleanField(default=False)
     as_tab = models.BooleanField(default=False)
     on_index = models.BooleanField(default=False)
     on_index = models.BooleanField(default=False)
     order = models.IntegerField(default=0)
     order = models.IntegerField(default=0)
-    criteria = models.CharField(max_length=255,null=True,blank=True)
-    
+    criteria = models.CharField(max_length=255, null=True, blank=True)
+
     def __unicode__(self):
     def __unicode__(self):
         return unicode(_(self.name))
         return unicode(_(self.name))
-    
+
     def assign_rank(self, users=0, special_ranks=None):
     def assign_rank(self, users=0, special_ranks=None):
         if not self.criteria or self.special or users == 0:
         if not self.criteria or self.special or users == 0:
             # Rank cant be rolled in
             # Rank cant be rolled in
             return False
             return False
-        
+
         if self.criteria == "0":
         if self.criteria == "0":
             # Just update all fellows
             # Just update all fellows
             User.objects.exclude(rank__in=special_ranks).update(rank=self)
             User.objects.exclude(rank__in=special_ranks).update(rank=self)
@@ -33,14 +33,14 @@ class Rank(models.Model):
             # Count number of users to update
             # Count number of users to update
             if self.criteria[-1] == '%':
             if self.criteria[-1] == '%':
                 criteria = int(self.criteria[0:-1])
                 criteria = int(self.criteria[0:-1])
-                criteria = int(math.ceil(float(users / 100.0)* criteria))
+                criteria = int(math.ceil(float(users / 100.0) * criteria))
             else:
             else:
                 criteria = int(self.criteria)
                 criteria = int(self.criteria)
-            
+
             # Join special ranks
             # Join special ranks
             if special_ranks:
             if special_ranks:
                 special_ranks = ','.join(special_ranks)
                 special_ranks = ','.join(special_ranks)
-            
+
             # Run raw query
             # Run raw query
             cursor = connection.cursor()
             cursor = connection.cursor()
             try:
             try:
@@ -68,7 +68,7 @@ class Rank(models.Model):
                             SET rank_id=%s
                             SET rank_id=%s
                             WHERE id = updateable.id
                             WHERE id = updateable.id
                             RETURNING *''', [self.id, criteria])
                             RETURNING *''', [self.id, criteria])
-                        
+
                 # MySQL, SQLite and Oracle
                 # MySQL, SQLite and Oracle
                 if (settings.DATABASES['default']['ENGINE'] == 'django.db.backends.mysql'
                 if (settings.DATABASES['default']['ENGINE'] == 'django.db.backends.mysql'
                     or settings.DATABASES['default']['ENGINE'] == 'django.db.backends.sqlite3'
                     or settings.DATABASES['default']['ENGINE'] == 'django.db.backends.sqlite3'
@@ -87,4 +87,4 @@ class Rank(models.Model):
             except Exception as e:
             except Exception as e:
                 print 'Error updating users ranking: %s' % e
                 print 'Error updating users ranking: %s' % e
             transaction.commit_unless_managed()
             transaction.commit_unless_managed()
-        return True
+        return True

+ 36 - 36
misago/ranks/views.py

@@ -19,41 +19,41 @@ Views
 class List(ListWidget):
 class List(ListWidget):
     admin = site.get_action('ranks')
     admin = site.get_action('ranks')
     id = 'list'
     id = 'list'
-    columns=(
-             ('rank', _("Rank")),
-             )
+    columns = (
+               ('rank', _("Rank")),
+               )
     table_form_button = _('Reorder Ranks')
     table_form_button = _('Reorder Ranks')
     nothing_checked_message = _('You have to check at least one rank.')
     nothing_checked_message = _('You have to check at least one rank.')
-    actions=(
-             ('delete', _("Delete selected ranks"), _("Are you sure you want to delete selected ranks?")),
-             )
-    
+    actions = (
+               ('delete', _("Delete selected ranks"), _("Are you sure you want to delete selected ranks?")),
+               )
+
     def get_table_form(self, page_items):
     def get_table_form(self, page_items):
         order_form = {}
         order_form = {}
-        
+
         # Build choices list
         # Build choices list
         choices = []
         choices = []
         for i in range(0, len(page_items)):
         for i in range(0, len(page_items)):
            choices.append([str(i), i + 1])
            choices.append([str(i), i + 1])
-        
+
         # Build selectors list
         # Build selectors list
         position = 0
         position = 0
         for item in page_items:
         for item in page_items:
-            order_form['pos_' + str(item.pk)] = forms.ChoiceField(choices=choices,initial=str(position))
+            order_form['pos_' + str(item.pk)] = forms.ChoiceField(choices=choices, initial=str(position))
             position += 1
             position += 1
-        
+
         # Turn dict into object
         # Turn dict into object
         return type('OrderRanksForm', (Form,), order_form)
         return type('OrderRanksForm', (Form,), order_form)
-    
+
     def table_action(self, page_items, cleaned_data):
     def table_action(self, page_items, cleaned_data):
         for item in page_items:
         for item in page_items:
             item.order = cleaned_data['pos_' + str(item.pk)]
             item.order = cleaned_data['pos_' + str(item.pk)]
             item.save(force_update=True)
             item.save(force_update=True)
         return Message(_('Ranks order has been changed'), 'success'), reverse('admin_ranks')
         return Message(_('Ranks order has been changed'), 'success'), reverse('admin_ranks')
-    
+
     def sort_items(self, page_items, sorting_method):
     def sort_items(self, page_items, sorting_method):
         return page_items.order_by('order')
         return page_items.order_by('order')
-    
+
     def get_item_actions(self, item):
     def get_item_actions(self, item):
         return (
         return (
                 self.action('pencil', _("Edit Rank"), reverse('admin_ranks_edit', item)),
                 self.action('pencil', _("Edit Rank"), reverse('admin_ranks_edit', item)),
@@ -68,35 +68,35 @@ class List(ListWidget):
 class New(FormWidget):
 class New(FormWidget):
     admin = site.get_action('ranks')
     admin = site.get_action('ranks')
     id = 'new'
     id = 'new'
-    fallback = 'admin_ranks' 
+    fallback = 'admin_ranks'
     form = RankForm
     form = RankForm
     submit_button = _("Save Rank")
     submit_button = _("Save Rank")
-        
+
     def get_new_url(self, model):
     def get_new_url(self, model):
         return reverse('admin_ranks_new')
         return reverse('admin_ranks_new')
-    
+
     def get_edit_url(self, model):
     def get_edit_url(self, model):
         return reverse('admin_ranks_edit', model)
         return reverse('admin_ranks_edit', model)
-    
+
     def submit_form(self, form, target):
     def submit_form(self, form, target):
         position = 0
         position = 0
         last_rank = Rank.objects.latest('order')
         last_rank = Rank.objects.latest('order')
         new_rank = Rank(
         new_rank = Rank(
-                      name = form.cleaned_data['name'],
-                      name_slug = slugify(form.cleaned_data['name']),
-                      description = form.cleaned_data['description'],
-                      style = form.cleaned_data['style'],
-                      title = form.cleaned_data['title'],
-                      special = form.cleaned_data['special'],
-                      as_tab = form.cleaned_data['as_tab'],
-                      on_index = form.cleaned_data['on_index'],
-                      order = (last_rank.order + 1 if last_rank else 0),
-                      criteria = form.cleaned_data['criteria']
+                      name=form.cleaned_data['name'],
+                      name_slug=slugify(form.cleaned_data['name']),
+                      description=form.cleaned_data['description'],
+                      style=form.cleaned_data['style'],
+                      title=form.cleaned_data['title'],
+                      special=form.cleaned_data['special'],
+                      as_tab=form.cleaned_data['as_tab'],
+                      on_index=form.cleaned_data['on_index'],
+                      order=(last_rank.order + 1 if last_rank else 0),
+                      criteria=form.cleaned_data['criteria']
                      )
                      )
         new_rank.save(force_insert=True)
         new_rank.save(force_insert=True)
         return new_rank, Message(_('New Rank has been created.'), 'success')
         return new_rank, Message(_('New Rank has been created.'), 'success')
-    
-   
+
+
 class Edit(FormWidget):
 class Edit(FormWidget):
     admin = site.get_action('ranks')
     admin = site.get_action('ranks')
     id = 'edit'
     id = 'edit'
@@ -106,13 +106,13 @@ class Edit(FormWidget):
     target_name = 'name'
     target_name = 'name'
     notfound_message = _('Requested Rank could not be found.')
     notfound_message = _('Requested Rank could not be found.')
     submit_fallback = True
     submit_fallback = True
-    
+
     def get_url(self, model):
     def get_url(self, model):
         return reverse('admin_ranks_edit', model)
         return reverse('admin_ranks_edit', model)
-    
+
     def get_edit_url(self, model):
     def get_edit_url(self, model):
         return self.get_url(model)
         return self.get_url(model)
-    
+
     def get_initial_data(self, model):
     def get_initial_data(self, model):
         return {
         return {
                 'name': model.name,
                 'name': model.name,
@@ -124,7 +124,7 @@ class Edit(FormWidget):
                 'on_index': model.on_index,
                 'on_index': model.on_index,
                 'criteria': model.criteria
                 'criteria': model.criteria
                 }
                 }
-    
+
     def submit_form(self, form, target):
     def submit_form(self, form, target):
         target.name = form.cleaned_data['name']
         target.name = form.cleaned_data['name']
         target.name_slug = slugify(form.cleaned_data['name'])
         target.name_slug = slugify(form.cleaned_data['name'])
@@ -144,7 +144,7 @@ class Delete(ButtonWidget):
     id = 'delete'
     id = 'delete'
     fallback = 'admin_ranks'
     fallback = 'admin_ranks'
     notfound_message = _('Requested Rank could not be found.')
     notfound_message = _('Requested Rank could not be found.')
-    
+
     def action(self, target):
     def action(self, target):
         target.delete()
         target.delete()
-        return Message(_('Rank "%(name)s" has been deleted.') % {'name': target.name}, 'success'), False
+        return Message(_('Rank "%(name)s" has been deleted.') % {'name': target.name}, 'success'), False

+ 2 - 2
misago/sessions/forms.py

@@ -13,7 +13,7 @@ class SearchSessionsForm(Form):
                                       ('guest', _("Guests Sessions")),
                                       ('guest', _("Guests Sessions")),
                                       ('crawler', _("Crawler Sessions")),
                                       ('crawler', _("Crawler Sessions")),
                                       ), required=False)
                                       ), required=False)
-    
+
     layout = (
     layout = (
               (
               (
                _("Search Sessions"),
                _("Search Sessions"),
@@ -24,4 +24,4 @@ class SearchSessionsForm(Form):
                 ('type', {'label': _("Session Type")}),
                 ('type', {'label': _("Session Type")}),
                ),
                ),
               ),
               ),
-             )
+             )

+ 1 - 1
misago/sessions/management/commands/clearsessions.py

@@ -11,4 +11,4 @@ class Command(BaseCommand):
     help = 'Clears users sessions'
     help = 'Clears users sessions'
     def handle(self, *args, **options):
     def handle(self, *args, **options):
         Session.objects.filter(last__lte=timezone.now() - timedelta(seconds=settings.SESSION_LIFETIME)).delete()
         Session.objects.filter(last__lte=timezone.now() - timedelta(seconds=settings.SESSION_LIFETIME)).delete()
-        self.stdout.write('Sessions have been cleared.\n')
+        self.stdout.write('Sessions have been cleared.\n')

+ 1 - 1
misago/sessions/management/commands/cleartokens.py

@@ -10,4 +10,4 @@ class Command(BaseCommand):
     help = 'Clears "Remember Me" tokens'
     help = 'Clears "Remember Me" tokens'
     def handle(self, *args, **options):
     def handle(self, *args, **options):
         Token.objects.filter(accessed__lte=timezone.now() - timedelta(days=5)).delete()
         Token.objects.filter(accessed__lte=timezone.now() - timedelta(days=5)).delete()
-        self.stdout.write('Sessions tokens have been cleared.\n')        
+        self.stdout.write('Sessions tokens have been cleared.\n')

+ 3 - 3
misago/sessions/middleware.py

@@ -10,13 +10,13 @@ class SessionMiddleware(object):
             # Human Session
             # Human Session
             request.session = SessionHuman(request)
             request.session = SessionHuman(request)
             request.user = request.session.get_user()
             request.user = request.session.get_user()
-            
+
             if request.user.is_authenticated():
             if request.user.is_authenticated():
                 request.session.set_hidden(request.user.hide_activity > 0)
                 request.session.set_hidden(request.user.hide_activity > 0)
-        
+
     def process_response(self, request, response):
     def process_response(self, request, response):
         try:
         try:
             request.session.save()
             request.session.save()
         except AttributeError:
         except AttributeError:
             pass
             pass
-        return response
+        return response

+ 2 - 2
misago/sessions/models.py

@@ -1,5 +1,5 @@
 from django.db import models
 from django.db import models
-       
+
 class Session(models.Model):
 class Session(models.Model):
     id = models.CharField(max_length=42, primary_key=True)
     id = models.CharField(max_length=42, primary_key=True)
     data = models.TextField(db_column="session_data")
     data = models.TextField(db_column="session_data")
@@ -19,4 +19,4 @@ class Token(models.Model):
     id = models.CharField(max_length=42, primary_key=True)
     id = models.CharField(max_length=42, primary_key=True)
     user = models.ForeignKey('users.User', related_name='signin_tokens')
     user = models.ForeignKey('users.User', related_name='signin_tokens')
     created = models.DateTimeField()
     created = models.DateTimeField()
-    accessed = models.DateTimeField()
+    accessed = models.DateTimeField()

+ 31 - 31
misago/sessions/sessions.py

@@ -13,62 +13,62 @@ from misago.utils import get_random_string
 # Assert models are loaded
 # Assert models are loaded
 if not model_cache.loaded:
 if not model_cache.loaded:
     model_cache.get_models()
     model_cache.get_models()
-    
-    
+
+
 class IncorrectSessionException(Exception):
 class IncorrectSessionException(Exception):
     pass
     pass
 
 
-    
+
 class SessionMisago(SessionBase):
 class SessionMisago(SessionBase):
     """
     """
     Abstract class for sessions to inherit and extend
     Abstract class for sessions to inherit and extend
     """
     """
     def _get_new_session_key(self):
     def _get_new_session_key(self):
         return get_random_string(42)
         return get_random_string(42)
-      
+
     def _get_session(self):
     def _get_session(self):
         try:
         try:
             return self._session_cache
             return self._session_cache
         except AttributeError:
         except AttributeError:
             self._session_cache = self.load()
             self._session_cache = self.load()
         return self._session_cache
         return self._session_cache
-        
+
     def _hash(self, value):
     def _hash(self, value):
         key_salt = "misago.sessions" + self.__class__.__name__
         key_salt = "misago.sessions" + self.__class__.__name__
         return salted_hmac(key_salt, value).hexdigest()
         return salted_hmac(key_salt, value).hexdigest()
-       
+
     def delete(self):
     def delete(self):
         """We use sessions to track onlines so sorry, only sessions cleaner may delete sessions"""
         """We use sessions to track onlines so sorry, only sessions cleaner may delete sessions"""
         pass
         pass
-       
+
     def flush(self):
     def flush(self):
         """We use sessions to track onlines so sorry, only sessions cleaner may delete sessions"""
         """We use sessions to track onlines so sorry, only sessions cleaner may delete sessions"""
         pass
         pass
 
 
     def load(self):
     def load(self):
         return self.decode(force_unicode(self._session_rk.data))
         return self.decode(force_unicode(self._session_rk.data))
-    
+
     def session_expired(self):
     def session_expired(self):
         return False
         return False
-        
+
     def get_hidden(self):
     def get_hidden(self):
         return False
         return False
-    
+
     def set_hidden(self, hidden=False):
     def set_hidden(self, hidden=False):
         pass
         pass
-    
+
     def get_ip(self, request):
     def get_ip(self, request):
         return request.META.get('HTTP_X_FORWARDED_FOR', '') or request.META.get('REMOTE_ADDR')
         return request.META.get('HTTP_X_FORWARDED_FOR', '') or request.META.get('REMOTE_ADDR')
-    
-    def set_user(self, user = None):
+
+    def set_user(self, user=None):
         pass
         pass
-    
+
     def get_ban(self):
     def get_ban(self):
         return False
         return False
-    
+
     def set_ban(self, ban):
     def set_ban(self, ban):
         return False
         return False
-    
+
     def save(self):
     def save(self):
         self._session_rk.data = self.encode(self._get_session())
         self._session_rk.data = self.encode(self._get_session())
         self._session_rk.last = timezone.now()
         self._session_rk.last = timezone.now()
@@ -88,7 +88,7 @@ class SessionCrawler(SessionMisago):
             self._session_key = self._session_rk.id
             self._session_key = self._session_rk.id
         except Session.DoesNotExist:
         except Session.DoesNotExist:
             self.create(request)
             self.create(request)
-            
+
     def create(self, request):
     def create(self, request):
         while True:
         while True:
             try:
             try:
@@ -108,7 +108,7 @@ class SessionCrawler(SessionMisago):
             except CreateError:
             except CreateError:
                 # Key wasn't unique. Try again.
                 # Key wasn't unique. Try again.
                 continue
                 continue
-            
+
     def human_session(self):
     def human_session(self):
         return False
         return False
 
 
@@ -159,14 +159,14 @@ class SessionHuman(SessionMisago):
             except AuthException as e:
             except AuthException as e:
                 # Autolog failed
                 # Autolog failed
                 self.create(request)
                 self.create(request)
-        self.id = self._session_rk.id        
-        
+        self.id = self._session_rk.id
+
         # Make cookie live longer
         # Make cookie live longer
         if request.firewall.admin:
         if request.firewall.admin:
             request.cookie_jar.set('ASID', self._session_rk.id)
             request.cookie_jar.set('ASID', self._session_rk.id)
-        else:   
+        else:
             request.cookie_jar.set('SID', self._session_rk.id)
             request.cookie_jar.set('SID', self._session_rk.id)
-            
+
     def create(self, request, user=None):
     def create(self, request, user=None):
         self._user = user
         self._user = user
         while True:
         while True:
@@ -195,28 +195,28 @@ class SessionHuman(SessionMisago):
             except CreateError:
             except CreateError:
                 # Key wasn't unique. Try again.
                 # Key wasn't unique. Try again.
                 continue
                 continue
-    
+
     def save(self):
     def save(self):
         self._session_rk.user = self._user
         self._session_rk.user = self._user
         self._session_rk.hidden = self.hidden
         self._session_rk.hidden = self.hidden
         self._session_rk.team = self.team
         self._session_rk.team = self.team
         self._session_rk.rank_id = self.rank
         self._session_rk.rank_id = self.rank
         super(SessionHuman, self).save()
         super(SessionHuman, self).save()
-        
+
     def human_session(self):
     def human_session(self):
         return True
         return True
-    
+
     def session_expired(self):
     def session_expired(self):
         return self.expired
         return self.expired
-        
+
     def get_user(self):
     def get_user(self):
         if self._user == None:
         if self._user == None:
             return Guest()
             return Guest()
         return self._user
         return self._user
-    
+
     def set_user(self, user=None):
     def set_user(self, user=None):
         self._user = user
         self._user = user
-    
+
     def sign_out(self, request):
     def sign_out(self, request):
         try:
         try:
             if self._user.is_authenticated():
             if self._user.is_authenticated():
@@ -231,9 +231,9 @@ class SessionHuman(SessionMisago):
                 request.user = Guest()
                 request.user = Guest()
         except AttributeError:
         except AttributeError:
             pass
             pass
-        
+
     def get_hidden(self):
     def get_hidden(self):
         return self.hidden
         return self.hidden
-    
+
     def set_hidden(self, hidden=False):
     def set_hidden(self, hidden=False):
-        self.hidden = hidden
+        self.hidden = hidden

+ 13 - 13
misago/sessions/views.py

@@ -6,21 +6,21 @@ from misago.sessions.forms import SearchSessionsForm
 class List(ListWidget):
 class List(ListWidget):
     admin = site.get_action('online')
     admin = site.get_action('online')
     id = 'list'
     id = 'list'
-    columns=(
-             ('owner', _("Session Owner")),
-             ('start', _("Session Start"), 25),
-             ('last', _("Last Click"), 25),
-             )
+    columns = (
+               ('owner', _("Session Owner")),
+               ('start', _("Session Start"), 25),
+               ('last', _("Last Click"), 25),
+               )
     default_sorting = 'start'
     default_sorting = 'start'
-    sortables={
-               'start': 0,
-               'last': 0,
-              }
+    sortables = {
+                 'start': 0,
+                 'last': 0,
+                }
     hide_actions = True
     hide_actions = True
     pagination = 50
     pagination = 50
     search_form = SearchSessionsForm
     search_form = SearchSessionsForm
     empty_message = _('Looks like nobody is currently online on forums.')
     empty_message = _('Looks like nobody is currently online on forums.')
-    
+
     def set_filters(self, model, filters):
     def set_filters(self, model, filters):
         if 'username' in filters:
         if 'username' in filters:
             model = model.filter(user__username__istartswith=filters['username'])
             model = model.filter(user__username__istartswith=filters['username'])
@@ -37,9 +37,9 @@ class List(ListWidget):
         if filters['type'] == 'crawler':
         if filters['type'] == 'crawler':
             model = model.filter(crawler__isnull=False)
             model = model.filter(crawler__isnull=False)
         return model
         return model
-    
+
     def prefetch_related(self, items):
     def prefetch_related(self, items):
         return items.prefetch_related('user')
         return items.prefetch_related('user')
-    
+
     def select_items(self, items):
     def select_items(self, items):
-        return items.filter(matched=1).filter(admin=0)
+        return items.filter(matched=1).filter(admin=0)

+ 1 - 1
misago/settings/context_processors.py

@@ -1,4 +1,4 @@
 def settings(request):
 def settings(request):
     return {
     return {
         'settings' : request.settings,
         'settings' : request.settings,
-    }
+    }

+ 10 - 10
misago/settings/fixtures.py

@@ -6,7 +6,7 @@ try:
     import cPickle as pickle
     import cPickle as pickle
 except ImportError:
 except ImportError:
     import pickle
     import pickle
-    
+
 settings_fixture = (
 settings_fixture = (
    # Basic options
    # Basic options
    ('basic', {
    ('basic', {
@@ -116,7 +116,7 @@ def update_settings_group_fixture(group, fixture):
             settings[setting.pk] = setting.value
             settings[setting.pk] = setting.value
         model_group.delete()
         model_group.delete()
         load_settings_group_fixture(group, fixture)
         load_settings_group_fixture(group, fixture)
-        
+
         for setting in settings:
         for setting in settings:
             try:
             try:
                 new_setting = Setting.objects.get(pk=setting)
                 new_setting = Setting.objects.get(pk=setting)
@@ -126,21 +126,21 @@ def update_settings_group_fixture(group, fixture):
                 pass
                 pass
     except Group.DoesNotExist:
     except Group.DoesNotExist:
         load_settings_group_fixture(group, fixture)
         load_settings_group_fixture(group, fixture)
-    
+
 
 
 def load_settings_fixture(fixture):
 def load_settings_fixture(fixture):
     for group in fixture:
     for group in fixture:
         load_settings_group_fixture(group[0], group[1])
         load_settings_group_fixture(group[0], group[1])
-    
-    
+
+
 def update_settings_fixture(fixture):
 def update_settings_fixture(fixture):
     for group in fixture:
     for group in fixture:
         update_settings_group_fixture(group[0], group[1])
         update_settings_group_fixture(group[0], group[1])
-    
-    
+
+
 def load_fixtures():
 def load_fixtures():
     load_settings_fixture(settings_fixture)
     load_settings_fixture(settings_fixture)
-    
-    
+
+
 def update_fixtures():
 def update_fixtures():
-    update_settings_fixture(settings_fixture)
+    update_settings_fixture(settings_fixture)

+ 1 - 1
misago/settings/forms.py

@@ -2,4 +2,4 @@ from django import forms
 from misago.forms import Form
 from misago.forms import Form
 
 
 class SearchForm(Form):
 class SearchForm(Form):
-    search_text = forms.CharField(max_length=255)
+    search_text = forms.CharField(max_length=255)

+ 2 - 2
misago/settings/middleware.py

@@ -1,5 +1,5 @@
 from misago.settings.settings import Settings
 from misago.settings.settings import Settings
-    
+
 class SettingsMiddleware(object):
 class SettingsMiddleware(object):
     def process_request(self, request):
     def process_request(self, request):
-        request.settings = Settings()
+        request.settings = Settings()

+ 19 - 20
misago/settings/models.py

@@ -13,8 +13,8 @@ except ImportError:
 class Group(models.Model):
 class Group(models.Model):
     key = models.CharField(max_length=255, unique=True)
     key = models.CharField(max_length=255, unique=True)
     name = models.CharField(max_length=255)
     name = models.CharField(max_length=255)
-    description = models.TextField(null=True,blank=True)
-    
+    description = models.TextField(null=True, blank=True)
+
     def is_active(self, active_group):
     def is_active(self, active_group):
         try:
         try:
             return self.pk == active_group.pk
             return self.pk == active_group.pk
@@ -24,19 +24,19 @@ class Group(models.Model):
 class Setting(models.Model):
 class Setting(models.Model):
     setting = models.CharField(max_length=255, primary_key=True)
     setting = models.CharField(max_length=255, primary_key=True)
     group = models.ForeignKey('Group', to_field='key')
     group = models.ForeignKey('Group', to_field='key')
-    value = models.TextField(null=True,blank=True)
-    value_default = models.TextField(null=True,blank=True)
+    value = models.TextField(null=True, blank=True)
+    value_default = models.TextField(null=True, blank=True)
     type = models.CharField(max_length=255)
     type = models.CharField(max_length=255)
     input = models.CharField(max_length=255)
     input = models.CharField(max_length=255)
-    extra = models.TextField(null=True,blank=True)
+    extra = models.TextField(null=True, blank=True)
     position = models.IntegerField(default=0)
     position = models.IntegerField(default=0)
-    separator = models.CharField(max_length=255,null=True,blank=True)
+    separator = models.CharField(max_length=255, null=True, blank=True)
     name = models.CharField(max_length=255)
     name = models.CharField(max_length=255)
-    description = models.TextField(null=True,blank=True)
-    
+    description = models.TextField(null=True, blank=True)
+
     def get_extra(self):
     def get_extra(self):
         return pickle.loads(base64.decodestring(self.extra))
         return pickle.loads(base64.decodestring(self.extra))
-                
+
     def get_value(self):
     def get_value(self):
         if self.type == 'array':
         if self.type == 'array':
             return self.value.split(',')
             return self.value.split(',')
@@ -47,7 +47,7 @@ class Setting(models.Model):
         if self.type == 'boolean':
         if self.type == 'boolean':
             return self.value == "1"
             return self.value == "1"
         return self.value
         return self.value
-            
+
     def set_value(self, value):
     def set_value(self, value):
         if self.type == 'array':
         if self.type == 'array':
             self.value = ','.join(value)
             self.value = ','.join(value)
@@ -62,10 +62,10 @@ class Setting(models.Model):
         if not self.value and self.value_default:
         if not self.value and self.value_default:
             self.value = self.value_default
             self.value = self.value_default
         return self.value
         return self.value
-    
+
     def get_field(self):
     def get_field(self):
         extra = self.get_extra()
         extra = self.get_extra()
-        
+
         # Set validators
         # Set validators
         field_validators = []
         field_validators = []
         if 'min' in extra:
         if 'min' in extra:
@@ -78,7 +78,7 @@ class Setting(models.Model):
                 field_validators.append(validators.MaxLengthValidator(extra['max']))
                 field_validators.append(validators.MaxLengthValidator(extra['max']))
             if self.type == 'integer' or self.type == 'float':
             if self.type == 'integer' or self.type == 'float':
                 field_validators.append(validators.MaxValueValidator(extra['max']))
                 field_validators.append(validators.MaxValueValidator(extra['max']))
-        
+
         # Yes-no
         # Yes-no
         if self.input == 'yesno':
         if self.input == 'yesno':
             return forms.BooleanField(
             return forms.BooleanField(
@@ -88,7 +88,7 @@ class Setting(models.Model):
                                    required=False,
                                    required=False,
                                    widget=YesNoSwitch,
                                    widget=YesNoSwitch,
                                    )
                                    )
-        
+
         # Multi-list
         # Multi-list
         if self.input == 'mlist':
         if self.input == 'mlist':
             return forms.MultipleChoiceField(
             return forms.MultipleChoiceField(
@@ -100,7 +100,7 @@ class Setting(models.Model):
                                      required=False,
                                      required=False,
                                      choices=extra['choices']
                                      choices=extra['choices']
                                      )
                                      )
-        
+
         # Select or choice
         # Select or choice
         if self.input == 'select' or self.input == 'choice':
         if self.input == 'select' or self.input == 'choice':
             # Timezone list?
             # Timezone list?
@@ -114,8 +114,8 @@ class Setting(models.Model):
                                      validators=field_validators,
                                      validators=field_validators,
                                      required=False,
                                      required=False,
                                      choices=extra['choices']
                                      choices=extra['choices']
-                                     )        
-        
+                                     )
+
         # Textarea
         # Textarea
         if self.input == 'textarea':
         if self.input == 'textarea':
             return forms.CharField(
             return forms.CharField(
@@ -126,14 +126,14 @@ class Setting(models.Model):
                                    required=False,
                                    required=False,
                                    widget=forms.Textarea
                                    widget=forms.Textarea
                                    )
                                    )
-            
+
         # Default input
         # Default input
         default_input = forms.CharField
         default_input = forms.CharField
         if self.type == 'integer':
         if self.type == 'integer':
             default_input = forms.IntegerField
             default_input = forms.IntegerField
         if self.type == 'float':
         if self.type == 'float':
             default_input = forms.FloatField
             default_input = forms.FloatField
-            
+
         # Make text-input
         # Make text-input
         return default_input(
         return default_input(
                              initial=self.get_value(),
                              initial=self.get_value(),
@@ -142,4 +142,3 @@ class Setting(models.Model):
                              validators=field_validators,
                              validators=field_validators,
                              required=False,
                              required=False,
                              )
                              )
-        

+ 7 - 7
misago/settings/settings.py

@@ -7,7 +7,7 @@ class Settings(object):
         self._settings = {}
         self._settings = {}
         self._models = {}
         self._models = {}
         self.refresh()
         self.refresh()
-        
+
     def refresh(self):
     def refresh(self):
         self._models = cache.get('misago.settings')
         self._models = cache.get('misago.settings')
         if not self._models:
         if not self._models:
@@ -22,10 +22,10 @@ class Settings(object):
         else:
         else:
             for i, model in self._models.items():
             for i, model in self._models.items():
                 self._settings[i] = model.get_value()
                 self._settings[i] = model.get_value()
-            
+
     def __getattr__(self, key):
     def __getattr__(self, key):
         return self._settings[key]
         return self._settings[key]
-    
+
     def __contains__(self, key):
     def __contains__(self, key):
         return key in self._settings.keys()
         return key in self._settings.keys()
 
 
@@ -39,16 +39,16 @@ class Settings(object):
             self._settings[key] = value
             self._settings[key] = value
             cache.set('misago.settings', self._models)
             cache.set('misago.settings', self._models)
         return value
         return value
-        
+
     def __delitem__(self, key):
     def __delitem__(self, key):
         pass
         pass
-        
+
     def get(self, key, default=None):
     def get(self, key, default=None):
         try:
         try:
             return self._settings[key]
             return self._settings[key]
         except KeyError:
         except KeyError:
             return None
             return None
-        
+
     def has_key(self, key):
     def has_key(self, key):
         return key in self._settings.keys()
         return key in self._settings.keys()
 
 
@@ -68,4 +68,4 @@ class Settings(object):
         return self._settings.itervalues()
         return self._settings.itervalues()
 
 
     def iteritems(self):
     def iteritems(self):
-        return self._settings.iteritems()
+        return self._settings.iteritems()

+ 8 - 8
misago/settings/views.py

@@ -24,7 +24,7 @@ def settings(request, group_id=None, group_slug=None):
                 break
                 break
         else:
         else:
             return error404(request, _('The requested settings group could not be found.'))
             return error404(request, _('The requested settings group could not be found.'))
-            
+
     # Load selected group settings and turn them into form
     # Load selected group settings and turn them into form
     group_settings = Setting.objects.filter(group=active_group).order_by('position')
     group_settings = Setting.objects.filter(group=active_group).order_by('position')
     last_fieldset = (None, [])
     last_fieldset = (None, [])
@@ -39,7 +39,7 @@ def settings(request, group_id=None, group_slug=None):
         group_form[setting.pk] = setting.get_field()
         group_form[setting.pk] = setting.get_field()
     group_form['layout'].append(last_fieldset)
     group_form['layout'].append(last_fieldset)
     SettingsGroupForm = type('SettingsGroupForm', (Form,), group_form)
     SettingsGroupForm = type('SettingsGroupForm', (Form,), group_form)
-    
+
     #Submit form
     #Submit form
     message = request.messages.get_message('admin_settings')
     message = request.messages.get_message('admin_settings')
     if request.method == 'POST':
     if request.method == 'POST':
@@ -56,7 +56,7 @@ def settings(request, group_id=None, group_slug=None):
             message = Message(form.non_field_errors()[0], 'error')
             message = Message(form.non_field_errors()[0], 'error')
     else:
     else:
         form = SettingsGroupForm(request=request)
         form = SettingsGroupForm(request=request)
-    
+
     # Display settings group form      
     # Display settings group form      
     return request.theme.render_to_response('settings/settings.html',
     return request.theme.render_to_response('settings/settings.html',
                                             {
                                             {
@@ -80,14 +80,14 @@ def settings_search(request):
             if form.is_valid():
             if form.is_valid():
                 # Start search
                 # Start search
                 search_strings = SearchQuery(form.cleaned_data['search_text'])
                 search_strings = SearchQuery(form.cleaned_data['search_text'])
-                
+
                 # Loop over groups using our search query
                 # Loop over groups using our search query
                 for setting in Setting.objects.all().order_by('setting'):
                 for setting in Setting.objects.all().order_by('setting'):
                     if (search_strings.search(_(setting.name))
                     if (search_strings.search(_(setting.name))
                         or (setting.description and search_strings.search(_(setting.description)))
                         or (setting.description and search_strings.search(_(setting.description)))
                         or (setting.value and search_strings.search(setting.value))):
                         or (setting.value and search_strings.search(setting.value))):
                         found_settings.append(setting)
                         found_settings.append(setting)
-                        
+
                 # Scream if nothing could be found
                 # Scream if nothing could be found
                 if found_settings:
                 if found_settings:
                     message = Message(ungettext(
                     message = Message(ungettext(
@@ -96,13 +96,13 @@ def settings_search(request):
                                                 len(found_settings)) % {
                                                 len(found_settings)) % {
                                                     'count': len(found_settings),
                                                     'count': len(found_settings),
                                                 }, 'success')
                                                 }, 'success')
-                else:                    
+                else:
                     raise SearchException(_('No settings that match search criteria has been found.'))
                     raise SearchException(_('No settings that match search criteria has been found.'))
             else:
             else:
                 raise SearchException(_('Search query is empty.'))
                 raise SearchException(_('Search query is empty.'))
         else:
         else:
             raise SearchException(_('Search query is invalid.'))
             raise SearchException(_('Search query is invalid.'))
-    except SearchException as e: 
+    except SearchException as e:
         message = Message(e.message, 'error')
         message = Message(e.message, 'error')
     return request.theme.render_to_response('settings/search_results.html',
     return request.theme.render_to_response('settings/search_results.html',
                                     {
                                     {
@@ -112,4 +112,4 @@ def settings_search(request):
                                     'found_settings': found_settings,
                                     'found_settings': found_settings,
                                     'search_form': FormFields(form),
                                     'search_form': FormFields(form),
                                     },
                                     },
-                                    context_instance=RequestContext(request));
+                                    context_instance=RequestContext(request));

+ 1 - 1
misago/settings_base.py

@@ -29,7 +29,7 @@ USE_TZ = True
 # List of directories that contain Misago locale files
 # List of directories that contain Misago locale files
 # Defautly set Django to look for Misago translations in misago/locale directory
 # Defautly set Django to look for Misago translations in misago/locale directory
 LOCALE_PATHS = (
 LOCALE_PATHS = (
-    ('%slocale%s' % (os.path.dirname( __file__ ) + os.sep, os.sep)),
+    ('%slocale%s' % (os.path.dirname(__file__) + os.sep, os.sep)),
 )
 )
 
 
 # Catch-all e-mail address
 # Catch-all e-mail address

+ 2 - 2
misago/setup/fixtures.py

@@ -16,7 +16,7 @@ def load_app_fixtures(app):
         print 'Could not load fixtures from %s:\n%s' % (app, e)
         print 'Could not load fixtures from %s:\n%s' % (app, e)
         return False
         return False
 
 
-    
+
 def update_app_fixtures(app):
 def update_app_fixtures(app):
     """
     """
     See if application has fixtures module defining update_fixtures function
     See if application has fixtures module defining update_fixtures function
@@ -31,4 +31,4 @@ def update_app_fixtures(app):
         return False
         return False
     except Exception as e:
     except Exception as e:
         print 'Could not update fixtures from %s:\n%s' % (app, e)
         print 'Could not update fixtures from %s:\n%s' % (app, e)
-        return False
+        return False

+ 1 - 1
misago/setup/management/commands/about.py

@@ -35,4 +35,4 @@ class Command(BaseCommand):
         self.stdout.write('\n')
         self.stdout.write('\n')
         self.stdout.write('\nYou should have received a copy of the GNU General Public License along')
         self.stdout.write('\nYou should have received a copy of the GNU General Public License along')
         self.stdout.write('\nalong with this program.  If not, see <http://www.gnu.org/licenses/>.')
         self.stdout.write('\nalong with this program.  If not, see <http://www.gnu.org/licenses/>.')
-        self.stdout.write('\n\n')
+        self.stdout.write('\n\n')

+ 2 - 2
misago/setup/management/commands/loadfixtures.py

@@ -2,7 +2,7 @@ from django.conf import settings
 from django.core.management.base import BaseCommand, CommandError
 from django.core.management.base import BaseCommand, CommandError
 from django.utils import timezone
 from django.utils import timezone
 from misago.setup.fixtures import load_app_fixtures
 from misago.setup.fixtures import load_app_fixtures
-from misago.monitor.models import Item 
+from misago.monitor.models import Item
 from optparse import make_option
 from optparse import make_option
 
 
 class Command(BaseCommand):
 class Command(BaseCommand):
@@ -19,4 +19,4 @@ class Command(BaseCommand):
                 if load_app_fixtures(app):
                 if load_app_fixtures(app):
                     fixtures += 1
                     fixtures += 1
                     print 'Loading fixtures from %s' % app
                     print 'Loading fixtures from %s' % app
-            self.stdout.write('\nLoaded fixtures from %s applications.\n' % fixtures)
+            self.stdout.write('\nLoaded fixtures from %s applications.\n' % fixtures)

+ 1 - 1
misago/setup/management/commands/updatefixtures.py

@@ -15,4 +15,4 @@ class Command(BaseCommand):
             if update_app_fixtures(app):
             if update_app_fixtures(app):
                 fixtures += 1
                 fixtures += 1
                 print 'Updating fixtures from %s' % app
                 print 'Updating fixtures from %s' % app
-        self.stdout.write('\nUpdated fixtures from %s applications.\n' % fixtures)
+        self.stdout.write('\nUpdated fixtures from %s applications.\n' % fixtures)

+ 3 - 3
misago/stats/forms.py

@@ -9,7 +9,7 @@ class GenerateStatisticsForm(Form):
     date_start = forms.DateField(initial=tz.now() - timedelta(days=7))
     date_start = forms.DateField(initial=tz.now() - timedelta(days=7))
     date_end = forms.DateField(initial=tz.now())
     date_end = forms.DateField(initial=tz.now())
     stats_precision = forms.ChoiceField(choices=(('day', _('For each day')), ('week', _('For each week')), ('month', _('For each month')), ('year', _('For each year'))))
     stats_precision = forms.ChoiceField(choices=(('day', _('For each day')), ('week', _('For each week')), ('month', _('For each month')), ('year', _('For each year'))))
-    
+
     layout = (
     layout = (
               (None, (
               (None, (
                         ('provider_model', {'label': _('Report Type'), 'help_text': _('Select statistics provider.')}),
                         ('provider_model', {'label': _('Report Type'), 'help_text': _('Select statistics provider.')}),
@@ -20,9 +20,9 @@ class GenerateStatisticsForm(Form):
                         ('stats_precision', {'label': _('Graph Precision')}),
                         ('stats_precision', {'label': _('Graph Precision')}),
                       )),
                       )),
               )
               )
-    
+
     def __init__(self, *args, **kwargs):
     def __init__(self, *args, **kwargs):
         provider_choices = kwargs.get('provider_choices')
         provider_choices = kwargs.get('provider_choices')
         del kwargs['provider_choices']
         del kwargs['provider_choices']
         super(GenerateStatisticsForm, self).__init__(*args, **kwargs)
         super(GenerateStatisticsForm, self).__init__(*args, **kwargs)
-        self.fields['provider_model'] = forms.ChoiceField(choices=provider_choices)
+        self.fields['provider_model'] = forms.ChoiceField(choices=provider_choices)

+ 15 - 16
misago/stats/views.py

@@ -11,7 +11,6 @@ from misago.messages import Message
 from misago.stats.forms import GenerateStatisticsForm
 from misago.stats.forms import GenerateStatisticsForm
 from misago.views import error404
 from misago.views import error404
 
 
-
 def form(request):
 def form(request):
     """
     """
     Allow admins to generate fancy statistic graphs for different models
     Allow admins to generate fancy statistic graphs for different models
@@ -33,7 +32,7 @@ def form(request):
         """
         """
         return request.theme.render_to_response('stats/not_available.html',
         return request.theme.render_to_response('stats/not_available.html',
                                                 context_instance=RequestContext(request));
                                                 context_instance=RequestContext(request));
-    
+
     message = None
     message = None
     if request.method == 'POST':
     if request.method == 'POST':
         form = GenerateStatisticsForm(request.POST, provider_choices=statistics_providers, request=request)
         form = GenerateStatisticsForm(request.POST, provider_choices=statistics_providers, request=request)
@@ -62,7 +61,7 @@ def form(request):
             message = Message(form.non_field_errors()[0], 'error')
             message = Message(form.non_field_errors()[0], 'error')
     else:
     else:
         form = GenerateStatisticsForm(provider_choices=statistics_providers, request=request)
         form = GenerateStatisticsForm(provider_choices=statistics_providers, request=request)
-    
+
     return request.theme.render_to_response('stats/form.html', {
     return request.theme.render_to_response('stats/form.html', {
                                             'form': FormLayout(form),
                                             'form': FormLayout(form),
                                             'message': message,
                                             'message': message,
@@ -76,12 +75,12 @@ def graph(request, model, date_start, date_end, precision):
     if date_start == date_end:
     if date_start == date_end:
         # Bad dates
         # Bad dates
         raise error404()
         raise error404()
-    
+
     # Turn stuff into datetime's
     # Turn stuff into datetime's
     date_start = datetime.strptime(date_start, '%Y-%m-%d')
     date_start = datetime.strptime(date_start, '%Y-%m-%d')
     date_end = datetime.strptime(date_end, '%Y-%m-%d')
     date_end = datetime.strptime(date_end, '%Y-%m-%d')
-    
-    
+
+
     statistics_providers = []
     statistics_providers = []
     models_map = {}
     models_map = {}
     for model_obj in models.get_models():
     for model_obj in models.get_models():
@@ -96,11 +95,11 @@ def graph(request, model, date_start, date_end, precision):
         # Like before, q.q on lack of models
         # Like before, q.q on lack of models
         return request.theme.render_to_response('stats/not_available.html',
         return request.theme.render_to_response('stats/not_available.html',
                                                 context_instance=RequestContext(request));
                                                 context_instance=RequestContext(request));
-    
+
     if not model in models_map or check_dates(date_start, date_end, precision):
     if not model in models_map or check_dates(date_start, date_end, precision):
         # Bad model name or graph data!
         # Bad model name or graph data!
         raise error404()
         raise error404()
-    
+
     form = GenerateStatisticsForm(
     form = GenerateStatisticsForm(
                                   provider_choices=statistics_providers,
                                   provider_choices=statistics_providers,
                                   request=request,
                                   request=request,
@@ -116,7 +115,7 @@ def graph(request, model, date_start, date_end, precision):
 def check_dates(date_start, date_end, precision):
 def check_dates(date_start, date_end, precision):
     date_diff = date_end - date_start
     date_diff = date_end - date_start
     date_diff = date_diff.seconds + date_diff.days * 86400
     date_diff = date_diff.seconds + date_diff.days * 86400
-    
+
     if ((precision == 'day' and date_diff / 86400 > 60)
     if ((precision == 'day' and date_diff / 86400 > 60)
         or (precision == 'week' and date_diff / 604800 > 60)
         or (precision == 'week' and date_diff / 604800 > 60)
         or (precision == 'month' and date_diff / 2592000 > 60)
         or (precision == 'month' and date_diff / 2592000 > 60)
@@ -128,7 +127,7 @@ def check_dates(date_start, date_end, precision):
           or (precision == 'year' and date_diff / 31536000 < 1)):
           or (precision == 'year' and date_diff / 31536000 < 1)):
         return Message(_('Too few items to display on graph'), 'error')
         return Message(_('Too few items to display on graph'), 'error')
     return None
     return None
-        
+
 
 
 def build_graph(model, date_start, date_end, precision):
 def build_graph(model, date_start, date_end, precision):
     if precision == 'day':
     if precision == 'day':
@@ -143,19 +142,19 @@ def build_graph(model, date_start, date_end, precision):
     if precision == 'year':
     if precision == 'year':
         format = 'Y'
         format = 'Y'
         step = 31536000
         step = 31536000
-    
+
     date_end = timezone.make_aware(date_end, timezone.get_current_timezone())
     date_end = timezone.make_aware(date_end, timezone.get_current_timezone())
     date_start = timezone.make_aware(date_start, timezone.get_current_timezone())
     date_start = timezone.make_aware(date_start, timezone.get_current_timezone())
-    
+
     date_diff = date_end - date_start
     date_diff = date_end - date_start
     date_diff = date_diff.seconds + date_diff.days * 86400
     date_diff = date_diff.seconds + date_diff.days * 86400
     steps = int(math.ceil(float(date_diff / step))) + 1
     steps = int(math.ceil(float(date_diff / step))) + 1
     timeline = [0 for i in range(0, steps)]
     timeline = [0 for i in range(0, steps)]
     for i in range(0, steps):
     for i in range(0, steps):
         step_date = date_end - timedelta(seconds=(i * step));
         step_date = date_end - timedelta(seconds=(i * step));
-        timeline[steps - i - 1] = step_date    
+        timeline[steps - i - 1] = step_date
     stat = {'total': 0, 'max': 0, 'stat': [0 for i in range(0, steps)], 'timeline': timeline, 'start': date_start, 'end': date_end, 'format': format}
     stat = {'total': 0, 'max': 0, 'stat': [0 for i in range(0, steps)], 'timeline': timeline, 'start': date_start, 'end': date_end, 'format': format}
-        
+
     # Loop model items
     # Loop model items
     for item in model.objects.filter_stats(date_start, date_end).iterator():
     for item in model.objects.filter_stats(date_start, date_end).iterator():
         date_diff = date_end - item.get_date()
         date_diff = date_end - item.get_date()
@@ -163,9 +162,9 @@ def build_graph(model, date_start, date_end, precision):
         date_diff = steps - int(math.floor(float(date_diff / step))) - 2
         date_diff = steps - int(math.floor(float(date_diff / step))) - 2
         stat['stat'][date_diff] += 1
         stat['stat'][date_diff] += 1
         stat['total'] += 1
         stat['total'] += 1
-        
+
     # Find max
     # Find max
     for i in stat['stat']:
     for i in stat['stat']:
         if i > stat['max']:
         if i > stat['max']:
             stat['max'] = i
             stat['max'] = i
-    return stat
+    return stat

+ 2 - 2
misago/stopwatch/middleware.py

@@ -4,7 +4,7 @@ from misago.stopwatch import Stopwatch
 class StopwatchMiddleware(object):
 class StopwatchMiddleware(object):
     def process_request(self, request):
     def process_request(self, request):
         request.stopwatch = Stopwatch()
         request.stopwatch = Stopwatch()
-        
+
     def process_response(self, request, response):
     def process_response(self, request, response):
         try:
         try:
             time = request.stopwatch.time()
             time = request.stopwatch.time()
@@ -14,4 +14,4 @@ class StopwatchMiddleware(object):
                 stat_file.close()
                 stat_file.close()
         except AttributeError:
         except AttributeError:
             pass
             pass
-        return response
+        return response

+ 3 - 3
misago/team/views.py

@@ -5,12 +5,12 @@ from misago.admin.widgets import ListWidget
 class List(ListWidget):
 class List(ListWidget):
     admin = site.get_action('team')
     admin = site.get_action('team')
     id = 'list'
     id = 'list'
-    columns=(
+    columns = (
              ('username', _("Team Member")),
              ('username', _("Team Member")),
              )
              )
     default_sorting = 'username_slug'
     default_sorting = 'username_slug'
     hide_actions = True
     hide_actions = True
     pagination = 50
     pagination = 50
-    
+
     def select_items(self, items):
     def select_items(self, items):
-        return items.filter(is_team=1)
+        return items.filter(is_team=1)

+ 5 - 5
misago/template/templatetags/django2jinja.py

@@ -61,7 +61,7 @@ def reldate(val, arg=""):
     now = datetime.now(utc if is_aware(val) else None)
     now = datetime.now(utc if is_aware(val) else None)
     diff = now - val
     diff = now - val
     local = localtime(val)
     local = localtime(val)
-    
+
     # Common situations
     # Common situations
     if diff.days == 0:
     if diff.days == 0:
         return _("Today, %(hour)s") % {'hour': time_format(local, formats['TIME_FORMAT'])}
         return _("Today, %(hour)s") % {'hour': time_format(local, formats['TIME_FORMAT'])}
@@ -71,7 +71,7 @@ def reldate(val, arg=""):
         return _("Tomorrow, %(hour)s") % {'hour': time_format(local, formats['TIME_FORMAT'])}
         return _("Tomorrow, %(hour)s") % {'hour': time_format(local, formats['TIME_FORMAT'])}
     if diff.days > -7 or diff.days < 7:
     if diff.days > -7 or diff.days < 7:
         return _("%(day)s, %(hour)s") % {'day': format(local, 'l'), 'hour': time_format(local, formats['TIME_FORMAT'])}
         return _("%(day)s, %(hour)s") % {'day': format(local, 'l'), 'hour': time_format(local, formats['TIME_FORMAT'])}
-    
+
     # Fallback to custom      
     # Fallback to custom      
     return date(val, arg)
     return date(val, arg)
 
 
@@ -80,7 +80,7 @@ def reltimesince(val, arg=""):
     now = datetime.now(utc if is_aware(val) else None)
     now = datetime.now(utc if is_aware(val) else None)
     diff = now - val
     diff = now - val
     local = localtime(val)
     local = localtime(val)
-    
+
     # Display specific time
     # Display specific time
     if diff.seconds >= 0:
     if diff.seconds >= 0:
         if diff.seconds <= 60:
         if diff.seconds <= 60:
@@ -107,7 +107,7 @@ def reltimesince(val, arg=""):
                     "Hour ago",
                     "Hour ago",
                     "%(hours)s hours ago",
                     "%(hours)s hours ago",
                 hours) % {'hours': hours}
                 hours) % {'hours': hours}
-        
+
     # Fallback to reldate
     # Fallback to reldate
     return reldate(val, arg)
     return reldate(val, arg)
 
 
@@ -123,4 +123,4 @@ def reldate_filter(val, arg=""):
 
 
 @register.filter(name='reltimesince')
 @register.filter(name='reltimesince')
 def reltimesince_filter(val, arg=""):
 def reltimesince_filter(val, arg=""):
-    return reltimesince(val, arg)
+    return reltimesince(val, arg)

+ 1 - 1
misago/themes/middleware.py

@@ -5,4 +5,4 @@ class ThemeMiddleware(object):
     def process_request(self, request):
     def process_request(self, request):
         if not settings.INSTALLED_THEMES:
         if not settings.INSTALLED_THEMES:
             raise ValueError('There are no themes installed!')
             raise ValueError('There are no themes installed!')
-        request.theme = Theme(settings.INSTALLED_THEMES[0])
+        request.theme = Theme(settings.INSTALLED_THEMES[0])

+ 9 - 9
misago/themes/theme.py

@@ -11,20 +11,20 @@ if not hasattr(safestring, '__html__'):
 class Theme(object):
 class Theme(object):
     def __init__(self, theme):
     def __init__(self, theme):
         self.set_theme(theme);
         self.set_theme(theme);
-    
+
     def set_theme(self, theme):
     def set_theme(self, theme):
         if theme not in settings.INSTALLED_THEMES:
         if theme not in settings.INSTALLED_THEMES:
             raise ValueError('"%s" is not correct theme name.' % theme)
             raise ValueError('"%s" is not correct theme name.' % theme)
         if theme[0] == '_':
         if theme[0] == '_':
             raise ValueError('"%s" is a template package, not a theme.' % theme[1:])
             raise ValueError('"%s" is a template package, not a theme.' % theme[1:])
         self._theme = theme;
         self._theme = theme;
-          
+
     def reset_theme(self):
     def reset_theme(self):
         self._theme = settings.INSTALLED_THEMES[0]
         self._theme = settings.INSTALLED_THEMES[0]
-    
+
     def get_theme(self):
     def get_theme(self):
         return self._theme
         return self._theme
-    
+
     def prefix_templates(self, templates):
     def prefix_templates(self, templates):
         if isinstance(templates, str):
         if isinstance(templates, str):
             return ('%s/%s' % (self._theme, templates), templates)
             return ('%s/%s' % (self._theme, templates), templates)
@@ -34,22 +34,22 @@ class Theme(object):
                 prefixed.append('%s/%s' % (self._theme, template))
                 prefixed.append('%s/%s' % (self._theme, template))
             prefixed += templates
             prefixed += templates
             return prefixed
             return prefixed
-    
+
     def render(self, request, *args, **kwargs):
     def render(self, request, *args, **kwargs):
         return render(request, *args, **kwargs)
         return render(request, *args, **kwargs)
-    
+
     def render_to_string(self, templates, *args, **kwargs):
     def render_to_string(self, templates, *args, **kwargs):
         templates = self.prefix_templates(templates)
         templates = self.prefix_templates(templates)
         return render_to_string(templates, *args, **kwargs)
         return render_to_string(templates, *args, **kwargs)
-    
+
     def render_to_response(self, templates, *args, **kwargs):
     def render_to_response(self, templates, *args, **kwargs):
         templates = self.prefix_templates(templates)
         templates = self.prefix_templates(templates)
         return render_to_response(templates, *args, **kwargs)
         return render_to_response(templates, *args, **kwargs)
-        
+
     def get_email_templates(self, template, contex={}):
     def get_email_templates(self, template, contex={}):
             email_type_plain = '_email/%s_plain.html' % template
             email_type_plain = '_email/%s_plain.html' % template
             email_type_html = '_email/%s_html.html' % template
             email_type_html = '_email/%s_html.html' % template
             return (
             return (
                     select_template(('%s/%s' % (self._theme, email_type_plain[1:]), email_type_plain)),
                     select_template(('%s/%s' % (self._theme, email_type_plain[1:]), email_type_plain)),
                     select_template(('%s/%s' % (self._theme, email_type_html[1:]), email_type_html)),
                     select_template(('%s/%s' % (self._theme, email_type_html[1:]), email_type_html)),
-                    )
+                    )

+ 47 - 48
misago/threads/acl.py

@@ -17,43 +17,43 @@ def make_forum_form(request, role, form):
                                                                        ('1', _("Yes, with moderation")),
                                                                        ('1', _("Yes, with moderation")),
                                                                        ('2', _("Yes")),
                                                                        ('2', _("Yes")),
                                                                        ))
                                                                        ))
-    form.base_fields['can_edit_own_threads'] = forms.BooleanField(widget=YesNoSwitch,initial=False,required=False)
-    form.base_fields['can_soft_delete_own_threads'] = forms.BooleanField(widget=YesNoSwitch,initial=False,required=False)
+    form.base_fields['can_edit_own_threads'] = forms.BooleanField(widget=YesNoSwitch, initial=False, required=False)
+    form.base_fields['can_soft_delete_own_threads'] = forms.BooleanField(widget=YesNoSwitch, initial=False, required=False)
     form.base_fields['can_write_posts'] = forms.ChoiceField(choices=(
     form.base_fields['can_write_posts'] = forms.ChoiceField(choices=(
                                                                      ('0', _("No")),
                                                                      ('0', _("No")),
                                                                      ('1', _("Yes, with moderation")),
                                                                      ('1', _("Yes, with moderation")),
                                                                      ('2', _("Yes")),
                                                                      ('2', _("Yes")),
                                                                      ))
                                                                      ))
-    form.base_fields['can_edit_own_posts'] = forms.BooleanField(widget=YesNoSwitch,initial=False,required=False)
-    form.base_fields['can_soft_delete_own_posts'] = forms.BooleanField(widget=YesNoSwitch,initial=False,required=False)
-    form.base_fields['can_upvote_posts'] = forms.BooleanField(widget=YesNoSwitch,initial=False,required=False)
-    form.base_fields['can_downvote_posts'] = forms.BooleanField(widget=YesNoSwitch,initial=False,required=False)
+    form.base_fields['can_edit_own_posts'] = forms.BooleanField(widget=YesNoSwitch, initial=False, required=False)
+    form.base_fields['can_soft_delete_own_posts'] = forms.BooleanField(widget=YesNoSwitch, initial=False, required=False)
+    form.base_fields['can_upvote_posts'] = forms.BooleanField(widget=YesNoSwitch, initial=False, required=False)
+    form.base_fields['can_downvote_posts'] = forms.BooleanField(widget=YesNoSwitch, initial=False, required=False)
     form.base_fields['can_see_posts_scores'] = forms.ChoiceField(choices=(
     form.base_fields['can_see_posts_scores'] = forms.ChoiceField(choices=(
                                                                           ('0', _("No")),
                                                                           ('0', _("No")),
                                                                           ('1', _("Yes, final score")),
                                                                           ('1', _("Yes, final score")),
                                                                           ('2', _("Yes, both up and down-votes")),
                                                                           ('2', _("Yes, both up and down-votes")),
                                                                           ))
                                                                           ))
-    form.base_fields['can_see_votes'] = forms.BooleanField(widget=YesNoSwitch,initial=False,required=False)
-    form.base_fields['can_make_polls'] = forms.BooleanField(widget=YesNoSwitch,initial=False,required=False)
-    form.base_fields['can_vote_in_polls'] = forms.BooleanField(widget=YesNoSwitch,initial=False,required=False)
-    form.base_fields['can_see_poll_votes'] = forms.BooleanField(widget=YesNoSwitch,initial=False,required=False)
-    form.base_fields['can_see_attachments'] = forms.BooleanField(widget=YesNoSwitch,initial=False,required=False)
-    form.base_fields['can_upload_attachments'] = forms.BooleanField(widget=YesNoSwitch,initial=False,required=False)
-    form.base_fields['can_download_attachments'] = forms.BooleanField(widget=YesNoSwitch,initial=False,required=False)
-    form.base_fields['attachment_size'] = forms.IntegerField(min_value=0,initial=100)
-    form.base_fields['attachment_limit'] = forms.IntegerField(min_value=0,initial=3)
-    form.base_fields['can_approve'] = forms.BooleanField(widget=YesNoSwitch,initial=False,required=False)
-    form.base_fields['can_edit_labels'] = forms.BooleanField(widget=YesNoSwitch,initial=False,required=False)
-    form.base_fields['can_see_changelog'] = forms.BooleanField(widget=YesNoSwitch,initial=False,required=False)
+    form.base_fields['can_see_votes'] = forms.BooleanField(widget=YesNoSwitch, initial=False, required=False)
+    form.base_fields['can_make_polls'] = forms.BooleanField(widget=YesNoSwitch, initial=False, required=False)
+    form.base_fields['can_vote_in_polls'] = forms.BooleanField(widget=YesNoSwitch, initial=False, required=False)
+    form.base_fields['can_see_poll_votes'] = forms.BooleanField(widget=YesNoSwitch, initial=False, required=False)
+    form.base_fields['can_see_attachments'] = forms.BooleanField(widget=YesNoSwitch, initial=False, required=False)
+    form.base_fields['can_upload_attachments'] = forms.BooleanField(widget=YesNoSwitch, initial=False, required=False)
+    form.base_fields['can_download_attachments'] = forms.BooleanField(widget=YesNoSwitch, initial=False, required=False)
+    form.base_fields['attachment_size'] = forms.IntegerField(min_value=0, initial=100)
+    form.base_fields['attachment_limit'] = forms.IntegerField(min_value=0, initial=3)
+    form.base_fields['can_approve'] = forms.BooleanField(widget=YesNoSwitch, initial=False, required=False)
+    form.base_fields['can_edit_labels'] = forms.BooleanField(widget=YesNoSwitch, initial=False, required=False)
+    form.base_fields['can_see_changelog'] = forms.BooleanField(widget=YesNoSwitch, initial=False, required=False)
     form.base_fields['can_pin_threads'] = forms.ChoiceField(choices=(
     form.base_fields['can_pin_threads'] = forms.ChoiceField(choices=(
                                                                      ('0', _("No")),
                                                                      ('0', _("No")),
                                                                      ('1', _("Yes, to stickies")),
                                                                      ('1', _("Yes, to stickies")),
                                                                      ('2', _("Yes, to annoucements")),
                                                                      ('2', _("Yes, to annoucements")),
                                                                      ))
                                                                      ))
-    form.base_fields['can_edit_threads_posts'] = forms.BooleanField(widget=YesNoSwitch,initial=False,required=False)
-    form.base_fields['can_move_threads_posts'] = forms.BooleanField(widget=YesNoSwitch,initial=False,required=False)
-    form.base_fields['can_close_threads'] = forms.BooleanField(widget=YesNoSwitch,initial=False,required=False)
-    form.base_fields['can_protect_posts'] = forms.BooleanField(widget=YesNoSwitch,initial=False,required=False)
+    form.base_fields['can_edit_threads_posts'] = forms.BooleanField(widget=YesNoSwitch, initial=False, required=False)
+    form.base_fields['can_move_threads_posts'] = forms.BooleanField(widget=YesNoSwitch, initial=False, required=False)
+    form.base_fields['can_close_threads'] = forms.BooleanField(widget=YesNoSwitch, initial=False, required=False)
+    form.base_fields['can_protect_posts'] = forms.BooleanField(widget=YesNoSwitch, initial=False, required=False)
     form.base_fields['can_delete_threads'] = forms.ChoiceField(choices=(
     form.base_fields['can_delete_threads'] = forms.ChoiceField(choices=(
                                                                         ('0', _("No")),
                                                                         ('0', _("No")),
                                                                         ('1', _("Yes, soft-delete")),
                                                                         ('1', _("Yes, soft-delete")),
@@ -69,8 +69,8 @@ def make_forum_form(request, role, form):
                                                                       ('1', _("Yes, soft-delete")),
                                                                       ('1', _("Yes, soft-delete")),
                                                                       ('2', _("Yes, hard-delete")),
                                                                       ('2', _("Yes, hard-delete")),
                                                                       ))
                                                                       ))
-    form.base_fields['can_delete_attachments'] = forms.BooleanField(widget=YesNoSwitch,initial=False,required=False)
-    
+    form.base_fields['can_delete_attachments'] = forms.BooleanField(widget=YesNoSwitch, initial=False, required=False)
+
     form.layout.append((
     form.layout.append((
                         _("Threads"),
                         _("Threads"),
                         (
                         (
@@ -144,7 +144,7 @@ class ThreadsACL(BaseACL):
                 return self.acl[forum]
                 return self.acl[forum]
         except KeyError:
         except KeyError:
             return {}
             return {}
-    
+
     def allow_thread_view(self, user, thread):
     def allow_thread_view(self, user, thread):
         try:
         try:
             forum_role = self.acl[thread.forum_id]
             forum_role = self.acl[thread.forum_id]
@@ -158,21 +158,21 @@ class ThreadsACL(BaseACL):
                 raise ACLError404()
                 raise ACLError404()
         except KeyError:
         except KeyError:
             raise ACLError403(_("You don't have permission to read threads in this forum."))
             raise ACLError403(_("You don't have permission to read threads in this forum."))
-    
+
     def allow_post_view(self, user, thread, post):
     def allow_post_view(self, user, thread, post):
         forum_role = self.acl[thread.forum_id]
         forum_role = self.acl[thread.forum_id]
         if post.moderated and not (forum_role['can_approve'] or (user.is_authenticated() and user == post.user)):
         if post.moderated and not (forum_role['can_approve'] or (user.is_authenticated() and user == post.user)):
             raise ACLError404()
             raise ACLError404()
         if post.deleted and not (forum_role['can_delete_posts'] or (user.is_authenticated() and user == post.user)):
         if post.deleted and not (forum_role['can_delete_posts'] or (user.is_authenticated() and user == post.user)):
             raise ACLError404()
             raise ACLError404()
-    
+
     def get_readable_forums(self, acl):
     def get_readable_forums(self, acl):
         readable = []
         readable = []
         for forum in self.acl:
         for forum in self.acl:
             if acl.forums.can_browse(forum) and self.acl[forum]['can_read_threads']:
             if acl.forums.can_browse(forum) and self.acl[forum]['can_read_threads']:
                 readable.append(forum)
                 readable.append(forum)
         return readable
         return readable
-    
+
     def filter_threads(self, request, forum, queryset):
     def filter_threads(self, request, forum, queryset):
         try:
         try:
             forum_role = self.acl[forum.pk]
             forum_role = self.acl[forum.pk]
@@ -188,7 +188,7 @@ class ThreadsACL(BaseACL):
         except KeyError:
         except KeyError:
             return False
             return False
         return queryset
         return queryset
-    
+
     def filter_posts(self, request, thread, queryset):
     def filter_posts(self, request, thread, queryset):
         try:
         try:
             forum_role = self.acl[thread.forum.pk]
             forum_role = self.acl[thread.forum.pk]
@@ -200,7 +200,7 @@ class ThreadsACL(BaseACL):
         except KeyError:
         except KeyError:
             return False
             return False
         return queryset
         return queryset
-    
+
     def can_start_threads(self, forum):
     def can_start_threads(self, forum):
         try:
         try:
             forum_role = self.acl[forum.pk]
             forum_role = self.acl[forum.pk]
@@ -211,7 +211,7 @@ class ThreadsACL(BaseACL):
             return True
             return True
         except KeyError:
         except KeyError:
             return False
             return False
-    
+
     def allow_new_threads(self, forum):
     def allow_new_threads(self, forum):
         try:
         try:
             forum_role = self.acl[forum.pk]
             forum_role = self.acl[forum.pk]
@@ -221,7 +221,7 @@ class ThreadsACL(BaseACL):
                 raise ACLError403(_("This forum is closed, you can't start new threads in it."))
                 raise ACLError403(_("This forum is closed, you can't start new threads in it."))
         except KeyError:
         except KeyError:
             raise ACLError403(_("You don't have permission to start new threads in this forum."))
             raise ACLError403(_("You don't have permission to start new threads in this forum."))
-    
+
     def can_edit_thread(self, user, forum, thread, post):
     def can_edit_thread(self, user, forum, thread, post):
         try:
         try:
             forum_role = self.acl[thread.forum_id]
             forum_role = self.acl[thread.forum_id]
@@ -234,7 +234,7 @@ class ThreadsACL(BaseACL):
             return False
             return False
         except KeyError:
         except KeyError:
             return False
             return False
-    
+
     def allow_thread_edit(self, user, forum, thread, post):
     def allow_thread_edit(self, user, forum, thread, post):
         try:
         try:
             forum_role = self.acl[thread.forum_id]
             forum_role = self.acl[thread.forum_id]
@@ -277,7 +277,7 @@ class ThreadsACL(BaseACL):
                     raise ACLError403(_("You can't write replies in closed threads."))
                     raise ACLError403(_("You can't write replies in closed threads."))
         except KeyError:
         except KeyError:
             raise ACLError403(_("You don't have permission to write replies in this forum."))
             raise ACLError403(_("You don't have permission to write replies in this forum."))
-    
+
     def can_edit_reply(self, user, forum, thread, post):
     def can_edit_reply(self, user, forum, thread, post):
         try:
         try:
             forum_role = self.acl[thread.forum_id]
             forum_role = self.acl[thread.forum_id]
@@ -290,7 +290,7 @@ class ThreadsACL(BaseACL):
             return False
             return False
         except KeyError:
         except KeyError:
             return False
             return False
-    
+
     def allow_reply_edit(self, user, forum, thread, post):
     def allow_reply_edit(self, user, forum, thread, post):
         try:
         try:
             forum_role = self.acl[thread.forum_id]
             forum_role = self.acl[thread.forum_id]
@@ -309,14 +309,14 @@ class ThreadsACL(BaseACL):
                     raise ACLError403(_("This reply is protected, you cannot edit it."))
                     raise ACLError403(_("This reply is protected, you cannot edit it."))
         except KeyError:
         except KeyError:
             raise ACLError403(_("You don't have permission to edit replies in this forum."))
             raise ACLError403(_("You don't have permission to edit replies in this forum."))
-    
+
     def can_see_changelog(self, user, forum, post):
     def can_see_changelog(self, user, forum, post):
         try:
         try:
             forum_role = self.acl[forum.pk]
             forum_role = self.acl[forum.pk]
             return forum_role['can_see_changelog'] or user.pk == post.user_id
             return forum_role['can_see_changelog'] or user.pk == post.user_id
         except KeyError:
         except KeyError:
             return False
             return False
-    
+
     def allow_changelog_view(self, user, forum, post):
     def allow_changelog_view(self, user, forum, post):
         try:
         try:
             forum_role = self.acl[forum.pk]
             forum_role = self.acl[forum.pk]
@@ -325,7 +325,7 @@ class ThreadsACL(BaseACL):
                 raise ACLError403(_("You don't have permission to see history of changes made to this post."))
                 raise ACLError403(_("You don't have permission to see history of changes made to this post."))
         except KeyError:
         except KeyError:
             raise ACLError403(_("You don't have permission to see history of changes made to this post."))
             raise ACLError403(_("You don't have permission to see history of changes made to this post."))
-        
+
     def can_make_revert(self, forum, thread):
     def can_make_revert(self, forum, thread):
         try:
         try:
             forum_role = self.acl[forum.pk]
             forum_role = self.acl[forum.pk]
@@ -334,7 +334,7 @@ class ThreadsACL(BaseACL):
             return forum_role['can_edit_threads_posts']
             return forum_role['can_edit_threads_posts']
         except KeyError:
         except KeyError:
             return False
             return False
-    
+
     def allow_revert(self, forum, thread):
     def allow_revert(self, forum, thread):
         try:
         try:
             forum_role = self.acl[forum.pk]
             forum_role = self.acl[forum.pk]
@@ -347,7 +347,7 @@ class ThreadsACL(BaseACL):
                 raise ACLError403(_("You don't have permission to make reverts in this forum."))
                 raise ACLError403(_("You don't have permission to make reverts in this forum."))
         except KeyError:
         except KeyError:
             raise ACLError403(_("You don't have permission to make reverts in this forum."))
             raise ACLError403(_("You don't have permission to make reverts in this forum."))
-            
+
     def can_mod_threads(self, forum):
     def can_mod_threads(self, forum):
         try:
         try:
             forum_role = self.acl[forum.pk]
             forum_role = self.acl[forum.pk]
@@ -360,7 +360,7 @@ class ThreadsACL(BaseACL):
                     )
                     )
         except KeyError:
         except KeyError:
             return False
             return False
-        
+
     def can_mod_posts(self, thread):
     def can_mod_posts(self, thread):
         try:
         try:
             forum_role = self.acl[thread.forum.pk]
             forum_role = self.acl[thread.forum.pk]
@@ -373,14 +373,14 @@ class ThreadsACL(BaseACL):
                     )
                     )
         except KeyError:
         except KeyError:
             return False
             return False
-    
+
     def can_approve(self, forum):
     def can_approve(self, forum):
         try:
         try:
             forum_role = self.acl[forum.pk]
             forum_role = self.acl[forum.pk]
             return forum_role['can_approve']
             return forum_role['can_approve']
         except KeyError:
         except KeyError:
             return False
             return False
-        
+
     def can_protect(self, forum):
     def can_protect(self, forum):
         try:
         try:
             forum_role = self.acl[forum.pk]
             forum_role = self.acl[forum.pk]
@@ -402,7 +402,7 @@ class ThreadsACL(BaseACL):
             return False
             return False
         except KeyError:
         except KeyError:
             return False
             return False
-        
+
     def allow_delete_thread(self, user, forum, thread, post, delete=False):
     def allow_delete_thread(self, user, forum, thread, post, delete=False):
         try:
         try:
             forum_role = self.acl[forum.pk]
             forum_role = self.acl[forum.pk]
@@ -455,21 +455,21 @@ class ThreadsACL(BaseACL):
                 raise ACLError403(_("This post is already deleted."))
                 raise ACLError403(_("This post is already deleted."))
         except KeyError:
         except KeyError:
             raise ACLError403(_("You don't have permission to delete this post."))
             raise ACLError403(_("You don't have permission to delete this post."))
-    
+
     def can_see_deleted_threads(self, forum):
     def can_see_deleted_threads(self, forum):
         try:
         try:
             forum_role = self.acl[forum.pk]
             forum_role = self.acl[forum.pk]
             return forum_role['can_delete_threads']
             return forum_role['can_delete_threads']
         except KeyError:
         except KeyError:
             raise false
             raise false
-        
+
     def can_see_deleted_posts(self, forum):
     def can_see_deleted_posts(self, forum):
         try:
         try:
             forum_role = self.acl[forum.pk]
             forum_role = self.acl[forum.pk]
             return forum_role['can_delete_posts']
             return forum_role['can_delete_posts']
         except KeyError:
         except KeyError:
             raise false
             raise false
-        
+
     def allow_deleted_post_view(self, forum):
     def allow_deleted_post_view(self, forum):
         try:
         try:
             forum_role = self.acl[forum.pk]
             forum_role = self.acl[forum.pk]
@@ -530,4 +530,3 @@ def build_forums(acl, perms, forums, forum_roles):
             except KeyError:
             except KeyError:
                 pass
                 pass
         acl.threads.acl[forum.pk] = forum_role
         acl.threads.acl[forum.pk] = forum_role
-            

+ 4 - 4
misago/threads/fixtures.py

@@ -44,7 +44,7 @@ settings_fixtures = (
                 'value':        10,
                 'value':        10,
                 'type':         "integer",
                 'type':         "integer",
                 'input':        "text",
                 'input':        "text",
-                'extra':        {'min': 0,'max': 30},
+                'extra':        {'min': 0, 'max': 30},
                 'separator':    _("Thread Popularity Ranking"),
                 'separator':    _("Thread Popularity Ranking"),
                 'name':         _('Threads on "Popular Threads" list'),
                 'name':         _('Threads on "Popular Threads" list'),
                 'description':  _('Enter number of threads to be displayed on "Popular Threads" list on board index or 0 to don\'t display any threads there.'),
                 'description':  _('Enter number of threads to be displayed on "Popular Threads" list on board index or 0 to don\'t display any threads there.'),
@@ -121,7 +121,7 @@ settings_fixtures = (
 
 
 def load_fixtures():
 def load_fixtures():
     load_settings_fixture(settings_fixtures)
     load_settings_fixture(settings_fixtures)
-    
-    
+
+
 def update_fixtures():
 def update_fixtures():
-    update_settings_fixture(settings_fixtures)
+    update_settings_fixture(settings_fixtures)

+ 25 - 25
misago/threads/forms.py

@@ -34,7 +34,7 @@ class PostForm(Form, ThreadNameMixin):
     def __init__(self, data=None, file=None, request=None, mode=None, *args, **kwargs):
     def __init__(self, data=None, file=None, request=None, mode=None, *args, **kwargs):
         self.mode = mode
         self.mode = mode
         super(PostForm, self).__init__(data, file, request=request, *args, **kwargs)
         super(PostForm, self).__init__(data, file, request=request, *args, **kwargs)
-    
+
     def finalize_form(self):
     def finalize_form(self):
         self.layout = [
         self.layout = [
                        [
                        [
@@ -46,12 +46,12 @@ class PostForm(Form, ThreadNameMixin):
                          ],
                          ],
                         ],
                         ],
                        ]
                        ]
-    
+
         if self.mode in ['edit_thread', 'edit_post']:
         if self.mode in ['edit_thread', 'edit_post']:
-            self.fields['edit_reason'] = forms.CharField(max_length=255,required=False,help_text=_("Optional reason for changing this post."))
+            self.fields['edit_reason'] = forms.CharField(max_length=255, required=False, help_text=_("Optional reason for changing this post."))
         else:
         else:
             del self.layout[0][1][1]
             del self.layout[0][1][1]
-            
+
         if self.mode not in ['edit_thread', 'new_thread']:
         if self.mode not in ['edit_thread', 'new_thread']:
             del self.layout[0][1][0]
             del self.layout[0][1][0]
         else:
         else:
@@ -61,7 +61,7 @@ class PostForm(Form, ThreadNameMixin):
                                                                                         _("Thread name must contain at least one alpha-numeric character."),
                                                                                         _("Thread name must contain at least one alpha-numeric character."),
                                                                                         _("Thread name is too long. Try shorter name.")
                                                                                         _("Thread name is too long. Try shorter name.")
                                                                                         )])
                                                                                         )])
-    
+
     def clean_post(self):
     def clean_post(self):
         data = self.cleaned_data['post']
         data = self.cleaned_data['post']
         if len(data) < self.request.settings['post_length_min']:
         if len(data) < self.request.settings['post_length_min']:
@@ -71,10 +71,10 @@ class PostForm(Form, ThreadNameMixin):
                                                   self.request.settings['post_length_min']
                                                   self.request.settings['post_length_min']
                                                   ) % {'count': self.request.settings['post_length_min']})
                                                   ) % {'count': self.request.settings['post_length_min']})
         return data
         return data
-        
-        
 
 
-class SplitThreadForm(Form, ThreadNameMixin):        
+
+
+class SplitThreadForm(Form, ThreadNameMixin):
     def finalize_form(self):
     def finalize_form(self):
         self.layout = [
         self.layout = [
                        [
                        [
@@ -85,15 +85,15 @@ class SplitThreadForm(Form, ThreadNameMixin):
                          ],
                          ],
                         ],
                         ],
                        ]
                        ]
-    
+
         self.fields['thread_name'] = forms.CharField(
         self.fields['thread_name'] = forms.CharField(
                                                      max_length=self.request.settings['thread_name_max'],
                                                      max_length=self.request.settings['thread_name_max'],
                                                      validators=[validate_sluggable(
                                                      validators=[validate_sluggable(
                                                                                     _("Thread name must contain at least one alpha-numeric character."),
                                                                                     _("Thread name must contain at least one alpha-numeric character."),
                                                                                     _("Thread name is too long. Try shorter name.")
                                                                                     _("Thread name is too long. Try shorter name.")
                                                                                     )])
                                                                                     )])
-        self.fields['thread_forum'] = TreeNodeChoiceField(queryset=Forum.tree.get(token='root').get_descendants().filter(pk__in=self.request.acl.forums.acl['can_browse']),level_indicator=u'- - ')
-            
+        self.fields['thread_forum'] = TreeNodeChoiceField(queryset=Forum.tree.get(token='root').get_descendants().filter(pk__in=self.request.acl.forums.acl['can_browse']), level_indicator=u'- - ')
+
     def clean_thread_forum(self):
     def clean_thread_forum(self):
         new_forum = self.cleaned_data['thread_forum']
         new_forum = self.cleaned_data['thread_forum']
         # Assert its forum and its not current forum
         # Assert its forum and its not current forum
@@ -102,13 +102,13 @@ class SplitThreadForm(Form, ThreadNameMixin):
         return new_forum
         return new_forum
 
 
 
 
-class MovePostsForm(Form, ThreadNameMixin):  
+class MovePostsForm(Form, ThreadNameMixin):
     error_source = 'thread_url'
     error_source = 'thread_url'
 
 
     def __init__(self, data=None, request=None, thread=None, *args, **kwargs):
     def __init__(self, data=None, request=None, thread=None, *args, **kwargs):
         self.thread = thread
         self.thread = thread
         super(MovePostsForm, self).__init__(data, request=request, *args, **kwargs)
         super(MovePostsForm, self).__init__(data, request=request, *args, **kwargs)
-          
+
     def finalize_form(self):
     def finalize_form(self):
         self.layout = [
         self.layout = [
                        [
                        [
@@ -118,9 +118,9 @@ class MovePostsForm(Form, ThreadNameMixin):
                          ],
                          ],
                         ],
                         ],
                        ]
                        ]
-    
+
         self.fields['thread_url'] = forms.CharField()
         self.fields['thread_url'] = forms.CharField()
-            
+
     def clean_thread_url(self):
     def clean_thread_url(self):
         from django.core.urlresolvers import resolve
         from django.core.urlresolvers import resolve
         from django.http import Http404
         from django.http import Http404
@@ -145,13 +145,13 @@ class QuickReplyForm(Form):
 
 
 class MoveThreadsForm(Form):
 class MoveThreadsForm(Form):
     error_source = 'new_forum'
     error_source = 'new_forum'
-    
+
     def __init__(self, data=None, request=None, forum=None, *args, **kwargs):
     def __init__(self, data=None, request=None, forum=None, *args, **kwargs):
         self.forum = forum
         self.forum = forum
         super(MoveThreadsForm, self).__init__(data, request=request, *args, **kwargs)
         super(MoveThreadsForm, self).__init__(data, request=request, *args, **kwargs)
-    
+
     def finalize_form(self):
     def finalize_form(self):
-        self.fields['new_forum'] = TreeNodeChoiceField(queryset=Forum.tree.get(token='root').get_descendants().filter(pk__in=self.request.acl.forums.acl['can_browse']),level_indicator=u'- - ')
+        self.fields['new_forum'] = TreeNodeChoiceField(queryset=Forum.tree.get(token='root').get_descendants().filter(pk__in=self.request.acl.forums.acl['can_browse']), level_indicator=u'- - ')
         self.layout = [
         self.layout = [
                        [
                        [
                         _("Thread Options"),
                         _("Thread Options"),
@@ -160,7 +160,7 @@ class MoveThreadsForm(Form):
                          ],
                          ],
                         ],
                         ],
                        ]
                        ]
-            
+
     def clean_new_forum(self):
     def clean_new_forum(self):
         new_forum = self.cleaned_data['new_forum']
         new_forum = self.cleaned_data['new_forum']
         # Assert its forum and its not current forum
         # Assert its forum and its not current forum
@@ -175,7 +175,7 @@ class MergeThreadsForm(Form, ThreadNameMixin):
     def __init__(self, data=None, request=None, threads=[], *args, **kwargs):
     def __init__(self, data=None, request=None, threads=[], *args, **kwargs):
         self.threads = threads
         self.threads = threads
         super(MergeThreadsForm, self).__init__(data, request=request, *args, **kwargs)
         super(MergeThreadsForm, self).__init__(data, request=request, *args, **kwargs)
-    
+
     def finalize_form(self):
     def finalize_form(self):
         self.fields['thread_name'] = forms.CharField(
         self.fields['thread_name'] = forms.CharField(
                                                      max_length=self.request.settings['thread_name_max'],
                                                      max_length=self.request.settings['thread_name_max'],
@@ -197,15 +197,15 @@ class MergeThreadsForm(Form, ThreadNameMixin):
                          ],
                          ],
                         ],
                         ],
                        ]
                        ]
-        
+
         choices = []
         choices = []
         for i, thread in enumerate(self.threads):
         for i, thread in enumerate(self.threads):
             choices.append((str(i), i + 1))
             choices.append((str(i), i + 1))
         for i, thread in enumerate(self.threads):
         for i, thread in enumerate(self.threads):
-            self.fields['thread_%s' % thread.pk] = forms.ChoiceField(choices=choices,initial=str(i))
+            self.fields['thread_%s' % thread.pk] = forms.ChoiceField(choices=choices, initial=str(i))
             self.layout[1][1].append(('thread_%s' % thread.pk, {'label': thread.name}))
             self.layout[1][1].append(('thread_%s' % thread.pk, {'label': thread.name}))
-            
-    def clean(self):        
+
+    def clean(self):
         cleaned_data = super(MergeThreadsForm, self).clean()
         cleaned_data = super(MergeThreadsForm, self).clean()
         self.merge_order = {}
         self.merge_order = {}
         lookback = []
         lookback = []
@@ -215,4 +215,4 @@ class MergeThreadsForm(Form, ThreadNameMixin):
                 raise forms.ValidationError(_("One or more threads have same position in merge order."))
                 raise forms.ValidationError(_("One or more threads have same position in merge order."))
             lookback.append(order)
             lookback.append(order)
             self.merge_order[order] = thread
             self.merge_order[order] = thread
-        return cleaned_data
+        return cleaned_data

+ 1 - 1
misago/threads/management/commands/updatethreadranking.py

@@ -15,4 +15,4 @@ class Command(BaseCommand):
             Thread.objects.all().update(score=F('score') * inflation)
             Thread.objects.all().update(score=F('score') * inflation)
             self.stdout.write('Thread ranking has been updated.\n')
             self.stdout.write('Thread ranking has been updated.\n')
         else:
         else:
-            self.stdout.write('Thread ranking inflation is disabled.\n')
+            self.stdout.write('Thread ranking inflation is disabled.\n')

+ 37 - 38
misago/threads/models.py

@@ -10,7 +10,7 @@ class ThreadManager(models.Manager):
 
 
 class Thread(models.Model):
 class Thread(models.Model):
     forum = models.ForeignKey('forums.Forum')
     forum = models.ForeignKey('forums.Forum')
-    weight = models.PositiveIntegerField(default=0,db_index=True)
+    weight = models.PositiveIntegerField(default=0, db_index=True)
     type = models.PositiveIntegerField(default=0)
     type = models.PositiveIntegerField(default=0)
     name = models.CharField(max_length=255)
     name = models.CharField(max_length=255)
     slug = models.SlugField(max_length=255)
     slug = models.SlugField(max_length=255)
@@ -18,33 +18,33 @@ class Thread(models.Model):
     replies_reported = models.PositiveIntegerField(default=0)
     replies_reported = models.PositiveIntegerField(default=0)
     replies_moderated = models.PositiveIntegerField(default=0)
     replies_moderated = models.PositiveIntegerField(default=0)
     replies_deleted = models.PositiveIntegerField(default=0)
     replies_deleted = models.PositiveIntegerField(default=0)
-    merges = models.PositiveIntegerField(default=0,db_index=True)
-    score = models.PositiveIntegerField(default=30,db_index=True)
+    merges = models.PositiveIntegerField(default=0, db_index=True)
+    score = models.PositiveIntegerField(default=30, db_index=True)
     upvotes = models.PositiveIntegerField(default=0)
     upvotes = models.PositiveIntegerField(default=0)
     downvotes = models.PositiveIntegerField(default=0)
     downvotes = models.PositiveIntegerField(default=0)
     start = models.DateTimeField(db_index=True)
     start = models.DateTimeField(db_index=True)
-    start_post = models.ForeignKey('Post',related_name='+',null=True,blank=True,on_delete=models.SET_NULL)
-    start_poster = models.ForeignKey('users.User',null=True,blank=True)
+    start_post = models.ForeignKey('Post', related_name='+', null=True, blank=True, on_delete=models.SET_NULL)
+    start_poster = models.ForeignKey('users.User', null=True, blank=True)
     start_poster_name = models.CharField(max_length=255)
     start_poster_name = models.CharField(max_length=255)
     start_poster_slug = models.SlugField(max_length=255)
     start_poster_slug = models.SlugField(max_length=255)
-    start_poster_style = models.CharField(max_length=255,null=True,blank=True)
+    start_poster_style = models.CharField(max_length=255, null=True, blank=True)
     last = models.DateTimeField(db_index=True)
     last = models.DateTimeField(db_index=True)
-    last_post = models.ForeignKey('Post',related_name='+',null=True,blank=True,on_delete=models.SET_NULL)
-    last_poster = models.ForeignKey('users.User',related_name='+',null=True,blank=True)
-    last_poster_name = models.CharField(max_length=255,null=True,blank=True)
-    last_poster_slug = models.SlugField(max_length=255,null=True,blank=True)
-    last_poster_style = models.CharField(max_length=255,null=True,blank=True)
-    moderated = models.BooleanField(default=False,db_index=True)
-    deleted = models.BooleanField(default=False,db_index=True)
+    last_post = models.ForeignKey('Post', related_name='+', null=True, blank=True, on_delete=models.SET_NULL)
+    last_poster = models.ForeignKey('users.User', related_name='+', null=True, blank=True)
+    last_poster_name = models.CharField(max_length=255, null=True, blank=True)
+    last_poster_slug = models.SlugField(max_length=255, null=True, blank=True)
+    last_poster_style = models.CharField(max_length=255, null=True, blank=True)
+    moderated = models.BooleanField(default=False, db_index=True)
+    deleted = models.BooleanField(default=False, db_index=True)
     closed = models.BooleanField(default=False)
     closed = models.BooleanField(default=False)
-    
+
     objects = ThreadManager()
     objects = ThreadManager()
-    
+
     statistics_name = _('New Threads')
     statistics_name = _('New Threads')
-        
+
     def get_date(self):
     def get_date(self):
         return self.start
         return self.start
-    
+
     def sync(self):
     def sync(self):
         # Counters
         # Counters
         self.replies = self.post_set.filter(moderated=False).filter(deleted=False).count() - 1
         self.replies = self.post_set.filter(moderated=False).filter(deleted=False).count() - 1
@@ -78,18 +78,18 @@ class Thread(models.Model):
         self.moderated = start_post.moderated
         self.moderated = start_post.moderated
         self.deleted = start_post.deleted
         self.deleted = start_post.deleted
         self.merges = last_post.merge
         self.merges = last_post.merge
-    
+
 
 
 class PostManager(models.Manager):
 class PostManager(models.Manager):
     def filter_stats(self, start, end):
     def filter_stats(self, start, end):
         return self.filter(date__gte=start).filter(date__lte=end)
         return self.filter(date__gte=start).filter(date__lte=end)
-    
+
 
 
 class Post(models.Model):
 class Post(models.Model):
     forum = models.ForeignKey('forums.Forum')
     forum = models.ForeignKey('forums.Forum')
     thread = models.ForeignKey(Thread)
     thread = models.ForeignKey(Thread)
-    merge = models.PositiveIntegerField(default=0,db_index=True)
-    user = models.ForeignKey('users.User',null=True,blank=True)
+    merge = models.PositiveIntegerField(default=0, db_index=True)
+    user = models.ForeignKey('users.User', null=True, blank=True)
     user_name = models.CharField(max_length=255)
     user_name = models.CharField(max_length=255)
     ip = models.GenericIPAddressField()
     ip = models.GenericIPAddressField()
     agent = models.CharField(max_length=255)
     agent = models.CharField(max_length=255)
@@ -99,23 +99,23 @@ class Post(models.Model):
     downvotes = models.PositiveIntegerField(default=0)
     downvotes = models.PositiveIntegerField(default=0)
     date = models.DateTimeField()
     date = models.DateTimeField()
     edits = models.PositiveIntegerField(default=0)
     edits = models.PositiveIntegerField(default=0)
-    edit_date = models.DateTimeField(null=True,blank=True)
-    edit_reason = models.CharField(max_length=255,null=True,blank=True)
-    edit_user = models.ForeignKey('users.User',related_name='+',null=True)
-    edit_user_name = models.CharField(max_length=255,null=True,blank=True)
-    edit_user_slug = models.SlugField(max_length=255,null=True,blank=True)
+    edit_date = models.DateTimeField(null=True, blank=True)
+    edit_reason = models.CharField(max_length=255, null=True, blank=True)
+    edit_user = models.ForeignKey('users.User', related_name='+', null=True)
+    edit_user_name = models.CharField(max_length=255, null=True, blank=True)
+    edit_user_slug = models.SlugField(max_length=255, null=True, blank=True)
     reported = models.BooleanField(default=False)
     reported = models.BooleanField(default=False)
-    moderated = models.BooleanField(default=False,db_index=True)
-    deleted = models.BooleanField(default=False,db_index=True)
+    moderated = models.BooleanField(default=False, db_index=True)
+    deleted = models.BooleanField(default=False, db_index=True)
     protected = models.BooleanField(default=False)
     protected = models.BooleanField(default=False)
-    
+
     objects = PostManager()
     objects = PostManager()
-    
+
     statistics_name = _('New Posts')
     statistics_name = _('New Posts')
-    
+
     def get_date(self):
     def get_date(self):
         return self.date
         return self.date
-    
+
     def set_checkpoint(self, request, action):
     def set_checkpoint(self, request, action):
         if request.user.is_authenticated():
         if request.user.is_authenticated():
             self.checkpoint_set.create(
             self.checkpoint_set.create(
@@ -136,15 +136,15 @@ class Change(models.Model):
     forum = models.ForeignKey('forums.Forum')
     forum = models.ForeignKey('forums.Forum')
     thread = models.ForeignKey(Thread)
     thread = models.ForeignKey(Thread)
     post = models.ForeignKey(Post)
     post = models.ForeignKey(Post)
-    user = models.ForeignKey('users.User',null=True,blank=True)
+    user = models.ForeignKey('users.User', null=True, blank=True)
     user_name = models.CharField(max_length=255)
     user_name = models.CharField(max_length=255)
     user_slug = models.CharField(max_length=255)
     user_slug = models.CharField(max_length=255)
     date = models.DateTimeField()
     date = models.DateTimeField()
     ip = models.GenericIPAddressField()
     ip = models.GenericIPAddressField()
     agent = models.CharField(max_length=255)
     agent = models.CharField(max_length=255)
-    reason = models.CharField(max_length=255,null=True,blank=True)
-    thread_name_new = models.CharField(max_length=255,null=True,blank=True)
-    thread_name_old = models.CharField(max_length=255,null=True,blank=True)
+    reason = models.CharField(max_length=255, null=True, blank=True)
+    thread_name_new = models.CharField(max_length=255, null=True, blank=True)
+    thread_name_old = models.CharField(max_length=255, null=True, blank=True)
     post_content = models.TextField()
     post_content = models.TextField()
     size = models.IntegerField(default=0)
     size = models.IntegerField(default=0)
     change = models.IntegerField(default=0)
     change = models.IntegerField(default=0)
@@ -155,10 +155,9 @@ class Checkpoint(models.Model):
     thread = models.ForeignKey(Thread)
     thread = models.ForeignKey(Thread)
     post = models.ForeignKey(Post)
     post = models.ForeignKey(Post)
     action = models.CharField(max_length=255)
     action = models.CharField(max_length=255)
-    user = models.ForeignKey('users.User',null=True,blank=True)
+    user = models.ForeignKey('users.User', null=True, blank=True)
     user_name = models.CharField(max_length=255)
     user_name = models.CharField(max_length=255)
     user_slug = models.CharField(max_length=255)
     user_slug = models.CharField(max_length=255)
     date = models.DateTimeField()
     date = models.DateTimeField()
     ip = models.GenericIPAddressField()
     ip = models.GenericIPAddressField()
     agent = models.CharField(max_length=255)
     agent = models.CharField(max_length=255)
-    

+ 1 - 1
misago/threads/urls.py

@@ -22,4 +22,4 @@ urlpatterns = patterns('misago.threads.views',
     url(r'^thread/(?P<slug>(\w|-)+)-(?P<thread>\d+)/(?P<post>\d+)/changelog/$', 'ChangelogView', name="changelog"),
     url(r'^thread/(?P<slug>(\w|-)+)-(?P<thread>\d+)/(?P<post>\d+)/changelog/$', 'ChangelogView', name="changelog"),
     url(r'^thread/(?P<slug>(\w|-)+)-(?P<thread>\d+)/(?P<post>\d+)/changelog/(?P<change>\d+)/$', 'ChangelogDiffView', name="changelog_diff"),
     url(r'^thread/(?P<slug>(\w|-)+)-(?P<thread>\d+)/(?P<post>\d+)/changelog/(?P<change>\d+)/$', 'ChangelogDiffView', name="changelog_diff"),
     url(r'^thread/(?P<slug>(\w|-)+)-(?P<thread>\d+)/(?P<post>\d+)/changelog/(?P<change>\d+)/revert/$', 'ChangelogRevertView', name="changelog_revert"),
     url(r'^thread/(?P<slug>(\w|-)+)-(?P<thread>\d+)/(?P<post>\d+)/changelog/(?P<change>\d+)/revert/$', 'ChangelogRevertView', name="changelog_revert"),
-)
+)

+ 2 - 2
misago/threads/views/base.py

@@ -6,9 +6,9 @@ class BaseView(object):
     def __new__(cls, request, **kwargs):
     def __new__(cls, request, **kwargs):
         obj = super(BaseView, cls).__new__(cls)
         obj = super(BaseView, cls).__new__(cls)
         return obj(request, **kwargs)
         return obj(request, **kwargs)
-    
+
     def redirect_to_post(self, post):
     def redirect_to_post(self, post):
         pagination = make_pagination(0, self.request.acl.threads.filter_posts(self.request, self.thread, self.thread.post_set).filter(id__lte=post.pk).count(), self.request.settings.posts_per_page)
         pagination = make_pagination(0, self.request.acl.threads.filter_posts(self.request, self.thread, self.thread.post_set).filter(id__lte=post.pk).count(), self.request.settings.posts_per_page)
         if pagination['total'] > 1:
         if pagination['total'] > 1:
             return redirect(reverse('thread', kwargs={'thread': self.thread.pk, 'slug': self.thread.slug, 'page': pagination['total']}) + ('#post-%s' % post.pk))
             return redirect(reverse('thread', kwargs={'thread': self.thread.pk, 'slug': self.thread.slug, 'page': pagination['total']}) + ('#post-%s' % post.pk))
-        return redirect(reverse('thread', kwargs={'thread': self.thread.pk, 'slug': self.thread.slug}) + ('#post-%s' % post.pk))
+        return redirect(reverse('thread', kwargs={'thread': self.thread.pk, 'slug': self.thread.slug}) + ('#post-%s' % post.pk))

+ 11 - 12
misago/threads/views/changelog.py

@@ -23,10 +23,10 @@ class ChangelogBaseView(BaseView):
         self.post = Post.objects.select_related('user').get(pk=kwargs['post'], thread=self.thread.pk)
         self.post = Post.objects.select_related('user').get(pk=kwargs['post'], thread=self.thread.pk)
         self.request.acl.threads.allow_post_view(self.request.user, self.thread, self.post)
         self.request.acl.threads.allow_post_view(self.request.user, self.thread, self.post)
         self.request.acl.threads.allow_changelog_view(self.request.user, self.forum, self.post)
         self.request.acl.threads.allow_changelog_view(self.request.user, self.forum, self.post)
-            
+
     def dispatch(self, request, **kwargs):
     def dispatch(self, request, **kwargs):
         raise NotImplementedError('ChangelogBaseView cannot be called directly. Did you forget to define custom "dispatch" method?')
         raise NotImplementedError('ChangelogBaseView cannot be called directly. Did you forget to define custom "dispatch" method?')
-    
+
     def __call__(self, request, **kwargs):
     def __call__(self, request, **kwargs):
         self.request = request
         self.request = request
         self.forum = None
         self.forum = None
@@ -43,7 +43,7 @@ class ChangelogBaseView(BaseView):
         except ACLError404 as e:
         except ACLError404 as e:
             return error404(request, e.message)
             return error404(request, e.message)
         return self.dispatch(request, **kwargs)
         return self.dispatch(request, **kwargs)
-    
+
 
 
 class ChangelogView(ChangelogBaseView):
 class ChangelogView(ChangelogBaseView):
     def dispatch(self, request, **kwargs):
     def dispatch(self, request, **kwargs):
@@ -62,7 +62,7 @@ class ChangelogDiffView(ChangelogBaseView):
     def fetch_target(self, kwargs):
     def fetch_target(self, kwargs):
         super(ChangelogDiffView, self).fetch_target(kwargs)
         super(ChangelogDiffView, self).fetch_target(kwargs)
         self.change = self.post.change_set.get(pk=kwargs['change'])
         self.change = self.post.change_set.get(pk=kwargs['change'])
-    
+
     def dispatch(self, request, **kwargs):
     def dispatch(self, request, **kwargs):
         try:
         try:
             next = self.post.change_set.filter(id__gt=self.change.pk)[:1][0]
             next = self.post.change_set.filter(id__gt=self.change.pk)[:1][0]
@@ -86,7 +86,7 @@ class ChangelogDiffView(ChangelogBaseView):
                                                  'l': 1,
                                                  'l': 1,
                                                  'diff': difflib.ndiff(self.change.post_content.splitlines(), self.post.post.splitlines()),
                                                  'diff': difflib.ndiff(self.change.post_content.splitlines(), self.post.post.splitlines()),
                                                  },
                                                  },
-                                                context_instance=RequestContext(request))        
+                                                context_instance=RequestContext(request))
 
 
 
 
 class ChangelogRevertView(ChangelogDiffView):
 class ChangelogRevertView(ChangelogDiffView):
@@ -94,31 +94,30 @@ class ChangelogRevertView(ChangelogDiffView):
         super(ChangelogDiffView, self).fetch_target(kwargs)
         super(ChangelogDiffView, self).fetch_target(kwargs)
         self.change = self.post.change_set.get(pk=kwargs['change'])
         self.change = self.post.change_set.get(pk=kwargs['change'])
         self.request.acl.threads.allow_revert(self.proxy, self.thread)
         self.request.acl.threads.allow_revert(self.proxy, self.thread)
-        
-    def dispatch(self, request, **kwargs):        
+
+    def dispatch(self, request, **kwargs):
         if ((not self.change.thread_name_old or self.thread.name == self.change.thread_name_old)
         if ((not self.change.thread_name_old or self.thread.name == self.change.thread_name_old)
             and (self.change.post_content == self.post.post)):
             and (self.change.post_content == self.post.post)):
             request.messages.set_flash(Message(_("No changes to revert.")), 'error', 'changelog')
             request.messages.set_flash(Message(_("No changes to revert.")), 'error', 'changelog')
             return redirect(reverse('changelog_diff', kwargs={'thread': self.thread.pk, 'slug': self.thread.slug, 'post': self.post.pk, 'change': self.change.pk}))
             return redirect(reverse('changelog_diff', kwargs={'thread': self.thread.pk, 'slug': self.thread.slug, 'post': self.post.pk, 'change': self.change.pk}))
-        
+
         if self.change.thread_name_old and self.change.thread_name_old != self.thread.name:
         if self.change.thread_name_old and self.change.thread_name_old != self.thread.name:
             self.thread.name = self.change.thread_name_old
             self.thread.name = self.change.thread_name_old
             self.thread.slug = slugify(self.change.thread_name_old)
             self.thread.slug = slugify(self.change.thread_name_old)
             self.thread.save(force_update=True)
             self.thread.save(force_update=True)
-            
+
             if self.forum.last_thread_id == self.thread.pk:
             if self.forum.last_thread_id == self.thread.pk:
                 self.forum.last_thread_name = self.change.thread_name_old
                 self.forum.last_thread_name = self.change.thread_name_old
                 self.forum.last_thread_slug = slugify(self.change.thread_name_old)
                 self.forum.last_thread_slug = slugify(self.change.thread_name_old)
                 self.forum.save(force_update=True)
                 self.forum.save(force_update=True)
-            
+
         if self.change.post_content != self.post.post:
         if self.change.post_content != self.post.post:
             self.post.post = self.change.post_content
             self.post.post = self.change.post_content
             self.post.post_preparsed = post_markdown(request, self.change.post_content)
             self.post.post_preparsed = post_markdown(request, self.change.post_content)
             self.post.save(force_update=True)
             self.post.save(force_update=True)
-        
+
         request.messages.set_flash(Message(_("Post has been reverted previous state.")), 'success', 'threads_%s' % self.post.pk)
         request.messages.set_flash(Message(_("Post has been reverted previous state.")), 'success', 'threads_%s' % self.post.pk)
         pagination = make_pagination(0, request.acl.threads.filter_posts(self.request, self.thread, self.thread.post_set).filter(id__lte=self.post.pk).count(), self.request.settings.posts_per_page)
         pagination = make_pagination(0, request.acl.threads.filter_posts(self.request, self.thread, self.thread.post_set).filter(id__lte=self.post.pk).count(), self.request.settings.posts_per_page)
         if pagination['total'] > 1:
         if pagination['total'] > 1:
             return redirect(reverse('thread', kwargs={'thread': self.thread.pk, 'slug': self.thread.slug, 'page': pagination['total']}) + ('#post-%s' % self.post.pk))
             return redirect(reverse('thread', kwargs={'thread': self.thread.pk, 'slug': self.thread.slug, 'page': pagination['total']}) + ('#post-%s' % self.post.pk))
         return redirect(reverse('thread', kwargs={'thread': self.thread.pk, 'slug': self.thread.slug}) + ('#post-%s' % self.post.pk))
         return redirect(reverse('thread', kwargs={'thread': self.thread.pk, 'slug': self.thread.slug}) + ('#post-%s' % self.post.pk))
-                

+ 7 - 7
misago/threads/views/delete.py

@@ -29,7 +29,7 @@ class DeleteView(BaseView):
             if not acl['can_delete_threads']:
             if not acl['can_delete_threads']:
                 if self.thread.post_set.exclude(user_id=self.request.user.id).count() > 0:
                 if self.thread.post_set.exclude(user_id=self.request.user.id).count() > 0:
                     raise ACLError403(_("Somebody has already replied to this thread. You cannot delete it."))
                     raise ACLError403(_("Somebody has already replied to this thread. You cannot delete it."))
-            
+
     def fetch_post(self, kwargs):
     def fetch_post(self, kwargs):
         self.post = self.thread.post_set.get(pk=kwargs['post'])
         self.post = self.thread.post_set.get(pk=kwargs['post'])
         if self.post.pk == self.thread.start_post_id:
         if self.post.pk == self.thread.start_post_id:
@@ -44,7 +44,7 @@ class DeleteView(BaseView):
         acl = self.request.acl.threads.get_role(self.thread.forum_id)
         acl = self.request.acl.threads.get_role(self.thread.forum_id)
         if not acl['can_delete_posts'] and self.thread.post_set.filter(id__gt=self.post.pk).count() > 0:
         if not acl['can_delete_posts'] and self.thread.post_set.filter(id__gt=self.post.pk).count() > 0:
             raise ACLError403(_("Somebody has already replied to this post, you cannot delete it."))
             raise ACLError403(_("Somebody has already replied to this post, you cannot delete it."))
-        
+
     def __call__(self, request, **kwargs):
     def __call__(self, request, **kwargs):
         self.request = request
         self.request = request
         self.mode = kwargs['mode']
         self.mode = kwargs['mode']
@@ -60,14 +60,14 @@ class DeleteView(BaseView):
             return error403(request, e.message)
             return error403(request, e.message)
         except ACLError404 as e:
         except ACLError404 as e:
             return error404(request, e.message)
             return error404(request, e.message)
-        
+
         if self.mode == 'delete_thread':
         if self.mode == 'delete_thread':
             self.thread.delete()
             self.thread.delete()
             self.forum.sync()
             self.forum.sync()
             self.forum.save(force_update=True)
             self.forum.save(force_update=True)
             request.messages.set_flash(Message(_('Thread "%(thread)s" has been deleted.') % {'thread': self.thread.name}), 'success', 'threads')
             request.messages.set_flash(Message(_('Thread "%(thread)s" has been deleted.') % {'thread': self.thread.name}), 'success', 'threads')
             return redirect(reverse('forum', kwargs={'forum': self.thread.forum.pk, 'slug': self.thread.forum.slug}))
             return redirect(reverse('forum', kwargs={'forum': self.thread.forum.pk, 'slug': self.thread.forum.slug}))
-        
+
         if self.mode == 'hide_thread':
         if self.mode == 'hide_thread':
             self.thread.start_post.deleted = True
             self.thread.start_post.deleted = True
             self.thread.start_post.save(force_update=True)
             self.thread.start_post.save(force_update=True)
@@ -80,7 +80,7 @@ class DeleteView(BaseView):
             if request.acl.threads.can_see_deleted_threads(self.thread.forum):
             if request.acl.threads.can_see_deleted_threads(self.thread.forum):
                 return redirect(reverse('thread', kwargs={'thread': self.thread.pk, 'slug': self.thread.slug}))
                 return redirect(reverse('thread', kwargs={'thread': self.thread.pk, 'slug': self.thread.slug}))
             return redirect(reverse('forum', kwargs={'forum': self.thread.forum.pk, 'slug': self.thread.forum.slug}))
             return redirect(reverse('forum', kwargs={'forum': self.thread.forum.pk, 'slug': self.thread.forum.slug}))
-        
+
         if self.mode == 'delete_post':
         if self.mode == 'delete_post':
             self.post.delete()
             self.post.delete()
             self.thread.sync()
             self.thread.sync()
@@ -89,7 +89,7 @@ class DeleteView(BaseView):
             self.forum.save(force_update=True)
             self.forum.save(force_update=True)
             request.messages.set_flash(Message(_("Selected Reply has been deleted.")), 'success', 'threads')
             request.messages.set_flash(Message(_("Selected Reply has been deleted.")), 'success', 'threads')
             return redirect(reverse('thread', kwargs={'thread': self.thread.pk, 'slug': self.thread.slug}))
             return redirect(reverse('thread', kwargs={'thread': self.thread.pk, 'slug': self.thread.slug}))
-            
+
         if self.mode == 'hide_post':
         if self.mode == 'hide_post':
             self.post.deleted = True
             self.post.deleted = True
             self.post.edit_date = timezone.now()
             self.post.edit_date = timezone.now()
@@ -102,4 +102,4 @@ class DeleteView(BaseView):
             self.forum.sync()
             self.forum.sync()
             self.forum.save(force_update=True)
             self.forum.save(force_update=True)
             request.messages.set_flash(Message(_("Selected Reply has been deleted.")), 'success', 'threads_%s' % self.post.pk)
             request.messages.set_flash(Message(_("Selected Reply has been deleted.")), 'success', 'threads_%s' % self.post.pk)
-            return self.redirect_to_post(self.post)
+            return self.redirect_to_post(self.post)

+ 7 - 7
misago/threads/views/jumps.py

@@ -15,20 +15,20 @@ class JumpView(BaseView):
         self.forum = self.thread.forum
         self.forum = self.thread.forum
         self.request.acl.forums.allow_forum_view(self.forum)
         self.request.acl.forums.allow_forum_view(self.forum)
         self.request.acl.threads.allow_thread_view(self.request.user, self.thread)
         self.request.acl.threads.allow_thread_view(self.request.user, self.thread)
-        
+
     def fetch_post(self, post):
     def fetch_post(self, post):
         self.post = self.thread.post_set.get(pk=post)
         self.post = self.thread.post_set.get(pk=post)
         self.request.acl.threads.allow_post_view(self.request.user, self.thread, self.post)
         self.request.acl.threads.allow_post_view(self.request.user, self.thread, self.post)
-        
+
     def redirect(self, post):
     def redirect(self, post):
         pagination = make_pagination(0, self.request.acl.threads.filter_posts(self.request, self.thread, self.thread.post_set.filter(date__lt=post.date)).count() + 1, self.request.settings.posts_per_page)
         pagination = make_pagination(0, self.request.acl.threads.filter_posts(self.request, self.thread, self.thread.post_set.filter(date__lt=post.date)).count() + 1, self.request.settings.posts_per_page)
         if pagination['total'] > 1:
         if pagination['total'] > 1:
             return redirect(reverse('thread', kwargs={'thread': self.thread.pk, 'slug': self.thread.slug, 'page': pagination['total']}) + ('#post-%s' % post.pk))
             return redirect(reverse('thread', kwargs={'thread': self.thread.pk, 'slug': self.thread.slug, 'page': pagination['total']}) + ('#post-%s' % post.pk))
         return redirect(reverse('thread', kwargs={'thread': self.thread.pk, 'slug': self.thread.slug}) + ('#post-%s' % post.pk))
         return redirect(reverse('thread', kwargs={'thread': self.thread.pk, 'slug': self.thread.slug}) + ('#post-%s' % post.pk))
-        
+
     def make_jump(self):
     def make_jump(self):
         raise NotImplementedError('JumpView cannot be called directly.')
         raise NotImplementedError('JumpView cannot be called directly.')
-        
+
     def __call__(self, request, slug=None, thread=None, post=None):
     def __call__(self, request, slug=None, thread=None, post=None):
         self.request = request
         self.request = request
         try:
         try:
@@ -42,7 +42,7 @@ class JumpView(BaseView):
             return error403(request, e.message)
             return error403(request, e.message)
         except ACLError404 as e:
         except ACLError404 as e:
             return error404(request, e.message)
             return error404(request, e.message)
-        
+
 
 
 class LastReplyView(JumpView):
 class LastReplyView(JumpView):
     def make_jump(self):
     def make_jump(self):
@@ -53,7 +53,7 @@ class FindReplyView(JumpView):
     def make_jump(self):
     def make_jump(self):
         return self.redirect(self.post)
         return self.redirect(self.post)
 
 
-    
+
 class NewReplyView(JumpView):
 class NewReplyView(JumpView):
     def make_jump(self):
     def make_jump(self):
         if not self.request.user.is_authenticated():
         if not self.request.user.is_authenticated():
@@ -85,4 +85,4 @@ class FirstReportedView(JumpView):
             return self.redirect(
             return self.redirect(
                 self.thread.post_set.get(reported=True))
                 self.thread.post_set.get(reported=True))
         except Post.DoesNotExist:
         except Post.DoesNotExist:
-            return error404(self.request)
+            return error404(self.request)

+ 28 - 28
misago/threads/views/list.py

@@ -26,7 +26,7 @@ class ThreadsView(BaseView):
         if self.forum.lft + 1 != self.forum.rght:
         if self.forum.lft + 1 != self.forum.rght:
             self.forum.subforums = Forum.objects.treelist(self.request.acl.forums, self.forum, tracker=ForumsTracker(self.request.user))
             self.forum.subforums = Forum.objects.treelist(self.request.acl.forums, self.forum, tracker=ForumsTracker(self.request.user))
         self.tracker = ThreadsTracker(self.request.user, self.forum)
         self.tracker = ThreadsTracker(self.request.user, self.forum)
-                
+
     def fetch_threads(self, page):
     def fetch_threads(self, page):
         self.count = self.request.acl.threads.filter_threads(self.request, self.forum, Thread.objects.filter(forum=self.forum).filter(weight__lt=2)).count()
         self.count = self.request.acl.threads.filter_threads(self.request, self.forum, Thread.objects.filter(forum=self.forum).filter(weight__lt=2)).count()
         self.pagination = make_pagination(page, self.count, self.request.settings.threads_per_page)
         self.pagination = make_pagination(page, self.count, self.request.settings.threads_per_page)
@@ -44,7 +44,7 @@ class ThreadsView(BaseView):
             self.threads = self.threads[self.pagination['start']:self.pagination['stop']]
             self.threads = self.threads[self.pagination['start']:self.pagination['stop']]
         for thread in self.threads:
         for thread in self.threads:
             thread.is_read = self.tracker.is_read(thread)
             thread.is_read = self.tracker.is_read(thread)
-    
+
     def get_thread_actions(self):
     def get_thread_actions(self):
         acl = self.request.acl.threads.get_role(self.forum)
         acl = self.request.acl.threads.get_role(self.forum)
         actions = []
         actions = []
@@ -71,14 +71,14 @@ class ThreadsView(BaseView):
         except KeyError:
         except KeyError:
             pass
             pass
         return actions
         return actions
-    
+
     def make_form(self):
     def make_form(self):
         self.form = None
         self.form = None
         list_choices = self.get_thread_actions();
         list_choices = self.get_thread_actions();
         if (not self.request.user.is_authenticated()
         if (not self.request.user.is_authenticated()
             or not list_choices):
             or not list_choices):
             return
             return
-        
+
         form_fields = {}
         form_fields = {}
         form_fields['list_action'] = forms.ChoiceField(choices=list_choices)
         form_fields['list_action'] = forms.ChoiceField(choices=list_choices)
         list_choices = []
         list_choices = []
@@ -87,9 +87,9 @@ class ThreadsView(BaseView):
                 list_choices.append((item.pk, None))
                 list_choices.append((item.pk, None))
         if not list_choices:
         if not list_choices:
             return
             return
-        form_fields['list_items'] = forms.MultipleChoiceField(choices=list_choices,widget=forms.CheckboxSelectMultiple)
+        form_fields['list_items'] = forms.MultipleChoiceField(choices=list_choices, widget=forms.CheckboxSelectMultiple)
         self.form = type('ThreadsViewForm', (Form,), form_fields)
         self.form = type('ThreadsViewForm', (Form,), form_fields)
-    
+
     def handle_form(self):
     def handle_form(self):
         if self.request.method == 'POST':
         if self.request.method == 'POST':
             self.form = self.form(self.request.POST, request=self.request)
             self.form = self.form(self.request.POST, request=self.request)
@@ -129,7 +129,7 @@ class ThreadsView(BaseView):
                     self.message = Message(form.non_field_errors()[0], 'error')
                     self.message = Message(form.non_field_errors()[0], 'error')
         else:
         else:
             self.form = self.form(request=self.request)
             self.form = self.form(request=self.request)
-            
+
     def action_accept(self, ids):
     def action_accept(self, ids):
         accepted = 0
         accepted = 0
         users = []
         users = []
@@ -158,7 +158,7 @@ class ThreadsView(BaseView):
             for user in users:
             for user in users:
                 user.save(force_update=True)
                 user.save(force_update=True)
             self.request.messages.set_flash(Message(_('Selected threads have been marked as reviewed and made visible to other members.')), 'success', 'threads')
             self.request.messages.set_flash(Message(_('Selected threads have been marked as reviewed and made visible to other members.')), 'success', 'threads')
-    
+
     def action_annouce(self, ids):
     def action_annouce(self, ids):
         acl = self.request.acl.threads.get_role(self.forum)
         acl = self.request.acl.threads.get_role(self.forum)
         annouced = []
         annouced = []
@@ -168,7 +168,7 @@ class ThreadsView(BaseView):
         if annouced:
         if annouced:
             Thread.objects.filter(id__in=annouced).update(weight=2)
             Thread.objects.filter(id__in=annouced).update(weight=2)
             self.request.messages.set_flash(Message(_('Selected threads have been turned into annoucements.')), 'success', 'threads')
             self.request.messages.set_flash(Message(_('Selected threads have been turned into annoucements.')), 'success', 'threads')
-    
+
     def action_sticky(self, ids):
     def action_sticky(self, ids):
         sticky = []
         sticky = []
         for thread in self.threads:
         for thread in self.threads:
@@ -177,7 +177,7 @@ class ThreadsView(BaseView):
         if sticky:
         if sticky:
             Thread.objects.filter(id__in=sticky).update(weight=1)
             Thread.objects.filter(id__in=sticky).update(weight=1)
             self.request.messages.set_flash(Message(_('Selected threads have been sticked to the top of list.')), 'success', 'threads')
             self.request.messages.set_flash(Message(_('Selected threads have been sticked to the top of list.')), 'success', 'threads')
-    
+
     def action_normal(self, ids):
     def action_normal(self, ids):
         normalised = []
         normalised = []
         for thread in self.threads:
         for thread in self.threads:
@@ -186,14 +186,14 @@ class ThreadsView(BaseView):
         if normalised:
         if normalised:
             Thread.objects.filter(id__in=normalised).update(weight=0)
             Thread.objects.filter(id__in=normalised).update(weight=0)
             self.request.messages.set_flash(Message(_('Selected threads weight has been removed.')), 'success', 'threads')
             self.request.messages.set_flash(Message(_('Selected threads weight has been removed.')), 'success', 'threads')
-    
+
     def action_move(self, ids):
     def action_move(self, ids):
         threads = []
         threads = []
         for thread in self.threads:
         for thread in self.threads:
             if thread.pk in ids:
             if thread.pk in ids:
                 threads.append(thread)
                 threads.append(thread)
         if self.request.POST.get('origin') == 'move_form':
         if self.request.POST.get('origin') == 'move_form':
-            form = MoveThreadsForm(self.request.POST,request=self.request,forum=self.forum)
+            form = MoveThreadsForm(self.request.POST, request=self.request, forum=self.forum)
             if form.is_valid():
             if form.is_valid():
                 new_forum = form.cleaned_data['new_forum']
                 new_forum = form.cleaned_data['new_forum']
                 for thread in threads:
                 for thread in threads:
@@ -210,7 +210,7 @@ class ThreadsView(BaseView):
                 return None
                 return None
             self.message = Message(form.non_field_errors()[0], 'error')
             self.message = Message(form.non_field_errors()[0], 'error')
         else:
         else:
-            form = MoveThreadsForm(request=self.request,forum=self.forum)
+            form = MoveThreadsForm(request=self.request, forum=self.forum)
         return self.request.theme.render_to_response('threads/move.html',
         return self.request.theme.render_to_response('threads/move.html',
                                                      {
                                                      {
                                                       'message': self.message,
                                                       'message': self.message,
@@ -219,8 +219,8 @@ class ThreadsView(BaseView):
                                                       'threads': threads,
                                                       'threads': threads,
                                                       'form': FormLayout(form),
                                                       'form': FormLayout(form),
                                                       },
                                                       },
-                                                     context_instance=RequestContext(self.request)); 
-            
+                                                     context_instance=RequestContext(self.request));
+
     def action_merge(self, ids):
     def action_merge(self, ids):
         if len(ids) < 2:
         if len(ids) < 2:
             raise ValidationError(_("You have to pick two or more threads to merge."))
             raise ValidationError(_("You have to pick two or more threads to merge."))
@@ -229,7 +229,7 @@ class ThreadsView(BaseView):
             if thread.pk in ids:
             if thread.pk in ids:
                 threads.append(thread)
                 threads.append(thread)
         if self.request.POST.get('origin') == 'merge_form':
         if self.request.POST.get('origin') == 'merge_form':
-            form = MergeThreadsForm(self.request.POST,request=self.request,threads=threads)
+            form = MergeThreadsForm(self.request.POST, request=self.request, threads=threads)
             if form.is_valid():
             if form.is_valid():
                 new_thread = Thread.objects.create(
                 new_thread = Thread.objects.create(
                                                    forum=self.forum,
                                                    forum=self.forum,
@@ -246,7 +246,7 @@ class ThreadsView(BaseView):
                     merged.append(thread.pk)
                     merged.append(thread.pk)
                     if last_thread and last_thread.last > thread.start:
                     if last_thread and last_thread.last > thread.start:
                         last_merge += thread.merges + 1
                         last_merge += thread.merges + 1
-                    thread.post_set.update(thread=new_thread,merge=F('merge') + last_merge)
+                    thread.post_set.update(thread=new_thread, merge=F('merge') + last_merge)
                     thread.change_set.update(thread=new_thread)
                     thread.change_set.update(thread=new_thread)
                     thread.checkpoint_set.update(thread=new_thread)
                     thread.checkpoint_set.update(thread=new_thread)
                     last_thread = thread
                     last_thread = thread
@@ -259,7 +259,7 @@ class ThreadsView(BaseView):
                 return None
                 return None
             self.message = Message(form.non_field_errors()[0], 'error')
             self.message = Message(form.non_field_errors()[0], 'error')
         else:
         else:
-            form = MergeThreadsForm(request=self.request,threads=threads)  
+            form = MergeThreadsForm(request=self.request, threads=threads)
         return self.request.theme.render_to_response('threads/merge.html',
         return self.request.theme.render_to_response('threads/merge.html',
                                                      {
                                                      {
                                                       'message': self.message,
                                                       'message': self.message,
@@ -268,8 +268,8 @@ class ThreadsView(BaseView):
                                                       'threads': threads,
                                                       'threads': threads,
                                                       'form': FormLayout(form),
                                                       'form': FormLayout(form),
                                                       },
                                                       },
-                                                     context_instance=RequestContext(self.request)); 
-    
+                                                     context_instance=RequestContext(self.request));
+
     def action_open(self, ids):
     def action_open(self, ids):
         opened = []
         opened = []
         for thread in self.threads:
         for thread in self.threads:
@@ -278,8 +278,8 @@ class ThreadsView(BaseView):
                 thread.last_post.set_checkpoint(self.request, 'opened')
                 thread.last_post.set_checkpoint(self.request, 'opened')
         if opened:
         if opened:
             Thread.objects.filter(id__in=opened).update(closed=False)
             Thread.objects.filter(id__in=opened).update(closed=False)
-            self.request.messages.set_flash(Message(_('Selected threads have been opened.')), 'success', 'threads')     
-        
+            self.request.messages.set_flash(Message(_('Selected threads have been opened.')), 'success', 'threads')
+
     def action_close(self, ids):
     def action_close(self, ids):
         closed = []
         closed = []
         for thread in self.threads:
         for thread in self.threads:
@@ -289,7 +289,7 @@ class ThreadsView(BaseView):
         if closed:
         if closed:
             Thread.objects.filter(id__in=closed).update(closed=True)
             Thread.objects.filter(id__in=closed).update(closed=True)
             self.request.messages.set_flash(Message(_('Selected threads have been closed.')), 'success', 'threads')
             self.request.messages.set_flash(Message(_('Selected threads have been closed.')), 'success', 'threads')
-    
+
     def action_undelete(self, ids):
     def action_undelete(self, ids):
         undeleted = []
         undeleted = []
         posts = 0
         posts = 0
@@ -307,7 +307,7 @@ class ThreadsView(BaseView):
             self.forum.save(force_update=True)
             self.forum.save(force_update=True)
             Thread.objects.filter(id__in=undeleted).update(deleted=False)
             Thread.objects.filter(id__in=undeleted).update(deleted=False)
             self.request.messages.set_flash(Message(_('Selected threads have been undeleted.')), 'success', 'threads')
             self.request.messages.set_flash(Message(_('Selected threads have been undeleted.')), 'success', 'threads')
-    
+
     def action_soft(self, ids):
     def action_soft(self, ids):
         deleted = []
         deleted = []
         posts = 0
         posts = 0
@@ -324,8 +324,8 @@ class ThreadsView(BaseView):
             self.forum.sync()
             self.forum.sync()
             self.forum.save(force_update=True)
             self.forum.save(force_update=True)
             Thread.objects.filter(id__in=deleted).update(deleted=True)
             Thread.objects.filter(id__in=deleted).update(deleted=True)
-            self.request.messages.set_flash(Message(_('Selected threads have been softly deleted.')), 'success', 'threads')            
-    
+            self.request.messages.set_flash(Message(_('Selected threads have been softly deleted.')), 'success', 'threads')
+
     def action_hard(self, ids):
     def action_hard(self, ids):
         deleted = []
         deleted = []
         posts = 0
         posts = 0
@@ -340,7 +340,7 @@ class ThreadsView(BaseView):
             self.forum.sync()
             self.forum.sync()
             self.forum.save(force_update=True)
             self.forum.save(force_update=True)
             self.request.messages.set_flash(Message(_('Selected threads have been deleted.')), 'success', 'threads')
             self.request.messages.set_flash(Message(_('Selected threads have been deleted.')), 'success', 'threads')
-    
+
     def __call__(self, request, slug=None, forum=None, page=0):
     def __call__(self, request, slug=None, forum=None, page=0):
         self.request = request
         self.request = request
         self.pagination = None
         self.pagination = None
@@ -372,4 +372,4 @@ class ThreadsView(BaseView):
                                                  'threads': self.threads,
                                                  'threads': self.threads,
                                                  'pagination': self.pagination,
                                                  'pagination': self.pagination,
                                                  },
                                                  },
-                                                context_instance=RequestContext(request));
+                                                context_instance=RequestContext(request));

+ 30 - 30
misago/threads/views/posting.py

@@ -25,14 +25,14 @@ class PostingView(BaseView):
                 self.fetch_post(self.thread.start_post_id)
                 self.fetch_post(self.thread.start_post_id)
             if self.mode == 'edit_post':
             if self.mode == 'edit_post':
                 self.fetch_post(kwargs['post'])
                 self.fetch_post(kwargs['post'])
-    
+
     def fetch_forum(self, kwargs):
     def fetch_forum(self, kwargs):
         self.forum = Forum.objects.get(pk=kwargs['forum'], type='forum')
         self.forum = Forum.objects.get(pk=kwargs['forum'], type='forum')
         self.proxy = Forum.objects.parents_aware_forum(self.forum)
         self.proxy = Forum.objects.parents_aware_forum(self.forum)
         self.request.acl.forums.allow_forum_view(self.forum)
         self.request.acl.forums.allow_forum_view(self.forum)
         self.request.acl.threads.allow_new_threads(self.proxy)
         self.request.acl.threads.allow_new_threads(self.proxy)
         self.parents = Forum.objects.forum_parents(self.forum.pk, True)
         self.parents = Forum.objects.forum_parents(self.forum.pk, True)
-    
+
     def fetch_thread(self, kwargs):
     def fetch_thread(self, kwargs):
         self.thread = Thread.objects.get(pk=kwargs['thread'])
         self.thread = Thread.objects.get(pk=kwargs['thread'])
         self.forum = self.thread.forum
         self.forum = self.thread.forum
@@ -44,15 +44,15 @@ class PostingView(BaseView):
         if kwargs.get('quote'):
         if kwargs.get('quote'):
             self.quote = Post.objects.select_related('user').get(pk=kwargs['quote'], thread=self.thread.pk)
             self.quote = Post.objects.select_related('user').get(pk=kwargs['quote'], thread=self.thread.pk)
             self.request.acl.threads.allow_post_view(self.request.user, self.thread, self.quote)
             self.request.acl.threads.allow_post_view(self.request.user, self.thread, self.quote)
-    
+
     def fetch_post(self, post):
     def fetch_post(self, post):
         self.post = self.thread.post_set.get(pk=post)
         self.post = self.thread.post_set.get(pk=post)
         self.request.acl.threads.allow_post_view(self.request.user, self.thread, self.post)
         self.request.acl.threads.allow_post_view(self.request.user, self.thread, self.post)
         if self.mode == 'edit_thread':
         if self.mode == 'edit_thread':
             self.request.acl.threads.allow_thread_edit(self.request.user, self.proxy, self.thread, self.post)
             self.request.acl.threads.allow_thread_edit(self.request.user, self.proxy, self.thread, self.post)
         if self.mode == 'edit_post':
         if self.mode == 'edit_post':
-            self.request.acl.threads.allow_reply_edit(self.request.user, self.proxy, self.thread, self.post)     
-        
+            self.request.acl.threads.allow_reply_edit(self.request.user, self.proxy, self.thread, self.post)
+
     def get_form(self, bound=False):
     def get_form(self, bound=False):
         initial = {}
         initial = {}
         if self.mode == 'edit_thread':
         if self.mode == 'edit_thread':
@@ -69,11 +69,11 @@ class PostingView(BaseView):
                 quote_post.append('> %s' % line)
                 quote_post.append('> %s' % line)
             quote_post.append('\n')
             quote_post.append('\n')
             initial['post'] = '\n'.join(quote_post)
             initial['post'] = '\n'.join(quote_post)
-            
-        if bound:            
-            return PostForm(self.request.POST,request=self.request,mode=self.mode,initial=initial)
-        return PostForm(request=self.request,mode=self.mode,initial=initial)
-            
+
+        if bound:
+            return PostForm(self.request.POST, request=self.request, mode=self.mode, initial=initial)
+        return PostForm(request=self.request, mode=self.mode, initial=initial)
+
     def __call__(self, request, **kwargs):
     def __call__(self, request, **kwargs):
         self.request = request
         self.request = request
         self.forum = None
         self.forum = None
@@ -94,7 +94,7 @@ class PostingView(BaseView):
             return error403(request, e.message)
             return error403(request, e.message)
         except ACLError404 as e:
         except ACLError404 as e:
             return error404(request, e.message)
             return error404(request, e.message)
-        
+
         message = request.messages.get_message('threads')
         message = request.messages.get_message('threads')
         if request.method == 'POST':
         if request.method == 'POST':
             form = self.get_form(True)
             form = self.get_form(True)
@@ -107,7 +107,7 @@ class PostingView(BaseView):
                     changed_name = (old_name != form.cleaned_data['thread_name']) if self.mode == 'edit_thread' else False
                     changed_name = (old_name != form.cleaned_data['thread_name']) if self.mode == 'edit_thread' else False
                     changed_post = old_post != form.cleaned_data['post']
                     changed_post = old_post != form.cleaned_data['post']
                     changed_anything = changed_name or changed_post
                     changed_anything = changed_name or changed_post
-                
+
                 # Some extra initialisation
                 # Some extra initialisation
                 now = timezone.now()
                 now = timezone.now()
                 moderation = False
                 moderation = False
@@ -115,8 +115,8 @@ class PostingView(BaseView):
                     if self.mode == 'new_thread' and request.acl.threads.acl[self.forum.pk]['can_start_threads'] == 1:
                     if self.mode == 'new_thread' and request.acl.threads.acl[self.forum.pk]['can_start_threads'] == 1:
                         moderation = True
                         moderation = True
                     if self.mode in ['new_post', 'new_post_quick'] and request.acl.threads.acl[self.forum.pk]['can_write_posts'] == 1:
                     if self.mode in ['new_post', 'new_post_quick'] and request.acl.threads.acl[self.forum.pk]['can_write_posts'] == 1:
-                        moderation = True 
-                        
+                        moderation = True
+
                 # Get or create new thread
                 # Get or create new thread
                 if self.mode == 'new_thread':
                 if self.mode == 'new_thread':
                     thread = Thread.objects.create(
                     thread = Thread.objects.create(
@@ -134,8 +134,8 @@ class PostingView(BaseView):
                     thread = self.thread
                     thread = self.thread
                     if self.mode == 'edit_thread':
                     if self.mode == 'edit_thread':
                         thread.name = form.cleaned_data['thread_name']
                         thread.name = form.cleaned_data['thread_name']
-                        thread.slug = slugify(form.cleaned_data['thread_name']) 
-                
+                        thread.slug = slugify(form.cleaned_data['thread_name'])
+
                 # Create new message
                 # Create new message
                 if self.mode in ['new_thread', 'new_post', 'new_post_quick']:
                 if self.mode in ['new_thread', 'new_post', 'new_post_quick']:
                     # Use last post instead?
                     # Use last post instead?
@@ -178,7 +178,7 @@ class PostingView(BaseView):
                     post.edit_user_name = request.user.username
                     post.edit_user_name = request.user.username
                     post.edit_user_slug = request.user.username_slug
                     post.edit_user_slug = request.user.username_slug
                     post.save(force_update=True)
                     post.save(force_update=True)
-                
+
                 # Record this edit in changelog?
                 # Record this edit in changelog?
                 if self.mode in ['edit_thread', 'edit_post'] and changed_anything:
                 if self.mode in ['edit_thread', 'edit_post'] and changed_anything:
                     self.post.change_set.create(
                     self.post.change_set.create(
@@ -198,7 +198,7 @@ class PostingView(BaseView):
                                                 thread_name_new=self.thread.name if self.mode == 'edit_thread' and form.cleaned_data['thread_name'] != old_name else None,
                                                 thread_name_new=self.thread.name if self.mode == 'edit_thread' and form.cleaned_data['thread_name'] != old_name else None,
                                                 post_content=old_post,
                                                 post_content=old_post,
                                                 )
                                                 )
-                
+
                 # Set thread start post and author data
                 # Set thread start post and author data
                 if self.mode == 'new_thread':
                 if self.mode == 'new_thread':
                     thread.start_post = post
                     thread.start_post = post
@@ -207,7 +207,7 @@ class PostingView(BaseView):
                     thread.start_poster_slug = request.user.username_slug
                     thread.start_poster_slug = request.user.username_slug
                     if request.user.rank and request.user.rank.style:
                     if request.user.rank and request.user.rank.style:
                         thread.start_poster_style = request.user.rank.style
                         thread.start_poster_style = request.user.rank.style
-                
+
                 # New post - increase post counters, thread score
                 # New post - increase post counters, thread score
                 # Notify quoted post author and close thread if it has hit limit
                 # Notify quoted post author and close thread if it has hit limit
                 if self.mode in ['new_post', 'new_post_quick']:
                 if self.mode in ['new_post', 'new_post_quick']:
@@ -228,7 +228,7 @@ class PostingView(BaseView):
                             and thread.replies >= self.request.settings.thread_length):
                             and thread.replies >= self.request.settings.thread_length):
                             thread.closed = True
                             thread.closed = True
                             post.set_checkpoint(self.request, 'limit')
                             post.set_checkpoint(self.request, 'limit')
-                
+
                 # Update last poster data
                 # Update last poster data
                 if not moderation and self.mode not in ['edit_thread', 'edit_post']:
                 if not moderation and self.mode not in ['edit_thread', 'edit_post']:
                     thread.last = now
                     thread.last = now
@@ -238,23 +238,23 @@ class PostingView(BaseView):
                     thread.last_poster_slug = request.user.username_slug
                     thread.last_poster_slug = request.user.username_slug
                     if request.user.rank and request.user.rank.style:
                     if request.user.rank and request.user.rank.style:
                         thread.last_poster_style = request.user.rank.style
                         thread.last_poster_style = request.user.rank.style
-                        
+
                 # Final update of thread entry
                 # Final update of thread entry
                 if self.mode != 'edit_post':
                 if self.mode != 'edit_post':
                     thread.save(force_update=True)
                     thread.save(force_update=True)
-                
+
                 # Update forum and monitor
                 # Update forum and monitor
                 if not moderation:
                 if not moderation:
                     if self.mode == 'new_thread':
                     if self.mode == 'new_thread':
                         self.request.monitor['threads'] = int(self.request.monitor['threads']) + 1
                         self.request.monitor['threads'] = int(self.request.monitor['threads']) + 1
                         self.forum.threads += 1
                         self.forum.threads += 1
                         self.forum.threads_delta += 1
                         self.forum.threads_delta += 1
-                        
+
                     if self.mode in ['new_thread', 'new_post', 'new_post_quick']:
                     if self.mode in ['new_thread', 'new_post', 'new_post_quick']:
                         self.request.monitor['posts'] = int(self.request.monitor['posts']) + 1
                         self.request.monitor['posts'] = int(self.request.monitor['posts']) + 1
                         self.forum.posts += 1
                         self.forum.posts += 1
                         self.forum.posts_delta += 1
                         self.forum.posts_delta += 1
-                        
+
                     self.forum.last_thread = thread
                     self.forum.last_thread = thread
                     self.forum.last_thread_name = thread.name
                     self.forum.last_thread_name = thread.name
                     self.forum.last_thread_slug = thread.slug
                     self.forum.last_thread_slug = thread.slug
@@ -264,7 +264,7 @@ class PostingView(BaseView):
                     self.forum.last_poster_slug = thread.last_poster_slug
                     self.forum.last_poster_slug = thread.last_poster_slug
                     self.forum.last_poster_style = thread.last_poster_style
                     self.forum.last_poster_style = thread.last_poster_style
                     self.forum.save(force_update=True)
                     self.forum.save(force_update=True)
-                
+
                 # Update user
                 # Update user
                 if not moderation:
                 if not moderation:
                     if self.mode == 'new_thread':
                     if self.mode == 'new_thread':
@@ -273,7 +273,7 @@ class PostingView(BaseView):
                 if self.mode in ['new_thread', 'new_post', 'new_post_quick']:
                 if self.mode in ['new_thread', 'new_post', 'new_post_quick']:
                     request.user.last_post = thread.last
                     request.user.last_post = thread.last
                     request.user.save(force_update=True)
                     request.user.save(force_update=True)
-                
+
                 # Set flash and redirect user to his post
                 # Set flash and redirect user to his post
                 if self.mode == 'new_thread':
                 if self.mode == 'new_thread':
                     if moderation:
                     if moderation:
@@ -281,14 +281,14 @@ class PostingView(BaseView):
                     else:
                     else:
                         request.messages.set_flash(Message(_("New thread has been posted.")), 'success', 'threads')
                         request.messages.set_flash(Message(_("New thread has been posted.")), 'success', 'threads')
                     return redirect(reverse('thread', kwargs={'thread': thread.pk, 'slug': thread.slug}) + ('#post-%s' % post.pk))
                     return redirect(reverse('thread', kwargs={'thread': thread.pk, 'slug': thread.slug}) + ('#post-%s' % post.pk))
-                
+
                 if self.mode in ['new_post', 'new_post_quick']:
                 if self.mode in ['new_post', 'new_post_quick']:
                     if moderation:
                     if moderation:
                         request.messages.set_flash(Message(_("Your reply has been posted. It will be hidden from other members until moderator reviews it.")), 'success', 'threads_%s' % post.pk)
                         request.messages.set_flash(Message(_("Your reply has been posted. It will be hidden from other members until moderator reviews it.")), 'success', 'threads_%s' % post.pk)
                     else:
                     else:
                         request.messages.set_flash(Message(_("Your reply has been posted.")), 'success', 'threads_%s' % post.pk)
                         request.messages.set_flash(Message(_("Your reply has been posted.")), 'success', 'threads_%s' % post.pk)
                     return self.redirect_to_post(post)
                     return self.redirect_to_post(post)
-                
+
                 if self.mode == 'edit_thread':
                 if self.mode == 'edit_thread':
                     request.messages.set_flash(Message(_("Your thread has been edited.")), 'success', 'threads_%s' % self.post.pk)
                     request.messages.set_flash(Message(_("Your thread has been edited.")), 'success', 'threads_%s' % self.post.pk)
                 if self.mode == 'edit_post':
                 if self.mode == 'edit_post':
@@ -298,7 +298,7 @@ class PostingView(BaseView):
             message = Message(form.non_field_errors()[0], 'error')
             message = Message(form.non_field_errors()[0], 'error')
         else:
         else:
             form = self.get_form()
             form = self.get_form()
-            
+
         # Merge proxy into forum
         # Merge proxy into forum
         self.forum.closed = self.proxy.closed
         self.forum.closed = self.proxy.closed
         return request.theme.render_to_response('threads/posting.html',
         return request.theme.render_to_response('threads/posting.html',
@@ -312,4 +312,4 @@ class PostingView(BaseView):
                                                  'message': message,
                                                  'message': message,
                                                  'form': FormLayout(form),
                                                  'form': FormLayout(form),
                                                  },
                                                  },
-                                                context_instance=RequestContext(request));
+                                                context_instance=RequestContext(request));

+ 38 - 38
misago/threads/views/thread.py

@@ -27,7 +27,7 @@ class ThreadView(BaseView):
         self.request.acl.threads.allow_thread_view(self.request.user, self.thread)
         self.request.acl.threads.allow_thread_view(self.request.user, self.thread)
         self.parents = Forum.objects.forum_parents(self.forum.pk, True)
         self.parents = Forum.objects.forum_parents(self.forum.pk, True)
         self.tracker = ThreadsTracker(self.request.user, self.forum)
         self.tracker = ThreadsTracker(self.request.user, self.forum)
-    
+
     def fetch_posts(self, page):
     def fetch_posts(self, page):
         self.count = self.request.acl.threads.filter_posts(self.request, self.thread, Post.objects.filter(thread=self.thread)).count()
         self.count = self.request.acl.threads.filter_posts(self.request, self.thread, Post.objects.filter(thread=self.thread)).count()
         self.posts = self.request.acl.threads.filter_posts(self.request, self.thread, Post.objects.filter(thread=self.thread)).prefetch_related('checkpoint_set', 'user', 'user__rank')
         self.posts = self.request.acl.threads.filter_posts(self.request, self.thread, Post.objects.filter(thread=self.thread)).prefetch_related('checkpoint_set', 'user', 'user__rank')
@@ -38,7 +38,7 @@ class ThreadView(BaseView):
         self.pagination = make_pagination(page, self.count, self.request.settings.posts_per_page)
         self.pagination = make_pagination(page, self.count, self.request.settings.posts_per_page)
         if self.request.settings.posts_per_page < self.count:
         if self.request.settings.posts_per_page < self.count:
             self.posts = self.posts[self.pagination['start']:self.pagination['stop']]
             self.posts = self.posts[self.pagination['start']:self.pagination['stop']]
-        self.read_date = self.tracker.get_read_date(self.thread) 
+        self.read_date = self.tracker.get_read_date(self.thread)
         for post in self.posts:
         for post in self.posts:
             post.message = self.request.messages.get_message('threads_%s' % post.pk)
             post.message = self.request.messages.get_message('threads_%s' % post.pk)
             post.is_read = post.date <= self.read_date
             post.is_read = post.date <= self.read_date
@@ -46,7 +46,7 @@ class ThreadView(BaseView):
         if not self.tracker.is_read(self.thread):
         if not self.tracker.is_read(self.thread):
             self.tracker.set_read(self.thread, last_post)
             self.tracker.set_read(self.thread, last_post)
             self.tracker.sync()
             self.tracker.sync()
-            
+
     def get_post_actions(self):
     def get_post_actions(self):
         acl = self.request.acl.threads.get_role(self.thread.forum_id)
         acl = self.request.acl.threads.get_role(self.thread.forum_id)
         actions = []
         actions = []
@@ -69,14 +69,14 @@ class ThreadView(BaseView):
         except KeyError:
         except KeyError:
             pass
             pass
         return actions
         return actions
-    
+
     def make_posts_form(self):
     def make_posts_form(self):
         self.posts_form = None
         self.posts_form = None
         list_choices = self.get_post_actions();
         list_choices = self.get_post_actions();
         if (not self.request.user.is_authenticated()
         if (not self.request.user.is_authenticated()
             or not list_choices):
             or not list_choices):
             return
             return
-        
+
         form_fields = {}
         form_fields = {}
         form_fields['list_action'] = forms.ChoiceField(choices=list_choices)
         form_fields['list_action'] = forms.ChoiceField(choices=list_choices)
         list_choices = []
         list_choices = []
@@ -84,9 +84,9 @@ class ThreadView(BaseView):
             list_choices.append((item.pk, None))
             list_choices.append((item.pk, None))
         if not list_choices:
         if not list_choices:
             return
             return
-        form_fields['list_items'] = forms.MultipleChoiceField(choices=list_choices,widget=forms.CheckboxSelectMultiple)
+        form_fields['list_items'] = forms.MultipleChoiceField(choices=list_choices, widget=forms.CheckboxSelectMultiple)
         self.posts_form = type('PostsViewForm', (Form,), form_fields)
         self.posts_form = type('PostsViewForm', (Form,), form_fields)
-     
+
     def handle_posts_form(self):
     def handle_posts_form(self):
         if self.request.method == 'POST' and self.request.POST.get('origin') == 'posts_form':
         if self.request.method == 'POST' and self.request.POST.get('origin') == 'posts_form':
             self.posts_form = self.posts_form(self.request.POST, request=self.request)
             self.posts_form = self.posts_form(self.request.POST, request=self.request)
@@ -113,7 +113,7 @@ class ThreadView(BaseView):
                     self.message = Message(posts_form.non_field_errors()[0], 'error')
                     self.message = Message(posts_form.non_field_errors()[0], 'error')
         else:
         else:
             self.posts_form = self.posts_form(request=self.request)
             self.posts_form = self.posts_form(request=self.request)
-            
+
     def post_action_accept(self, ids):
     def post_action_accept(self, ids):
         accepted = 0
         accepted = 0
         for post in self.posts:
         for post in self.posts:
@@ -123,8 +123,8 @@ class ThreadView(BaseView):
             self.thread.post_set.filter(id__in=ids).update(moderated=False)
             self.thread.post_set.filter(id__in=ids).update(moderated=False)
             self.thread.sync()
             self.thread.sync()
             self.thread.save(force_update=True)
             self.thread.save(force_update=True)
-            self.request.messages.set_flash(Message(_('Selected posts have been accepted and made visible to other members.')), 'success', 'threads')           
-            
+            self.request.messages.set_flash(Message(_('Selected posts have been accepted and made visible to other members.')), 'success', 'threads')
+
     def post_action_merge(self, ids):
     def post_action_merge(self, ids):
         users = []
         users = []
         posts = []
         posts = []
@@ -150,14 +150,14 @@ class ThreadView(BaseView):
         self.forum.sync()
         self.forum.sync()
         self.forum.save(force_update=True)
         self.forum.save(force_update=True)
         self.request.messages.set_flash(Message(_('Selected posts have been merged into one message.')), 'success', 'threads')
         self.request.messages.set_flash(Message(_('Selected posts have been merged into one message.')), 'success', 'threads')
-                    
+
     def post_action_split(self, ids):
     def post_action_split(self, ids):
         for id in ids:
         for id in ids:
             if id == self.thread.start_post_id:
             if id == self.thread.start_post_id:
                 raise forms.ValidationError(_("You cannot split first post from thread."))
                 raise forms.ValidationError(_("You cannot split first post from thread."))
         message = None
         message = None
         if self.request.POST.get('do') == 'split':
         if self.request.POST.get('do') == 'split':
-            form = SplitThreadForm(self.request.POST,request=self.request)
+            form = SplitThreadForm(self.request.POST, request=self.request)
             if form.is_valid():
             if form.is_valid():
                 new_thread = Thread()
                 new_thread = Thread()
                 new_thread.forum = form.cleaned_data['thread_forum']
                 new_thread.forum = form.cleaned_data['thread_forum']
@@ -200,11 +200,11 @@ class ThreadView(BaseView):
                                                       'form': FormLayout(form),
                                                       'form': FormLayout(form),
                                                       },
                                                       },
                                                      context_instance=RequestContext(self.request));
                                                      context_instance=RequestContext(self.request));
-    
+
     def post_action_move(self, ids):
     def post_action_move(self, ids):
         message = None
         message = None
         if self.request.POST.get('do') == 'move':
         if self.request.POST.get('do') == 'move':
-            form = MovePostsForm(self.request.POST,request=self.request,thread=self.thread)
+            form = MovePostsForm(self.request.POST, request=self.request, thread=self.thread)
             if form.is_valid():
             if form.is_valid():
                 thread = form.cleaned_data['thread_url']
                 thread = form.cleaned_data['thread_url']
                 self.thread.post_set.filter(id__in=ids).update(thread=thread, forum=thread.forum, merge=F('merge') + thread.merges + 1)
                 self.thread.post_set.filter(id__in=ids).update(thread=thread, forum=thread.forum, merge=F('merge') + thread.merges + 1)
@@ -237,7 +237,7 @@ class ThreadView(BaseView):
                                                       'form': FormLayout(form),
                                                       'form': FormLayout(form),
                                                       },
                                                       },
                                                      context_instance=RequestContext(self.request));
                                                      context_instance=RequestContext(self.request));
-    
+
     def post_action_undelete(self, ids):
     def post_action_undelete(self, ids):
         undeleted = []
         undeleted = []
         for post in self.posts:
         for post in self.posts:
@@ -250,7 +250,7 @@ class ThreadView(BaseView):
             self.forum.sync()
             self.forum.sync()
             self.forum.save(force_update=True)
             self.forum.save(force_update=True)
             self.request.messages.set_flash(Message(_('Selected posts have been restored.')), 'success', 'threads')
             self.request.messages.set_flash(Message(_('Selected posts have been restored.')), 'success', 'threads')
-    
+
     def post_action_protect(self, ids):
     def post_action_protect(self, ids):
         protected = 0
         protected = 0
         for post in self.posts:
         for post in self.posts:
@@ -259,7 +259,7 @@ class ThreadView(BaseView):
         if protected:
         if protected:
             self.thread.post_set.filter(id__in=ids).update(protected=True)
             self.thread.post_set.filter(id__in=ids).update(protected=True)
             self.request.messages.set_flash(Message(_('Selected posts have been protected from edition.')), 'success', 'threads')
             self.request.messages.set_flash(Message(_('Selected posts have been protected from edition.')), 'success', 'threads')
-      
+
     def post_action_unprotect(self, ids):
     def post_action_unprotect(self, ids):
         unprotected = 0
         unprotected = 0
         for post in self.posts:
         for post in self.posts:
@@ -268,7 +268,7 @@ class ThreadView(BaseView):
         if unprotected:
         if unprotected:
             self.thread.post_set.filter(id__in=ids).update(protected=False)
             self.thread.post_set.filter(id__in=ids).update(protected=False)
             self.request.messages.set_flash(Message(_('Protection from editions has been removed from selected posts.')), 'success', 'threads')
             self.request.messages.set_flash(Message(_('Protection from editions has been removed from selected posts.')), 'success', 'threads')
-    
+
     def post_action_soft(self, ids):
     def post_action_soft(self, ids):
         deleted = []
         deleted = []
         for post in self.posts:
         for post in self.posts:
@@ -283,7 +283,7 @@ class ThreadView(BaseView):
             self.forum.sync()
             self.forum.sync()
             self.forum.save(force_update=True)
             self.forum.save(force_update=True)
             self.request.messages.set_flash(Message(_('Selected posts have been deleted.')), 'success', 'threads')
             self.request.messages.set_flash(Message(_('Selected posts have been deleted.')), 'success', 'threads')
-    
+
     def post_action_hard(self, ids):
     def post_action_hard(self, ids):
         deleted = []
         deleted = []
         for post in self.posts:
         for post in self.posts:
@@ -302,7 +302,7 @@ class ThreadView(BaseView):
             self.forum.sync()
             self.forum.sync()
             self.forum.save(force_update=True)
             self.forum.save(force_update=True)
             self.request.messages.set_flash(Message(_('Selected posts have been deleted.')), 'success', 'threads')
             self.request.messages.set_flash(Message(_('Selected posts have been deleted.')), 'success', 'threads')
-               
+
     def get_thread_actions(self):
     def get_thread_actions(self):
         acl = self.request.acl.threads.get_role(self.thread.forum_id)
         acl = self.request.acl.threads.get_role(self.thread.forum_id)
         actions = []
         actions = []
@@ -335,16 +335,16 @@ class ThreadView(BaseView):
         except KeyError:
         except KeyError:
             pass
             pass
         return actions
         return actions
-    
+
     def make_thread_form(self):
     def make_thread_form(self):
         self.thread_form = None
         self.thread_form = None
         list_choices = self.get_thread_actions();
         list_choices = self.get_thread_actions();
         if (not self.request.user.is_authenticated()
         if (not self.request.user.is_authenticated()
             or not list_choices):
             or not list_choices):
-            return      
+            return
         form_fields = {'thread_action': forms.ChoiceField(choices=list_choices)}
         form_fields = {'thread_action': forms.ChoiceField(choices=list_choices)}
         self.thread_form = type('ThreadViewForm', (Form,), form_fields)
         self.thread_form = type('ThreadViewForm', (Form,), form_fields)
-    
+
     def handle_thread_form(self):
     def handle_thread_form(self):
         if self.request.method == 'POST' and self.request.POST.get('origin') == 'thread_form':
         if self.request.method == 'POST' and self.request.POST.get('origin') == 'thread_form':
             self.thread_form = self.thread_form(self.request.POST, request=self.request)
             self.thread_form = self.thread_form(self.request.POST, request=self.request)
@@ -377,7 +377,7 @@ class ThreadView(BaseView):
         if self.thread.last_post.user:
         if self.thread.last_post.user:
             self.thread.start_post.user.threads += 1
             self.thread.start_post.user.threads += 1
             self.thread.start_post.user.posts += 1
             self.thread.start_post.user.posts += 1
-            self.thread.start_post.user.save(force_update=True)            
+            self.thread.start_post.user.save(force_update=True)
         # Sync forum
         # Sync forum
         self.forum.threads_delta += 1
         self.forum.threads_delta += 1
         self.forum.posts_delta += self.thread.replies + 1
         self.forum.posts_delta += self.thread.replies + 1
@@ -387,26 +387,26 @@ class ThreadView(BaseView):
         self.request.monitor['threads'] = int(self.request.monitor['threads']) + 1
         self.request.monitor['threads'] = int(self.request.monitor['threads']) + 1
         self.request.monitor['posts'] = int(self.request.monitor['posts']) + self.thread.replies + 1
         self.request.monitor['posts'] = int(self.request.monitor['posts']) + self.thread.replies + 1
         self.request.messages.set_flash(Message(_('Thread has been marked as reviewed and made visible to other members.')), 'success', 'threads')
         self.request.messages.set_flash(Message(_('Thread has been marked as reviewed and made visible to other members.')), 'success', 'threads')
-    
+
     def thread_action_annouce(self):
     def thread_action_annouce(self):
         self.thread.weight = 2
         self.thread.weight = 2
         self.thread.save(force_update=True)
         self.thread.save(force_update=True)
         self.request.messages.set_flash(Message(_('Thread has been turned into annoucement.')), 'success', 'threads')
         self.request.messages.set_flash(Message(_('Thread has been turned into annoucement.')), 'success', 'threads')
-    
+
     def thread_action_sticky(self):
     def thread_action_sticky(self):
         self.thread.weight = 1
         self.thread.weight = 1
         self.thread.save(force_update=True)
         self.thread.save(force_update=True)
         self.request.messages.set_flash(Message(_('Thread has been turned into sticky.')), 'success', 'threads')
         self.request.messages.set_flash(Message(_('Thread has been turned into sticky.')), 'success', 'threads')
-    
+
     def thread_action_normal(self):
     def thread_action_normal(self):
         self.thread.weight = 0
         self.thread.weight = 0
         self.thread.save(force_update=True)
         self.thread.save(force_update=True)
         self.request.messages.set_flash(Message(_('Thread weight has been changed to normal.')), 'success', 'threads')
         self.request.messages.set_flash(Message(_('Thread weight has been changed to normal.')), 'success', 'threads')
-    
+
     def thread_action_move(self):
     def thread_action_move(self):
         message = None
         message = None
         if self.request.POST.get('do') == 'move':
         if self.request.POST.get('do') == 'move':
-            form = MoveThreadsForm(self.request.POST,request=self.request,forum=self.forum)
+            form = MoveThreadsForm(self.request.POST, request=self.request, forum=self.forum)
             if form.is_valid():
             if form.is_valid():
                 new_forum = form.cleaned_data['new_forum']
                 new_forum = form.cleaned_data['new_forum']
                 self.thread.forum = new_forum
                 self.thread.forum = new_forum
@@ -420,7 +420,7 @@ class ThreadView(BaseView):
                 return None
                 return None
             message = Message(form.non_field_errors()[0], 'error')
             message = Message(form.non_field_errors()[0], 'error')
         else:
         else:
-            form = MoveThreadsForm(request=self.request,forum=self.forum)
+            form = MoveThreadsForm(request=self.request, forum=self.forum)
         return self.request.theme.render_to_response('threads/move.html',
         return self.request.theme.render_to_response('threads/move.html',
                                                      {
                                                      {
                                                       'message': message,
                                                       'message': message,
@@ -430,19 +430,19 @@ class ThreadView(BaseView):
                                                       'form': FormLayout(form),
                                                       'form': FormLayout(form),
                                                       },
                                                       },
                                                      context_instance=RequestContext(self.request));
                                                      context_instance=RequestContext(self.request));
-        
+
     def thread_action_open(self):
     def thread_action_open(self):
         self.thread.closed = False
         self.thread.closed = False
         self.thread.save(force_update=True)
         self.thread.save(force_update=True)
         self.thread.last_post.set_checkpoint(self.request, 'opened')
         self.thread.last_post.set_checkpoint(self.request, 'opened')
         self.request.messages.set_flash(Message(_('Thread has been opened.')), 'success', 'threads')
         self.request.messages.set_flash(Message(_('Thread has been opened.')), 'success', 'threads')
-        
+
     def thread_action_close(self):
     def thread_action_close(self):
         self.thread.closed = True
         self.thread.closed = True
         self.thread.save(force_update=True)
         self.thread.save(force_update=True)
         self.thread.last_post.set_checkpoint(self.request, 'closed')
         self.thread.last_post.set_checkpoint(self.request, 'closed')
         self.request.messages.set_flash(Message(_('Thread has been closed.')), 'success', 'threads')
         self.request.messages.set_flash(Message(_('Thread has been closed.')), 'success', 'threads')
-    
+
     def thread_action_undelete(self):
     def thread_action_undelete(self):
         # Update thread
         # Update thread
         self.thread.deleted = False
         self.thread.deleted = False
@@ -460,7 +460,7 @@ class ThreadView(BaseView):
         self.request.monitor['threads'] = int(self.request.monitor['threads']) + 1
         self.request.monitor['threads'] = int(self.request.monitor['threads']) + 1
         self.request.monitor['posts'] = int(self.request.monitor['posts']) + self.thread.replies + 1
         self.request.monitor['posts'] = int(self.request.monitor['posts']) + self.thread.replies + 1
         self.request.messages.set_flash(Message(_('Thread has been undeleted.')), 'success', 'threads')
         self.request.messages.set_flash(Message(_('Thread has been undeleted.')), 'success', 'threads')
-    
+
     def thread_action_soft(self):
     def thread_action_soft(self):
         # Update thread
         # Update thread
         self.thread.deleted = True
         self.thread.deleted = True
@@ -477,8 +477,8 @@ class ThreadView(BaseView):
         # Update monitor
         # Update monitor
         self.request.monitor['threads'] = int(self.request.monitor['threads']) - 1
         self.request.monitor['threads'] = int(self.request.monitor['threads']) - 1
         self.request.monitor['posts'] = int(self.request.monitor['posts']) - self.thread.replies - 1
         self.request.monitor['posts'] = int(self.request.monitor['posts']) - self.thread.replies - 1
-        self.request.messages.set_flash(Message(_('Thread has been deleted.')), 'success', 'threads')        
-    
+        self.request.messages.set_flash(Message(_('Thread has been deleted.')), 'success', 'threads')
+
     def thread_action_hard(self):
     def thread_action_hard(self):
         # Delete thread
         # Delete thread
         self.thread.delete()
         self.thread.delete()
@@ -490,7 +490,7 @@ class ThreadView(BaseView):
         self.request.monitor['posts'] = int(self.request.monitor['posts']) - self.thread.replies - 1
         self.request.monitor['posts'] = int(self.request.monitor['posts']) - self.thread.replies - 1
         self.request.messages.set_flash(Message(_('Thread "%(thread)s" has been deleted.') % {'thread': self.thread.name}), 'success', 'threads')
         self.request.messages.set_flash(Message(_('Thread "%(thread)s" has been deleted.') % {'thread': self.thread.name}), 'success', 'threads')
         return redirect(reverse('forum', kwargs={'forum': self.forum.pk, 'slug': self.forum.slug}))
         return redirect(reverse('forum', kwargs={'forum': self.forum.pk, 'slug': self.forum.slug}))
-    
+
     def __call__(self, request, slug=None, thread=None, page=0):
     def __call__(self, request, slug=None, thread=None, page=0):
         self.request = request
         self.request = request
         self.pagination = None
         self.pagination = None
@@ -531,4 +531,4 @@ class ThreadView(BaseView):
                                                  'thread_form': FormFields(self.thread_form).fields if self.thread_form else None,
                                                  'thread_form': FormFields(self.thread_form).fields if self.thread_form else None,
                                                  'posts_form': FormFields(self.posts_form).fields if self.posts_form else None,
                                                  'posts_form': FormFields(self.posts_form).fields if self.posts_form else None,
                                                  },
                                                  },
-                                                context_instance=RequestContext(request));
+                                                context_instance=RequestContext(request));

+ 2 - 2
misago/timezones/__init__.py

@@ -83,5 +83,5 @@ def tzlist():
             else:
             else:
                 ready_list.append((tz[0], tz[1]))
                 ready_list.append((tz[0], tz[1]))
         else:
         else:
-           ready_list.append((tz[0], tz[1])) 
-    return tuple(ready_list)
+           ready_list.append((tz[0], tz[1]))
+    return tuple(ready_list)

+ 3 - 3
misago/tos/fixtures.py

@@ -37,7 +37,7 @@ settings_fixtures = (
 
 
 def load_fixtures():
 def load_fixtures():
     load_settings_fixture(settings_fixtures)
     load_settings_fixture(settings_fixtures)
-    
-    
+
+
 def update_fixtures():
 def update_fixtures():
-    update_settings_fixture(settings_fixtures)
+    update_settings_fixture(settings_fixtures)

+ 1 - 1
misago/tos/views.py

@@ -5,4 +5,4 @@ def forum_tos(request):
     if request.settings.tos_url or not request.settings.tos_content:
     if request.settings.tos_url or not request.settings.tos_content:
         return error404(request)
         return error404(request)
     return request.theme.render_to_response('forum_tos.html',
     return request.theme.render_to_response('forum_tos.html',
-                                            context_instance=RequestContext(request));
+                                            context_instance=RequestContext(request));

+ 2 - 2
misago/urls.py

@@ -26,7 +26,7 @@ if ADMIN_PATH:
     urlpatterns += patterns('',
     urlpatterns += patterns('',
         url(r'^' + ADMIN_PATH, include(site.discover())),
         url(r'^' + ADMIN_PATH, include(site.discover())),
     )
     )
-    
+
 # Include static and media patterns in DEBUG
 # Include static and media patterns in DEBUG
 if settings.DEBUG:
 if settings.DEBUG:
     urlpatterns += patterns('django.views.static',
     urlpatterns += patterns('django.views.static',
@@ -35,4 +35,4 @@ if settings.DEBUG:
 
 
 # Set error handlers
 # Set error handlers
 handler403 = 'misago.views.error403'
 handler403 = 'misago.views.error403'
-handler404 = 'misago.views.error404'
+handler404 = 'misago.views.error404'

+ 17 - 17
misago/usercp/acl.py

@@ -7,11 +7,11 @@ from misago.forms import YesNoSwitch
 
 
 def make_form(request, role, form):
 def make_form(request, role, form):
     if role.token != 'guest':
     if role.token != 'guest':
-        form.base_fields['name_changes_allowed'] = forms.IntegerField(min_value=0,initial=1)
-        form.base_fields['changes_expire'] = forms.IntegerField(min_value=0,initial=0)
-        form.base_fields['can_use_signature'] = forms.BooleanField(widget=YesNoSwitch,initial=False,required=False)
-        form.base_fields['allow_signature_links'] = forms.BooleanField(widget=YesNoSwitch,initial=False,required=False)
-        form.base_fields['allow_signature_images'] = forms.BooleanField(widget=YesNoSwitch,initial=False,required=False)
+        form.base_fields['name_changes_allowed'] = forms.IntegerField(min_value=0, initial=1)
+        form.base_fields['changes_expire'] = forms.IntegerField(min_value=0, initial=0)
+        form.base_fields['can_use_signature'] = forms.BooleanField(widget=YesNoSwitch, initial=False, required=False)
+        form.base_fields['allow_signature_links'] = forms.BooleanField(widget=YesNoSwitch, initial=False, required=False)
+        form.base_fields['allow_signature_images'] = forms.BooleanField(widget=YesNoSwitch, initial=False, required=False)
         form.layout.append((
         form.layout.append((
                             _("User Profile"),
                             _("User Profile"),
                             (
                             (
@@ -24,34 +24,34 @@ def make_form(request, role, form):
                             ))
                             ))
 
 
 
 
-class UserCPACL(BaseACL):        
+class UserCPACL(BaseACL):
     def show_username_change(self):
     def show_username_change(self):
         return self.acl['name_changes_allowed'] > 0
         return self.acl['name_changes_allowed'] > 0
-    
+
     def changes_expire(self):
     def changes_expire(self):
         return self.acl['changes_expire'] > 0
         return self.acl['changes_expire'] > 0
-    
+
     def changes_left(self, user):
     def changes_left(self, user):
         if not self.acl['name_changes_allowed']:
         if not self.acl['name_changes_allowed']:
             return 0
             return 0
-        
+
         if self.acl['changes_expire']:
         if self.acl['changes_expire']:
             changes_left = self.acl['name_changes_allowed'] - user.namechanges.filter(
             changes_left = self.acl['name_changes_allowed'] - user.namechanges.filter(
                                                     date__gte=timezone.now() - timedelta(days=self.acl['changes_expire']),
                                                     date__gte=timezone.now() - timedelta(days=self.acl['changes_expire']),
                                                     ).count()
                                                     ).count()
         else:
         else:
             changes_left = self.acl['name_changes_allowed'] - user.namechanges.all().count()
             changes_left = self.acl['name_changes_allowed'] - user.namechanges.all().count()
-            
+
         if changes_left:
         if changes_left:
             return changes_left
             return changes_left
         return 0
         return 0
-    
+
     def can_use_signature(self):
     def can_use_signature(self):
         return self.acl['signature']
         return self.acl['signature']
-    
+
     def allow_signature_links(self):
     def allow_signature_links(self):
         return self.acl['signature_links']
         return self.acl['signature_links']
-    
+
     def allow_signature_images(self):
     def allow_signature_images(self):
         return self.acl['signature_images']
         return self.acl['signature_images']
 
 
@@ -63,19 +63,19 @@ def build(acl, roles):
     acl.usercp.acl['signature'] = False
     acl.usercp.acl['signature'] = False
     acl.usercp.acl['signature_links'] = False
     acl.usercp.acl['signature_links'] = False
     acl.usercp.acl['signature_images'] = False
     acl.usercp.acl['signature_images'] = False
-    
+
     for role in roles:
     for role in roles:
         if 'name_changes_allowed' in role and role['name_changes_allowed'] > acl.usercp.acl['name_changes_allowed']:
         if 'name_changes_allowed' in role and role['name_changes_allowed'] > acl.usercp.acl['name_changes_allowed']:
             acl.usercp.acl['name_changes_allowed'] = role['name_changes_allowed']
             acl.usercp.acl['name_changes_allowed'] = role['name_changes_allowed']
 
 
         if 'changes_expire' in role and role['changes_expire'] > acl.usercp.acl['changes_expire']:
         if 'changes_expire' in role and role['changes_expire'] > acl.usercp.acl['changes_expire']:
             acl.usercp.acl['changes_expire'] = role['changes_expire']
             acl.usercp.acl['changes_expire'] = role['changes_expire']
-            
+
         if 'can_use_signature' in role and role['can_use_signature'] > acl.usercp.acl['signature']:
         if 'can_use_signature' in role and role['can_use_signature'] > acl.usercp.acl['signature']:
             acl.usercp.acl['signature'] = role['can_use_signature']
             acl.usercp.acl['signature'] = role['can_use_signature']
-            
+
         if 'allow_signature_links' in role and role['allow_signature_links'] > acl.usercp.acl['signature_links']:
         if 'allow_signature_links' in role and role['allow_signature_links'] > acl.usercp.acl['signature_links']:
             acl.usercp.acl['signature_links'] = role['allow_signature_links']
             acl.usercp.acl['signature_links'] = role['allow_signature_links']
-            
+
         if 'allow_signature_images' in role and role['allow_signature_images'] > acl.usercp.acl['signature_images']:
         if 'allow_signature_images' in role and role['allow_signature_images'] > acl.usercp.acl['signature_images']:
             acl.usercp.acl['signature_images'] = role['allow_signature_images']
             acl.usercp.acl['signature_images'] = role['allow_signature_images']

+ 4 - 4
misago/usercp/avatar/forms.py

@@ -8,7 +8,7 @@ from misago.forms import Form
 class UploadAvatarForm(Form):
 class UploadAvatarForm(Form):
     avatar_upload = forms.ImageField(error_messages={'invalid_image': _("Uploaded file is not correct image.")})
     avatar_upload = forms.ImageField(error_messages={'invalid_image': _("Uploaded file is not correct image.")})
     error_source = 'avatar_upload'
     error_source = 'avatar_upload'
-    
+
     layout = [
     layout = [
               [
               [
                None,
                None,
@@ -17,9 +17,9 @@ class UploadAvatarForm(Form):
                 ],
                 ],
                ],
                ],
               ]
               ]
-    
+
     def clean_avatar_upload(self):
     def clean_avatar_upload(self):
-        image = self.cleaned_data.get('avatar_upload',False)
+        image = self.cleaned_data.get('avatar_upload', False)
         if image:
         if image:
             if image._size > self.request.settings.upload_limit * 1024:
             if image._size > self.request.settings.upload_limit * 1024:
                 if self.request.settings.upload_limit > 1024:
                 if self.request.settings.upload_limit > 1024:
@@ -29,4 +29,4 @@ class UploadAvatarForm(Form):
                 raise ValidationError(_("Avatar image cannot be larger than %(limit)s.") % {'limit': limit})
                 raise ValidationError(_("Avatar image cannot be larger than %(limit)s.") % {'limit': limit})
         else:
         else:
             raise ValidationError(_("Couldn't read uploaded image"))
             raise ValidationError(_("Couldn't read uploaded image"))
-        return image
+        return image

+ 1 - 1
misago/usercp/avatar/urls.py

@@ -7,4 +7,4 @@ urlpatterns = patterns('misago.usercp.avatar.views',
     url(r'^avatar/upload/crop/$', 'crop', name="usercp_avatar_upload_crop", kwargs={'upload': True}),
     url(r'^avatar/upload/crop/$', 'crop', name="usercp_avatar_upload_crop", kwargs={'upload': True}),
     url(r'^avatar/crop/$', 'crop', name="usercp_avatar_crop"),
     url(r'^avatar/crop/$', 'crop', name="usercp_avatar_crop"),
     url(r'^avatar/gravatar/$', 'gravatar', name="usercp_avatar_gravatar"),
     url(r'^avatar/gravatar/$', 'gravatar', name="usercp_avatar_gravatar"),
-)
+)

+ 1 - 1
misago/usercp/avatar/usercp.py

@@ -1,4 +1,4 @@
 from django.utils.translation import ugettext_lazy as _
 from django.utils.translation import ugettext_lazy as _
 
 
 def register_usercp_extension(request):
 def register_usercp_extension(request):
-    return (('usercp_avatar', _('Change Avatar')),)
+    return (('usercp_avatar', _('Change Avatar')),)

+ 15 - 15
misago/usercp/avatar/views.py

@@ -58,7 +58,7 @@ def gravatar(request):
 def gallery(request):
 def gallery(request):
     if not 'gallery' in request.settings.avatars_types:
     if not 'gallery' in request.settings.avatars_types:
         return error404(request)
         return error404(request)
-    
+
     allowed_avatars = []
     allowed_avatars = []
     galleries = []
     galleries = []
     for directory in path(settings.STATICFILES_DIRS[0]).joinpath('avatars').dirs():
     for directory in path(settings.STATICFILES_DIRS[0]).joinpath('avatars').dirs():
@@ -72,11 +72,11 @@ def gallery(request):
                 gallery['avatars'].append('/'.join(path(item).splitall()[-2:]))
                 gallery['avatars'].append('/'.join(path(item).splitall()[-2:]))
             galleries.append(gallery)
             galleries.append(gallery)
             allowed_avatars += gallery['avatars']
             allowed_avatars += gallery['avatars']
-    
+
     if not allowed_avatars:
     if not allowed_avatars:
         request.messages.set_flash(Message(_("No avatars are avaiable.")), 'info', 'usercp_avatar')
         request.messages.set_flash(Message(_("No avatars are avaiable.")), 'info', 'usercp_avatar')
         return redirect(reverse('usercp_avatar'))
         return redirect(reverse('usercp_avatar'))
-    
+
     message = request.messages.get_message('usercp_avatar')
     message = request.messages.get_message('usercp_avatar')
     if request.method == 'POST':
     if request.method == 'POST':
         if request.csrf.request_secure(request):
         if request.csrf.request_secure(request):
@@ -91,7 +91,7 @@ def gallery(request):
             message = Message(_("Selected Avatar is incorrect."), 'error')
             message = Message(_("Selected Avatar is incorrect."), 'error')
         else:
         else:
             message = Message(_("Request authorisation is invalid."), 'error')
             message = Message(_("Request authorisation is invalid."), 'error')
-    
+
     return request.theme.render_to_response('usercp/avatar_gallery.html',
     return request.theme.render_to_response('usercp/avatar_gallery.html',
                                             context_instance=RequestContext(request, {
                                             context_instance=RequestContext(request, {
                                               'message': message,
                                               'message': message,
@@ -151,12 +151,12 @@ def upload(request):
             except ValidationError:
             except ValidationError:
                 request.user.delete_avatar()
                 request.user.delete_avatar()
                 request.user.default_avatar(request.settings)
                 request.user.default_avatar(request.settings)
-                message = Message(_("Only gif, jpeg and png files are allowed for member avatars."), 'error') 
+                message = Message(_("Only gif, jpeg and png files are allowed for member avatars."), 'error')
         else:
         else:
-            message = Message(form.non_field_errors()[0], 'error')          
+            message = Message(form.non_field_errors()[0], 'error')
     else:
     else:
         form = UploadAvatarForm(request=request)
         form = UploadAvatarForm(request=request)
-        
+
     return request.theme.render_to_response('usercp/avatar_upload.html',
     return request.theme.render_to_response('usercp/avatar_upload.html',
                                             context_instance=RequestContext(request, {
                                             context_instance=RequestContext(request, {
                                               'message': message,
                                               'message': message,
@@ -170,11 +170,11 @@ def upload(request):
 def crop(request, upload=False):
 def crop(request, upload=False):
     if upload and (not request.user.avatar_temp or not 'upload' in request.settings.avatars_types):
     if upload and (not request.user.avatar_temp or not 'upload' in request.settings.avatars_types):
         return error404(request)
         return error404(request)
-    
+
     if not upload and request.user.avatar_type != 'upload':
     if not upload and request.user.avatar_type != 'upload':
         request.messages.set_flash(Message(_("Crop Avatar option is avaiable only when you use uploaded image as your avatar.")), 'error', 'usercp_avatar')
         request.messages.set_flash(Message(_("Crop Avatar option is avaiable only when you use uploaded image as your avatar.")), 'error', 'usercp_avatar')
         return redirect(reverse('usercp_avatar'))
         return redirect(reverse('usercp_avatar'))
-    
+
     message = request.messages.get_message('usercp_avatar')
     message = request.messages.get_message('usercp_avatar')
     if request.method == 'POST':
     if request.method == 'POST':
         if request.csrf.request_secure(request):
         if request.csrf.request_secure(request):
@@ -185,13 +185,13 @@ def crop(request, upload=False):
                 else:
                 else:
                     source = Image.open(image_path + request.user.avatar_original)
                     source = Image.open(image_path + request.user.avatar_original)
                 width, height = source.size
                 width, height = source.size
-                
+
                 aspect = float(width) / float(request.POST['crop_b'])
                 aspect = float(width) / float(request.POST['crop_b'])
                 crop_x = int(aspect * float(request.POST['crop_x']))
                 crop_x = int(aspect * float(request.POST['crop_x']))
                 crop_y = int(aspect * float(request.POST['crop_y']))
                 crop_y = int(aspect * float(request.POST['crop_y']))
                 crop_w = int(aspect * float(request.POST['crop_w']))
                 crop_w = int(aspect * float(request.POST['crop_w']))
                 crop = source.crop((crop_x, crop_y, crop_x + crop_w, crop_y + crop_w))
                 crop = source.crop((crop_x, crop_y, crop_x + crop_w, crop_y + crop_w))
-                           
+
                 if upload:
                 if upload:
                     image_name, image_extension = path(request.user.avatar_temp).splitext()
                     image_name, image_extension = path(request.user.avatar_temp).splitext()
                 else:
                 else:
@@ -200,7 +200,7 @@ def crop(request, upload=False):
                 resizeimage(crop, settings.AVATAR_SIZES[0], image_path + image_name, info=source.info, format=source.format)
                 resizeimage(crop, settings.AVATAR_SIZES[0], image_path + image_name, info=source.info, format=source.format)
                 for size in settings.AVATAR_SIZES[1:]:
                 for size in settings.AVATAR_SIZES[1:]:
                     resizeimage(crop, size, image_path + str(size) + '_' + image_name, info=source.info, format=source.format)
                     resizeimage(crop, size, image_path + str(size) + '_' + image_name, info=source.info, format=source.format)
-                
+
                 request.user.delete_avatar_image()
                 request.user.delete_avatar_image()
                 if upload:
                 if upload:
                     request.user.delete_avatar_original()
                     request.user.delete_avatar_original()
@@ -216,8 +216,8 @@ def crop(request, upload=False):
                 message = Message(_("Form contains errors."), 'error')
                 message = Message(_("Form contains errors."), 'error')
         else:
         else:
             message = Message(_("Request authorisation is invalid."), 'error')
             message = Message(_("Request authorisation is invalid."), 'error')
-    
-    
+
+
     return request.theme.render_to_response('usercp/avatar_crop.html',
     return request.theme.render_to_response('usercp/avatar_crop.html',
                                             context_instance=RequestContext(request, {
                                             context_instance=RequestContext(request, {
                                               'message': message,
                                               'message': message,
@@ -225,4 +225,4 @@ def crop(request, upload=False):
                                               'avatar_size': settings.AVATAR_SIZES[0],
                                               'avatar_size': settings.AVATAR_SIZES[0],
                                               'source': 'avatars/%s' % (request.user.avatar_temp if upload else request.user.avatar_original),
                                               'source': 'avatars/%s' % (request.user.avatar_temp if upload else request.user.avatar_original),
                                               'tab': 'avatar',
                                               'tab': 'avatar',
-                                            }));
+                                            }));

+ 1 - 1
misago/usercp/blocked/urls.py

@@ -2,4 +2,4 @@ from django.conf.urls import patterns, url
 
 
 urlpatterns = patterns('misago.usercp.blocked.views',
 urlpatterns = patterns('misago.usercp.blocked.views',
     url(r'^blocked/$', 'blocked', name="usercp_blocked"),
     url(r'^blocked/$', 'blocked', name="usercp_blocked"),
-)
+)

+ 1 - 1
misago/usercp/blocked/usercp.py

@@ -1,4 +1,4 @@
 from django.utils.translation import ugettext_lazy as _
 from django.utils.translation import ugettext_lazy as _
 
 
 def register_usercp_extension(request):
 def register_usercp_extension(request):
-    return (('usercp_blocked', _('Blocked Members')),)
+    return (('usercp_blocked', _('Blocked Members')),)

+ 1 - 1
misago/usercp/blocked/views.py

@@ -6,4 +6,4 @@ def blocked(request):
     return request.theme.render_to_response('usercp/blocked.html',
     return request.theme.render_to_response('usercp/blocked.html',
                                             context_instance=RequestContext(request, {
                                             context_instance=RequestContext(request, {
                                               'tab': 'blocked',
                                               'tab': 'blocked',
-                                             }));
+                                             }));

+ 9 - 9
misago/usercp/credentials/forms.py

@@ -7,10 +7,10 @@ from misago.users.models import User
 from misago.users.validators import validate_password, validate_email
 from misago.users.validators import validate_password, validate_email
 
 
 class CredentialsChangeForm(Form):
 class CredentialsChangeForm(Form):
-    new_email = forms.EmailField(max_length=255,required=False)
-    new_password = forms.CharField(max_length=255,widget=forms.PasswordInput,required=False)
-    current_password = forms.CharField(max_length=255,widget=forms.PasswordInput)
-    
+    new_email = forms.EmailField(max_length=255, required=False)
+    new_password = forms.CharField(max_length=255, widget=forms.PasswordInput, required=False)
+    current_password = forms.CharField(max_length=255, widget=forms.PasswordInput)
+
     layout = [
     layout = [
               (
               (
                None,
                None,
@@ -21,7 +21,7 @@ class CredentialsChangeForm(Form):
                 ]
                 ]
                ),
                ),
               ]
               ]
-        
+
     def clean_new_email(self):
     def clean_new_email(self):
         if self.cleaned_data['new_email']:
         if self.cleaned_data['new_email']:
             new_hash = hashlib.md5(self.cleaned_data['new_email'].lower()).hexdigest()
             new_hash = hashlib.md5(self.cleaned_data['new_email'].lower()).hexdigest()
@@ -34,19 +34,19 @@ class CredentialsChangeForm(Form):
                 pass
                 pass
             validate_email(self.cleaned_data['new_email'])
             validate_email(self.cleaned_data['new_email'])
         return self.cleaned_data['new_email'].lower()
         return self.cleaned_data['new_email'].lower()
-        
+
     def clean_new_password(self):
     def clean_new_password(self):
         if self.cleaned_data['new_password']:
         if self.cleaned_data['new_password']:
             validate_password(self.cleaned_data['new_password'])
             validate_password(self.cleaned_data['new_password'])
         return self.cleaned_data['new_password']
         return self.cleaned_data['new_password']
-        
+
     def clean_current_password(self):
     def clean_current_password(self):
         if not self.request.user.check_password(self.cleaned_data['current_password']):
         if not self.request.user.check_password(self.cleaned_data['current_password']):
             raise ValidationError(_("You have entered wrong password."))
             raise ValidationError(_("You have entered wrong password."))
         return ''
         return ''
-        
+
     def clean(self):
     def clean(self):
         cleaned_data = super(CredentialsChangeForm, self).clean()
         cleaned_data = super(CredentialsChangeForm, self).clean()
         if not cleaned_data['new_email'] and not cleaned_data['new_password']:
         if not cleaned_data['new_email'] and not cleaned_data['new_password']:
             raise ValidationError(_("You have to enter either new e-mail address or new password."))
             raise ValidationError(_("You have to enter either new e-mail address or new password."))
-        return cleaned_data
+        return cleaned_data

+ 1 - 1
misago/usercp/credentials/urls.py

@@ -3,4 +3,4 @@ from django.conf.urls import patterns, url
 urlpatterns = patterns('misago.usercp.credentials.views',
 urlpatterns = patterns('misago.usercp.credentials.views',
     url(r'^credentials/$', 'credentials', name="usercp_credentials"),
     url(r'^credentials/$', 'credentials', name="usercp_credentials"),
     url(r'^credentials/activate/(?P<token>[a-zA-Z0-9]+)/$', 'activate', name="usercp_credentials_activate"),
     url(r'^credentials/activate/(?P<token>[a-zA-Z0-9]+)/$', 'activate', name="usercp_credentials_activate"),
-)
+)

+ 1 - 1
misago/usercp/credentials/usercp.py

@@ -1,4 +1,4 @@
 from django.utils.translation import ugettext_lazy as _
 from django.utils.translation import ugettext_lazy as _
 
 
 def register_usercp_extension(request):
 def register_usercp_extension(request):
-    return (('usercp_credentials', _('Change E-mail or Password')),)
+    return (('usercp_credentials', _('Change E-mail or Password')),)

+ 3 - 4
misago/usercp/credentials/views.py

@@ -38,7 +38,7 @@ def credentials(request):
         message = Message(form.non_field_errors()[0], 'error')
         message = Message(form.non_field_errors()[0], 'error')
     else:
     else:
         form = CredentialsChangeForm(request=request)
         form = CredentialsChangeForm(request=request)
-        
+
     return request.theme.render_to_response('usercp/credentials.html',
     return request.theme.render_to_response('usercp/credentials.html',
                                             context_instance=RequestContext(request, {
                                             context_instance=RequestContext(request, {
                                               'message': message,
                                               'message': message,
@@ -52,12 +52,12 @@ def activate(request, token):
     new_credentials = request.session.get('new_credentials')
     new_credentials = request.session.get('new_credentials')
     if not new_credentials or new_credentials['token'] != token:
     if not new_credentials or new_credentials['token'] != token:
         return error404(request)
         return error404(request)
-    
+
     if new_credentials['new_email']:
     if new_credentials['new_email']:
         request.user.set_email(new_credentials['new_email'])
         request.user.set_email(new_credentials['new_email'])
     if new_credentials['new_password']:
     if new_credentials['new_password']:
         request.user.set_password(new_credentials['new_password'])
         request.user.set_password(new_credentials['new_password'])
-        
+
     try:
     try:
         request.user.full_clean()
         request.user.full_clean()
         request.user.save(force_update=True)
         request.user.save(force_update=True)
@@ -70,4 +70,3 @@ def activate(request, token):
     except ValidationError:
     except ValidationError:
         request.messages.set_flash(Message(_("Your new credentials have been invalidated. Please try again.")), 'error', 'usercp_credentials')
         request.messages.set_flash(Message(_("Your new credentials have been invalidated. Please try again.")), 'error', 'usercp_credentials')
         return redirect(reverse('usercp_credentials'))
         return redirect(reverse('usercp_credentials'))
-    

+ 3 - 3
misago/usercp/fixtures.py

@@ -41,7 +41,7 @@ settings_fixtures = (
 
 
 def load_fixtures():
 def load_fixtures():
     load_settings_fixture(settings_fixtures)
     load_settings_fixture(settings_fixtures)
-    
-    
+
+
 def update_fixtures():
 def update_fixtures():
-    update_settings_fixture(settings_fixtures)
+    update_settings_fixture(settings_fixtures)

+ 1 - 1
misago/usercp/models.py

@@ -3,4 +3,4 @@ from django.db import models
 class UsernameChange(models.Model):
 class UsernameChange(models.Model):
     user = models.ForeignKey('users.User', related_name='namechanges')
     user = models.ForeignKey('users.User', related_name='namechanges')
     date = models.DateTimeField()
     date = models.DateTimeField()
-    old_username = models.CharField(max_length=255)
+    old_username = models.CharField(max_length=255)

+ 2 - 2
misago/usercp/options/forms.py

@@ -12,7 +12,7 @@ class UserForumOptionsForm(Form):
                                                (1, _("Show my presence to people I follow")),
                                                (1, _("Show my presence to people I follow")),
                                                (2, _("Show my presence to nobody")),
                                                (2, _("Show my presence to nobody")),
                                                ))
                                                ))
-    
+
     layout = (
     layout = (
               (
               (
                _("Forum Options"),
                _("Forum Options"),
@@ -22,4 +22,4 @@ class UserForumOptionsForm(Form):
                 ('newsletters', {'label': _("Newsletters"), 'help_text': _("On occasion board administrator may want to send e-mail message to multiple members."), 'inline': _("Yes, I want to subscribe forum newsletter")}),
                 ('newsletters', {'label': _("Newsletters"), 'help_text': _("On occasion board administrator may want to send e-mail message to multiple members."), 'inline': _("Yes, I want to subscribe forum newsletter")}),
                 )
                 )
                ),
                ),
-              )
+              )

+ 1 - 1
misago/usercp/options/urls.py

@@ -2,4 +2,4 @@ from django.conf.urls import patterns, url
 
 
 urlpatterns = patterns('misago.usercp.options.views',
 urlpatterns = patterns('misago.usercp.options.views',
     url(r'^$', 'options', name="usercp"),
     url(r'^$', 'options', name="usercp"),
-)
+)

+ 1 - 1
misago/usercp/options/usercp.py

@@ -1,4 +1,4 @@
 from django.utils.translation import ugettext_lazy as _
 from django.utils.translation import ugettext_lazy as _
 
 
 def register_usercp_extension(request):
 def register_usercp_extension(request):
-    return (('usercp', _('Forum Options')),)
+    return (('usercp', _('Forum Options')),)

+ 4 - 4
misago/usercp/options/views.py

@@ -8,7 +8,7 @@ from misago.usercp.options.forms import UserForumOptionsForm
 from misago.usercp.template import RequestContext
 from misago.usercp.template import RequestContext
 
 
 
 
-@block_guest   
+@block_guest
 def options(request):
 def options(request):
     message = request.messages.get_message('usercp_options')
     message = request.messages.get_message('usercp_options')
     if request.method == 'POST':
     if request.method == 'POST':
@@ -22,15 +22,15 @@ def options(request):
             return redirect(reverse('usercp'))
             return redirect(reverse('usercp'))
         message = Message(form.non_field_errors()[0], 'error')
         message = Message(form.non_field_errors()[0], 'error')
     else:
     else:
-        form = UserForumOptionsForm(request=request,initial={
+        form = UserForumOptionsForm(request=request, initial={
                                                              'newsletters': request.user.receive_newsletters,
                                                              'newsletters': request.user.receive_newsletters,
                                                              'hide_activity': request.user.hide_activity,
                                                              'hide_activity': request.user.hide_activity,
                                                              'timezone': request.user.timezone,
                                                              'timezone': request.user.timezone,
                                                              })
                                                              })
-    
+
     return request.theme.render_to_response('usercp/options.html',
     return request.theme.render_to_response('usercp/options.html',
                                             context_instance=RequestContext(request, {
                                             context_instance=RequestContext(request, {
                                               'message': message,
                                               'message': message,
                                               'tab': 'usercp',
                                               'tab': 'usercp',
                                               'form': FormLayout(form)
                                               'form': FormLayout(form)
-                                             }));
+                                             }));

+ 3 - 3
misago/usercp/signature/forms.py

@@ -4,8 +4,8 @@ from misago.forms import Form
 
 
 
 
 class SignatureForm(Form):
 class SignatureForm(Form):
-    signature = forms.CharField(widget=forms.Textarea,required=False)
-    
+    signature = forms.CharField(widget=forms.Textarea, required=False)
+
     layout = (
     layout = (
               (
               (
                None,
                None,
@@ -13,4 +13,4 @@ class SignatureForm(Form):
                 ('signature', {'label': _("Your Signature"), 'attrs': {'rows': 10}}),
                 ('signature', {'label': _("Your Signature"), 'attrs': {'rows': 10}}),
                 )
                 )
                ),
                ),
-              )
+              )

+ 1 - 1
misago/usercp/signature/urls.py

@@ -2,4 +2,4 @@ from django.conf.urls import patterns, url
 
 
 urlpatterns = patterns('misago.usercp.signature.views',
 urlpatterns = patterns('misago.usercp.signature.views',
     url(r'^signature/$', 'signature', name="usercp_signature"),
     url(r'^signature/$', 'signature', name="usercp_signature"),
-)
+)

+ 1 - 1
misago/usercp/signature/usercp.py

@@ -1,4 +1,4 @@
 from django.utils.translation import ugettext_lazy as _
 from django.utils.translation import ugettext_lazy as _
 
 
 def register_usercp_extension(request):
 def register_usercp_extension(request):
-    return (('usercp_signature', _('Edit Signature')),)
+    return (('usercp_signature', _('Edit Signature')),)

+ 3 - 3
misago/usercp/signature/views.py

@@ -17,7 +17,7 @@ def signature(request):
                                                 context_instance=RequestContext(request, {
                                                 context_instance=RequestContext(request, {
                                                   'tab': 'signature',
                                                   'tab': 'signature',
                                                  }));
                                                  }));
-    
+
     siggy_text = ''
     siggy_text = ''
     message = request.messages.get_message('usercp_signature')
     message = request.messages.get_message('usercp_signature')
     if request.method == 'POST':
     if request.method == 'POST':
@@ -36,10 +36,10 @@ def signature(request):
             message = Message(form.non_field_errors()[0], 'error')
             message = Message(form.non_field_errors()[0], 'error')
     else:
     else:
         form = SignatureForm(request=request, initial={'signature': request.user.signature})
         form = SignatureForm(request=request, initial={'signature': request.user.signature})
-        
+
     return request.theme.render_to_response('usercp/signature.html',
     return request.theme.render_to_response('usercp/signature.html',
                                             context_instance=RequestContext(request, {
                                             context_instance=RequestContext(request, {
                                               'message': message,
                                               'message': message,
                                               'tab': 'signature',
                                               'tab': 'signature',
                                               'form': FormLayout(form),
                                               'form': FormLayout(form),
-                                             }));
+                                             }));

+ 2 - 3
misago/usercp/template.py

@@ -6,7 +6,7 @@ def RequestContext(request, context=None):
     if not context:
     if not context:
         context = {}
         context = {}
     context['tabs'] = []
     context['tabs'] = []
-    
+
     for extension in settings.USERCP_EXTENSIONS:
     for extension in settings.USERCP_EXTENSIONS:
         usercp_module = import_module(extension + '.usercp')
         usercp_module = import_module(extension + '.usercp')
         try:
         try:
@@ -21,6 +21,5 @@ def RequestContext(request, context=None):
                                             })
                                             })
         except AttributeError:
         except AttributeError:
             pass
             pass
-    
+
     return DjangoRequestContext(request, context)
     return DjangoRequestContext(request, context)
-    

+ 1 - 1
misago/usercp/urls.py

@@ -5,4 +5,4 @@ urlpatterns = []
 for extension in settings.USERCP_EXTENSIONS:
 for extension in settings.USERCP_EXTENSIONS:
     urlpatterns += patterns('',
     urlpatterns += patterns('',
         (r'^', include(extension + '.urls')),
         (r'^', include(extension + '.urls')),
-    )
+    )

+ 5 - 5
misago/usercp/username/forms.py

@@ -6,7 +6,7 @@ from misago.forms import Form
 class UsernameChangeForm(Form):
 class UsernameChangeForm(Form):
     username = forms.CharField(max_length=255)
     username = forms.CharField(max_length=255)
     error_source = 'username'
     error_source = 'username'
-    
+
     layout = [
     layout = [
               [
               [
                None,
                None,
@@ -15,16 +15,16 @@ class UsernameChangeForm(Form):
                 ],
                 ],
                ],
                ],
               ]
               ]
-    
+
     def clean_username(self):
     def clean_username(self):
         org_username = self.request.user.username
         org_username = self.request.user.username
-        
+
         self.request.user.set_username(self.cleaned_data['username'])
         self.request.user.set_username(self.cleaned_data['username'])
         if org_username == self.request.user.username:
         if org_username == self.request.user.username:
             raise ValidationError(_("Your new username is same as current one."))
             raise ValidationError(_("Your new username is same as current one."))
-        
+
         try:
         try:
             self.request.user.full_clean()
             self.request.user.full_clean()
         except ValidationError as e:
         except ValidationError as e:
             self.request.user.is_username_valid(e)
             self.request.user.is_username_valid(e)
-        return self.cleaned_data['username']
+        return self.cleaned_data['username']

+ 1 - 1
misago/usercp/username/urls.py

@@ -2,4 +2,4 @@ from django.conf.urls import patterns, url
 
 
 urlpatterns = patterns('misago.usercp.username.views',
 urlpatterns = patterns('misago.usercp.username.views',
     url(r'^username/$', 'username', name="usercp_username"),
     url(r'^username/$', 'username', name="usercp_username"),
-)
+)

+ 1 - 1
misago/usercp/username/usercp.py

@@ -2,4 +2,4 @@ from django.utils.translation import ugettext_lazy as _
 
 
 def register_usercp_extension(request):
 def register_usercp_extension(request):
     if request.acl.usercp.show_username_change():
     if request.acl.usercp.show_username_change():
-        return (('usercp_username', _('Change Username')),)
+        return (('usercp_username', _('Change Username')),)

+ 7 - 7
misago/usercp/username/views.py

@@ -15,16 +15,16 @@ from misago.views import error404
 def username(request):
 def username(request):
     if not request.acl.usercp.show_username_change():
     if not request.acl.usercp.show_username_change():
         return error404(request)
         return error404(request)
-    
+
     changes_left = request.acl.usercp.changes_left(request.user)
     changes_left = request.acl.usercp.changes_left(request.user)
-    
+
     next_change = None
     next_change = None
     if request.acl.usercp.changes_expire() and not changes_left:
     if request.acl.usercp.changes_expire() and not changes_left:
         next_change = request.user.namechanges.filter(
         next_change = request.user.namechanges.filter(
                                                       date__gte=timezone.now() - timedelta(days=request.acl.usercp.acl['changes_expire']),
                                                       date__gte=timezone.now() - timedelta(days=request.acl.usercp.acl['changes_expire']),
                                                       ).order_by('-date')[0]
                                                       ).order_by('-date')[0]
         next_change = next_change.date + timedelta(days=request.acl.usercp.acl['changes_expire'])
         next_change = next_change.date + timedelta(days=request.acl.usercp.acl['changes_expire'])
-    
+
     message = request.messages.get_message('usercp_username')
     message = request.messages.get_message('usercp_username')
     if request.method == 'POST':
     if request.method == 'POST':
         org_username = request.user.username
         org_username = request.user.username
@@ -32,14 +32,14 @@ def username(request):
         if form.is_valid():
         if form.is_valid():
             request.user.set_username(form.cleaned_data['username'])
             request.user.set_username(form.cleaned_data['username'])
             request.user.save(force_update=True)
             request.user.save(force_update=True)
-            request.user.namechanges.create(date=timezone.now(),old_username=org_username)
-            
+            request.user.namechanges.create(date=timezone.now(), old_username=org_username)
+
             request.messages.set_flash(Message(_("Your username has been changed.")), 'success', 'usercp_username')
             request.messages.set_flash(Message(_("Your username has been changed.")), 'success', 'usercp_username')
             return redirect(reverse('usercp_username'))
             return redirect(reverse('usercp_username'))
         message = Message(form.non_field_errors()[0], 'error')
         message = Message(form.non_field_errors()[0], 'error')
     else:
     else:
         form = UsernameChangeForm(request=request)
         form = UsernameChangeForm(request=request)
-    
+
     return request.theme.render_to_response('usercp/username.html',
     return request.theme.render_to_response('usercp/username.html',
                                             context_instance=RequestContext(request, {
                                             context_instance=RequestContext(request, {
                                               'message': message,
                                               'message': message,
@@ -48,4 +48,4 @@ def username(request):
                                               'next_change': next_change,
                                               'next_change': next_change,
                                               'changes_history': request.user.namechanges.order_by('-date')[:10],
                                               'changes_history': request.user.namechanges.order_by('-date')[:10],
                                               'tab': 'username',
                                               'tab': 'username',
-                                             }));
+                                             }));

+ 1 - 1
misago/users/context_processors.py

@@ -1,4 +1,4 @@
 def user(request):
 def user(request):
     return {
     return {
         'user': request.user,
         'user': request.user,
-    }
+    }

+ 1 - 1
misago/users/fixtures.py

@@ -11,4 +11,4 @@ monitor_fixtures = {
 
 
 
 
 def load_fixtures():
 def load_fixtures():
-    load_monitor_fixture(monitor_fixtures)
+    load_monitor_fixture(monitor_fixtures)

+ 34 - 35
misago/users/forms.py

@@ -11,25 +11,25 @@ from misago.forms import Form, YesNoSwitch
 
 
 class UserForm(Form):
 class UserForm(Form):
     username = forms.CharField(max_length=255)
     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'))
+    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'))
     roles = False
     roles = False
     email = forms.EmailField(max_length=255)
     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)
-            
+    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)
+
     def __init__(self, user=None, *args, **kwargs):
     def __init__(self, user=None, *args, **kwargs):
         self.request = kwargs['request']
         self.request = kwargs['request']
         self.user = user
         self.user = user
         super(UserForm, self).__init__(*args, **kwargs)
         super(UserForm, self).__init__(*args, **kwargs)
-    
+
     def finalize_form(self):
     def finalize_form(self):
         self.layout = [
         self.layout = [
                        [
                        [
@@ -67,19 +67,19 @@ class UserForm(Form):
                          ],
                          ],
                         ],
                         ],
                        ]
                        ]
-        
+
         # Roles list
         # Roles list
         if self.request.user.is_god():
         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.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.")})
         else:
         else:
-            self.fields['roles'] = forms.ModelMultipleChoiceField(widget=forms.CheckboxSelectMultiple,queryset=Role.objects.filter(protected__exact=False).order_by('name').all(),required=False)
-            
+            self.fields['roles'] = forms.ModelMultipleChoiceField(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
         # 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:
         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['email']
             del self.fields['new_password']
             del self.fields['new_password']
             del self.layout[1]
             del self.layout[1]
-    
+
     def clean_username(self):
     def clean_username(self):
         self.user.set_username(self.cleaned_data['username'])
         self.user.set_username(self.cleaned_data['username'])
         try:
         try:
@@ -87,7 +87,7 @@ class UserForm(Form):
         except ValidationError as e:
         except ValidationError as e:
             self.user.is_username_valid(e)
             self.user.is_username_valid(e)
         return self.cleaned_data['username']
         return self.cleaned_data['username']
-        
+
     def clean_email(self):
     def clean_email(self):
         self.user.set_email(self.cleaned_data['email'])
         self.user.set_email(self.cleaned_data['email'])
         try:
         try:
@@ -95,7 +95,7 @@ class UserForm(Form):
         except ValidationError as e:
         except ValidationError as e:
             self.user.is_email_valid(e)
             self.user.is_email_valid(e)
         return self.cleaned_data['email']
         return self.cleaned_data['email']
-        
+
     def clean_new_password(self):
     def clean_new_password(self):
         if self.cleaned_data['new_password']:
         if self.cleaned_data['new_password']:
             self.user.set_password(self.cleaned_data['new_password'])
             self.user.set_password(self.cleaned_data['new_password'])
@@ -113,18 +113,18 @@ class UserForm(Form):
                 avatar_image = Image.open('%s/avatars/%s' % (settings.STATICFILES_DIRS[0], self.cleaned_data['avatar_custom']))
                 avatar_image = Image.open('%s/avatars/%s' % (settings.STATICFILES_DIRS[0], self.cleaned_data['avatar_custom']))
             except IOError:
             except IOError:
                 raise ValidationError(_("Avatar does not exist or is not image file."))
                 raise ValidationError(_("Avatar does not exist or is not image file."))
-            return self.cleaned_data['avatar_custom']            
+            return self.cleaned_data['avatar_custom']
         return ''
         return ''
 
 
 
 
 class NewUserForm(Form):
 class NewUserForm(Form):
     username = forms.CharField(max_length=255)
     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'))
+    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'))
     roles = False
     roles = False
     email = forms.EmailField(max_length=255)
     email = forms.EmailField(max_length=255)
-    password = forms.CharField(max_length=255,widget=forms.PasswordInput)
-    
+    password = forms.CharField(max_length=255, widget=forms.PasswordInput)
+
     layout = [
     layout = [
               [
               [
                _("Basic Account Settings"),
                _("Basic Account Settings"),
@@ -143,18 +143,18 @@ class NewUserForm(Form):
                 ],
                 ],
                ],
                ],
               ]
               ]
-        
+
     def __init__(self, *args, **kwargs):
     def __init__(self, *args, **kwargs):
         self.request = kwargs['request']
         self.request = kwargs['request']
-        
+
         # Roles list
         # Roles list
         if self.request.user.is_god():
         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.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.")})
         else:
         else:
-            self.base_fields['roles'] = forms.ModelMultipleChoiceField(widget=forms.CheckboxSelectMultiple,queryset=Role.objects.filter(protected__exact=False).order_by('name').all(),required=False)
-        
+            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)
         super(NewUserForm, self).__init__(*args, **kwargs)
-        
+
     def clean_username(self):
     def clean_username(self):
         new_user = User.objects.get_blank_user()
         new_user = User.objects.get_blank_user()
         new_user.set_username(self.cleaned_data['username'])
         new_user.set_username(self.cleaned_data['username'])
@@ -163,7 +163,7 @@ class NewUserForm(Form):
         except ValidationError as e:
         except ValidationError as e:
             new_user.is_username_valid(e)
             new_user.is_username_valid(e)
         return self.cleaned_data['username']
         return self.cleaned_data['username']
-        
+
     def clean_email(self):
     def clean_email(self):
         new_user = User.objects.get_blank_user()
         new_user = User.objects.get_blank_user()
         new_user.set_email(self.cleaned_data['email'])
         new_user.set_email(self.cleaned_data['email'])
@@ -172,7 +172,7 @@ class NewUserForm(Form):
         except ValidationError as e:
         except ValidationError as e:
             new_user.is_email_valid(e)
             new_user.is_email_valid(e)
         return self.cleaned_data['email']
         return self.cleaned_data['email']
-        
+
     def clean_password(self):
     def clean_password(self):
         new_user = User.objects.get_blank_user()
         new_user = User.objects.get_blank_user()
         new_user.set_password(self.cleaned_data['password'])
         new_user.set_password(self.cleaned_data['password'])
@@ -190,7 +190,7 @@ class SearchUsersForm(Form):
     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)
     rank = forms.ModelMultipleChoiceField(widget=forms.CheckboxSelectMultiple, queryset=Rank.objects.order_by('order').all(), 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)
     role = forms.ModelMultipleChoiceField(widget=forms.CheckboxSelectMultiple, queryset=Role.objects.order_by('name').all(), required=False)
-    
+
     layout = (
     layout = (
               (
               (
                _("Search Users"),
                _("Search Users"),
@@ -203,4 +203,3 @@ class SearchUsersForm(Form):
                ),
                ),
               ),
               ),
              )
              )
-    

+ 4 - 4
misago/users/management/commands/adduser.py

@@ -19,21 +19,21 @@ class Command(BaseCommand):
     def handle(self, *args, **options):
     def handle(self, *args, **options):
         if len(args) < 3:
         if len(args) < 3:
             raise CommandError('adduser requires exactly three arguments: user name, e-mail addres and password')
             raise CommandError('adduser requires exactly three arguments: user name, e-mail addres and password')
-                
+
         # Set user
         # Set user
         try:
         try:
             new_user = User.objects.create_user(args[0], args[1], args[2])
             new_user = User.objects.create_user(args[0], args[1], args[2])
         except ValidationError as e:
         except ValidationError as e:
             raise CommandError("New user cannot be created because of following errors:\n\n%s" % '\n'.join(e.messages))
             raise CommandError("New user cannot be created because of following errors:\n\n%s" % '\n'.join(e.messages))
-                
+
         # Set admin role
         # Set admin role
         if options['admin']:
         if options['admin']:
             new_user.roles.add(Role.objects.get(token='admin'))
             new_user.roles.add(Role.objects.get(token='admin'))
             new_user.make_acl_key(True)
             new_user.make_acl_key(True)
             new_user.save(force_update=True)
             new_user.save(force_update=True)
-        
+
         if options['admin']:
         if options['admin']:
             self.stdout.write('Successfully created new administrator "%s"' % args[0])
             self.stdout.write('Successfully created new administrator "%s"' % args[0])
         else:
         else:
             self.stdout.write('Successfully created new user "%s"' % args[0])
             self.stdout.write('Successfully created new user "%s"' % args[0])
-        self.stdout.write('\n\nNew user should use "%s" e-mail address and "%s" password to sign in.\n' % (args[1], args[2]))
+        self.stdout.write('\n\nNew user should use "%s" e-mail address and "%s" password to sign in.\n' % (args[1], args[2]))

+ 5 - 5
misago/users/management/commands/genavatars.py

@@ -8,7 +8,7 @@ except ImportError:
     has_pil = False
     has_pil = False
 from misago.users.models import User
 from misago.users.models import User
 from misago.utils.avatars import resizeimage
 from misago.utils.avatars import resizeimage
-    
+
 class Command(BaseCommand):
 class Command(BaseCommand):
     help = 'Regenerates avatar images for new dimensions'
     help = 'Regenerates avatar images for new dimensions'
     def handle(self, *args, **options):
     def handle(self, *args, **options):
@@ -17,21 +17,21 @@ class Command(BaseCommand):
         self.scale_user_avatars()
         self.scale_user_avatars()
         self.scale_gallery_avatars()
         self.scale_gallery_avatars()
         self.stdout.write('\n\nAvatar images have been regenerated.\n')
         self.stdout.write('\n\nAvatar images have been regenerated.\n')
-        
+
     def scale_image(self, image_src, image_dir=None):
     def scale_image(self, image_src, image_dir=None):
         image_name = path.basename(path(image_src))
         image_name = path.basename(path(image_src))
         if not image_dir:
         if not image_dir:
             image_dir = path.dirname(path(image_src)) + '/%s_'
             image_dir = path.dirname(path(image_src)) + '/%s_'
         for size in settings.AVATAR_SIZES[1:]:
         for size in settings.AVATAR_SIZES[1:]:
             resizeimage(image_src, size, image_dir % size + image_name)
             resizeimage(image_src, size, image_dir % size + image_name)
-    
+
     def scale_user_avatars(self):
     def scale_user_avatars(self):
         for user in User.objects.filter(avatar_type='upload').iterator():
         for user in User.objects.filter(avatar_type='upload').iterator():
             for image in path(settings.MEDIA_ROOT).joinpath('avatars').files('*_%s' % user.avatar_image):
             for image in path(settings.MEDIA_ROOT).joinpath('avatars').files('*_%s' % user.avatar_image):
                 if not image.isdir():
                 if not image.isdir():
                     image.remove()
                     image.remove()
             self.scale_image(settings.MEDIA_ROOT + 'avatars/' + user.avatar_image)
             self.scale_image(settings.MEDIA_ROOT + 'avatars/' + user.avatar_image)
-    
+
     def scale_gallery_avatars(self):
     def scale_gallery_avatars(self):
         try:
         try:
             thumb_dir = path(settings.STATICFILES_DIRS[0]).joinpath('avatars').joinpath('_thumbs')
             thumb_dir = path(settings.STATICFILES_DIRS[0]).joinpath('avatars').joinpath('_thumbs')
@@ -64,4 +64,4 @@ class Command(BaseCommand):
                     thumb_dir.joinpath(str(size)).joinpath(dirname).mkdir(777)
                     thumb_dir.joinpath(str(size)).joinpath(dirname).mkdir(777)
         for avatar in avatars_list:
         for avatar in avatars_list:
             self.scale_image(avatar,
             self.scale_image(avatar,
-                             thumb_dir + '/%s' + avatar.dirname()[avatars_len:] + '/')
+                             thumb_dir + '/%s' + avatar.dirname()[avatars_len:] + '/')

+ 1 - 1
misago/users/management/commands/syncusermonitor.py

@@ -9,4 +9,4 @@ class Command(BaseCommand):
 
 
     def handle(self, *args, **options):
     def handle(self, *args, **options):
         User.objects.resync_monitor(Monitor())
         User.objects.resync_monitor(Monitor())
-        self.stdout.write('\n\nForum monitor has been updated to contain to date user information.\n')
+        self.stdout.write('\n\nForum monitor has been updated to contain to date user information.\n')

+ 2 - 2
misago/users/middleware.py

@@ -18,11 +18,11 @@ class UserMiddleware(object):
             # Set user timezone and rank
             # Set user timezone and rank
             request.session.rank = request.user.rank_id
             request.session.rank = request.user.rank_id
             set_timezone(request.user.timezone)
             set_timezone(request.user.timezone)
-            
+
             # Display "welcome back!" message
             # Display "welcome back!" message
             if request.session.remember_me:
             if request.session.remember_me:
                 request.messages.set_message(Message(_("Welcome back, %(username)s! We've signed you in automatically for your convenience.") % {'username': request.user.username}), 'info')
                 request.messages.set_message(Message(_("Welcome back, %(username)s! We've signed you in automatically for your convenience.") % {'username': request.user.username}), 'info')
         else:
         else:
             # Set guest's timezone and empty rank
             # Set guest's timezone and empty rank
             set_timezone(request.settings['default_timezone'])
             set_timezone(request.settings['default_timezone'])
-            request.session.rank = None
+            request.session.rank = None

+ 101 - 101
misago/users/models.py

@@ -30,7 +30,7 @@ class UserManager(models.Manager):
                         join_ip='127.0.0.1'
                         join_ip='127.0.0.1'
                         )
                         )
         return blank_user
         return blank_user
-    
+
     def resync_monitor(self, monitor):
     def resync_monitor(self, monitor):
         monitor['users'] = self.count()
         monitor['users'] = self.count()
         monitor['users_inactive'] = self.filter(activation__gt=0).count()
         monitor['users_inactive'] = self.filter(activation__gt=0).count()
@@ -38,27 +38,27 @@ class UserManager(models.Manager):
         monitor['last_user'] = last_user.pk
         monitor['last_user'] = last_user.pk
         monitor['last_user_name'] = last_user.username
         monitor['last_user_name'] = last_user.username
         monitor['last_user_slug'] = last_user.username_slug
         monitor['last_user_slug'] = last_user.username_slug
-    
+
     def create_user(self, username, email, password, timezone=False, ip='127.0.0.1', no_roles=False, activation=0, request=False):
     def create_user(self, username, email, password, timezone=False, ip='127.0.0.1', no_roles=False, activation=0, request=False):
         token = ''
         token = ''
         if activation > 0:
         if activation > 0:
             token = get_random_string(12)
             token = get_random_string(12)
-        
+
         try:
         try:
             db_settings = request.settings
             db_settings = request.settings
         except AttributeError:
         except AttributeError:
             db_settings = DBSettings()
             db_settings = DBSettings()
-            
+
         if timezone == False:
         if timezone == False:
             timezone = db_settings['default_timezone']
             timezone = db_settings['default_timezone']
-        
+
         # Get first rank
         # Get first rank
         try:
         try:
             from misago.ranks.models import Rank
             from misago.ranks.models import Rank
             default_rank = Rank.objects.filter(special=0).order_by('order')[0]
             default_rank = Rank.objects.filter(special=0).order_by('order')[0]
         except IndexError:
         except IndexError:
             default_rank = None
             default_rank = None
-        
+
         # Store user in database
         # Store user in database
         new_user = User(
         new_user = User(
                         last_sync=tz_util.now(),
                         last_sync=tz_util.now(),
@@ -69,27 +69,27 @@ class UserManager(models.Manager):
                         timezone=timezone,
                         timezone=timezone,
                         rank=default_rank,
                         rank=default_rank,
                         )
                         )
-        
+
         new_user.set_username(username)
         new_user.set_username(username)
         new_user.set_email(email)
         new_user.set_email(email)
         new_user.set_password(password)
         new_user.set_password(password)
         new_user.full_clean()
         new_user.full_clean()
         new_user.default_avatar(db_settings)
         new_user.default_avatar(db_settings)
         new_user.save(force_insert=True)
         new_user.save(force_insert=True)
-        
+
         # Set user roles?
         # Set user roles?
         if not no_roles:
         if not no_roles:
             from misago.roles.models import Role
             from misago.roles.models import Role
             new_user.roles.add(Role.objects.get(token='registered'))
             new_user.roles.add(Role.objects.get(token='registered'))
             new_user.make_acl_key()
             new_user.make_acl_key()
             new_user.save(force_update=True)
             new_user.save(force_update=True)
-        
+
         # Load monitor
         # Load monitor
         try:
         try:
             monitor = request.monitor
             monitor = request.monitor
         except AttributeError:
         except AttributeError:
             monitor = Monitor()
             monitor = Monitor()
-        
+
         # Update forum stats
         # Update forum stats
         if activation == 0:
         if activation == 0:
             monitor['users'] = int(monitor['users']) + 1
             monitor['users'] = int(monitor['users']) + 1
@@ -98,41 +98,41 @@ class UserManager(models.Manager):
             monitor['last_user_slug'] = new_user.username_slug
             monitor['last_user_slug'] = new_user.username_slug
         else:
         else:
             monitor['users_inactive'] = int(monitor['users_inactive']) + 1
             monitor['users_inactive'] = int(monitor['users_inactive']) + 1
-            
+
         # Return new user
         # Return new user
         return new_user
         return new_user
-            
+
     def get_by_email(self, email):
     def get_by_email(self, email):
         return self.get(email_hash=hashlib.md5(email).hexdigest())
         return self.get(email_hash=hashlib.md5(email).hexdigest())
-    
+
     def filter_stats(self, start, end):
     def filter_stats(self, start, end):
         return self.filter(join_date__gte=start).filter(join_date__lte=end)
         return self.filter(join_date__gte=start).filter(join_date__lte=end)
-    
-        
+
+
 class User(models.Model):
 class User(models.Model):
     """
     """
     Misago User model
     Misago User model
     """
     """
-    username = models.CharField(max_length=255,validators=[validate_username])
-    username_slug = models.SlugField(max_length=255,unique=True,
+    username = models.CharField(max_length=255, validators=[validate_username])
+    username_slug = models.SlugField(max_length=255, unique=True,
                                      error_messages={'unique': _("This user name is already in use by another user.")})
                                      error_messages={'unique': _("This user name is already in use by another user.")})
-    email = models.EmailField(max_length=255,validators=[validate_email])
-    email_hash = models.CharField(max_length=32,unique=True,
+    email = models.EmailField(max_length=255, validators=[validate_email])
+    email_hash = models.CharField(max_length=32, unique=True,
                                      error_messages={'unique': _("This email address is already in use by another user.")})
                                      error_messages={'unique': _("This email address is already in use by another user.")})
     password = models.CharField(max_length=255)
     password = models.CharField(max_length=255)
     password_date = models.DateTimeField()
     password_date = models.DateTimeField()
-    avatar_type = models.CharField(max_length=10,null=True,blank=True)
-    avatar_image = models.CharField(max_length=255,null=True,blank=True)
-    avatar_original = models.CharField(max_length=255,null=True,blank=True)
-    avatar_temp = models.CharField(max_length=255,null=True,blank=True)
-    signature = models.TextField(null=True,blank=True)
-    signature_preparsed = models.TextField(null=True,blank=True)
+    avatar_type = models.CharField(max_length=10, null=True, blank=True)
+    avatar_image = models.CharField(max_length=255, null=True, blank=True)
+    avatar_original = models.CharField(max_length=255, null=True, blank=True)
+    avatar_temp = models.CharField(max_length=255, null=True, blank=True)
+    signature = models.TextField(null=True, blank=True)
+    signature_preparsed = models.TextField(null=True, blank=True)
     join_date = models.DateTimeField()
     join_date = models.DateTimeField()
     join_ip = models.GenericIPAddressField()
     join_ip = models.GenericIPAddressField()
-    join_agent = models.TextField(null=True,blank=True)
-    last_date = models.DateTimeField(null=True,blank=True)
-    last_ip = models.GenericIPAddressField(null=True,blank=True)
-    last_agent = models.TextField(null=True,blank=True)
+    join_agent = models.TextField(null=True, blank=True)
+    last_date = models.DateTimeField(null=True, blank=True)
+    last_ip = models.GenericIPAddressField(null=True, blank=True)
+    last_agent = models.TextField(null=True, blank=True)
     hide_activity = models.PositiveIntegerField(default=0)
     hide_activity = models.PositiveIntegerField(default=0)
     alert_ats = models.PositiveIntegerField(default=0)
     alert_ats = models.PositiveIntegerField(default=0)
     allow_pms = models.PositiveIntegerField(default=0)
     allow_pms = models.PositiveIntegerField(default=0)
@@ -146,38 +146,38 @@ class User(models.Model):
     karma_n = models.PositiveIntegerField(default=0)
     karma_n = models.PositiveIntegerField(default=0)
     following = models.PositiveIntegerField(default=0)
     following = models.PositiveIntegerField(default=0)
     followers = models.PositiveIntegerField(default=0)
     followers = models.PositiveIntegerField(default=0)
-    score = models.IntegerField(default=0,db_index=True)
-    rank = models.ForeignKey('ranks.Rank',null=True,blank=True,on_delete=models.SET_NULL)
-    last_sync = models.DateTimeField(null=True,blank=True)
-    follows = models.ManyToManyField('self',related_name='follows_set',symmetrical=False)
-    ignores = models.ManyToManyField('self',related_name='ignores_set',symmetrical=False)
-    title = models.CharField(max_length=255,null=True,blank=True)
-    last_post = models.DateTimeField(null=True,blank=True)
-    last_search = models.DateTimeField(null=True,blank=True)
+    score = models.IntegerField(default=0, db_index=True)
+    rank = models.ForeignKey('ranks.Rank', null=True, blank=True, on_delete=models.SET_NULL)
+    last_sync = models.DateTimeField(null=True, blank=True)
+    follows = models.ManyToManyField('self', related_name='follows_set', symmetrical=False)
+    ignores = models.ManyToManyField('self', related_name='ignores_set', symmetrical=False)
+    title = models.CharField(max_length=255, null=True, blank=True)
+    last_post = models.DateTimeField(null=True, blank=True)
+    last_search = models.DateTimeField(null=True, blank=True)
     alerts = models.PositiveIntegerField(default=0)
     alerts = models.PositiveIntegerField(default=0)
-    alerts_date = models.DateTimeField(null=True,blank=True)
+    alerts_date = models.DateTimeField(null=True, blank=True)
     activation = models.IntegerField(default=0)
     activation = models.IntegerField(default=0)
-    token = models.CharField(max_length=12,null=True,blank=True)
+    token = models.CharField(max_length=12, null=True, blank=True)
     avatar_ban = models.BooleanField(default=False)
     avatar_ban = models.BooleanField(default=False)
-    avatar_ban_reason_user = models.TextField(null=True,blank=True)
-    avatar_ban_reason_admin = models.TextField(null=True,blank=True)
+    avatar_ban_reason_user = models.TextField(null=True, blank=True)
+    avatar_ban_reason_admin = models.TextField(null=True, blank=True)
     signature_ban = models.BooleanField(default=False)
     signature_ban = models.BooleanField(default=False)
-    signature_ban_reason_user = models.TextField(null=True,blank=True)
-    signature_ban_reason_admin = models.TextField(null=True,blank=True)
-    timezone = models.CharField(max_length=255,default='utc')
+    signature_ban_reason_user = models.TextField(null=True, blank=True)
+    signature_ban_reason_admin = models.TextField(null=True, blank=True)
+    timezone = models.CharField(max_length=255, default='utc')
     roles = models.ManyToManyField('roles.Role')
     roles = models.ManyToManyField('roles.Role')
-    is_team = models.BooleanField(default=False,db_index=True)
-    acl_key = models.CharField(max_length=12,null=True,blank=True)
-    
-    objects = UserManager()   
-    
+    is_team = models.BooleanField(default=False, db_index=True)
+    acl_key = models.CharField(max_length=12, null=True, blank=True)
+
+    objects = UserManager()
+
     ACTIVATION_NONE = 0
     ACTIVATION_NONE = 0
     ACTIVATION_USER = 1
     ACTIVATION_USER = 1
     ACTIVATION_ADMIN = 2
     ACTIVATION_ADMIN = 2
     ACTIVATION_CREDENTIALS = 3
     ACTIVATION_CREDENTIALS = 3
-    
+
     statistics_name = _('Users Registrations')
     statistics_name = _('Users Registrations')
-        
+
     def is_god(self):
     def is_god(self):
         try:
         try:
             return self.is_god_cache
             return self.is_god_cache
@@ -188,13 +188,13 @@ class User(models.Model):
                     return True
                     return True
             self.is_god_cache = False
             self.is_god_cache = False
             return False
             return False
-            
+
     def is_anonymous(self):
     def is_anonymous(self):
         return False
         return False
-    
+
     def is_authenticated(self):
     def is_authenticated(self):
         return True
         return True
-    
+
     def is_crawler(self):
     def is_crawler(self):
         return False
         return False
 
 
@@ -203,12 +203,12 @@ class User(models.Model):
             if role.protected:
             if role.protected:
                 return True
                 return True
         return False
         return False
-    
+
     def lock_avatar(self):
     def lock_avatar(self):
         # Kill existing avatar and lock our ability to change it
         # Kill existing avatar and lock our ability to change it
         self.delete_avatar()
         self.delete_avatar()
         self.avatar_ban = True
         self.avatar_ban = True
-        
+
         # Pick new one from _locked gallery
         # Pick new one from _locked gallery
         galleries = path(settings.STATICFILES_DIRS[0]).joinpath('avatars').joinpath('_locked')
         galleries = path(settings.STATICFILES_DIRS[0]).joinpath('avatars').joinpath('_locked')
         avatars_list = galleries.files('*.gif')
         avatars_list = galleries.files('*.gif')
@@ -217,7 +217,7 @@ class User(models.Model):
         avatars_list += galleries.files('*.png')
         avatars_list += galleries.files('*.png')
         self.avatar_type = 'gallery'
         self.avatar_type = 'gallery'
         self.avatar_image = '/'.join(path(choice(avatars_list)).splitall()[-2:])
         self.avatar_image = '/'.join(path(choice(avatars_list)).splitall()[-2:])
-        
+
     def default_avatar(self, db_settings):
     def default_avatar(self, db_settings):
         if db_settings['default_avatar'] == 'gallery':
         if db_settings['default_avatar'] == 'gallery':
             try:
             try:
@@ -247,7 +247,7 @@ class User(models.Model):
                     return True
                     return True
             except Exception as e:
             except Exception as e:
                 pass
                 pass
-            
+
         self.avatar_type = 'gravatar'
         self.avatar_type = 'gravatar'
         self.avatar_image = None
         self.avatar_image = None
         return True
         return True
@@ -260,7 +260,7 @@ class User(models.Model):
                     av_file.remove()
                     av_file.remove()
             except Exception:
             except Exception:
                 pass
                 pass
-            
+
         self.avatar_temp = None
         self.avatar_temp = None
 
 
     def delete_avatar_original(self):
     def delete_avatar_original(self):
@@ -271,7 +271,7 @@ class User(models.Model):
                     av_file.remove()
                     av_file.remove()
             except Exception:
             except Exception:
                 pass
                 pass
-        
+
         self.avatar_original = None
         self.avatar_original = None
 
 
     def delete_avatar_image(self):
     def delete_avatar_image(self):
@@ -289,14 +289,14 @@ class User(models.Model):
                     av_file.remove()
                     av_file.remove()
             except Exception:
             except Exception:
                 pass
                 pass
-        
+
         self.avatar_image = None
         self.avatar_image = None
 
 
     def delete_avatar(self):
     def delete_avatar(self):
         self.delete_avatar_temp()
         self.delete_avatar_temp()
         self.delete_avatar_original()
         self.delete_avatar_original()
         self.delete_avatar_image()
         self.delete_avatar_image()
-            
+
     def delete_content(self):
     def delete_content(self):
         if self.pk:
         if self.pk:
             for model_obj in models.get_models():
             for model_obj in models.get_models():
@@ -304,22 +304,22 @@ class User(models.Model):
                     model_obj.objects.delete_user_content(self)
                     model_obj.objects.delete_user_content(self)
                 except AttributeError:
                 except AttributeError:
                     pass
                     pass
-    
+
     def delete(self, *args, **kwargs):
     def delete(self, *args, **kwargs):
         self.delete_avatar()
         self.delete_avatar()
         super(User, self).delete(*args, **kwargs)
         super(User, self).delete(*args, **kwargs)
-            
+
     def set_username(self, username):
     def set_username(self, username):
         self.username = username.strip()
         self.username = username.strip()
         self.username_slug = slugify(username)
         self.username_slug = slugify(username)
-        
+
         if self.pk:
         if self.pk:
             for model_obj in models.get_models():
             for model_obj in models.get_models():
                 try:
                 try:
                     model_obj.objects.update_username(self)
                     model_obj.objects.update_username(self)
                 except AttributeError:
                 except AttributeError:
                     pass
                     pass
-    
+
     def is_username_valid(self, e):
     def is_username_valid(self, e):
         try:
         try:
             raise ValidationError(e.message_dict['username'])
             raise ValidationError(e.message_dict['username'])
@@ -329,7 +329,7 @@ class User(models.Model):
             raise ValidationError(e.message_dict['username_slug'])
             raise ValidationError(e.message_dict['username_slug'])
         except KeyError:
         except KeyError:
             pass
             pass
-        
+
     def is_email_valid(self, e):
     def is_email_valid(self, e):
         try:
         try:
             raise ValidationError(e.message_dict['email'])
             raise ValidationError(e.message_dict['email'])
@@ -339,17 +339,17 @@ class User(models.Model):
             raise ValidationError(e.message_dict['email_hash'])
             raise ValidationError(e.message_dict['email_hash'])
         except KeyError:
         except KeyError:
             pass
             pass
-        
+
     def is_password_valid(self, e):
     def is_password_valid(self, e):
         try:
         try:
             raise ValidationError(e.message_dict['password'])
             raise ValidationError(e.message_dict['password'])
         except KeyError:
         except KeyError:
             pass
             pass
-        
+
     def set_email(self, email):
     def set_email(self, email):
         self.email = email.strip().lower()
         self.email = email.strip().lower()
         self.email_hash = hashlib.md5(self.email).hexdigest()
         self.email_hash = hashlib.md5(self.email).hexdigest()
-        
+
     def set_password(self, raw_password):
     def set_password(self, raw_password):
         self.password_date = tz_util.now()
         self.password_date = tz_util.now()
         self.password = make_password(raw_password.strip())
         self.password = make_password(raw_password.strip())
@@ -368,11 +368,11 @@ class User(models.Model):
         def setter(raw_password):
         def setter(raw_password):
             self.set_password(raw_password)
             self.set_password(raw_password)
             self.save()
             self.save()
-            
+
         # Is standard password allright?
         # Is standard password allright?
         if check_password(raw_password, self.password, setter):
         if check_password(raw_password, self.password, setter):
             return True
             return True
-        
+
         # Check mobile password?
         # Check mobile password?
         if mobile:
         if mobile:
             raw_password = raw_password[:1].lower() + raw_password[1:]
             raw_password = raw_password[:1].lower() + raw_password[1:]
@@ -382,13 +382,13 @@ class User(models.Model):
                 r = c.upper()
                 r = c.upper()
                 if r == c:
                 if r == c:
                     r = c.lower()
                     r = c.lower()
-                password_reversed += r 
+                password_reversed += r
             raw_password = password_reversed
             raw_password = password_reversed
         return check_password(raw_password, self.password, setter)
         return check_password(raw_password, self.password, setter)
-    
+
     def get_roles(self):
     def get_roles(self):
         return self.roles.all()
         return self.roles.all()
-        
+
     def make_acl_key(self, force=False):
     def make_acl_key(self, force=False):
         if not force and self.acl_key:
         if not force and self.acl_key:
             return self.acl_key
             return self.acl_key
@@ -397,7 +397,7 @@ class User(models.Model):
             roles_ids.append(str(role.pk))
             roles_ids.append(str(role.pk))
         self.acl_key = 'acl_%s' % hashlib.md5('_'.join(roles_ids)).hexdigest()[0:8]
         self.acl_key = 'acl_%s' % hashlib.md5('_'.join(roles_ids)).hexdigest()[0:8]
         return self.acl_key
         return self.acl_key
-    
+
     def get_acl(self, request):
     def get_acl(self, request):
         try:
         try:
             acl = cache.get(self.acl_key)
             acl = cache.get(self.acl_key)
@@ -408,66 +408,66 @@ class User(models.Model):
             acl = build_acl(request, self.get_roles())
             acl = build_acl(request, self.get_roles())
             cache.set(self.acl_key, acl, 2592000)
             cache.set(self.acl_key, acl, 2592000)
         return acl
         return acl
-            
+
     def get_avatar(self, size=None):
     def get_avatar(self, size=None):
         image_size = avatar_size(size) if size else None
         image_size = avatar_size(size) if size else None
-                
+
         # Get uploaded avatar
         # Get uploaded avatar
         if self.avatar_type == 'upload':
         if self.avatar_type == 'upload':
             image_prefix = '%s_' % image_size if image_size else ''
             image_prefix = '%s_' % image_size if image_size else ''
             return settings.MEDIA_URL + 'avatars/' + image_prefix + self.avatar_image
             return settings.MEDIA_URL + 'avatars/' + image_prefix + self.avatar_image
-        
+
         # Get gallery avatar
         # Get gallery avatar
         if self.avatar_type == 'gallery':
         if self.avatar_type == 'gallery':
             image_prefix = '_thumbs/%s/' % image_size if image_size else ''
             image_prefix = '_thumbs/%s/' % image_size if image_size else ''
             return settings.STATIC_URL + 'avatars/' + image_prefix + self.avatar_image
             return settings.STATIC_URL + 'avatars/' + image_prefix + self.avatar_image
-        
+
         # No avatar found, get gravatar
         # No avatar found, get gravatar
         if not image_size:
         if not image_size:
             image_size = settings.AVATAR_SIZES[0]
             image_size = settings.AVATAR_SIZES[0]
         return 'http://www.gravatar.com/avatar/%s?s=%s' % (hashlib.md5(self.email).hexdigest(), image_size)
         return 'http://www.gravatar.com/avatar/%s?s=%s' % (hashlib.md5(self.email).hexdigest(), image_size)
-    
+
     def get_title(self):
     def get_title(self):
         if self.title:
         if self.title:
             return self.title
             return self.title
         if self.rank:
         if self.rank:
             return self.rank.title
             return self.rank.title
         return None
         return None
-    
+
     def get_style(self):
     def get_style(self):
         if self.rank:
         if self.rank:
             return self.rank.style
             return self.rank.style
         return ''
         return ''
-    
+
     def email_user(self, request, template, subject, context={}):
     def email_user(self, request, template, subject, context={}):
         templates = request.theme.get_email_templates(template)
         templates = request.theme.get_email_templates(template)
         context = RequestContext(request, context)
         context = RequestContext(request, context)
         context['author'] = context['user']
         context['author'] = context['user']
         context['user'] = self
         context['user'] = self
-        
+
         # Set message recipient
         # Set message recipient
         if settings.DEBUG and settings.CATCH_ALL_EMAIL_ADDRESS:
         if settings.DEBUG and settings.CATCH_ALL_EMAIL_ADDRESS:
             recipient = settings.CATCH_ALL_EMAIL_ADDRESS
             recipient = settings.CATCH_ALL_EMAIL_ADDRESS
         else:
         else:
             recipient = self.email
             recipient = self.email
-            
+
         # Build and send message
         # Build and send message
         email = EmailMultiAlternatives(subject, templates[0].render(context), settings.EMAIL_HOST_USER, [recipient])
         email = EmailMultiAlternatives(subject, templates[0].render(context), settings.EMAIL_HOST_USER, [recipient])
         email.attach_alternative(templates[1].render(context), "text/html")
         email.attach_alternative(templates[1].render(context), "text/html")
         email.send()
         email.send()
-    
+
     def get_activation(self):
     def get_activation(self):
         activations = ['none', 'user', 'admin', 'credentials']
         activations = ['none', 'user', 'admin', 'credentials']
         return activations[self.activation]
         return activations[self.activation]
-    
+
     def alert(self, message):
     def alert(self, message):
         from misago.alerts.models import Alert
         from misago.alerts.models import Alert
         self.alerts += 1
         self.alerts += 1
         return Alert(user=self, message=message, date=tz_util.now())
         return Alert(user=self, message=message, date=tz_util.now())
-    
+
     def get_date(self):
     def get_date(self):
         return self.join_date
         return self.join_date
-    
+
     def sync_user(self):
     def sync_user(self):
         pass
         pass
 
 
@@ -475,42 +475,42 @@ class User(models.Model):
 class Guest(object):
 class Guest(object):
     """
     """
     Misago Guest dummy
     Misago Guest dummy
-    """    
+    """
     id = -1
     id = -1
     pk = -1
     pk = -1
     is_team = False
     is_team = False
-    
+
     def is_anonymous(self):
     def is_anonymous(self):
         return True
         return True
-    
+
     def is_authenticated(self):
     def is_authenticated(self):
         return False
         return False
-    
+
     def is_crawler(self):
     def is_crawler(self):
         return False
         return False
-        
+
     def get_roles(self):
     def get_roles(self):
         return Role.objects.filter(token='guest')
         return Role.objects.filter(token='guest')
-    
+
     def make_acl_key(self):
     def make_acl_key(self):
         return 'acl_guest'
         return 'acl_guest'
 
 
-        
-class Crawler(Guest): 
+
+class Crawler(Guest):
     """
     """
     Misago Crawler dummy
     Misago Crawler dummy
     """
     """
     is_team = False
     is_team = False
-    
+
     def __init__(self, username):
     def __init__(self, username):
         self.username = username
         self.username = username
-    
+
     def is_anonymous(self):
     def is_anonymous(self):
         return True
         return True
-    
+
     def is_authenticated(self):
     def is_authenticated(self):
         return False
         return False
-    
+
     def is_crawler(self):
     def is_crawler(self):
         return True
         return True
 
 

+ 2 - 2
misago/users/validators.py

@@ -14,7 +14,7 @@ def validate_username(value):
         raise ValidationError(_("Username can only contain letters and digits."))
         raise ValidationError(_("Username can only contain letters and digits."))
     if check_ban(username=value):
     if check_ban(username=value):
         raise ValidationError(_("This username is forbidden."))
         raise ValidationError(_("This username is forbidden."))
-        
+
 
 
 def validate_password(value):
 def validate_password(value):
     value = unicode(value).strip()
     value = unicode(value).strip()
@@ -45,4 +45,4 @@ def validate_password(value):
 def validate_email(value):
 def validate_email(value):
     value = unicode(value).strip()
     value = unicode(value).strip()
     if check_ban(email=value):
     if check_ban(email=value):
-        raise ValidationError(_("This board forbids registrations using this e-mail address."))
+        raise ValidationError(_("This board forbids registrations using this e-mail address."))

+ 57 - 57
misago/users/views.py

@@ -19,28 +19,28 @@ Views
 class List(ListWidget):
 class List(ListWidget):
     admin = site.get_action('users')
     admin = site.get_action('users')
     id = 'list'
     id = 'list'
-    columns=(
-             ('username_slug', _("User Name"), 35),
-             ('join_date', _("Join Date")),
-             )
+    columns = (
+               ('username_slug', _("User Name"), 35),
+               ('join_date', _("Join Date")),
+               )
     default_sorting = 'username'
     default_sorting = 'username'
-    sortables={
-               'username_slug': 1,
-               'join_date': 0,
-              }
+    sortables = {
+                 'username_slug': 1,
+                 'join_date': 0,
+                }
     pagination = 25
     pagination = 25
     search_form = SearchUsersForm
     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=(
-             ('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', _("Delete users"), _("Are you sure you want to delete selected users?")),
-             )
-    
+    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', _("Delete users"), _("Are you sure you want to delete selected users?")),
+               )
+
     def set_filters(self, model, filters):
     def set_filters(self, model, filters):
         if 'role' in filters:
         if 'role' in filters:
             model = model.filter(roles__in=filters['role']).distinct()
             model = model.filter(roles__in=filters['role']).distinct()
@@ -77,16 +77,16 @@ class List(ListWidget):
         if 'activation' in filters:
         if 'activation' in filters:
             model = model.filter(activation__in=filters['activation'])
             model = model.filter(activation__in=filters['activation'])
         return model
         return model
-    
+
     def prefetch_related(self, items):
     def prefetch_related(self, items):
         return items.prefetch_related('roles')
         return items.prefetch_related('roles')
-    
+
     def get_item_actions(self, item):
     def get_item_actions(self, item):
         return (
         return (
                 self.action('pencil', _("Edit User Details"), reverse('admin_users_edit', item)),
                 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?")),
                 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):
     def action_activate(self, items, checked):
         for user in items:
         for user in items:
             if unicode(user.pk) in checked and user.activation > 0:
             if unicode(user.pk) in checked and user.activation > 0:
@@ -98,16 +98,16 @@ class List(ListWidget):
                                 'users/activation/admin_done',
                                 'users/activation/admin_done',
                                 _("Your Account has been activated"),
                                 _("Your Account has been activated"),
                                 )
                                 )
-                
+
         return Message(_('Selected users accounts have been activated.'), 'success'), reverse('admin_users')
         return Message(_('Selected users accounts have been activated.'), 'success'), reverse('admin_users')
-    
+
     def action_deactivate(self, items, checked):
     def action_deactivate(self, items, checked):
         # First loop - check for errors
         # First loop - check for errors
         for user in items:
         for user in items:
             if unicode(user.pk) in checked:
             if unicode(user.pk) in checked:
                 if user.is_protected() and not self.request.user.is_god():
                 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')
                     return Message(_('You cannot force validation of protected members e-mails.'), 'error'), reverse('admin_users')
-                
+
         # Second loop - reset passwords
         # Second loop - reset passwords
         for user in items:
         for user in items:
             if unicode(user.pk) in checked:
             if unicode(user.pk) in checked:
@@ -119,7 +119,7 @@ class List(ListWidget):
                                 'users/activation/invalidated',
                                 'users/activation/invalidated',
                                 _("Account Activation"),
                                 _("Account Activation"),
                                 )
                                 )
-                
+
         return Message(_('Selected users accounts have been deactivated and new activation links have been sent to them.'), 'success'), reverse('admin_users')
         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):
     def action_remove_av(self, items, checked):
@@ -128,13 +128,13 @@ class List(ListWidget):
             if unicode(user.pk) in checked:
             if unicode(user.pk) in checked:
                 if user.is_protected() and not self.request.user.is_god():
                 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')
                     return Message(_('You cannot remove and block protected members avatars.'), 'error'), reverse('admin_users')
-                
+
         # Second loop - reset passwords
         # Second loop - reset passwords
         for user in items:
         for user in items:
             if unicode(user.pk) in checked:
             if unicode(user.pk) in checked:
                 user.lock_avatar()
                 user.lock_avatar()
                 user.save(force_update=True)
                 user.save(force_update=True)
-                
+
         return Message(_('Selected users avatars were deleted and locked.'), 'success'), reverse('admin_users')
         return Message(_('Selected users avatars were deleted and locked.'), 'success'), reverse('admin_users')
 
 
     def action_remove_sig(self, items, checked):
     def action_remove_sig(self, items, checked):
@@ -143,7 +143,7 @@ class List(ListWidget):
             if unicode(user.pk) in checked:
             if unicode(user.pk) in checked:
                 if user.is_protected() and not self.request.user.is_god():
                 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')
                     return Message(_('You cannot remove and block protected members signatures.'), 'error'), reverse('admin_users')
-                
+
         # Second loop - reset passwords
         # Second loop - reset passwords
         for user in items:
         for user in items:
             if unicode(user.pk) in checked:
             if unicode(user.pk) in checked:
@@ -151,9 +151,9 @@ class List(ListWidget):
                 user.signature = ''
                 user.signature = ''
                 user.signature_preparsed = ''
                 user.signature_preparsed = ''
                 user.save(force_update=True)
                 user.save(force_update=True)
-                
+
         return Message(_('Selected users signatures were deleted and locked.'), 'success'), reverse('admin_users')
         return Message(_('Selected users signatures were deleted and locked.'), 'success'), reverse('admin_users')
-   
+
     def action_remove_locks(self, items, checked):
     def action_remove_locks(self, items, checked):
         for user in items:
         for user in items:
             if unicode(user.pk) in checked:
             if unicode(user.pk) in checked:
@@ -161,16 +161,16 @@ class List(ListWidget):
                 user.avatar_ban = False
                 user.avatar_ban = False
                 user.signature_ban = False
                 user.signature_ban = False
                 user.save(force_update=True)
                 user.save(force_update=True)
-                
+
         return Message(_('Selected users can now edit their avatars and signatures.'), 'success'), reverse('admin_users')
         return Message(_('Selected users can now edit their avatars and signatures.'), 'success'), reverse('admin_users')
-    
+
     def action_reset(self, items, checked):
     def action_reset(self, items, checked):
         # First loop - check for errors
         # First loop - check for errors
         for user in items:
         for user in items:
             if unicode(user.pk) in checked:
             if unicode(user.pk) in checked:
                 if user.is_protected() and not self.request.user.is_god():
                 if user.is_protected() and not self.request.user.is_god():
                     return Message(_('You cannot reset protected members passwords.'), 'error'), reverse('admin_users')
                     return Message(_('You cannot reset protected members passwords.'), 'error'), reverse('admin_users')
-                
+
         # Second loop - reset passwords
         # Second loop - reset passwords
         for user in items:
         for user in items:
             if unicode(user.pk) in checked:
             if unicode(user.pk) in checked:
@@ -185,7 +185,7 @@ class List(ListWidget):
                                  'password': new_password,
                                  'password': new_password,
                                  },
                                  },
                                 )
                                 )
-                
+
         return Message(_('Selected users passwords have been reset successfully.'), 'success'), reverse('admin_users')
         return Message(_('Selected users passwords have been reset successfully.'), 'success'), reverse('admin_users')
 
 
     def action_delete(self, items, checked):
     def action_delete(self, items, checked):
@@ -195,28 +195,28 @@ class List(ListWidget):
                     return Message(_('You cannot delete yourself.'), 'error'), reverse('admin_users')
                     return Message(_('You cannot delete yourself.'), 'error'), reverse('admin_users')
                 if user.is_protected():
                 if user.is_protected():
                     return Message(_('You cannot delete protected members.'), 'error'), reverse('admin_users')
                     return Message(_('You cannot delete protected members.'), 'error'), reverse('admin_users')
-        
+
         for user in items:
         for user in items:
             if unicode(user.pk) in checked:
             if unicode(user.pk) in checked:
                 user.delete()
                 user.delete()
-                
+
         User.objects.resync_monitor(self.request.monitor)
         User.objects.resync_monitor(self.request.monitor)
         return Message(_('Selected users have been deleted successfully.'), 'success'), reverse('admin_users')
         return Message(_('Selected users have been deleted successfully.'), 'success'), reverse('admin_users')
-    
+
 
 
 class New(FormWidget):
 class New(FormWidget):
     admin = site.get_action('users')
     admin = site.get_action('users')
     id = 'new'
     id = 'new'
-    fallback = 'admin_users' 
+    fallback = 'admin_users'
     form = NewUserForm
     form = NewUserForm
     submit_button = _("Save User")
     submit_button = _("Save User")
-        
+
     def get_new_url(self, model):
     def get_new_url(self, model):
         return reverse('admin_users_new')
         return reverse('admin_users_new')
-    
+
     def get_edit_url(self, model):
     def get_edit_url(self, model):
         return reverse('admin_users_edit', model)
         return reverse('admin_users_edit', model)
-    
+
     def submit_form(self, form, target):
     def submit_form(self, form, target):
         new_user = User.objects.create_user(
         new_user = User.objects.create_user(
                                             form.cleaned_data['username'],
                                             form.cleaned_data['username'],
@@ -229,15 +229,15 @@ class New(FormWidget):
                                             )
                                             )
         new_user.title = form.cleaned_data['title']
         new_user.title = form.cleaned_data['title']
         new_user.rank = form.cleaned_data['rank']
         new_user.rank = form.cleaned_data['rank']
-        
+
         for role in form.cleaned_data['roles']:
         for role in form.cleaned_data['roles']:
             new_user.roles.add(role)
             new_user.roles.add(role)
         new_user.make_acl_key(True)
         new_user.make_acl_key(True)
         new_user.save(force_update=True)
         new_user.save(force_update=True)
-        
+
         return new_user, Message(_('New User has been created.'), 'success')
         return new_user, Message(_('New User has been created.'), 'success')
-    
-    
+
+
 class Edit(FormWidget):
 class Edit(FormWidget):
     admin = site.get_action('users')
     admin = site.get_action('users')
     id = 'edit'
     id = 'edit'
@@ -248,18 +248,18 @@ class Edit(FormWidget):
     target_name = 'username'
     target_name = 'username'
     notfound_message = _('Requested User could not be found.')
     notfound_message = _('Requested User could not be found.')
     submit_fallback = True
     submit_fallback = True
-    
+
     def get_form_instance(self, form, model, initial, post=False):
     def get_form_instance(self, form, model, initial, post=False):
         if post:
         if post:
             return form(model, self.request.POST, request=self.request, initial=self.get_initial_data(model))
             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))
         return form(model, request=self.request, initial=self.get_initial_data(model))
-        
+
     def get_url(self, model):
     def get_url(self, model):
         return reverse('admin_users_edit', model)
         return reverse('admin_users_edit', model)
-    
+
     def get_edit_url(self, model):
     def get_edit_url(self, model):
         return self.get_url(model)
         return self.get_url(model)
-    
+
     def get_initial_data(self, model):
     def get_initial_data(self, model):
         return {
         return {
                 'username': model.username,
                 'username': model.username,
@@ -275,7 +275,7 @@ class Edit(FormWidget):
                 'signature_ban_reason_user': model.signature_ban_reason_user,
                 'signature_ban_reason_user': model.signature_ban_reason_user,
                 'signature_ban_reason_admin': model.signature_ban_reason_admin,
                 'signature_ban_reason_admin': model.signature_ban_reason_admin,
                 }
                 }
-    
+
     def submit_form(self, form, target):
     def submit_form(self, form, target):
         target.title = form.cleaned_data['title']
         target.title = form.cleaned_data['title']
         target.rank = form.cleaned_data['rank']
         target.rank = form.cleaned_data['rank']
@@ -284,7 +284,7 @@ class Edit(FormWidget):
         target.signature_ban = form.cleaned_data['signature_ban']
         target.signature_ban = form.cleaned_data['signature_ban']
         target.signature_ban_reason_user = form.cleaned_data['signature_ban_reason_user']
         target.signature_ban_reason_user = form.cleaned_data['signature_ban_reason_user']
         target.signature_ban_reason_admin = form.cleaned_data['signature_ban_reason_admin']
         target.signature_ban_reason_admin = form.cleaned_data['signature_ban_reason_admin']
-        
+
         # Do signature mumbo-jumbo
         # Do signature mumbo-jumbo
         if form.cleaned_data['signature']:
         if form.cleaned_data['signature']:
             target.signature = form.cleaned_data['signature']
             target.signature = form.cleaned_data['signature']
@@ -293,7 +293,7 @@ class Edit(FormWidget):
         else:
         else:
             target.signature = None
             target.signature = None
             target.signature_preparsed = None
             target.signature_preparsed = None
-        
+
         # Do avatar ban mumbo-jumbo
         # Do avatar ban mumbo-jumbo
         if target.avatar_ban != form.cleaned_data['avatar_ban']:
         if target.avatar_ban != form.cleaned_data['avatar_ban']:
             if form.cleaned_data['avatar_ban']:
             if form.cleaned_data['avatar_ban']:
@@ -301,13 +301,13 @@ class Edit(FormWidget):
             else:
             else:
                 target.default_avatar(self.request.settings)
                 target.default_avatar(self.request.settings)
         target.avatar_ban = form.cleaned_data['avatar_ban']
         target.avatar_ban = form.cleaned_data['avatar_ban']
-               
+
         # Set custom avatar
         # Set custom avatar
         if form.cleaned_data['avatar_custom']:
         if form.cleaned_data['avatar_custom']:
             target.delete_avatar()
             target.delete_avatar()
             target.avatar_image = form.cleaned_data['avatar_custom']
             target.avatar_image = form.cleaned_data['avatar_custom']
             target.avatar_type = 'gallery'
             target.avatar_type = 'gallery'
-        
+
         # Update user roles
         # Update user roles
         if self.request.user.is_god():
         if self.request.user.is_god():
             target.roles.clear()
             target.roles.clear()
@@ -319,7 +319,7 @@ class Edit(FormWidget):
                     target.roles.remove(role)
                     target.roles.remove(role)
             for role in form.cleaned_data['roles']:
             for role in form.cleaned_data['roles']:
                 target.roles.add(role)
                 target.roles.add(role)
-        
+
         target.make_acl_key(True)
         target.make_acl_key(True)
         target.save(force_update=True)
         target.save(force_update=True)
         return target, Message(_('Changes in user\'s "%(name)s" account have been saved.') % {'name': self.original_name}, 'success')
         return target, Message(_('Changes in user\'s "%(name)s" account have been saved.') % {'name': self.original_name}, 'success')
@@ -330,7 +330,7 @@ class Delete(ButtonWidget):
     id = 'delete'
     id = 'delete'
     fallback = 'admin_users'
     fallback = 'admin_users'
     notfound_message = _('Requested User account could not be found.')
     notfound_message = _('Requested User account could not be found.')
-    
+
     def action(self, target):
     def action(self, target):
         if target.pk == self.request.user.id:
         if target.pk == self.request.user.id:
             return Message(_('You cannot delete yourself.'), 'error'), False
             return Message(_('You cannot delete yourself.'), 'error'), False
@@ -344,4 +344,4 @@ class Delete(ButtonWidget):
 def inactive(request):
 def inactive(request):
     token = 'list_filter_misago.users.models.User'
     token = 'list_filter_misago.users.models.User'
     request.session[token] = {'activation': ['1', '2', '3']}
     request.session[token] = {'activation': ['1', '2', '3']}
-    return redirect(reverse('admin_users'))
+    return redirect(reverse('admin_users'))

+ 12 - 12
misago/utils/__init__.py

@@ -8,7 +8,7 @@ try:
     from unidecode import unidecode
     from unidecode import unidecode
 except ImportError:
 except ImportError:
     use_unidecode = False
     use_unidecode = False
-    
+
 def slugify(string):
 def slugify(string):
     if use_unidecode:
     if use_unidecode:
         string = unidecode(string)
         string = unidecode(string)
@@ -35,14 +35,14 @@ def get_msgid(gettext):
 Random string
 Random string
 """
 """
 from django.utils import crypto
 from django.utils import crypto
-    
+
 def get_random_string(length):
 def get_random_string(length):
     return crypto.get_random_string(length, "1234567890qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM")
     return crypto.get_random_string(length, "1234567890qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM")
 
 
 
 
 """
 """
 Date formats
 Date formats
-"""               
+"""
 from django.utils.formats import get_format
 from django.utils.formats import get_format
 
 
 formats = {
 formats = {
@@ -57,27 +57,27 @@ formats = {
 
 
 for key in formats:
 for key in formats:
     formats[key] = get_format(key).replace('P', 'g:i a')
     formats[key] = get_format(key).replace('P', 'g:i a')
-    
-    
+
+
 """
 """
 Build pagination list
 Build pagination list
 """
 """
 import math
 import math
 
 
 def make_pagination(page, total, max):
 def make_pagination(page, total, max):
-    pagination = {'start': 0, 'stop': 0, 'prev': -1, 'next': -1}
+    pagination = {'start': 0, 'stop': 0, 'prev':-1, 'next':-1}
     page = int(page)
     page = int(page)
     if page > 0:
     if page > 0:
         pagination['start'] = (page - 1) * max
         pagination['start'] = (page - 1) * max
-        
+
     # Set page and total stat
     # Set page and total stat
     pagination['page'] = int(pagination['start'] / max) + 1
     pagination['page'] = int(pagination['start'] / max) + 1
     pagination['total'] = int(math.ceil(total / float(max)))
     pagination['total'] = int(math.ceil(total / float(max)))
-        
+
     # Fix too large offset
     # Fix too large offset
     if pagination['start'] > total:
     if pagination['start'] > total:
         pagination['start'] = 0
         pagination['start'] = 0
-        
+
     # Allow prev/next?
     # Allow prev/next?
     if total > max:
     if total > max:
         if pagination['page'] > 1:
         if pagination['page'] > 1:
@@ -87,8 +87,8 @@ def make_pagination(page, total, max):
 
 
     # Fix empty pagers
     # Fix empty pagers
     if not pagination['total']:
     if not pagination['total']:
-        pagination['total'] = 1 
-            
+        pagination['total'] = 1
+
     # Set stop offset
     # Set stop offset
     pagination['stop'] = pagination['start'] + max
     pagination['stop'] = pagination['start'] + max
-    return pagination
+    return pagination

+ 2 - 2
misago/utils/avatars.py

@@ -40,7 +40,7 @@ def resizeimage(image, size, target, info=None, format=None):
         image.save(target, quality=95)
         image.save(target, quality=95)
     if format == "JPEG":
     if format == "JPEG":
         image = image.convert("RGB")
         image = image.convert("RGB")
-        image = image.resize((size, size), Image.ANTIALIAS) 
+        image = image.resize((size, size), Image.ANTIALIAS)
         image = image.convert('P', palette=Image.ADAPTIVE)
         image = image.convert('P', palette=Image.ADAPTIVE)
         image = image.convert("RGB", dither=None)
         image = image.convert("RGB", dither=None)
-        image.save(target, image.format, quality=95)
+        image.save(target, image.format, quality=95)

+ 2 - 2
misago/utils/validators.py

@@ -6,10 +6,10 @@ class validate_sluggable(object):
     def __init__(self, error_short=None, error_long=None):
     def __init__(self, error_short=None, error_long=None):
         self.error_short = error_short if error_short else _("Value has to contain alpha-numerical characters.")
         self.error_short = error_short if error_short else _("Value has to contain alpha-numerical characters.")
         self.error_long = error_long if error_long else _("Value is too long.")
         self.error_long = error_long if error_long else _("Value is too long.")
-         
+
     def __call__(self, value):
     def __call__(self, value):
         slug = slugify(value)
         slug = slugify(value)
         if not slug:
         if not slug:
             raise ValidationError(self.error_short)
             raise ValidationError(self.error_short)
         if len(slug) > 255:
         if len(slug) > 255:
-            raise ValidationError(self.error_long)
+            raise ValidationError(self.error_long)

+ 4 - 4
misago/views.py

@@ -25,7 +25,7 @@ def home(request):
             thread.forum_slug = thread.forum.slug
             thread.forum_slug = thread.forum.slug
             popular_threads.append(thread)
             popular_threads.append(thread)
         cache.set('thread_ranking_%s' % request.user.make_acl_key(), popular_threads, request.settings['thread_ranking_refresh'])
         cache.set('thread_ranking_%s' % request.user.make_acl_key(), popular_threads, request.settings['thread_ranking_refresh'])
-          
+
     # Ranks online
     # Ranks online
     ranks_list = cache.get('users_online', 'nada')
     ranks_list = cache.get('users_online', 'nada')
     if ranks_list == 'nada':
     if ranks_list == 'nada':
@@ -44,7 +44,7 @@ def home(request):
             del ranks_dict
             del ranks_dict
             del users_list
             del users_list
         cache.set('ranks_list', ranks_list, 10)
         cache.set('ranks_list', ranks_list, 10)
-            
+
     # Render page with forums list
     # Render page with forums list
     reads_tracker = ForumsTracker(request.user)
     reads_tracker = ForumsTracker(request.user)
     return request.theme.render_to_response('index.html',
     return request.theme.render_to_response('index.html',
@@ -114,7 +114,7 @@ def redirect_message(request, message, type='info', owner=None):
 def error403(request, message=None):
 def error403(request, message=None):
     return error_view(request, 403, message)
     return error_view(request, 403, message)
 
 
-                                            
+
 def error404(request, message=None):
 def error404(request, message=None):
     return error_view(request, 404, message)
     return error_view(request, 404, message)
 
 
@@ -128,4 +128,4 @@ def error_view(request, error, message):
                                                  },
                                                  },
                                                 context_instance=RequestContext(request));
                                                 context_instance=RequestContext(request));
     response.status_code = error
     response.status_code = error
-    return response
+    return response