Browse Source

Refactored monitor to behave like settings do. #161

Ralfp 12 years ago
parent
commit
0cfdc474ef

+ 3 - 2
misago/acl/builder.py

@@ -3,6 +3,7 @@ from django.core.cache import cache, InvalidCacheBackendError
 from django.utils.importlib import import_module
 from misago.forms import Form
 from misago.models import Forum, ForumRole
+from misago.monitor import monitor
 
 def build_form(request, role):
     form_type = type('ACLForm', (Form,), dict(layout=[]))
@@ -50,7 +51,7 @@ def acl(request, user):
     acl_key = user.make_acl_key()
     try:
         user_acl = cache.get(acl_key)
-        if user_acl.version != request.monitor['acl_version']:
+        if user_acl.version != monitor.acl_version:
             raise InvalidCacheBackendError()
     except (AttributeError, InvalidCacheBackendError):
         user_acl = build_acl(request, user.get_roles())
@@ -59,7 +60,7 @@ def acl(request, user):
 
 
 def build_acl(request, roles):
-    new_acl = ACL(request.monitor['acl_version'])
+    new_acl = ACL(monitor.acl_version)
     forums = Forum.objects.get(special='root').get_descendants().order_by('lft')
     perms = []
     forum_roles = {}

+ 1 - 1
misago/apps/activation/views.py

@@ -77,7 +77,7 @@ def activate(request, username="", user="0", token=""):
         sign_user_in(request, user)
 
         # Update monitor
-        User.objects.resync_monitor(request.monitor)
+        User.objects.resync_monitor()
 
         if current_activation == User.ACTIVATION_CREDENTIALS:
             return redirect_message(request, Message(_("%(username)s, your account has been successfully reactivated after change of sign-in credentials.") % {'username': user.username}), 'success')

+ 9 - 4
misago/apps/admin/bans/views.py

@@ -6,6 +6,7 @@ from misago.admin import site
 from misago.apps.admin.widgets import *
 from misago.messages import Message
 from misago.models import Ban
+from misago.monitor import monitor, UpdatingMonitor
 from misago.apps.admin.bans.forms import BanForm, SearchBansForm
 
 def reverse(route, target=None):
@@ -58,7 +59,8 @@ class List(ListWidget):
 
     def action_delete(self, items, checked):
         Ban.objects.filter(id__in=checked).delete()
-        self.request.monitor.increase('bans_version')
+        with UpdatingMonitor() as cm:
+            monitor.increase('bans_version')
         return Message(_('Selected bans have been lifted successfully.'), 'success'), reverse('admin_bans')
 
 
@@ -87,7 +89,8 @@ class New(FormWidget):
                       expires=form.cleaned_data['expires']
                      )
         new_ban.save(force_insert=True)
-        self.request.monitor.increase('bans_version')
+        with UpdatingMonitor() as cm:
+            monitor.increase('bans_version')
         return new_ban, Message(_('New Ban has been set.'), 'success')
 
 
@@ -126,7 +129,8 @@ class Edit(FormWidget):
         target.reason_admin = form.cleaned_data['reason_admin']
         target.expires = form.cleaned_data['expires']
         target.save(force_update=True)
-        self.request.monitor.increase('bans_version')
+        with UpdatingMonitor() as cm:
+            monitor.increase('bans_version')
         return target, Message(_('Changes in ban have been saved.'), 'success')
 
 
@@ -141,7 +145,8 @@ class Delete(ButtonWidget):
 
     def action(self, target):
         target.delete()
-        self.request.monitor.increase('bans_version')
+        with UpdatingMonitor() as cm:
+            monitor.increase('bans_version')
         if target.test == 0:
             return Message(_('E-mail and username Ban "%(ban)s" has been lifted.') % {'ban': target.ban}, 'success'), False
         if target.test == 1:

+ 7 - 3
misago/apps/admin/forumroles/views.py

@@ -6,6 +6,7 @@ from misago.admin import site
 from misago.apps.admin.widgets import *
 from misago.forms import Form, YesNoSwitch
 from misago.models import ForumRole
+from misago.monitor import monitor, UpdatingMonitor
 from misago.utils.strings import slugify
 from misago.apps.admin.forumroles.forms import ForumRoleForm
 
@@ -40,7 +41,8 @@ class List(ListWidget):
                 )
 
     def action_delete(self, items, checked):
