Browse Source

Ran pyDev formatters on Misago .py files.

Ralfp 12 years ago
parent
commit
dc7004227a
177 changed files with 1533 additions and 1544 deletions
  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 = {
     'default': {
         '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
 INSTALLED_THEMES = (
-    'sora',  # Default style always first
+    'sora', # Default style always first
     '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'}
         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):
     def __init__(self):
         self.acl = {}
-        
+
     def __repr__(self):
         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')
     perms = []
     forum_roles = {}
-    
+
     for role in roles:
         perms.append(role.get_permissions())
-    
+
     for role in ForumRole.objects.all():
         forum_roles[role.pk] = role.get_permissions()
-    
+
     for provider in settings.PERMISSION_PROVIDERS:
         app_module = import_module(provider)
         try:
@@ -67,7 +67,7 @@ def build_acl(request, roles):
             app_module.build_forums(acl, perms, forums, forum_roles)
         except AttributeError:
             pass
-        
+
     for provider in settings.PERMISSION_PROVIDERS:
         app_module = import_module(provider)
         try:
@@ -75,4 +75,4 @@ def build_acl(request, roles):
         except AttributeError:
             pass
 
-    return acl
+    return acl

+ 1 - 1
misago/acl/context_processors.py

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

+ 1 - 1
misago/acl/fixtures.py

@@ -6,4 +6,4 @@ monitor_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):
             user_acl = build_acl(request, request.user.get_roles())
             cache.set(acl_key, user_acl, 2592000)
-        
+
         request.acl = user_acl
         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.save(force_update=True)
         if 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):
         self.request = request
-        
+
     def content(self):
         context = self.context.copy()
         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)
         except ACLError404 as e:
             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 import captcha
 from misago.users.models import User
-    
-    
+
+
 class UserSendActivationMailForm(Form):
     email = forms.EmailField(max_length=255)
     captcha_qa = captcha.QACaptchaField()
     recaptcha = captcha.ReCaptchaField()
     error_source = 'email'
-    
+
     layout = [
               (
                None,
@@ -23,7 +23,7 @@ class UserSendActivationMailForm(Form):
                ['captcha_qa', 'recaptcha']
                ),
               ]
-    
+
     def clean_email(self):
         try:
             email = self.cleaned_data['email'].lower()
@@ -31,4 +31,4 @@ class UserSendActivationMailForm(Form):
             self.found_user = User.objects.get(email_hash=email_hash)
         except User.DoesNotExist:
             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',
     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"),
-)
+)

+ 13 - 13
misago/activation/views.py

@@ -23,16 +23,16 @@ def form(request):
         if form.is_valid():
             user = form.found_user
             user_ban = check_ban(username=user.username, email=user.email)
-            
+
             if user_ban:
                 return error_banned(request, user, user_ban)
-            
+
             if user.activation == User.ACTIVATION_NONE:
                 return redirect_message(request, Message(_("%(username)s, your account is already active.") % {'username': user.username}), 'info')
-            
+
             if user.activation == User.ACTIVATION_ADMIN:
                 return redirect_message(request, Message(_("%(username)s, only board administrator can activate your account.") % {'username': user.username}), 'info')
-        
+
             user.email_user(
                             request,
                             'users/activation/resend',
@@ -56,35 +56,35 @@ def form(request):
 @block_jammed
 def activate(request, username="", user="0", token=""):
     user = int(user)
-    
+
     try:
         user = User.objects.get(pk=user)
         current_activation = user.activation
-        
+
         # Run checks
         user_ban = check_ban(username=user.username, email=user.email)
         if user_ban:
             return error_banned(request, user, user_ban)
-        
+
         if user.activation == User.ACTIVATION_NONE:
             return redirect_message(request, Message(_("%(username)s, your account is already active.") % {'username': user.username}), 'info')
-            
+
         if user.activation == User.ACTIVATION_ADMIN:
             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:
             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
         user.activation = User.ACTIVATION_NONE
         sign_user_in(request, user)
-        
+
         # Update monitor
         User.objects.resync_monitor(request.monitor)
-        
+
         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')
         else:
             return redirect_message(request, Message(_("%(username)s, your account has been successfully activated. Welcome aboard!") % {'username': user.username}), 'success')
     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:] == '/':
         ADMIN_PATH = ADMIN_PATH[:-1]
     ADMIN_PATH += '/'
-    
+
 
 """
 Admin lists sorter for admin sections and actions
@@ -22,7 +22,7 @@ Admin lists sorter for admin sections and actions
 class SortList(object):
     def __init__(self, unsorted):
         self.unsorted = unsorted
-        
+
     def sort(self):
         # Sort and return sorted list
         order = []
@@ -53,8 +53,8 @@ class SortList(object):
                     sorted.append(object)
                     break
         return sorted
-        
-            
+
+
 """
 Admin site section
 """
@@ -68,8 +68,8 @@ class AdminSiteItem(object):
         self.target = target
         self.route = route
         self.sorted = False
-    
-    
+
+
 """
 Admin site action
 """
@@ -81,13 +81,13 @@ class AdminAction(AdminSiteItem):
         self.messages = messages
         self.urlpatterns = urlpatterns
         super(AdminAction, self).__init__(**kwargs)
-    
+
     def get_action_attr(self, id, attr):
         for action in self.actions:
             if action['id'] == id:
                 return action[attr]
         return None
-    
+
     def is_active(self, full_path, section=None):
         if section:
             action_path = '/%s%s/%s/' % (ADMIN_PATH, section, self.id)
@@ -105,7 +105,7 @@ class AdminSection(AdminSiteItem):
         self.actions = []
         self.last = None
         super(AdminSection, self).__init__(**kwargs)
-        
+
     def get_routes(self):
         routes = []
         first_action = True
@@ -116,7 +116,7 @@ class AdminSection(AdminSiteItem):
             else:
                 routes += patterns('', url(('^%s/' % action.id), include(action.urlpatterns)))
         return routes
-            
+
     def is_active(self, full_path):
         action_path = '/%s%s/' % (ADMIN_PATH, self.id)
         # Paths overlap = active action
@@ -131,7 +131,7 @@ class AdminSite(object):
     routes = []
     sections = []
     sections_index = {}
-    
+
     def discover(self):
         """
         Build admin site structure
@@ -139,19 +139,19 @@ class AdminSite(object):
         # Return discovered admin routes, so we dont repeat ourself
         if self.routes:
             return self.routes
-        
+
         # Found actions
         actions = []
-        
+
         # Orphan actions that have no section yet
         late_actions = []
-        
+
         # Load default admin site
         from misago.admin.layout.sections import ADMIN_SECTIONS
         for section in ADMIN_SECTIONS:
             self.sections.append(section)
             self.sections_index[section.id] = section
-            
+
             # Loop section actions
             section_actions = import_module('misago.admin.layout.%s' % section.id)
             for action in section_actions.ADMIN_ACTIONS:
@@ -160,12 +160,12 @@ class AdminSite(object):
                      action.after = self.sections_index[section.id].last
                 actions.append(action)
                 self.sections_index[section.id].last = action.after
-        
+
         # Iterate over installed applications
         for app_name in settings.INSTALLED_APPS:
             try:
                 app = import_module(app_name + '.admin')
-                
+
                 # Attempt to import sections
                 try:
                     for section in app.ADMIN_SECTIONS:
@@ -173,7 +173,7 @@ class AdminSite(object):
                         self.sections_index[section.id] = section
                 except AttributeError:
                     pass
-                
+
                 # Attempt to import actions
                 try:
                     for action in app.ADMIN_ACTIONS:
@@ -189,20 +189,20 @@ class AdminSite(object):
                     pass
             except ImportError:
                 pass
-                
+
         # So actions and late actions
         actions += late_actions
-        
+
         # Sorth sections and actions
         sort_sections = SortList(self.sections)
         sort_actions = SortList(actions)
         self.sections = sort_sections.sort()
         actions = sort_actions.sort()
-        
+
         # Put actions in sections
         for action in actions:
             self.sections_index[action.section].actions.append(action)
-        
+
         # Return ready admin routing
         first_section = True
         for section in self.sections:
@@ -212,19 +212,19 @@ class AdminSite(object):
             else:
                 self.routes += patterns('', url(('^%s/' % section.id), include(section.get_routes())))
         return self.routes
-    
+
     def get_action(self, action):
         """
         Get admin action
         """
         return self.actions_index.get(action)
-            
+
     def get_admin_index(self):
         """
         Return admin index route - first action of first section
         """
         return self.sections[0].actions[0].route
-            
+
     def get_admin_navigation(self, request):
         """
         Find and return current admin navigation
@@ -233,7 +233,7 @@ class AdminSite(object):
         actions = []
         active_section = False
         active_action = False
-        
+
         # Loop sections, build list of sections and find active section
         for section in self.sections:
             is_active = section.is_active(request.path)
@@ -245,12 +245,12 @@ class AdminSite(object):
                              })
             if is_active:
                 active_section = section
-        
+
         # If no section was found to be active, default to first one
         if not active_section:
             active_section = self.sections[0]
             sections[0]['is_active'] = True
-            
+
         # Loop 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)
@@ -263,12 +263,12 @@ class AdminSite(object):
                              })
             if is_active:
                 active_action = action
-        
+
         # If no action was found to be active, default to first one
         if not active_action:
             active_action = active_section.actions[0]
             actions[0]['is_active'] = True
-        
+
         # Return admin navigation for this location
         return {
                 '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):
     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((
                             _("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.")}),),
@@ -15,15 +15,15 @@ def make_form(request, role, form):
 class AdminACL(BaseACL):
     def is_admin(self):
         return self.acl['can_use_acp']
-    
+
 
 def build(acl, roles):
     acl.admin = AdminACL()
     acl.admin.acl['can_use_acp'] = False
-    
+
     for role in roles:
         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']
-            
+
     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
 
 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.utils import ugettext_lazy as _
 from misago.utils import get_msgid
-    
+
 admin_fixtures = {
     # Overview
     'overview': {
@@ -10,32 +10,32 @@ admin_fixtures = {
         'icon': 'signal',
         'pos': 0,
     },
-    
+
     # Users
     'users': {
         'name': _('Users'),
         'icon': 'user',
         'pos': 100,
     },
-    
+
     # Forums
     'forums': {
         'name': _('Forums'),
         'icon': 'comment',
         'pos': 200,
     },
-    
+
     # Permissions
     'permissions': {
         'name': _('Permissions'),
         'icon': 'adjust',
         'pos': 300,
     },
-    
+
     # System
     'system': {
         'name': _('System'),
         'icon': 'wrench',
         '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.forums.models import Forum
 
-ADMIN_ACTIONS=(
+ADMIN_ACTIONS = (
    AdminAction(
                section='forums',
                id='forums',
@@ -93,4 +93,4 @@ ADMIN_ACTIONS=(
                         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.users.models import User
 
-ADMIN_ACTIONS=(
+ADMIN_ACTIONS = (
    AdminAction(
                section='overview',
                id='home',
@@ -43,7 +43,7 @@ ADMIN_ACTIONS=(
                          'route': 'admin_online'
                          },
                         ],
-               route='admin_online', 
+               route='admin_online',
                urlpatterns=patterns('misago.sessions.views',
                         url(r'^$', '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'),
                     ),
                ),
-)
+)

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

@@ -5,7 +5,7 @@ from misago.roles.models import Role
 from misago.forumroles.models import ForumRole
 
 
-ADMIN_ACTIONS=(
+ADMIN_ACTIONS = (
    AdminAction(
                section='perms',
                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'),
                     ),
                ),
-)
+)

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

@@ -1,7 +1,7 @@
 from django.utils.translation import ugettext_lazy as _
 from misago.admin import AdminSection
 
-ADMIN_SECTIONS=(
+ADMIN_SECTIONS = (
     AdminSection(
                  id='overview',
                  name=_("Overview"),
@@ -27,4 +27,4 @@ ADMIN_SECTIONS=(
                  name=_("System"),
                  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 misago.admin import AdminAction
 
-ADMIN_ACTIONS=(
+ADMIN_ACTIONS = (
    AdminAction(
                section='system',
                id='settings',
@@ -16,4 +16,4 @@ ADMIN_ACTIONS=(
                         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.users.models import User
 
-ADMIN_ACTIONS=(
+ADMIN_ACTIONS = (
    AdminAction(
                section='users',
                id='users',
@@ -159,4 +159,4 @@ ADMIN_ACTIONS=(
                         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),
         }, context_instance=RequestContext(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
     help = None
     notfound_message = None
-    
+
     def __new__(cls, request, **kwargs):
         obj = super(BaseWidget, cls).__new__(cls)
         if not obj.name:
@@ -32,35 +32,35 @@ class BaseWidget(object):
         if not obj.help:
             obj.help = obj.get_help()
         return obj(request, **kwargs)
-    
+
     def get_token(self, token):
         return '%s_%s_%s' % (self.id, token, str('%s.%s' % (self.admin.model.__module__, self.admin.model.__name__)))
-        
+
     def get_url(self):
         return reverse(self.admin.get_action_attr(self.id, 'route'))
-    
+
     def get_name(self):
         return self.admin.get_action_attr(self.id, 'name')
-    
+
     def get_help(self):
         return self.admin.get_action_attr(self.id, 'help')
-    
+
     def get_id(self):
         return 'admin_%s' % self.id
-         
+
     def get_template(self):
         return ('%s/%s.html' % (self.admin.id, self.template),
                 'admin/%s.html' % self.template)
-    
+
     def add_template_variables(self, variables):
         return variables
-            
+
     def get_fallback_url(self):
         return reverse(self.fallback)
-        
+
     def get_target(self, model):
         pass
-    
+
     def get_target_name(self, model):
         try:
             if self.translate_target_name:
@@ -68,7 +68,7 @@ class BaseWidget(object):
             return model.__dict__[self.target_name]
         except AttributeError:
             return None
-        
+
     def get_and_validate_target(self, target):
         try:
             model = self.admin.model.objects.select_related().get(pk=target)
@@ -85,7 +85,7 @@ class ListWidget(BaseWidget):
     """
     Items list widget
     """
-    actions =[]
+    actions = []
     columns = []
     sortables = {}
     default_sorting = None
@@ -99,14 +99,14 @@ class ListWidget(BaseWidget):
     empty_search_message = _('Search has returned no items')
     nothing_checked_message = _('You have to select at least one item.')
     prompt_select = False
-    
+
     def get_item_actions(self, item):
         """
         Provides request and item, should return list of tuples with item actions in following format:
         (id, name, help, icon, link)
         """
         return []
-    
+
     def action(self, icon=None, name=None, url=None, post=False, prompt=None):
         """
         Function call to make hash with item actions
@@ -120,31 +120,31 @@ class ListWidget(BaseWidget):
                 'post': post,
                 'prompt': prompt,
                 }
-        
+
     def get_search_form(self):
         """
         Build a form object with items search
         """
         return self.search_form
-            
+
     def set_filters(self, model, filters):
         """
         Set filters on model using filters from session
         """
         return None
-    
+
     def get_table_form(self, page_items):
         """
         Build a form object with list of all items fields
         """
         return None
-    
+
     def table_action(self, page_items, cleaned_data):
         """
         Handle table form submission, return tuple containing message and redirect link/false
         """
         return None
-    
+
     def get_actions_form(self, page_items):
         """
         Build a form object with list of all items actions
@@ -159,9 +159,9 @@ class ListWidget(BaseWidget):
         list_choices = []
         for item in page_items:
             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)
-        
+
     def get_sorting(self):
         """
         Return list sorting method.
@@ -173,7 +173,7 @@ class ListWidget(BaseWidget):
         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:
             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:
             new_sorting = self.request.GET.get('sort')
             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
                    ]
             self.request.session[self.get_token('sort')] = sorting_method
-            
+
         if not sorting_method:
             if self.sortables:
                 new_sorting = self.sortables.keys()[0]
@@ -201,13 +201,13 @@ class ListWidget(BaseWidget):
                         '-id'
                        ]
         return sorting_method
-    
+
     def sort_items(self, page_items, sorting_method):
         return page_items.order_by(sorting_method[2])
-    
+
     def get_pagination_url(self, page):
         return reverse(self.admin.get_action_attr(self.id, 'route'), kwargs={'page': page})
-    
+
     def get_pagination(self, total, page):
         """
         Return list pagination.
@@ -222,86 +222,86 @@ class ListWidget(BaseWidget):
         if not self.pagination or total < 0:
             # Dont do anything if we are not paging
             return None
-        
+
         # 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')):
             pagination['start'] = self.request.session.get(self.get_token('pagination'))
         page = int(page)
         if page > 0:
             pagination['start'] = (page - 1) * self.pagination
-            
+
         # Set page and total stat
         pagination['page'] = int(pagination['start'] / self.pagination) + 1
         pagination['total'] = int(math.ceil(total / float(self.pagination)))
-            
+
         # Fix too large offset
         if pagination['start'] > total:
             pagination['start'] = 0
-            
+
         # Allow prev/next?
         if total > self.pagination:
             if pagination['page'] > 1:
                 pagination['prev'] = pagination['page'] - 1
             if pagination['page'] < pagination['total']:
                 pagination['next'] = pagination['page'] + 1
-                
+
         # Set stop offset
         pagination['stop'] = pagination['start'] + self.pagination
         return pagination
-    
+
     def get_items(self):
         if self.request.session.get(self.get_token('filter')):
             self.is_filtering = True
             return self.set_filters(self.admin.model.objects, self.request.session.get(self.get_token('filter')))
         return self.admin.model.objects
-            
+
     def __call__(self, request, page=0):
         """
         Use widget as view
         """
         self.request = request
-        
+
         # Get basic list items
         items_total = self.get_items()
-            
+
         # Set extra filters?
         try:
             items_total = self.select_items(items_total).count()
         except AttributeError:
             items_total = items_total.count()
-            
+
         # Set sorting and paginating
         sorting_method = self.get_sorting()
         paginating_method = self.get_pagination(items_total, page)
-        
+
         # List items
         items = self.get_items()
         if not request.session.get(self.get_token('filter')):
             items = items.all()
-         
+
         # Set extra filters?
         try:
             items = self.select_items(items)
         except AttributeError:
             pass
-                  
+
         # Sort them
         items = self.sort_items(items, sorting_method);
-        
+
         # Set pagination
         if self.pagination:
             items = items[paginating_method['start']:paginating_method['stop']]
-        
+
         # Prefetch related?
         try:
             items = self.prefetch_related(items)
         except AttributeError:
             pass
-        
+
         # Default message
         message = None
-        
+
         # See if we should make and handle search form
         search_form = None
         SearchForm = self.get_search_form()
@@ -325,7 +325,7 @@ class ListWidget(BaseWidget):
                     message.type = 'error'
                 else:
                     search_form = SearchForm(request=request)
-                    
+
                 # Kill search
                 if request.POST.get('origin') == 'clear' and self.is_filtering and request.csrf.request_secure(request):
                     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')))
                 else:
                     search_form = SearchForm(request=request)
-        
+
         # See if we sould make and handle tab form
         table_form = None
         TableForm = self.get_table_form(items)
@@ -352,7 +352,7 @@ class ListWidget(BaseWidget):
                     message = Message(table_form.non_field_errors()[0], 'error')
             else:
                 table_form = TableForm(request=request)
-        
+
         # See if we should make and handle list form
         list_form = None
         ListForm = self.get_actions_form(items)
@@ -378,12 +378,12 @@ class ListWidget(BaseWidget):
                 message.type = 'error'
             else:
                 list_form = ListForm(request=request)
-        
+
         # Little hax to keep counters correct 
         items_shown = len(items)
         if items_total < items_shown:
             items_total = items_shown
-                
+
         # Render list
         return request.theme.render_to_response(self.get_template(),
                                                 self.add_template_variables({
@@ -405,7 +405,7 @@ class ListWidget(BaseWidget):
                                                 }),
                                                 context_instance=RequestContext(request));
 
-                                                
+
 class FormWidget(BaseWidget):
     """
     Form page widget
@@ -419,35 +419,35 @@ class FormWidget(BaseWidget):
     translate_target_name = False
     original_name = None
     submit_fallback = False
-    
+
     def get_url(self, model):
         return reverse(self.admin.get_action_attr(self.id, 'route'))
-    
+
     def get_form(self, target):
         return self.form
-    
+
     def get_form_instance(self, form, target, initial, post=False):
         if post:
             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))
-    
+
     def get_layout(self, form, model):
         if self.layout:
             return self.layout
         return form.layout
-    
+
     def get_initial_data(self, model):
         return {}
-    
+
     def submit_form(self, form, model):
         """
         Handle form submission, ALWAYS return tuple with model and message
         """
         pass
-    
+
     def __call__(self, request, target=None, slug=None):
         self.request = request
-        
+
         # Fetch target?
         model = None
         if target:
@@ -456,10 +456,10 @@ class FormWidget(BaseWidget):
             if not model:
                 return redirect(self.get_fallback_url())
         original_model = model
-        
+
         # Get form type to instantiate
         FormType = self.get_form(model)
-        
+
         #Submit form
         message = None
         if request.method == 'POST':
@@ -492,7 +492,7 @@ class FormWidget(BaseWidget):
                 message = Message(form.non_field_errors()[0], 'error')
         else:
             form = self.get_form_instance(FormType, model, self.get_initial_data(model))
-            
+
         # Render form
         return request.theme.render_to_response(self.get_template(),
                                                 self.add_template_variables({
@@ -510,7 +510,7 @@ class FormWidget(BaseWidget):
                                                 }),
                                                 context_instance=RequestContext(request));
 
-                                        
+
 class ButtonWidget(BaseWidget):
     """
     Button Action Widget
@@ -522,7 +522,7 @@ class ButtonWidget(BaseWidget):
     """
     def __call__(self, request, target=None, slug=None):
         self.request = request
-        
+
         # Fetch target?
         model = None
         if target:
@@ -530,23 +530,23 @@ class ButtonWidget(BaseWidget):
             if not model:
                 return redirect(self.get_fallback_url())
         original_model = model
-            
+
         # Crash if this is invalid request
         if not request.csrf.request_secure(request):
             request.messages.set_flash(Message(_("Action authorization is invalid.")), 'error', self.admin.id)
             return redirect(self.get_fallback_url())
-        
+
         # Do something
         message, url = self.action(model)
         request.messages.set_flash(message, message.type, self.admin.id)
         if url:
             return redirect(url)
         return redirect(self.get_fallback_url())
