Browse Source

Simplified private thread participation implementation

Rafał Pitoń 10 years ago
parent
commit
99a3dead81

+ 2 - 7
misago/threads/migrations/0001_initial.py

@@ -41,7 +41,7 @@ class Migration(migrations.Migration):
                 ('checksum', models.CharField(max_length=64, default='-')),
                 ('has_attachments', models.BooleanField(default=False)),
                 ('pickled_attachments', models.TextField(null=True, blank=True)),
-                ('posted_on', models.DateTimeField(db_index=True)),
+                ('posted_on', models.DateTimeField()),
                 ('updated_on', models.DateTimeField()),
                 ('edits', models.PositiveIntegerField(default=0)),
                 ('last_editor_name', models.CharField(max_length=255, null=True, blank=True)),
@@ -104,14 +104,9 @@ class Migration(migrations.Migration):
             name='ThreadParticipant',
             fields=[
                 ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
-                ('level', models.PositiveIntegerField(default=1)),
                 ('thread', models.ForeignKey(to='misago_threads.Thread')),
                 ('user', models.ForeignKey(to=settings.AUTH_USER_MODEL)),
-                ('replies', models.PositiveIntegerField(default=0)),
-                ('last_post_on', models.DateTimeField(null=True, blank=True)),
-                ('last_poster', models.ForeignKey(settings.AUTH_USER_MODEL, related_name='+', null=True, blank=True, on_delete=django.db.models.deletion.SET_NULL)),
-                ('last_poster_name', models.CharField(max_length=255, null=True, blank=True)),
-                ('last_poster_slug', models.CharField(max_length=255, null=True, blank=True)),
+                ('is_owner', models.BooleanField(default=False)),
             ],
             options={
             },

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

@@ -25,7 +25,7 @@ class Post(models.Model):
     has_attachments = models.BooleanField(default=False)
     pickled_attachments = models.TextField(null=True, blank=True)
 
-    posted_on = models.DateTimeField(db_index=True)
+    posted_on = models.DateTimeField()
     updated_on = models.DateTimeField()
 
     edits = models.PositiveIntegerField(default=0)

+ 8 - 50
misago/threads/models/thread.py

@@ -8,19 +8,11 @@ from misago.core.utils import slugify
 
 
 __all__ = [
-    'PARTICIPANT_REMOVED',
-    'PARTICIPANT_ACTIVE',
-    'PARTICIPANT_OWNER',
     'Thread',
     'ThreadParticipant'
 ]
 
 
-PARTICIPANT_REMOVED = 0
-PARTICIPANT_ACTIVE = 1
-PARTICIPANT_OWNER = 2
-
-
 class PrivateThreadMixin(object):
     pass
 
@@ -187,66 +179,32 @@ class Thread(models.Model, PrivateThreadMixin):
 
 
 class ThreadParticipantManager(models.Manager):
-    def delete_participant(self, thread, user):
+    def remove_participant(self, thread, user):
         ThreadParticipant.objects.filter(thread=thread, user=user).delete()
 
     @transaction.atomic
     def set_owner(self, thread, user):
         thread_owner = ThreadParticipant.objects.filter(
-            thread=thread, level=PARTICIPANT_OWNER)
-        thread_owner.update(level=PARTICIPANT_ACTIVE)
+            thread=thread, is_owner=True)
+        thread_owner.update(is_owner=False)
 
-        self.delete_participant(thread, user)
+        self.remove_participant(thread, user)
         ThreadParticipant.objects.create(
             thread=thread,
             user=user,
-            level=PARTICIPANT_OWNER)
+            is_owner=True)
 
     @transaction.atomic
     def add_participant(self, thread, user):
-        self.delete_participant(thread, user)
+        self.remove_participant(thread, user)
         ThreadParticipant.objects.create(
             thread=thread,
-            user=user,
-            level=PARTICIPANT_ACTIVE)
-
-    @transaction.atomic
-    def remove_participant(self, thread, user):
-        self.delete_participant(thread, user)
-        ThreadParticipant.objects.create(
-            thread=thread,
-            user=user,
-            level=PARTICIPANT_REMOVED,
-            replies=thread.replies,
-            last_post_on=thread.last_post_on,
-            last_poster_id=thread.last_poster_id,
-            last_poster_name=thread.last_poster_name,
-            last_poster_slug=thread.last_poster_slug)
+            user=user,)
 
 
 class ThreadParticipant(models.Model):
     thread = models.ForeignKey(Thread)
     user = models.ForeignKey(settings.AUTH_USER_MODEL)