-        self.request.monitor.increase('acl_version')
+        with UpdatingMonitor() as cm:
+            monitor.increase('acl_version')
         Role.objects.filter(id__in=checked).delete()
         return Message(_('Selected forum roles have been deleted successfully.'), 'success'), reverse('admin_roles_forums')
 
@@ -127,7 +129,8 @@ class ACL(FormWidget):
             raw_acl[perm] = form.cleaned_data[perm]
         target.permissions = raw_acl
         target.save(force_update=True)
-        self.request.monitor.increase('acl_version')
+        with UpdatingMonitor() as cm:
+            monitor.increase('acl_version')
 
         return target, Message(_('Forum Role "%(name)s" permissions have been changed.') % {'name': self.original_name}, 'success')
 
@@ -140,5 +143,6 @@ class Delete(ButtonWidget):
 
     def action(self, target):
         target.delete()
-        self.request.monitor.increase('acl_version')
+        with UpdatingMonitor() as cm:
+            monitor.increase('acl_version')
         return Message(_('Forum Role "%(name)s" has been deleted.') % {'name': _(target.name)}, 'success'), False

+ 12 - 8
misago/apps/admin/forums/views.py

@@ -9,6 +9,7 @@ from mptt.forms import TreeNodeChoiceField
 from misago.admin import site
 from misago.apps.admin.widgets import *
 from misago.models import Forum
+from misago.monitor import monitor, UpdatingMonitor
 from misago.shortcuts import render_to_response
 from misago.utils.strings import slugify
 from misago.apps.admin.forums.forms import NewNodeForm, CategoryForm, ForumForm, RedirectForm, DeleteForm
@@ -189,7 +190,8 @@ class NewNode(FormWidget):
 
         if form.cleaned_data['perms']:
             new_forum.copy_permissions(form.cleaned_data['perms'])
-            self.request.monitor.increase('acl_version')
+            with UpdatingMonitor() as cm:
+                monitor.increase('acl_version')
 
         self.request.session['forums_admin_preffs'] = {
             'parent': form.cleaned_data['parent'].pk,
@@ -304,19 +306,20 @@ class Edit(FormWidget):
             target.prune_last = form.cleaned_data['prune_last']
             target.pruned_archive = form.cleaned_data['pruned_archive']
 
-        if form.cleaned_data['parent'].pk != target.parent.pk:
-            target.move_to(form.cleaned_data['parent'], 'last-child')
-            self.request.monitor.increase('acl_version')
-
         target.save(force_update=True)
         Forum.objects.populate_tree(True)
 
         if form.cleaned_data['perms']:
             target.copy_permissions(form.cleaned_data['perms'])
 
-        if form.cleaned_data['parent'].pk != target.parent.pk or form.cleaned_data['perms']:
-            self.request.monitor.increase('acl_version')
+        with UpdatingMonitor() as cm:
+            if form.cleaned_data['parent'].pk != target.parent.pk:
+                target.move_to(form.cleaned_data['parent'], 'last-child')
+                monitor.increase('acl_version')
 
+            if form.cleaned_data['parent'].pk != target.parent.pk or form.cleaned_data['perms']:
+                monitor.increase('acl_version')
+                
         if self.original_name != target.name:
             target.sync_name()
 
@@ -373,5 +376,6 @@ class Delete(FormWidget):
                 Forum.objects.get(id=child.pk).delete()
         Forum.objects.get(id=target.pk).delete()
         Forum.objects.populate_tree(True)
-        self.request.monitor.increase('acl_version')
+        with UpdatingMonitor() as cm:
+            monitor.increase('acl_version')
         return target, Message(_('Forum "%(name)s" has been deleted.') % {'name': self.original_name}, 'success')

+ 5 - 4
misago/apps/admin/index.py

@@ -1,14 +1,15 @@
 from django.template import RequestContext
 from misago.models import Session
+from misago.monitor import monitor
 from misago.shortcuts import render_to_response
 
 def index(request):
     return render_to_response('index.html',
                               {
-                               'users': request.monitor['users'],
-                               'users_inactive': request.monitor['users_inactive'],
-                               'threads': request.monitor['threads'],
-                               'posts': request.monitor['posts'],
+                               'users': monitor.users,
+                               'users_inactive': monitor.users_inactive,
+                               'threads': monitor.threads,
+                               'posts': monitor.posts,
                                'admins': Session.objects.filter(user__isnull=False).filter(admin=1).order_by('user__username_slug').select_related('user'),
                               },
                               context_instance=RequestContext(request));

+ 1 - 1
misago/apps/admin/pruneusers/views.py

@@ -189,7 +189,7 @@ class Apply(FormWidget):
                                                                  '%(deleted)d users have been deleted.',
                                                                  deleted
                                                                  ) % {'deleted': deleted}), 'success', self.admin.id)