-        
+
     def action(self, target):
         """
         Action to be executed when button is pressed
         Define custom one in your Admin action.
         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'
     def handle(self, *args, **options):
         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')
     date = models.DateTimeField()
     message = models.TextField()
-    variables = models.TextField(null=True,blank=True)
-    
+    variables = models.TextField(null=True, blank=True)
+
     def vars(self):
         try:
             return pickle.loads(base64.decodestring(self.variables))
         except Exception:
             return {}
-    
+
     def text(self, var, value):
         value = cgi.escape(value, True)
         try:
@@ -25,7 +25,7 @@ class Alert(models.Model):
         except AttributeError:
             self.vars_raw = {var: value}
         return self
-    
+
     def url(self, var, value, href, attrs=None):
         url = '<a href="%s"' % cgi.escape(href, True)
         if attrs:
@@ -37,27 +37,27 @@ class Alert(models.Model):
         except AttributeError:
             self.vars_raw = {var: url}
         return self
-    
+
     def profile(self, var, user):
         from django.core.urlresolvers import reverse
         return self.url(var, user.username, reverse('user', kwargs={'user': user.pk, 'username': user.username_slug}))
-    
+
     def thread(self, var, thread):
         from django.core.urlresolvers import reverse
         return self.url(var, thread.name, reverse('thread', kwargs={'thread': thread.pk, 'slug': thread.slug}))
-    
+
     def post(self, var, thread, post):
         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}))
-    
+
     def save_all(self, *args, **kwargs):
         self.save(force_insert=True)
         self.user.save(force_update=True)
-        
+
     def save(self, *args, **kwargs):
         try:
             self.variables = base64.encodestring(pickle.dumps(self.vars_raw, pickle.HIGHEST_PROTOCOL))
         except AttributeError:
             self.variables = base64.encodestring(pickle.dumps({}, pickle.HIGHEST_PROTOCOL))
         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)
             except KeyError:
                 alerts['older'] = [alert]
-    
+
     new_alerts = request.user.alerts
     request.user.alerts = 0
     request.user.alerts_date = now
@@ -48,4 +48,4 @@ def show_alerts(request):
                                              'new_alerts': new_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
             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 decorator
+    return decorator

+ 3 - 3
misago/authn/fixtures.py

@@ -45,7 +45,7 @@ settings_fixtures = (
 
 def load_fixtures():
     load_settings_fixture(settings_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_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)
-    
+
     layout = [
               (
                None,
@@ -20,11 +20,11 @@ class SignInForm(Form):
                ['user_remember_me'],
                ),
               ]
-    
+
     def __init__(self, *args, **kwargs):
         show_remember_me = kwargs['show_remember_me']
         del kwargs['show_remember_me']
-        
+
         super(SignInForm, self).__init__(*args, **kwargs)
         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.sessions.models import Token
 from misago.users.models import User
-    
+
 """
 Exception constants
 """
@@ -27,11 +27,11 @@ class AuthException(Exception):
         self.password = password
         self.activation = activation
         self.ban = ban
-        
+
     def __str__(self):
         return self.error
-      
-    
+
+
 def get_user(email, password, admin=False):
     """
     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:
                 # 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)
-    
+
     except User.DoesNotExist:
         raise AuthException(CREDENTIALS, _("Your e-mail address or password is incorrect. Please try again."), password=True)
     return user;
@@ -85,17 +85,17 @@ def auth_remember(request, ip):
         except Token.DoesNotExist:
             request.cookie_jar.delete('TOKEN')
             raise AuthException()
-        
+
         # See if token is not expired
         token_expires = timezone.now() - timedelta(days=request.settings['remember_me_lifetime'])
         if request.settings['remember_me_extensible'] and token_rk.accessed < token_expires:
             # Token expired because it's last use is smaller than expiration date
             raise AuthException()
-        
+
         if not request.settings['remember_me_extensible'] and token_rk.created < token_expires:
             # Token expired because it was created before expiration date
             raise AuthException()
-        
+
         # Update token date
         token_rk.accessed = timezone.now()
         token_rk.save(force_update=True)
@@ -122,4 +122,4 @@ def sign_user_in(request, user):
                         )
     user.save(force_update=True)
     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:
     urlpatterns += patterns('misago.authn.views',
         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')
     bad_password = False
     not_active = False
-    banned_account = False   
-    
+    banned_account = False
+
     if request.method == 'POST':
         form = SignInForm(
                           request.POST,
                           show_remember_me=not request.firewall.admin and request.settings['remember_me_allow'],
                           request=request
                           )
-        
+
         if form.is_valid():
             try:
                 # Configure correct auth and redirect links
@@ -42,17 +42,17 @@ def signin(request):
                 else:
                     auth_method = auth_forum
                     success_redirect = reverse('index')
-                
+
                 # Authenticate user
                 user = auth_method(
                                   request,
                                   form.cleaned_data['user_email'],
                                   form.cleaned_data['user_password'],
                                   )
-                
-                sign_user_in(request, user)     
+
+                sign_user_in(request, user)
                 remember_me_token = False
-                
+
                 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(
@@ -71,11 +71,11 @@ def signin(request):
                 bad_password = e.password
                 banned_account = e.ban
                 not_active = e.activation
-                
+
                 # If not in Admin, register failed attempt
                 if not request.firewall.admin and e.type == auth.CREDENTIALS:
                     SignInAttempt.objects.register_attempt(request.session.get_ip(request))
-                    
+
                     # Have we jammed our account?
                     if SignInAttempt.objects.is_jammed(request.settings, request.session.get_ip(request)):
                         request.jam.expires = timezone.now()
@@ -94,7 +94,7 @@ def signin(request):
                                              'banned_account': banned_account,
                                              'not_active': not_active,
                                              'form': FormLayout(form),
-                                             'hide_signin': True, 
+                                             'hide_signin': True,
                                              },
                                             context_instance=RequestContext(request));
 
@@ -107,4 +107,4 @@ def signout(request):
     request.messages.set_flash(Message(_("You have been signed out.")), 'info', 'security')
     if request.firewall.admin:
         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 {
         'is_banned': request.ban.is_banned(),
-    }
+    }

+ 1 - 1
misago/banning/decorators.py

@@ -9,4 +9,4 @@ def block_banned(f):
         except AttributeError:
             pass
         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
 
 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')),
                                       (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)
     expires = forms.DateField(required=False)
     layout = (
@@ -53,4 +53,4 @@ class SearchBansForm(Form):
                 ('type', {'label': _("Type")}),
                ),
               ),
-             )
+             )

+ 1 - 1
misago/banning/middleware.py

@@ -14,4 +14,4 @@ class BanningMiddleware(object):
             request.ban.check_for_updates(request)
             # Make sure banned session is downgraded to guest level
             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):
     type = models.PositiveIntegerField(default=BAN_NAME_EMAIL)
     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):
     bans_model = Ban.objects.filter(Q(expires=None) | Q(expires__gt=timezone.now()))
     if not (ip and username and email):
@@ -32,13 +32,13 @@ def check_ban(ip=False, username=False, email=False):
         if (
             # Check user 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
             ((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
             (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 False
 
@@ -50,12 +50,12 @@ class BanCache(object):
         self.expires = None
         self.reason_user = None
         self.version = 0
-        
+
     def check_for_updates(self, request):
         if (self.version < request.monitor['bans_version']
             or (self.expires != None and self.expires < timezone.now())):
             self.version = request.monitor['bans_version']
-            
+
             # Check Ban
             if request.user.is_authenticated():
                 ban = check_ban(
@@ -65,7 +65,7 @@ class BanCache(object):
                                 )
             else:
                 ban = check_ban(ip=request.session.get_ip(request))
-                
+
             # Update ban cache
             if ban:
                 self.banned = True
@@ -78,7 +78,7 @@ class BanCache(object):
                 self.expires = None
                 self.type = None
             return True
-        return False    
-    
+        return False
+
     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')
     id = 'list'
-    columns=(
+    columns = (
              ('ban', _("Ban"), 50),
              ('expires', _("Expires")),
              )
     default_sorting = 'expires'
-    sortables={
+    sortables = {
                'ban': 1,
                'expires': 0,
               }
@@ -54,10 +54,10 @@ class List(ListWidget):
     empty_message = _('No bans are currently set.')
     empty_search_message = _('No bans have been found.')
     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?")),
              )
-    
+
     def set_filters(self, model, filters):
         if 'ban' in filters:
             model = model.filter(ban__contains=filters['ban'])
@@ -66,7 +66,7 @@ class List(ListWidget):
         if 'type' in filters:
             model = model.filter(type__in=filters['type'])
         return model
-    
+
     def get_item_actions(self, item):
         return (
                 self.action('pencil', _("Edit Ban"), reverse('admin_bans_edit', item)),
@@ -77,7 +77,7 @@ class List(ListWidget):
         Ban.objects.filter(id__in=checked).delete()
         self.request.monitor['bans_version'] = int(self.request.monitor['bans_version']) + 1
         return Message(_('Selected bans have been lifted successfully.'), 'success'), reverse('admin_bans')
-    
+
 
 class New(FormWidget):
     """
@@ -85,29 +85,29 @@ class New(FormWidget):
     """
     admin = site.get_action('bans')
     id = 'new'
-    fallback = 'admin_bans' 
+    fallback = 'admin_bans'
     form = BanForm
     submit_button = _("Set Ban")
-        
+
     def get_new_url(self, model):
         return reverse('admin_bans_new')
-    
+
     def get_edit_url(self, model):
         return reverse('admin_bans_edit', model)
-    
+
     def submit_form(self, form, target):
         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)
         self.request.monitor['bans_version'] = int(self.request.monitor['bans_version']) + 1
         return new_ban, Message(_('New Ban has been set.'), 'success')
-    
-   
+
+
 class Edit(FormWidget):
     """
     Edit Ban
@@ -120,13 +120,13 @@ class Edit(FormWidget):
     target_name = 'ban'
     notfound_message = _('Requested Ban could not be found.')
     submit_fallback = True
-    
+
     def get_url(self, model):
         return reverse('admin_bans_edit', model)
-    
+
     def get_edit_url(self, model):
         return self.get_url(model)
-    
+
     def get_initial_data(self, model):
         return {
                 'type': model.type,
@@ -135,7 +135,7 @@ class Edit(FormWidget):
                 'reason_admin': model.reason_admin,
                 'expires': model.expires,
                 }
-    
+
     def submit_form(self, form, target):
         target.type = form.cleaned_data['type']
         target.ban = form.cleaned_data['ban']
@@ -155,7 +155,7 @@ class Delete(ButtonWidget):
     id = 'delete'
     fallback = 'admin_bans'
     notfound_message = _('Requested Ban could not be found.')
-    
+
     def action(self, target):
         target.delete()
         self.request.monitor['bans_version'] = int(self.request.monitor['bans_version']) + 1
@@ -166,4 +166,4 @@ class Delete(ButtonWidget):
         if target.type == 2:
             return Message(_('E-mail Ban "%(ban)s" has been lifted.') % {'ban': target.ban}, 'success'), False
         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 {
         '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():
             return error403(request, _("You have used up allowed attempts quota and we temporarily banned you from accessing this page."))
         return f(*args, **kwargs)
-    return decorator
+    return decorator

+ 3 - 3
misago/bruteforce/fixtures.py

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

+ 1 - 1
misago/context_processors.py

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

+ 6 - 6
misago/cookie_jar/cookie_jar.py

@@ -1,11 +1,11 @@
 from datetime import datetime, timedelta
 from django.conf import settings
 
-class CookieJar(object):    
+class CookieJar(object):
     def __init__(self):
         self._set_cookies = []
         self._delete_cookies = []
-    
+
     def set(self, cookie, value, permanent=False):
         if permanent:
             # 360 days
@@ -18,10 +18,10 @@ class CookieJar(object):
                                   'value': value,
                                   'max_age': max_age,
                                   })
-        
+
     def delete(self, cookie):
         self._delete_cookies.append(cookie)
-        
+
     def flush(self, response):
         for cookie in self._set_cookies:
             response.set_cookie(
@@ -32,10 +32,10 @@ class CookieJar(object):
                                 domain=settings.COOKIES_DOMAIN,
                                 secure=settings.COOKIES_SECURE
                                 )
-        
+
         for cookie in self._delete_cookies:
             response.delete_cookie(
                                    settings.COOKIES_PREFIX + cookie,
                                    path=settings.COOKIES_PATH,
                                    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):
     def process_request(self, request):
         request.cookie_jar = CookieJar()
-                    
+
     def process_response(self, request, response):
         try:
             request.cookie_jar.flush(response)
         except AttributeError:
             pass
-        return response
+        return response

+ 1 - 1
misago/csrf/context_processors.py

@@ -4,4 +4,4 @@ def csrf(request):
     return {
         'csrf_id': request.csrf.csrf_id,
         '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
             return error403(request, _("Request authorization is invalid. Please try again."))
         return f(*args, **kwargs)
-    return decorator
+    return decorator

+ 1 - 1
misago/csrf/middleware.py

@@ -10,4 +10,4 @@ class CSRFMiddleware(object):
         else:
             csrf_token = get_random_string(16);
             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
         """
         return path[:len(self.prefix)] == self.prefix
-    
+
     def process_view(self, request, callback, callback_args, callback_kwargs):
         return None
-    
-    
+
+
 class FirewallAdmin(FirewallForum):
     admin = True
-    prefix = '/' + ADMIN_PATH    
+    prefix = '/' + ADMIN_PATH
     def process_view(self, request, callback, callback_args, callback_kwargs):
         # Block all crawlers with 403
         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():
                 request.messages.set_message(Message(_("Your account does not have admin privileges")), 'error', 'security')
                 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):
     firewall_admin = FirewallAdmin()
     firewall_forum = FirewallForum()
-    
+
     def process_request(self, request):
         if settings.ADMIN_PATH and self.firewall_admin.behind_firewall(request.path_info):
             request.firewall = self.firewall_admin
@@ -14,4 +14,4 @@ class FirewallMiddleware(object):
             request.firewall = self.firewall_forum
 
     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
     def __init__(self, data=None, file=None, request=None, *args, **kwargs):
         self.request = request
-                
+
         # Extract request from first argument
         if data != None:
             super(Form, self).__init__(data, file, *args, **kwargs)
         else:
             super(Form, self).__init__(*args, **kwargs)
-            
+
         # Kill captcha fields
         try:
             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']
         except KeyError:
             pass
-        
+
         # Let forms do mumbo-jumbo with fields removing
         self.finalize_form()
-     
+
     def finalize_form(self):
         pass
-        
+
     def full_clean(self):
         """
         Trim inputs and strip newlines
         """
-        self.data = self.data.copy() 
+        self.data = self.data.copy()
         for key, field in self.fields.iteritems():
             try:
                 if field.__class__.__name__ in ['ModelChoiceField', 'TreeForeignKey'] and self.data[key]:
@@ -68,7 +68,7 @@ class Form(forms.Form):
             except (KeyError, AttributeError):
                 pass
         super(Form, self).full_clean()
-     
+
     def clean(self):
         """
         Clean data, do magic checks and stuff
@@ -76,7 +76,7 @@ class Form(forms.Form):
         cleaned_data = super(Form, self).clean()
         self._check_all()
         return cleaned_data
-         
+
     def clean_recaptcha(self):
         """
         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."))
         self.request.session['captcha_passed'] = True
         return ''
-    
+
     def clean_captcha_qa(self):
         """
         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()):
             raise forms.ValidationError(_("The answer you entered is incorrect."))
         self.request.session['captcha_passed'] = True
         return self.cleaned_data['captcha_qa']
-    
+
     def _check_all(self):
         # Check repeated fields
         self._check_repeats()
         # Check CSRF, we dont allow un-csrf'd forms in Misago
         self._check_csrf()
         # 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):
         for index, repeat in enumerate(self.validate_repeats):
             # Check empty fields
@@ -118,15 +118,15 @@ class Form(forms.Form):
                     try:
                         if len(repeat) == 2:
                             self.errors['_'.join(repeat)] = [self.repeats_errors[index]['fill_both']]
-                        else: 
+                        else:
                             self.errors['_'.join(repeat)] = [self.repeats_errors[index]['fill_all']]
                     except (IndexError, KeyError):
                         if len(repeat) == 2:
                             self.errors['_'.join(repeat)] = [_("You have to fill in both fields.")]
-                        else: 
+                        else:
                             self.errors['_'.join(repeat)] = [_("You have to fill in all fields.")]
                     break
-                    
+
             else:
                 # Check different fields
                 past_field = self.data[repeat[0]]
@@ -138,22 +138,22 @@ class Form(forms.Form):
                             self.errors['_'.join(repeat)] = [_("Entered values differ from each other.")]
                         break
                     past_field = self.data[field]
-            
-        
+
+
     def _check_csrf(self):
         if not self.request.csrf.request_secure(self.request):
             raise forms.ValidationError(_("Request authorization is invalid. Please resubmit your form."))
-        
+
     def _check_fields_errors(self):
         if 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], []
                 raise forms.ValidationError(field_error)
             raise forms.ValidationError(_("Form contains errors."))
-        
-        
+
+
 class YesNoSwitch(forms.CheckboxInput):
     """
     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):
         scaffold_fields = FormFields(form)
         scaffold_fieldsets = FormFieldsets(form, scaffold_fields.fields, fieldsets)
-        
+
         self.multipart_form = scaffold_fields.multipart_form
         self.fieldsets = scaffold_fieldsets.fieldsets
         self.fields = scaffold_fields.fields
         self.hidden = scaffold_fields.hidden
-    
+
 class FormFields(object):
     """
     Hydrator that builds fields list from form and blueprint
@@ -19,14 +19,14 @@ class FormFields(object):
         self.multipart_form = False
         self.fields = {}
         self.hidden = []
-        
+
         # Extract widgets from meta
         self.meta_widgets = {}
         try:
             self.meta_widgets = form.Meta.widgets
         except AttributeError:
             pass
-                
+
         # Find out field input types
         for field in form.fields.keys():
             widget = self._get_widget(field, form.fields[field])
@@ -56,11 +56,11 @@ class FormFields(object):
                          'widget': '',
                          'choices': [],
                         }
-            
+
             # Set multipart form
             if widget.needs_multipart_form:
                 self.multipart_form = True
-            
+
             # Get errors?
             if form.is_bound:
                 for error in bound_field._errors():
@@ -71,14 +71,14 @@ class FormFields(object):
                             blueprint['errors'].append(error)
                 except KeyError:
                     pass
-            
+
             # Use clean value instead?
             try:
                 if field in form.cleaned_data:
                     blueprint['value'] = form.cleaned_data[field]
             except AttributeError:
                 pass
-            
+
             # TextInput
             if widget_name in ['TextInput', 'PasswordInput', 'Textarea']:
                 blueprint['widget'] = 'text'
@@ -87,15 +87,15 @@ class FormFields(object):
                     blueprint['attrs']['maxlength'] = bound_field.field.max_length
                 except AttributeError:
                     pass
-            
+
             # PasswordInput
             if widget_name == 'PasswordInput':
                 blueprint['attrs']['type'] = 'password'
-              
+
             # Textarea      
             if widget_name == 'Textarea':
                 blueprint['widget'] = 'textarea'
-                
+
             # ReCaptcha      
             if widget_name == 'ReCaptchaWidget':
                 from recaptcha.client.captcha import displayhtml
@@ -105,26 +105,26 @@ class FormFields(object):
                                                           form.request.settings['recaptcha_ssl'],
                                                           bound_field.field.api_error,
                                                           )}
-                
+
             # HiddenInput
             if widget_name == 'HiddenInput':
                 blueprint['widget'] = 'hidden'
-                
+
             # MultipleHiddenInput
             if widget_name == 'MultipleHiddenInput':
                 blueprint['widget'] = 'multiple_hidden'
                 blueprint['attrs'] = {
                                       'choices': widget.choices
                                      }
-            
+
             # FileInput
             if widget_name == 'FileInput':
                 blueprint['widget'] = 'file'
-            
+
             # ClearableFileInput
             if widget_name == 'ClearableFileInput':
                 blueprint['widget'] = 'file_clearable'
-                
+
             # DateInput
             if widget_name == 'DateInput':
                 blueprint['widget'] = 'date'
@@ -132,7 +132,7 @@ class FormFields(object):
                     blueprint['value'] = blueprint['value'].strftime('%Y-%m-%d')
                 except AttributeError as e:
                     pass
-            
+
             # DateTimeInput
             if widget_name == 'DateTimeInput':
                 blueprint['widget'] = 'datetime'
@@ -140,7 +140,7 @@ class FormFields(object):
                     blueprint['value'] = blueprint['value'].strftime('%Y-%m-%d %H:%M')
                 except AttributeError as e:
                     pass
-            
+
             # TimeInput
             if widget_name == 'TimeInput':
                 blueprint['widget'] = 'time'
@@ -148,87 +148,87 @@ class FormFields(object):
                     blueprint['value'] = blueprint['value'].strftime('%H:%M')
                 except AttributeError as e:
                     pass
-                
+
             # CheckboxInput
             if widget_name == 'CheckboxInput':
                 blueprint['widget'] = 'checkbox'
-                
+
             # Select, NullBooleanSelect, SelectMultiple, RadioSelect, CheckboxSelectMultiple
             if widget_name in ['Select', 'NullBooleanSelect', 'SelectMultiple', 'RadioSelect', 'CheckboxSelectMultiple']:
                 blueprint['choices'] = widget.choices
-                
+
             # Yes-no radio select
             if widget_name == 'YesNoSwitch':
                 blueprint['widget'] = 'yes_no_switch'
-            
+
             # Select
             if widget_name == 'Select':
                 blueprint['widget'] = 'select'
                 if not blueprint['value']:
                     blueprint['value'] = u''
-                
+
             # NullBooleanSelect
             if widget_name == 'NullBooleanSelect':
                 blueprint['widget'] = 'null_boolean_select'
-                
+
             # SelectMultiple
             if widget_name == 'SelectMultiple':
                 blueprint['widget'] = 'select_multiple'
-                
+
             # RadioSelect
             if widget_name == 'RadioSelect':
                 blueprint['widget'] = 'radio_select'
                 if not blueprint['value']:
                     blueprint['value'] = u''
-                
+
             # CheckboxSelectMultiple
             if widget_name == 'CheckboxSelectMultiple':
                 blueprint['widget'] = 'checkbox_select_multiple'
-            
+
             # MultiWidget
             if widget_name == 'MultiWidget':
                 blueprint['widget'] = 'multi'
-            
+
             # SplitDateTimeWidget
             if widget_name == 'SplitDateTimeWidget':
                 blueprint['widget'] = 'split_datetime'
-            
+
             # SplitHiddenDateTimeWidget
             if widget_name == 'SplitHiddenDateTimeWidget':
                 blueprint['widget'] = 'split_hidden_datetime'
-            
+
             # SelectDateWidget
             if widget_name == 'SelectDateWidget':
                 blueprint['widget'] = 'select_date'
                 blueprint['years'] = widget.years
-                
+
             # Store field in either of collections
             if blueprint['hidden']:
                 blueprint['attrs']['type'] = 'hidden'
                 self.hidden.append(blueprint)
             else:
                 self.fields[field] = blueprint
-                                
+
     def _get_widget(self, name, field):
         if name in self.meta_widgets:
             return self.meta_widgets[name]
         return field.widget
-    
-    
+
+
 class FormFieldsets(object):
     """
     Hydrator that builds fieldset from form and blueprint
     """
     def __init__(self, form, fields, fieldsets=None):
         self.fieldsets = []
-        
+
         # Use form layout
         if not fieldsets:
             try:
                 fieldsets = form.layout
             except AttributeError:
                 pass
-        
+
         # Build fieldsets data
         if fieldsets:
             for blueprint in fieldsets:
@@ -268,7 +268,7 @@ class FormFieldsets(object):
                             if not subfields['help_text']:
                                 subfields['help_text'] = subfields['nested'][0]['help_text']
                             try:
-                                subfields['errors'] = form.errors["_".join(subfiels_ids)] 
+                                subfields['errors'] = form.errors["_".join(subfiels_ids)]
                             except KeyError:
                                 pass
                             fieldset['fields'].append(subfields)
@@ -291,10 +291,9 @@ class FormFieldsets(object):
                     fieldset['help'] = blueprint[2]
                 except IndexError:
                     pass
-                
+
                 # Append complete fieldset
                 if fieldset['fields']:
                     self.fieldsets.append(fieldset)
             self.fieldsets[-1]['last'] = True
-        
-        
+

+ 6 - 6
misago/forumroles/fixtures.py

@@ -41,7 +41,7 @@ def load_fixtures():
                           'can_delete_attachments': True,
                           })
     role.save(force_insert=True)
-    
+
     role = ForumRole()
     role.name = _('Standard Access and Upload').message
     role.set_permissions({
@@ -63,7 +63,7 @@ def load_fixtures():
                           'attachment_limit': 3,
                           })
     role.save(force_insert=True)
-    
+
     role = ForumRole()
     role.name = _('Standard Access').message
     role.set_permissions({
@@ -82,7 +82,7 @@ def load_fixtures():
                           'can_download_attachments': True,
                           })
     role.save(force_insert=True)
-    
+
     role = ForumRole()
     role.name = _('Read and Download').message
     role.set_permissions({
@@ -92,7 +92,7 @@ def load_fixtures():
                           'can_download_attachments': True,
                           })
     role.save(force_insert=True)
-    
+
     role = ForumRole()
     role.name = _('Threads list only').message
     role.set_permissions({
@@ -100,7 +100,7 @@ def load_fixtures():
                           'can_see_forum_contents': True,
                           })
     role.save(force_insert=True)
-    
+
     role = ForumRole()
     role.name = _('Read only').message
     role.set_permissions({
@@ -108,4 +108,4 @@ def load_fixtures():
                           'can_see_forum_contents': True,
                           '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
 
 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 is too long.")
                                                                          )])
-    
+
     def finalize_form(self):
         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.")}),
                          ),
                         ),
-                       )
+                       )

+ 7 - 7
misago/forumroles/models.py

@@ -12,25 +12,25 @@ class ForumRole(models.Model):
     Misago User Role model
     """
     name = models.CharField(max_length=255)
-    permissions = models.TextField(null=True,blank=True)
+    permissions = models.TextField(null=True, blank=True)
     permissions_cache = {}
-    
+
     def __unicode__(self):
         return unicode(_(self.name))
-    
+
     def get_permissions(self):
         if self.permissions_cache:
             return self.permissions_cache
-        
+
         try:
             self.permissions_cache = pickle.loads(base64.decodestring(self.permissions))
         except Exception:
             # ValueError, SuspiciousOperation, unpickling exceptions. If any of
             # these happen, just return an empty dictionary (an empty permissions list).
             self.permissions_cache = {}
-            
+
         return self.permissions_cache
-    
+
     def set_permissions(self, 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
 from django.core.urlresolvers import reverse as django_reverse
 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.widgets import *
 from misago.utils import slugify
@@ -20,17 +20,17 @@ Views
 class List(ListWidget):
     admin = site.get_action('roles_forums')
     id = 'list'
-    columns=(
-             ('role', _("Role")),
-             )
+    columns = (
+               ('role', _("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):
         return page_items.order_by('name')
-    
+
     def get_item_actions(self, item):
         return (
                 self.action('adjust', _("Role Permissions"), reverse('admin_roles_forums_acl', item)),
@@ -47,24 +47,24 @@ class List(ListWidget):
 class New(FormWidget):
     admin = site.get_action('roles_forums')
     id = 'new'
-    fallback = 'admin_roles_forums' 
+    fallback = 'admin_roles_forums'
     form = ForumRoleForm
     submit_button = _("Save Role")
-        
+
     def get_new_url(self, model):
         return reverse('admin_roles_forums_new')
-    
+
     def get_edit_url(self, model):
         return reverse('admin_roles_forums_edit', model)
-    
+
     def submit_form(self, form, target):
         new_role = ForumRole(
-                      name = form.cleaned_data['name'],
+                      name=form.cleaned_data['name'],
                      )
         new_role.save(force_insert=True)
         return new_role, Message(_('New Forum Role has been created.'), 'success')
-    
-   
+
+
 class Edit(FormWidget):
     admin = site.get_action('roles_forums')
     id = 'edit'
@@ -74,18 +74,18 @@ class Edit(FormWidget):
     target_name = 'name'
     notfound_message = _('Requested Forum Role could not be found.')
     submit_fallback = True
-    
+
     def get_url(self, model):
         return reverse('admin_roles_forums_edit', model)
-    
+
     def get_edit_url(self, model):
         return self.get_url(model)
-    
+
     def get_initial_data(self, model):
         return {
                 'name': model.name,
                 }
-    
+
     def submit_form(self, form, target):
         target.name = form.cleaned_data['name']
         target.save(force_update=True)
@@ -101,17 +101,17 @@ class ACL(FormWidget):
     notfound_message = _('Requested Forum Role could not be found.')
     submit_fallback = True
     template = 'acl_form'
-    
+
     def get_form(self, target):
         self.form = build_forum_form(self.request, target)
         return self.form
-    
+
     def get_url(self, model):
         return reverse('admin_roles_forums_acl', model)
-    
+
     def get_edit_url(self, model):
         return self.get_url(model)
-    
+
     def get_initial_data(self, model):
         raw_acl = model.get_permissions()
         initial = {}
@@ -119,7 +119,7 @@ class ACL(FormWidget):
             if field in raw_acl:
                 initial[field] = raw_acl[field]
         return initial
-    
+
     def submit_form(self, form, target):
         raw_acl = target.get_permissions()
         for perm in form.cleaned_data:
@@ -127,7 +127,7 @@ class ACL(FormWidget):
         target.set_permissions(raw_acl)
         target.save(force_update=True)
         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')
 
 
@@ -136,8 +136,8 @@ class Delete(ButtonWidget):
     id = 'delete'
     fallback = 'admin_roles_forums'
     notfound_message = _('Requested Forum Role could not be found.')
-    
+
     def action(self, target):
         target.delete()
         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
 
 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((
                         _("Forums Permissions"),
                         (
                          ('can_see_forum', {'label': _("Can see forum")}),
                          ('can_see_forum_contents', {'label': _("Can see forum contents")}),
-                        ),
-                       ))
-    
+                         ),
+                        ))
+
 
 class ForumsACL(BaseACL):
     def known_forums(self):
         return self.acl['can_see']
-    
+
     def can_see(self, forum):
         try:
             return forum.pk in self.acl['can_see']
         except AttributeError:
             return long(forum) in self.acl['can_see']
-        
+
     def can_browse(self, forum):
         if self.can_see(forum):
             try:
@@ -33,7 +33,7 @@ class ForumsACL(BaseACL):
             except AttributeError:
                 return long(forum) in self.acl['can_browse']
         return False
-    
+
     def allow_forum_view(self, forum):
         if not self.can_see(forum):
             raise ACLError404()
@@ -45,7 +45,7 @@ def build_forums(acl, perms, forums, forum_roles):
     acl.forums = ForumsACL()
     acl.forums.acl['can_see'] = []
     acl.forums.acl['can_browse'] = []
-    
+
     for forum in forums:
         for perm in perms:
             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']:
             # 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)]
-            
+
         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']:
                 # Second burp: we cant see or read parent forum
@@ -74,4 +74,4 @@ def cleanup(acl, perms, forums):
                 try:
                     del acl.forums.acl['can_browse'][acl.forums.acl['can_browse'].index(forum.pk)]
                 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
 
 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.insert_at(None,save=True)
+    root.insert_at(None, save=True)
     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.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)
-    
+
     now = timezone.now()
     thread = Thread.objects.create(
                                    forum=forum,
@@ -50,9 +50,9 @@ def load_fixtures():
     forum.last_poster = thread.last_poster
     forum.last_poster_name = thread.last_poster_name
     forum.last_poster_slug = thread.last_poster_slug
-    forum.save(force_update=True)    
-    
+    forum.save(force_update=True)
+
     load_monitor_fixture({
                           'threads': 1,
                           'posts': 1,
-                          })
+                          })

+ 51 - 51
misago/forums/forms.py

@@ -8,20 +8,20 @@ from misago.utils.validators import validate_sluggable
 class CategoryForm(Form):
     parent = 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=(
                                           ('row', _('One forum per row')),
                                           ('half', _('Two 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 = (
               (
                _("Basic Options"),
@@ -42,31 +42,31 @@ class CategoryForm(Form):
                 ),
               ),
              )
-    
+
     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):
     parent = 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=(
                                           ('row', _('One forum per row')),
                                           ('half', _('Two 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 = (
               (
                _("Basic Options"),
@@ -77,14 +77,14 @@ class ForumForm(Form):
                 ('description', {'label': _("Forum Description")}),
                 ('closed', {'label': _("Closed 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_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"),
                (
@@ -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.")}),
                 ('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):
-        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):
     parent = 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)
-    style = forms.CharField(max_length=255,required=False)
-    
+    style = forms.CharField(max_length=255, required=False)
+
     layout = (
               (
                _("Basic Options"),
@@ -121,31 +121,31 @@ class RedirectForm(Form):
                 ('redirect', {'label': _("Redirect URL")}),
                 ('description', {'label': _("Redirect Description")}),
                 ),
-              ),
+               ),
               (
                _("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.')}),
                 ),
-              ),
-             )
-    
+               ),
+              )
+
     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):
     parent = False
-   
+
     layout = (
               (
                _("Delete Options"),
                (
                 ('parent', {'label': _("Move deleted Forum contents to")}),
                 ),
-              ),
-             )
-        
+               ),
+              )
+
     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'
     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.db import models
 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
 
 class ForumManager(models.Manager):
     forums_tree = None
-    
+
     def token_to_pk(self, token):
         self.populate_tree()
         try:
             return self.forums_tree[token].pk
         except KeyError:
             return 0
-    
+
     def populate_tree(self, force=False):
         if not self.forums_tree:
             self.forums_tree = cache.get('forums_tree')
@@ -25,7 +25,7 @@ class ForumManager(models.Manager):
                 if forum.token:
                     self.forums_tree[forum.token] = forum
             cache.set('forums_tree', self.forums_tree)
-    
+
     def forum_parents(self, forum, include_self=False):
         self.populate_tree()
         parents = []
@@ -36,7 +36,7 @@ class ForumManager(models.Manager):
             parent = self.forums_tree[parent.parent_id]
             parents.append(parent)
         return reversed(parents)
-        
+
     def parents_aware_forum(self, forum):
         self.populate_tree()
         proxy = Forum()
@@ -52,17 +52,17 @@ class ForumManager(models.Manager):
                 proxy.closed = True
                 return proxy
         return proxy
-        
+
     def treelist(self, acl, parent=None, tracker=None):
         complete_list = []
         forums_list = []
         parents = {}
-        
+
         if parent:
             queryset = Forum.objects.filter(pk__in=acl.known_forums).filter(lft__gt=parent.lft).filter(rght__lt=parent.rght).order_by('lft')
         else:
             queryset = Forum.objects.filter(pk__in=acl.known_forums).order_by('lft')
-            
+
         for forum in queryset:
             forum.subforums = []
             forum.is_read = False
@@ -74,7 +74,7 @@ class ForumManager(models.Manager):
                 parents[forum.parent_id].subforums.append(forum)
             else:
                 forums_list.append(forum)
-        
+
         # Second iteration - sum up forum counters
         for forum in reversed(complete_list):
             if forum.parent_id in parents and parents[forum.parent_id].type != 'redirect':
@@ -100,49 +100,49 @@ class ForumManager(models.Manager):
 
 
 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)
-    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)
     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_delta = models.PositiveIntegerField(default=0)
     posts = models.PositiveIntegerField(default=0)
     posts_delta = models.IntegerField(default=0)
     redirects = models.PositiveIntegerField(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_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)
