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

Signals for some threads operations

Rafał Pitoń 10 лет назад
Родитель
Сommit
7ec4f54fca

+ 3 - 0
misago/forums/apps.py

@@ -5,3 +5,6 @@ class MisagoForumsConfig(AppConfig):
     name = 'misago.forums'
     label = 'misago_forums'
     verbose_name = "Misago Forums"
+
+    def ready(self):
+        from misago.forums import signals

+ 27 - 1
misago/forums/lists.py

@@ -16,12 +16,14 @@ def get_forums_list(user, parent=None):
         queryset = Forum.objects.all_forums()
     queryset_with_acl = queryset.filter(id__in=user.acl['visible_forums'])
 
+    visible_forums = [f for f in queryset_with_acl]
+
     forums_dict = {}
     forums_list = []
 
     parent_level = parent.level + 1 if parent else 1
 
-    for forum in queryset_with_acl:
+    for forum in visible_forums:
         forum.is_read = True
         forum.subforums = []
         forums_dict[forum.pk] = forum
@@ -32,6 +34,30 @@ def get_forums_list(user, parent=None):
 
     add_acl(user, forums_list)
 
+    for forum in reversed(visible_forums):
+        if forum.acl['can_browse']:
+            forum_parent = forums_dict.get(forum.parent_id)
+            if forum_parent:
+                forum_parent.threads += forum.threads
+                forum_parent.posts += forum.posts
+
+                if forum_parent.last_post_on and forum.last_post_on:
+                    parent_last_post = forum_parent.last_post_on
+                    forum_last_post = forum.last_post_on
+                    update_last_thead = parent_last_post < forum_last_post
+                elif not forum_parent.last_post_on and forum.last_post_on:
+                    update_last_thead = True
+                else:
+                    update_last_thead = False
+
+                if update_last_thead:
+                    forum_parent.last_post_on = forum.last_post_on
+                    forum_parent.last_thread_id = forum.last_thread_id
+                    forum_parent.last_thread_title = forum.last_thread_title
+                    forum_parent.last_thread_slug = forum.last_thread_slug
+                    forum_parent.last_poster_name = forum.last_poster_name
+                    forum_parent.last_poster_slug = forum.last_poster_slug
+
     flat_list = []
     for forum in forums_list:
         if forum.role != "category" or forum.subforums:

+ 31 - 16
misago/forums/models.py

@@ -2,7 +2,6 @@ from urlparse import urlparse
 
 from django.core.urlresolvers import reverse
 from django.db import models
-from django.dispatch import receiver
 from django.utils.translation import ugettext_lazy as _
 
 from mptt.managers import TreeManager
@@ -11,9 +10,7 @@ from mptt.models import MPTTModel, TreeForeignKey
 from misago.acl import version as acl_version
 from misago.acl.models import BaseRole
 from misago.conf import settings
-from misago.core import serializer
 from misago.core.cache import cache
-from misago.core.signals import secret_key_changed
 from misago.core.utils import slugify
 
 
@@ -70,7 +67,8 @@ class Forum(MPTTModel):
                                     on_delete=models.SET_NULL)
     last_thread_title = models.CharField(max_length=255, null=True, blank=True)
     last_thread_slug = models.CharField(max_length=255, null=True, blank=True)