-                    User.objects.resync_monitor(request.monitor)
+                    User.objects.resync_monitor()
                 else:
                     request.messages.set_flash(Message(_("No users have been deleted.")), 'info', self.admin.id)
                 return redirect(reverse('admin_prune_users'))

+ 5 - 2
misago/apps/admin/roles/views.py

@@ -7,6 +7,7 @@ from misago.admin import site
 from misago.apps.admin.widgets import *
 from misago.forms import Form, YesNoSwitch
 from misago.models import Forum, ForumRole, Role
+from misago.monitor import monitor, UpdatingMonitor
 from misago.utils.strings import slugify
 from misago.apps.admin.roles.forms import RoleForm
 
@@ -110,7 +111,8 @@ class Edit(FormWidget):
         if self.request.user.is_god():
             target.protected = form.cleaned_data['protected']
         target.save(force_update=True)
-        self.request.monitor.increase('acl_version')
+        with UpdatingMonitor() as cm:
+            monitor.increase('acl_version')
         return target, Message(_('Changes in role "%(name)s" have been saved.') % {'name': self.original_name}, 'success')
 
 
@@ -226,7 +228,8 @@ class ACL(FormWidget):
             raw_acl[perm] = form.cleaned_data[perm]
         target.permissions = raw_acl
         target.save(force_update=True)
-        self.request.monitor.increase('acl_version')
+        with UpdatingMonitor() as cm:
+            monitor.increase('acl_version')
         
         return target, Message(_('Role "%(name)s" permissions have been changed.') % {'name': self.original_name}, 'success')
 

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

@@ -7,6 +7,7 @@ from misago.apps.admin.widgets import *
 from misago.conf import settings
 from misago.markdown import signature_markdown
 from misago.models import Forum, User
+from misago.monitor import monitor, UpdatingMonitor
 from misago.utils.strings import random_string
 from misago.apps.admin.users.forms import UserForm, NewUserForm, SearchUsersForm
 
@@ -94,7 +95,8 @@ class List(ListWidget):
     def action_activate(self, items, checked):
         for user in items:
             if user.pk in checked and user.activation > 0:
-                self.request.monitor.decrease('users_inactive')
+                with UpdatingMonitor() as cm:
+                    monitor.decrease('users_inactive')
                 user.activation = user.ACTIVATION_NONE
                 user.save(force_update=True)
                 user.email_user(
@@ -209,7 +211,7 @@ class List(ListWidget):
             forum.sync()
             forum.save(force_update=True)
         
-        User.objects.resync_monitor(self.request.monitor)
+        User.objects.resync_monitor()
         return Message(_('Selected users and their content have been deleted successfully.'), 'success'), reverse('admin_users')
 
     def action_delete(self, items, checked):
@@ -224,7 +226,7 @@ class List(ListWidget):
             if user.pk in checked:
                 user.delete()
 
-        User.objects.resync_monitor(self.request.monitor)
+        User.objects.resync_monitor()
         return Message(_('Selected users have been deleted successfully.'), 'success'), reverse('admin_users')
 
 
@@ -361,7 +363,7 @@ class Delete(ButtonWidget):
         if target.is_protected():
             return Message(_('You cannot delete protected member.'), 'error'), False
         target.delete()
-        User.objects.resync_monitor(self.request.monitor)
+        User.objects.resync_monitor()
         return Message(_('User "%(name)s" has been deleted.') % {'name': target.username}, 'success'), False
 
 

+ 1 - 1
misago/apps/register/views.py

@@ -65,7 +65,7 @@ def form(request):
                                     {'password': form.cleaned_data['password']}
                                     )
             
-            User.objects.resync_monitor(request.monitor)
+            User.objects.resync_monitor()
             return redirect(reverse('index'))
         else:
             message = Message(form.non_field_errors()[0], 'error')

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