-    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)
-    
-    objects = ForumManager()   
-    
+
+    objects = ForumManager()
+
     def __unicode__(self):
         if self.token == 'root':
-           return unicode(_('Root Category')) 
+           return unicode(_('Root Category'))
         return unicode(self.name)
-        
+
     def set_description(self, description):
         self.description = description.strip()
         self.description_preparsed = ''
         if self.description:
             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):
         if target.pk != self.pk:
             for role in Role.objects.all():
@@ -153,10 +153,10 @@ class Forum(MPTTModel):
                     role.save(force_update=True)
                 except KeyError:
                     pass
-        
+
     def move_content(self, target):
         pass
-    
+
     def sync(self):
         self.threads = self.thread_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
         except (IndexError, AttributeError):
             pass
-    
+
     def prune(self):
-        pass
+        pass

+ 83 - 83
misago/forums/views.py

@@ -20,22 +20,22 @@ Views
 class List(ListWidget):
     admin = site.get_action('forums')
     id = 'list'
-    columns=(
-             ('forum', _("Forum")),
-             )
+    columns = (
+               ('forum', _("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.')
-    
+
     def get_items(self):
         return self.admin.model.objects.get(token='root').get_descendants()
-    
+
     def sort_items(self, page_items, sorting_method):
         return page_items.order_by('lft')
-    
+
     def get_item_actions(self, item):
         if item.type == 'category':
             return (
@@ -44,7 +44,7 @@ class List(ListWidget):
                     self.action('pencil', _("Edit Category"), reverse('admin_forums_edit', item)),
                     self.action('remove', _("Delete Category"), reverse('admin_forums_delete', item)),
                     )
-            
+
         if item.type == 'forum':
             return (
                     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('remove', _("Delete Forum"), reverse('admin_forums_delete', item)),
                     )
-            
+
         return (
                 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),
@@ -70,70 +70,70 @@ class List(ListWidget):
 class NewCategory(FormWidget):
     admin = site.get_action('forums')
     id = 'new_category'
-    fallback = 'admin_forums' 
+    fallback = 'admin_forums'
     form = CategoryForm
     submit_button = _("Save Category")
-        
+
     def get_new_url(self, model):
         return reverse('admin_forums_new_category')
-    
+
     def get_edit_url(self, model):
         return reverse('admin_forums_edit', model)
-    
+
     def submit_form(self, form, target):
         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.insert_at(form.cleaned_data['parent'], position='last-child', save=True)
         Forum.objects.populate_tree(True)
-        
+
         if form.cleaned_data['perms']:
             new_forum.copy_permissions(form.cleaned_data['perms'])
             self.request.monitor['acl_version'] = int(self.request.monitor['acl_version']) + 1
-            
+
         return new_forum, Message(_('New Category has been created.'), 'success')
 
 
 class NewForum(FormWidget):
     admin = site.get_action('forums')
     id = 'new_forum'
-    fallback = 'admin_forums' 
+    fallback = 'admin_forums'
     form = ForumForm
     submit_button = _("Save Forum")
-        
+
     def get_new_url(self, model):
         return reverse('admin_forums_new_forum')
-    
+
     def get_edit_url(self, model):
         return reverse('admin_forums_edit', model)
-    
+
     def submit_form(self, form, target):
         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.insert_at(form.cleaned_data['parent'], position='last-child', save=True)
         Forum.objects.populate_tree(True)
-        
+
         if form.cleaned_data['perms']:
             new_forum.copy_permissions(form.cleaned_data['perms'])
             self.request.monitor['acl_version'] = int(self.request.monitor['acl_version']) + 1
-            
+
         return new_forum, Message(_('New Forum has been created.'), 'success')
 
     def __call__(self, request):
@@ -146,34 +146,34 @@ class NewForum(FormWidget):
 class NewRedirect(FormWidget):
     admin = site.get_action('forums')
     id = 'new_redirect'
-    fallback = 'admin_forums' 
+    fallback = 'admin_forums'
     form = RedirectForm
     submit_button = _("Save Forum")
-        
+
     def get_new_url(self, model):
         return reverse('admin_forums_new_redirect')
-    
+
     def get_edit_url(self, model):
         return reverse('admin_forums_edit', model)
-    
+
     def submit_form(self, form, target):
         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.insert_at(form.cleaned_data['parent'], position='last-child', save=True)
         Forum.objects.populate_tree(True)
-        
+
         if form.cleaned_data['perms']:
             new_forum.copy_permissions(form.cleaned_data['perms'])
             self.request.monitor['acl_version'] = int(self.request.monitor['acl_version']) + 1
-            
+
         return new_forum, Message(_('New Redirect has been created.'), 'success')
-    
+
     def __call__(self, request):
         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)
@@ -186,7 +186,7 @@ class Up(ButtonWidget):
     id = 'up'
     fallback = 'admin_forums'
     notfound_message = _('Requested Forum could not be found.')
-    
+
     def action(self, target):
         previous_sibling = target.get_previous_sibling()
         if previous_sibling:
@@ -200,15 +200,15 @@ class Down(ButtonWidget):
     id = 'down'
     fallback = 'admin_forums'
     notfound_message = _('Requested Forum could not be found.')
-    
+
     def action(self, target):
         next_sibling = target.get_next_sibling()
         if next_sibling:
             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" is last child of its parent node and cannot be moved down.') % {'name': target.name}, 'info'), False
-  
-   
+
+
 class Edit(FormWidget):
     admin = site.get_action('forums')
     id = 'edit'
@@ -218,13 +218,13 @@ class Edit(FormWidget):
     target_name = 'name'
     notfound_message = _('Requested Forum could not be found.')
     submit_fallback = True
-    
+
     def get_url(self, model):
         return reverse('admin_forums_edit', model)
-    
+
     def get_edit_url(self, model):
         return self.get_url(model)
-    
+
     def get_form(self, target):
         if target.type == 'category':
             self.name = _("Edit Category")
@@ -233,20 +233,20 @@ class Edit(FormWidget):
             self.name = _("Edit Redirect")
             self.form = RedirectForm
         return self.form
-    
+
     def get_form_instance(self, form, target, initial, post=False):
         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))
-        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
-    
+
     def get_initial_data(self, model):
         initial = {
                    'parent': model.parent,
                    'name': model.name,
                    'description': model.description,
                    }
-            
+
         if model.type == 'redirect':
             initial['redirect'] = model.redirect
         else:
@@ -254,13 +254,13 @@ class Edit(FormWidget):
             initial['show_details'] = model.show_details
             initial['style'] = model.style
             initial['closed'] = model.closed
-            
+
         if model.type == 'forum':
             initial['prune_start'] = model.prune_start
             initial['prune_last'] = model.prune_last
-        
+
         return initial
-    
+
     def submit_form(self, form, target):
         target.name = 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.style = form.cleaned_data['style']
             target.closed = form.cleaned_data['closed']
-            
+
         if target.type == 'forum':
             target.prune_start = form.cleaned_data['prune_start']
             target.prune_last = form.cleaned_data['prune_last']
-            
+
         if form.cleaned_data['parent'].pk != target.parent.pk:
             print 'MOVE FORUM!'
             target.move_to(form.cleaned_data['parent'], 'last-child')
             self.request.monitor['acl_version'] = int(self.request.monitor['acl_version']) + 1
-            
+
         target.save(force_update=True)
         Forum.objects.populate_tree(True)
-            
+
         if 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']:
             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')
 
 
@@ -304,23 +304,23 @@ class Delete(FormWidget):
     target_name = 'name'
     notfound_message = _('Requested Forum could not be found.')
     submit_fallback = True
-    
+
     def get_url(self, model):
         return reverse('admin_forums_delete', model)
-   
+
     def get_form(self, target):
         if target.type == 'category':
-            self.name= _("Delete Category")
+            self.name = _("Delete Category")
         if target.type == 'redirect':
-            self.name= _("Delete Redirect")
+            self.name = _("Delete Redirect")
         return self.form
-    
+
     def get_form_instance(self, form, target, initial, post=False):
         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))
-        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
-        
+
     def submit_form(self, form, target):
         new_parent = form.cleaned_data['parent']
         if new_parent:
@@ -333,4 +333,4 @@ class Delete(FormWidget):
                 child.delete()
         target.delete()
         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):
         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):
         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>')
-        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['image_reference']
     del md.inlinePatterns['short_reference']
-    
+
 
 def signature_markdown(acl, text):
     md = markdown.Markdown(
                            safe_mode='escape',
                            output_format=settings.OUTPUT_FORMAT,
                            extensions=['nl2br'])
-    
+
     remove_unsupported(md)
-    
+
     if not acl.usercp.allow_signature_links():
         del md.inlinePatterns['link']
         del md.inlinePatterns['autolink']
     if not acl.usercp.allow_signature_images():
         del md.inlinePatterns['image_link']
-        
+
     del md.parser.blockprocessors['hashheader']
     del md.parser.blockprocessors['setextheader']
     del md.parser.blockprocessors['code']
@@ -34,7 +34,7 @@ def signature_markdown(acl, text):
     del md.parser.blockprocessors['hr']
     del md.parser.blockprocessors['olist']
     del md.parser.blockprocessors['ulist']
-    
+
     return md.convert(text)
 
 
@@ -43,7 +43,7 @@ def post_markdown(request, text):
                            safe_mode='escape',
                            output_format=settings.OUTPUT_FORMAT,
                            extensions=['nl2br', 'fenced_code'])
-    
+
     remove_unsupported(md)
     md.mi_token = get_random_string(16)
     for extension in settings.MARKDOWN_EXTENSIONS:
@@ -54,14 +54,14 @@ def post_markdown(request, text):
         ext = attr()
         ext.extendMarkdown(md)
     text = md.convert(text)
-    
+
     # Final cleanups
     text = text.replace('<p><h3><quotetitle>', '<h3><quotetitle>')
     text = text.replace('</quotetitle></h3></p>', '</quotetitle></h3>')
     text = text.replace('</quotetitle></h3><br>\n', '</quotetitle></h3>\n<p>')
     text = text.replace('\n<p></p>', '')
     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)
-    
-    return text
+
+    return text

+ 1 - 1
misago/markdown/views.py

@@ -4,4 +4,4 @@ from misago.markdown import post_markdown
 def preview(request):
     if 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.messages = session.get('messages_list', [])
         self.session['messages_list'] = []
-        
+
     def set_message(self, message, type='info', owner=None):
         message.type = type
         message.owner = owner
         self.messages.append(message)
-    
+
     def set_flash(self, message, type='info', owner=None):
         self.set_message(message, type, owner)
         self.session['messages_list'].append(message)
-        
+
     def get_message(self, owner=None):
         for index, message in enumerate(self.messages):
             if message.owner == owner:
                 del self.messages[index]
                 return message
         return None
-        
+
     def get_messages(self, owner=None):
         orphans = []
         messages = []
@@ -36,4 +36,4 @@ class Message(object):
     def __init__(self, message=None, type='info', owner=None):
         self.type = type
         self.message = message
-        self.owner = owner
+        self.owner = owner

+ 1 - 1
misago/messages/context_processors.py

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

+ 1 - 1
misago/messages/middleware.py

@@ -2,4 +2,4 @@ from misago.messages import Messages
 
 class MessagesMiddleware(object):
     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):
     return {
         'monitor' : request.monitor,
-    }
+    }

+ 2 - 2
misago/monitor/fixtures.py

@@ -1,6 +1,6 @@
 from django.utils import timezone
 from misago.monitor.models import Item
-    
+
 def load_monitor_fixture(fixture):
     for id in fixture.keys():
         item = Item(
@@ -8,4 +8,4 @@ def load_monitor_fixture(fixture):
                     value=fixture[id],
                     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):
     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):
     id = models.CharField(max_length=255, primary_key=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._items = {}
         self.refresh()
-            
+
     def refresh(self):
         self._items = cache.get('misago.monitor')
         if not self._items:
@@ -28,20 +28,20 @@ class Monitor(object):
         sync_item = Item(id=key, value=value, updated=timezone.now())
         sync_item.save(force_update=True)
         return value
-        
+
     def __delitem__(self, key):
         pass
-        
+
     def get(self, key, default=None):
         if not key in self._items:
             return default
         return self._items[key][0]
-    
+
     def get_updated(self, key):
         if key in self._items:
             return self._items[key][1]
         return None
-        
+
     def has_key(self, key):
         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
 
 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_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 = (
               (
                _("Newsletter Options"),
@@ -36,12 +36,12 @@ class NewsletterForm(Form):
              )
 
 
-class SearchNewslettersForm(Form):    
+class SearchNewslettersForm(Form):
     name = 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)
     rank = forms.ModelMultipleChoiceField(widget=forms.CheckboxSelectMultiple, queryset=Rank.objects.order_by('order').all(), required=False)
-    
+
     layout = (
               (
                _("Search Newsletters"),
@@ -52,4 +52,4 @@ class SearchNewslettersForm(Form):
                 ('rank', {'label': _("Recipient Rank")}),
                ),
               ),
-             )
+             )

