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.db.models import Q
 from django.shortcuts import redirect
@@ -6,6 +5,7 @@ from django.template import RequestContext
 from django.utils.translation import ugettext as _
 from misago.admin import site
 from misago.apps.admin.widgets import *
+from misago.conf import settings
 from misago.models import Newsletter, User
 from misago.shortcuts import render_to_response
 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)]:
             tokens = {
-              '{{ board_name }}': request.settings.board_name,
+              '{{ board_name }}': settings.board_name,
               '{{ username }}': user.username,
               '{{ user_url }}': django_reverse('user', kwargs={'username': user.username_slug, 'user': user.pk}),
               '{{ 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.template import RequestContext
 from django.utils.translation import ungettext, ugettext as _
+from misago.conf import settings
 from misago.forms import Form, FormLayout, FormFields
 from misago.messages import Message
 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)
         if form.is_valid():
             for setting in form.cleaned_data.keys():
-                request.settings[setting] = form.cleaned_data[setting]
+                settings[setting] = form.cleaned_data[setting]
             cache.delete('settings')
             request.messages.set_flash(Message(_('Configuration has been changed.')), 'success', 'admin_settings')
             return redirect(reverse('admin_settings', kwargs={

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

@@ -1,8 +1,8 @@
 from PIL import Image
-from django.conf import settings
 from django.core.exceptions import ValidationError
 from django.utils.translation import ugettext_lazy as _
 from django import forms
+from misago.conf import settings
 from misago.forms import Form, YesNoSwitch
 from misago.models import Rank, Role, User
 from misago.validators import validate_username, validate_password, validate_email
@@ -80,7 +80,7 @@ class UserForm(Form):
 
     def clean_username(self):
         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'])
         try:
             self.user.full_clean()
@@ -99,7 +99,7 @@ class UserForm(Form):
 
     def clean_new_password(self):
         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'])
             try:
                 self.user.full_clean()
@@ -157,7 +157,7 @@ class NewUserForm(Form):
         super(NewUserForm, self).__init__(*args, **kwargs)
 
     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.set_username(self.cleaned_data['username'])
         try:
@@ -182,7 +182,7 @@ class NewUserForm(Form):
             new_user.full_clean()
         except ValidationError as 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']
 
 

+ 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 misago.admin import site
 from misago.apps.admin.widgets import *
+from misago.conf import settings
 from misago.markdown import signature_markdown
 from misago.models import Forum, User
 from misago.utils.strings import random_string
@@ -160,7 +161,7 @@ class List(ListWidget):
     def action_remove_locks(self, items, checked):
         for user in items:
             if user.pk in checked:
-                user.default_avatar(self.request.settings)
+                user.default_avatar()
                 user.avatar_ban = False
                 user.signature_ban = False
                 user.save(force_update=True)
@@ -245,7 +246,7 @@ class New(FormWidget):
                                             form.cleaned_data['username'],
                                             form.cleaned_data['email'],
                                             form.cleaned_data['password'],
-                                            self.request.settings['default_timezone'],
+                                            settings.default_timezone,
                                             self.request.META['REMOTE_ADDR'],
                                             no_roles=True,
                                             request=self.request,
@@ -326,7 +327,7 @@ class Edit(FormWidget):
             if form.cleaned_data['avatar_ban']:
                 target.lock_avatar()
             else:
-                target.default_avatar(self.request.settings)
+                target.default_avatar()
         target.avatar_ban = form.cleaned_data['avatar_ban']
 
         # 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.template import RequestContext
 from django.utils import timezone
+from misago.conf import settings
 from misago.shortcuts import render_to_response
 from misago.models import Forum, Post, Rank, Session, Thread
 from misago.readstrackers import ForumsTracker
@@ -9,15 +10,15 @@ from misago.readstrackers import ForumsTracker
 def index(request):
     # Threads ranking
     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')
         if popular_threads == 'nada':
             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_slug = thread.forum.slug
                 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 = request.onlines.stats(request)
@@ -41,7 +42,7 @@ def index(request):
             ranks_list.append(rank_entry)
             ranks_dict[rank.pk] = rank_entry
         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:
                     ranks_dict[session.user.rank_id]['online'].append(session.user)
                     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]['pks'].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 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():
         for rank in ranks_list:
             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.template import RequestContext
 from django.utils import timezone
+from misago.conf import settings
 from misago.models import Forum, Thread
 from misago.shortcuts import render_to_response
 from misago.utils.pagination import make_pagination
@@ -17,7 +18,7 @@ def new_threads(request, page=0):
         return redirect(reverse('new_threads'))
 
     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')
 
     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.template import RequestContext
 from django.utils import timezone
+from misago.conf import settings
 from misago.models import Forum, Thread
 from misago.shortcuts import render_to_response
 from misago.utils.pagination import make_pagination
@@ -17,7 +18,7 @@ def popular_threads(request, page=0):
         return redirect(reverse('popular_threads'))
 
     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')
 
     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.utils.translation import ugettext as _
 from misago.apps.threadtype.list import ThreadsListBaseView, ThreadsListModeration
+from misago.conf import settings
 from misago.models import Forum, Thread
 from misago.readstrackers import ThreadsTracker
 from misago.utils.pagination import make_pagination
@@ -23,12 +24,12 @@ class ThreadsListView(ThreadsListBaseView, ThreadsListModeration, TypeMixin):
         qs_threads = self.threads_queryset()
 
         # 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')
 
         self.count = qs_threads.count()
         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:
             return self.threads_list_redirect()
 

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

@@ -1,13 +1,14 @@
 from django.core.urlresolvers import reverse
 from django.shortcuts import redirect
 from django.utils.translation import ugettext as _
+from misago.conf import settings
 from misago.acl.exceptions import ACLError404
 
 class TypeMixin(object):
     type_prefix = 'private_thread'
 
     def type_available(self):
-        return self.request.settings['enable_private_threads']
+        return settings.enable_private_threads
 
     def check_permissions(self):
         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.http import Http404
 from django.shortcuts import redirect
 from django.template import RequestContext
 from misago.apps.errors import error403, error404
+from misago.conf import settings
 from misago.forms import FormFields
 from misago.messages import Message
 from misago.models import Rank, User
@@ -81,7 +81,7 @@ def list(request, slug=None, page=0):
             users = User.objects.filter(rank=active_rank)
             items_total = users.count()
             try:
-                pagination = make_pagination(page, items_total, request.settings['profiles_per_list'])
+                pagination = make_pagination(page, items_total, settings.profiles_per_list)
             except Http404:
                 if not default_rank and active_rank:
                     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.core.exceptions import ValidationError
 from django.utils.translation import ugettext_lazy as _
+from misago.conf import settings
 from misago.forms import Form, QACaptchaField, ReCaptchaField
 from misago.models import User
 from misago.utils.timezones import tzlist
@@ -28,7 +29,7 @@ class UserRegisterForm(Form):
         self.layout = [
                       (
                        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,
@@ -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.layout[3]
         
     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.set_username(self.cleaned_data['username'])
         try:
@@ -69,7 +70,7 @@ class UserRegisterForm(Form):
         return self.cleaned_data['email']
         
     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.set_password(self.cleaned_data['password'])
         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.translation import ugettext as _
 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.forms import FormLayout
 from misago.messages import Message
@@ -17,7 +18,7 @@ from misago.apps.register.forms import UserRegisterForm
 @block_authenticated
 @block_jammed
 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')
     
     message = None
@@ -25,9 +26,9 @@ def form(request):
         form = UserRegisterForm(request.POST, request=request)
         if form.is_valid():
             need_activation = 0
-            if request.settings['account_activation'] == 'user':
+            if settings.account_activation == 'user':
                 need_activation = User.ACTIVATION_USER
-            if request.settings['account_activation'] == 'admin':
+            if settings.account_activation == 'admin':
                 need_activation = User.ACTIVATION_ADMIN
                 
             new_user = User.objects.create_user(
@@ -68,10 +69,10 @@ def form(request):
             return redirect(reverse('index'))
         else:
             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))
             # 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()
                 return redirect(reverse('register'))
     else:

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

@@ -5,6 +5,7 @@ from django.http import Http404
 from django.shortcuts import redirect
 from django.utils.translation import ugettext as _
 from misago.apps.threadtype.list import ThreadsListBaseView, ThreadsListModeration
+from misago.conf import settings
 from misago.messages import Message
 from misago.models import Forum, Thread, Post
 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')
 
         # 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')
             threads = threads.prefetch_related('start_poster', 'last_poster')
 
@@ -31,7 +32,7 @@ class ThreadsListView(ThreadsListBaseView, ThreadsListModeration, TypeMixin):
         self.count = qs_threads.count()
 
         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:
             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.query import SearchQuerySet, RelatedSearchQuerySet
 from misago.acl.exceptions import ACLError403, ACLError404
+from misago.conf import settings
 from misago.decorators import block_crawlers
 from misago.forms import FormFields
 from misago.models import Forum, Thread, Post, User
@@ -32,7 +33,7 @@ class ViewBase(object):
 
         if self.request.POST.get('search_in') == 'private':
             if not (self.request.acl.private_threads.can_participate()
-                    and self.request.settings['enable_private_threads']):
+                    and settings.enable_private_threads):
                 raise ACLError404()
             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':

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

@@ -9,6 +9,7 @@ from misago.forms import FormLayout
 from misago.messages import Message
 import misago.auth as auth
 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,
                             block_guest, block_jammed, check_csrf)
 from misago.models import SignInAttempt, Token
@@ -29,7 +30,7 @@ def signin(request):
     if request.method == 'POST':
         form = SignInForm(
                           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
                           )
 
@@ -53,7 +54,7 @@ def signin(request):
                 sign_user_in(request, user)
                 remember_me_token = False
 
-                if not request.firewall.admin and request.settings['remember_me_allow'] and form.cleaned_data['user_remember_me']:
+                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(
                                         id=remember_me_token,
@@ -77,14 +78,14 @@ def signin(request):
                     SignInAttempt.objects.register_attempt(request.session.get_ip(request))
 
                     # Have we jammed our account?
-                    if SignInAttempt.objects.is_jammed(request.settings, request.session.get_ip(request)):
+                    if SignInAttempt.objects.is_jammed(request.session.get_ip(request)):
                         request.jam.expires = timezone.now()
                         return redirect(reverse('sign_in'))
         else:
             message = Message(form.non_field_errors()[0], 'error')
     else:
         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
                           )
     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.utils.translation import ugettext as _
 from misago.apps.threadtype.list import ThreadsListBaseView, ThreadsListModeration
+from misago.conf import settings
 from misago.models import Forum, Thread
 from misago.readstrackers import ThreadsTracker
 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])])
 
         # 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')
             threads = threads.prefetch_related('start_poster', 'last_poster')
 