@@ -8,6 +8,7 @@ from misago.apps.threadtype.list import ThreadsListBaseView, ThreadsListModerati
 from misago.conf import settings
 from misago.messages import Message
 from misago.models import Forum, Thread, Post
+from misago.monitor import monitor, UpdatingMonitor
 from misago.readstrackers import ThreadsTracker
 from misago.utils.pagination import make_pagination
 from misago.apps.reports.mixins import TypeMixin
@@ -48,8 +49,9 @@ class ThreadsListView(ThreadsListBaseView, ThreadsListModeration, TypeMixin):
                 thread.report_forum = Forum.objects.forums_tree.get(thread.report_for.forum_id)
             self.threads.append(thread)
 
-        if int(self.request.monitor['reported_posts']) != unresolved_count:
-            self.request.monitor['reported_posts'] = unresolved_count
+        if int(monitor.reported_posts) != unresolved_count:
+            with UpdatingMonitor() as cm:
+                monitor.reported_posts = unresolved_count
 
     def threads_actions(self):
         acl = self.request.acl.threads.get_role(self.forum)

+ 3 - 1
misago/apps/reports/posting.py

@@ -4,6 +4,7 @@ from django.utils.translation import ugettext as _
 from misago.apps.threadtype.posting import EditThreadBaseView, NewReplyBaseView, EditReplyBaseView
 from misago.messages import Message
 from misago.models import Forum, Thread, Post
+from misago.monitor import monitor, UpdatingMonitor
 from misago.apps.reports.mixins import TypeMixin
 from misago.apps.reports.forms import EditThreadForm, NewReplyForm, EditReplyForm
 
@@ -13,7 +14,8 @@ class SetStateCheckpointMixin(object):
         super(SetStateCheckpointMixin, self).post_form(form)
         if self.thread.original_weight != self.thread.weight:
             if self.thread.original_weight == 2:
-                self.request.monitor.decrease('reported_posts')
+                with UpdatingMonitor() as cm:
+                    monitor.decrease('reported_posts')
             if self.thread.weight == 1:
                 self.thread.set_checkpoint(self.request, 'resolved')
             if self.thread.weight == 0:

+ 9 - 4
misago/apps/reports/thread.py

@@ -2,6 +2,7 @@ from django.utils.translation import ugettext as _
 from misago.apps.threadtype.thread import ThreadBaseView, ThreadModeration, PostsModeration
 from misago.messages import Message
 from misago.models import Forum, Thread
+from misago.monitor import monitor, UpdatingMonitor
 from misago.apps.reports.mixins import TypeMixin
 
 class ThreadView(ThreadBaseView, ThreadModeration, PostsModeration, TypeMixin):
@@ -45,23 +46,27 @@ class ThreadView(ThreadBaseView, ThreadModeration, PostsModeration, TypeMixin):
     def after_thread_action_sticky(self):
         self.thread.set_checkpoint(self.request, 'resolved')
         if self.thread.original_weight == 2:
-            self.request.monitor.decrease('reported_posts')
+            with UpdatingMonitor() as cm:
+                monitor.decrease('reported_posts')
         self.request.messages.set_flash(Message(_('Report has been set as resolved.')), 'success', 'threads')
 
     def after_thread_action_normal(self):
         self.thread.set_checkpoint(self.request, 'bogus')
         if self.thread.original_weight == 2:
-            self.request.monitor.decrease('reported_posts')
+            with UpdatingMonitor() as cm:
+                monitor.decrease('reported_posts')
         self.request.messages.set_flash(Message(_('Report has been set as bogus.')), 'success', 'threads')
 
     def after_thread_action_undelete(self):
         if self.thread.original_weight == 2:
-            self.request.monitor.increase('reported_posts')
+            with UpdatingMonitor() as cm:
+                monitor.increase('reported_posts')
         self.request.messages.set_flash(Message(_('Report has been restored.')), 'success', 'threads')
 
     def after_thread_action_soft(self):
         if self.thread.original_weight == 2:
-            self.request.monitor.decrease('reported_posts')
+            with UpdatingMonitor() as cm:
+                monitor.decrease('reported_posts')
         self.request.messages.set_flash(Message(_('Report has been hidden.')), 'success', 'threads')
 
     def after_thread_action_hard(self):

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

