Browse Source

Fix #435: simplified threads weights

Rafał Pitoń 10 years ago
parent
commit
2c1276c898

+ 1 - 1
misago/conf/defaults.py

@@ -177,7 +177,7 @@ MISAGO_MARKUP_EXTENSIONS = ()
 MISAGO_POSTING_MIDDLEWARES = (
 MISAGO_POSTING_MIDDLEWARES = (
     'misago.threads.posting.reply.ReplyFormMiddleware',
     'misago.threads.posting.reply.ReplyFormMiddleware',
     'misago.threads.posting.threadlabel.ThreadLabelFormMiddleware',
     'misago.threads.posting.threadlabel.ThreadLabelFormMiddleware',
-    'misago.threads.posting.threadweight.ThreadWeightFormMiddleware',
+    'misago.threads.posting.threadpin.ThreadPinFormMiddleware',
     'misago.threads.posting.threadclose.ThreadCloseFormMiddleware',
     'misago.threads.posting.threadclose.ThreadCloseFormMiddleware',
     'misago.threads.posting.recordedit.RecordEditMiddleware',
     'misago.threads.posting.recordedit.RecordEditMiddleware',
     'misago.threads.posting.updatestats.UpdateStatsMiddleware',
     'misago.threads.posting.updatestats.UpdateStatsMiddleware',

+ 1 - 9
misago/faker/management/commands/createfakethreads.py

@@ -53,7 +53,6 @@ class Command(BaseCommand):
 
 
                 thread = Thread(
                 thread = Thread(
                     forum=forum,
                     forum=forum,
-                    weight=0,
                     started_on=datetime,
                     started_on=datetime,
                     starter_name='-',
                     starter_name='-',
                     starter_slug='-',
                     starter_slug='-',
@@ -102,14 +101,7 @@ class Command(BaseCommand):
         self.stdout.write('\nPinning %s threads...' % pinned_threads)
         self.stdout.write('\nPinning %s threads...' % pinned_threads)
         for i in xrange(0, pinned_threads):
         for i in xrange(0, pinned_threads):
             thread = Thread.objects.order_by('?')[:1][0]
             thread = Thread.objects.order_by('?')[:1][0]
-            thread.weight = 1
-            thread.save()
-
-        announcements = random.randint(0, int(created_threads * 0.001)) or 1
-        self.stdout.write('\nMaking %s announcements...' % announcements)
-        for i in xrange(0, announcements):
-            thread = Thread.objects.order_by('?')[:1][0]
-            thread.weight = 2
+            thread.is_pinned = True
             thread.save()
             thread.save()
 
 
         self.stdout.write(message % created_threads)
         self.stdout.write(message % created_threads)

+ 1 - 1
misago/forums/management/commands/pruneforums.py

@@ -21,7 +21,7 @@ class Command(BaseCommand):
             archive = forum.archive_pruned_in
             archive = forum.archive_pruned_in
             pruned_threads = 0
             pruned_threads = 0
 
 
-            threads_qs = forum.thread_set.filter(weight=0)
+            threads_qs = forum.thread_set.filter(is_pinned=False)
 
 
             if forum.prune_started_after:
             if forum.prune_started_after:
                 cutoff = now - timedelta(days=forum.prune_started_after)
                 cutoff = now - timedelta(days=forum.prune_started_after)

+ 1 - 1
misago/forums/migrations/0003_forums_roles.py

@@ -129,7 +129,7 @@ def create_default_forums_roles(apps, schema_editor):
                 'can_move_posts': 1,
                 'can_move_posts': 1,
                 'can_merge_posts': 1,
                 'can_merge_posts': 1,
                 'can_change_threads_labels': 2,
                 'can_change_threads_labels': 2,
-                'can_change_threads_weight': 2,
+                'can_pin_threads': 1,
                 'can_close_threads': 1,
                 'can_close_threads': 1,
                 'can_move_threads': 1,
                 'can_move_threads': 1,
                 'can_merge_threads': 1,
                 'can_merge_threads': 1,

+ 2 - 0
misago/templates/misago/posting/threadpinform.html

@@ -0,0 +1,2 @@
+{% load misago_forms %}
+{% form_input form.is_pinned %}

+ 0 - 2
misago/templates/misago/posting/threadweightform.html

@@ -1,2 +0,0 @@
-{% load misago_forms %}
-{% form_input form.weight %}

+ 3 - 9
misago/templates/misago/threads/base.html

@@ -14,17 +14,11 @@
 
 
             <div class="col-md-7">
             <div class="col-md-7">
 
 
-              {% if thread.is_announcement %}
+              {% if thread.is_pinned %}
                 {% if thread.is_read %}
                 {% if thread.is_read %}
-                <span class="thread-icon tooltip-top fa fa-star-o fa-lg fa-fw" title="{% trans "Announcement, has no unread posts" %}"></span>
+                <span class="thread-icon tooltip-top fa fa-star-o fa-lg fa-fw" title="{% trans "Pinned, has no unread posts" %}"></span>
                 {% else %}
                 {% else %}
-                <span class="thread-icon tooltip-top fa fa-star fa-lg fa-fw" title="{% trans "Announcement, has unread posts" %}"></span>
-                {% endif %}
-              {% elif thread.is_pinned %}
-                {% if thread.is_read %}
-                <span class="thread-icon tooltip-top fa fa-bookmark-o fa-lg fa-fw" title="{% trans "Pinned, has no unread posts" %}"></span>
-                {% else %}
-                <span class="thread-icon tooltip-top fa fa-bookmark fa-lg fa-fw" title="{% trans "Pinned, has unread posts" %}"></span>
+                <span class="thread-icon tooltip-top fa fa-star fa-lg fa-fw" title="{% trans "Pinned, has unread posts" %}"></span>
                 {% endif %}
                 {% endif %}
               {% else %}
               {% else %}
                 {% if thread.is_read %}
                 {% if thread.is_read %}

+ 5 - 10
misago/threads/forms/posting.py

@@ -109,17 +109,12 @@ def ThreadLabelForm(*args, **kwargs):
     return FormType(*args, **kwargs)
     return FormType(*args, **kwargs)
 
 
 
 
-class ThreadWeightForm(forms.Form):
+class ThreadPinForm(forms.Form):
     is_supporting = True
     is_supporting = True
-    legend = _("Weight")
-    template = "misago/posting/threadweightform.html"
-
-    weight = forms.TypedChoiceField(label=_("Thread weight"), initial=0,
-                                    choices=(
-                                        (0, _("Standard")),
-                                        (1, _("Pinned")),
-                                        (2, _("Announcement")),
-                                    ))
+    legend = _("Thread weight")
+    template = "misago/posting/threadpinform.html"
+
+    is_pinned = forms.YesNoSwitch(label=_("Pin thread"), initial=0)
 
 
 
 
 class ThreadCloseForm(forms.Form):
 class ThreadCloseForm(forms.Form):

+ 4 - 5
misago/threads/migrations/0001_initial.py

@@ -72,7 +72,6 @@ class Migration(migrations.Migration):
             name='Thread',
             name='Thread',
             fields=[
             fields=[
                 ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
                 ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
-                ('weight', models.PositiveIntegerField(default=0, db_index=True)),
                 ('title', models.CharField(max_length=255)),
                 ('title', models.CharField(max_length=255)),
                 ('slug', models.CharField(max_length=255)),
                 ('slug', models.CharField(max_length=255)),
                 ('replies', models.PositiveIntegerField(default=0, db_index=True)),
                 ('replies', models.PositiveIntegerField(default=0, db_index=True)),
@@ -86,6 +85,7 @@ class Migration(migrations.Migration):
                 ('last_post_on', models.DateTimeField(db_index=True)),
                 ('last_post_on', models.DateTimeField(db_index=True)),
                 ('last_poster_name', models.CharField(max_length=255, null=True, blank=True)),
                 ('last_poster_name', models.CharField(max_length=255, null=True, blank=True)),
                 ('last_poster_slug', models.CharField(max_length=255, null=True, blank=True)),
                 ('last_poster_slug', models.CharField(max_length=255, null=True, blank=True)),
+                ('is_pinned', models.BooleanField(default=False, db_index=True)),
                 ('is_poll', models.BooleanField(default=False)),
                 ('is_poll', models.BooleanField(default=False)),
                 ('is_moderated', models.BooleanField(default=False, db_index=True)),
                 ('is_moderated', models.BooleanField(default=False, db_index=True)),
                 ('is_hidden', models.BooleanField(default=False)),
                 ('is_hidden', models.BooleanField(default=False)),
@@ -174,10 +174,9 @@ class Migration(migrations.Migration):
         migrations.AlterIndexTogether(
         migrations.AlterIndexTogether(
             name='thread',
             name='thread',
             index_together=set([
             index_together=set([
-                ('forum', 'weight', 'id'),
-                ('forum', 'weight', 'last_post_on'),
-                ('forum', 'weight', 'replies'),
-                ('forum', 'weight')
+                ('forum', 'id'),
+                ('forum', 'last_post_on'),
+                ('forum', 'replies'),
             ]),
             ]),
         ),
         ),
 ]
 ]

+ 5 - 18
misago/threads/models/thread.py

@@ -7,16 +7,11 @@ from misago.core.shortcuts import paginate
 from misago.core.utils import slugify
 from misago.core.utils import slugify
 
 
 
 
-__all__ = ['ANNOUNCEMENT', 'PINNED', 'Thread']
-
-
-ANNOUNCEMENT = 2
-PINNED = 1
+__all__ = ['Thread']
 
 
 
 
 class Thread(models.Model):
 class Thread(models.Model):
     forum = models.ForeignKey('misago_forums.Forum')
     forum = models.ForeignKey('misago_forums.Forum')
-    weight = models.PositiveIntegerField(default=0, db_index=True)
     label = models.ForeignKey('misago_threads.Label',
     label = models.ForeignKey('misago_threads.Label',
                               null=True, blank=True,
                               null=True, blank=True,
                               on_delete=models.SET_NULL)
                               on_delete=models.SET_NULL)
@@ -46,6 +41,7 @@ class Thread(models.Model):
                                     on_delete=models.SET_NULL)
                                     on_delete=models.SET_NULL)
     last_poster_name = models.CharField(max_length=255, null=True, blank=True)
     last_poster_name = models.CharField(max_length=255, null=True, blank=True)
     last_poster_slug = models.CharField(max_length=255, null=True, blank=True)
     last_poster_slug = models.CharField(max_length=255, null=True, blank=True)
+    is_pinned = models.BooleanField(default=False, db_index=True)
     is_poll = models.BooleanField(default=False)
     is_poll = models.BooleanField(default=False)
     is_moderated = models.BooleanField(default=False, db_index=True)
     is_moderated = models.BooleanField(default=False, db_index=True)
     is_hidden = models.BooleanField(default=False)
     is_hidden = models.BooleanField(default=False)
@@ -53,10 +49,9 @@ class Thread(models.Model):
 
 
     class Meta:
     class Meta:
         index_together = [
         index_together = [
-            ['forum', 'weight'],
-            ['forum', 'weight', 'id'],
-            ['forum', 'weight', 'last_post_on'],
-            ['forum', 'weight', 'replies'],
+            ['forum', 'id'],
+            ['forum', 'last_post_on'],
+            ['forum', 'replies'],
         ]
         ]
 
 
     def __unicode__(self):
     def __unicode__(self):
@@ -111,14 +106,6 @@ class Thread(models.Model):
             self.set_last_post(first_post)
             self.set_last_post(first_post)
 
 
     @property
     @property
-    def is_announcement(self):
-        return self.weight == ANNOUNCEMENT
-
-    @property
-    def is_pinned(self):
-        return self.weight == PINNED
-
-    @property
     def link_prefix(self):
     def link_prefix(self):
         if self.forum.special_role == 'private_threads':
         if self.forum.special_role == 'private_threads':
             return 'private_thread'
             return 'private_thread'

+ 9 - 26
misago/threads/moderation/threads.py

@@ -40,44 +40,27 @@ def unlabel_thread(user, thread):
 
 
 
 
 @atomic
 @atomic
-def announce_thread(user, thread):
-    if thread.weight < 2:
-        thread.weight = 2
-
-        message = _("%(user)s changed thread to announcement.")
-        record_event(user, thread, "star", message, {'user': user})
-
-        thread.save(update_fields=['has_events', 'weight'])
-        return True
-    else:
-        return False
-
-
-@atomic
 def pin_thread(user, thread):
 def pin_thread(user, thread):
-    if thread.weight != 1:
-        thread.weight = 1
+    if not thread.is_pinned:
+        thread.is_pinned = True
 
 
         message = _("%(user)s pinned thread.")
         message = _("%(user)s pinned thread.")
-        record_event(user, thread, "bookmark", message, {'user': user})
+        record_event(user, thread, "star", message, {'user': user})
 
 
-        thread.save(update_fields=['has_events', 'weight'])
+        thread.save(update_fields=['has_events', 'is_pinned'])
         return True
         return True
     else:
     else:
         return False
         return False
 
 
 
 
 @atomic
 @atomic
-def reset_thread(user, thread):
-    if thread.weight > 0:
-        if thread.is_announcement:
-            message = _("%(user)s withhold announcement.")
-        if thread.is_pinned:
-            message = _("%(user)s unpinned thread.")
+def unpin_thread(user, thread):
+    if thread.is_pinned:
+        message = _("%(user)s unpinned thread.")
         record_event(user, thread, "circle", message, {'user': user})
         record_event(user, thread, "circle", message, {'user': user})
 
 
-        thread.weight = 0
-        thread.save(update_fields=['has_events', 'weight'])
+        thread.is_pinned = False
+        thread.save(update_fields=['has_events', 'is_pinned'])
         return True
         return True
     else:
     else:
         return False
         return False

+ 7 - 12
misago/threads/permissions.py

@@ -99,13 +99,8 @@ class PermissionsForm(forms.Form):
     can_change_threads_labels = forms.TypedChoiceField(
     can_change_threads_labels = forms.TypedChoiceField(
         label=_("Can change threads labels"), coerce=int, initial=0,
         label=_("Can change threads labels"), coerce=int, initial=0,
         choices=((0, _("No")), (1, _("Own threads")), (2, _("All threads"))))
         choices=((0, _("No")), (1, _("Own threads")), (2, _("All threads"))))
-    can_change_threads_weight = forms.TypedChoiceField(
-        label=_("Can change threads weight"), coerce=int, initial=0,
-        choices=(
-            (0, _("No")),
-            (1, _("Pin threads")),
-            (2, _("Make announcements")),
-        ))
+    can_pin_threads = forms.YesNoSwitch(
+        label=_("Can pin threads"))
     can_close_threads = forms.TypedChoiceField(
     can_close_threads = forms.TypedChoiceField(
         label=_("Can close threads"),
         label=_("Can close threads"),
         coerce=int,
         coerce=int,
@@ -174,7 +169,7 @@ def build_forum_acl(acl, forum, forums_roles, key_name):
         'can_move_posts': 0,
         'can_move_posts': 0,
         'can_merge_posts': 0,
         'can_merge_posts': 0,
         'can_change_threads_labels': 0,
         'can_change_threads_labels': 0,
-        'can_change_threads_weight': 0,
+        'can_pin_threads': 0,
         'can_close_threads': 0,
         'can_close_threads': 0,
         'can_move_threads': 0,
         'can_move_threads': 0,
         'can_merge_threads': 0,
         'can_merge_threads': 0,
@@ -202,7 +197,7 @@ def build_forum_acl(acl, forum, forums_roles, key_name):
         can_move_posts=algebra.greater,
         can_move_posts=algebra.greater,
         can_merge_posts=algebra.greater,
         can_merge_posts=algebra.greater,
         can_change_threads_labels=algebra.greater,
         can_change_threads_labels=algebra.greater,
-        can_change_threads_weight=algebra.greater,
+        can_pin_threads=algebra.greater,
         can_close_threads=algebra.greater,
         can_close_threads=algebra.greater,
         can_move_threads=algebra.greater,
         can_move_threads=algebra.greater,
         can_merge_threads=algebra.greater,
         can_merge_threads=algebra.greater,
@@ -249,7 +244,7 @@ def add_acl_to_forum(user, forum):
         'can_move_posts': 0,
         'can_move_posts': 0,
         'can_merge_posts': 0,
         'can_merge_posts': 0,
         'can_change_threads_labels': 0,
         'can_change_threads_labels': 0,
-        'can_change_threads_weight': 0,
+        'can_pin_threads': 0,
         'can_close_threads': 0,
         'can_close_threads': 0,
         'can_move_threads': 0,
         'can_move_threads': 0,
         'can_merge_threads': 0,
         'can_merge_threads': 0,
@@ -279,7 +274,7 @@ def add_acl_to_forum(user, forum):
             can_move_posts=algebra.greater,
             can_move_posts=algebra.greater,
             can_merge_posts=algebra.greater,
             can_merge_posts=algebra.greater,
             can_change_threads_labels=algebra.greater,
             can_change_threads_labels=algebra.greater,
-            can_change_threads_weight=algebra.greater,
+            can_pin_threads=algebra.greater,
             can_close_threads=algebra.greater,
             can_close_threads=algebra.greater,
             can_move_threads=algebra.greater,
             can_move_threads=algebra.greater,
             can_merge_threads=algebra.greater,
             can_merge_threads=algebra.greater,
@@ -361,7 +356,7 @@ def exclude_invisible_threads(user, forum, queryset):
     return queryset
     return queryset
 
 
 
 
-def exclude_invisible_postss(user, forum, queryset):
+def exclude_invisible_posts(user, forum, queryset):
     if user.is_authenticated():
     if user.is_authenticated():
         if not forum.acl['can_review_moderated_content']:
         if not forum.acl['can_review_moderated_content']:
             condition_author = Q(starter_id=user.id)
             condition_author = Q(starter_id=user.id)

+ 23 - 0
misago/threads/posting/threadpin.py

@@ -0,0 +1,23 @@
+from misago.threads.forms.posting import ThreadPinForm
+from misago.threads.posting import PostingMiddleware
+
+
+class ThreadPinFormMiddleware(PostingMiddleware):
+    def use_this_middleware(self):
+        if self.forum.acl['can_pin_threads']:
+            self.thread_is_pinned = self.thread.is_pinned
+            return True
+        else:
+            return False
+
+    def make_form(self):
+        if self.request.method == 'POST':
+            return ThreadPinForm(self.request.POST, prefix=self.prefix)
+        else:
+            initial = {'is_pinned': self.is_pinned}
+            return ThreadPinForm(prefix=self.prefix, initial=initial)
+
+    def pre_save(self, form):
+        if self.thread_is_pinned != form.cleaned_data.get('is_pinned'):
+            self.thread.is_pinned = form.cleaned_data.get('is_pinned')
+            self.thread.update_fields.append('is_pinned')

+ 0 - 23
misago/threads/posting/threadweight.py

@@ -1,23 +0,0 @@
-from misago.threads.forms.posting import ThreadWeightForm
-from misago.threads.posting import PostingMiddleware
-
-
-class ThreadWeightFormMiddleware(PostingMiddleware):
-    def use_this_middleware(self):
-        if self.forum.acl['can_change_threads_weight']:
-            self.thread_weight = self.thread.weight
-            return True
-        else:
-            return False
-
-    def make_form(self):
-        if self.request.method == 'POST':
-            return ThreadWeightForm(self.request.POST, prefix=self.prefix)
-        else:
-            initial = {'weight': self.thread_weight}
-            return ThreadWeightForm(prefix=self.prefix, initial=initial)
-
-    def pre_save(self, form):
-        if self.thread_weight != form.cleaned_data.get('weight'):
-            self.thread.weight = form.cleaned_data.get('weight')
-            self.thread.update_fields.append('weight')

+ 0 - 1
misago/threads/tests/test_event_model.py

@@ -18,7 +18,6 @@ class EventModelTests(TestCase):
         self.forum = Forum.objects.filter(role="forum")[:1][0]
         self.forum = Forum.objects.filter(role="forum")[:1][0]
         self.thread = Thread(
         self.thread = Thread(
             forum=self.forum,
             forum=self.forum,
-            weight=0,
             started_on=datetime,
             started_on=datetime,
             starter_name='Tester',
             starter_name='Tester',
             starter_slug='tester',
             starter_slug='tester',

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

@@ -21,7 +21,6 @@ class EventsAPITests(TestCase):
         self.forum = Forum.objects.filter(role="forum")[:1][0]
         self.forum = Forum.objects.filter(role="forum")[:1][0]
         self.thread = Thread(
         self.thread = Thread(
             forum=self.forum,
             forum=self.forum,
-            weight=0,
             started_on=datetime,
             started_on=datetime,
             starter_name='Tester',
             starter_name='Tester',
             starter_slug='tester',
             starter_slug='tester',

+ 28 - 74
misago/threads/tests/test_forumthreads_view.py

@@ -92,53 +92,30 @@ class ActionsTests(ForumViewHelperTestCase):
             },
             },
         ])
         ])
 
 
-    def test_weight_actions(self):
-        """ForumActions initializes list with available weights"""
+    def test_pin_unpin_actions(self):
+        """ForumActions initializes list with pin and unpin actions"""
         self.override_acl({
         self.override_acl({
-            'can_change_threads_weight': 0,
+            'can_pin_threads': 0,
         })
         })
 
 
         actions = ForumActions(user=self.user, forum=self.forum)
         actions = ForumActions(user=self.user, forum=self.forum)
         self.assertEqual(actions.available_actions, [])
         self.assertEqual(actions.available_actions, [])
 
 
         self.override_acl({
         self.override_acl({
-            'can_change_threads_weight': 1,
+            'can_pin_threads': 1,
         })
         })
 
 
         actions = ForumActions(user=self.user, forum=self.forum)
         actions = ForumActions(user=self.user, forum=self.forum)
         self.assertEqual(actions.available_actions, [
         self.assertEqual(actions.available_actions, [
             {
             {
                 'action': 'pin',
                 'action': 'pin',
-                'icon': 'bookmark',
-                'name': _("Change to pinned")
-            },
-            {
-                'action': 'reset',
-                'icon': 'circle',
-                'name': _("Reset weight")
-            },
-        ])
-
-        self.override_acl({
-            'can_change_threads_weight': 2,
-        })
-
-        actions = ForumActions(user=self.user, forum=self.forum)
-        self.assertEqual(actions.available_actions, [
-            {
-                'action': 'announce',
                 'icon': 'star',
                 'icon': 'star',
-                'name': _("Change to announcements")
-            },
-            {
-                'action': 'pin',
-                'icon': 'bookmark',
-                'name': _("Change to pinned")
+                'name': _("Pin threads")
             },
             },
             {
             {
-                'action': 'reset',
+                'action': 'unpin',
                 'icon': 'circle',
                 'icon': 'circle',
-                'name': _("Reset weight")
+                'name': _("Unpin threads")
             },
             },
         ])
         ])
 
 
@@ -889,64 +866,44 @@ class ForumThreadsViewTests(AuthenticatedUserTestCase):
         self.assertEqual(response.status_code, 200)
         self.assertEqual(response.status_code, 200)
         self.assertIn("No threads were unlabeled.", response.content)
         self.assertIn("No threads were unlabeled.", response.content)
 
 
-    def test_moderate_threads_weight(self):
-        """moderation allows for changing threads weight"""
+    def test_pin_unpin_threads(self):
+        """moderation allows for pinning and unpinning threads"""
         test_acl = {
         test_acl = {
             'can_see': 1,
             'can_see': 1,
             'can_browse': 1,
             'can_browse': 1,
             'can_see_all_threads': 1,
             'can_see_all_threads': 1,
-            'can_change_threads_weight': 2
+            'can_pin_threads': 1
         }
         }
 
 
         self.override_acl(test_acl)
         self.override_acl(test_acl)
         response = self.client.get(self.link)
         response = self.client.get(self.link)
         self.assertEqual(response.status_code, 200)
         self.assertEqual(response.status_code, 200)
-        self.assertIn("Change to announcements", response.content)
+        self.assertIn("Pin threads", response.content)
 
 
-        announcement = testutils.post_thread(self.forum, weight=2)
-        pinned = testutils.post_thread(self.forum, weight=1)
-        thread = testutils.post_thread(self.forum, weight=0)
+        pinned = testutils.post_thread(self.forum, is_pinned=True)
+        thread = testutils.post_thread(self.forum, is_pinned=False)
 
 
-        # annouce nothing
+        # pin nothing
         self.override_acl(test_acl)
         self.override_acl(test_acl)
-        response = self.client.post(self.link, data={'action': 'announce'})
+        response = self.client.post(self.link, data={'action': 'pin'})
         self.assertEqual(response.status_code, 200)
         self.assertEqual(response.status_code, 200)
         self.assertIn("You have to select at least one thread.",
         self.assertIn("You have to select at least one thread.",
                       response.content)
                       response.content)
 
 
-        # make announcement announcement
+        # pin pinned
         self.override_acl(test_acl)
         self.override_acl(test_acl)
         response = self.client.post(self.link, data={
         response = self.client.post(self.link, data={
-            'action': 'announce', 'thread': [announcement.pk]
+            'action': 'pin', 'thread': [pinned.pk]
         })
         })
         self.assertEqual(response.status_code, 302)
         self.assertEqual(response.status_code, 302)
 
 
         self.override_acl(test_acl)
         self.override_acl(test_acl)
         response = self.client.get(self.link)
         response = self.client.get(self.link)
         self.assertEqual(response.status_code, 200)
         self.assertEqual(response.status_code, 200)
-        self.assertIn("No threads were changed to announcements.",
+        self.assertIn("No threads were pinned.",
                       response.content)
                       response.content)
 
 
-        # make non-announcements announcements
-        self.override_acl(test_acl)
-        response = self.client.post(self.link, data={
-            'action': 'announce', 'thread': [pinned.pk, thread.pk]
-        })
-        self.assertEqual(response.status_code, 302)
-
-        self.override_acl(test_acl)
-        response = self.client.get(self.link)
-        self.assertEqual(response.status_code, 200)
-        self.assertIn("2 threads were changed to announcements.",
-                      response.content)
-
-        pinned = Thread.objects.get(pk=pinned.pk)
-        thread = Thread.objects.get(pk=thread.pk)
-
-        self.assertEqual(pinned.weight, 2)
-        self.assertEqual(thread.weight, 2)
-
-        # make threads pinned
+        # pin unpinned
         self.override_acl(test_acl)
         self.override_acl(test_acl)
         response = self.client.post(self.link, data={
         response = self.client.post(self.link, data={
             'action': 'pin', 'thread': [pinned.pk, thread.pk]
             'action': 'pin', 'thread': [pinned.pk, thread.pk]
@@ -956,35 +913,32 @@ class ForumThreadsViewTests(AuthenticatedUserTestCase):
         self.override_acl(test_acl)
         self.override_acl(test_acl)
         response = self.client.get(self.link)
         response = self.client.get(self.link)
         self.assertEqual(response.status_code, 200)
         self.assertEqual(response.status_code, 200)
-        self.assertIn("2 threads were pinned.", response.content)
+        self.assertIn("1 thread was pinned.",
+                      response.content)
 
 
-        announcement = Thread.objects.get(pk=announcement.pk)
         pinned = Thread.objects.get(pk=pinned.pk)
         pinned = Thread.objects.get(pk=pinned.pk)
         thread = Thread.objects.get(pk=thread.pk)
         thread = Thread.objects.get(pk=thread.pk)
 
 
-        self.assertEqual(announcement.weight, 2)
-        self.assertEqual(pinned.weight, 1)
-        self.assertEqual(thread.weight, 1)
+        self.assertTrue(pinned.is_pinned)
+        self.assertTrue(thread.is_pinned)
 
 
-        # reset threads pinned
+        # unpin thread
         self.override_acl(test_acl)
         self.override_acl(test_acl)
         response = self.client.post(self.link, data={
         response = self.client.post(self.link, data={
-            'action': 'reset', 'thread': [thread.pk]
+            'action': 'unpin', 'thread': [thread.pk]
         })
         })
         self.assertEqual(response.status_code, 302)
         self.assertEqual(response.status_code, 302)
 
 
         self.override_acl(test_acl)
         self.override_acl(test_acl)
         response = self.client.get(self.link)
         response = self.client.get(self.link)
         self.assertEqual(response.status_code, 200)
         self.assertEqual(response.status_code, 200)
-        self.assertIn("1 thread weight was reset.", response.content)
+        self.assertIn("1 thread was unpinned.", response.content)
 
 
-        announcement = Thread.objects.get(pk=announcement.pk)
         pinned = Thread.objects.get(pk=pinned.pk)
         pinned = Thread.objects.get(pk=pinned.pk)
         thread = Thread.objects.get(pk=thread.pk)
         thread = Thread.objects.get(pk=thread.pk)
 
 
-        self.assertEqual(announcement.weight, 2)
-        self.assertEqual(pinned.weight, 1)
-        self.assertEqual(thread.weight, 0)
+        self.assertTrue(pinned.is_pinned)
+        self.assertFalse(thread.is_pinned)
 
 
     def test_approve_moderated_threads(self):
     def test_approve_moderated_threads(self):
         """moderation allows for aproving moderated threads"""
         """moderation allows for aproving moderated threads"""

+ 0 - 3
misago/threads/tests/test_post_model.py

@@ -20,7 +20,6 @@ class PostModelTests(TestCase):
         self.forum = Forum.objects.filter(role="forum")[:1][0]
         self.forum = Forum.objects.filter(role="forum")[:1][0]
         self.thread = Thread(
         self.thread = Thread(
             forum=self.forum,
             forum=self.forum,
-            weight=0,
             started_on=datetime,
             started_on=datetime,
             starter_name='Tester',
             starter_name='Tester',
             starter_slug='tester',
             starter_slug='tester',
@@ -75,7 +74,6 @@ class PostModelTests(TestCase):
 
 
         other_thread = Thread.objects.create(
         other_thread = Thread.objects.create(
             forum=self.forum,
             forum=self.forum,
-            weight=0,
             started_on=timezone.now(),
             started_on=timezone.now(),
             starter_name='Tester',
             starter_name='Tester',
             starter_slug='tester',
             starter_slug='tester',
@@ -138,7 +136,6 @@ class PostModelTests(TestCase):
         """move method moves post to other thread"""
         """move method moves post to other thread"""
         new_thread = Thread.objects.create(
         new_thread = Thread.objects.create(
             forum=self.forum,
             forum=self.forum,
-            weight=0,
             started_on=timezone.now(),
             started_on=timezone.now(),
             starter_name='Tester',
             starter_name='Tester',
             starter_slug='tester',
             starter_slug='tester',

+ 0 - 2
misago/threads/tests/test_thread_model.py

@@ -16,7 +16,6 @@ class ThreadModelTests(TestCase):
         self.forum = Forum.objects.filter(role="forum")[:1][0]
         self.forum = Forum.objects.filter(role="forum")[:1][0]
         self.thread = Thread(
         self.thread = Thread(
             forum=self.forum,
             forum=self.forum,
-            weight=0,
             started_on=datetime,
             started_on=datetime,
             starter_name='Tester',
             starter_name='Tester',
             starter_slug='tester',
             starter_slug='tester',
@@ -251,7 +250,6 @@ class ThreadModelTests(TestCase):
 
 
         other_thread = Thread(
         other_thread = Thread(
             forum=self.forum,
             forum=self.forum,
-            weight=0,
             started_on=datetime,
             started_on=datetime,
             starter_name='Tester',
             starter_name='Tester',
             starter_slug='tester',
             starter_slug='tester',

+ 14 - 35
misago/threads/tests/test_threads_moderation.py

@@ -53,57 +53,36 @@ class ThreadsModerationTests(AuthenticatedUserTestCase):
         self.assertEqual(event.icon, "tag")
         self.assertEqual(event.icon, "tag")
         self.assertIn("removed thread label.", event.message)
         self.assertIn("removed thread label.", event.message)
 
 
-    def test_announce_thread(self):
-        """announce_thread makes thread announcement"""
-        self.assertEqual(self.thread.weight, 0)
-        self.assertTrue(moderation.announce_thread(self.user, self.thread))
-
-        self.reload_thread()
-        self.assertEqual(self.thread.weight, 2)
-
-        self.assertTrue(self.thread.has_events)
-        event = self.thread.event_set.last()
-
-        self.assertEqual(event.icon, "star")
-        self.assertIn("changed thread to announcement.", event.message)
-
-    def test_announce_invalid_thread(self):
-        """announce_thread returns false for already announced thread"""
-        self.thread.weight = 2
-
-        self.assertFalse(moderation.announce_thread(self.user, self.thread))
-        self.assertEqual(self.thread.weight, 2)
-
     def test_pin_thread(self):
     def test_pin_thread(self):
         """pin_thread makes thread pinned"""
         """pin_thread makes thread pinned"""
-        self.assertEqual(self.thread.weight, 0)
+        self.assertFalse(self.thread.is_pinned)
         self.assertTrue(moderation.pin_thread(self.user, self.thread))
         self.assertTrue(moderation.pin_thread(self.user, self.thread))
 
 
         self.reload_thread()
         self.reload_thread()
-        self.assertEqual(self.thread.weight, 1)
+        self.assertTrue(self.thread.is_pinned)
 
 
         self.assertTrue(self.thread.has_events)
         self.assertTrue(self.thread.has_events)
         event = self.thread.event_set.last()
         event = self.thread.event_set.last()
 
 
-        self.assertEqual(event.icon, "bookmark")
+        self.assertEqual(event.icon, "star")
         self.assertIn("pinned thread.", event.message)
         self.assertIn("pinned thread.", event.message)
 
 
     def test_pin_invalid_thread(self):
     def test_pin_invalid_thread(self):
         """pin_thread returns false for already pinned thread"""
         """pin_thread returns false for already pinned thread"""
-        self.thread.weight = 1
+        self.thread.is_pinned = True
 
 
         self.assertFalse(moderation.pin_thread(self.user, self.thread))
         self.assertFalse(moderation.pin_thread(self.user, self.thread))
-        self.assertEqual(self.thread.weight, 1)
+        self.assertTrue(self.thread.is_pinned)
 
 
-    def test_reset_thread(self):
-        """reset_thread defaults thread weight"""
+    def test_unpin_thread(self):
+        """unpin_thread defaults thread weight"""
         moderation.pin_thread(self.user, self.thread)
         moderation.pin_thread(self.user, self.thread)
 
 
-        self.assertEqual(self.thread.weight, 1)
-        self.assertTrue(moderation.reset_thread(self.user, self.thread))
+        self.assertTrue(self.thread.is_pinned)
+        self.assertTrue(moderation.unpin_thread(self.user, self.thread))
 
 
         self.reload_thread()
         self.reload_thread()
-        self.assertEqual(self.thread.weight, 0)
+        self.assertFalse(self.thread.is_pinned)
 
 
         self.assertTrue(self.thread.has_events)
         self.assertTrue(self.thread.has_events)
         event = self.thread.event_set.last()
         event = self.thread.event_set.last()
@@ -111,10 +90,10 @@ class ThreadsModerationTests(AuthenticatedUserTestCase):
         self.assertIn("unpinned thread.", event.message)
         self.assertIn("unpinned thread.", event.message)
         self.assertEqual(event.icon, "circle")
         self.assertEqual(event.icon, "circle")
 
 
-    def test_reset_invalid_thread(self):
-        """reset_thread returns false for already default thread"""
-        self.assertFalse(moderation.reset_thread(self.user, self.thread))
-        self.assertEqual(self.thread.weight, 0)
+    def test_unpin_invalid_thread(self):
+        """unpin_thread returns false for already pinned thread"""
+        self.assertFalse(moderation.unpin_thread(self.user, self.thread))
+        self.assertFalse(self.thread.is_pinned)
 
 
     def test_approve_thread(self):
     def test_approve_thread(self):
         """approve_thread approves moderated thread"""
         """approve_thread approves moderated thread"""

+ 2 - 2
misago/threads/testutils.py

@@ -7,18 +7,18 @@ from misago.core.utils import slugify
 from misago.threads.models import Thread, Post
 from misago.threads.models import Thread, Post
 
 
 
 
-def post_thread(forum, title='Test thread', weight=0, poster='Tester',
+def post_thread(forum, title='Test thread', poster='Tester', is_pinned=False,
                 is_moderated=False, is_hidden=False, is_closed=False,
                 is_moderated=False, is_hidden=False, is_closed=False,
                 started_on=None):
                 started_on=None):
     started_on = started_on or timezone.now()
     started_on = started_on or timezone.now()
 
 
     kwargs = {
     kwargs = {
         'forum': forum,
         'forum': forum,
-        'weight': weight,
         'title': title,
         'title': title,
         'slug': slugify(title),
         'slug': slugify(title),
         'started_on': started_on,
         'started_on': started_on,
         'last_post_on': started_on,
         'last_post_on': started_on,
+        'is_pinned': is_pinned,
         'is_moderated': is_moderated,
         'is_moderated': is_moderated,
         'is_hidden': is_hidden,
         'is_hidden': is_hidden,
         'is_closed': is_closed,
         'is_closed': is_closed,

+ 13 - 33
misago/threads/views/generic/forum/actions.py

@@ -36,22 +36,16 @@ class ForumActions(Actions):
                     'name': _("Remove labels")
                     'name': _("Remove labels")
                 })
                 })
 
 
-        if self.forum.acl['can_change_threads_weight'] == 2:
-            actions.append({
-                'action': 'announce',
-                'icon': 'star',
-                'name': _("Change to announcements")
-            })
-        if self.forum.acl['can_change_threads_weight']:
+        if self.forum.acl['can_pin_threads']:
             actions.append({
             actions.append({
                 'action': 'pin',
                 'action': 'pin',
-                'icon': 'bookmark',
-                'name': _("Change to pinned")
+                'icon': 'star',
+                'name': _("Pin threads")
             })
             })
             actions.append({
             actions.append({
-                'action': 'reset',
+                'action': 'unpin',
                 'icon': 'circle',
                 'icon': 'circle',
-                'name': _("Reset weight")
+                'name': _("Unpin threads")
             })
             })
 
 
         if self.forum.acl['can_review_moderated_content']:
         if self.forum.acl['can_review_moderated_content']:
@@ -150,22 +144,6 @@ class ForumActions(Actions):
             message = _("No threads were unlabeled.")
             message = _("No threads were unlabeled.")
             messages.info(request, message)
             messages.info(request, message)
 
 
-    def action_announce(self, request, threads):
-        changed_threads = 0
-        for thread in threads:
-            if moderation.announce_thread(request.user, thread):
-                changed_threads += 1
-
-        if changed_threads:
-            message = ungettext(
-                '%(changed)d thread was changed to announcement.',
-                '%(changed)d threads were changed to announcements.',
-            changed_threads)
-            messages.success(request, message % {'changed': changed_threads})
-        else:
-            message = _("No threads were changed to announcements.")
-            messages.info(request, message)
-
     def action_pin(self, request, threads):
     def action_pin(self, request, threads):
         changed_threads = 0
         changed_threads = 0
         for thread in threads:
         for thread in threads:
@@ -182,20 +160,20 @@ class ForumActions(Actions):
             message = _("No threads were pinned.")
             message = _("No threads were pinned.")
             messages.info(request, message)
             messages.info(request, message)
 
 
-    def action_reset(self, request, threads):
+    def action_unpin(self, request, threads):
         changed_threads = 0
         changed_threads = 0
         for thread in threads:
         for thread in threads:
-            if moderation.reset_thread(request.user, thread):
+            if moderation.unpin_thread(request.user, thread):
                 changed_threads += 1
                 changed_threads += 1
 
 
         if changed_threads:
         if changed_threads:
             message = ungettext(
             message = ungettext(
-                '%(changed)d thread weight was reset.',
-                '%(changed)d threads weight was reset.',
+                '%(changed)d thread was unpinned.',
+                '%(changed)d threads were unpinned.',
             changed_threads)
             changed_threads)
             messages.success(request, message % {'changed': changed_threads})
             messages.success(request, message % {'changed': changed_threads})
         else:
         else:
-            message = _("No threads weight was reset.")
+            message = _("No threads were unpinned.")
             messages.info(request, message)
             messages.info(request, message)
 
 
     move_threads_template = 'misago/threads/move.html'
     move_threads_template = 'misago/threads/move.html'
@@ -252,7 +230,6 @@ class ForumActions(Actions):
 
 
                 with atomic():
                 with atomic():
                     merged_thread = Thread()
                     merged_thread = Thread()
-                    merged_thread.weight = max(t.weight for t in threads)
                     merged_thread.forum = self.forum
                     merged_thread.forum = self.forum
                     merged_thread.set_title(
                     merged_thread.set_title(
                         form.cleaned_data['merged_thread_title'])
                         form.cleaned_data['merged_thread_title'])
@@ -262,6 +239,9 @@ class ForumActions(Actions):
                     merged_thread.last_poster_slug = "-"
                     merged_thread.last_poster_slug = "-"
                     merged_thread.started_on = timezone.now()
                     merged_thread.started_on = timezone.now()
                     merged_thread.last_post_on = timezone.now()
                     merged_thread.last_post_on = timezone.now()
+                    merged_thread.is_pinned = max(t.is_pinned for t in threads)
+                    merged_thread.is_closed = max(t.is_closed for t in threads)
+                    merged_thread.is_hidden = max(t.is_hidden for t in threads)
                     merged_thread.save()
                     merged_thread.save()
 
 
                     for thread in threads:
                     for thread in threads:

+ 7 - 12
misago/threads/views/generic/forum/threads.py

@@ -1,6 +1,5 @@
 from misago.core.shortcuts import paginate
 from misago.core.shortcuts import paginate
 
 
-from misago.threads.models import ANNOUNCEMENT
 from misago.threads.permissions import exclude_invisible_threads
 from misago.threads.permissions import exclude_invisible_threads
 from misago.threads.views.generic.threads import Threads
 from misago.threads.views.generic.threads import Threads
 
 
@@ -14,31 +13,27 @@ class ForumThreads(Threads):
         self.forum = forum
         self.forum = forum
 
 
         self.filter_by = None
         self.filter_by = None
-        self.sort_by = ('-weight', '-last_post_on')
+        self.sort_by = '-last_post_on'
 
 
     def filter(self, filter_by):
     def filter(self, filter_by):
         self.filter_by = filter_by
         self.filter_by = filter_by
 
 
     def sort(self, sort_by):
     def sort(self, sort_by):
-        if sort_by[0] == '-':
-            weight = '-weight'
-        else:
-            weight = 'weight'
-        self.sort_by = (weight, sort_by)
+        self.sort_by = sort_by
 
 
     def list(self, page=0):
     def list(self, page=0):
         queryset = self.get_queryset()
         queryset = self.get_queryset()
-        queryset = queryset.order_by(*self.sort_by)
+        queryset = queryset.order_by(self.sort_by)
 
 
-        announcements_qs = queryset.filter(weight=ANNOUNCEMENT)
-        threads_qs = queryset.filter(weight__lt=ANNOUNCEMENT)
+        pinned_qs = queryset.filter(is_pinned=True)
+        threads_qs = queryset.filter(is_pinned=False)
 
 
         self._page = paginate(threads_qs, page, 20, 10)
         self._page = paginate(threads_qs, page, 20, 10)
         self._paginator = self._page.paginator
         self._paginator = self._page.paginator
 
 
         threads = []
         threads = []
-        for announcement in announcements_qs:
-            threads.append(announcement)
+        for thread in pinned_qs:
+            threads.append(thread)
         for thread in self._page.object_list:
         for thread in self._page.object_list:
             threads.append(thread)
             threads.append(thread)
 
 

+ 1 - 1
misago/threads/views/generic/posting.py

@@ -9,7 +9,7 @@ from misago.forums.lists import get_forum_path
 
 
 from misago.threads.posting import (PostingInterrupt, EditorFormset,
 from misago.threads.posting import (PostingInterrupt, EditorFormset,
                                     START, REPLY, EDIT)
                                     START, REPLY, EDIT)
-from misago.threads.models import ANNOUNCEMENT, Thread, Post, Label
+from misago.threads.models import Thread, Post, Label
 from misago.threads.permissions import allow_start_thread
 from misago.threads.permissions import allow_start_thread
 from misago.threads.views.generic.base import ViewBase
 from misago.threads.views.generic.base import ViewBase