Browse Source

Refactored settings handling. #160

Ralfp 12 years ago
parent
commit
0270def8d9
50 changed files with 254 additions and 251 deletions
  1. 2 2
      misago/apps/admin/newsletters/views.py
  2. 2 1
      misago/apps/admin/settings/views.py
  3. 5 5
      misago/apps/admin/users/forms.py
  4. 4 3
      misago/apps/admin/users/views.py
  5. 7 6
      misago/apps/index.py
  6. 2 1
      misago/apps/newthreads.py
  7. 2 1
      misago/apps/popularthreads.py
  8. 3 2
      misago/apps/privatethreads/list.py
  9. 2 1
      misago/apps/privatethreads/mixins.py
  10. 2 2
      misago/apps/profiles/views.py
  11. 5 4
      misago/apps/register/forms.py
  12. 6 5
      misago/apps/register/views.py
  13. 3 2
      misago/apps/reports/list.py
  14. 2 1
      misago/apps/search/views.py
  15. 5 4
      misago/apps/signin/views.py
  16. 3 2
      misago/apps/threads/list.py
  17. 2 1
      misago/apps/threadtype/base.py
  18. 3 3
      misago/apps/threadtype/jumps.py
  19. 2 1
      misago/apps/threadtype/list/forms.py
  20. 10 9
      misago/apps/threadtype/mixins.py
  21. 2 2
      misago/apps/threadtype/posting/forms.py
  22. 8 7
      misago/apps/threadtype/posting/newreply.py
  23. 4 3
      misago/apps/threadtype/posting/newthread.py
  24. 2 1
      misago/apps/threadtype/thread/moderation/forms.py
  25. 3 2
      misago/apps/threadtype/thread/views.py
  26. 3 2
      misago/apps/tos.py
  27. 5 5
      misago/apps/usercp/avatar/forms.py
  28. 6 6
      misago/apps/usercp/avatar/views.py
  29. 1 1
      misago/apps/usercp/credentials/forms.py
  30. 1 1
      misago/apps/usercp/username/forms.py
  31. 5 4
      misago/apps/watchedthreads/views.py
  32. 5 5
      misago/auth.py
  33. 63 0
      misago/conf.py
  34. 2 2
      misago/context_processors.py
  35. 0 72
      misago/dbsettings.py
  36. 7 6
      misago/forms/forms.py
  37. 3 2
      misago/forms/layouts.py
  38. 3 4
      misago/management/commands/updateranking.py
  39. 3 4
      misago/management/commands/updatethreadranking.py
  40. 0 1
      misago/markdown/parsers.py
  41. 3 2
      misago/middleware/bruteforce.py
  42. 0 5
      misago/middleware/settings.py
  43. 3 3
      misago/middleware/user.py
  44. 20 17
      misago/models/settingmodel.py
  45. 6 5
      misago/models/signinattemptmodel.py
  46. 9 16
      misago/models/usermodel.py
  47. 2 2
      misago/sessions.py
  48. 0 1
      misago/settings_base.py
  49. 0 1
      misago/templatetags/django2jinja.py
  50. 13 13
      misago/validators.py

+ 2 - 2
misago/apps/admin/newsletters/views.py

@@ -1,4 +1,3 @@
-from django.conf import settings
 from django.core.urlresolvers import reverse as django_reverse
 from django.core.urlresolvers import reverse as django_reverse
 from django.db.models import Q
 from django.db.models import Q
 from django.shortcuts import redirect
 from django.shortcuts import redirect
@@ -6,6 +5,7 @@ from django.template import RequestContext
 from django.utils.translation import ugettext as _
 from django.utils.translation import ugettext as _
 from misago.admin import site
 from misago.admin import site
 from misago.apps.admin.widgets import *
 from misago.apps.admin.widgets import *
+from misago.conf import settings
 from misago.models import Newsletter, User
 from misago.models import Newsletter, User
 from misago.shortcuts import render_to_response
 from misago.shortcuts import render_to_response
 from misago.apps.admin.newsletters.forms import NewsletterForm, SearchNewslettersForm
 from misago.apps.admin.newsletters.forms import NewsletterForm, SearchNewslettersForm