@@ -9,6 +9,7 @@ from misago.decorators import block_guest, check_csrf
 from misago.markdown import post_markdown
 from misago.messages import Message
 from misago.models import Forum, Checkpoint, Thread, Post, Karma, WatchedThread
+from misago.monitor import monitor, UpdatingMonitor
 from misago.readstrackers import ThreadsTracker
 from misago.utils.strings import short_string, slugify
 from misago.utils.views import json_response
@@ -331,7 +332,8 @@ Member @%(reporter)s has reported following post by @%(reported)s:
                 self.post.save(force_update=True)
                 self.thread.replies_reported += 1
                 self.thread.save(force_update=True)
-                request.monitor.increase('reported_posts')
+                with UpdatingMonitor() as cm:
+                    monitor.increase('reported_posts')
                 made_report = True
 
             if made_report:

+ 4 - 2
misago/apps/threadtype/list/moderation.py

@@ -5,6 +5,7 @@ from django.utils.translation import ugettext as _
 from misago.forms import FormLayout
 from misago.messages import Message
 from misago.models import Forum, Thread, Post
+from misago.monitor import monitor, UpdatingMonitor
 from misago.shortcuts import render_to_response
 from misago.apps.threadtype.list.forms import MoveThreadsForm, MergeThreadsForm
 from misago.utils.strings import slugify
@@ -36,8 +37,9 @@ class ThreadsListModeration(object):
                     thread.start_post.user.posts += 1
                     users.append(thread.start_post.user)
         if accepted:
-            self.request.monitor['threads'] = int(self.request.monitor['threads']) + accepted
-            self.request.monitor['posts'] = int(self.request.monitor['posts']) + accepted
+            with UpdatingMonitor() as cm:
+                monitor.threads = int(monitor.threads) + accepted
+                monitor.posts = int(monitor.posts) + accepted
             self.forum.sync()
             self.forum.save(force_update=True)
             for user in users:

+ 3 - 1
misago/apps/threadtype/posting/newreply.py

@@ -4,6 +4,7 @@ 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.monitor import monitor, UpdatingMonitor
 from misago.utils.datesformats import date
 from misago.utils.translation import ugettext_lazy
 from misago.apps.threadtype.posting.base import PostingBaseView
@@ -79,7 +80,8 @@ class NewReplyBaseView(PostingBaseView):
 
         # Update forum and monitor
         if not moderation and not merged:
-            self.request.monitor.increase('posts')
+            with UpdatingMonitor() as cm:
+                monitor.increase('posts')
             self.forum.posts += 1
             self.forum.new_last_thread(self.thread)
             self.forum.save(force_update=True)

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

@@ -5,6 +5,7 @@ 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.monitor import monitor, UpdatingMonitor
 from misago.utils.strings import slugify
 
 class NewThreadBaseView(PostingBaseView):
@@ -63,8 +64,9 @@ class NewThreadBaseView(PostingBaseView):
 
         # Update forum monitor
         if not moderation:
-            self.request.monitor.increase('threads')
-            self.request.monitor.increase('posts')
+            with UpdatingMonitor() as cm:
+                monitor.increase('threads')
+                monitor.increase('posts')
             self.forum.threads += 1
             self.forum.posts += 1
             self.forum.new_last_thread(self.thread)

+ 13 - 8
misago/apps/threadtype/thread/moderation/thread.py

@@ -2,6 +2,7 @@ from django.template import RequestContext
 from django.utils.translation import ugettext as _
 from misago.forms import Form, FormLayout
 from misago.messages import Message
+from misago.monitor import monitor, UpdatingMonitor
 from misago.shortcuts import render_to_response
 from misago.apps.threadtype.list.forms import MoveThreadsForm
 
@@ -23,8 +24,9 @@ class ThreadModeration(object):
         self.forum.sync()
         self.forum.save(force_update=True)
         # Update monitor
-        self.request.monitor.increase('threads')
-        self.request.monitor.increase('posts', self.thread.replies + 1)
+        with UpdatingMonitor() as cm:
+            monitor.increase('threads')
+            monitor.increase('posts', self.thread.replies + 1)
         # After
         self.after_thread_action_accept()
 
@@ -115,8 +117,9 @@ class ThreadModeration(object):
         self.forum.sync()
         self.forum.save(force_update=True)
         # Update monitor