@@ -35,7 +36,7 @@ class ThreadsListView(ThreadsListBaseView, ThreadsListModeration, TypeMixin):
         self.count = qs_threads.count()
 
         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:
             return self.threads_list_redirect()
 

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

@@ -1,6 +1,7 @@
 from django.core.urlresolvers import reverse
 from django.http import Http404
 from django.shortcuts import redirect
+from misago.conf import settings
 from misago.models import Forum, Thread, Post
 from misago.utils.pagination import page_number
 
@@ -51,7 +52,7 @@ class ViewBase(object):
     def redirect_to_post(self, post, type_prefix=None):
         type_prefix = type_prefix or self.type_prefix
         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:
             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))

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

@@ -1,10 +1,10 @@
-from django.conf import settings
 from django.core.urlresolvers import reverse
 from django.shortcuts import redirect
 from django.utils import timezone
 from django.utils.translation import ugettext as _
 from misago.acl.exceptions import ACLError403, ACLError404
 from misago.apps.errors import error403, error404
+from misago.conf import settings
 from misago.decorators import block_guest, check_csrf
 from misago.markdown import post_markdown
 from misago.messages import Message
@@ -211,13 +211,13 @@ class UpvotePostBaseView(JumpView):
                 request.user.karma_given_p += 1
                 if self.post.user_id:
                     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:
                 self.post.downvotes += 1
                 request.user.karma_given_n += 1
                 if self.post.user_id:
                     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)
             request.user.save(force_update=True)
             if self.post.user_id:

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