@@ -163,7 +163,7 @@ def send(request, target, token):
 
 
         for user in recipients.all()[newsletter.progress:(newsletter.progress + newsletter.step_size)]:
         for user in recipients.all()[newsletter.progress:(newsletter.progress + newsletter.step_size)]:
             tokens = {
             tokens = {
-              '{{ board_name }}': request.settings.board_name,
+              '{{ board_name }}': settings.board_name,
               '{{ username }}': user.username,
               '{{ username }}': user.username,
               '{{ user_url }}': django_reverse('user', kwargs={'username': user.username_slug, 'user': user.pk}),
               '{{ user_url }}': django_reverse('user', kwargs={'username': user.username_slug, 'user': user.pk}),
               '{{ board_url }}': settings.BOARD_ADDRESS,
               '{{ board_url }}': settings.BOARD_ADDRESS,

+ 2 - 1
misago/apps/admin/settings/views.py

@@ -3,6 +3,7 @@ from django.core.urlresolvers import reverse
 from django.shortcuts import redirect
 from django.shortcuts import redirect
 from django.template import RequestContext
 from django.template import RequestContext
 from django.utils.translation import ungettext, ugettext as _
 from django.utils.translation import ungettext, ugettext as _
+from misago.conf import settings
 from misago.forms import Form, FormLayout, FormFields
 from misago.forms import Form, FormLayout, FormFields
 from misago.messages import Message
 from misago.messages import Message
 from misago.search import SearchQuery, SearchException
 from misago.search import SearchQuery, SearchException
@@ -47,7 +48,7 @@ def settings(request, group_id=None, group_slug=None):
         form = SettingsGroupForm(request.POST, request=request)
         form = SettingsGroupForm(request.POST, request=request)
         if form.is_valid():
         if form.is_valid():
             for setting in form.cleaned_data.keys():
             for setting in form.cleaned_data.keys():
-                request.settings[setting] = form.cleaned_data[setting]
+                settings[setting] = form.cleaned_data[setting]
             cache.delete('settings')
             cache.delete('settings')
             request.messages.set_flash(Message(_('Configuration has been changed.')), 'success', 'admin_settings')
             request.messages.set_flash(Message(_('Configuration has been changed.')), 'success', 'admin_settings')
             return redirect(reverse('admin_settings', kwargs={
             return redirect(reverse('admin_settings', kwargs={

+ 5 - 5
misago/apps/admin/users/forms.py

@@ -1,8 +1,8 @@
 from PIL import Image
 from PIL import Image
-from django.conf import settings
 from django.core.exceptions import ValidationError
 from django.core.exceptions import ValidationError
 from django.utils.translation import ugettext_lazy as _
 from django.utils.translation import ugettext_lazy as _
 from django import forms
 from django import forms
+from misago.conf import settings
 from misago.forms import Form, YesNoSwitch
 from misago.forms import Form, YesNoSwitch
 from misago.models import Rank, Role, User
 from misago.models import Rank, Role, User
 from misago.validators import validate_username, validate_password, validate_email
 from misago.validators import validate_username, validate_password, validate_email
@@ -80,7 +80,7 @@ class UserForm(Form):
 
 
     def clean_username(self):
     def clean_username(self):
         org_username = self.user.username
         org_username = self.user.username
-        validate_username(self.cleaned_data['username'], self.request.settings)
+        validate_username(self.cleaned_data['username'], settings)
         self.user.set_username(self.cleaned_data['username'])
         self.user.set_username(self.cleaned_data['username'])
         try:
         try:
             self.user.full_clean()
             self.user.full_clean()
@@ -99,7 +99,7 @@ class UserForm(Form):
 
 
     def clean_new_password(self):
     def clean_new_password(self):
         if self.cleaned_data['new_password']:
         if self.cleaned_data['new_password']:
-            validate_password(self.cleaned_data['new_password'], self.request.settings)
+            validate_password(self.cleaned_data['new_password'], settings)
             self.user.set_password(self.cleaned_data['new_password'])
             self.user.set_password(self.cleaned_data['new_password'])
             try:
             try:
                 self.user.full_clean()
                 self.user.full_clean()
@@ -157,7 +157,7 @@ class NewUserForm(Form):
         super(NewUserForm, self).__init__(*args, **kwargs)
         super(NewUserForm, self).__init__(*args, **kwargs)
 
 
     def clean_username(self):
     def clean_username(self):
-        validate_username(self.cleaned_data['username'], self.request.settings)
+        validate_username(self.cleaned_data['username'], settings)
         new_user = User.objects.get_blank_user()
         new_user = User.objects.get_blank_user()
         new_user.set_username(self.cleaned_data['username'])
         new_user.set_username(self.cleaned_data['username'])
         try:
         try:
@@ -182,7 +182,7 @@ class NewUserForm(Form):
             new_user.full_clean()
             new_user.full_clean()
         except ValidationError as e:
         except ValidationError as e:
             new_user.is_password_valid(e)
             new_user.is_password_valid(e)
-        validate_password(self.cleaned_data['password'],  self.request.settings)
+        validate_password(self.cleaned_data['password'], settings)
         return self.cleaned_data['password']
         return self.cleaned_data['password']
 
 
 
 

+ 4 - 3
misago/apps/admin/users/views.py

@@ -4,6 +4,7 @@ from django.shortcuts import redirect
 from django.utils.translation import ugettext as _
 from django.utils.translation import ugettext as _
 from misago.admin import site
 from misago.admin import site
 from misago.apps.admin.widgets import *
 from misago.apps.admin.widgets import *
+from misago.conf import settings
 from misago.markdown import signature_markdown
 from misago.markdown import signature_markdown
 from misago.models import Forum, User
 from misago.models import Forum, User
 from misago.utils.strings import random_string
 from misago.utils.strings import random_string
@@ -160,7 +161,7 @@ class List(ListWidget):
     def action_remove_locks(self, items, checked):
     def action_remove_locks(self, items, checked):
         for user in items:
         for user in items:
             if user.pk in checked:
             if user.pk in checked:
-                user.default_avatar(self.request.settings)
+                user.default_avatar()
                 user.avatar_ban = False
                 user.avatar_ban = False
                 user.signature_ban = False
                 user.signature_ban = False
                 user.save(force_update=True)
                 user.save(force_update=True)
@@ -245,7 +246,7 @@ class New(FormWidget):
                                             form.cleaned_data['username'],
                                             form.cleaned_data['username'],
                                             form.cleaned_data['email'],
                                             form.cleaned_data['email'],
                                             form.cleaned_data['password'],
                                             form.cleaned_data['password'],
-                                            self.request.settings['default_timezone'],
+                                            settings.default_timezone,
                                             self.request.META['REMOTE_ADDR'],
                                             self.request.META['REMOTE_ADDR'],
                                             no_roles=True,
                                             no_roles=True,
                                             request=self.request,
                                             request=self.request,
@@ -326,7 +327,7 @@ class Edit(FormWidget):
             if form.cleaned_data['avatar_ban']:
             if form.cleaned_data['avatar_ban']:
                 target.lock_avatar()
                 target.lock_avatar()
             else:
             else:
-                target.default_avatar(self.request.settings)
+                target.default_avatar()
         target.avatar_ban = form.cleaned_data['avatar_ban']
         target.avatar_ban = form.cleaned_data['avatar_ban']
 
 
         # Set custom avatar
         # Set custom avatar

+ 7 - 6
misago/apps/index.py

@@ -2,6 +2,7 @@ from datetime import timedelta
 from django.core.cache import cache
 from django.core.cache import cache
 from django.template import RequestContext
 from django.template import RequestContext
 from django.utils import timezone
 from django.utils import timezone
+from misago.conf import settings
 from misago.shortcuts import render_to_response
 from misago.shortcuts import render_to_response
 from misago.models import Forum, Post, Rank, Session, Thread
 from misago.models import Forum, Post, Rank, Session, Thread
 from misago.readstrackers import ForumsTracker
 from misago.readstrackers import ForumsTracker
@@ -9,15 +10,15 @@ from misago.readstrackers import ForumsTracker
 def index(request):
 def index(request):
     # Threads ranking
     # Threads ranking
     popular_threads = []
     popular_threads = []
-    if request.settings['thread_ranking_size'] > 0:
+    if settings.thread_ranking_size > 0:
         popular_threads = cache.get('thread_ranking_%s' % request.user.make_acl_key(), 'nada')
         popular_threads = cache.get('thread_ranking_%s' % request.user.make_acl_key(), 'nada')
         if popular_threads == 'nada':
         if popular_threads == 'nada':
             popular_threads = []
             popular_threads = []
-            for thread in Thread.objects.filter(moderated=False).filter(deleted=False).filter(forum__in=Forum.objects.readable_forums(request.acl)).prefetch_related('forum').order_by('-score', '-last')[:request.settings['thread_ranking_size']]:
+            for thread in Thread.objects.filter(moderated=False).filter(deleted=False).filter(forum__in=Forum.objects.readable_forums(request.acl)).prefetch_related('forum').order_by('-score', '-last')[:settings.thread_ranking_size]:
                 thread.forum_name = thread.forum.name
                 thread.forum_name = thread.forum.name
                 thread.forum_slug = thread.forum.slug
                 thread.forum_slug = thread.forum.slug
                 popular_threads.append(thread)
                 popular_threads.append(thread)
-            cache.set('thread_ranking_%s' % request.user.make_acl_key(), popular_threads, 60 * request.settings['thread_ranking_refresh'])
+            cache.set('thread_ranking_%s' % request.user.make_acl_key(), popular_threads, 60 * settings.thread_ranking_refresh)
 
 
     # Users online
     # Users online
     users_online = request.onlines.stats(request)
     users_online = request.onlines.stats(request)
@@ -41,7 +42,7 @@ def index(request):
             ranks_list.append(rank_entry)
             ranks_list.append(rank_entry)
             ranks_dict[rank.pk] = rank_entry
             ranks_dict[rank.pk] = rank_entry
         if ranks_dict:
         if ranks_dict:
-            for session in Session.objects.select_related('user').filter(rank__in=ranks_dict.keys()).filter(last__gte=timezone.now() - timedelta(seconds=request.settings['online_counting_frequency'])).filter(user__isnull=False):
+            for session in Session.objects.select_related('user').filter(rank__in=ranks_dict.keys()).filter(last__gte=timezone.now() - timedelta(seconds=settings.online_counting_frequency)).filter(user__isnull=False):
                 if not session.user_id in users_list:
                 if not session.user_id in users_list:
                     ranks_dict[session.user.rank_id]['online'].append(session.user)
                     ranks_dict[session.user.rank_id]['online'].append(session.user)
                     ranks_dict[session.user.rank_id]['pks'].append(session.user.pk)
                     ranks_dict[session.user.rank_id]['pks'].append(session.user.pk)
@@ -52,10 +53,10 @@ def index(request):
                     ranks_dict[request.user.rank_id]['online'].append(request.user)
                     ranks_dict[request.user.rank_id]['online'].append(request.user)
                     ranks_dict[request.user.rank_id]['pks'].append(request.user.pk)
                     ranks_dict[request.user.rank_id]['pks'].append(request.user.pk)
                     users_list.append(request.user.pk)
                     users_list.append(request.user.pk)
-            cache.set('team_users_online', users_list, request.settings['online_counting_frequency'])
+            cache.set('team_users_online', users_list, settings.online_counting_frequency)
             del ranks_dict
             del ranks_dict
             del users_list
             del users_list
-        cache.set('ranks_online', ranks_list, request.settings['online_counting_frequency'])
+        cache.set('ranks_online', ranks_list, settings.online_counting_frequency)
     elif request.user.is_authenticated():
     elif request.user.is_authenticated():
         for rank in ranks_list:
         for rank in ranks_list:
             if rank['id'] == request.user.rank_id and not request.user.pk in rank['pks']:
             if rank['id'] == request.user.rank_id and not request.user.pk in rank['pks']:

+ 2 - 1
misago/apps/newthreads.py

@@ -4,6 +4,7 @@ from django.http import Http404
 from django.shortcuts import redirect
 from django.shortcuts import redirect
 from django.template import RequestContext
 from django.template import RequestContext
 from django.utils import timezone
 from django.utils import timezone
+from misago.conf import settings
 from misago.models import Forum, Thread
 from misago.models import Forum, Thread
 from misago.shortcuts import render_to_response
 from misago.shortcuts import render_to_response
 from misago.utils.pagination import make_pagination
 from misago.utils.pagination import make_pagination
@@ -17,7 +18,7 @@ def new_threads(request, page=0):
         return redirect(reverse('new_threads'))
         return redirect(reverse('new_threads'))
 
 
     queryset = queryset.order_by('-start').prefetch_related('forum')[pagination['start']:pagination['stop']];
     queryset = queryset.order_by('-start').prefetch_related('forum')[pagination['start']:pagination['stop']];
-    if request.settings['avatars_on_threads_list']:
+    if settings.avatars_on_threads_list:
         queryset = queryset.prefetch_related('start_poster', 'last_poster')
         queryset = queryset.prefetch_related('start_poster', 'last_poster')
 
 
     return render_to_response('new_threads.html',
     return render_to_response('new_threads.html',

+ 2 - 1
misago/apps/popularthreads.py

@@ -4,6 +4,7 @@ from django.http import Http404
 from django.shortcuts import redirect
 from django.shortcuts import redirect
 from django.template import RequestContext
 from django.template import RequestContext
 from django.utils import timezone
 from django.utils import timezone
+from misago.conf import settings
 from misago.models import Forum, Thread
 from misago.models import Forum, Thread
 from misago.shortcuts import render_to_response
 from misago.shortcuts import render_to_response
 from misago.utils.pagination import make_pagination
 from misago.utils.pagination import make_pagination
@@ -17,7 +18,7 @@ def popular_threads(request, page=0):
         return redirect(reverse('popular_threads'))
         return redirect(reverse('popular_threads'))
 
 
     queryset = queryset.order_by('-score', '-last').prefetch_related('forum')[pagination['start']:pagination['stop']];
     queryset = queryset.order_by('-score', '-last').prefetch_related('forum')[pagination['start']:pagination['stop']];
-    if request.settings['avatars_on_threads_list']:
+    if settings.avatars_on_threads_list:
         queryset = queryset.prefetch_related('start_poster', 'last_poster')
         queryset = queryset.prefetch_related('start_poster', 'last_poster')
 
 
     return render_to_response('popular_threads.html',
     return render_to_response('popular_threads.html',

+ 3 - 2
misago/apps/privatethreads/list.py

@@ -2,6 +2,7 @@ from itertools import chain
 from django.http import Http404
 from django.http import Http404
 from django.utils.translation import ugettext as _
 from django.utils.translation import ugettext as _
 from misago.apps.threadtype.list import ThreadsListBaseView, ThreadsListModeration
 from misago.apps.threadtype.list import ThreadsListBaseView, ThreadsListModeration
+from misago.conf import settings
 from misago.models import Forum, Thread
 from misago.models import Forum, Thread
 from misago.readstrackers import ThreadsTracker
 from misago.readstrackers import ThreadsTracker
 from misago.utils.pagination import make_pagination
 from misago.utils.pagination import make_pagination
@@ -23,12 +24,12 @@ class ThreadsListView(ThreadsListBaseView, ThreadsListModeration, TypeMixin):
         qs_threads = self.threads_queryset()
         qs_threads = self.threads_queryset()
 
 
         # Add in first and last poster
         # Add in first and last poster
-        if self.request.settings.avatars_on_threads_list:
+        if settings.avatars_on_threads_list:
             qs_threads = qs_threads.prefetch_related('start_poster', 'last_poster')
             qs_threads = qs_threads.prefetch_related('start_poster', 'last_poster')
 
 
         self.count = qs_threads.count()
         self.count = qs_threads.count()
         try:
         try:
-            self.pagination = make_pagination(self.kwargs.get('page', 0), self.count, self.request.settings.threads_per_page)
+            self.pagination = make_pagination(self.kwargs.get('page', 0), self.count, settings.threads_per_page)
         except Http404:
         except Http404:
             return self.threads_list_redirect()
             return self.threads_list_redirect()
 
 

+ 2 - 1
misago/apps/privatethreads/mixins.py

@@ -1,13 +1,14 @@
 from django.core.urlresolvers import reverse
 from django.core.urlresolvers import reverse
 from django.shortcuts import redirect
 from django.shortcuts import redirect
 from django.utils.translation import ugettext as _
 from django.utils.translation import ugettext as _
+from misago.conf import settings
 from misago.acl.exceptions import ACLError404
 from misago.acl.exceptions import ACLError404
 
 
 class TypeMixin(object):
 class TypeMixin(object):
     type_prefix = 'private_thread'
     type_prefix = 'private_thread'
 
 
     def type_available(self):
     def type_available(self):
-        return self.request.settings['enable_private_threads']
+        return settings.enable_private_threads
 
 
     def check_permissions(self):
     def check_permissions(self):
         try:
         try:

+ 2 - 2
misago/apps/profiles/views.py

@@ -1,9 +1,9 @@
-from django.conf import settings
 from django.core.urlresolvers import reverse
 from django.core.urlresolvers import reverse
 from django.http import Http404
 from django.http import Http404
 from django.shortcuts import redirect
 from django.shortcuts import redirect
 from django.template import RequestContext
 from django.template import RequestContext
 from misago.apps.errors import error403, error404
 from misago.apps.errors import error403, error404
+from misago.conf import settings
 from misago.forms import FormFields
 from misago.forms import FormFields
 from misago.messages import Message
 from misago.messages import Message
 from misago.models import Rank, User
 from misago.models import Rank, User
@@ -81,7 +81,7 @@ def list(request, slug=None, page=0):
             users = User.objects.filter(rank=active_rank)
             users = User.objects.filter(rank=active_rank)
             items_total = users.count()
             items_total = users.count()
             try:
             try:
-                pagination = make_pagination(page, items_total, request.settings['profiles_per_list'])
+                pagination = make_pagination(page, items_total, settings.profiles_per_list)
             except Http404:
             except Http404:
                 if not default_rank and active_rank:
                 if not default_rank and active_rank:
                     return redirect(reverse('users', kwargs={'slug': active_rank.slug}))
                     return redirect(reverse('users', kwargs={'slug': active_rank.slug}))

+ 5 - 4
misago/apps/register/forms.py

@@ -1,6 +1,7 @@
 from django import forms
 from django import forms
 from django.core.exceptions import ValidationError
 from django.core.exceptions import ValidationError
 from django.utils.translation import ugettext_lazy as _
 from django.utils.translation import ugettext_lazy as _
+from misago.conf import settings
 from misago.forms import Form, QACaptchaField, ReCaptchaField
 from misago.forms import Form, QACaptchaField, ReCaptchaField
 from misago.models import User
 from misago.models import User
 from misago.utils.timezones import tzlist
 from misago.utils.timezones import tzlist
@@ -28,7 +29,7 @@ class UserRegisterForm(Form):
         self.layout = [
         self.layout = [
                       (
                       (
                        None,
                        None,
-                       [('username', {'label': _('Username'), 'help_text': _("Your displayed username. Between %(min)s and %(max)s characters, only letters and digits are allowed.") % {'min': self.request.settings['username_length_min'], 'max': self.request.settings['username_length_max']},'attrs': {'placeholder': _("Enter your desired username")}})]
+                       [('username', {'label': _('Username'), 'help_text': _("Your displayed username. Between %(min)s and %(max)s characters, only letters and digits are allowed.") % {'min': settings.username_length_min, 'max': settings.username_length_max},'attrs': {'placeholder': _("Enter your desired username")}})]
                        ),
                        ),
                       (
                       (
                        None,
                        None,
@@ -45,12 +46,12 @@ class UserRegisterForm(Form):
                        ),
                        ),
                       ]
                       ]
         
         
-        if not self.request.settings['tos_url'] and not self.request.settings['tos_content']:
+        if not settings.tos_url and not settings.tos_content:
             del self.fields['accept_tos']
             del self.fields['accept_tos']
             del self.layout[3]
             del self.layout[3]
         
         
     def clean_username(self):
     def clean_username(self):
-        validate_username(self.cleaned_data['username'], self.request.settings)
+        validate_username(self.cleaned_data['username'], settings)
         new_user = User.objects.get_blank_user()
         new_user = User.objects.get_blank_user()
         new_user.set_username(self.cleaned_data['username'])
         new_user.set_username(self.cleaned_data['username'])
         try:
         try:
@@ -69,7 +70,7 @@ class UserRegisterForm(Form):
         return self.cleaned_data['email']
         return self.cleaned_data['email']
         
         
     def clean_password(self):
     def clean_password(self):
-        validate_password(self.cleaned_data['password'], self.request.settings)
+        validate_password(self.cleaned_data['password'], settings)
         new_user = User.objects.get_blank_user()
         new_user = User.objects.get_blank_user()
         new_user.set_password(self.cleaned_data['password'])
         new_user.set_password(self.cleaned_data['password'])
         try:
         try:

+ 6 - 5
misago/apps/register/views.py

@@ -4,6 +4,7 @@ from django.template import RequestContext
 from django.utils import timezone
 from django.utils import timezone
 from django.utils.translation import ugettext as _
 from django.utils.translation import ugettext as _
 from misago.auth import sign_user_in
 from misago.auth import sign_user_in
+from misago.conf import settings
 from misago.decorators import block_authenticated, block_banned, block_crawlers, block_jammed
 from misago.decorators import block_authenticated, block_banned, block_crawlers, block_jammed
 from misago.forms import FormLayout
 from misago.forms import FormLayout
 from misago.messages import Message
 from misago.messages import Message
@@ -17,7 +18,7 @@ from misago.apps.register.forms import UserRegisterForm
 @block_authenticated
 @block_authenticated
 @block_jammed
 @block_jammed
 def form(request):
 def form(request):
-    if request.settings['account_activation'] == 'block':
+    if settings.account_activation == 'block':
        return redirect_message(request, Message(_("We are sorry but we don't allow new members registrations at this time.")), 'info')
        return redirect_message(request, Message(_("We are sorry but we don't allow new members registrations at this time.")), 'info')
     
     
     message = None
     message = None
@@ -25,9 +26,9 @@ def form(request):
         form = UserRegisterForm(request.POST, request=request)
         form = UserRegisterForm(request.POST, request=request)
         if form.is_valid():
         if form.is_valid():
             need_activation = 0
             need_activation = 0
-            if request.settings['account_activation'] == 'user':
+            if settings.account_activation == 'user':
                 need_activation = User.ACTIVATION_USER
                 need_activation = User.ACTIVATION_USER
-            if request.settings['account_activation'] == 'admin':
+            if settings.account_activation == 'admin':
                 need_activation = User.ACTIVATION_ADMIN
                 need_activation = User.ACTIVATION_ADMIN
                 
                 
             new_user = User.objects.create_user(
             new_user = User.objects.create_user(
@@ -68,10 +69,10 @@ def form(request):
             return redirect(reverse('index'))
             return redirect(reverse('index'))
         else:
         else:
             message = Message(form.non_field_errors()[0], 'error')
             message = Message(form.non_field_errors()[0], 'error')
-            if request.settings['registrations_jams']:
+            if settings.registrations_jams:
                 SignInAttempt.objects.register_attempt(request.session.get_ip(request))
                 SignInAttempt.objects.register_attempt(request.session.get_ip(request))
             # Have we jammed our account?
             # Have we jammed our account?
-            if SignInAttempt.objects.is_jammed(request.settings, request.session.get_ip(request)):
+            if SignInAttempt.objects.is_jammed(request.session.get_ip(request)):
                 request.jam.expires = timezone.now()
                 request.jam.expires = timezone.now()
                 return redirect(reverse('register'))
                 return redirect(reverse('register'))
     else:
     else:

+ 3 - 2
misago/apps/reports/list.py

@@ -5,6 +5,7 @@ from django.http import Http404
 from django.shortcuts import redirect
 from django.shortcuts import redirect
 from django.utils.translation import ugettext as _
 from django.utils.translation import ugettext as _
 from misago.apps.threadtype.list import ThreadsListBaseView, ThreadsListModeration
 from misago.apps.threadtype.list import ThreadsListBaseView, ThreadsListModeration
+from misago.conf import settings
 from misago.messages import Message
 from misago.messages import Message
 from misago.models import Forum, Thread, Post
 from misago.models import Forum, Thread, Post
 from misago.readstrackers import ThreadsTracker
 from misago.readstrackers import ThreadsTracker
@@ -20,7 +21,7 @@ class ThreadsListView(ThreadsListBaseView, ThreadsListModeration, TypeMixin):
         threads = self.forum.thread_set.filter(weight__lt=2).prefetch_related('report_for').order_by('-weight', '-last')
         threads = self.forum.thread_set.filter(weight__lt=2).prefetch_related('report_for').order_by('-weight', '-last')
 
 
         # Add in first and last poster
         # Add in first and last poster
-        if self.request.settings.avatars_on_threads_list:
+        if settings.avatars_on_threads_list:
             announcements = announcements.prefetch_related('start_poster', 'last_poster')
             announcements = announcements.prefetch_related('start_poster', 'last_poster')
             threads = threads.prefetch_related('start_poster', 'last_poster')
             threads = threads.prefetch_related('start_poster', 'last_poster')
 
 
@@ -31,7 +32,7 @@ class ThreadsListView(ThreadsListBaseView, ThreadsListModeration, TypeMixin):
         self.count = qs_threads.count()
         self.count = qs_threads.count()
 
 
         try:
         try:
-            self.pagination = make_pagination(self.kwargs.get('page', 0), self.count, self.request.settings.threads_per_page)
+            self.pagination = make_pagination(self.kwargs.get('page', 0), self.count, settings.threads_per_page)
         except Http404:
         except Http404:
             return self.threads_list_redirect()
             return self.threads_list_redirect()
 
 

+ 2 - 1
misago/apps/search/views.py

@@ -7,6 +7,7 @@ from django.utils.translation import ugettext as _
 from haystack.inputs import AutoQuery
 from haystack.inputs import AutoQuery
 from haystack.query import SearchQuerySet, RelatedSearchQuerySet
 from haystack.query import SearchQuerySet, RelatedSearchQuerySet
 from misago.acl.exceptions import ACLError403, ACLError404
 from misago.acl.exceptions import ACLError403, ACLError404
+from misago.conf import settings
 from misago.decorators import block_crawlers
 from misago.decorators import block_crawlers
 from misago.forms import FormFields
 from misago.forms import FormFields
 from misago.models import Forum, Thread, Post, User
 from misago.models import Forum, Thread, Post, User
@@ -32,7 +33,7 @@ class ViewBase(object):
 
 
         if self.request.POST.get('search_in') == 'private':
         if self.request.POST.get('search_in') == 'private':
             if not (self.request.acl.private_threads.can_participate()
             if not (self.request.acl.private_threads.can_participate()
-                    and self.request.settings['enable_private_threads']):
+                    and settings.enable_private_threads):
                 raise ACLError404()
                 raise ACLError404()
             sqs = sqs.filter(thread__in=[t.pk for t in self.request.user.private_thread_set.all()])
             sqs = sqs.filter(thread__in=[t.pk for t in self.request.user.private_thread_set.all()])
         elif self.request.POST.get('search_in') == 'reports':
         elif self.request.POST.get('search_in') == 'reports':

+ 5 - 4
misago/apps/signin/views.py

@@ -9,6 +9,7 @@ from misago.forms import FormLayout
 from misago.messages import Message
 from misago.messages import Message
 import misago.auth as auth
 import misago.auth as auth
 from misago.auth import AuthException, auth_admin, auth_forum, sign_user_in
 from misago.auth import AuthException, auth_admin, auth_forum, sign_user_in
+from misago.conf import settings
 from misago.decorators import (block_authenticated, block_banned, block_crawlers,
 from misago.decorators import (block_authenticated, block_banned, block_crawlers,
                             block_guest, block_jammed, check_csrf)
                             block_guest, block_jammed, check_csrf)
 from misago.models import SignInAttempt, Token
 from misago.models import SignInAttempt, Token
@@ -29,7 +30,7 @@ def signin(request):
     if request.method == 'POST':
     if request.method == 'POST':
         form = SignInForm(
         form = SignInForm(
                           request.POST,
                           request.POST,
-                          show_remember_me=not request.firewall.admin and request.settings['remember_me_allow'],
+                          show_remember_me=not request.firewall.admin and settings.remember_me_allow,
                           request=request
                           request=request
                           )
                           )
 
 
@@ -53,7 +54,7 @@ def signin(request):
                 sign_user_in(request, user)
                 sign_user_in(request, user)
                 remember_me_token = False
                 remember_me_token = False
 
 
-                if not request.firewall.admin and request.settings['remember_me_allow'] and form.cleaned_data['user_remember_me']:
+                if not request.firewall.admin and settings.remember_me_allow and form.cleaned_data['user_remember_me']:
                     remember_me_token = random_string(42)
                     remember_me_token = random_string(42)
                     remember_me = Token(
                     remember_me = Token(
                                         id=remember_me_token,
                                         id=remember_me_token,
@@ -77,14 +78,14 @@ def signin(request):
                     SignInAttempt.objects.register_attempt(request.session.get_ip(request))
                     SignInAttempt.objects.register_attempt(request.session.get_ip(request))
 
 
                     # Have we jammed our account?
                     # Have we jammed our account?
-                    if SignInAttempt.objects.is_jammed(request.settings, request.session.get_ip(request)):
+                    if SignInAttempt.objects.is_jammed(request.session.get_ip(request)):
                         request.jam.expires = timezone.now()
                         request.jam.expires = timezone.now()
                         return redirect(reverse('sign_in'))
                         return redirect(reverse('sign_in'))
         else:
         else:
             message = Message(form.non_field_errors()[0], 'error')
             message = Message(form.non_field_errors()[0], 'error')
     else:
     else:
         form = SignInForm(
         form = SignInForm(
-                          show_remember_me=not request.firewall.admin and request.settings['remember_me_allow'],
+                          show_remember_me=not request.firewall.admin and settings.remember_me_allow,
                           request=request
                           request=request
                           )
                           )
     return render_to_response('signin.html',
     return render_to_response('signin.html',

+ 3 - 2
misago/apps/threads/list.py

@@ -4,6 +4,7 @@ from django.http import Http404
 from django.shortcuts import redirect
 from django.shortcuts import redirect
 from django.utils.translation import ugettext as _
 from django.utils.translation import ugettext as _
 from misago.apps.threadtype.list import ThreadsListBaseView, ThreadsListModeration
 from misago.apps.threadtype.list import ThreadsListBaseView, ThreadsListModeration
+from misago.conf import settings
 from misago.models import Forum, Thread
 from misago.models import Forum, Thread
 from misago.readstrackers import ThreadsTracker
 from misago.readstrackers import ThreadsTracker
 from misago.utils.pagination import make_pagination
 from misago.utils.pagination import make_pagination
@@ -24,7 +25,7 @@ class ThreadsListView(ThreadsListBaseView, ThreadsListModeration, TypeMixin):
                 threads = threads.extra(where=["`threads_thread`.`start_poster_id` IS NULL OR `threads_thread`.`start_poster_id` NOT IN (%s)" % ','.join([str(i) for i in ignored_users])])
                 threads = threads.extra(where=["`threads_thread`.`start_poster_id` IS NULL OR `threads_thread`.`start_poster_id` NOT IN (%s)" % ','.join([str(i) for i in ignored_users])])
 
 
         # Add in first and last poster
         # Add in first and last poster
-        if self.request.settings.avatars_on_threads_list:
+        if settings.avatars_on_threads_list:
             announcements = announcements.prefetch_related('start_poster', 'last_poster')
             announcements = announcements.prefetch_related('start_poster', 'last_poster')
             threads = threads.prefetch_related('start_poster', 'last_poster')
             threads = threads.prefetch_related('start_poster', 'last_poster')
 
 
@@ -35,7 +36,7 @@ class ThreadsListView(ThreadsListBaseView, ThreadsListModeration, TypeMixin):
         self.count = qs_threads.count()
         self.count = qs_threads.count()
 
 
         try:
         try:
-            self.pagination = make_pagination(self.kwargs.get('page', 0), self.count, self.request.settings.threads_per_page)
+            self.pagination = make_pagination(self.kwargs.get('page', 0), self.count, settings.threads_per_page)
         except Http404:
         except Http404:
             return self.threads_list_redirect()
             return self.threads_list_redirect()
 
 

+ 2 - 1
misago/apps/threadtype/base.py

@@ -1,6 +1,7 @@
 from django.core.urlresolvers import reverse
 from django.core.urlresolvers import reverse
 from django.http import Http404
 from django.http import Http404
 from django.shortcuts import redirect
 from django.shortcuts import redirect
+from misago.conf import settings
 from misago.models import Forum, Thread, Post
 from misago.models import Forum, Thread, Post
 from misago.utils.pagination import page_number
 from misago.utils.pagination import page_number
 
 
@@ -51,7 +52,7 @@ class ViewBase(object):
     def redirect_to_post(self, post, type_prefix=None):
     def redirect_to_post(self, post, type_prefix=None):
         type_prefix = type_prefix or self.type_prefix
         type_prefix = type_prefix or self.type_prefix
         queryset = self.request.acl.threads.filter_posts(self.request, self.thread, self.thread.post_set)
         queryset = self.request.acl.threads.filter_posts(self.request, self.thread, self.thread.post_set)
-        page = page_number(queryset.filter(id__lte=post.pk).count(), queryset.count(), self.request.settings.posts_per_page)
+        page = page_number(queryset.filter(id__lte=post.pk).count(), queryset.count(), settings.posts_per_page)
         if page > 1:
         if page > 1:
             return redirect(reverse(type_prefix, kwargs={'thread': self.thread.pk, 'slug': self.thread.slug, 'page': page}) + ('#post-%s' % post.pk))
             return redirect(reverse(type_prefix, kwargs={'thread': self.thread.pk, 'slug': self.thread.slug, 'page': page}) + ('#post-%s' % post.pk))
         return redirect(reverse(type_prefix, kwargs={'thread': self.thread.pk, 'slug': self.thread.slug}) + ('#post-%s' % post.pk))
         return redirect(reverse(type_prefix, kwargs={'thread': self.thread.pk, 'slug': self.thread.slug}) + ('#post-%s' % post.pk))

+ 3 - 3
misago/apps/threadtype/jumps.py

@@ -1,10 +1,10 @@
-from django.conf import settings
 from django.core.urlresolvers import reverse
 from django.core.urlresolvers import reverse
 from django.shortcuts import redirect
 from django.shortcuts import redirect
 from django.utils import timezone
 from django.utils import timezone
 from django.utils.translation import ugettext as _
 from django.utils.translation import ugettext as _
 from misago.acl.exceptions import ACLError403, ACLError404
 from misago.acl.exceptions import ACLError403, ACLError404
 from misago.apps.errors import error403, error404
 from misago.apps.errors import error403, error404
+from misago.conf import settings
 from misago.decorators import block_guest, check_csrf
 from misago.decorators import block_guest, check_csrf
 from misago.markdown import post_markdown
 from misago.markdown import post_markdown
 from misago.messages import Message
 from misago.messages import Message
@@ -211,13 +211,13 @@ class UpvotePostBaseView(JumpView):
                 request.user.karma_given_p += 1
                 request.user.karma_given_p += 1
                 if self.post.user_id:
                 if self.post.user_id:
                     self.post.user.karma_p += 1
                     self.post.user.karma_p += 1
-                    self.post.user.score += request.settings['score_reward_karma_positive']
+                    self.post.user.score += settings.score_reward_karma_positive
             else:
             else:
                 self.post.downvotes += 1
                 self.post.downvotes += 1
                 request.user.karma_given_n += 1
                 request.user.karma_given_n += 1
                 if self.post.user_id:
                 if self.post.user_id:
                     self.post.user.karma_n += 1
                     self.post.user.karma_n += 1
-                    self.post.user.score -= request.settings['score_reward_karma_negative']
+                    self.post.user.score -= settings.score_reward_karma_negative
             self.post.save(force_update=True)
             self.post.save(force_update=True)
             request.user.save(force_update=True)
             request.user.save(force_update=True)
             if self.post.user_id:
             if self.post.user_id:

+ 2 - 1
misago/apps/threadtype/list/forms.py

@@ -1,5 +1,6 @@
 from django import forms
 from django import forms
 from django.utils.translation import ugettext_lazy as _
 from django.utils.translation import ugettext_lazy as _
+from misago.conf import settings
 from misago.forms import Form, ForumChoiceField
 from misago.forms import Form, ForumChoiceField
 from misago.models import Forum
 from misago.models import Forum
 from misago.validators import validate_sluggable
 from misago.validators import validate_sluggable
@@ -41,7 +42,7 @@ class MergeThreadsForm(Form, ValidateThreadNameMixin):
     def finalize_form(self):
     def finalize_form(self):
         self.fields['new_forum'] = ForumChoiceField(queryset=Forum.objects.get(special='root').get_descendants().filter(pk__in=self.request.acl.forums.acl['can_browse']), initial=self.threads[0].forum)
         self.fields['new_forum'] = ForumChoiceField(queryset=Forum.objects.get(special='root').get_descendants().filter(pk__in=self.request.acl.forums.acl['can_browse']), initial=self.threads[0].forum)
         self.fields['thread_name'] = forms.CharField(
         self.fields['thread_name'] = forms.CharField(
-                                                     max_length=self.request.settings['thread_name_max'],
+                                                     max_length=settings.thread_name_max,
                                                      initial=self.threads[-1].name,
                                                      initial=self.threads[-1].name,
                                                      validators=[validate_sluggable(
                                                      validators=[validate_sluggable(
                                                                                     _("Thread name must contain at least one alpha-numeric character."),
                                                                                     _("Thread name must contain at least one alpha-numeric character."),

+ 10 - 9
misago/apps/threadtype/mixins.py

@@ -1,6 +1,7 @@
 from django import forms
 from django import forms
 from django.utils import timezone
 from django.utils import timezone
 from django.utils.translation import ungettext_lazy, ugettext_lazy as _
 from django.utils.translation import ungettext_lazy, ugettext_lazy as _
+from misago.conf import settings
 from misago.utils.strings import slugify
 from misago.utils.strings import slugify
 
 
 class FloodProtectionMixin(object):
 class FloodProtectionMixin(object):
@@ -28,28 +29,28 @@ class ValidateThreadNameMixin(object):
     def clean_thread_name(self):
     def clean_thread_name(self):
         data = self.cleaned_data['thread_name']
         data = self.cleaned_data['thread_name']
         slug = slugify(data)
         slug = slugify(data)
-        if len(slug) < self.request.settings['thread_name_min']:
+        if len(slug) < settings.thread_name_min:
             raise forms.ValidationError(ungettext_lazy(
             raise forms.ValidationError(ungettext_lazy(
                                                   "Thread name must contain at least one alpha-numeric character.",
                                                   "Thread name must contain at least one alpha-numeric character.",
                                                   "Thread name must contain at least %(count)d alpha-numeric characters.",
                                                   "Thread name must contain at least %(count)d alpha-numeric characters.",
-                                                  self.request.settings['thread_name_min']
-                                                  ) % {'count': self.request.settings['thread_name_min']})
-        if len(data) > self.request.settings['thread_name_max']:
+                                                  settings.thread_name_min
+                                                  ) % {'count': settings.thread_name_min})
+        if len(data) > settings.thread_name_max:
             raise forms.ValidationError(ungettext_lazy(
             raise forms.ValidationError(ungettext_lazy(
                                                   "Thread name cannot be longer than %(count)d character.",
                                                   "Thread name cannot be longer than %(count)d character.",
                                                   "Thread name cannot be longer than %(count)d characters.",
                                                   "Thread name cannot be longer than %(count)d characters.",
-                                                  self.request.settings['thread_name_max']
-                                                  ) % {'count': self.request.settings['thread_name_max']})
+                                                  settings.thread_name_max
+                                                  ) % {'count': settings.thread_name_max})
         return data
         return data
 
 
 
 
 class ValidatePostLengthMixin(object):
 class ValidatePostLengthMixin(object):
     def clean_post(self):
     def clean_post(self):
         data = self.cleaned_data['post']
         data = self.cleaned_data['post']
-        if len(data) < self.request.settings['post_length_min']:
+        if len(data) < settings.post_length_min:
             raise forms.ValidationError(ungettext_lazy(
             raise forms.ValidationError(ungettext_lazy(
                                                   "Post content cannot be empty.",
                                                   "Post content cannot be empty.",
                                                   "Post content cannot be shorter than %(count)d characters.",
                                                   "Post content cannot be shorter than %(count)d characters.",
-                                                  self.request.settings['post_length_min']
-                                                  ) % {'count': self.request.settings['post_length_min']})
+                                                  settings.post_length_min
+                                                  ) % {'count': settings.post_length_min})
         return data
         return data

+ 2 - 2
misago/apps/threadtype/posting/forms.py

@@ -1,10 +1,10 @@
 from django import forms
 from django import forms
-from django.conf import settings
 from django.utils import timezone
 from django.utils import timezone
 from django.utils.translation import ugettext_lazy as _
 from django.utils.translation import ugettext_lazy as _
 from misago.apps.threadtype.mixins import (FloodProtectionMixin,
 from misago.apps.threadtype.mixins import (FloodProtectionMixin,
                                            ValidateThreadNameMixin,
                                            ValidateThreadNameMixin,
                                            ValidatePostLengthMixin)
                                            ValidatePostLengthMixin)
+from misago.conf import settings
 from misago.forms import Form
 from misago.forms import Form
 from misago.validators import validate_sluggable
 from misago.validators import validate_sluggable
 
 
@@ -77,7 +77,7 @@ class NewThreadForm(PostingForm, ValidateThreadNameMixin):
     def finalize_form(self):
     def finalize_form(self):
         super(NewThreadForm, self).finalize_form()
         super(NewThreadForm, self).finalize_form()
         self.layout[0][1].append(('thread_name', {'label': _("Thread Name")}))
         self.layout[0][1].append(('thread_name', {'label': _("Thread Name")}))
-        self.fields['thread_name'] = forms.CharField(max_length=self.request.settings['thread_name_max'],
+        self.fields['thread_name'] = forms.CharField(max_length=settings.thread_name_max,
                                                      validators=[validate_sluggable(_("Thread name must contain at least one alpha-numeric character."),
                                                      validators=[validate_sluggable(_("Thread name must contain at least one alpha-numeric character."),
                                                                                     _("Thread name is too long. Try shorter name."))])
                                                                                     _("Thread name is too long. Try shorter name."))])
 
 

+ 8 - 7
misago/apps/threadtype/posting/newreply.py

@@ -1,6 +1,7 @@
 from datetime import timedelta
 from datetime import timedelta
 from django.utils import timezone
 from django.utils import timezone
 from django.utils.translation import ugettext as _
 from django.utils.translation import ugettext as _
+from misago.conf import settings
 from misago.markdown import post_markdown
 from misago.markdown import post_markdown
 from misago.models import Post
 from misago.models import Post
 from misago.utils.datesformats import date
 from misago.utils.datesformats import date
@@ -36,8 +37,8 @@ class NewReplyBaseView(PostingBaseView):
         # Count merge diff and see if we are merging
         # Count merge diff and see if we are merging
         merge_diff = (now - self.thread.last)
         merge_diff = (now - self.thread.last)
         merge_diff = (merge_diff.days * 86400) + merge_diff.seconds
         merge_diff = (merge_diff.days * 86400) + merge_diff.seconds
-        if (self.request.settings.post_merge_time
-                and merge_diff < (self.request.settings.post_merge_time * 60)
+        if (settings.post_merge_time
+                and merge_diff < (settings.post_merge_time * 60)
                 and self.thread.last_poster_id == self.request.user.id
                 and self.thread.last_poster_id == self.request.user.id
                 and self.thread.last_post.moderated == moderation):
                 and self.thread.last_post.moderated == moderation):
             merged = True
             merged = True
@@ -74,7 +75,7 @@ class NewReplyBaseView(PostingBaseView):
 
 
             # Increase thread score
             # Increase thread score
             if self.thread.last_poster_id != self.request.user.pk:
             if self.thread.last_poster_id != self.request.user.pk:
-                self.thread.score += self.request.settings['thread_ranking_reply_score']
+                self.thread.score += settings.thread_ranking_reply_score
 
 
         # Update forum and monitor
         # Update forum and monitor
         if not moderation and not merged:
         if not moderation and not merged:
@@ -85,8 +86,8 @@ class NewReplyBaseView(PostingBaseView):
         
         
         # Reward user for posting new reply?
         # Reward user for posting new reply?
         if not moderation and not merged and (not self.request.user.last_post
         if not moderation and not merged and (not self.request.user.last_post
-                or self.request.user.last_post < timezone.now() - timedelta(seconds=self.request.settings['score_reward_new_post_cooldown'])):
-            self.request.user.score += self.request.settings['score_reward_new_post']
+                or self.request.user.last_post < timezone.now() - timedelta(seconds=settings.score_reward_new_post_cooldown)):
+            self.request.user.score += settings.score_reward_new_post
 
 
         # Update user
         # Update user
         if not moderation and not merged:
         if not moderation and not merged:
@@ -99,9 +100,9 @@ class NewReplyBaseView(PostingBaseView):
             self.thread.weight = form.cleaned_data['thread_weight']
             self.thread.weight = form.cleaned_data['thread_weight']
 
 
         # Set "closed" checkpoint, either due to thread limit or posters wish
         # Set "closed" checkpoint, either due to thread limit or posters wish
-        if (self.request.settings.thread_length > 0
+        if (settings.thread_length > 0
                 and not merged and not moderation and not self.thread.closed
                 and not merged and not moderation and not self.thread.closed
-                and self.thread.replies >= self.request.settings.thread_length):
+                and self.thread.replies >= settings.thread_length):
             self.thread.closed = True
             self.thread.closed = True
             self.thread.set_checkpoint(self.request, 'limit')
             self.thread.set_checkpoint(self.request, 'limit')
         elif 'close_thread' in form.cleaned_data and form.cleaned_data['close_thread']:
         elif 'close_thread' in form.cleaned_data and form.cleaned_data['close_thread']:

+ 4 - 3
misago/apps/threadtype/posting/newthread.py

@@ -2,6 +2,7 @@ from datetime import timedelta
 from django.utils import timezone
 from django.utils import timezone
 from misago.apps.threadtype.posting.base import PostingBaseView
 from misago.apps.threadtype.posting.base import PostingBaseView
 from misago.apps.threadtype.posting.forms import NewThreadForm
 from misago.apps.threadtype.posting.forms import NewThreadForm
+from misago.conf import settings
 from misago.markdown import post_markdown
 from misago.markdown import post_markdown
 from misago.models import Forum, Thread, Post
 from misago.models import Forum, Thread, Post
 from misago.utils.strings import slugify
 from misago.utils.strings import slugify
@@ -29,7 +30,7 @@ class NewThreadBaseView(PostingBaseView):
                                             start=now,
                                             start=now,
                                             last=now,
                                             last=now,
                                             moderated=moderation,
                                             moderated=moderation,
-                                            score=self.request.settings['thread_ranking_initial_score'],
+                                            score=settings.thread_ranking_initial_score,
                                             )
                                             )
 
 
         # Create our post
         # Create our post
@@ -71,8 +72,8 @@ class NewThreadBaseView(PostingBaseView):
 
 
         # Reward user for posting new thread?
         # Reward user for posting new thread?
         if not moderation and (not self.request.user.last_post
         if not moderation and (not self.request.user.last_post
-                or self.request.user.last_post < timezone.now() - timedelta(seconds=self.request.settings['score_reward_new_post_cooldown'])):
-            self.request.user.score += self.request.settings['score_reward_new_thread']
+                or self.request.user.last_post < timezone.now() - timedelta(seconds=settings.score_reward_new_post_cooldown)):
+            self.request.user.score += settings.score_reward_new_thread
 
 
         # Update user
         # Update user
         if not moderation:
         if not moderation:

+ 2 - 1
misago/apps/threadtype/thread/moderation/forms.py

@@ -2,6 +2,7 @@ from django import forms
 from django.http import Http404
 from django.http import Http404
 from django.utils.translation import ugettext_lazy as _
 from django.utils.translation import ugettext_lazy as _
 from misago.acl.exceptions import ACLError403, ACLError404
 from misago.acl.exceptions import ACLError403, ACLError404
+from misago.conf import settings
 from misago.forms import Form, ForumChoiceField
 from misago.forms import Form, ForumChoiceField
 from misago.models import Forum, Thread
 from misago.models import Forum, Thread
 from misago.validators import validate_sluggable
 from misago.validators import validate_sluggable
@@ -19,7 +20,7 @@ class SplitThreadForm(Form, ValidateThreadNameMixin):
                         ],
                         ],
                        ]
                        ]
 
 
-        self.fields['thread_name'] = forms.CharField(max_length=self.request.settings['thread_name_max'],
+        self.fields['thread_name'] = forms.CharField(max_length=settings.thread_name_max,
                                                      validators=[validate_sluggable(_("Thread name must contain at least one alpha-numeric character."),
                                                      validators=[validate_sluggable(_("Thread name must contain at least one alpha-numeric character."),
                                                                                     _("Thread name is too long. Try shorter name.")
                                                                                     _("Thread name is too long. Try shorter name.")
                                                                                     )])
                                                                                     )])

+ 3 - 2
misago/apps/threadtype/thread/views.py

@@ -8,6 +8,7 @@ from django.utils import timezone
 from django.utils.translation import ugettext as _
 from django.utils.translation import ugettext as _
 from misago.acl.exceptions import ACLError403, ACLError404
 from misago.acl.exceptions import ACLError403, ACLError404
 from misago.apps.errors import error403, error404
 from misago.apps.errors import error403, error404
+from misago.conf import settings
 from misago.forms import Form, FormLayout, FormFields
 from misago.forms import Form, FormLayout, FormFields
 from misago.markdown import emojis
 from misago.markdown import emojis
 from misago.messages import Message
 from misago.messages import Message
@@ -43,12 +44,12 @@ class ThreadBaseView(ViewBase):
         self.posts = self.posts.order_by('id')
         self.posts = self.posts.order_by('id')
 
 
         try:
         try:
-            self.pagination = make_pagination(self.kwargs.get('page', 0), self.count, self.request.settings.posts_per_page)
+            self.pagination = make_pagination(self.kwargs.get('page', 0), self.count, settings.posts_per_page)
         except Http404:
         except Http404:
             return redirect(reverse(self.type_prefix, kwargs={'thread': self.thread.pk, 'slug': self.thread.slug}))
             return redirect(reverse(self.type_prefix, kwargs={'thread': self.thread.pk, 'slug': self.thread.slug}))
 
 
         checkpoints_range = None
         checkpoints_range = None
-        if self.request.settings.posts_per_page < self.count:
+        if settings.posts_per_page < self.count:
             self.posts = self.posts[self.pagination['start']:self.pagination['stop'] + 1]
             self.posts = self.posts[self.pagination['start']:self.pagination['stop'] + 1]
             posts_len = len(self.posts)
             posts_len = len(self.posts)
             checkpoints_range = self.posts[posts_len - 1].date
             checkpoints_range = self.posts[posts_len - 1].date

+ 3 - 2
misago/apps/tos.py

@@ -1,9 +1,10 @@
 from django.template import RequestContext
 from django.template import RequestContext
-from misago.shortcuts import render_to_response
 from misago.apps.errors import error404
 from misago.apps.errors import error404
+from misago.conf import settings
+from misago.shortcuts import render_to_response
 
 
 def tos(request):
 def tos(request):
-    if request.settings.tos_url or not request.settings.tos_content:
+    if settings.tos_url or not settings.tos_content:
         return error404(request)
         return error404(request)
     return render_to_response('forum_tos.html',
     return render_to_response('forum_tos.html',
                               context_instance=RequestContext(request));
                               context_instance=RequestContext(request));

+ 5 - 5
misago/apps/usercp/avatar/forms.py

@@ -1,8 +1,8 @@
 from PIL import Image
 from PIL import Image
 from django import forms
 from django import forms
-from django.conf import settings
 from django.core.exceptions import ValidationError
 from django.core.exceptions import ValidationError
 from django.utils.translation import ugettext_lazy as _
 from django.utils.translation import ugettext_lazy as _
+from misago.conf import settings
 from misago.forms import Form
 from misago.forms import Form
 
 
 class UploadAvatarForm(Form):
 class UploadAvatarForm(Form):
@@ -21,11 +21,11 @@ class UploadAvatarForm(Form):
     def clean_avatar_upload(self):
     def clean_avatar_upload(self):
         image = self.cleaned_data.get('avatar_upload', False)
         image = self.cleaned_data.get('avatar_upload', False)
         if image:
         if image:
-            if image._size > self.request.settings.upload_limit * 1024:
-                if self.request.settings.upload_limit > 1024:
-                    limit = '%s Mb' % "{:10.2f}".format(float(self.request.settings.upload_limit / 1024.0))
+            if image._size > settings.upload_limit * 1024:
+                if settings.upload_limit > 1024:
+                    limit = '%s Mb' % "{:10.2f}".format(float(settings.upload_limit / 1024.0))
                 else:
                 else:
-                    limit = '%s Kb' % self.request.settings.upload_limit
+                    limit = '%s Kb' % settings.upload_limit
                 raise ValidationError(_("Avatar image cannot be larger than %(limit)s.") % {'limit': limit})
                 raise ValidationError(_("Avatar image cannot be larger than %(limit)s.") % {'limit': limit})
         else:
         else:
             raise ValidationError(_("Couldn't read uploaded image"))
             raise ValidationError(_("Couldn't read uploaded image"))

+ 6 - 6
misago/apps/usercp/avatar/views.py

@@ -1,13 +1,13 @@
 from path import path
 from path import path
 from PIL import Image
 from PIL import Image
 from zipfile import is_zipfile
 from zipfile import is_zipfile
-from django.conf import settings
 from django.core.exceptions import ValidationError
 from django.core.exceptions import ValidationError
 from django.core.urlresolvers import reverse
 from django.core.urlresolvers import reverse
 from django.shortcuts import redirect
 from django.shortcuts import redirect
 from django.utils.encoding import smart_str
 from django.utils.encoding import smart_str
 from django.utils.translation import ugettext as _
 from django.utils.translation import ugettext as _
 from misago.apps.errors import error404
 from misago.apps.errors import error404
+from misago.conf import settings
 from misago.decorators import block_guest
 from misago.decorators import block_guest
 from misago.forms import FormLayout
 from misago.forms import FormLayout
 from misago.messages import Message
 from misago.messages import Message
@@ -41,7 +41,7 @@ def avatar(request):
 @block_guest
 @block_guest
 @avatar_view
 @avatar_view
 def gravatar(request):
 def gravatar(request):
-    if not 'gravatar' in request.settings.avatars_types:
+    if not 'gravatar' in settings.avatars_types:
         return error404(request)
         return error404(request)
     if request.user.avatar_type != 'gravatar':
     if request.user.avatar_type != 'gravatar':
         if request.csrf.request_secure(request):
         if request.csrf.request_secure(request):
@@ -57,7 +57,7 @@ def gravatar(request):
 @block_guest
 @block_guest
 @avatar_view
 @avatar_view
 def gallery(request):
 def gallery(request):
-    if not 'gallery' in request.settings.avatars_types:
+    if not 'gallery' in settings.avatars_types:
         return error404(request)
         return error404(request)
 
 
     allowed_avatars = []
     allowed_avatars = []
@@ -103,7 +103,7 @@ def gallery(request):
 @block_guest
 @block_guest
 @avatar_view
 @avatar_view
 def upload(request):
 def upload(request):
-    if not 'upload' in request.settings.avatars_types:
+    if not 'upload' in settings.avatars_types:
         return error404(request)
         return error404(request)
     message = request.messages.get_message('usercp_avatar')
     message = request.messages.get_message('usercp_avatar')
     if request.method == 'POST':
     if request.method == 'POST':
@@ -153,7 +153,7 @@ def upload(request):
                 return redirect(reverse('usercp_avatar'))
                 return redirect(reverse('usercp_avatar'))
             except ValidationError:
             except ValidationError:
                 request.user.delete_avatar()
                 request.user.delete_avatar()
-                request.user.default_avatar(request.settings)
+                request.user.default_avatar()
                 message = Message(_("Only gif, jpeg and png files are allowed for member avatars."), 'error')
                 message = Message(_("Only gif, jpeg and png files are allowed for member avatars."), 'error')
         else:
         else:
             message = Message(form.non_field_errors()[0], 'error')
             message = Message(form.non_field_errors()[0], 'error')
@@ -170,7 +170,7 @@ def upload(request):
 @block_guest
 @block_guest
 @avatar_view
 @avatar_view
 def crop(request, upload=False):
 def crop(request, upload=False):
-    if upload and (not request.user.avatar_temp or not 'upload' in request.settings.avatars_types):
+    if upload and (not request.user.avatar_temp or not 'upload' in settings.avatars_types):
         return error404(request)
         return error404(request)
 
 
     if not upload and request.user.avatar_type != 'upload':
     if not upload and request.user.avatar_type != 'upload':

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

@@ -37,7 +37,7 @@ class CredentialsChangeForm(Form):
 
 
     def clean_new_password(self):
     def clean_new_password(self):
         if self.cleaned_data['new_password']:
         if self.cleaned_data['new_password']:
-            validate_password(self.cleaned_data['new_password'],  self.request.settings)
+            validate_password(self.cleaned_data['new_password'])
         return self.cleaned_data['new_password']
         return self.cleaned_data['new_password']
 
 
     def clean_current_password(self):
     def clean_current_password(self):

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

@@ -21,7 +21,7 @@ class UsernameChangeForm(Form):
         org_username = self.request.user.username
         org_username = self.request.user.username
         if org_username == self.cleaned_data['username']:
         if org_username == self.cleaned_data['username']:
             raise ValidationError(_("Your new username is same as current one."))
             raise ValidationError(_("Your new username is same as current one."))
-        validate_username(self.cleaned_data['username'], self.request.settings)
+        validate_username(self.cleaned_data['username'])
         self.request.user.set_username(self.cleaned_data['username'])
         self.request.user.set_username(self.cleaned_data['username'])
         try:
         try:
             self.request.user.full_clean()
             self.request.user.full_clean()

+ 5 - 4
misago/apps/watchedthreads/views.py

@@ -5,6 +5,7 @@ from django.http import Http404
 from django.shortcuts import redirect
 from django.shortcuts import redirect
 from django.template import RequestContext
 from django.template import RequestContext
 from django.utils.translation import ugettext as _
 from django.utils.translation import ugettext as _
+from misago.conf import settings
 from misago.decorators import block_guest
 from misago.decorators import block_guest
 from misago.forms import Form, FormLayout, FormFields
 from misago.forms import Form, FormLayout, FormFields
 from misago.messages import Message
 from misago.messages import Message
@@ -16,22 +17,22 @@ from misago.utils.pagination import make_pagination
 def watched_threads(request, page=0, new=False):
 def watched_threads(request, page=0, new=False):
     # Find mode and fetch threads
     # Find mode and fetch threads
     readable_forums = Forum.objects.readable_forums(request.acl, True)
     readable_forums = Forum.objects.readable_forums(request.acl, True)
-    if not request.settings['enable_private_threads']:
+    if not settings.enable_private_threads:
         readable_forums.remove(Forum.objects.special_pk('private_threads'))
         readable_forums.remove(Forum.objects.special_pk('private_threads'))
     queryset = WatchedThread.objects.filter(user=request.user).filter(forum_id__in=readable_forums).select_related('thread').filter(thread__moderated=False).filter(thread__deleted=False)
     queryset = WatchedThread.objects.filter(user=request.user).filter(forum_id__in=readable_forums).select_related('thread').filter(thread__moderated=False).filter(thread__deleted=False)
-    if request.settings['avatars_on_threads_list']:
+    if settings.avatars_on_threads_list:
         queryset = queryset.prefetch_related('thread__last_poster')
         queryset = queryset.prefetch_related('thread__last_poster')
     if new:
     if new:
         queryset = queryset.filter(last_read__lt=F('thread__last'))
         queryset = queryset.filter(last_read__lt=F('thread__last'))
     count = queryset.count()
     count = queryset.count()
     try:
     try:
-        pagination = make_pagination(page, count, request.settings.threads_per_page)
+        pagination = make_pagination(page, count, settings.threads_per_page)
     except Http404:
     except Http404:
         if new:
         if new:
             return redirect(reverse('watched_threads_new'))
             return redirect(reverse('watched_threads_new'))
         return redirect(reverse('watched_threads'))
         return redirect(reverse('watched_threads'))
     queryset = queryset.order_by('-thread__last')
     queryset = queryset.order_by('-thread__last')
-    if request.settings.threads_per_page < count:
+    if settings.threads_per_page < count:
         queryset = queryset[pagination['start']:pagination['stop']]
         queryset = queryset[pagination['start']:pagination['stop']]
     queryset.prefetch_related('thread__forum', 'thread__start_poster', 'thread__last_poster')
     queryset.prefetch_related('thread__forum', 'thread__start_poster', 'thread__last_poster')
     threads = []
     threads = []

+ 5 - 5
misago/auth.py

@@ -1,7 +1,7 @@
 from datetime import timedelta
 from datetime import timedelta
-from django.conf import settings
 from django.utils import timezone
 from django.utils import timezone
 from django.utils.translation import ugettext_lazy as _
 from django.utils.translation import ugettext_lazy as _
+from misago.conf import settings
 from misago.models import Ban, SignInAttempt, Token, User
 from misago.models import Ban, SignInAttempt, Token, User
 
 
 """
 """
@@ -70,7 +70,7 @@ def auth_remember(request, ip):
     """
     """
     if request.firewall.admin:
     if request.firewall.admin:
         raise AuthException()
         raise AuthException()
-    if SignInAttempt.objects.is_jammed(request.settings, ip):
+    if SignInAttempt.objects.is_jammed(ip):
         raise AuthException()
         raise AuthException()
     cookie_token = settings.COOKIES_PREFIX + 'TOKEN'
     cookie_token = settings.COOKIES_PREFIX + 'TOKEN'
     try:
     try:
@@ -85,12 +85,12 @@ def auth_remember(request, ip):
             raise AuthException()
             raise AuthException()
 
 
         # See if token is not expired
         # See if token is not expired
-        token_expires = timezone.now() - timedelta(days=request.settings['remember_me_lifetime'])
-        if request.settings['remember_me_extensible'] and token_rk.accessed < token_expires:
+        token_expires = timezone.now() - timedelta(days=settings.remember_me_lifetime)
+        if settings.remember_me_extensible and token_rk.accessed < token_expires:
             # Token expired because it's last use is smaller than expiration date
             # Token expired because it's last use is smaller than expiration date
             raise AuthException()
             raise AuthException()
 
 
-        if not request.settings['remember_me_extensible'] and token_rk.created < token_expires:
+        if not settings.remember_me_extensible and token_rk.created < token_expires:
             # Token expired because it was created before expiration date
             # Token expired because it was created before expiration date
             raise AuthException()
             raise AuthException()
 
 

+ 63 - 0
misago/conf.py

@@ -0,0 +1,63 @@
+from threading import local
+from django.conf import settings as dj_settings
+from django.core.cache import cache
+from misago.models import Setting
+
+_local_thread = local()
+
+def load_settings():
+    settings = cache.get('settings', {})
+    if not settings:
+        for i in Setting.objects.all():
+            settings[i.pk] = i.value
+        cache.set('settings', settings)
+    return settings
+
+
+class MisagoSettings(object):
+    def __init__(self, local, safe):
+        self.thread = local
+        self.is_safe = safe
+
+    def settings(self):
+        try:
+            return self.thread.settings
+        except AttributeError:
+            self.thread.settings = load_settings()
+            return self.thread.settings
+
+    def setting(self, key):
+        try:
+            try:
+                return self.settings()[key]
+            except KeyError:
+                if self.is_safe:
+                    return getattr(dj_settings, key)
+                else:
+                    raise AttributeError()
+        except AttributeError:
+            raise Exception(u"Requested setting \"%s\" could not be found." % key)
+
+    def __getattr__(self, key):
+        return self.setting(key)
+
+    def __contains__(self, key):
+        return key in self.settings
+
+    def __getitem__(self, key):
+        return self.setting(key)
+
+    def __setitem__(self, key, value):
+        setting = Setting.objects.get(pk=key)
+        setting.value = value
+        setting.save(force_update=True)
+
+
+settings = MisagoSettings(_local_thread, True)
+
+
+def SafeSettings(): 
+    """
+    Safe settings factory for MisagoSettings
+    """
+    return MisagoSettings(_local_thread, False)

+ 2 - 2
misago/context_processors.py

@@ -1,4 +1,4 @@
-from django.conf import settings
+from misago.conf import settings, SafeSettings
 from misago import __version__
 from misago import __version__
 from misago.admin import site
 from misago.admin import site
 from misago.models import Forum
 from misago.models import Forum
@@ -28,7 +28,7 @@ def common(request):
             'messages' : request.messages.messages,
             'messages' : request.messages.messages,
             'monitor': request.monitor,
             'monitor': request.monitor,
             'request_path': request.get_full_path(),
             'request_path': request.get_full_path(),
-            'settings': request.settings,
+            'settings': SafeSettings(),
             'stopwatch': request.stopwatch.time(),
             'stopwatch': request.stopwatch.time(),
             'user': request.user,
             'user': request.user,
             'version': __version__,
             'version': __version__,

+ 0 - 72
misago/dbsettings.py

@@ -1,72 +0,0 @@
-from django.db.utils import DatabaseError
-from django.core.cache import cache
-from misago.models import Setting
-
-class DBSettings(object):
-    """
-    Database-stored high-level and "safe" settings controller
-    """
-    def __init__(self):
-        self._settings = {}
-        self._models = {}
-        self.refresh()
-
-    def refresh(self):
-        self._models = cache.get('settings')
-        if not self._models:
-            self._models = {}
-            try:
-                for i in Setting.objects.all():
-                    self._models[i.pk] = i
-                    self._settings[i.pk] = i.get_value()
-            except DatabaseError:
-                pass
-        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()
-
-    def __getitem__(self, key):
-        return self._settings[key]
-
-    def __setitem__(self, key, value):
-        if key in self._settings:
-            self._models[key].set_value(value)
-            self._models[key].save(force_update=True)
-            self._settings[key] = value
-        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()
-
-    def keys(self):
-        return self._settings.keys()
-
-    def values(self):
-        return self._settings.values()
-
-    def items(self):
-        return self._settings.items()
-
-    def iterkeys(self):
-        return self._settings.iterkeys()
-
-    def itervalues(self):
-        return self._settings.itervalues()
-
-    def iteritems(self):
-        return self._settings.iteritems()

+ 7 - 6
misago/forms/forms.py

@@ -1,6 +1,7 @@
 from recaptcha.client.captcha import submit as recaptcha_submit
 from recaptcha.client.captcha import submit as recaptcha_submit
 from django import forms
 from django import forms
 from django.utils.translation import ugettext_lazy as _
 from django.utils.translation import ugettext_lazy as _
+from misago.conf import settings
 
 
 class Form(forms.Form):
 class Form(forms.Form):
     """
     """
@@ -27,17 +28,17 @@ class Form(forms.Form):
 
 
         # Kill captcha fields
         # Kill captcha fields
         try:
         try:
-            if self.request.settings['bots_registration'] != 'recaptcha' or self.request.session.get('captcha_passed'):
+            if settings.bots_registration != 'recaptcha' or self.request.session.get('captcha_passed'):
                 del self.fields['recaptcha']
                 del self.fields['recaptcha']
         except KeyError:
         except KeyError:
             pass
             pass
         try:
         try:
-            if self.request.settings['bots_registration'] != 'qa' or self.request.session.get('captcha_passed'):
+            if settings.bots_registration != 'qa' or self.request.session.get('captcha_passed'):
                 del self.fields['captcha_qa']
                 del self.fields['captcha_qa']
             else:
             else:
                 # Make sure we have any questions loaded
                 # Make sure we have any questions loaded
-                self.fields['captcha_qa'].label = self.request.settings['qa_test']
-                self.fields['captcha_qa'].help_text = self.request.settings['qa_test_help']
+                self.fields['captcha_qa'].label = settings.qa_test
+                self.fields['captcha_qa'].help_text = settings.qa_test_help
         except KeyError:
         except KeyError:
             pass
             pass
 
 
@@ -90,7 +91,7 @@ class Form(forms.Form):
         response = recaptcha_submit(
         response = recaptcha_submit(
                                     self.request.POST.get('recaptcha_challenge_field'),
                                     self.request.POST.get('recaptcha_challenge_field'),
                                     self.request.POST.get('recaptcha_response_field'),
                                     self.request.POST.get('recaptcha_response_field'),
-                                    self.request.settings['recaptcha_private'],
+                                    settings.recaptcha_private,
                                     self.request.session.get_ip(self.request)
                                     self.request.session.get_ip(self.request)
                                     ).is_valid
                                     ).is_valid
         if not response:
         if not response:
@@ -103,7 +104,7 @@ class Form(forms.Form):
         Test QA Captcha, scream if it went wrong
         Test QA Captcha, scream if it went wrong
         """
         """
 
 
-        if not unicode(self.cleaned_data['captcha_qa']).lower() in (name.lower() for name in unicode(self.request.settings['qa_test_answers']).splitlines()):
+        if not unicode(self.cleaned_data['captcha_qa']).lower() in (name.lower() for name in unicode(settings.qa_test_answers).splitlines()):
             raise forms.ValidationError(_("The answer you entered is incorrect."))
             raise forms.ValidationError(_("The answer you entered is incorrect."))
         self.request.session['captcha_passed'] = True
         self.request.session['captcha_passed'] = True
         return self.cleaned_data['captcha_qa']
         return self.cleaned_data['captcha_qa']

+ 3 - 2
misago/forms/layouts.py

@@ -1,6 +1,7 @@
 from UserDict import IterableUserDict
 from UserDict import IterableUserDict
 from recaptcha.client.captcha import displayhtml
 from recaptcha.client.captcha import displayhtml
 from django.utils import formats
 from django.utils import formats
+from misago.conf import settings
 
 
 class FormLayout(object):
 class FormLayout(object):
     """
     """
@@ -117,8 +118,8 @@ class FormFields(object):
             if widget_name == 'ReCaptchaWidget':
             if widget_name == 'ReCaptchaWidget':
                 blueprint['widget'] = 'recaptcha'
                 blueprint['widget'] = 'recaptcha'
                 blueprint['attrs'] = {'html': displayhtml(
                 blueprint['attrs'] = {'html': displayhtml(
-                                                          form.request.settings['recaptcha_public'],
-                                                          form.request.settings['recaptcha_ssl'],
+                                                          settings.recaptcha_public,
+                                                          settings.recaptcha_ssl,
                                                           bound_field.field.api_error,
                                                           bound_field.field.api_error,
                                                           )}
                                                           )}
 
 

+ 3 - 4
misago/management/commands/updateranking.py

@@ -1,6 +1,6 @@
 from django.core.management.base import BaseCommand, CommandError
 from django.core.management.base import BaseCommand, CommandError
 from django.db.models import F
 from django.db.models import F
-from misago.dbsettings import DBSettings
+from misago.conf import settings
 from misago.models import Rank, User
 from misago.models import Rank, User
 
 
 class Command(BaseCommand):
 class Command(BaseCommand):
@@ -29,9 +29,8 @@ class Command(BaseCommand):
                 defaulted_ranks = True
                 defaulted_ranks = True
 
 
         # Inflate scores
         # Inflate scores
-        settings = DBSettings()
-        if settings['ranking_inflation']:
-            inflation = float(100 - settings['ranking_inflation']) / 100
+        if settings.ranking_inflation:
+            inflation = float(100 - settings.ranking_inflation) / 100
             User.objects.all().update(acl_key=None, score=F('score') * inflation, ranking=0)
             User.objects.all().update(acl_key=None, score=F('score') * inflation, ranking=0)
         else:
         else:
             User.objects.all().update(acl_key=None)
             User.objects.all().update(acl_key=None)

+ 3 - 4
misago/management/commands/updatethreadranking.py

@@ -1,6 +1,6 @@
 from django.core.management.base import BaseCommand
 from django.core.management.base import BaseCommand
 from django.db.models import F
 from django.db.models import F
-from misago.dbsettings import DBSettings
+from misago.conf import settings
 from misago.models import Thread
 from misago.models import Thread
 
 
 class Command(BaseCommand):
 class Command(BaseCommand):
@@ -9,9 +9,8 @@ class Command(BaseCommand):
     """
     """
     help = 'Updates Popular Threads ranking'
     help = 'Updates Popular Threads ranking'
     def handle(self, *args, **options):
     def handle(self, *args, **options):
-        settings = DBSettings()
-        if settings['thread_ranking_inflation'] > 0:
-            inflation = float(100 - settings['thread_ranking_inflation']) / 100
+        if settings.thread_ranking_inflation > 0:
+            inflation = float(100 - settings.thread_ranking_inflation) / 100
             Thread.objects.all().update(score=F('score') * inflation)
             Thread.objects.all().update(score=F('score') * inflation)
             self.stdout.write('Thread ranking has been updated.\n')
             self.stdout.write('Thread ranking has been updated.\n')
         else:
         else:

+ 0 - 1
misago/markdown/parsers.py

@@ -1,6 +1,5 @@
 from HTMLParser import HTMLParser
 from HTMLParser import HTMLParser
 from urlparse import urlparse
 from urlparse import urlparse
-from django.conf import settings
 from misago.utils.strings import random_string
 from misago.utils.strings import random_string
 
 
 class RemoveHTMLParser(HTMLParser):
 class RemoveHTMLParser(HTMLParser):

+ 3 - 2
misago/middleware/bruteforce.py

@@ -1,5 +1,6 @@
 from datetime import timedelta
 from datetime import timedelta
 from django.utils import timezone
 from django.utils import timezone
+from misago.conf import settings
 from misago.models import SignInAttempt
 from misago.models import SignInAttempt
 
 
 class JamCache(object):
 class JamCache(object):
@@ -9,8 +10,8 @@ class JamCache(object):
     
     
     def check_for_updates(self, request):
     def check_for_updates(self, request):
         if self.expires < timezone.now():
         if self.expires < timezone.now():
-            self.jammed = SignInAttempt.objects.is_jammed(request.settings, request.session.get_ip(request))
-            self.expires = timezone.now() + timedelta(minutes=request.settings['jams_lifetime'])
+            self.jammed = SignInAttempt.objects.is_jammed(request.session.get_ip(request))
+            self.expires = timezone.now() + timedelta(minutes=settings.jams_lifetime)
             return True
             return True
         return False
         return False
 
 

+ 0 - 5
misago/middleware/settings.py

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

+ 3 - 3
misago/middleware/user.py

@@ -1,6 +1,6 @@
-from django.conf import settings
 from django.utils import timezone
 from django.utils import timezone
 from django.utils.translation import ugettext_lazy as _
 from django.utils.translation import ugettext_lazy as _
+from misago.conf import settings
 from misago.messages import Message
 from misago.messages import Message
 from misago.onlines import MembersOnline
 from misago.onlines import MembersOnline
 
 
@@ -21,9 +21,9 @@ class UserMiddleware(object):
             if request.session.remember_me:
             if request.session.remember_me:
                 request.messages.set_message(Message(_("Welcome back, %(username)s! We've signed you in automatically for your convenience.") % {'username': request.user.username}), 'info')
                 request.messages.set_message(Message(_("Welcome back, %(username)s! We've signed you in automatically for your convenience.") % {'username': request.user.username}), 'info')
         else:
         else:
-            set_timezone(request.settings['default_timezone'])
+            set_timezone(settings.default_timezone)
             request.session.rank = None
             request.session.rank = None
-        request.onlines = MembersOnline(request.settings['online_counting'], request.monitor, request.settings['online_counting_frequency'])
+        request.onlines = MembersOnline(settings.online_counting, request.monitor, settings.online_counting_frequency)
 
 
     def process_response(self, request, response):
     def process_response(self, request, response):
         try:
         try:

+ 20 - 17
misago/models/settingmodel.py

@@ -3,7 +3,6 @@ from django import forms
 from django.core import validators
 from django.core import validators
 from django.db import models
 from django.db import models
 from django.utils.translation import ugettext_lazy as _
 from django.utils.translation import ugettext_lazy as _
-from misago.forms import YesNoSwitch
 from misago.utils.timezones import tzlist
 from misago.utils.timezones import tzlist
 try:
 try:
     import cPickle as pickle
     import cPickle as pickle
@@ -13,7 +12,7 @@ except ImportError:
 class Setting(models.Model):
 class Setting(models.Model):
     setting = models.CharField(max_length=255, primary_key=True)
     setting = models.CharField(max_length=255, primary_key=True)
     group = models.ForeignKey('SettingsGroup', to_field='key')
     group = models.ForeignKey('SettingsGroup', to_field='key')
-    value = models.TextField(null=True, blank=True)
+    _value = models.TextField(db_column='value', null=True, blank=True)
     value_default = models.TextField(null=True, blank=True)
     value_default = models.TextField(null=True, blank=True)
     normalize_to = models.CharField(max_length=255)
     normalize_to = models.CharField(max_length=255)
     field = models.CharField(max_length=255)
     field = models.CharField(max_length=255)
@@ -29,33 +28,37 @@ class Setting(models.Model):
     def get_extra(self):
     def get_extra(self):
         return pickle.loads(base64.decodestring(self.extra))
         return pickle.loads(base64.decodestring(self.extra))
 
 
-    def get_value(self):
+    @property
+    def value(self):
         if self.normalize_to == 'array':
         if self.normalize_to == 'array':
-            return self.value.split(',')
+            return self._value.split(',')
         if self.normalize_to == 'integer':
         if self.normalize_to == 'integer':
-            return int(self.value)
+            return int(self._value)
         if self.normalize_to == 'float':
         if self.normalize_to == 'float':
-            return float(self.value)
+            return float(self._value)
         if self.normalize_to == 'boolean':
         if self.normalize_to == 'boolean':
-            return self.value == "1"
-        return self.value
+            return self._value == "1"
+        return self._value
 
 
-    def set_value(self, value):
+    @value.setter
+    def value(self, value):
         if self.normalize_to == 'array':
         if self.normalize_to == 'array':
-            self.value = ','.join(value)
+            self._value = ','.join(value)
         elif self.normalize_to == 'integer':
         elif self.normalize_to == 'integer':
-            self.value = int(value)
+            self._value = int(value)
         elif self.normalize_to == 'float':
         elif self.normalize_to == 'float':
-            self.value = float(value)
+            self._value = float(value)
         elif self.normalize_to == 'boolean':
         elif self.normalize_to == 'boolean':
-            self.value = 1 if value else 0
+            self._value = 1 if value else 0
         else:
         else:
-            self.value = value
-        if not self.value and self.value_default:
-            self.value = self.value_default
-        return self.value
+            self._value = value
+        if not self._value and self.value_default:
+            self._value = self.value_default
+        return self._value
 
 
     def get_field(self):
     def get_field(self):
+        from misago.forms import YesNoSwitch
+        
         extra = self.get_extra()
         extra = self.get_extra()
 
 
         # Set validators
         # Set validators

+ 6 - 5
misago/models/signinattemptmodel.py

@@ -1,6 +1,7 @@
 from datetime import timedelta
 from datetime import timedelta
 from django.db import models
 from django.db import models
 from django.utils import timezone
 from django.utils import timezone
+from misago.conf import settings
 
 
 class SignInAttemptsManager(models.Manager):
 class SignInAttemptsManager(models.Manager):
     """
     """
@@ -13,19 +14,19 @@ class SignInAttemptsManager(models.Manager):
         attempt = SignInAttempt(ip=ip, date=timezone.now())
         attempt = SignInAttempt(ip=ip, date=timezone.now())
         attempt.save(force_insert=True)
         attempt.save(force_insert=True)
 
 
-    def is_jammed(self, settings, ip):
+    def is_jammed(self, ip):
         # Limit is off, dont jam IPs?
         # Limit is off, dont jam IPs?
-        if settings['attempts_limit'] == 0:
+        if settings.attempts_limit == 0:
             return False
             return False
         # Check jam
         # Check jam
-        if settings['jams_lifetime'] > 0:
+        if settings.jams_lifetime > 0:
             attempts = SignInAttempt.objects.filter(
             attempts = SignInAttempt.objects.filter(
-                                                    date__gt=timezone.now() - timedelta(minutes=settings['jams_lifetime']),
+                                                    date__gt=timezone.now() - timedelta(minutes=settings.jams_lifetime),
                                                     ip=ip
                                                     ip=ip
                                                     )
                                                     )
         else:
         else:
             attempts = SignInAttempt.objects.filter(ip=ip)
             attempts = SignInAttempt.objects.filter(ip=ip)
-        return attempts.count() > settings['attempts_limit']
+        return attempts.count() > settings.attempts_limit
 
 
 
 
 class SignInAttempt(models.Model):
 class SignInAttempt(models.Model):

+ 9 - 16
misago/models/usermodel.py

@@ -3,7 +3,6 @@ from datetime import timedelta
 import math
 import math
 from random import choice
 from random import choice
 from path import path
 from path import path
-from django.conf import settings
 from django.contrib.auth.hashers import (
 from django.contrib.auth.hashers import (
     check_password, make_password, is_password_usable, UNUSABLE_PASSWORD)
     check_password, make_password, is_password_usable, UNUSABLE_PASSWORD)
 from django.core.cache import cache, InvalidCacheBackendError
 from django.core.cache import cache, InvalidCacheBackendError
@@ -14,6 +13,7 @@ from django.template import RequestContext
 from django.utils import timezone as tz_util
 from django.utils import timezone as tz_util
 from django.utils.translation import ugettext_lazy as _
 from django.utils.translation import ugettext_lazy as _
 from misago.acl.builder import acl
 from misago.acl.builder import acl
+from misago.conf import settings
 from misago.signals import delete_user_content, rename_user, sync_user_profile
 from misago.signals import delete_user_content, rename_user, sync_user_profile
 from misago.template.loader import render_to_string
 from misago.template.loader import render_to_string
 from misago.utils.avatars import avatar_size
 from misago.utils.avatars import avatar_size
@@ -44,14 +44,7 @@ class UserManager(models.Manager):
         if activation > 0:
         if activation > 0:
             token = random_string(12)
             token = random_string(12)
 
 
-        try:
-            db_settings = request.settings
-        except AttributeError:
-            from misago.dbsettings import DBSettings
-            db_settings = DBSettings()
-
-        if timezone == False:
-            timezone = db_settings['default_timezone']
+        timezone = timezone or settings.default_timezone
 
 
         # Get first rank
         # Get first rank
         try:
         try:
@@ -70,17 +63,17 @@ class UserManager(models.Manager):
                         token=token,
                         token=token,
                         timezone=timezone,
                         timezone=timezone,
                         rank=default_rank,
                         rank=default_rank,
-                        subscribe_start=db_settings['subscribe_start'],
-                        subscribe_reply=db_settings['subscribe_reply'],
+                        subscribe_start=settings.subscribe_start,
+                        subscribe_reply=settings.subscribe_reply,
                         )
                         )
 
 
-        validate_username(username, db_settings)
-        validate_password(password, db_settings)
+        validate_username(username, settings)
+        validate_password(password, settings)
         new_user.set_username(username)
         new_user.set_username(username)
         new_user.set_email(email)
         new_user.set_email(email)
         new_user.set_password(password)
         new_user.set_password(password)
         new_user.full_clean()
         new_user.full_clean()
-        new_user.default_avatar(db_settings)
+        new_user.default_avatar()
         new_user.save(force_insert=True)
         new_user.save(force_insert=True)
 
 
         # Set user roles?
         # Set user roles?
@@ -232,8 +225,8 @@ class User(models.Model):
         self.avatar_type = 'gallery'
         self.avatar_type = 'gallery'
         self.avatar_image = '/'.join(path(choice(avatars_list)).splitall()[-2:])
         self.avatar_image = '/'.join(path(choice(avatars_list)).splitall()[-2:])
 
 
-    def default_avatar(self, db_settings):
-        if db_settings['default_avatar'] == 'gallery':
+    def default_avatar(self):
+        if settings.default_avatar == 'gallery':
             try:
             try:
                 avatars_list = []
                 avatars_list = []
                 try:
                 try:

+ 2 - 2
misago/sessions.py

@@ -1,6 +1,5 @@
 from hashlib import md5
 from hashlib import md5
 from datetime import timedelta
 from datetime import timedelta
-from django.conf import settings
 from django.contrib.sessions.backends.base import SessionBase, CreateError
 from django.contrib.sessions.backends.base import SessionBase, CreateError
 from django.db import IntegrityError
 from django.db import IntegrityError
 from django.db.models.loading import cache as model_cache
 from django.db.models.loading import cache as model_cache
@@ -8,6 +7,7 @@ from django.utils import timezone
 from django.utils.crypto import salted_hmac
 from django.utils.crypto import salted_hmac
 from django.utils.encoding import force_unicode
 from django.utils.encoding import force_unicode
 from misago.auth import auth_remember, AuthException
 from misago.auth import auth_remember, AuthException
+from misago.conf import settings
 from misago.models import Session, Token, Guest, User
 from misago.models import Session, Token, Guest, User
 from misago.utils.strings import random_string
 from misago.utils.strings import random_string
 
 
@@ -156,7 +156,7 @@ class HumanSession(MisagoSession):
                                                     admin=request.firewall.admin
                                                     admin=request.firewall.admin
                                                     )
                                                     )
             # IP invalid
             # IP invalid
-            if request.settings.sessions_validate_ip and self._session_rk.ip != self._ip:
+            if settings.sessions_validate_ip and self._session_rk.ip != self._ip:
                 raise IncorrectSessionException()
                 raise IncorrectSessionException()
             
             
             # Session expired
             # Session expired

+ 0 - 1
misago/settings_base.py

@@ -109,7 +109,6 @@ MIDDLEWARE_CLASSES = (
     'misago.middleware.heartbeat.HeartbeatMiddleware',
     'misago.middleware.heartbeat.HeartbeatMiddleware',
     'debug_toolbar.middleware.DebugToolbarMiddleware',
     'debug_toolbar.middleware.DebugToolbarMiddleware',
     'misago.middleware.cookiejar.CookieJarMiddleware',
     'misago.middleware.cookiejar.CookieJarMiddleware',
-    'misago.middleware.settings.SettingsMiddleware',
     'misago.middleware.monitor.MonitorMiddleware',
     'misago.middleware.monitor.MonitorMiddleware',
     'misago.middleware.theme.ThemeMiddleware',
     'misago.middleware.theme.ThemeMiddleware',
     'misago.middleware.firewalls.FirewallMiddleware',
     'misago.middleware.firewalls.FirewallMiddleware',

+ 0 - 1
misago/templatetags/django2jinja.py

@@ -3,7 +3,6 @@ import urllib
 from django.contrib.humanize.templatetags.humanize import (intcomma as intcomma_func,
 from django.contrib.humanize.templatetags.humanize import (intcomma as intcomma_func,
                                                            intword as intword_func)
                                                            intword as intword_func)
 from django_jinja.library import Library
 from django_jinja.library import Library
-from django.conf import settings
 from misago.utils.strings import slugify
 from misago.utils.strings import slugify
 
 
 register = Library()
 register = Library()

+ 13 - 13
misago/validators.py

@@ -1,7 +1,7 @@
 import re
 import re
-from django.conf import settings
 from django.core.exceptions import ValidationError
 from django.core.exceptions import ValidationError
 from django.utils.translation import ungettext, ugettext_lazy as _
 from django.utils.translation import ungettext, ugettext_lazy as _
+from misago.conf import settings
 from misago.models import Ban
 from misago.models import Ban
 from misago.utils.strings import slugify
 from misago.utils.strings import slugify
 
 
@@ -18,25 +18,25 @@ class validate_sluggable(object):
             raise ValidationError(self.error_long)
             raise ValidationError(self.error_long)
 
 
 
 
-def validate_username(value, db_settings):
+def validate_username(value):
     value = unicode(value).strip()
     value = unicode(value).strip()
 
 
-    if len(value) < db_settings['username_length_min']:
+    if len(value) < settings.username_length_min:
         raise ValidationError(ungettext(
         raise ValidationError(ungettext(
             'Username must be at least one character long.',
             'Username must be at least one character long.',
             'Username must be at least %(count)d characters long.',
             'Username must be at least %(count)d characters long.',
-            db_settings['username_length_min']
+            settings.username_length_min
         ) % {
         ) % {
-            'count': db_settings['username_length_min'],
+            'count': settings.username_length_min,
         })
         })
 
 
-    if len(value) > db_settings['username_length_max']:
+    if len(value) > settings.username_length_max:
         raise ValidationError(ungettext(
         raise ValidationError(ungettext(
             'Username cannot be longer than one characters.',
             'Username cannot be longer than one characters.',
             'Username cannot be longer than %(count)d characters.',
             'Username cannot be longer than %(count)d characters.',
-            db_settings['username_length_max']
+            settings.username_length_max
         ) % {
         ) % {
-            'count': db_settings['username_length_max'],
+            'count': settings.username_length_max,
         })
         })
 
 
     if settings.UNICODE_USERNAMES:
     if settings.UNICODE_USERNAMES:
@@ -50,19 +50,19 @@ def validate_username(value, db_settings):
         raise ValidationError(_("This username is forbidden."))
         raise ValidationError(_("This username is forbidden."))
 
 
 
 
-def validate_password(value, db_settings):
+def validate_password(value):
     value = unicode(value).strip()
     value = unicode(value).strip()
 
 
-    if len(value) < db_settings['password_length']:
+    if len(value) < settings.password_length:
         raise ValidationError(ungettext(
         raise ValidationError(ungettext(
             'Correct password has to be at least one character long.',
             'Correct password has to be at least one character long.',
             'Correct password has to be at least %(count)d characters long.',
             'Correct password has to be at least %(count)d characters long.',
-            db_settings['password_length']
+            settings.password_length
         ) % {
         ) % {
-            'count': db_settings['password_length'],
+            'count': settings.password_length,
         })
         })
 
 
-    for test in db_settings['password_complexity']:
+    for test in settings.password_complexity:
         if test in ('case', 'digits', 'special'):
         if test in ('case', 'digits', 'special'):
             if not re.search('[a-zA-Z]', value):
             if not re.search('[a-zA-Z]', value):
                 raise ValidationError(_("Password must contain alphabetical characters."))
                 raise ValidationError(_("Password must contain alphabetical characters."))