-        self.request.monitor.increase('threads')
-        self.request.monitor.increase('posts', self.thread.replies + 1)
+        with UpdatingMonitor() as cm:
+            monitor.increase('threads')
+            monitor.increase('posts', self.thread.replies + 1)
         self.after_thread_action_undelete()
 
     def after_thread_action_undelete(self):
@@ -135,8 +138,9 @@ class ThreadModeration(object):
         self.forum.sync()
         self.forum.save(force_update=True)
         # Update monitor
-        self.request.monitor.decrease('threads')
-        self.request.monitor.decrease('posts', self.thread.replies + 1)
+        with UpdatingMonitor() as cm:
+            monitor.decrease('threads')
+            monitor.decrease('posts', self.thread.replies + 1)
         self.after_thread_action_soft()
 
     def after_thread_action_soft(self):
@@ -149,8 +153,9 @@ class ThreadModeration(object):
         self.forum.sync()
         self.forum.save(force_update=True)
         # Update monitor
-        self.request.monitor.decrease('threads')
-        self.request.monitor.decrease('posts', self.thread.replies + 1)
+        with UpdatingMonitor() as cm:
+            monitor.decrease('threads')
+            monitor.decrease('posts', self.thread.replies + 1)
         self.after_thread_action_hard()
         return self.threads_list_redirect()
 

+ 4 - 4
misago/conf.py

@@ -3,7 +3,7 @@ from django.core.cache import cache
 from misago.models import Setting
 from misago.thread import local
 
-_local_thread = local()
+_thread_local = local()
 
 def load_settings():
     settings = cache.get('settings', {})
@@ -42,7 +42,7 @@ class MisagoSettings(object):
         return self.setting(key)
 
     def __contains__(self, key):
-        return key in self.settings
+        return key in self.settings()
 
     def __getitem__(self, key):
         return self.setting(key)
@@ -53,11 +53,11 @@ class MisagoSettings(object):
         setting.save(force_update=True)
 
 
-settings = MisagoSettings(_local_thread, True)
+settings = MisagoSettings(_thread_local, True)
 
 
 def SafeSettings(): 
     """
     Safe settings factory for MisagoSettings
     """
-    return MisagoSettings(_local_thread, False)
+    return MisagoSettings(_thread_local, False)

+ 3 - 2
misago/context_processors.py

@@ -1,7 +1,8 @@
-from misago.conf import settings, SafeSettings
 from misago import __version__
 from misago.admin import site
+from misago.conf import settings, SafeSettings
 from misago.models import Forum
+from misago.monitor import monitor
 
 def common(request):
     context = {
@@ -26,7 +27,7 @@ def common(request):
             'acl': request.acl,
             'board_address': settings.BOARD_ADDRESS,
             'messages' : request.messages.messages,
-            'monitor': request.monitor,
+            'monitor': monitor,
             'request_path': request.get_full_path(),
             'settings': SafeSettings(),
             'stopwatch': request.stopwatch.time(),

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

@@ -1,12 +1,11 @@
 from django.core.management.base import BaseCommand
 from django.utils import timezone
 from optparse import make_option
-from misago.monitor import Monitor
 from misago.models import User
 
 class Command(BaseCommand):
     help = 'Updates forum monitor to contain to date user information'
 
     def handle(self, *args, **options):
-        User.objects.resync_monitor(Monitor())
+        User.objects.resync_monitor()
         self.stdout.write('\nForum monitor has been updated to contain to date user information.\n')

+ 0 - 5
misago/middleware/monitor.py

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

+ 2 - 1
misago/middleware/user.py

@@ -2,6 +2,7 @@ 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.monitor import monitor, UpdatingMonitor
 from misago.onlines import MembersOnline
 
 def set_timezone(new_tz):
@@ -23,7 +24,7 @@ class UserMiddleware(object):
         else:
             set_timezone(settings.default_timezone)
             request.session.rank = None
-        request.onlines = MembersOnline(settings.online_counting, request.monitor, settings.online_counting_frequency)
+        request.onlines = MembersOnline(settings.online_counting, settings.online_counting_frequency)
 
     def process_response(self, request, response):
         try:

+ 4 - 3
misago/models/banmodel.py

@@ -2,6 +2,7 @@ import re
 from django.db import models
 from django.db.models import Q
 from django.utils import timezone
+from misago.monitor import monitor
 
 BAN_NAME_EMAIL = 0
 BAN_NAME = 1
@@ -58,9 +59,9 @@ class BanCache(object):
         self.version = 0
 
     def check_for_updates(self, request):
-        if (self.version < request.monitor['bans_version']
-            or (self.expires != None and self.expires < timezone.now())):
-            self.version = request.monitor['bans_version']
+        if (self.version < monitor.bans_version
+                or (self.expires != None and self.expires < timezone.now())):
+            self.version = monitor.bans_version
 
             # Check Ban
             if request.user.is_authenticated():

+ 17 - 21
misago/models/usermodel.py

@@ -14,6 +14,7 @@ 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.monitor import monitor, UpdatingMonitor
 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
@@ -31,13 +32,14 @@ class UserManager(models.Manager):
                         )
         return blank_user
 