+ 7 - 7
misago/newsletters/models.py

@@ -6,28 +6,28 @@ class Newsletter(models.Model):
     token = models.CharField(max_length=32)
     step_size = 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)
     ranks = models.ManyToManyField('ranks.Rank')
-    
+
     def generate_token(self):
         self.token = get_random_string(32)
-    
+
     def parse_name(self, tokens):
         name = self.name
         for key in tokens:
             name = name.replace(key, tokens[key])
         return name
-    
+
     def parse_html(self, tokens):
         content_html = self.content_html
         for key in tokens:
             content_html = content_html.replace(key, tokens[key])
         return content_html
-    
+
     def parse_plain(self, tokens):
         content_plain = self.content_plain
         for key in tokens:
             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):
     admin = site.get_action('newsletters')
     id = 'list'
-    columns=(
+    columns = (
              ('newsletter', _("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?")),
              )
     pagination = 20
     search_form = SearchNewslettersForm
-    
+
     def sort_items(self, page_items, sorting_method):
         return page_items.order_by('-id')
-    
+
     def set_filters(self, model, filters):
         if 'rank' in filters:
             model = model.filter(ranks__in=filters['rank']).distinct()
@@ -46,7 +46,7 @@ class List(ListWidget):
         if 'content' in filters:
             model = model.filter(Q(content_html__icontains=filters['content']) | Q(content_plain__icontains=filters['content']))
         return model
-    
+
     def get_item_actions(self, item):
         return (
                 self.action('envelope', _("Send Newsletter"), reverse('admin_newsletters_send', item)),
@@ -62,35 +62,35 @@ class List(ListWidget):
 class New(FormWidget):
     admin = site.get_action('newsletters')
     id = 'new'
-    fallback = 'admin_newsletters' 
+    fallback = 'admin_newsletters'
     form = NewsletterForm
     submit_button = _("Save Newsletter")
     tabbed = True
-        
+
     def get_new_url(self, model):
         return reverse('admin_newsletters_new')
-    
+
     def get_edit_url(self, model):
         return reverse('admin_newsletters_edit', model)
-    
+
     def submit_form(self, form, target):
         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.save(force_insert=True)
-        
+
         for rank in form.cleaned_data['ranks']:
             new_newsletter.ranks.add(rank)
         new_newsletter.save(force_update=True)
-        
+
         return new_newsletter, Message(_('New Newsletter has been created.'), 'success')
-    
-   
+
+
 class Edit(FormWidget):
     admin = site.get_action('newsletters')
     id = 'edit'
@@ -101,13 +101,13 @@ class Edit(FormWidget):
     notfound_message = _('Requested Newsletter could not be found.')
     submit_fallback = True
     tabbed = True
-    
+
     def get_url(self, model):
         return reverse('admin_newsletters_edit', model)
-    
+
     def get_edit_url(self, model):
         return self.get_url(model)
-    
+
     def get_initial_data(self, model):
         return {
                 'name': model.name,
@@ -117,7 +117,7 @@ class Edit(FormWidget):
                 'content_plain': model.content_plain,
                 'ranks': model.ranks.all(),
                 }
-    
+
     def submit_form(self, form, target):
         target.name = form.cleaned_data['name']
         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_plain = form.cleaned_data['content_plain']
         target.generate_token()
-        
+
         target.ranks.clear()
         for rank in form.cleaned_data['ranks']:
             target.ranks.add(rank)
-            
+
         target.save(force_update=True)
         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'
     fallback = 'admin_newsletters'
     notfound_message = _('Requested newsletter could not be found.')
-    
+
     def action(self, target):
         target.delete()
         return Message(_('Newsletter "%(name)s"" has been deleted.') % {'name': target.name}, 'success'), False
-    
+
 
 def send(request, target, token):
     try:
         newsletter = Newsletter.objects.get(pk=target, token=token)
-        
+
         # Build recipients selector
         recipients = User.objects
         if newsletter.ranks.all():
             recipients.filter(rank__in=[x.pk for x in newsletter.ranks.all()])
         if not newsletter.ignore_subscriptions:
             recipients.filter(receive_newsletters=1)
-        
+
         recipients_total = recipients
         recipients_total = recipients_total.count()
         if recipients_total < 1:
             request.messages.set_flash(Message(_('No recipients for newsletter "%(newsletter)s" could be found.') % {'newsletter': newsletter.name}), 'error', 'newsletters')
             return redirect(reverse('admin_newsletters'))
-       
+
         for user in recipients.all()[newsletter.progress:(newsletter.progress + newsletter.step_size)]:
             tokens = {
               '{{ board_name }}': request.settings.board_name,
@@ -179,13 +179,13 @@ def send(request, target, token):
             newsletter.progress += 1
         newsletter.generate_token()
         newsletter.save(force_update=True)
-        
+
         if newsletter.progress >= recipients_total:
             newsletter.progress = 0
             newsletter.save(force_update=True)
             request.messages.set_flash(Message(_('Newsletter "%(newsletter)s" has been sent.') % {'newsletter': newsletter.name}), 'success', 'newsletters')
             return redirect(reverse('admin_newsletters'))
-        
+
         # Render Progress
         response = request.theme.render_to_response('processing.html', {
                 'task_name': _('Sending Newsletter'),
@@ -198,4 +198,4 @@ def send(request, target, token):
         return response
     except Newsletter.DoesNotExist:
         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+)/details/$', 'profile', name="user_details", kwargs={'tab': 'details'}),
     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):
     ranks = Rank.objects.filter(as_tab=1).order_by('order')
-    
+
     # Find active rank
     active_rank = None
     if rank_slug:
@@ -23,12 +23,12 @@ def list(request, rank_slug=None):
             return error404(request)
     elif ranks:
         active_rank = ranks[0]
-    
+
     # Empty Defaults
     message = None
     users = []
     in_search = False
-    
+
     # Users search?
     if request.method == 'POST':
         in_search = True
@@ -42,7 +42,7 @@ def list(request, rank_slug=None):
                 return redirect(reverse('user', args=(user.username_slug, user.pk)))
             except User.DoesNotExist:
                 pass
-            
+
             # Looks like well have to find near match
             if len(username) > 6:
                 username = username[0:-3]
@@ -51,7 +51,7 @@ def list(request, rank_slug=None):
             elif len(username) > 4:
                 username = username[0:-1]
             username = slugify(username.strip())
-            
+
             # Go for rought match
             if len(username) > 0:
                 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)
         if active_rank:
             users = User.objects.filter(rank=active_rank).order_by('username_slug')
-    
+
     return request.theme.render_to_response('profiles/list.html',
                                         {
                                          'message': message,
@@ -86,7 +86,7 @@ def profile(request, user, username, tab='posts'):
         return globals()['profile_%s' % tab](request, user)
     except User.DoesNotExist:
         return error404(request)
-    
+
 
 def profile_posts(request, user):
     return request.theme.render_to_response('profiles/profile.html',
@@ -95,7 +95,7 @@ def profile_posts(request, user):
                                              'tab': 'posts',
                                             },
                                             context_instance=RequestContext(request));
-    
+
 
 def profile_threads(request, user):
     return request.theme.render_to_response('profiles/profile.html',
@@ -104,7 +104,7 @@ def profile_threads(request, user):
                                              'tab': 'threads',
                                             },
                                             context_instance=RequestContext(request));
-    
+
 
 def profile_following(request, user):
     return request.theme.render_to_response('profiles/profile.html',
@@ -113,7 +113,7 @@ def profile_following(request, user):
                                              'tab': 'following',
                                             },
                                             context_instance=RequestContext(request));
-    
+
 
 def profile_followers(request, user):
     return request.theme.render_to_response('profiles/profile.html',
@@ -122,7 +122,7 @@ def profile_followers(request, user):
                                              'tab': 'followers',
                                             },
                                             context_instance=RequestContext(request));
-    
+
 
 def profile_details(request, user):
     return request.theme.render_to_response('profiles/details.html',
@@ -130,4 +130,4 @@ def profile_details(request, user):
                                              'profile': user,
                                              '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
 
 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 = (
               (
                _("Basic Policy Options"),
                (
                 ('name', {'label': _("Policy Name"), 'help_text': _("Short, descriptive name of this pruning policy.")}),
-               )
-              ),
+                )
+               ),
               (
                _("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")}),
                 ('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.")}),
-               )
-              ),
-             )
-    
+                )
+               ),
+              )

+ 9 - 9
misago/prune/models.py

@@ -11,18 +11,18 @@ class Policy(models.Model):
     Pruning policy
     """
     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)
     registered = models.PositiveIntegerField(default=0)
     last_visit = models.PositiveIntegerField(default=0)
-    
+
     def clean(self):
         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."))
-        
+
     def get_model(self):
         model = User.objects
-        
+
         if self.email:
             if ',' in self.email:
                 qs = None
@@ -37,16 +37,16 @@ class Policy(models.Model):
                     model = model.filter(qs)
             else:
                 model = model.filter(email__iendswith=self.email)
-                
+
         if self.posts:
             model = model.filter(posts__lt=self.posts)
-            
+
         if self.registered:
             date = timezone.now() - timedelta(days=self.registered)
             model = model.filter(join_date__gte=date)
-            
+
         if self.last_visit:
             date = timezone.now() - timedelta(days=self.last_visit)
             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):
     admin = site.get_action('prune_users')
     id = 'list'
-    columns=(
-             ('name', _("Pruning Policy")),
-             )
+    columns = (
+               ('name', _("Pruning 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):
         return page_items.order_by('name')
-    
+
     def get_item_actions(self, item):
         return (
                 self.action('filter', _("Apply Policy"), reverse('admin_prune_users_apply', item)),
@@ -40,7 +40,7 @@ class List(ListWidget):
     def action_delete(self, items, checked):
         if not self.request.user.is_god():
             return Message(_('Only system administrators can delete pruning policies.'), 'error'), reverse('admin_prune_users')
-        
+
         Policy.objects.filter(id__in=checked).delete()
         return Message(_('Selected pruning policies have been deleted successfully.'), 'success'), reverse('admin_prune_users')
 
@@ -48,37 +48,37 @@ class List(ListWidget):
 class New(FormWidget):
     admin = site.get_action('prune_users')
     id = 'new'
-    fallback = 'admin_prune_users' 
+    fallback = 'admin_prune_users'
     form = PolicyForm
     submit_button = _("Save Policy")
-        
+
     def get_new_url(self, model):
         return reverse('admin_prune_users_new')
-    
+
     def get_edit_url(self, model):
         return reverse('admin_prune_users_edit', model)
-    
+
     def submit_form(self, form, target):
         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.save(force_insert=True)
-        
+
         return new_policy, Message(_('New Pruning Policy has been created.'), 'success')
-    
+
     def __call__(self, request, *args, **kwargs):
         if not request.user.is_god():
             request.messages.set_flash(Message(_('Only system administrators can set new pruning policies.')), 'error', self.admin.id)
             return redirect(reverse('admin_prune_users'))
-        
+
         return super(New, self).__call__(request, *args, **kwargs)
 
-  
+
 class Edit(FormWidget):
     admin = site.get_action('prune_users')
     id = 'edit'
@@ -88,13 +88,13 @@ class Edit(FormWidget):
     target_name = 'name'
     notfound_message = _('Requested pruning policy could not be found.')
     submit_fallback = True
-    
+
     def get_url(self, model):
         return reverse('admin_prune_users_edit', model)
-    
+
     def get_edit_url(self, model):
         return self.get_url(model)
-    
+
     def get_initial_data(self, model):
         return {
                 'name': model.name,
@@ -103,7 +103,7 @@ class Edit(FormWidget):
                 'registered': model.registered,
                 'last_visit': model.last_visit,
                 }
-    
+
     def submit_form(self, form, target):
         target.name = form.cleaned_data['name']
         target.email = form.cleaned_data['email']
@@ -112,14 +112,14 @@ class Edit(FormWidget):
         target.last_visit = form.cleaned_data['last_visit']
         target.clean()
         target.save(force_update=True)
-        
+
         return target, Message(_('Changes in policy "%(name)s" have been saved.') % {'name': self.original_name}, 'success')
-    
+
     def __call__(self, request, *args, **kwargs):
         if not request.user.is_god():
             request.messages.set_flash(Message(_('Only system administrators can edit pruning policies.')), 'error', self.admin.id)
             return redirect(reverse('admin_prune_users'))
-        
+
         return super(Edit, self).__call__(request, *args, **kwargs)
 
 
@@ -128,14 +128,14 @@ class Delete(ButtonWidget):
     id = 'delete'
     fallback = 'admin_prune_users'
     notfound_message = _('Requested pruning policy could not be found.')
-    
+
     def action(self, target):
         if not self.request.user.is_god():
             return Message(_('Only system administrators can delete pruning policies.'), 'error'), False
-        
+
         target.delete()
         return Message(_('Pruning policy "%(name)s" has been deleted.') % {'name': target.name}, 'success'), False
-    
+
 
 class Apply(FormWidget):
     admin = site.get_action('prune_users')
@@ -147,13 +147,13 @@ class Apply(FormWidget):
     notfound_message = _('Requested pruning policy could not be found.')
     submit_fallback = True
     template = 'apply'
-    
+
     def get_url(self, model):
         return reverse('admin_prune_users_apply', model)
-    
+
     def __call__(self, request, target=None, slug=None):
         self.request = request
-        
+
         # Fetch target
         model = None
         if target:
@@ -162,16 +162,16 @@ class Apply(FormWidget):
             if not model:
                 return redirect(self.get_fallback_url())
         original_model = model
-                
+
         # Set filter
-        users = model.get_model() 
+        users = model.get_model()
         total_users = users
         total_users = total_users.count()
-        
+
         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)
             return redirect(reverse('admin_prune_users'))
-        
+
         message = None
         if request.method == 'POST':
             deleted = 0
@@ -194,7 +194,7 @@ class Apply(FormWidget):
                 return redirect(reverse('admin_prune_users'))
             else:
                 message = Message(_("Request authorization is invalid. Please resubmit your form."), 'error')
-        
+
         return request.theme.render_to_response(self.get_template(),
                                                 {
                                                  'admin': self.admin,
@@ -209,4 +209,4 @@ class Apply(FormWidget):
                                                  'target': self.get_target_name(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,
                         on_index=True,
                         )
-    
+
     Rank.objects.create(
                         name=_("Most Valuable Posters").message,
                         name_slug='most-valuable-posters',
@@ -23,26 +23,26 @@ def load_fixtures():
                         order=1,
                         as_tab=True,
                         )
-    
+
     Rank.objects.create(
                         name=_("Lurkers").message,
                         name_slug='lurkers',
                         order=1,
                         criteria="100%"
                         )
-    
+
     Rank.objects.create(
                         name=_("Members").message,
-                        name_slug='members'
+                        name_slug='members',
                         order=2,
                         criteria="75%"
                         )
-    
+
     Rank.objects.create(
                         name=_("Active Members").message,
-                        name_slug='active-members'
+                        name_slug='active-members',
                         style='rank-active',
                         order=3,
                         criteria="10%",
                         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
 
 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 = (
               (
                _("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.")}),
                 ('as_tab', {'label': _("As Tab on Users List"), 'help_text': _("Should this rank have its own page on users list, containing rank's description and list of users that have it? This is good option for rank used by forum team members or members that should be visible and easily reachable.")}),
                 ('on_index', {'label': _("Display members online"), 'help_text': _("Should users online with this rank be displayed on board index?")}),
-               )
-              ),
+                )
+               ),
               (
                _("Rank Looks"),
                (
                 ('title', {'label': _("Rank Title"), 'help_text': _("Short description of rank's bearer role in your community.")}),
                 ('style', {'label': _("Rank CSS Class"), 'help_text': _("Optional CSS class that will be added to different elements displaying rank's owner or his content, allowing you to make them stand out from other members.")}),
-               )
-              ),
+                )
+               ),
               (
                _("Rank Attainability"),
                (
                 ('special', {'label': _("Special Rank"), 'help_text': _("Special ranks are ignored during updates of user ranking, making them unattainable without admin ingerention.")}),
                 ('criteria', {'label': _("Rank Criteria"), 'help_text': _("This setting allows you to limit number of users that can attain this rank. Enter 0 to assign this rank to all members (good for default rank). To give this rank to 10% of most active members, enter \"10%\". To give this rank to 10 most active members, enter \"10\". This setting is ignored for special ranks as they don't participate in user's ranking updates.")}),
+                ),
                ),
-              ),
-             )
-    
+              )

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

@@ -13,10 +13,10 @@ class Command(BaseCommand):
         special_ranks = []
         for rank in Rank.objects.filter(special=1):
             special_ranks.append(str(rank.pk))
-        
+
         # Count users that are in ranking
         users_total = User.objects.exclude(rank__in=special_ranks).count()
-        
+
         # Update Ranking
         defaulted_ranks = False
         for rank in Rank.objects.filter(special=0).order_by('order'):
@@ -27,8 +27,8 @@ class Command(BaseCommand):
                 # Set default rank first
                 User.objects.exclude(rank__in=special_ranks).update(rank=rank)
                 defaulted_ranks = True
-        
+
         # Inflate scores
         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.
     """
     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)
     as_tab = models.BooleanField(default=False)
     on_index = models.BooleanField(default=False)
     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):
         return unicode(_(self.name))
-    
+
     def assign_rank(self, users=0, special_ranks=None):
         if not self.criteria or self.special or users == 0:
             # Rank cant be rolled in
             return False
-        
+
         if self.criteria == "0":
             # Just update all fellows
             User.objects.exclude(rank__in=special_ranks).update(rank=self)