-    level = models.PositiveIntegerField(default=PARTICIPANT_ACTIVE)
-    replies = models.PositiveIntegerField(default=0)
-    last_post_on = models.DateTimeField(null=True, blank=True)
-    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)
-    last_poster_slug = models.CharField(max_length=255, null=True, blank=True)
+    is_owner = models.BooleanField(default=False)
 
     objects = ThreadParticipantManager()
-
-    @property
-    def is_removed(self):
-        return self.level == PARTICIPANT_REMOVED
-
-    @property
-    def is_active(self):
-        return self.level == PARTICIPANT_ACTIVE
-
-    @property
-    def is_owner(self):
-        return self.level == PARTICIPANT_OWNER

+ 0 - 10
misago/threads/permissions/privatethreads.py

@@ -21,7 +21,6 @@ __all__ = [
     'allow_message_user',
     'can_message_user',
     'exclude_invisible_private_threads',
-    'exclude_invisible_private_posts'
 ]
 
 
@@ -211,12 +210,3 @@ def exclude_invisible_private_threads(queryset, user):
         return queryset.filter(see_reported | see_participating)
     else:
         return queryset.filter(participants=user)
-
-
-def exclude_invisible_private_posts(queryset, user, forum, thread):
-    if not forum.acl['can_review_moderated_content']:
-        for participant in thread.participants_list:
-            if participant.user == user and participant.is_removed:
-                left_on = participant.last_post_on
-                return queryset.filter(posted_on__lte=left_on)
-    return queryset

+ 4 - 29
misago/threads/tests/test_privatethread_view.py

@@ -45,39 +45,14 @@ class PrivateThreadTests(AuthenticatedUserTestCase):
         self.assertEqual(response.status_code, 200)
         self.assertIn(self.thread.title, response.content)
 
-    def test_removed_can_access_thread(self):
-        """removed user has access to private thread"""
+    def test_removed_user_cant_access_thread(self):
+        """removed user can't access thread"""
         override_acl(self.user, {'can_use_private_threads': True})
-        ThreadParticipant.objects.remove_participant(self.thread, self.user)
-
-        response = self.client.get(self.thread.get_absolute_url())
-        self.assertEqual(response.status_code, 200)
-        self.assertIn(self.thread.title, response.content)
-
-    def test_removed_user_access_to_thread(self):
-        """removed user can't see content made after he was removed"""
-        override_acl(self.user, {'can_use_private_threads': True})
-
-        visible_posts = []
-        for p in range(4):
-            visible_posts.append(
-                testutils.reply_thread(self.thread, posted_on=timezone.now()))
 
+        ThreadParticipant.objects.add_participant(self.thread, self.user)
         ThreadParticipant.objects.remove_participant(self.thread, self.user)
-
-        hidden_posts = []
-        for p in range(4):
-            hidden_posts.append(
-                testutils.reply_thread(self.thread, posted_on=timezone.now()))
-
         response = self.client.get(self.thread.get_absolute_url())
-        self.assertEqual(response.status_code, 200)
-        self.assertIn(self.thread.title, response.content)
-
-        for visible_post in visible_posts:
-            self.assertIn(visible_post.get_absolute_url(), response.content)
-        for hidden_post in hidden_posts:
-            self.assertNotIn(hidden_post.get_absolute_url(), response.content)
+        self.assertEqual(response.status_code, 404)
 
     def test_moderator_cant_access_unreported_thread(self):
         """moderator cant see private thread without reports"""

+ 7 - 26
misago/threads/tests/test_threadparticipant_model.py

@@ -53,7 +53,7 @@ class ThreadParticipantTests(TestCase):
         ThreadParticipant.objects.add_participant(self.thread, other_user)
         self.assertEqual(self.thread.participants.count(), 2)
 
-        ThreadParticipant.objects.delete_participant(self.thread, user)
+        ThreadParticipant.objects.remove_participant(self.thread, user)
         self.assertEqual(self.thread.participants.count(), 1)
 
         with self.assertRaises(ThreadParticipant.DoesNotExist):
@@ -71,14 +71,15 @@ class ThreadParticipantTests(TestCase):
 
         participation = ThreadParticipant.objects.get(
             thread=self.thread, user=user)
-        self.assertTrue(participation.is_active)
-        self.assertFalse(participation.is_removed)
         self.assertFalse(participation.is_owner)