-    def resync_monitor(self, monitor):
-        monitor['users'] = self.filter(activation=0).count()
-        monitor['users_inactive'] = self.filter(activation__gt=0).count()
-        last_user = self.filter(activation=0).latest('id')
-        monitor['last_user'] = last_user.pk
-        monitor['last_user_name'] = last_user.username
-        monitor['last_user_slug'] = last_user.username_slug
+    def resync_monitor(self):
+        with UpdatingMonitor() as cm:
+            monitor.users = self.filter(activation=0).count()
+            monitor.users_inactive = self.filter(activation__gt=0).count()
+            last_user = self.filter(activation=0).latest('id')
+            monitor.last_user = last_user.pk
+            monitor.last_user_name = last_user.username
+            monitor.last_user_slug = last_user.username_slug
 
     def create_user(self, username, email, password, timezone=False, ip='127.0.0.1', agent='', no_roles=False, activation=0, request=False):
         token = ''
@@ -83,21 +85,15 @@ class UserManager(models.Manager):
             new_user.make_acl_key()
             new_user.save(force_update=True)
 
-        # Load monitor
-        try:
-            monitor = request.monitor
-        except AttributeError:
-            from misago.monitor import Monitor
-            monitor = Monitor()
-
         # Update forum stats
-        if activation == 0:
-            monitor.increase('users')
-            monitor['last_user'] = new_user.pk
-            monitor['last_user_name'] = new_user.username
-            monitor['last_user_slug'] = new_user.username_slug
-        else:
-            monitor.increase('users_inactive')
+        with UpdatingMonitor() as cm:
+            if activation == 0:
+                monitor.increase('users')
+                monitor.last_user = new_user.pk
+                monitor.last_user_name = new_user.username
+                monitor.last_user_slug = new_user.username_slug
+            else:
+                monitor.increase('users_inactive')
 
         # Return new user
         return new_user

+ 64 - 42
misago/monitor.py

@@ -1,80 +1,102 @@
 from datetime import timedelta
 from django.core.cache import cache
 from django.utils import timezone
-from misago.models import MonitorItem
+from misago.thread import local
+
+_thread_local = local()
+
+def load_monitor():
+    from misago.models import MonitorItem
+    monitor = cache.get('monitor', {})
+    if not monitor:
+        for i in MonitorItem.objects.all():
+            monitor[i.id] = [i.value, i.updated, i.type]
+        cache.set('monitor', monitor)
+    return monitor
+
 
 class Monitor(object):
-    def __init__(self):
-        self._cache_deleted = False
-        self._items = {}
-        self.refresh()
-
-    def refresh(self):
-        self._items = cache.get('monitor')
-        if not self._items:
-            self._items = {}
-            for i in MonitorItem.objects.all():
-                self._items[i.id] = [i.value, i.updated, i.type]
-            cache.set('monitor', self._items)
+    def __init__(self, local):
+        self.thread = local
+
+    def monitor(self):
+        try:
+            return self.thread.monitor
+        except AttributeError:
+            self.thread.monitor = load_monitor()
+            return self.thread.monitor
+
+    def entry(self, key):
+        try:
+            return self.monitor()[key]
+        except KeyError:
+            raise Exception(u"Monitor entry \"%s\" could not be found." % key)
 
     def __contains__(self, key):
-        return key in self._items
+        return key in self.monitor()
+
+    def __getattr__(self, key):
+        return self.entry(key)[0]
 
     def __getitem__(self, key):