-    last_poster = models.ForeignKey(settings.AUTH_USER_MODEL, related_name='+',
+    last_poster = models.ForeignKey(settings.AUTH_USER_MODEL,
+                                    related_name='+',
                                     null=True, blank=True,
                                     on_delete=models.SET_NULL)
     last_poster_name = models.CharField(max_length=255, null=True, blank=True)
@@ -103,6 +101,26 @@ class Forum(MPTTModel):
         acl_version.invalidate()
         return super(Forum, self).delete(*args, **kwargs)
 
+    def recount(self):
+        counted_criteria = {'is_hidden':False, 'is_moderated':False}
+        self.threads = self.thread_set.filter(**counted_criteria).count()
+        self.posts = self.post_set.filter(**counted_criteria).count()
+
+        if self.threads:
+            last_thread_qs = self.thread_set.filter(**counted_criteria)
+            last_thread = last_thread_qs.order_by('-last_post_id')[:1][0]
+            self.set_last_thread(last_thread)
+        else:
+            self.empty_last_thread()
+
+    def delete_content(self):
+        from misago.forums.signals import delete_forum_content
+        delete_forum_content.send(sender=self)
+
+    def move_content(self, new_forum):
+        from misago.forums.signals import move_forum_content
+        move_forum_content.send(sender=self, new_forum=new_forum)
+
     @property
     def redirect_host(self):
         return urlparse(self.redirect_url).hostname
@@ -132,6 +150,15 @@ class Forum(MPTTModel):
         self.last_poster_name = thread.last_poster_name
         self.last_poster_slug = thread.last_poster_slug
 
+    def empty_last_thread(self):
+        self.last_post_on = None
+        self.last_thread = None
+        self.last_thread_title = None
+        self.last_thread_slug = None
+        self.last_poster = None
+        self.last_poster_name = None
+        self.last_poster_slug = None
+
     def has_child(self, child):
         return child.lft > self.lft and child.rght < self.rght
 
@@ -144,15 +171,3 @@ class RoleForumACL(models.Model):
     role = models.ForeignKey('misago_acl.Role', related_name='forums_acls')
     forum = models.ForeignKey('Forum', related_name='forum_role_set')
     forum_role = models.ForeignKey(ForumRole)
-
-
-"""
-Signal handlers
-"""
-@receiver(secret_key_changed)
-def update_roles_pickles(sender, **kwargs):
-    for role in ForumRole.objects.iterator():
-        if role.pickled_permissions:
-            role.pickled_permissions = serializer.regenerate_checksum(
-                role.pickled_permissions)
-            role.save(update_fields=['pickled_permissions'])

+ 31 - 0
misago/forums/signals.py

@@ -0,0 +1,31 @@
+import django.dispatch
+from django.dispatch import receiver
+
+from misago.core import serializer
+
+from misago.forums.models import Forum, ForumRole
+
+
+delete_forum_content = django.dispatch.Signal()
+move_forum_content = django.dispatch.Signal()
+
+
+"""
+Signal handlers
+"""
+from misago.core.signals import secret_key_changed
+@receiver(secret_key_changed)
+def update_roles_pickles(sender, **kwargs):
+    for role in ForumRole.objects.iterator():
+        if role.pickled_permissions:
+            role.pickled_permissions = serializer.regenerate_checksum(
+                role.pickled_permissions)
+            role.save(update_fields=['pickled_permissions'])
+
+
+from misago.users.signals import username_changed
+@receiver(username_changed)
+def update_usernames(sender, **kwargs):
+    Forum.objects.filter(last_poster=sender).update(
+        last_poster_name=sender.username,
+        last_poster_slug=sender.slug)

+ 6 - 4
misago/forums/views/forumsadmin.py

@@ -1,5 +1,3 @@
-import warnings
-
 from django.contrib import messages
 from django.shortcuts import redirect
 from django.utils.translation import ugettext_lazy as _
@@ -110,12 +108,16 @@ class DeleteForum(ForumAdmin, generic.ModelFormView):
                 Forum.objects.move_node(child, move_children_to, 'last-child')
         else:
             for child in target.get_descendants().order_by('-lft'):
+                child.delete_content()
                 child.delete()
 
         move_threads_to = form.cleaned_data.get('move_threads_to')
         if move_threads_to:
-            warnings.warn("Not implemented yet! See #354 for details.",
-                          FutureWarning)
+            target.move_content(move_threads_to)
+            move_threads_to.recount()
+            move_threads_to.save()
+        else:
+            target.delete_content()
 
         form.instance.delete()
 

+ 1 - 1
misago/templates/misago/forums/forums.html

@@ -47,7 +47,7 @@
       </div>
       {% elif forum.acl.can_browse %}
         {% if forum.last_thread_title %}
-        <a href="#" class="item-title">{{ forum.last_thread_title }}</a>
+        <a href="{% url 'misago:thread' thread_slug=forum.last_thread_slug thread_id=forum.last_thread_id %}" class="item-title">{{ forum.last_thread_title }}</a>
         <div class="text-muted">
           {% capture trimmed as last_poster %}
             {% if forum.last_poster_id %}

+ 3 - 0
misago/threads/apps.py

@@ -5,3 +5,6 @@ class MisagoThreadsConfig(AppConfig):
     name = 'misago.threads'
     label = 'misago_threads'
     verbose_name = "Misago Threads"
+
+    def ready(self):
+        from misago.threads import signals

+ 1 - 0
misago/threads/models/post.py

@@ -1,4 +1,5 @@
 from django.db import models
+from django.dispatch import receiver
 
 from misago.conf import settings
 

+ 33 - 1
misago/threads/models/thread.py

@@ -1,5 +1,6 @@
 from django.core.urlresolvers import reverse
 from django.db import models
+from django.dispatch import receiver
 
 from misago.conf import settings
 from misago.core.utils import slugify
@@ -37,7 +38,8 @@ class Thread(models.Model):
     last_post = models.ForeignKey('misago_threads.Post', related_name='+',
                                   null=True, blank=True,
                                   on_delete=models.SET_NULL)
-    last_poster = models.ForeignKey(settings.AUTH_USER_MODEL, related_name='+',
+    last_poster = models.ForeignKey(settings.AUTH_USER_MODEL,
+                                    related_name='last_poster_set',
                                     null=True, blank=True,
                                     on_delete=models.SET_NULL)
     last_poster_name = models.CharField(max_length=255, null=True, blank=True)
@@ -55,6 +57,36 @@ class Thread(models.Model):
             ['forum', 'weight', 'replies'],
         ]
 
+    def move(self, new_forum):
+        pass
+
+    def merge(self, thread):
+        pass
+
+    def recount(self):
+        counted_criteria = {'is_hidden':False, 'is_moderated':False}
+        self.replies = self.post_set.filter(**counted_criteria).count()
+        if self.replies > 0:
+            self.replies -= 1
+
+        reported_posts_count = self.post_set.filter(is_reported=True).count()
+        self.has_reported_posts = reported_posts_count > 0
+
+        moderated_posts_count = self.post_set.filter(is_moderated=True).count()
+        self.has_moderated_posts = moderated_posts_count > 0
+
+        hidden_posts_count = self.post_set.filter(is_hidden=True).count()
+        self.has_hidden_posts = hidden_posts_count > 0
+
+        first_post = self.post_set.order_by('id')[:1][0]
+        self.set_first_post(first_post)
+
+        last_post = self.post_set.filter(**counted_criteria).order_by('id')[:1]
+        if last_post:
+            self.set_last_post(last_post[0])
+        else:
+            self.set_last_post(first_post)
+
     @property
     def is_announcement(self):
         return self.weight == ANNOUNCEMENT

+ 70 - 0
misago/threads/signals.py

@@ -0,0 +1,70 @@
+import django.dispatch
+from django.dispatch import receiver
+
+from misago.core.pgutils import batch_update, batch_delete
+from misago.forums.models import Forum
+
+from misago.threads.models import Thread, Post
+
+
+move_thread = django.dispatch.Signal()
+delete_thread = django.dispatch.Signal()
+
+
+"""
+Signal handlers
+"""
+from misago.forums.signals import delete_forum_content, move_forum_content
+@receiver(delete_forum_content)
+def delete_forum_threads(sender, **kwargs):
+    sender.thread_set.all().delete()
+    sender.post_set.all().delete()
+
+
+@receiver(move_forum_content)
+def move_forum_threads(sender, **kwargs):
+    new_forum = kwargs['new_forum']
+    Thread.objects.filter(forum=sender).update(forum=new_forum)
+    Post.objects.filter(forum=sender).update(forum=new_forum)
+
+
+from misago.users.signals import delete_user_content, username_changed
+@receiver(delete_user_content)
+def delete_user_threads(sender, **kwargs):
+    recount_forums = set([])
+    recount_threads = set([])
+
+    for thread in batch_delete(sender.thread_set.all(), 50):
+        recount_forums.add(thread.forum_id)
+        thread.delete()
+
+    for post in batch_delete(sender.post_set.all(), 50):
+        recount_forums.add(post.forum_id)
+        recount_threads.add(post.thread_id)
+        post.delete()
+
+    if recount_threads:
+        changed_threads_qs = Thread.objects.filter(id__in=recount_threads)
+        for thread in batch_update(changed_threads_qs, 50):
+            thread.recount()
+            thread.save()
+
+    if recount_forums:
+        for forum in Forum.objects.filter(id__in=recount_forums):
+            forum.recount()
+            forum.save()
+
+
+@receiver(username_changed)
+def update_usernames(sender, **kwargs):
+    Thread.objects.filter(starter=sender).update(
+        starter_name=sender.username,
+        starter_slug=sender.slug)
+    Thread.objects.filter(last_poster=sender).update(
+        last_poster_name=sender.username,
+        last_poster_slug=sender.slug)
+
+    Post.objects.filter(poster=sender).update(poster_name=sender.username)
+    Post.objects.filter(last_editor=sender).update(
+        last_editor_name=sender.username,
+        last_editor_slug=sender.slug)

+ 2 - 2
misago/users/signals.py

@@ -7,10 +7,10 @@ username_changed = django.dispatch.Signal()
 
 
 """
-Register default signal handlers
+Signal handlers
 """
 @receiver(username_changed)
-def sync_username_in_user_models(sender, **kwargs):
+def handle_name_change(sender, **kwargs):
     sender.user_renames.update(changed_by_username=sender.username,
                                changed_by_slug=sender.slug)
     sender.warnings_given.update(giver_username=sender.username,