Rafał Pitoń 10 years ago
parent
commit
60773b5ae0

+ 69 - 0
misago/threads/events.py

@@ -0,0 +1,69 @@
+from cgi import escape
+
+from misago.acl import add_acl
+
+from misago.threads.checksums import update_event_checksum
+from misago.threads.models import Event
+
+
+__all__ = ['record_event', 'add_events_to_posts']
+
+
+LINK_TEMPLATE = '<a href="%s" class="event-%s">%s</a>'
+
+
+def format_message(message, links):
+    if links:
+        formats = {}
+        for name, value in links.items():
+            formats[name] = LINK_TEMPLATE % (escape(value[1]), escape(name), escape(value[0]))
+        return message % formats
+    else:
+        return message
+
+
+def record_event(user, thread, icon, message, links=None):
+    event = Event.objects.create(
+        forum=thread.forum,
+        thread=thread,
+        author=user,
+        author_name=user.username,
+        author_slug=user.slug,
+        icon=icon,
+        message=format_message(message, links))
+
+    update_event_checksum(event)
+    event.save(update_fields=['checksum'])
+
+    thread.has_events = True
+    return event
+
+
+def add_events_to_posts(user, thread, posts, delimeter=None):
+    if thread.has_events:
+        real_add_events_to_posts(user, thread, posts, delimeter)
+    else:
+        for post in posts:
+            post.events = []
+
+
+def real_add_events_to_posts(user, thread, posts, delimeter=None):
+    start_date = posts[0].posted_on
+    events_queryset = thread.event_set.filter(occured_on__gte=start_date)
+    if delimeter:
+        events_queryset = events_queryset.filter(occured_on__lt=delimeter)
+    events_queryset = events_queryset.order_by('id')
+
+    acl = user.acl['forums'].get(thread.forum_id, {'can_hide_events': False})
+    if not acl['can_hide_events']:
+        events_queryset = events_queryset.filter(is_hidden=False)
+
+    events = [e for e in events_queryset]
+    add_acl(user, events)
+
+    for i, post in enumerate(posts[:-1]):
+        post.events = []
+        while events and events[0].occured_on < posts[i + 1].posted_on:
+            post.events.append(events.pop(0))
+
+    posts[-1].events = events

+ 1 - 0
misago/threads/migrations/0001_initial.py

@@ -79,6 +79,7 @@ class Migration(migrations.Migration):
                 ('has_reported_posts', models.BooleanField(default=False)),
                 ('has_moderated_posts', models.BooleanField(default=False)),
                 ('has_hidden_posts', models.BooleanField(default=False)),
+                ('has_events', models.BooleanField(default=False)),
                 ('started_on', models.DateTimeField()),
                 ('starter_name', models.CharField(max_length=255)),
                 ('starter_slug', models.CharField(max_length=255)),

+ 3 - 0
misago/threads/models/thread.py

@@ -26,6 +26,7 @@ class Thread(models.Model):
     has_reported_posts = models.BooleanField(default=False)
     has_moderated_posts = models.BooleanField(default=False)
     has_hidden_posts = models.BooleanField(default=False)