-        return self._items[key][0]
+        return self.entry(key)[0]
 
     def __setitem__(self, key, value):
-        self._items[key][0] = value
-        self._items[key][1] = timezone.now()
-        cache.set('monitor', self._items)
-        sync_item = MonitorItem(
-                                id=key,
-                                value=value,
-                                type=self._items[key][2],
-                                updated=timezone.now()
-                                )
-        sync_item.save(force_update=True)
+        self.thread.monitor_update.append((key, value))
         return value
 
-    def __delitem__(self, key):
-        pass
-
     def increase(self, key, i=1):
-        self[key] = self[key] + i
+        self.thread.monitor_update.append((key, self[key] + i))
 
     def decrease(self, key, i=1):
-        self[key] = self[key] - i
+        self.thread.monitor_update.append((key, self[key] - i))
 
     def get(self, key, default=None):
-        if not key in self._items:
+        if not key in self.monitor():
             return default
-        return self._items[key][0]
+        return self.entry(key)[0]
 
     def get_updated(self, key):
-        if key in self._items:
-            return self._items[key][1]
+        if key in self.monitor():
+            return self.entry(key)[1]
         return None
 
     def expired(self, key, seconds=5):
-        return self._items[key][1] < (timezone.now() - timedelta(seconds=seconds))
+        return self.entry(key)[1] < (timezone.now() - timedelta(seconds=seconds))
 
     def has_key(self, key):
-        return key in self._items
+        return key in self.entry()
 
     def keys(self):
-        return self._items.keys()
+        return self.entry().keys()
 
     def values(self):
-        return self._items.values()
+        return self.entry().values()
 
     def items(self):
-        return self._items.items()
+        return self.entry().items()
 
     def iterkeys(self):
-        return self._items.iterkeys()
+        return self.entry().iterkeys()
 
     def itervalues(self):
-        return self._items.itervalues()
+        return self.entry().itervalues()
 
     def iteritems(self):
-        return self._items.iteritems()
+        return self.entry().iteritems()
+
+
+class UpdatingMonitor(object):
+    def __enter__(self):
+        _thread_local.monitor_update = []
+
+    def __exit__(self, type, value, traceback):
+        if _thread_local.monitor_update:
+            from misago.models import MonitorItem
+            for key, value in _thread_local.monitor_update:
+                MonitorItem.objects.filter(pk=key).update(_value=value, updated=timezone.now())
+            cache.delete('monitor')
+            _thread_local.monitor_update = None
+
+
+monitor = Monitor(_thread_local)

+ 9 - 8
misago/onlines.py

@@ -2,14 +2,14 @@ from datetime import timedelta
 from django.core.cache import cache
 from django.utils import timezone
 from misago.models import Session
+from misago.monitor import monitor, UpdatingMonitor
 
 class MembersOnline(object):
-    def __init__(self, mode, monitor, frequency=180):
-        self.monitor = monitor
+    def __init__(self, mode, frequency=180):
         self.frequency = frequency
         self._mode = mode
-        self._members = int(monitor['online_members'])
-        self._all = int(monitor['online_all'])
+        self._members = int(monitor.online_members)
+        self._all = int(monitor.online_all)
         self._om = self._members
         self._oa = self._all
         if (self._mode != 'no' or monitor.expired('online_all', frequency) or
@@ -42,10 +42,11 @@ class MembersOnline(object):
 
     def sync(self):
         if self._mode == 'snap':
-            if self._members != self._om:
-                self.monitor['online_members'] = self._members
-            if self._all != self._oa:
-                self.monitor['online_all'] = self._all
+            with UpdatingMonitor() as cm:
+                if self._members != self._om:
+                    monitor.online_members = self._members
+                if self._all != self._oa:
+                    monitor.online_all = self._all
 
     def stats(self, request):
         stat = {

+ 0 - 1
misago/settings_base.py

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

+ 1 - 1
misago/template/loader.py

@@ -3,6 +3,6 @@ from misago.template.middlewares import process_context
 from misago.template.theme import prefix_templates
 
 def render_to_string(template_name, dictionary=None, context_instance=None):
-    dictionary = process_context(template_name, dictionary, kwargs.get('context_instance'))
+    dictionary = process_context(template_name, dictionary, context_instance)
     template_name = prefix_templates(template_name)
     return django_render_to_string(template_name, dictionary)