-        self.assertEqual(user, participation.user)
 
         ThreadParticipant.objects.add_participant(self.thread, user)
         self.assertEqual(self.thread.participants.count(), 1)
 
+        participation = ThreadParticipant.objects.get(
+            thread=self.thread, user=user)
+        self.assertFalse(participation.is_owner)
+
     def test_set_owner(self):
         """set_owner makes user thread owner"""
         User = get_user_model()
@@ -90,35 +91,15 @@ class ThreadParticipantTests(TestCase):
 
         participation = ThreadParticipant.objects.get(
             thread=self.thread, user=user)
-        self.assertFalse(participation.is_active)
-        self.assertFalse(participation.is_removed)
         self.assertTrue(participation.is_owner)
         self.assertEqual(user, participation.user)
 
         other_user = User.objects.create_user(
             "Bob2", "bob2@boberson.com", "Pass.123")
         ThreadParticipant.objects.set_owner(self.thread, other_user)
-
-    def test_remove_participant(self):
-        """remove_participant flags participant as removed"""
-        User = get_user_model()
-        user = User.objects.create_user(
-            "Bob", "bob@boberson.com", "Pass.123")
-
-        ThreadParticipant.objects.add_participant(self.thread, user)
-        self.assertEqual(self.thread.participants.count(), 1)
-
-        ThreadParticipant.objects.remove_participant(self.thread, user)
-        self.assertEqual(self.thread.participants.count(), 1)
+        self.assertEqual(self.thread.participants.count(), 2)
 
         participation = ThreadParticipant.objects.get(
             thread=self.thread, user=user)
-        self.assertFalse(participation.is_active)
-        self.assertTrue(participation.is_removed)
         self.assertFalse(participation.is_owner)
-        self.assertEqual(user, participation.user)
-        self.assertEqual(self.thread.last_post_on, participation.last_post_on)
-        self.assertEqual(self.thread.last_poster_id,
-                         participation.last_poster_id)
-        self.assertEqual(self.thread.last_poster_name,
-                         participation.last_poster_name)
+

+ 13 - 6
misago/threads/views/privatethreads.py

@@ -9,8 +9,7 @@ from misago.threads.models import Thread, ThreadParticipant
 from misago.threads.permissions import (allow_use_private_threads,
                                         allow_see_private_thread,
                                         allow_see_private_post,
-                                        exclude_invisible_private_threads,
-                                        exclude_invisible_private_posts)
+                                        exclude_invisible_private_threads)
 from misago.threads.views import generic
 
 
@@ -57,19 +56,24 @@ class PrivateThreadsMixin(object):
             raise Http404()
         return thread
 
-    def fetch_thread_participants(self, thread):
+    def fetch_thread_participants(self, user, thread):
         thread.participants_list = []
+        thread.participant = None
+
         participants_qs = ThreadParticipant.objects.filter(thread=thread)
         participants_qs = participants_qs.select_related('user')
         for participant in participants_qs:
             participant.thread = thread
             thread.participants_list.append(participant)
+            if participant.user == user:
+                thread.participant = participant
+        return thread.participants_list
 
     def check_thread_permissions(self, request, thread):
         add_acl(request.user, thread.forum)
         add_acl(request.user, thread)
 
-        self.fetch_thread_participants(thread)
+        self.fetch_thread_participants(request.user, thread)
 
         allow_see_private_thread(request.user, thread)
         allow_use_private_threads(request.user)
@@ -79,14 +83,14 @@ class PrivateThreadsMixin(object):
         add_acl(request.user, post.thread)
         add_acl(request.user, post)
 
-        self.fetch_thread_participants(post.thread)
+        self.fetch_thread_participants(request.user, post.thread)
 
         allow_see_private_post(request.user, post)
         allow_see_private_thread(request.user, post.thread)
         allow_use_private_threads(request.user)
 
     def exclude_invisible_posts(self, queryset, user, forum, thread):
-        return exclude_invisible_private_posts(queryset, user, forum, thread)
+        return queryset
 
 
 class PrivateThreads(generic.Threads):
@@ -94,6 +98,9 @@ class PrivateThreads(generic.Threads):
         threads_qs = Forum.objects.private_threads().thread_set
         return exclude_invisible_private_threads(threads_qs, self.user)
 
+    def clean_threads_activity(self, user, threads):
+        pass
+
 
 class PrivateThreadsFiltering(generic.ThreadsFiltering):
     def get_available_filters(self):