+    has_events = models.BooleanField(default=False)
     started_on = models.DateTimeField()
     first_post = models.ForeignKey('misago_threads.Post', related_name='+',
                                    null=True, blank=True,
@@ -94,6 +95,8 @@ class Thread(models.Model):
         hidden_post_qs = self.post_set.filter(is_hidden=True)[:1]
         self.has_hidden_posts = hidden_post_qs.exists()
 
+        self.has_events = self.event_set.exists()
+
         first_post = self.post_set.order_by('id')[:1][0]
         self.set_first_post(first_post)
 

+ 24 - 1
misago/threads/permissions.py

@@ -9,7 +9,7 @@ from misago.core import forms
 from misago.forums.models import Forum, RoleForumACL, ForumRole
 from misago.forums.permissions import get_forums_roles
 
-from misago.threads.models import Thread, Post
+from misago.threads.models import Thread, Post, Event
 
 
 """
@@ -112,6 +112,15 @@ class PermissionsForm(forms.Form):
         help_text=_("Will see and be able to accept moderated content."))
     can_report_content = forms.YesNoSwitch(label=_("Can report posts"))
     can_see_reports = forms.YesNoSwitch(label=_("Can see reports"))
+    can_hide_events = forms.TypedChoiceField(
+        label=_("Can hide events"),
+        coerce=int,
+        initial=0,
+        choices=(
+            (0, _("No")),
+            (1, _("Hide events")),
+            (2, _("Delete events"))
+        ))
 
 
 def change_permissions_form(role):
@@ -158,6 +167,7 @@ def build_forum_acl(acl, forum, forums_roles, key_name):
         'can_review_moderated_content': 0,
         'can_report_content': 0,
         'can_see_reports': 0,
+        'can_can_hide_events': 0,
     }
     final_acl.update(acl)
 
@@ -180,6 +190,7 @@ def build_forum_acl(acl, forum, forums_roles, key_name):
         can_review_moderated_content=algebra.greater,
         can_report_content=algebra.greater,
         can_see_reports=algebra.greater,
+        can_can_hide_events=algebra.greater,
     )
 
     return final_acl
@@ -195,6 +206,8 @@ def add_acl_to_target(user, target):
         add_acl_to_thread(user, target)
     if isinstance(target, Post):
         add_acl_to_post(user, target)
+    if isinstance(target, Event):
+        add_acl_to_event(user, target)
 
 
 def add_acl_to_forum(user, forum):
@@ -219,6 +232,7 @@ def add_acl_to_forum(user, forum):
         'can_review_moderated_content': 0,
         'can_report_content': 0,
         'can_see_reports': 0,
+        'can_can_hide_events': 0,
     })
 
     algebra.sum_acls(forum.acl, acls=[forum_acl],
@@ -243,6 +257,7 @@ def add_acl_to_forum(user, forum):
             can_review_moderated_content=algebra.greater,
             can_report_content=algebra.greater,
             can_see_reports=algebra.greater,
+            can_can_hide_events=algebra.greater,
         )
 
     forum.acl['can_see_own_threads'] = not forum.acl['can_see_all_threads']
@@ -256,6 +271,14 @@ def add_acl_to_post(user, post):
     pass
 
 
+def add_acl_to_event(user, event):
+    forum_acl = user.acl['forums'].get(event.forum_id, {})
+    can_hide_events = forum_acl.get('can_can_hide_events', 0)
+
+    event.acl['can_hide'] = can_hide_events > 0
+    event.acl['can_delete'] = can_hide_events == 2
+
+
 """
 ACL tests
 """

+ 66 - 0
misago/threads/tests/test_events.py

@@ -0,0 +1,66 @@
+#-*- coding: utf-8 -*-
+from django.contrib.auth import get_user_model
+from django.test import TestCase
+from django.utils import timezone
+
+from misago.acl import add_acl
+from misago.forums.models import Forum
+
+from misago.threads.events import record_event, add_events_to_posts
+from misago.threads.models import Thread, Event
+from misago.threads.testutils import reply_thread
+
+
+class EventsAPITests(TestCase):
+    def setUp(self):
+        User = get_user_model()
+        self.user = User.objects.create_user("Bob", "bob@bob.com", "Pass.123")
+
+        datetime = timezone.now()
+
+        self.forum = Forum.objects.filter(role="forum")[:1][0]
+        self.thread = Thread(
+            forum=self.forum,
+            weight=0,
+            started_on=datetime,
+            starter_name='Tester',
+            starter_slug='tester',
+            last_post_on=datetime,
+            last_poster_name='Tester',
+            last_poster_slug='tester')
+
+        self.thread.set_title("Test thread")
+        self.thread.save()
+
+        add_acl(self.user, self.forum)
+        add_acl(self.user, self.thread)
+
+    def test_record_event(self):
+        """record_event registers event in thread"""
+        message = "%(user)s has changed this thread to announcement."
+        event = record_event(self.user, self.thread, "announcement", message, {
+            'user': (u"Łob", self.user.get_absolute_url())
+        })
+
+        self.assertTrue(event.is_valid)
+        self.assertTrue(event.message.endswith(message[8:]))
+        self.assertTrue(self.thread.has_events)
+
+    def test_add_events_to_posts(self):
+        """add_events_to_posts makes posts event-aware"""
+        message = "Test event was recorded."
+
+        for p in xrange(2):
+            reply_thread(self.thread, posted_on=timezone.now())
+        event = record_event(self.user, self.thread, "check", message)
+        for p in xrange(2):
+            reply_thread(self.thread, posted_on=timezone.now())
+
+        posts = [p for p in self.thread.post_set.all().order_by('id')]
+        add_events_to_posts(self.user, self.thread, posts)
+
+        for i, post in enumerate(posts):
+            if i == 1:
+                self.assertEqual(post.events[0].message, message)
+            else:
+                self.assertEqual(post.events, [])

+ 23 - 1
misago/threads/tests/test_thread_model.py

@@ -6,7 +6,7 @@ from django.utils import timezone
 
 from misago.forums.models import Forum
 
-from misago.threads.models import Thread, Post
+from misago.threads.models import Thread, Post, Event
 
 
 class ThreadModelTests(TestCase):
@@ -73,6 +73,7 @@ class ThreadModelTests(TestCase):
         self.assertFalse(self.thread.has_reported_posts)
         self.assertFalse(self.thread.has_moderated_posts)
         self.assertFalse(self.thread.has_hidden_posts)
+        self.assertFalse(self.thread.has_events)
         self.assertEqual(self.thread.replies, 1)
 
         # add moderated post
@@ -98,6 +99,7 @@ class ThreadModelTests(TestCase):
         self.assertFalse(self.thread.has_reported_posts)
         self.assertTrue(self.thread.has_moderated_posts)
         self.assertFalse(self.thread.has_hidden_posts)
+        self.assertFalse(self.thread.has_events)
         self.assertEqual(self.thread.replies, 1)
 
         # add hidden post
@@ -123,6 +125,7 @@ class ThreadModelTests(TestCase):
         self.assertFalse(self.thread.has_reported_posts)
         self.assertTrue(self.thread.has_moderated_posts)
         self.assertTrue(self.thread.has_hidden_posts)
+        self.assertFalse(self.thread.has_events)
         self.assertEqual(self.thread.replies, 2)
 
         # unhide post
@@ -139,6 +142,7 @@ class ThreadModelTests(TestCase):
         self.assertFalse(self.thread.has_reported_posts)
         self.assertTrue(self.thread.has_moderated_posts)
         self.assertFalse(self.thread.has_hidden_posts)
+        self.assertFalse(self.thread.has_events)
         self.assertEqual(self.thread.replies, 2)
 
         # unmoderate post
@@ -155,8 +159,26 @@ class ThreadModelTests(TestCase):
         self.assertFalse(self.thread.has_reported_posts)
         self.assertFalse(self.thread.has_moderated_posts)
         self.assertFalse(self.thread.has_hidden_posts)
+        self.assertFalse(self.thread.has_events)
         self.assertEqual(self.thread.replies, 3)
 
+        # add event
+        event = Event.objects.create(
+            forum=self.forum,
+            thread=self.thread,
+            author_name=user.username,
+            author_slug=user.slug,
+            message="How bout nope?")
+
+        # sync set has_events flag
+        self.thread.synchronize()
+        self.assertTrue(self.thread.has_events)
+
+        # sync unsetset has_events flag after only event was deleted
+        event.delete()
+        self.thread.synchronize()
+        self.assertFalse(self.thread.has_events)
+
     def test_set_first_post(self):
         """set_first_post sets first post and poster data on thread"""
         User = get_user_model()