@@ -33,14 +33,14 @@ class Rank(models.Model):
             # Count number of users to update
             if self.criteria[-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:
                 criteria = int(self.criteria)
-            
+
             # Join special ranks
             if special_ranks:
                 special_ranks = ','.join(special_ranks)
-            
+
             # Run raw query
             cursor = connection.cursor()
             try:
@@ -68,7 +68,7 @@ class Rank(models.Model):
                             SET rank_id=%s
                             WHERE id = updateable.id
                             RETURNING *''', [self.id, criteria])
-                        
+
                 # MySQL, SQLite and Oracle
                 if (settings.DATABASES['default']['ENGINE'] == 'django.db.backends.mysql'
                     or settings.DATABASES['default']['ENGINE'] == 'django.db.backends.sqlite3'
@@ -87,4 +87,4 @@ class Rank(models.Model):
             except Exception as e:
                 print 'Error updating users ranking: %s' % e
             transaction.commit_unless_managed()
-        return True
+        return True

+ 36 - 36
misago/ranks/views.py

@@ -19,41 +19,41 @@ Views
 class List(ListWidget):
     admin = site.get_action('ranks')
     id = 'list'
-    columns=(
-             ('rank', _("Rank")),
-             )
+    columns = (
+               ('rank', _("Rank")),
+               )
     table_form_button = _('Reorder Ranks')
     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):
         order_form = {}
-        
+
         # Build choices list
         choices = []
         for i in range(0, len(page_items)):
            choices.append([str(i), i + 1])
-        
+
         # Build selectors list
         position = 0
         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
-        
+
         # Turn dict into object
         return type('OrderRanksForm', (Form,), order_form)
-    
+
     def table_action(self, page_items, cleaned_data):
         for item in page_items:
             item.order = cleaned_data['pos_' + str(item.pk)]
             item.save(force_update=True)
         return Message(_('Ranks order has been changed'), 'success'), reverse('admin_ranks')
-    
+
     def sort_items(self, page_items, sorting_method):
         return page_items.order_by('order')
-    
+
     def get_item_actions(self, item):
         return (
                 self.action('pencil', _("Edit Rank"), reverse('admin_ranks_edit', item)),
@@ -68,35 +68,35 @@ class List(ListWidget):
 class New(FormWidget):
     admin = site.get_action('ranks')
     id = 'new'
-    fallback = 'admin_ranks' 
+    fallback = 'admin_ranks'
     form = RankForm
     submit_button = _("Save Rank")
-        
+
     def get_new_url(self, model):
         return reverse('admin_ranks_new')
-    
+
     def get_edit_url(self, model):
         return reverse('admin_ranks_edit', model)
-    
+
     def submit_form(self, form, target):
         position = 0
         last_rank = Rank.objects.latest('order')
         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)
         return new_rank, Message(_('New Rank has been created.'), 'success')
-    
-   
+
+
 class Edit(FormWidget):
     admin = site.get_action('ranks')
     id = 'edit'
@@ -106,13 +106,13 @@ class Edit(FormWidget):
     target_name = 'name'
     notfound_message = _('Requested Rank could not be found.')
     submit_fallback = True
-    
+
     def get_url(self, model):
         return reverse('admin_ranks_edit', model)
-    
+
     def get_edit_url(self, model):
         return self.get_url(model)
-    
+
     def get_initial_data(self, model):
         return {
                 'name': model.name,
@@ -124,7 +124,7 @@ class Edit(FormWidget):
                 'on_index': model.on_index,
                 'criteria': model.criteria
                 }
-    
+
     def submit_form(self, form, target):
         target.name = form.cleaned_data['name']
         target.name_slug = slugify(form.cleaned_data['name'])
@@ -144,7 +144,7 @@ class Delete(ButtonWidget):
     id = 'delete'
     fallback = 'admin_ranks'
     notfound_message = _('Requested Rank could not be found.')
-    
+
     def action(self, target):
         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")),
                                       ('crawler', _("Crawler Sessions")),
                                       ), required=False)
-    
+
     layout = (
               (
                _("Search Sessions"),
@@ -24,4 +24,4 @@ class SearchSessionsForm(Form):
                 ('type', {'label': _("Session Type")}),
                ),
               ),
-             )
+             )

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

@@ -11,4 +11,4 @@ class Command(BaseCommand):
     help = 'Clears users sessions'
     def handle(self, *args, **options):
         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'
     def handle(self, *args, **options):
         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
             request.session = SessionHuman(request)
             request.user = request.session.get_user()
-            
+
             if request.user.is_authenticated():
                 request.session.set_hidden(request.user.hide_activity > 0)
-        
+
     def process_response(self, request, response):
         try:
             request.session.save()
         except AttributeError:
             pass
-        return response
+        return response

+ 2 - 2
misago/sessions/models.py

@@ -1,5 +1,5 @@
 from django.db import models
-       
+
 class Session(models.Model):
     id = models.CharField(max_length=42, primary_key=True)
     data = models.TextField(db_column="session_data")
@@ -19,4 +19,4 @@ class Token(models.Model):
     id = models.CharField(max_length=42, primary_key=True)
     user = models.ForeignKey('users.User', related_name='signin_tokens')
     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
 if not model_cache.loaded:
     model_cache.get_models()
-    
-    
+
+
 class IncorrectSessionException(Exception):
     pass
 
-    
+
 class SessionMisago(SessionBase):
     """
     Abstract class for sessions to inherit and extend
     """
     def _get_new_session_key(self):
         return get_random_string(42)
-      
+
     def _get_session(self):
         try:
             return self._session_cache
         except AttributeError:
             self._session_cache = self.load()
         return self._session_cache
-        
+
     def _hash(self, value):
         key_salt = "misago.sessions" + self.__class__.__name__
         return salted_hmac(key_salt, value).hexdigest()
-       
+
     def delete(self):
         """We use sessions to track onlines so sorry, only sessions cleaner may delete sessions"""
         pass
-       
+
     def flush(self):
         """We use sessions to track onlines so sorry, only sessions cleaner may delete sessions"""
         pass
 
     def load(self):
         return self.decode(force_unicode(self._session_rk.data))
-    
+
     def session_expired(self):
         return False
-        
+
     def get_hidden(self):
         return False
-    
+
     def set_hidden(self, hidden=False):
         pass
-    
+
     def get_ip(self, request):
         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
-    
+
     def get_ban(self):
         return False
-    
+
     def set_ban(self, ban):
         return False
-    
+
     def save(self):
         self._session_rk.data = self.encode(self._get_session())
         self._session_rk.last = timezone.now()
@@ -88,7 +88,7 @@ class SessionCrawler(SessionMisago):
             self._session_key = self._session_rk.id
         except Session.DoesNotExist:
             self.create(request)
-            
+
     def create(self, request):
         while True:
             try:
@@ -108,7 +108,7 @@ class SessionCrawler(SessionMisago):
             except CreateError:
                 # Key wasn't unique. Try again.
                 continue
-            
+
     def human_session(self):
         return False
 
@@ -159,14 +159,14 @@ class SessionHuman(SessionMisago):
             except AuthException as e:
                 # Autolog failed
                 self.create(request)
-        self.id = self._session_rk.id        
-        
+        self.id = self._session_rk.id
+
         # Make cookie live longer
         if request.firewall.admin:
             request.cookie_jar.set('ASID', self._session_rk.id)
-        else:   
+        else:
             request.cookie_jar.set('SID', self._session_rk.id)
-            
+
     def create(self, request, user=None):
         self._user = user
         while True:
@@ -195,28 +195,28 @@ class SessionHuman(SessionMisago):
             except CreateError:
                 # Key wasn't unique. Try again.
                 continue
-    
+
     def save(self):
         self._session_rk.user = self._user
         self._session_rk.hidden = self.hidden
         self._session_rk.team = self.team
         self._session_rk.rank_id = self.rank
         super(SessionHuman, self).save()
-        
+
     def human_session(self):
         return True
-    
+
     def session_expired(self):
         return self.expired
-        
+
     def get_user(self):
         if self._user == None:
             return Guest()
         return self._user
-    
+
     def set_user(self, user=None):
         self._user = user
-    
+
     def sign_out(self, request):
         try:
             if self._user.is_authenticated():
@@ -231,9 +231,9 @@ class SessionHuman(SessionMisago):
                 request.user = Guest()
         except AttributeError:
             pass
-        
+
     def get_hidden(self):
         return self.hidden
-    
+
     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):
     admin = site.get_action('online')
     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'
-    sortables={
-               'start': 0,
-               'last': 0,
-              }
+    sortables = {
+                 'start': 0,
+                 'last': 0,
+                }
     hide_actions = True
     pagination = 50
     search_form = SearchSessionsForm
     empty_message = _('Looks like nobody is currently online on forums.')
-    
+
     def set_filters(self, model, filters):
         if 'username' in filters:
             model = model.filter(user__username__istartswith=filters['username'])
@@ -37,9 +37,9 @@ class List(ListWidget):
         if filters['type'] == 'crawler':
             model = model.filter(crawler__isnull=False)
         return model
-    
+
     def prefetch_related(self, items):
         return items.prefetch_related('user')
-    
+
     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):
     return {
         'settings' : request.settings,
-    }
+    }

+ 10 - 10
misago/settings/fixtures.py

@@ -6,7 +6,7 @@ try:
     import cPickle as pickle
 except ImportError:
     import pickle
-    
+
 settings_fixture = (
    # Basic options
    ('basic', {
@@ -116,7 +116,7 @@ def update_settings_group_fixture(group, fixture):
             settings[setting.pk] = setting.value
         model_group.delete()
         load_settings_group_fixture(group, fixture)
-        
+
         for setting in settings:
             try:
                 new_setting = Setting.objects.get(pk=setting)
@@ -126,21 +126,21 @@ def update_settings_group_fixture(group, fixture):
                 pass
     except Group.DoesNotExist:
         load_settings_group_fixture(group, fixture)
-    
+
 
 def load_settings_fixture(fixture):
     for group in fixture:
         load_settings_group_fixture(group[0], group[1])
-    
-    
+
+
 def update_settings_fixture(fixture):
     for group in fixture:
         update_settings_group_fixture(group[0], group[1])
-    
-    
+
+
 def load_fixtures():
     load_settings_fixture(settings_fixture)
-    
-    
+
+
 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
 
 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
-    
+
 class SettingsMiddleware(object):
     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):
     key = models.CharField(max_length=255, unique=True)
     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):
         try:
             return self.pk == active_group.pk
@@ -24,19 +24,19 @@ class Group(models.Model):
 class Setting(models.Model):
     setting = models.CharField(max_length=255, primary_key=True)
     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)
     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)
-    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)
-    description = models.TextField(null=True,blank=True)
-    
+    description = models.TextField(null=True, blank=True)
+
     def get_extra(self):
         return pickle.loads(base64.decodestring(self.extra))
-                
+
     def get_value(self):
         if self.type == 'array':
             return self.value.split(',')
@@ -47,7 +47,7 @@ class Setting(models.Model):
         if self.type == 'boolean':
             return self.value == "1"
         return self.value
-            
+
     def set_value(self, value):
         if self.type == 'array':
             self.value = ','.join(value)
@@ -62,10 +62,10 @@ class Setting(models.Model):
         if not self.value and self.value_default:
             self.value = self.value_default
         return self.value
-    
+
     def get_field(self):
         extra = self.get_extra()
-        
+
         # Set validators
         field_validators = []
         if 'min' in extra:
@@ -78,7 +78,7 @@ class Setting(models.Model):
                 field_validators.append(validators.MaxLengthValidator(extra['max']))
             if self.type == 'integer' or self.type == 'float':
                 field_validators.append(validators.MaxValueValidator(extra['max']))
-        
+
         # Yes-no
         if self.input == 'yesno':
             return forms.BooleanField(
@@ -88,7 +88,7 @@ class Setting(models.Model):
                                    required=False,
                                    widget=YesNoSwitch,
                                    )
-        
+
         # Multi-list
         if self.input == 'mlist':
             return forms.MultipleChoiceField(
@@ -100,7 +100,7 @@ class Setting(models.Model):
                                      required=False,
                                      choices=extra['choices']
                                      )
-        
+
         # Select or choice
         if self.input == 'select' or self.input == 'choice':
             # Timezone list?
@@ -114,8 +114,8 @@ class Setting(models.Model):
                                      validators=field_validators,
                                      required=False,
                                      choices=extra['choices']
-                                     )        
-        
+                                     )
+
         # Textarea
         if self.input == 'textarea':
             return forms.CharField(
@@ -126,14 +126,14 @@ class Setting(models.Model):
                                    required=False,
                                    widget=forms.Textarea
                                    )
-            
+
         # Default input
         default_input = forms.CharField
         if self.type == 'integer':
             default_input = forms.IntegerField
         if self.type == 'float':
             default_input = forms.FloatField
-            
+
         # Make text-input
         return default_input(
                              initial=self.get_value(),
@@ -142,4 +142,3 @@ class Setting(models.Model):
                              validators=field_validators,
                              required=False,
                              )
-        

+ 7 - 7
misago/settings/settings.py

@@ -7,7 +7,7 @@ class Settings(object):
         self._settings = {}
         self._models = {}
         self.refresh()
-        
+
     def refresh(self):
         self._models = cache.get('misago.settings')
         if not self._models:
@@ -22,10 +22,10 @@ class Settings(object):
         else:
             for i, model in self._models.items():
                 self._settings[i] = model.get_value()
-            
+
     def __getattr__(self, key):
         return self._settings[key]
-    
+
     def __contains__(self, key):
         return key in self._settings.keys()
 
@@ -39,16 +39,16 @@ class Settings(object):
             self._settings[key] = value
             cache.set('misago.settings', self._models)
         return value
-        
+
     def __delitem__(self, key):
         pass
-        
+
     def get(self, key, default=None):
         try:
             return self._settings[key]
         except KeyError:
             return None
-        
+
     def has_key(self, key):
         return key in self._settings.keys()
 
@@ -68,4 +68,4 @@ class Settings(object):
         return self._settings.itervalues()
 
     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
         else:
             return error404(request, _('The requested settings group could not be found.'))
-            
+
     # Load selected group settings and turn them into form
     group_settings = Setting.objects.filter(group=active_group).order_by('position')
     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['layout'].append(last_fieldset)
     SettingsGroupForm = type('SettingsGroupForm', (Form,), group_form)
-    
+
     #Submit form
     message = request.messages.get_message('admin_settings')
     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')
     else:
         form = SettingsGroupForm(request=request)
-    
+
     # Display settings group form      
     return request.theme.render_to_response('settings/settings.html',
                                             {
@@ -80,14 +80,14 @@ def settings_search(request):
             if form.is_valid():
                 # Start search
                 search_strings = SearchQuery(form.cleaned_data['search_text'])
-                
+
                 # Loop over groups using our search query
                 for setting in Setting.objects.all().order_by('setting'):
                     if (search_strings.search(_(setting.name))
                         or (setting.description and search_strings.search(_(setting.description)))
                         or (setting.value and search_strings.search(setting.value))):
                         found_settings.append(setting)
-                        
+
                 # Scream if nothing could be found
                 if found_settings:
                     message = Message(ungettext(
@@ -96,13 +96,13 @@ def settings_search(request):
                                                 len(found_settings)) % {
                                                     'count': len(found_settings),
                                                 }, 'success')
-                else:                    
+                else:
                     raise SearchException(_('No settings that match search criteria has been found.'))
             else:
                 raise SearchException(_('Search query is empty.'))
         else:
             raise SearchException(_('Search query is invalid.'))
-    except SearchException as e: 
+    except SearchException as e:
         message = Message(e.message, 'error')
     return request.theme.render_to_response('settings/search_results.html',
                                     {
@@ -112,4 +112,4 @@ def settings_search(request):
                                     'found_settings': found_settings,
                                     '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
 # Defautly set Django to look for Misago translations in misago/locale directory
 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

+ 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)
         return False
 
-    
+
 def update_app_fixtures(app):
     """
     See if application has fixtures module defining update_fixtures function
@@ -31,4 +31,4 @@ def update_app_fixtures(app):
         return False
     except Exception as 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('\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('\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.utils import timezone
 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
 
 class Command(BaseCommand):
@@ -19,4 +19,4 @@ class Command(BaseCommand):
                 if load_app_fixtures(app):
                     fixtures += 1
                     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):
                 fixtures += 1
                 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_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'))))
-    
+
     layout = (
               (None, (
                         ('provider_model', {'label': _('Report Type'), 'help_text': _('Select statistics provider.')}),
@@ -20,9 +20,9 @@ class GenerateStatisticsForm(Form):
                         ('stats_precision', {'label': _('Graph Precision')}),
                       )),
               )
-    
+
     def __init__(self, *args, **kwargs):
         provider_choices = kwargs.get('provider_choices')
         del kwargs['provider_choices']
         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.views import error404
 
-
 def form(request):
     """
     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',
                                                 context_instance=RequestContext(request));
-    
+
     message = None
     if request.method == 'POST':
         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')
     else:
         form = GenerateStatisticsForm(provider_choices=statistics_providers, request=request)
-    
+
     return request.theme.render_to_response('stats/form.html', {
                                             'form': FormLayout(form),
                                             'message': message,
@@ -76,12 +75,12 @@ def graph(request, model, date_start, date_end, precision):
     if date_start == date_end:
         # Bad dates
         raise error404()
-    
+
     # Turn stuff into datetime's
     date_start = datetime.strptime(date_start, '%Y-%m-%d')
     date_end = datetime.strptime(date_end, '%Y-%m-%d')
-    
-    
+
+
     statistics_providers = []
     models_map = {}
     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
         return request.theme.render_to_response('stats/not_available.html',
                                                 context_instance=RequestContext(request));
-    
+
     if not model in models_map or check_dates(date_start, date_end, precision):
         # Bad model name or graph data!
         raise error404()
-    
+
     form = GenerateStatisticsForm(
                                   provider_choices=statistics_providers,
                                   request=request,
@@ -116,7 +115,7 @@ def graph(request, model, date_start, date_end, precision):
 def check_dates(date_start, date_end, precision):
     date_diff = date_end - date_start
     date_diff = date_diff.seconds + date_diff.days * 86400
-    
+
     if ((precision == 'day' and date_diff / 86400 > 60)
         or (precision == 'week' and date_diff / 604800 > 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)):
         return Message(_('Too few items to display on graph'), 'error')
     return None
-        
+
 
 def build_graph(model, date_start, date_end, precision):
     if precision == 'day':
@@ -143,19 +142,19 @@ def build_graph(model, date_start, date_end, precision):
     if precision == 'year':
         format = 'Y'
         step = 31536000
-    
+
     date_end = timezone.make_aware(date_end, timezone.get_current_timezone())
     date_start = timezone.make_aware(date_start, timezone.get_current_timezone())
-    
+
     date_diff = date_end - date_start
     date_diff = date_diff.seconds + date_diff.days * 86400
     steps = int(math.ceil(float(date_diff / step))) + 1
     timeline = [0 for i in range(0, steps)]
     for i in range(0, steps):
         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}
-        
+
     # Loop model items
     for item in model.objects.filter_stats(date_start, date_end).iterator():
         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
         stat['stat'][date_diff] += 1
         stat['total'] += 1
-        
+
     # Find max
     for i in stat['stat']:
         if i > stat['max']:
             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):
     def process_request(self, request):
         request.stopwatch = Stopwatch()
-        
+
     def process_response(self, request, response):
         try:
             time = request.stopwatch.time()
@@ -14,4 +14,4 @@ class StopwatchMiddleware(object):
                 stat_file.close()
         except AttributeError:
             pass
-        return response
+        return response

+ 3 - 3
misago/team/views.py

@@ -5,12 +5,12 @@ from misago.admin.widgets import ListWidget
 class List(ListWidget):
     admin = site.get_action('team')
     id = 'list'
-    columns=(
+    columns = (
              ('username', _("Team Member")),
              )
     default_sorting = 'username_slug'
     hide_actions = True
     pagination = 50
-    
+
     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)
     diff = now - val
     local = localtime(val)
-    
+
     # Common situations
     if diff.days == 0:
         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'])}
     if diff.days > -7 or diff.days < 7:
         return _("%(day)s, %(hour)s") % {'day': format(local, 'l'), 'hour': time_format(local, formats['TIME_FORMAT'])}
-    
+
     # Fallback to custom      
     return date(val, arg)
 
@@ -80,7 +80,7 @@ def reltimesince(val, arg=""):
     now = datetime.now(utc if is_aware(val) else None)
     diff = now - val
     local = localtime(val)
-    
+
     # Display specific time
     if diff.seconds >= 0:
         if diff.seconds <= 60:
@@ -107,7 +107,7 @@ def reltimesince(val, arg=""):
                     "Hour ago",
                     "%(hours)s hours ago",
                 hours) % {'hours': hours}
-        
+
     # Fallback to reldate
     return reldate(val, arg)
 
@@ -123,4 +123,4 @@ def reldate_filter(val, arg=""):
 
 @register.filter(name='reltimesince')
 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):
         if not settings.INSTALLED_THEMES:
             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):
     def __init__(self, theme):
         self.set_theme(theme);
-    
+
     def set_theme(self, theme):
         if theme not in settings.INSTALLED_THEMES:
             raise ValueError('"%s" is not correct theme name.' % theme)
         if theme[0] == '_':
             raise ValueError('"%s" is a template package, not a theme.' % theme[1:])
         self._theme = theme;
-          
+
     def reset_theme(self):
         self._theme = settings.INSTALLED_THEMES[0]
-    
+
     def get_theme(self):
         return self._theme
-    
+
     def prefix_templates(self, templates):
         if isinstance(templates, str):
             return ('%s/%s' % (self._theme, templates), templates)
@@ -34,22 +34,22 @@ class Theme(object):
                 prefixed.append('%s/%s' % (self._theme, template))
             prefixed += templates
             return prefixed
-    
+
     def render(self, request, *args, **kwargs):
         return render(request, *args, **kwargs)
-    
+
     def render_to_string(self, templates, *args, **kwargs):
         templates = self.prefix_templates(templates)
         return render_to_string(templates, *args, **kwargs)
-    
+
     def render_to_response(self, templates, *args, **kwargs):
         templates = self.prefix_templates(templates)
         return render_to_response(templates, *args, **kwargs)
-        
+
     def get_email_templates(self, template, contex={}):
             email_type_plain = '_email/%s_plain.html' % template
             email_type_html = '_email/%s_html.html' % template
             return (
                     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)),
-                    )
+                    )

+ 47 - 48
misago/threads/acl.py

@@ -17,43 +17,43 @@ def make_forum_form(request, role, form):
                                                                        ('1', _("Yes, with moderation")),
                                                                        ('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=(
                                                                      ('0', _("No")),
                                                                      ('1', _("Yes, with moderation")),
                                                                      ('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=(
                                                                           ('0', _("No")),
                                                                           ('1', _("Yes, final score")),
                                                                           ('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=(
                                                                      ('0', _("No")),
                                                                      ('1', _("Yes, to stickies")),
                                                                      ('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=(
                                                                         ('0', _("No")),
                                                                         ('1', _("Yes, soft-delete")),
@@ -69,8 +69,8 @@ def make_forum_form(request, role, form):
                                                                       ('1', _("Yes, soft-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((
                         _("Threads"),
                         (
@@ -144,7 +144,7 @@ class ThreadsACL(BaseACL):
                 return self.acl[forum]
         except KeyError:
             return {}
-    
+
     def allow_thread_view(self, user, thread):
         try:
             forum_role = self.acl[thread.forum_id]
@@ -158,21 +158,21 @@ class ThreadsACL(BaseACL):
                 raise ACLError404()
         except KeyError:
             raise ACLError403(_("You don't have permission to read threads in this forum."))
-    
+
     def allow_post_view(self, user, thread, post):
         forum_role = self.acl[thread.forum_id]
         if post.moderated and not (forum_role['can_approve'] or (user.is_authenticated() and user == post.user)):
             raise ACLError404()
         if post.deleted and not (forum_role['can_delete_posts'] or (user.is_authenticated() and user == post.user)):
             raise ACLError404()
-    
+
     def get_readable_forums(self, acl):
         readable = []
         for forum in self.acl:
             if acl.forums.can_browse(forum) and self.acl[forum]['can_read_threads']:
                 readable.append(forum)
         return readable
-    
+
     def filter_threads(self, request, forum, queryset):
         try:
             forum_role = self.acl[forum.pk]
@@ -188,7 +188,7 @@ class ThreadsACL(BaseACL):
         except KeyError:
             return False
         return queryset
-    
+
     def filter_posts(self, request, thread, queryset):
         try:
             forum_role = self.acl[thread.forum.pk]
@@ -200,7 +200,7 @@ class ThreadsACL(BaseACL):
         except KeyError:
             return False
         return queryset
-    
+
     def can_start_threads(self, forum):
         try:
             forum_role = self.acl[forum.pk]
@@ -211,7 +211,7 @@ class ThreadsACL(BaseACL):
             return True
         except KeyError:
             return False
-    
+
     def allow_new_threads(self, forum):
         try:
             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."))
         except KeyError:
             raise ACLError403(_("You don't have permission to start new threads in this forum."))
-    
+
     def can_edit_thread(self, user, forum, thread, post):
         try:
             forum_role = self.acl[thread.forum_id]
@@ -234,7 +234,7 @@ class ThreadsACL(BaseACL):
             return False
         except KeyError:
             return False
-    
+
     def allow_thread_edit(self, user, forum, thread, post):
         try:
             forum_role = self.acl[thread.forum_id]
@@ -277,7 +277,7 @@ class ThreadsACL(BaseACL):
                     raise ACLError403(_("You can't write replies in closed threads."))
         except KeyError:
             raise ACLError403(_("You don't have permission to write replies in this forum."))
-    
+
     def can_edit_reply(self, user, forum, thread, post):
         try:
             forum_role = self.acl[thread.forum_id]
@@ -290,7 +290,7 @@ class ThreadsACL(BaseACL):
             return False
         except KeyError:
             return False
-    
+
     def allow_reply_edit(self, user, forum, thread, post):
         try:
             forum_role = self.acl[thread.forum_id]
@@ -309,14 +309,14 @@ class ThreadsACL(BaseACL):
                     raise ACLError403(_("This reply is protected, you cannot edit it."))
         except KeyError:
             raise ACLError403(_("You don't have permission to edit replies in this forum."))
-    
+
     def can_see_changelog(self, user, forum, post):
         try:
             forum_role = self.acl[forum.pk]
             return forum_role['can_see_changelog'] or user.pk == post.user_id
         except KeyError:
             return False
-    
+
     def allow_changelog_view(self, user, forum, post):
         try:
             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."))
         except KeyError:
             raise ACLError403(_("You don't have permission to see history of changes made to this post."))
-        
+
     def can_make_revert(self, forum, thread):
         try:
             forum_role = self.acl[forum.pk]
@@ -334,7 +334,7 @@ class ThreadsACL(BaseACL):
             return forum_role['can_edit_threads_posts']
         except KeyError:
             return False
-    
+
     def allow_revert(self, forum, thread):
         try:
             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."))
         except KeyError:
             raise ACLError403(_("You don't have permission to make reverts in this forum."))
-            
+
     def can_mod_threads(self, forum):
         try:
             forum_role = self.acl[forum.pk]
@@ -360,7 +360,7 @@ class ThreadsACL(BaseACL):
                     )
         except KeyError:
             return False
-        
+
     def can_mod_posts(self, thread):
         try:
             forum_role = self.acl[thread.forum.pk]
@@ -373,14 +373,14 @@ class ThreadsACL(BaseACL):
                     )
         except KeyError:
             return False
-    
+
     def can_approve(self, forum):
         try:
             forum_role = self.acl[forum.pk]
             return forum_role['can_approve']
         except KeyError:
             return False
-        
+
     def can_protect(self, forum):
         try:
             forum_role = self.acl[forum.pk]
@@ -402,7 +402,7 @@ class ThreadsACL(BaseACL):
             return False
         except KeyError:
             return False
-        
+
     def allow_delete_thread(self, user, forum, thread, post, delete=False):
         try:
             forum_role = self.acl[forum.pk]
@@ -455,21 +455,21 @@ class ThreadsACL(BaseACL):
                 raise ACLError403(_("This post is already deleted."))
         except KeyError:
             raise ACLError403(_("You don't have permission to delete this post."))
-    
+
     def can_see_deleted_threads(self, forum):
         try:
             forum_role = self.acl[forum.pk]
             return forum_role['can_delete_threads']
         except KeyError:
             raise false
-        
+
     def can_see_deleted_posts(self, forum):
         try:
             forum_role = self.acl[forum.pk]
             return forum_role['can_delete_posts']
         except KeyError:
             raise false
-        
+
     def allow_deleted_post_view(self, forum):
         try:
             forum_role = self.acl[forum.pk]
@@ -530,4 +530,3 @@ def build_forums(acl, perms, forums, forum_roles):
             except KeyError:
                 pass
         acl.threads.acl[forum.pk] = forum_role
-            

+ 4 - 4
misago/threads/fixtures.py

@@ -44,7 +44,7 @@ settings_fixtures = (
                 'value':        10,
                 'type':         "integer",
                 'input':        "text",
-                'extra':        {'min': 0,'max': 30},
+                'extra':        {'min': 0, 'max': 30},
                 'separator':    _("Thread Popularity Ranking"),
                 '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.'),
@@ -121,7 +121,7 @@ settings_fixtures = (
 
 def load_fixtures():
     load_settings_fixture(settings_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):
         self.mode = mode
         super(PostForm, self).__init__(data, file, request=request, *args, **kwargs)
-    
+
     def finalize_form(self):
         self.layout = [
                        [
@@ -46,12 +46,12 @@ class PostForm(Form, ThreadNameMixin):
                          ],
                         ],
                        ]
-    
+
         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:
             del self.layout[0][1][1]
-            
+
         if self.mode not in ['edit_thread', 'new_thread']:
             del self.layout[0][1][0]
         else:
@@ -61,7 +61,7 @@ class PostForm(Form, ThreadNameMixin):
                                                                                         _("Thread name must contain at least one alpha-numeric character."),
                                                                                         _("Thread name is too long. Try shorter name.")
                                                                                         )])
-    
+
     def clean_post(self):
         data = self.cleaned_data['post']
         if len(data) < self.request.settings['post_length_min']:
@@ -71,10 +71,10 @@ class PostForm(Form, ThreadNameMixin):
                                                   self.request.settings['post_length_min']
                                                   ) % {'count': self.request.settings['post_length_min']})
         return data
-        
-        
 
-class SplitThreadForm(Form, ThreadNameMixin):        
+
+
+class SplitThreadForm(Form, ThreadNameMixin):
     def finalize_form(self):
         self.layout = [
                        [
@@ -85,15 +85,15 @@ class SplitThreadForm(Form, ThreadNameMixin):
                          ],
                         ],
                        ]
-    
+
         self.fields['thread_name'] = forms.CharField(
                                                      max_length=self.request.settings['thread_name_max'],
                                                      validators=[validate_sluggable(
                                                                                     _("Thread name must contain at least one alpha-numeric character."),
                                                                                     _("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):
         new_forum = self.cleaned_data['thread_forum']
         # Assert its forum and its not current forum
@@ -102,13 +102,13 @@ class SplitThreadForm(Form, ThreadNameMixin):
         return new_forum
 
 
-class MovePostsForm(Form, ThreadNameMixin):  
+class MovePostsForm(Form, ThreadNameMixin):
     error_source = 'thread_url'
 
     def __init__(self, data=None, request=None, thread=None, *args, **kwargs):
         self.thread = thread
         super(MovePostsForm, self).__init__(data, request=request, *args, **kwargs)
-          
+
     def finalize_form(self):
         self.layout = [
                        [
@@ -118,9 +118,9 @@ class MovePostsForm(Form, ThreadNameMixin):
                          ],
                         ],
                        ]
-    
+
         self.fields['thread_url'] = forms.CharField()
-            
+
     def clean_thread_url(self):
         from django.core.urlresolvers import resolve
         from django.http import Http404
@@ -145,13 +145,13 @@ class QuickReplyForm(Form):
 
 class MoveThreadsForm(Form):
     error_source = 'new_forum'
-    
+
     def __init__(self, data=None, request=None, forum=None, *args, **kwargs):
         self.forum = forum
         super(MoveThreadsForm, self).__init__(data, request=request, *args, **kwargs)
-    
+
     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 = [
                        [
                         _("Thread Options"),
@@ -160,7 +160,7 @@ class MoveThreadsForm(Form):
                          ],
                         ],
                        ]
-            
+
     def clean_new_forum(self):
         new_forum = self.cleaned_data['new_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):
         self.threads = threads
         super(MergeThreadsForm, self).__init__(data, request=request, *args, **kwargs)
-    
+
     def finalize_form(self):
         self.fields['thread_name'] = forms.CharField(
                                                      max_length=self.request.settings['thread_name_max'],
@@ -197,15 +197,15 @@ class MergeThreadsForm(Form, ThreadNameMixin):
                          ],
                         ],
                        ]
-        
+
         choices = []
         for i, thread in enumerate(self.threads):
             choices.append((str(i), i + 1))
         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}))
-            
-    def clean(self):        
+
+    def clean(self):
         cleaned_data = super(MergeThreadsForm, self).clean()
         self.merge_order = {}
         lookback = []
@@ -215,4 +215,4 @@ class MergeThreadsForm(Form, ThreadNameMixin):
                 raise forms.ValidationError(_("One or more threads have same position in merge order."))
             lookback.append(order)
             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)
             self.stdout.write('Thread ranking has been updated.\n')
         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):
     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)
     name = models.CharField(max_length=255)
     slug = models.SlugField(max_length=255)
@@ -18,33 +18,33 @@ class Thread(models.Model):
     replies_reported = models.PositiveIntegerField(default=0)
     replies_moderated = 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)
     downvotes = models.PositiveIntegerField(default=0)
     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_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_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)
-    
+
     objects = ThreadManager()
-    
+
     statistics_name = _('New Threads')
-        
+
     def get_date(self):
         return self.start
-    
+
     def sync(self):
         # Counters
         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.deleted = start_post.deleted
         self.merges = last_post.merge
-    
+
 
 class PostManager(models.Manager):
     def filter_stats(self, start, end):
         return self.filter(date__gte=start).filter(date__lte=end)
-    
+
 
 class Post(models.Model):
     forum = models.ForeignKey('forums.Forum')
     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)
     ip = models.GenericIPAddressField()
     agent = models.CharField(max_length=255)
@@ -99,23 +99,23 @@ class Post(models.Model):
     downvotes = models.PositiveIntegerField(default=0)
     date = models.DateTimeField()
     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)
-    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)
-    
+
     objects = PostManager()
-    
+
     statistics_name = _('New Posts')
-    
+
     def get_date(self):
         return self.date
-    
+
     def set_checkpoint(self, request, action):
         if request.user.is_authenticated():
             self.checkpoint_set.create(
@@ -136,15 +136,15 @@ class Change(models.Model):
     forum = models.ForeignKey('forums.Forum')
     thread = models.ForeignKey(Thread)
     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_slug = models.CharField(max_length=255)
     date = models.DateTimeField()
     ip = models.GenericIPAddressField()
     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()
     size = models.IntegerField(default=0)
     change = models.IntegerField(default=0)
@@ -155,10 +155,9 @@ class Checkpoint(models.Model):
     thread = models.ForeignKey(Thread)
     post = models.ForeignKey(Post)
     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_slug = models.CharField(max_length=255)
     date = models.DateTimeField()
     ip = models.GenericIPAddressField()
     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/(?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"),
-)
+)

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

@@ -6,9 +6,9 @@ class BaseView(object):
     def __new__(cls, request, **kwargs):
         obj = super(BaseView, cls).__new__(cls)
         return obj(request, **kwargs)
-    
+
     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)
         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}) + ('#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.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)
-            
+
     def dispatch(self, request, **kwargs):
         raise NotImplementedError('ChangelogBaseView cannot be called directly. Did you forget to define custom "dispatch" method?')
-    
+
     def __call__(self, request, **kwargs):
         self.request = request
         self.forum = None
@@ -43,7 +43,7 @@ class ChangelogBaseView(BaseView):
         except ACLError404 as e:
             return error404(request, e.message)
         return self.dispatch(request, **kwargs)
-    
+
 
 class ChangelogView(ChangelogBaseView):
     def dispatch(self, request, **kwargs):
@@ -62,7 +62,7 @@ class ChangelogDiffView(ChangelogBaseView):
     def fetch_target(self, kwargs):
         super(ChangelogDiffView, self).fetch_target(kwargs)
         self.change = self.post.change_set.get(pk=kwargs['change'])
-    
+
     def dispatch(self, request, **kwargs):
         try:
             next = self.post.change_set.filter(id__gt=self.change.pk)[:1][0]
@@ -86,7 +86,7 @@ class ChangelogDiffView(ChangelogBaseView):
                                                  'l': 1,
                                                  'diff': difflib.ndiff(self.change.post_content.splitlines(), self.post.post.splitlines()),
                                                  },
-                                                context_instance=RequestContext(request))        
+                                                context_instance=RequestContext(request))
 
 
 class ChangelogRevertView(ChangelogDiffView):
@@ -94,31 +94,30 @@ class ChangelogRevertView(ChangelogDiffView):
         super(ChangelogDiffView, self).fetch_target(kwargs)
         self.change = self.post.change_set.get(pk=kwargs['change'])
         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)
             and (self.change.post_content == self.post.post)):
             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}))
-        
+
         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.slug = slugify(self.change.thread_name_old)
             self.thread.save(force_update=True)
-            
+
             if self.forum.last_thread_id == self.thread.pk:
                 self.forum.last_thread_name = self.change.thread_name_old
                 self.forum.last_thread_slug = slugify(self.change.thread_name_old)
                 self.forum.save(force_update=True)
-            
+
         if self.change.post_content != self.post.post:
             self.post.post = self.change.post_content
             self.post.post_preparsed = post_markdown(request, self.change.post_content)
             self.post.save(force_update=True)
-        
+
         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)
         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}) + ('#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 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."))
-            
+
     def fetch_post(self, kwargs):
         self.post = self.thread.post_set.get(pk=kwargs['post'])
         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)
         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."))
-        
+
     def __call__(self, request, **kwargs):
         self.request = request
         self.mode = kwargs['mode']
@@ -60,14 +60,14 @@ class DeleteView(BaseView):
             return error403(request, e.message)
         except ACLError404 as e:
             return error404(request, e.message)
-        
+
         if self.mode == 'delete_thread':
             self.thread.delete()
             self.forum.sync()
             self.forum.save(force_update=True)
             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}))
-        
+
         if self.mode == 'hide_thread':
             self.thread.start_post.deleted = 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):
                 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}))
-        
+
         if self.mode == 'delete_post':
             self.post.delete()
             self.thread.sync()
@@ -89,7 +89,7 @@ class DeleteView(BaseView):
             self.forum.save(force_update=True)
             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}))
-            
+
         if self.mode == 'hide_post':
             self.post.deleted = True
             self.post.edit_date = timezone.now()
@@ -102,4 +102,4 @@ class DeleteView(BaseView):
             self.forum.sync()
             self.forum.save(force_update=True)
             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.request.acl.forums.allow_forum_view(self.forum)
         self.request.acl.threads.allow_thread_view(self.request.user, self.thread)
-        
+
     def fetch_post(self, post):
         self.post = self.thread.post_set.get(pk=post)
         self.request.acl.threads.allow_post_view(self.request.user, self.thread, 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)
         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}) + ('#post-%s' % post.pk))
-        
+
     def make_jump(self):
         raise NotImplementedError('JumpView cannot be called directly.')
-        
+
     def __call__(self, request, slug=None, thread=None, post=None):
         self.request = request
         try:
@@ -42,7 +42,7 @@ class JumpView(BaseView):
             return error403(request, e.message)
         except ACLError404 as e:
             return error404(request, e.message)
-        
+
 
 class LastReplyView(JumpView):
     def make_jump(self):
@@ -53,7 +53,7 @@ class FindReplyView(JumpView):
     def make_jump(self):
         return self.redirect(self.post)
 
-    
+
 class NewReplyView(JumpView):
     def make_jump(self):
         if not self.request.user.is_authenticated():
@@ -85,4 +85,4 @@ class FirstReportedView(JumpView):
             return self.redirect(
                 self.thread.post_set.get(reported=True))
         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:
             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)
-                
+
     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.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']]
         for thread in self.threads:
             thread.is_read = self.tracker.is_read(thread)
-    
+
     def get_thread_actions(self):
         acl = self.request.acl.threads.get_role(self.forum)
         actions = []
@@ -71,14 +71,14 @@ class ThreadsView(BaseView):
         except KeyError:
             pass
         return actions
-    
+
     def make_form(self):
         self.form = None
         list_choices = self.get_thread_actions();
         if (not self.request.user.is_authenticated()
             or not list_choices):
             return
-        
+
         form_fields = {}
         form_fields['list_action'] = forms.ChoiceField(choices=list_choices)
         list_choices = []
@@ -87,9 +87,9 @@ class ThreadsView(BaseView):
                 list_choices.append((item.pk, None))
         if not list_choices:
             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)
-    
+
     def handle_form(self):
         if self.request.method == 'POST':
             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')
         else:
             self.form = self.form(request=self.request)
-            
+
     def action_accept(self, ids):
         accepted = 0
         users = []
@@ -158,7 +158,7 @@ class ThreadsView(BaseView):
             for user in users:
                 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')
-    
+
     def action_annouce(self, ids):
         acl = self.request.acl.threads.get_role(self.forum)
         annouced = []
@@ -168,7 +168,7 @@ class ThreadsView(BaseView):
         if annouced:
             Thread.objects.filter(id__in=annouced).update(weight=2)
             self.request.messages.set_flash(Message(_('Selected threads have been turned into annoucements.')), 'success', 'threads')
-    
+
     def action_sticky(self, ids):
         sticky = []
         for thread in self.threads:
@@ -177,7 +177,7 @@ class ThreadsView(BaseView):
         if sticky:
             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')
-    
+
     def action_normal(self, ids):
         normalised = []
         for thread in self.threads:
@@ -186,14 +186,14 @@ class ThreadsView(BaseView):
         if normalised:
             Thread.objects.filter(id__in=normalised).update(weight=0)
             self.request.messages.set_flash(Message(_('Selected threads weight has been removed.')), 'success', 'threads')
-    
+
     def action_move(self, ids):
         threads = []
         for thread in self.threads:
             if thread.pk in ids:
                 threads.append(thread)
         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():
                 new_forum = form.cleaned_data['new_forum']
                 for thread in threads:
@@ -210,7 +210,7 @@ class ThreadsView(BaseView):
                 return None
             self.message = Message(form.non_field_errors()[0], 'error')
         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',
                                                      {
                                                       'message': self.message,
@@ -219,8 +219,8 @@ class ThreadsView(BaseView):
                                                       'threads': threads,
                                                       'form': FormLayout(form),
                                                       },
-                                                     context_instance=RequestContext(self.request)); 
-            
+                                                     context_instance=RequestContext(self.request));
+
     def action_merge(self, ids):
         if len(ids) < 2:
             raise ValidationError(_("You have to pick two or more threads to merge."))
@@ -229,7 +229,7 @@ class ThreadsView(BaseView):
             if thread.pk in ids:
                 threads.append(thread)
         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():
                 new_thread = Thread.objects.create(
                                                    forum=self.forum,
@@ -246,7 +246,7 @@ class ThreadsView(BaseView):
                     merged.append(thread.pk)
                     if last_thread and last_thread.last > thread.start:
                         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.checkpoint_set.update(thread=new_thread)
                     last_thread = thread
@@ -259,7 +259,7 @@ class ThreadsView(BaseView):
                 return None
             self.message = Message(form.non_field_errors()[0], 'error')
         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',
                                                      {
                                                       'message': self.message,
@@ -268,8 +268,8 @@ class ThreadsView(BaseView):
                                                       'threads': threads,
                                                       'form': FormLayout(form),
                                                       },
-                                                     context_instance=RequestContext(self.request)); 
-    
+                                                     context_instance=RequestContext(self.request));
+
     def action_open(self, ids):
         opened = []
         for thread in self.threads:
@@ -278,8 +278,8 @@ class ThreadsView(BaseView):
                 thread.last_post.set_checkpoint(self.request, 'opened')
         if opened:
             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):
         closed = []
         for thread in self.threads:
@@ -289,7 +289,7 @@ class ThreadsView(BaseView):
         if closed:
             Thread.objects.filter(id__in=closed).update(closed=True)
             self.request.messages.set_flash(Message(_('Selected threads have been closed.')), 'success', 'threads')
-    
+
     def action_undelete(self, ids):
         undeleted = []
         posts = 0
@@ -307,7 +307,7 @@ class ThreadsView(BaseView):
             self.forum.save(force_update=True)
             Thread.objects.filter(id__in=undeleted).update(deleted=False)
             self.request.messages.set_flash(Message(_('Selected threads have been undeleted.')), 'success', 'threads')
-    
+
     def action_soft(self, ids):
         deleted = []
         posts = 0
@@ -324,8 +324,8 @@ class ThreadsView(BaseView):
             self.forum.sync()
             self.forum.save(force_update=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):
         deleted = []
         posts = 0
@@ -340,7 +340,7 @@ class ThreadsView(BaseView):
             self.forum.sync()
             self.forum.save(force_update=True)
             self.request.messages.set_flash(Message(_('Selected threads have been deleted.')), 'success', 'threads')
-    
+
     def __call__(self, request, slug=None, forum=None, page=0):
         self.request = request
         self.pagination = None
@@ -372,4 +372,4 @@ class ThreadsView(BaseView):
                                                  'threads': self.threads,
                                                  '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)
             if self.mode == 'edit_post':
                 self.fetch_post(kwargs['post'])
-    
+
     def fetch_forum(self, kwargs):
         self.forum = Forum.objects.get(pk=kwargs['forum'], type='forum')
         self.proxy = Forum.objects.parents_aware_forum(self.forum)
         self.request.acl.forums.allow_forum_view(self.forum)
         self.request.acl.threads.allow_new_threads(self.proxy)
         self.parents = Forum.objects.forum_parents(self.forum.pk, True)
-    
+
     def fetch_thread(self, kwargs):
         self.thread = Thread.objects.get(pk=kwargs['thread'])
         self.forum = self.thread.forum
@@ -44,15 +44,15 @@ class PostingView(BaseView):
         if kwargs.get('quote'):
             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)
-    
+
     def fetch_post(self, post):
         self.post = self.thread.post_set.get(pk=post)
         self.request.acl.threads.allow_post_view(self.request.user, self.thread, self.post)
         if self.mode == 'edit_thread':
             self.request.acl.threads.allow_thread_edit(self.request.user, self.proxy, self.thread, self.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):
         initial = {}
         if self.mode == 'edit_thread':
@@ -69,11 +69,11 @@ class PostingView(BaseView):
                 quote_post.append('> %s' % line)
             quote_post.append('\n')
             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):
         self.request = request
         self.forum = None
@@ -94,7 +94,7 @@ class PostingView(BaseView):
             return error403(request, e.message)
         except ACLError404 as e:
             return error404(request, e.message)
-        
+
         message = request.messages.get_message('threads')
         if request.method == 'POST':
             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_post = old_post != form.cleaned_data['post']
                     changed_anything = changed_name or changed_post
-                
+
                 # Some extra initialisation
                 now = timezone.now()
                 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:
                         moderation = True
                     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
                 if self.mode == 'new_thread':
                     thread = Thread.objects.create(
@@ -134,8 +134,8 @@ class PostingView(BaseView):
                     thread = self.thread
                     if self.mode == 'edit_thread':
                         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
                 if self.mode in ['new_thread', 'new_post', 'new_post_quick']:
                     # Use last post instead?
@@ -178,7 +178,7 @@ class PostingView(BaseView):
                     post.edit_user_name = request.user.username
                     post.edit_user_slug = request.user.username_slug
                     post.save(force_update=True)
-                
+
                 # Record this edit in changelog?
                 if self.mode in ['edit_thread', 'edit_post'] and changed_anything:
                     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,
                                                 post_content=old_post,
                                                 )
-                
+
                 # Set thread start post and author data
                 if self.mode == 'new_thread':
                     thread.start_post = post
@@ -207,7 +207,7 @@ class PostingView(BaseView):
                     thread.start_poster_slug = request.user.username_slug
                     if request.user.rank and request.user.rank.style:
                         thread.start_poster_style = request.user.rank.style
-                
+
                 # New post - increase post counters, thread score
                 # Notify quoted post author and close thread if it has hit limit
                 if self.mode in ['new_post', 'new_post_quick']:
@@ -228,7 +228,7 @@ class PostingView(BaseView):
                             and thread.replies >= self.request.settings.thread_length):
                             thread.closed = True
                             post.set_checkpoint(self.request, 'limit')
-                
+
                 # Update last poster data
                 if not moderation and self.mode not in ['edit_thread', 'edit_post']:
                     thread.last = now
@@ -238,23 +238,23 @@ class PostingView(BaseView):
                     thread.last_poster_slug = request.user.username_slug
                     if request.user.rank and request.user.rank.style:
                         thread.last_poster_style = request.user.rank.style
-                        
+
                 # Final update of thread entry
                 if self.mode != 'edit_post':
                     thread.save(force_update=True)
-                
+
                 # Update forum and monitor
                 if not moderation:
                     if self.mode == 'new_thread':
                         self.request.monitor['threads'] = int(self.request.monitor['threads']) + 1
                         self.forum.threads += 1
                         self.forum.threads_delta += 1
-                        
+
                     if self.mode in ['new_thread', 'new_post', 'new_post_quick']:
                         self.request.monitor['posts'] = int(self.request.monitor['posts']) + 1
                         self.forum.posts += 1
                         self.forum.posts_delta += 1
-                        
+
                     self.forum.last_thread = thread
                     self.forum.last_thread_name = thread.name
                     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_style = thread.last_poster_style
                     self.forum.save(force_update=True)
-                
+
                 # Update user
                 if not moderation:
                     if self.mode == 'new_thread':
@@ -273,7 +273,7 @@ class PostingView(BaseView):
                 if self.mode in ['new_thread', 'new_post', 'new_post_quick']:
                     request.user.last_post = thread.last
                     request.user.save(force_update=True)
-                
+
                 # Set flash and redirect user to his post
                 if self.mode == 'new_thread':
                     if moderation:
@@ -281,14 +281,14 @@ class PostingView(BaseView):
                     else:
                         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))
-                
+
                 if self.mode in ['new_post', 'new_post_quick']:
                     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)
                     else:
                         request.messages.set_flash(Message(_("Your reply has been posted.")), 'success', 'threads_%s' % post.pk)
                     return self.redirect_to_post(post)
-                
+
                 if self.mode == 'edit_thread':
                     request.messages.set_flash(Message(_("Your thread has been edited.")), 'success', 'threads_%s' % self.post.pk)
                 if self.mode == 'edit_post':
@@ -298,7 +298,7 @@ class PostingView(BaseView):
             message = Message(form.non_field_errors()[0], 'error')
         else:
             form = self.get_form()
-            
+
         # Merge proxy into forum
         self.forum.closed = self.proxy.closed
         return request.theme.render_to_response('threads/posting.html',
@@ -312,4 +312,4 @@ class PostingView(BaseView):
                                                  'message': message,
                                                  '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.parents = Forum.objects.forum_parents(self.forum.pk, True)
         self.tracker = ThreadsTracker(self.request.user, self.forum)
-    
+
     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.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)
         if self.request.settings.posts_per_page < self.count:
             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:
             post.message = self.request.messages.get_message('threads_%s' % post.pk)
             post.is_read = post.date <= self.read_date
@@ -46,7 +46,7 @@ class ThreadView(BaseView):
         if not self.tracker.is_read(self.thread):
             self.tracker.set_read(self.thread, last_post)
             self.tracker.sync()
-            
+
     def get_post_actions(self):
         acl = self.request.acl.threads.get_role(self.thread.forum_id)
         actions = []
@@ -69,14 +69,14 @@ class ThreadView(BaseView):
         except KeyError:
             pass
         return actions
-    
+
     def make_posts_form(self):
         self.posts_form = None
         list_choices = self.get_post_actions();
         if (not self.request.user.is_authenticated()
             or not list_choices):
             return
-        
+
         form_fields = {}
         form_fields['list_action'] = forms.ChoiceField(choices=list_choices)
         list_choices = []
@@ -84,9 +84,9 @@ class ThreadView(BaseView):
             list_choices.append((item.pk, None))
         if not list_choices:
             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)
-     
+
     def handle_posts_form(self):
         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)
@@ -113,7 +113,7 @@ class ThreadView(BaseView):
                     self.message = Message(posts_form.non_field_errors()[0], 'error')
         else:
             self.posts_form = self.posts_form(request=self.request)
-            
+
     def post_action_accept(self, ids):
         accepted = 0
         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.sync()
             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):
         users = []
         posts = []
@@ -150,14 +150,14 @@ class ThreadView(BaseView):
         self.forum.sync()
         self.forum.save(force_update=True)
         self.request.messages.set_flash(Message(_('Selected posts have been merged into one message.')), 'success', 'threads')
-                    
+
     def post_action_split(self, ids):
         for id in ids:
             if id == self.thread.start_post_id:
                 raise forms.ValidationError(_("You cannot split first post from thread."))
         message = None
         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():
                 new_thread = Thread()
                 new_thread.forum = form.cleaned_data['thread_forum']
@@ -200,11 +200,11 @@ class ThreadView(BaseView):
                                                       'form': FormLayout(form),
                                                       },
                                                      context_instance=RequestContext(self.request));
-    
+
     def post_action_move(self, ids):
         message = None
         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():
                 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)
@@ -237,7 +237,7 @@ class ThreadView(BaseView):
                                                       'form': FormLayout(form),
                                                       },
                                                      context_instance=RequestContext(self.request));
-    
+
     def post_action_undelete(self, ids):
         undeleted = []
         for post in self.posts:
@@ -250,7 +250,7 @@ class ThreadView(BaseView):
             self.forum.sync()
             self.forum.save(force_update=True)
             self.request.messages.set_flash(Message(_('Selected posts have been restored.')), 'success', 'threads')
-    
+
     def post_action_protect(self, ids):
         protected = 0
         for post in self.posts:
@@ -259,7 +259,7 @@ class ThreadView(BaseView):
         if protected:
             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')
-      
+
     def post_action_unprotect(self, ids):
         unprotected = 0
         for post in self.posts:
@@ -268,7 +268,7 @@ class ThreadView(BaseView):
         if unprotected:
             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')
-    
+
     def post_action_soft(self, ids):
         deleted = []
         for post in self.posts:
@@ -283,7 +283,7 @@ class ThreadView(BaseView):
             self.forum.sync()
             self.forum.save(force_update=True)
             self.request.messages.set_flash(Message(_('Selected posts have been deleted.')), 'success', 'threads')
-    
+
     def post_action_hard(self, ids):
         deleted = []
         for post in self.posts:
@@ -302,7 +302,7 @@ class ThreadView(BaseView):
             self.forum.sync()
             self.forum.save(force_update=True)
             self.request.messages.set_flash(Message(_('Selected posts have been deleted.')), 'success', 'threads')
-               
+
     def get_thread_actions(self):
         acl = self.request.acl.threads.get_role(self.thread.forum_id)
         actions = []
@@ -335,16 +335,16 @@ class ThreadView(BaseView):
         except KeyError:
             pass
         return actions
-    
+
     def make_thread_form(self):
         self.thread_form = None
         list_choices = self.get_thread_actions();
         if (not self.request.user.is_authenticated()
             or not list_choices):
-            return      
+            return
         form_fields = {'thread_action': forms.ChoiceField(choices=list_choices)}
         self.thread_form = type('ThreadViewForm', (Form,), form_fields)
-    
+
     def handle_thread_form(self):
         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)
@@ -377,7 +377,7 @@ class ThreadView(BaseView):
         if self.thread.last_post.user:
             self.thread.start_post.user.threads += 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
         self.forum.threads_delta += 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['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')
-    
+
     def thread_action_annouce(self):
         self.thread.weight = 2
         self.thread.save(force_update=True)
         self.request.messages.set_flash(Message(_('Thread has been turned into annoucement.')), 'success', 'threads')
-    
+
     def thread_action_sticky(self):
         self.thread.weight = 1
         self.thread.save(force_update=True)
         self.request.messages.set_flash(Message(_('Thread has been turned into sticky.')), 'success', 'threads')
-    
+
     def thread_action_normal(self):
         self.thread.weight = 0
         self.thread.save(force_update=True)
         self.request.messages.set_flash(Message(_('Thread weight has been changed to normal.')), 'success', 'threads')
-    
+
     def thread_action_move(self):
         message = None
         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():
                 new_forum = form.cleaned_data['new_forum']
                 self.thread.forum = new_forum
@@ -420,7 +420,7 @@ class ThreadView(BaseView):
                 return None
             message = Message(form.non_field_errors()[0], 'error')
         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',
                                                      {
                                                       'message': message,
@@ -430,19 +430,19 @@ class ThreadView(BaseView):
                                                       'form': FormLayout(form),
                                                       },
                                                      context_instance=RequestContext(self.request));
-        
+
     def thread_action_open(self):
         self.thread.closed = False
         self.thread.save(force_update=True)
         self.thread.last_post.set_checkpoint(self.request, 'opened')
         self.request.messages.set_flash(Message(_('Thread has been opened.')), 'success', 'threads')
-        
+
     def thread_action_close(self):
         self.thread.closed = True
         self.thread.save(force_update=True)
         self.thread.last_post.set_checkpoint(self.request, 'closed')
         self.request.messages.set_flash(Message(_('Thread has been closed.')), 'success', 'threads')
-    
+
     def thread_action_undelete(self):
         # Update thread
         self.thread.deleted = False
@@ -460,7 +460,7 @@ class ThreadView(BaseView):
         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.messages.set_flash(Message(_('Thread has been undeleted.')), 'success', 'threads')
-    
+
     def thread_action_soft(self):
         # Update thread
         self.thread.deleted = True
@@ -477,8 +477,8 @@ class ThreadView(BaseView):
         # Update monitor
         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.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):
         # Delete thread
         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.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}))
-    
+
     def __call__(self, request, slug=None, thread=None, page=0):
         self.request = request
         self.pagination = None
@@ -531,4 +531,4 @@ class ThreadView(BaseView):
                                                  '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,
                                                  },
-                                                context_instance=RequestContext(request));
+                                                context_instance=RequestContext(request));

+ 2 - 2
misago/timezones/__init__.py

@@ -83,5 +83,5 @@ def tzlist():
             else:
                 ready_list.append((tz[0], tz[1]))
         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():
     load_settings_fixture(settings_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:
         return error404(request)
     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('',
         url(r'^' + ADMIN_PATH, include(site.discover())),
     )
-    
+
 # Include static and media patterns in DEBUG
 if settings.DEBUG:
     urlpatterns += patterns('django.views.static',
@@ -35,4 +35,4 @@ if settings.DEBUG:
 
 # Set error handlers
 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):
     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((
                             _("User Profile"),
                             (
@@ -24,34 +24,34 @@ def make_form(request, role, form):
                             ))
 
 
-class UserCPACL(BaseACL):        
+class UserCPACL(BaseACL):
     def show_username_change(self):
         return self.acl['name_changes_allowed'] > 0
-    
+
     def changes_expire(self):
         return self.acl['changes_expire'] > 0
-    
+
     def changes_left(self, user):
         if not self.acl['name_changes_allowed']:
             return 0
-        
+
         if self.acl['changes_expire']:
             changes_left = self.acl['name_changes_allowed'] - user.namechanges.filter(
                                                     date__gte=timezone.now() - timedelta(days=self.acl['changes_expire']),
                                                     ).count()
         else:
             changes_left = self.acl['name_changes_allowed'] - user.namechanges.all().count()
-            
+
         if changes_left:
             return changes_left
         return 0
-    
+
     def can_use_signature(self):
         return self.acl['signature']
-    
+
     def allow_signature_links(self):
         return self.acl['signature_links']
-    
+
     def allow_signature_images(self):
         return self.acl['signature_images']
 
@@ -63,19 +63,19 @@ def build(acl, roles):
     acl.usercp.acl['signature'] = False
     acl.usercp.acl['signature_links'] = False
     acl.usercp.acl['signature_images'] = False
-    
+
     for role in roles:
         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']
 
         if 'changes_expire' in role and role['changes_expire'] > acl.usercp.acl['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']:
             acl.usercp.acl['signature'] = role['can_use_signature']
-            
+
         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']
-            
+
         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']

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

@@ -8,7 +8,7 @@ from misago.forms import Form
 class UploadAvatarForm(Form):
     avatar_upload = forms.ImageField(error_messages={'invalid_image': _("Uploaded file is not correct image.")})
     error_source = 'avatar_upload'
-    
+
     layout = [
               [
                None,
@@ -17,9 +17,9 @@ class UploadAvatarForm(Form):
                 ],
                ],
               ]
-    
+
     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._size > 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})
         else:
             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/crop/$', 'crop', name="usercp_avatar_crop"),
     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 _
 
 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):
     if not 'gallery' in request.settings.avatars_types:
         return error404(request)
-    
+
     allowed_avatars = []
     galleries = []
     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:]))
             galleries.append(gallery)
             allowed_avatars += gallery['avatars']
-    
+
     if not allowed_avatars:
         request.messages.set_flash(Message(_("No avatars are avaiable.")), 'info', 'usercp_avatar')
         return redirect(reverse('usercp_avatar'))
-    
+
     message = request.messages.get_message('usercp_avatar')
     if request.method == 'POST':
         if request.csrf.request_secure(request):
@@ -91,7 +91,7 @@ def gallery(request):
             message = Message(_("Selected Avatar is incorrect."), 'error')
         else:
             message = Message(_("Request authorisation is invalid."), 'error')
-    
+
     return request.theme.render_to_response('usercp/avatar_gallery.html',
                                             context_instance=RequestContext(request, {
                                               'message': message,
@@ -151,12 +151,12 @@ def upload(request):
             except ValidationError:
                 request.user.delete_avatar()
                 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:
-            message = Message(form.non_field_errors()[0], 'error')          
+            message = Message(form.non_field_errors()[0], 'error')
     else:
         form = UploadAvatarForm(request=request)
-        
+
     return request.theme.render_to_response('usercp/avatar_upload.html',
                                             context_instance=RequestContext(request, {
                                               'message': message,
@@ -170,11 +170,11 @@ def upload(request):
 def crop(request, upload=False):
     if upload and (not request.user.avatar_temp or not 'upload' in request.settings.avatars_types):
         return error404(request)
-    
+
     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')
         return redirect(reverse('usercp_avatar'))
-    
+
     message = request.messages.get_message('usercp_avatar')
     if request.method == 'POST':
         if request.csrf.request_secure(request):
@@ -185,13 +185,13 @@ def crop(request, upload=False):
                 else:
                     source = Image.open(image_path + request.user.avatar_original)
                 width, height = source.size
-                
+
                 aspect = float(width) / float(request.POST['crop_b'])
                 crop_x = int(aspect * float(request.POST['crop_x']))
                 crop_y = int(aspect * float(request.POST['crop_y']))
                 crop_w = int(aspect * float(request.POST['crop_w']))
                 crop = source.crop((crop_x, crop_y, crop_x + crop_w, crop_y + crop_w))
-                           
+
                 if upload:
                     image_name, image_extension = path(request.user.avatar_temp).splitext()
                 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)
                 for size in settings.AVATAR_SIZES[1:]:
                     resizeimage(crop, size, image_path + str(size) + '_' + image_name, info=source.info, format=source.format)
-                
+
                 request.user.delete_avatar_image()
                 if upload:
                     request.user.delete_avatar_original()
@@ -216,8 +216,8 @@ def crop(request, upload=False):
                 message = Message(_("Form contains errors."), 'error')
         else:
             message = Message(_("Request authorisation is invalid."), 'error')
-    
-    
+
+
     return request.theme.render_to_response('usercp/avatar_crop.html',
                                             context_instance=RequestContext(request, {
                                               'message': message,
@@ -225,4 +225,4 @@ def crop(request, upload=False):
                                               'avatar_size': settings.AVATAR_SIZES[0],
                                               'source': 'avatars/%s' % (request.user.avatar_temp if upload else request.user.avatar_original),
                                               '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',
     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 _
 
 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',
                                             context_instance=RequestContext(request, {
                                               '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
 
 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 = [
               (
                None,
@@ -21,7 +21,7 @@ class CredentialsChangeForm(Form):
                 ]
                ),
               ]
-        
+
     def clean_new_email(self):
         if self.cleaned_data['new_email']:
             new_hash = hashlib.md5(self.cleaned_data['new_email'].lower()).hexdigest()
@@ -34,19 +34,19 @@ class CredentialsChangeForm(Form):
                 pass
             validate_email(self.cleaned_data['new_email'])
         return self.cleaned_data['new_email'].lower()
-        
+
     def clean_new_password(self):
         if self.cleaned_data['new_password']:
             validate_password(self.cleaned_data['new_password'])
         return self.cleaned_data['new_password']
-        
+
     def clean_current_password(self):
         if not self.request.user.check_password(self.cleaned_data['current_password']):
             raise ValidationError(_("You have entered wrong password."))
         return ''
-        
+
     def clean(self):
         cleaned_data = super(CredentialsChangeForm, self).clean()
         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."))
-        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',
     url(r'^credentials/$', 'credentials', name="usercp_credentials"),
     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 _
 
 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')
     else:
         form = CredentialsChangeForm(request=request)
-        
+
     return request.theme.render_to_response('usercp/credentials.html',
                                             context_instance=RequestContext(request, {
                                               'message': message,
@@ -52,12 +52,12 @@ def activate(request, token):
     new_credentials = request.session.get('new_credentials')
     if not new_credentials or new_credentials['token'] != token:
         return error404(request)
-    
+
     if new_credentials['new_email']:
         request.user.set_email(new_credentials['new_email'])
     if new_credentials['new_password']:
         request.user.set_password(new_credentials['new_password'])
-        
+
     try:
         request.user.full_clean()
         request.user.save(force_update=True)
@@ -70,4 +70,3 @@ def activate(request, token):
     except ValidationError:
         request.messages.set_flash(Message(_("Your new credentials have been invalidated. Please try again.")), 'error', 'usercp_credentials')
         return redirect(reverse('usercp_credentials'))
-    

+ 3 - 3
misago/usercp/fixtures.py

@@ -41,7 +41,7 @@ settings_fixtures = (
 
 def load_fixtures():
     load_settings_fixture(settings_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):
     user = models.ForeignKey('users.User', related_name='namechanges')
     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")),
                                                (2, _("Show my presence to nobody")),
                                                ))
-    
+
     layout = (
               (
                _("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")}),
                 )
                ),
-              )
+              )

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

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

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

@@ -1,4 +1,4 @@
 from django.utils.translation import ugettext_lazy as _
 
 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
 
 
-@block_guest   
+@block_guest
 def options(request):
     message = request.messages.get_message('usercp_options')
     if request.method == 'POST':
@@ -22,15 +22,15 @@ def options(request):
             return redirect(reverse('usercp'))
         message = Message(form.non_field_errors()[0], 'error')
     else:
-        form = UserForumOptionsForm(request=request,initial={
+        form = UserForumOptionsForm(request=request, initial={
                                                              'newsletters': request.user.receive_newsletters,
                                                              'hide_activity': request.user.hide_activity,
                                                              'timezone': request.user.timezone,
                                                              })
-    
+
     return request.theme.render_to_response('usercp/options.html',
                                             context_instance=RequestContext(request, {
                                               'message': message,
                                               'tab': 'usercp',
                                               'form': FormLayout(form)
-                                             }));
+                                             }));

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

@@ -4,8 +4,8 @@ from misago.forms import Form
 
 
 class SignatureForm(Form):
-    signature = forms.CharField(widget=forms.Textarea,required=False)
-    
+    signature = forms.CharField(widget=forms.Textarea, required=False)
+
     layout = (
               (
                None,
@@ -13,4 +13,4 @@ class SignatureForm(Form):
                 ('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',
     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 _
 
 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, {
                                                   'tab': 'signature',
                                                  }));
-    
+
     siggy_text = ''
     message = request.messages.get_message('usercp_signature')
     if request.method == 'POST':
@@ -36,10 +36,10 @@ def signature(request):
             message = Message(form.non_field_errors()[0], 'error')
     else:
         form = SignatureForm(request=request, initial={'signature': request.user.signature})
-        
+
     return request.theme.render_to_response('usercp/signature.html',
                                             context_instance=RequestContext(request, {
                                               'message': message,
                                               'tab': 'signature',
                                               'form': FormLayout(form),
-                                             }));
+                                             }));

+ 2 - 3
misago/usercp/template.py

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

+ 1 - 1
misago/usercp/urls.py

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

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

@@ -6,7 +6,7 @@ from misago.forms import Form
 class UsernameChangeForm(Form):
     username = forms.CharField(max_length=255)
     error_source = 'username'
-    
+
     layout = [
               [
                None,
@@ -15,16 +15,16 @@ class UsernameChangeForm(Form):
                 ],
                ],
               ]
-    
+
     def clean_username(self):
         org_username = self.request.user.username
-        
+
         self.request.user.set_username(self.cleaned_data['username'])
         if org_username == self.request.user.username:
             raise ValidationError(_("Your new username is same as current one."))
-        
+
         try:
             self.request.user.full_clean()
         except ValidationError as 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',
     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):
     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):
     if not request.acl.usercp.show_username_change():
         return error404(request)
-    
+
     changes_left = request.acl.usercp.changes_left(request.user)
-    
+
     next_change = None
     if request.acl.usercp.changes_expire() and not changes_left:
         next_change = request.user.namechanges.filter(
                                                       date__gte=timezone.now() - timedelta(days=request.acl.usercp.acl['changes_expire']),
                                                       ).order_by('-date')[0]
         next_change = next_change.date + timedelta(days=request.acl.usercp.acl['changes_expire'])
-    
+
     message = request.messages.get_message('usercp_username')
     if request.method == 'POST':
         org_username = request.user.username
@@ -32,14 +32,14 @@ def username(request):
         if form.is_valid():
             request.user.set_username(form.cleaned_data['username'])
             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')
             return redirect(reverse('usercp_username'))
         message = Message(form.non_field_errors()[0], 'error')
     else:
         form = UsernameChangeForm(request=request)
-    
+
     return request.theme.render_to_response('usercp/username.html',
                                             context_instance=RequestContext(request, {
                                               'message': message,
@@ -48,4 +48,4 @@ def username(request):
                                               'next_change': next_change,
                                               'changes_history': request.user.namechanges.order_by('-date')[:10],
                                               'tab': 'username',
-                                             }));
+                                             }));

+ 1 - 1
misago/users/context_processors.py

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

+ 1 - 1
misago/users/fixtures.py

@@ -11,4 +11,4 @@ monitor_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):
     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
     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):
         self.request = kwargs['request']
         self.user = user
         super(UserForm, self).__init__(*args, **kwargs)
-    
+
     def finalize_form(self):
         self.layout = [
                        [
@@ -67,19 +67,19 @@ class UserForm(Form):
                          ],
                         ],
                        ]
-        
+
         # Roles list
         if self.request.user.is_god():
-            self.fields['roles'] = forms.ModelMultipleChoiceField(widget=forms.CheckboxSelectMultiple,queryset=Role.objects.order_by('name').all(),error_messages={'required': _("User must have at least one role assigned.")})
+            self.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:
-            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
         if self.user.is_protected() and not self.request.user.is_god() and self.user.pk != self.request.user.pk:
             del self.fields['email']
             del self.fields['new_password']
             del self.layout[1]
-    
+
     def clean_username(self):
         self.user.set_username(self.cleaned_data['username'])
         try:
@@ -87,7 +87,7 @@ class UserForm(Form):
         except ValidationError as e:
             self.user.is_username_valid(e)
         return self.cleaned_data['username']
-        
+
     def clean_email(self):
         self.user.set_email(self.cleaned_data['email'])
         try:
@@ -95,7 +95,7 @@ class UserForm(Form):
         except ValidationError as e:
             self.user.is_email_valid(e)
         return self.cleaned_data['email']
-        
+
     def clean_new_password(self):
         if 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']))
             except IOError:
                 raise ValidationError(_("Avatar does not exist or is not image file."))
-            return self.cleaned_data['avatar_custom']            
+            return self.cleaned_data['avatar_custom']
         return ''
 
 
 class NewUserForm(Form):
     username = forms.CharField(max_length=255)
-    title = forms.CharField(max_length=255,required=False)
-    rank = forms.ModelChoiceField(queryset=Rank.objects.order_by('order').all(),required=False,empty_label=_('No rank assigned'))
+    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
     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 = [
               [
                _("Basic Account Settings"),
@@ -143,18 +143,18 @@ class NewUserForm(Form):
                 ],
                ],
               ]
-        
+
     def __init__(self, *args, **kwargs):
         self.request = kwargs['request']
-        
+
         # Roles list
         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:
-            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)
-        
+
     def clean_username(self):
         new_user = User.objects.get_blank_user()
         new_user.set_username(self.cleaned_data['username'])
@@ -163,7 +163,7 @@ class NewUserForm(Form):
         except ValidationError as e:
             new_user.is_username_valid(e)
         return self.cleaned_data['username']
-        
+
     def clean_email(self):
         new_user = User.objects.get_blank_user()
         new_user.set_email(self.cleaned_data['email'])
@@ -172,7 +172,7 @@ class NewUserForm(Form):
         except ValidationError as e:
             new_user.is_email_valid(e)
         return self.cleaned_data['email']
-        
+
     def clean_password(self):
         new_user = User.objects.get_blank_user()
         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)
     rank = forms.ModelMultipleChoiceField(widget=forms.CheckboxSelectMultiple, queryset=Rank.objects.order_by('order').all(), required=False)
     role = forms.ModelMultipleChoiceField(widget=forms.CheckboxSelectMultiple, queryset=Role.objects.order_by('name').all(), required=False)
-    
+
     layout = (
               (
                _("Search Users"),
@@ -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):
         if len(args) < 3:
             raise CommandError('adduser requires exactly three arguments: user name, e-mail addres and password')
-                
+
         # Set user
         try:
             new_user = User.objects.create_user(args[0], args[1], args[2])
         except ValidationError as e:
             raise CommandError("New user cannot be created because of following errors:\n\n%s" % '\n'.join(e.messages))
-                
+
         # Set admin role
         if options['admin']:
             new_user.roles.add(Role.objects.get(token='admin'))
             new_user.make_acl_key(True)
             new_user.save(force_update=True)
-        
+
         if options['admin']:
             self.stdout.write('Successfully created new administrator "%s"' % args[0])
         else:
             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
 from misago.users.models import User
 from misago.utils.avatars import resizeimage
-    
+
 class Command(BaseCommand):
     help = 'Regenerates avatar images for new dimensions'
     def handle(self, *args, **options):
@@ -17,21 +17,21 @@ class Command(BaseCommand):
         self.scale_user_avatars()
         self.scale_gallery_avatars()
         self.stdout.write('\n\nAvatar images have been regenerated.\n')
-        
+
     def scale_image(self, image_src, image_dir=None):
         image_name = path.basename(path(image_src))
         if not image_dir:
             image_dir = path.dirname(path(image_src)) + '/%s_'
         for size in settings.AVATAR_SIZES[1:]:
             resizeimage(image_src, size, image_dir % size + image_name)
-    
+
     def scale_user_avatars(self):
         for user in User.objects.filter(avatar_type='upload').iterator():
             for image in path(settings.MEDIA_ROOT).joinpath('avatars').files('*_%s' % user.avatar_image):
                 if not image.isdir():
                     image.remove()
             self.scale_image(settings.MEDIA_ROOT + 'avatars/' + user.avatar_image)
-    
+
     def scale_gallery_avatars(self):
         try:
             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)
         for avatar in avatars_list:
             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):
         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
             request.session.rank = request.user.rank_id
             set_timezone(request.user.timezone)
-            
+
             # Display "welcome back!" message
             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')
         else:
             # Set guest's timezone and empty rank
             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'
                         )
         return blank_user
-    
+
     def resync_monitor(self, monitor):
         monitor['users'] = self.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_name'] = last_user.username
         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):
         token = ''
         if activation > 0:
             token = get_random_string(12)
-        
+
         try:
             db_settings = request.settings
         except AttributeError:
             db_settings = DBSettings()
-            
+
         if timezone == False:
             timezone = db_settings['default_timezone']
-        
+
         # Get first rank
         try:
             from misago.ranks.models import Rank
             default_rank = Rank.objects.filter(special=0).order_by('order')[0]
         except IndexError:
             default_rank = None
-        
+
         # Store user in database
         new_user = User(
                         last_sync=tz_util.now(),
@@ -69,27 +69,27 @@ class UserManager(models.Manager):
                         timezone=timezone,
                         rank=default_rank,
                         )
-        
+
         new_user.set_username(username)
         new_user.set_email(email)
         new_user.set_password(password)
         new_user.full_clean()
         new_user.default_avatar(db_settings)
         new_user.save(force_insert=True)
-        
+
         # Set user roles?
         if not no_roles:
             from misago.roles.models import Role
             new_user.roles.add(Role.objects.get(token='registered'))
             new_user.make_acl_key()
             new_user.save(force_update=True)
-        
+
         # Load monitor
         try:
             monitor = request.monitor
         except AttributeError:
             monitor = Monitor()
-        
+
         # Update forum stats
         if activation == 0:
             monitor['users'] = int(monitor['users']) + 1
@@ -98,41 +98,41 @@ class UserManager(models.Manager):
             monitor['last_user_slug'] = new_user.username_slug
         else:
             monitor['users_inactive'] = int(monitor['users_inactive']) + 1
-            
+
         # Return new user
         return new_user
-            
+
     def get_by_email(self, email):
         return self.get(email_hash=hashlib.md5(email).hexdigest())
-    
+
     def filter_stats(self, start, end):
         return self.filter(join_date__gte=start).filter(join_date__lte=end)
-    
-        
+
+
 class User(models.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.")})
-    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.")})
     password = models.CharField(max_length=255)
     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_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)
     alert_ats = models.PositiveIntegerField(default=0)
     allow_pms = models.PositiveIntegerField(default=0)
@@ -146,38 +146,38 @@ class User(models.Model):
     karma_n = models.PositiveIntegerField(default=0)
     following = 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_date = models.DateTimeField(null=True,blank=True)
+    alerts_date = models.DateTimeField(null=True, blank=True)
     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_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_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')
-    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_USER = 1
     ACTIVATION_ADMIN = 2
     ACTIVATION_CREDENTIALS = 3
-    
+
     statistics_name = _('Users Registrations')
-        
+
     def is_god(self):
         try:
             return self.is_god_cache
@@ -188,13 +188,13 @@ class User(models.Model):
                     return True
             self.is_god_cache = False
             return False
-            
+
     def is_anonymous(self):
         return False
-    
+
     def is_authenticated(self):
         return True
-    
+
     def is_crawler(self):
         return False
 
@@ -203,12 +203,12 @@ class User(models.Model):
             if role.protected:
                 return True
         return False
-    
+
     def lock_avatar(self):
         # Kill existing avatar and lock our ability to change it
         self.delete_avatar()
         self.avatar_ban = True
-        
+
         # Pick new one from _locked gallery
         galleries = path(settings.STATICFILES_DIRS[0]).joinpath('avatars').joinpath('_locked')
         avatars_list = galleries.files('*.gif')
@@ -217,7 +217,7 @@ class User(models.Model):
         avatars_list += galleries.files('*.png')
         self.avatar_type = 'gallery'
         self.avatar_image = '/'.join(path(choice(avatars_list)).splitall()[-2:])
-        
+
     def default_avatar(self, db_settings):
         if db_settings['default_avatar'] == 'gallery':
             try:
@@ -247,7 +247,7 @@ class User(models.Model):
                     return True
             except Exception as e:
                 pass
-            
+
         self.avatar_type = 'gravatar'
         self.avatar_image = None
         return True
@@ -260,7 +260,7 @@ class User(models.Model):
                     av_file.remove()
             except Exception:
                 pass
-            
+
         self.avatar_temp = None
 
     def delete_avatar_original(self):
@@ -271,7 +271,7 @@ class User(models.Model):
                     av_file.remove()
             except Exception:
                 pass
-        
+
         self.avatar_original = None
 
     def delete_avatar_image(self):
@@ -289,14 +289,14 @@ class User(models.Model):
                     av_file.remove()
             except Exception:
                 pass
-        
+
         self.avatar_image = None
 
     def delete_avatar(self):
         self.delete_avatar_temp()
         self.delete_avatar_original()
         self.delete_avatar_image()
-            
+
     def delete_content(self):
         if self.pk:
             for model_obj in models.get_models():
@@ -304,22 +304,22 @@ class User(models.Model):
                     model_obj.objects.delete_user_content(self)
                 except AttributeError:
                     pass
-    
+
     def delete(self, *args, **kwargs):
         self.delete_avatar()
         super(User, self).delete(*args, **kwargs)
-            
+
     def set_username(self, username):
         self.username = username.strip()
         self.username_slug = slugify(username)
-        
+
         if self.pk:
             for model_obj in models.get_models():
                 try:
                     model_obj.objects.update_username(self)
                 except AttributeError:
                     pass
-    
+
     def is_username_valid(self, e):
         try:
             raise ValidationError(e.message_dict['username'])
@@ -329,7 +329,7 @@ class User(models.Model):
             raise ValidationError(e.message_dict['username_slug'])
         except KeyError:
             pass
-        
+
     def is_email_valid(self, e):
         try:
             raise ValidationError(e.message_dict['email'])
@@ -339,17 +339,17 @@ class User(models.Model):
             raise ValidationError(e.message_dict['email_hash'])
         except KeyError:
             pass
-        
+
     def is_password_valid(self, e):
         try:
             raise ValidationError(e.message_dict['password'])
         except KeyError:
             pass
-        
+
     def set_email(self, email):
         self.email = email.strip().lower()
         self.email_hash = hashlib.md5(self.email).hexdigest()
-        
+
     def set_password(self, raw_password):
         self.password_date = tz_util.now()
         self.password = make_password(raw_password.strip())
@@ -368,11 +368,11 @@ class User(models.Model):
         def setter(raw_password):
             self.set_password(raw_password)
             self.save()
-            
+
         # Is standard password allright?
         if check_password(raw_password, self.password, setter):
             return True
-        
+
         # Check mobile password?
         if mobile:
             raw_password = raw_password[:1].lower() + raw_password[1:]
@@ -382,13 +382,13 @@ class User(models.Model):
                 r = c.upper()
                 if r == c:
                     r = c.lower()
-                password_reversed += r 
+                password_reversed += r
             raw_password = password_reversed
         return check_password(raw_password, self.password, setter)
-    
+
     def get_roles(self):
         return self.roles.all()
-        
+
     def make_acl_key(self, force=False):
         if not force and self.acl_key:
             return self.acl_key
@@ -397,7 +397,7 @@ class User(models.Model):
             roles_ids.append(str(role.pk))
         self.acl_key = 'acl_%s' % hashlib.md5('_'.join(roles_ids)).hexdigest()[0:8]
         return self.acl_key
-    
+
     def get_acl(self, request):
         try:
             acl = cache.get(self.acl_key)
@@ -408,66 +408,66 @@ class User(models.Model):
             acl = build_acl(request, self.get_roles())
             cache.set(self.acl_key, acl, 2592000)
         return acl
-            
+
     def get_avatar(self, size=None):
         image_size = avatar_size(size) if size else None
-                
+
         # Get uploaded avatar
         if self.avatar_type == 'upload':
             image_prefix = '%s_' % image_size if image_size else ''
             return settings.MEDIA_URL + 'avatars/' + image_prefix + self.avatar_image
-        
+
         # Get gallery avatar
         if self.avatar_type == 'gallery':
             image_prefix = '_thumbs/%s/' % image_size if image_size else ''
             return settings.STATIC_URL + 'avatars/' + image_prefix + self.avatar_image
-        
+
         # No avatar found, get gravatar
         if not image_size:
             image_size = settings.AVATAR_SIZES[0]
         return 'http://www.gravatar.com/avatar/%s?s=%s' % (hashlib.md5(self.email).hexdigest(), image_size)
-    
+
     def get_title(self):
         if self.title:
             return self.title
         if self.rank:
             return self.rank.title
         return None
-    
+
     def get_style(self):
         if self.rank:
             return self.rank.style
         return ''
-    
+
     def email_user(self, request, template, subject, context={}):
         templates = request.theme.get_email_templates(template)
         context = RequestContext(request, context)
         context['author'] = context['user']
         context['user'] = self
-        
+
         # Set message recipient
         if settings.DEBUG and settings.CATCH_ALL_EMAIL_ADDRESS:
             recipient = settings.CATCH_ALL_EMAIL_ADDRESS
         else:
             recipient = self.email
-            
+
         # Build and send message
         email = EmailMultiAlternatives(subject, templates[0].render(context), settings.EMAIL_HOST_USER, [recipient])
         email.attach_alternative(templates[1].render(context), "text/html")
         email.send()
-    
+
     def get_activation(self):
         activations = ['none', 'user', 'admin', 'credentials']
         return activations[self.activation]
-    
+
     def alert(self, message):
         from misago.alerts.models import Alert
         self.alerts += 1
         return Alert(user=self, message=message, date=tz_util.now())
-    
+
     def get_date(self):
         return self.join_date
-    
+
     def sync_user(self):
         pass
 
@@ -475,42 +475,42 @@ class User(models.Model):
 class Guest(object):
     """
     Misago Guest dummy
-    """    
+    """
     id = -1
     pk = -1
     is_team = False
-    
+
     def is_anonymous(self):
         return True
-    
+
     def is_authenticated(self):
         return False
-    
+
     def is_crawler(self):
         return False
-        
+
     def get_roles(self):
         return Role.objects.filter(token='guest')
-    
+
     def make_acl_key(self):
         return 'acl_guest'
 
-        
-class Crawler(Guest): 
+
+class Crawler(Guest):
     """
     Misago Crawler dummy
     """
     is_team = False
-    
+
     def __init__(self, username):
         self.username = username
-    
+
     def is_anonymous(self):
         return True
-    
+
     def is_authenticated(self):
         return False
-    
+
     def is_crawler(self):
         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."))
     if check_ban(username=value):
         raise ValidationError(_("This username is forbidden."))
-        
+
 
 def validate_password(value):
     value = unicode(value).strip()
@@ -45,4 +45,4 @@ def validate_password(value):
 def validate_email(value):
     value = unicode(value).strip()
     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):
     admin = site.get_action('users')
     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'
-    sortables={
-               'username_slug': 1,
-               'join_date': 0,
-              }
+    sortables = {
+                 'username_slug': 1,
+                 'join_date': 0,
+                }
     pagination = 25
     search_form = SearchUsersForm
     nothing_checked_message = _('You have to check at least one user.')
-    actions=(
-             ('activate', _("Activate users"), _("Are you sure you want to activate selected members?")),
-             ('deactivate', _("Request e-mail validation"), _("Are you sure you want to deactivate selected members and request them to revalidate their e-mail addresses?")),
-             ('remove_av', _("Remove and lock avatars"), _("Are you sure you want to remove selected members avatars and their ability to change them?")),
-             ('remove_sig', _("Remove and lock signatures"), _("Are you sure you want to remove selected members signatures and their ability to edit them?")),
-             ('remove_locks', _("Remove locks from avatars and signatures"), _("Are you sure you want to remove locks from selected members avatars and signatures?")),
-             ('reset', _("Reset passwords"), _("Are you sure you want to reset selected members passwords?")),
-             ('delete', _("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):
         if 'role' in filters:
             model = model.filter(roles__in=filters['role']).distinct()
@@ -77,16 +77,16 @@ class List(ListWidget):
         if 'activation' in filters:
             model = model.filter(activation__in=filters['activation'])
         return model
-    
+
     def prefetch_related(self, items):
         return items.prefetch_related('roles')
-    
+
     def get_item_actions(self, item):
         return (
                 self.action('pencil', _("Edit User Details"), reverse('admin_users_edit', item)),
                 self.action('remove', _("Delete User"), reverse('admin_users_delete', item), post=True, prompt=_("Are you sure you want to delete this user account?")),
                 )
-    
+
     def action_activate(self, items, checked):
         for user in items:
             if unicode(user.pk) in checked and user.activation > 0:
@@ -98,16 +98,16 @@ class List(ListWidget):
                                 'users/activation/admin_done',
                                 _("Your Account has been activated"),
                                 )
-                
+
         return Message(_('Selected users accounts have been activated.'), 'success'), reverse('admin_users')
-    
+
     def action_deactivate(self, items, checked):
         # First loop - check for errors
         for user in items:
             if unicode(user.pk) in checked:
                 if user.is_protected() and not self.request.user.is_god():
                     return Message(_('You cannot force validation of protected members e-mails.'), 'error'), reverse('admin_users')
-                
+
         # Second loop - reset passwords
         for user in items:
             if unicode(user.pk) in checked:
@@ -119,7 +119,7 @@ class List(ListWidget):
                                 'users/activation/invalidated',
                                 _("Account Activation"),
                                 )
-                
+
         return Message(_('Selected users accounts have been deactivated and new activation links have been sent to them.'), 'success'), reverse('admin_users')
 
     def action_remove_av(self, items, checked):
@@ -128,13 +128,13 @@ class List(ListWidget):
             if unicode(user.pk) in checked:
                 if user.is_protected() and not self.request.user.is_god():
                     return Message(_('You cannot remove and block protected members avatars.'), 'error'), reverse('admin_users')
-                
+
         # Second loop - reset passwords
         for user in items:
             if unicode(user.pk) in checked:
                 user.lock_avatar()
                 user.save(force_update=True)
-                
+
         return Message(_('Selected users avatars were deleted and locked.'), 'success'), reverse('admin_users')
 
     def action_remove_sig(self, items, checked):
@@ -143,7 +143,7 @@ class List(ListWidget):
             if unicode(user.pk) in checked:
                 if user.is_protected() and not self.request.user.is_god():
                     return Message(_('You cannot remove and block protected members signatures.'), 'error'), reverse('admin_users')
-                
+
         # Second loop - reset passwords
         for user in items:
             if unicode(user.pk) in checked:
@@ -151,9 +151,9 @@ class List(ListWidget):
                 user.signature = ''
                 user.signature_preparsed = ''
                 user.save(force_update=True)
-                
+
         return Message(_('Selected users signatures were deleted and locked.'), 'success'), reverse('admin_users')
-   
+
     def action_remove_locks(self, items, checked):
         for user in items:
             if unicode(user.pk) in checked:
@@ -161,16 +161,16 @@ class List(ListWidget):
                 user.avatar_ban = False
                 user.signature_ban = False
                 user.save(force_update=True)
-                
+
         return Message(_('Selected users can now edit their avatars and signatures.'), 'success'), reverse('admin_users')
-    
+
     def action_reset(self, items, checked):
         # First loop - check for errors
         for user in items:
             if unicode(user.pk) in checked:
                 if user.is_protected() and not self.request.user.is_god():
                     return Message(_('You cannot reset protected members passwords.'), 'error'), reverse('admin_users')
-                
+
         # Second loop - reset passwords
         for user in items:
             if unicode(user.pk) in checked:
@@ -185,7 +185,7 @@ class List(ListWidget):
                                  'password': new_password,
                                  },
                                 )
-                
+
         return Message(_('Selected users passwords have been reset successfully.'), 'success'), reverse('admin_users')
 
     def action_delete(self, items, checked):
@@ -195,28 +195,28 @@ class List(ListWidget):
                     return Message(_('You cannot delete yourself.'), 'error'), reverse('admin_users')
                 if user.is_protected():
                     return Message(_('You cannot delete protected members.'), 'error'), reverse('admin_users')
-        
+
         for user in items:
             if unicode(user.pk) in checked:
                 user.delete()
-                
+
         User.objects.resync_monitor(self.request.monitor)
         return Message(_('Selected users have been deleted successfully.'), 'success'), reverse('admin_users')
-    
+
 
 class New(FormWidget):
     admin = site.get_action('users')
     id = 'new'
-    fallback = 'admin_users' 
+    fallback = 'admin_users'
     form = NewUserForm
     submit_button = _("Save User")
-        
+
     def get_new_url(self, model):
         return reverse('admin_users_new')
-    
+
     def get_edit_url(self, model):
         return reverse('admin_users_edit', model)
-    
+
     def submit_form(self, form, target):
         new_user = User.objects.create_user(
                                             form.cleaned_data['username'],
@@ -229,15 +229,15 @@ class New(FormWidget):
                                             )
         new_user.title = form.cleaned_data['title']
         new_user.rank = form.cleaned_data['rank']
-        
+
         for role in form.cleaned_data['roles']:
             new_user.roles.add(role)
         new_user.make_acl_key(True)
         new_user.save(force_update=True)
-        
+
         return new_user, Message(_('New User has been created.'), 'success')
-    
-    
+
+
 class Edit(FormWidget):
     admin = site.get_action('users')
     id = 'edit'
@@ -248,18 +248,18 @@ class Edit(FormWidget):
     target_name = 'username'
     notfound_message = _('Requested User could not be found.')
     submit_fallback = True
-    
+
     def get_form_instance(self, form, model, initial, post=False):
         if post:
             return form(model, self.request.POST, request=self.request, initial=self.get_initial_data(model))
         return form(model, request=self.request, initial=self.get_initial_data(model))
-        
+
     def get_url(self, model):
         return reverse('admin_users_edit', model)
-    
+
     def get_edit_url(self, model):
         return self.get_url(model)
-    
+
     def get_initial_data(self, model):
         return {
                 'username': model.username,
@@ -275,7 +275,7 @@ class Edit(FormWidget):
                 'signature_ban_reason_user': model.signature_ban_reason_user,
                 'signature_ban_reason_admin': model.signature_ban_reason_admin,
                 }
-    
+
     def submit_form(self, form, target):
         target.title = form.cleaned_data['title']
         target.rank = form.cleaned_data['rank']
@@ -284,7 +284,7 @@ class Edit(FormWidget):
         target.signature_ban = form.cleaned_data['signature_ban']
         target.signature_ban_reason_user = form.cleaned_data['signature_ban_reason_user']
         target.signature_ban_reason_admin = form.cleaned_data['signature_ban_reason_admin']
-        
+
         # Do signature mumbo-jumbo
         if form.cleaned_data['signature']:
             target.signature = form.cleaned_data['signature']
@@ -293,7 +293,7 @@ class Edit(FormWidget):
         else:
             target.signature = None
             target.signature_preparsed = None
-        
+
         # Do avatar ban mumbo-jumbo
         if target.avatar_ban != form.cleaned_data['avatar_ban']:
             if form.cleaned_data['avatar_ban']:
@@ -301,13 +301,13 @@ class Edit(FormWidget):
             else:
                 target.default_avatar(self.request.settings)
         target.avatar_ban = form.cleaned_data['avatar_ban']
-               
+
         # Set custom avatar
         if form.cleaned_data['avatar_custom']:
             target.delete_avatar()
             target.avatar_image = form.cleaned_data['avatar_custom']
             target.avatar_type = 'gallery'
-        
+
         # Update user roles
         if self.request.user.is_god():
             target.roles.clear()
@@ -319,7 +319,7 @@ class Edit(FormWidget):
                     target.roles.remove(role)
             for role in form.cleaned_data['roles']:
                 target.roles.add(role)
-        
+
         target.make_acl_key(True)
         target.save(force_update=True)
         return target, Message(_('Changes in user\'s "%(name)s" account have been saved.') % {'name': self.original_name}, 'success')
@@ -330,7 +330,7 @@ class Delete(ButtonWidget):
     id = 'delete'
     fallback = 'admin_users'
     notfound_message = _('Requested User account could not be found.')
-    
+
     def action(self, target):
         if target.pk == self.request.user.id:
             return Message(_('You cannot delete yourself.'), 'error'), False
@@ -344,4 +344,4 @@ class Delete(ButtonWidget):
 def inactive(request):
     token = 'list_filter_misago.users.models.User'
     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
 except ImportError:
     use_unidecode = False
-    
+
 def slugify(string):
     if use_unidecode:
         string = unidecode(string)
@@ -35,14 +35,14 @@ def get_msgid(gettext):
 Random string
 """
 from django.utils import crypto
-    
+
 def get_random_string(length):
     return crypto.get_random_string(length, "1234567890qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM")
 
 
 """
 Date formats
-"""               
+"""
 from django.utils.formats import get_format
 
 formats = {
@@ -57,27 +57,27 @@ formats = {
 
 for key in formats:
     formats[key] = get_format(key).replace('P', 'g:i a')
-    
-    
+
+
 """
 Build pagination list
 """
 import math
 
 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)
     if page > 0:
         pagination['start'] = (page - 1) * max
-        
+
     # Set page and total stat
     pagination['page'] = int(pagination['start'] / max) + 1
     pagination['total'] = int(math.ceil(total / float(max)))
-        
+
     # Fix too large offset
     if pagination['start'] > total:
         pagination['start'] = 0
-        
+
     # Allow prev/next?
     if total > max:
         if pagination['page'] > 1:
@@ -87,8 +87,8 @@ def make_pagination(page, total, max):
 
     # Fix empty pagers
     if not pagination['total']:
-        pagination['total'] = 1 
-            
+        pagination['total'] = 1
+
     # Set stop offset
     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)
     if format == "JPEG":
         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("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):
         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.")
-         
+
     def __call__(self, value):
         slug = slugify(value)
         if not slug:
             raise ValidationError(self.error_short)
         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
             popular_threads.append(thread)
         cache.set('thread_ranking_%s' % request.user.make_acl_key(), popular_threads, request.settings['thread_ranking_refresh'])
-          
+
     # Ranks online
     ranks_list = cache.get('users_online', 'nada')
     if ranks_list == 'nada':
@@ -44,7 +44,7 @@ def home(request):
             del ranks_dict
             del users_list
         cache.set('ranks_list', ranks_list, 10)
-            
+
     # Render page with forums list
     reads_tracker = ForumsTracker(request.user)
     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):
     return error_view(request, 403, message)
 
-                                            
+
 def error404(request, message=None):
     return error_view(request, 404, message)
 
@@ -128,4 +128,4 @@ def error_view(request, error, message):
                                                  },
                                                 context_instance=RequestContext(request));
     response.status_code = error
-    return response
+    return response