@@ -1,5 +1,6 @@
 from django import forms
 from django.utils.translation import ugettext_lazy as _
+from misago.conf import settings
 from misago.forms import Form, ForumChoiceField
 from misago.models import Forum
 from misago.validators import validate_sluggable
@@ -41,7 +42,7 @@ class MergeThreadsForm(Form, ValidateThreadNameMixin):
     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['thread_name'] = forms.CharField(
-                                                     max_length=self.request.settings['thread_name_max'],
+                                                     max_length=settings.thread_name_max,
                                                      initial=self.threads[-1].name,
                                                      validators=[validate_sluggable(
                                                                                     _("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.utils import timezone
 from django.utils.translation import ungettext_lazy, ugettext_lazy as _
+from misago.conf import settings
 from misago.utils.strings import slugify
 
 class FloodProtectionMixin(object):
@@ -28,28 +29,28 @@ class ValidateThreadNameMixin(object):
     def clean_thread_name(self):
         data = self.cleaned_data['thread_name']
         slug = slugify(data)
-        if len(slug) < self.request.settings['thread_name_min']:
+        if len(slug) < settings.thread_name_min:
             raise forms.ValidationError(ungettext_lazy(
                                                   "Thread name must contain at least one alpha-numeric character.",
                                                   "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(
                                                   "Thread name cannot be longer than %(count)d character.",
                                                   "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
 
 
 class ValidatePostLengthMixin(object):
     def clean_post(self):
         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(
                                                   "Post content cannot be empty.",
                                                   "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

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

@@ -1,10 +1,10 @@
 from django import forms
-from django.conf import settings
 from django.utils import timezone
 from django.utils.translation import ugettext_lazy as _
 from misago.apps.threadtype.mixins import (FloodProtectionMixin,
                                            ValidateThreadNameMixin,
                                            ValidatePostLengthMixin)
+from misago.conf import settings
 from misago.forms import Form
 from misago.validators import validate_sluggable
 
@@ -77,7 +77,7 @@ class NewThreadForm(PostingForm, ValidateThreadNameMixin):
     def finalize_form(self):
         super(NewThreadForm, self).finalize_form()
         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."),
                                                                                     _("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 django.utils import timezone
 from django.utils.translation import ugettext as _
+from misago.conf import settings
 from misago.markdown import post_markdown
 from misago.models import Post
 from misago.utils.datesformats import date
@@ -36,8 +37,8 @@ class NewReplyBaseView(PostingBaseView):
         # Count merge diff and see if we are merging
         merge_diff = (now - self.thread.last)
         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_post.moderated == moderation):
             merged = True
@@ -74,7 +75,7 @@ class NewReplyBaseView(PostingBaseView):
 
             # Increase thread score
             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
         if not moderation and not merged:
@@ -85,8 +86,8 @@ class NewReplyBaseView(PostingBaseView):
         
         # Reward user for posting new reply?
         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
         if not moderation and not merged:
@@ -99,9 +100,9 @@ class NewReplyBaseView(PostingBaseView):
             self.thread.weight = form.cleaned_data['thread_weight']
 
         # 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 self.thread.replies >= self.request.settings.thread_length):
+                and self.thread.replies >= settings.thread_length):
             self.thread.closed = True
             self.thread.set_checkpoint(self.request, 'limit')
         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 misago.apps.threadtype.posting.base import PostingBaseView
 from misago.apps.threadtype.posting.forms import NewThreadForm
+from misago.conf import settings
 from misago.markdown import post_markdown
 from misago.models import Forum, Thread, Post
 from misago.utils.strings import slugify
@@ -29,7 +30,7 @@ class NewThreadBaseView(PostingBaseView):
                                             start=now,
                                             last=now,
                                             moderated=moderation,
-                                            score=self.request.settings['thread_ranking_initial_score'],
+                                            score=settings.thread_ranking_initial_score,
                                             )
 
         # Create our post
@@ -71,8 +72,8 @@ class NewThreadBaseView(PostingBaseView):
 
         # Reward user for posting new thread?
         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
         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.utils.translation import ugettext_lazy as _
 from misago.acl.exceptions import ACLError403, ACLError404
+from misago.conf import settings
 from misago.forms import Form, ForumChoiceField
 from misago.models import Forum, Thread
 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."),
                                                                                     _("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 misago.acl.exceptions import ACLError403, ACLError404
 from misago.apps.errors import error403, error404
+from misago.conf import settings
 from misago.forms import Form, FormLayout, FormFields
 from misago.markdown import emojis
 from misago.messages import Message
@@ -43,12 +44,12 @@ class ThreadBaseView(ViewBase):
         self.posts = self.posts.order_by('id')
 
         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:
             return redirect(reverse(self.type_prefix, kwargs={'thread': self.thread.pk, 'slug': self.thread.slug}))
 
         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]
             posts_len = len(self.posts)
             checkpoints_range = self.posts[posts_len - 1].date

+ 3 - 2
misago/apps/tos.py

@@ -1,9 +1,10 @@
 from django.template import RequestContext
-from misago.shortcuts import render_to_response
 from misago.apps.errors import error404
+from misago.conf import settings
+from misago.shortcuts import render_to_response
 
 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 render_to_response('forum_tos.html',
                               context_instance=RequestContext(request));

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

@@ -1,8 +1,8 @@
 from PIL import Image
 from django import forms
-from django.conf import settings
 from django.core.exceptions import ValidationError
 from django.utils.translation import ugettext_lazy as _
+from misago.conf import settings
 from misago.forms import Form
 
 class UploadAvatarForm(Form):
@@ -21,11 +21,11 @@ class UploadAvatarForm(Form):
     def clean_avatar_upload(self):
         image = self.cleaned_data.get('avatar_upload', False)
         if image:
-            if image._size > self.request.settings.upload_limit * 1024:
-                if self.request.settings.upload_limit > 1024:
-                    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:
-                    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})
         else:
             raise ValidationError(_("Couldn't read uploaded image"))

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

@@ -1,13 +1,13 @@
 from path import path
 from PIL import Image
 from zipfile import is_zipfile
-from django.conf import settings
 from django.core.exceptions import ValidationError
 from django.core.urlresolvers import reverse
 from django.shortcuts import redirect
 from django.utils.encoding import smart_str
 from django.utils.translation import ugettext as _
 from misago.apps.errors import error404
+from misago.conf import settings
 from misago.decorators import block_guest
 from misago.forms import FormLayout
 from misago.messages import Message
@@ -41,7 +41,7 @@ def avatar(request):
 @block_guest
 @avatar_view
 def gravatar(request):
-    if not 'gravatar' in request.settings.avatars_types:
+    if not 'gravatar' in settings.avatars_types:
         return error404(request)
     if request.user.avatar_type != 'gravatar':
         if request.csrf.request_secure(request):
@@ -57,7 +57,7 @@ def gravatar(request):
 @block_guest
 @avatar_view
 def gallery(request):
-    if not 'gallery' in request.settings.avatars_types:
+    if not 'gallery' in settings.avatars_types:
         return error404(request)
 
     allowed_avatars = []
@@ -103,7 +103,7 @@ def gallery(request):
 @block_guest
 @avatar_view
 def upload(request):
-    if not 'upload' in request.settings.avatars_types:
+    if not 'upload' in settings.avatars_types:
         return error404(request)
     message = request.messages.get_message('usercp_avatar')
     if request.method == 'POST':
@@ -153,7 +153,7 @@ def upload(request):
                 return redirect(reverse('usercp_avatar'))
             except ValidationError:
                 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')
         else:
             message = Message(form.non_field_errors()[0], 'error')
@@ -170,7 +170,7 @@ def upload(request):
 @block_guest
 @avatar_view
 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)
 
     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):
         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']
 
     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
         if org_username == self.cleaned_data['username']:
             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'])
         try:
             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.template import RequestContext
 from django.utils.translation import ugettext as _
+from misago.conf import settings
 from misago.decorators import block_guest
 from misago.forms import Form, FormLayout, FormFields
 from misago.messages import Message
@@ -16,22 +17,22 @@ from misago.utils.pagination import make_pagination
 def watched_threads(request, page=0, new=False):
     # Find mode and fetch threads
     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'))
     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')
     if new:
         queryset = queryset.filter(last_read__lt=F('thread__last'))
     count = queryset.count()
     try:
-        pagination = make_pagination(page, count, request.settings.threads_per_page)
+        pagination = make_pagination(page, count, settings.threads_per_page)
     except Http404:
         if new:
             return redirect(reverse('watched_threads_new'))
         return redirect(reverse('watched_threads'))
     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.prefetch_related('thread__forum', 'thread__start_poster', 'thread__last_poster')
     threads = []

+ 5 - 5
misago/auth.py

@@ -1,7 +1,7 @@
 from datetime import timedelta
-from django.conf import settings
 from django.utils import timezone
 from django.utils.translation import ugettext_lazy as _
+from misago.conf import settings
 from misago.models import Ban, SignInAttempt, Token, User
 
 """
@@ -70,7 +70,7 @@ def auth_remember(request, ip):
     """
     if request.firewall.admin:
         raise AuthException()
-    if SignInAttempt.objects.is_jammed(request.settings, ip):
+    if SignInAttempt.objects.is_jammed(ip):
         raise AuthException()
     cookie_token = settings.COOKIES_PREFIX + 'TOKEN'
     try:
@@ -85,12 +85,12 @@ def auth_remember(request, ip):
             raise AuthException()
 
         # See if token is not expired
-        token_expires = timezone.now() - timedelta(days=request.settings['remember_me_lifetime'])
-        if request.settings['remember_me_extensible'] and token_rk.accessed < token_expires:
+        token_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
             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
             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.admin import site
 from misago.models import Forum
@@ -28,7 +28,7 @@ def common(request):
             'messages' : request.messages.messages,
             'monitor': request.monitor,
             'request_path': request.get_full_path(),
-            'settings': request.settings,
+            'settings': SafeSettings(),
             'stopwatch': request.stopwatch.time(),
             'user': request.user,
             '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 django import forms
 from django.utils.translation import ugettext_lazy as _
+from misago.conf import settings
 
 class Form(forms.Form):
     """
@@ -27,17 +28,17 @@ class Form(forms.Form):
 
         # Kill captcha fields
         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']
         except KeyError:
             pass
         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']
             else:
                 # 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:
             pass
 
@@ -90,7 +91,7 @@ class Form(forms.Form):
         response = recaptcha_submit(
                                     self.request.POST.get('recaptcha_challenge_field'),
                                     self.request.POST.get('recaptcha_response_field'),
-                                    self.request.settings['recaptcha_private'],
+                                    settings.recaptcha_private,
                                     self.request.session.get_ip(self.request)
                                     ).is_valid
         if not response:
@@ -103,7 +104,7 @@ class Form(forms.Form):
         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."))
         self.request.session['captcha_passed'] = True
         return self.cleaned_data['captcha_qa']

+ 3 - 2
misago/forms/layouts.py

@@ -1,6 +1,7 @@
 from UserDict import IterableUserDict
 from recaptcha.client.captcha import displayhtml
 from django.utils import formats
+from misago.conf import settings
 
 class FormLayout(object):
     """
@@ -117,8 +118,8 @@ class FormFields(object):
             if widget_name == 'ReCaptchaWidget':
                 blueprint['widget'] = 'recaptcha'
                 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,
                                                           )}
 

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

@@ -1,6 +1,6 @@
 from django.core.management.base import BaseCommand, CommandError
 from django.db.models import F
-from misago.dbsettings import DBSettings
+from misago.conf import settings
 from misago.models import Rank, User
 
 class Command(BaseCommand):
@@ -29,9 +29,8 @@ class Command(BaseCommand):
                 defaulted_ranks = True
 
         # 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)
         else:
             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.db.models import F
-from misago.dbsettings import DBSettings
+from misago.conf import settings
 from misago.models import Thread
 
 class Command(BaseCommand):
@@ -9,9 +9,8 @@ class Command(BaseCommand):
     """
     help = 'Updates Popular Threads ranking'
     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)
             self.stdout.write('Thread ranking has been updated.\n')
         else:

+ 0 - 1
misago/markdown/parsers.py

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

+ 3 - 2
misago/middleware/bruteforce.py

@@ -1,5 +1,6 @@
 from datetime import timedelta
 from django.utils import timezone
+from misago.conf import settings
 from misago.models import SignInAttempt
 
 class JamCache(object):
@@ -9,8 +10,8 @@ class JamCache(object):
     
     def check_for_updates(self, request):
         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 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.translation import ugettext_lazy as _
+from misago.conf import settings
 from misago.messages import Message
 from misago.onlines import MembersOnline
 
@@ -21,9 +21,9 @@ class UserMiddleware(object):
             if request.session.remember_me:
                 request.messages.set_message(Message(_("Welcome back, %(username)s! We've signed you in automatically for your convenience.") % {'username': request.user.username}), 'info')
         else:
-            set_timezone(request.settings['default_timezone'])
+            set_timezone(settings.default_timezone)
             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):
         try:

+ 20 - 17
misago/models/settingmodel.py

@@ -3,7 +3,6 @@ from django import forms
 from django.core import validators
 from django.db import models
 from django.utils.translation import ugettext_lazy as _
-from misago.forms import YesNoSwitch
 from misago.utils.timezones import tzlist
 try:
     import cPickle as pickle
@@ -13,7 +12,7 @@ except ImportError:
 class Setting(models.Model):
     setting = models.CharField(max_length=255, primary_key=True)
     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)
     normalize_to = models.CharField(max_length=255)
     field = models.CharField(max_length=255)
@@ -29,33 +28,37 @@ class Setting(models.Model):
     def get_extra(self):
         return pickle.loads(base64.decodestring(self.extra))
 
-    def get_value(self):
+    @property
+    def value(self):
         if self.normalize_to == 'array':
-            return self.value.split(',')
+            return self._value.split(',')
         if self.normalize_to == 'integer':
-            return int(self.value)
+            return int(self._value)
         if self.normalize_to == 'float':
-            return float(self.value)
+            return float(self._value)
         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':
-            self.value = ','.join(value)
+            self._value = ','.join(value)
         elif self.normalize_to == 'integer':
-            self.value = int(value)
+            self._value = int(value)
         elif self.normalize_to == 'float':
-            self.value = float(value)
+            self._value = float(value)
         elif self.normalize_to == 'boolean':
-            self.value = 1 if value else 0
+            self._value = 1 if value else 0
         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):
+        from misago.forms import YesNoSwitch
+        
         extra = self.get_extra()
 
         # Set validators

+ 6 - 5
misago/models/signinattemptmodel.py

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

+ 9 - 16
misago/models/usermodel.py

@@ -3,7 +3,6 @@ from datetime import timedelta
 import math
 from random import choice
 from path import path
-from django.conf import settings
 from django.contrib.auth.hashers import (
     check_password, make_password, is_password_usable, UNUSABLE_PASSWORD)
 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.translation import ugettext_lazy as _
 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.template.loader import render_to_string
 from misago.utils.avatars import avatar_size
@@ -44,14 +44,7 @@ class UserManager(models.Manager):
         if activation > 0:
             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
         try:
@@ -70,17 +63,17 @@ class UserManager(models.Manager):
                         token=token,
                         timezone=timezone,
                         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_email(email)
         new_user.set_password(password)
         new_user.full_clean()
-        new_user.default_avatar(db_settings)
+        new_user.default_avatar()
         new_user.save(force_insert=True)
 
         # Set user roles?
@@ -232,8 +225,8 @@ class User(models.Model):
         self.avatar_type = 'gallery'
         self.avatar_image = '/'.join(path(choice(avatars_list)).splitall()[-2:])
 
-    def default_avatar(self, db_settings):
-        if db_settings['default_avatar'] == 'gallery':
+    def default_avatar(self):
+        if settings.default_avatar == 'gallery':
             try:
                 avatars_list = []
                 try:

+ 2 - 2
misago/sessions.py

@@ -1,6 +1,5 @@
 from hashlib import md5
 from datetime import timedelta
-from django.conf import settings
 from django.contrib.sessions.backends.base import SessionBase, CreateError
 from django.db import IntegrityError
 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.encoding import force_unicode
 from misago.auth import auth_remember, AuthException
+from misago.conf import settings
 from misago.models import Session, Token, Guest, User
 from misago.utils.strings import random_string
 
@@ -156,7 +156,7 @@ class HumanSession(MisagoSession):
                                                     admin=request.firewall.admin
                                                     )
             # 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()
             
             # Session expired

+ 0 - 1
misago/settings_base.py

@@ -109,7 +109,6 @@ MIDDLEWARE_CLASSES = (
     'misago.middleware.heartbeat.HeartbeatMiddleware',
     'debug_toolbar.middleware.DebugToolbarMiddleware',
     'misago.middleware.cookiejar.CookieJarMiddleware',
-    'misago.middleware.settings.SettingsMiddleware',
     'misago.middleware.monitor.MonitorMiddleware',
     'misago.middleware.theme.ThemeMiddleware',
     '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,
                                                            intword as intword_func)
 from django_jinja.library import Library
-from django.conf import settings
 from misago.utils.strings import slugify
 
 register = Library()

+ 13 - 13
misago/validators.py

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