Browse Source

Refactored threads views hierarchy

Rafał Pitoń 10 years ago
parent
commit
870e880b46

+ 3 - 0
misago/forums/lists.py

@@ -71,6 +71,9 @@ def get_forums_list(user, parent=None):
 
 
 
 
 def get_forum_path(forum):
 def get_forum_path(forum):
+    if forum.special_role:
+        return [forum]
+
     forums_dict = Forum.objects.get_cached_forums_dict()
     forums_dict = Forum.objects.get_cached_forums_dict()
 
 
     forum_path = []
     forum_path = []

+ 10 - 2
misago/forums/models.py

@@ -140,7 +140,9 @@ class Forum(MPTTModel):
         return urlparse(self.redirect_url).hostname
         return urlparse(self.redirect_url).hostname
 
 
     def get_absolute_url(self):
     def get_absolute_url(self):
-        if not self.special_role:
+        if self.special_role == 'private_threads':
+            return reverse('misago:private_threads')
+        else:
             if self.level == 1:
             if self.level == 1:
                 formats = (reverse('misago:index'), self.slug, self.id)
                 formats = (reverse('misago:index'), self.slug, self.id)
                 return '%s#%s-%s' % formats
                 return '%s#%s-%s' % formats
@@ -148,8 +150,14 @@ class Forum(MPTTModel):
                 return reverse('misago:%s' % self.role, kwargs={
                 return reverse('misago:%s' % self.role, kwargs={
                     'forum_id': self.id, 'forum_slug': self.slug
                     'forum_id': self.id, 'forum_slug': self.slug
                 })
                 })
+
+    def get_new_thread_url(self):
+        if self.special_role == 'private_threads':
+            return reverse('misago:private_thread_new')
         else:
         else:
-            return None
+            return reverse('misago:thread_new' % self.role, kwargs={
+                'forum_id': self.id, 'forum_slug': self.slug
+            })
 
 
     def set_name(self, name):
     def set_name(self, name):
         self.name = name
         self.name = name

+ 1 - 1
misago/templates/misago/thread/replies.html

@@ -163,7 +163,7 @@
         }
         }
 
 
         Misago.Posting.load({
         Misago.Posting.load({
-          api_url: "{% url 'misago:reply_thread' forum_id=forum.id thread_id=thread.id %}",
+          api_url: "{{ thread.get_reply_api_url }}",
           on_load: function() {
           on_load: function() {
             $('.reply-to-thread').hide();
             $('.reply-to-thread').hide();
             extra_on_load();
             extra_on_load();

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

@@ -162,6 +162,17 @@ class Thread(models.Model, PrivateThreadMixin):
     def get_reported_url(self):
     def get_reported_url(self):
         return self.get_url('reported')
         return self.get_url('reported')
 
 
+    def get_reply_api_url(self):
+        if self.forum.special_role == 'private_threads':
+            return reverse('misago:reply_private_thread', kwargs={
+                'thread_id': self.id,
+            })
+        else:
+            return reverse('misago:reply_thread', kwargs={
+                'forum_id': self.forum.id,
+                'thread_id': self.id,
+            })
+
     def set_title(self, title):
     def set_title(self, title):
         self.title = title
         self.title = title
         self.slug = slugify(title)
         self.slug = slugify(title)

+ 78 - 2
misago/threads/permissions/privatethreads.py

@@ -7,11 +7,16 @@ from misago.acl import add_acl, algebra
 from misago.acl.decorators import return_boolean
 from misago.acl.decorators import return_boolean
 from misago.acl.models import Role
 from misago.acl.models import Role
 from misago.core import forms
 from misago.core import forms
+from misago.forums.models import Forum
 
 
 
 
 __all__ = [
 __all__ = [
     'allow_use_private_threads',
     'allow_use_private_threads',
     'can_use_private_threads',
     'can_use_private_threads',
+    'allow_see_private_thread',
+    'can_see_private_thread',
+    'allow_see_private_post',
+    'can_see_private_post',
     'allow_message_user',
     'allow_message_user',
     'can_message_user',
     'can_message_user',
     'exclude_invisible_private_threads',
     'exclude_invisible_private_threads',
@@ -78,6 +83,54 @@ def build_acl(acl, roles, key_name):
         can_moderate_private_threads=algebra.greater
         can_moderate_private_threads=algebra.greater
     )
     )
 
 
+    if not new_acl['can_use_private_threads']:
+        return new_acl
+
+    private_forum = Forum.objects.private_threads()
+
+    if new_acl['can_moderate_private_threads']:
+        new_acl['moderated_forums'].append(private_forum.pk)
+
+    forum_acl = {
+        'can_see': 1,
+        'can_browse': 1,
+        'can_see_all_threads': 1,
+        'can_see_own_threads': 0,
+        'can_start_threads': new_acl['can_start_private_threads'],
+        'can_reply_threads': 1,
+        'can_edit_threads': 1,
+        'can_edit_posts': 1,
+        'can_hide_own_threads': 0,
+        'can_hide_own_posts': 1,
+        'thread_edit_time': 0,
+        'post_edit_time': 0,
+        'can_hide_threads': 0,
+        'can_hide_posts': 0,
+        'can_protect_posts': 0,
+        'can_merge_posts': 0,
+        'can_close_threads': 0,
+        'can_review_moderated_content': 0,
+        'can_report_content': new_acl['can_report_private_threads'],
+        'can_see_reports': 0,
+        'can_hide_events': 0,
+    }
+
+    if new_acl['can_moderate_private_threads']:
+        forum_acl.update({
+            'can_edit_threads': 2,
+            'can_edit_posts': 2,
+            'can_hide_threads': 2,
+            'can_hide_posts': 2,
+            'can_protect_posts': 1,
+            'can_merge_posts': 1,
+            'can_see_reports': 1,
+            'can_see_reports': 1,
+            'can_review_moderated_content': 1,
+            'can_hide_events': 2,
+        })
+
+    new_acl['forums'][private_forum.pk] = forum_acl
+
     return new_acl
     return new_acl
 
 
 
 
@@ -93,6 +146,25 @@ def allow_use_private_threads(user):
 can_use_private_threads = return_boolean(allow_use_private_threads)
 can_use_private_threads = return_boolean(allow_use_private_threads)
 
 
 
 
+def allow_see_private_thread(user, target):
+    can_see_moderated = user.acl.get('can_moderate_private_threads')
+    can_see_moderated = can_see_moderated and target.has_reported_posts
+    can_see_participating = user in [p.user for p in target.participants_list]
+
+    if not (can_see_participating or can_see_moderated):
+        raise Http404()
+can_see_private_thread = return_boolean(allow_see_private_thread)
+
+
+def allow_see_private_post(user, target):
+    can_see_moderated = user.acl.get('can_moderate_private_threads')
+    if not (can_see_moderated and target.thread.has_reported_posts):
+        for participant in target.thread.participants_list:
+            if participant.user == user and participant.is_removed:
+                if post.posted_on > target.last_post_on:
+                    raise Http404()
+can_see_private_post = return_boolean(allow_see_private_post)
+
 
 
 def allow_message_user(user, target):
 def allow_message_user(user, target):
     allow_use_private_threads(user)
     allow_use_private_threads(user)
@@ -103,11 +175,15 @@ def allow_message_user(user, target):
     if not user.acl['can_start_private_threads']:
     if not user.acl['can_start_private_threads']:
         raise PermissionDenied(_("You can't start private threads."))
         raise PermissionDenied(_("You can't start private threads."))
 
 
+    message_format = {'user': user.username}
+
+    if not can_use_private_threads(target):
+        message = _("%(user)s can't participate in private threads.")
+        raise PermissionDenied(message % message_format)
+
     if user.acl['can_add_everyone_to_private_threads']:
     if user.acl['can_add_everyone_to_private_threads']:
         return None
         return None
 
 
-    message_format = {'user': user.username}
-
     if user.acl['can_be_blocked'] and target.is_blocking(user):
     if user.acl['can_be_blocked'] and target.is_blocking(user):
         message = _("%(user)s is blocking you.")
         message = _("%(user)s is blocking you.")
         raise PermissionDenied(message % message_format)
         raise PermissionDenied(message % message_format)

+ 2 - 6
misago/threads/urls/__init__.py

@@ -1,10 +1,6 @@
 # flake8: noqa
 # flake8: noqa
-from misago.threads.urls import events, posts, privatethreads, threads
+from misago.threads.urls import privatethreads, threads
 
 
 
 
-urlpatterns = []
-
-urlpatterns += events.urlpatterns
-urlpatterns += posts.urlpatterns
+urlpatterns = threads.urlpatterns
 urlpatterns += privatethreads.urlpatterns
 urlpatterns += privatethreads.urlpatterns
-urlpatterns += threads.urlpatterns

+ 0 - 7
misago/threads/urls/events.py

@@ -1,7 +0,0 @@
-from django.conf.urls import patterns, include, url
-from misago.threads.views.events import EventsView
-
-
-urlpatterns = patterns('',
-    url(r'^edit-event/(?P<event_id>\d+)/$', EventsView.as_view(), name='edit_event'),
-)

+ 0 - 13
misago/threads/urls/posts.py

@@ -1,13 +0,0 @@
-from django.conf.urls import patterns, include, url
-from misago.threads.views.post import (QuotePostView, ApprovePostView,
-                                       HidePostView, UnhidePostView,
-                                       DeletePostView)
-
-
-urlpatterns = patterns('',
-    url(r'^post/(?P<post_id>\d+)/quote/$', QuotePostView.as_view(), name='quote_post'),
-    url(r'^post/(?P<post_id>\d+)/approve/$', ApprovePostView.as_view(), name='approve_post'),
-    url(r'^post/(?P<post_id>\d+)/unhide/$', UnhidePostView.as_view(), name='unhide_post'),
-    url(r'^post/(?P<post_id>\d+)/hide/$', HidePostView.as_view(), name='hide_post'),
-    url(r'^post/(?P<post_id>\d+)/delete/$', DeletePostView.as_view(), name='delete_post'),
-)

+ 46 - 11
misago/threads/urls/privatethreads.py

@@ -1,32 +1,67 @@
 from django.conf.urls import patterns, include, url
 from django.conf.urls import patterns, include, url
 
 
 
 
-from misago.threads.views.privatethreads import ThreadsView
+from misago.threads.views.privatethreads import PrivateThreadsView
 urlpatterns = patterns('',
 urlpatterns = patterns('',
-    url(r'^private-threads/$', ThreadsView.as_view(), name='private_threads'),
-    url(r'^private-threads/(?P<page>\d+)/$', ThreadsView.as_view(), name='private_threads'),
-    url(r'^private-threads/sort-(?P<sort>[\w-]+)/$', ThreadsView.as_view(), name='private_threads'),
-    url(r'^private-threads/sort-(?P<sort>[\w-]+)/(?P<page>\d+)/$', ThreadsView.as_view(), name='private_threads'),
-    url(r'^private-threads/show-(?P<show>[\w-]+)/$', ThreadsView.as_view(), name='private_threads'),
-    url(r'^private-threads/show-(?P<show>[\w-]+)/(?P<page>\d+)/$', ThreadsView.as_view(), name='private_threads'),
-    url(r'^private-threads/sort-(?P<sort>[\w-]+)/show-(?P<show>[\w-]+)/$', ThreadsView.as_view(), name='private_threads'),
-    url(r'^private-threads/sort-(?P<sort>[\w-]+)/show-(?P<show>[\w-]+)/(?P<page>\d+)/$', ThreadsView.as_view(), name='private_threads'),
+    url(r'^private-threads/$', PrivateThreadsView.as_view(), name='private_threads'),
+    url(r'^private-threads/(?P<page>\d+)/$', PrivateThreadsView.as_view(), name='private_threads'),
+    url(r'^private-threads/sort-(?P<sort>[\w-]+)/$', PrivateThreadsView.as_view(), name='private_threads'),
+    url(r'^private-threads/sort-(?P<sort>[\w-]+)/(?P<page>\d+)/$', PrivateThreadsView.as_view(), name='private_threads'),
+    url(r'^private-threads/show-(?P<show>[\w-]+)/$', PrivateThreadsView.as_view(), name='private_threads'),
+    url(r'^private-threads/show-(?P<show>[\w-]+)/(?P<page>\d+)/$', PrivateThreadsView.as_view(), name='private_threads'),
+    url(r'^private-threads/sort-(?P<sort>[\w-]+)/show-(?P<show>[\w-]+)/$', PrivateThreadsView.as_view(), name='private_threads'),
+    url(r'^private-threads/sort-(?P<sort>[\w-]+)/show-(?P<show>[\w-]+)/(?P<page>\d+)/$', PrivateThreadsView.as_view(), name='private_threads'),
 )
 )
 
 
 
 
-from misago.threads.views.privatethreads import (ThreadView, GotoLastView,
-                                                 GotoNewView, GotoPostView)
+# thread view
+from misago.threads.views.privatethreads import ThreadView
 urlpatterns += patterns('',
 urlpatterns += patterns('',
     url(r'^private-thread/(?P<thread_slug>[\w\d-]+)-(?P<thread_id>\d+)/$', ThreadView.as_view(), name='private_thread'),
     url(r'^private-thread/(?P<thread_slug>[\w\d-]+)-(?P<thread_id>\d+)/$', ThreadView.as_view(), name='private_thread'),
     url(r'^private-thread/(?P<thread_slug>[\w\d-]+)-(?P<thread_id>\d+)/(?P<page>\d+)/$', ThreadView.as_view(), name='private_thread'),
     url(r'^private-thread/(?P<thread_slug>[\w\d-]+)-(?P<thread_id>\d+)/(?P<page>\d+)/$', ThreadView.as_view(), name='private_thread'),
+)
+
+
+# goto views
+from misago.threads.views.privatethreads import (GotoLastView, GotoNewView,
+                                                 GotoPostView)
+urlpatterns += patterns('',
     url(r'^private-thread/(?P<thread_slug>[\w\d-]+)-(?P<thread_id>\d+)/last/$', GotoLastView.as_view(), name='private_thread_last'),
     url(r'^private-thread/(?P<thread_slug>[\w\d-]+)-(?P<thread_id>\d+)/last/$', GotoLastView.as_view(), name='private_thread_last'),
     url(r'^private-thread/(?P<thread_slug>[\w\d-]+)-(?P<thread_id>\d+)/new/$', GotoNewView.as_view(), name='private_thread_new'),
     url(r'^private-thread/(?P<thread_slug>[\w\d-]+)-(?P<thread_id>\d+)/new/$', GotoNewView.as_view(), name='private_thread_new'),
     url(r'^private-thread/(?P<thread_slug>[\w\d-]+)-(?P<thread_id>\d+)/post-(?P<post_id>\d+)/$', GotoPostView.as_view(), name='private_thread_post'),
     url(r'^private-thread/(?P<thread_slug>[\w\d-]+)-(?P<thread_id>\d+)/post-(?P<post_id>\d+)/$', GotoPostView.as_view(), name='private_thread_post'),
 )
 )
 
 
 
 
+# moderated/reported posts views
+from misago.threads.views.privatethreads import ReportedPostsListView
+urlpatterns += patterns('',
+    url(r'^private-thread/(?P<thread_slug>[\w\d-]+)-(?P<thread_id>\d+)/reported-posts/$', ReportedPostsListView.as_view(), name='private_thread_reported'),
+)
+
+
+# post views
+from misago.threads.views.privatethreads import (QuotePostView, HidePostView,
+                                                 UnhidePostView,
+                                                 DeletePostView)
+urlpatterns += patterns('',
+    url(r'^private-post/(?P<post_id>\d+)/quote/$', QuotePostView.as_view(), name='quote_private_post'),
+    url(r'^private-post/(?P<post_id>\d+)/unhide/$', UnhidePostView.as_view(), name='unhide_private_post'),
+    url(r'^private-post/(?P<post_id>\d+)/hide/$', HidePostView.as_view(), name='hide_private_post'),
+    url(r'^private-post/(?P<post_id>\d+)/delete/$', DeletePostView.as_view(), name='delete_private_post'),
+)
+
+
+# events view
+from misago.threads.views.privatethreads import EventsView
+urlpatterns += patterns('',
+    url(r'^edit-private-event/(?P<event_id>\d+)/$', EventsView.as_view(), name='edit_private_event'),
+)
+
+
+# posting views
 from misago.threads.views.privatethreads import PostingView
 from misago.threads.views.privatethreads import PostingView
 urlpatterns += patterns('',
 urlpatterns += patterns('',
     url(r'^start-private-thread/$', PostingView.as_view(), name='start_private_thread'),
     url(r'^start-private-thread/$', PostingView.as_view(), name='start_private_thread'),
     url(r'^reply-private-thread/(?P<thread_id>\d+)/$', PostingView.as_view(), name='reply_private_thread'),
     url(r'^reply-private-thread/(?P<thread_id>\d+)/$', PostingView.as_view(), name='reply_private_thread'),
+    url(r'^edit-private_post/(?P<thread_id>\d+)/(?P<post_id>\d+)/edit/$', PostingView.as_view(), name='edit_private_post'),
 )
 )

+ 33 - 3
misago/threads/urls/threads.py

@@ -1,6 +1,7 @@
 from django.conf.urls import patterns, include, url
 from django.conf.urls import patterns, include, url
 
 
 
 
+# forum view
 from misago.threads.views.threads import ForumView
 from misago.threads.views.threads import ForumView
 urlpatterns = patterns('',
 urlpatterns = patterns('',
     url(r'^forum/(?P<forum_slug>[\w\d-]+)-(?P<forum_id>\d+)/$', ForumView.as_view(), name='forum'),
     url(r'^forum/(?P<forum_slug>[\w\d-]+)-(?P<forum_id>\d+)/$', ForumView.as_view(), name='forum'),
@@ -14,17 +15,25 @@ urlpatterns = patterns('',
 )
 )
 
 
 
 
-from misago.threads.views.threads import (ThreadView, GotoLastView,
-                                          GotoNewView, GotoPostView)
+# thread view
+from misago.threads.views.threads import ThreadView
 urlpatterns += patterns('',
 urlpatterns += patterns('',
     url(r'^thread/(?P<thread_slug>[\w\d-]+)-(?P<thread_id>\d+)/$', ThreadView.as_view(), name='thread'),
     url(r'^thread/(?P<thread_slug>[\w\d-]+)-(?P<thread_id>\d+)/$', ThreadView.as_view(), name='thread'),
     url(r'^thread/(?P<thread_slug>[\w\d-]+)-(?P<thread_id>\d+)/(?P<page>\d+)/$', ThreadView.as_view(), name='thread'),
     url(r'^thread/(?P<thread_slug>[\w\d-]+)-(?P<thread_id>\d+)/(?P<page>\d+)/$', ThreadView.as_view(), name='thread'),
+)
+
+
+# goto views
+from misago.threads.views.threads import (GotoLastView, GotoNewView,
+                                          GotoPostView)
+urlpatterns += patterns('',
     url(r'^thread/(?P<thread_slug>[\w\d-]+)-(?P<thread_id>\d+)/last/$', GotoLastView.as_view(), name='thread_last'),
     url(r'^thread/(?P<thread_slug>[\w\d-]+)-(?P<thread_id>\d+)/last/$', GotoLastView.as_view(), name='thread_last'),
     url(r'^thread/(?P<thread_slug>[\w\d-]+)-(?P<thread_id>\d+)/new/$', GotoNewView.as_view(), name='thread_new'),
     url(r'^thread/(?P<thread_slug>[\w\d-]+)-(?P<thread_id>\d+)/new/$', GotoNewView.as_view(), name='thread_new'),
     url(r'^thread/(?P<thread_slug>[\w\d-]+)-(?P<thread_id>\d+)/post-(?P<post_id>\d+)/$', GotoPostView.as_view(), name='thread_post'),
     url(r'^thread/(?P<thread_slug>[\w\d-]+)-(?P<thread_id>\d+)/post-(?P<post_id>\d+)/$', GotoPostView.as_view(), name='thread_post'),
 )
 )
 
 
 
 
+# moderated/reported posts views
 from misago.threads.views.threads import (ModeratedPostsListView,
 from misago.threads.views.threads import (ModeratedPostsListView,
                                           ReportedPostsListView)
                                           ReportedPostsListView)
 urlpatterns += patterns('',
 urlpatterns += patterns('',
@@ -33,7 +42,28 @@ urlpatterns += patterns('',
 )
 )
 
 
 
 
-from misago.threads.views.posting import PostingView
+# post views
+from misago.threads.views.threads import (QuotePostView, ApprovePostView,
+                                          HidePostView, UnhidePostView,
+                                          DeletePostView)
+urlpatterns += patterns('',
+    url(r'^post/(?P<post_id>\d+)/quote/$', QuotePostView.as_view(), name='quote_post'),
+    url(r'^post/(?P<post_id>\d+)/approve/$', ApprovePostView.as_view(), name='approve_post'),
+    url(r'^post/(?P<post_id>\d+)/unhide/$', UnhidePostView.as_view(), name='unhide_post'),
+    url(r'^post/(?P<post_id>\d+)/hide/$', HidePostView.as_view(), name='hide_post'),
+    url(r'^post/(?P<post_id>\d+)/delete/$', DeletePostView.as_view(), name='delete_post'),
+)
+
+
+# events view
+from misago.threads.views.threads import EventsView
+urlpatterns += patterns('',
+    url(r'^edit-event/(?P<event_id>\d+)/$', EventsView.as_view(), name='edit_event'),
+)
+
+
+# posting views
+from misago.threads.views.threads import PostingView
 urlpatterns += patterns('',
 urlpatterns += patterns('',
     url(r'^start-thread/(?P<forum_id>\d+)/$', PostingView.as_view(), name='start_thread'),
     url(r'^start-thread/(?P<forum_id>\d+)/$', PostingView.as_view(), name='start_thread'),
     url(r'^reply-thread/(?P<forum_id>\d+)/(?P<thread_id>\d+)/$', PostingView.as_view(), name='reply_thread'),
     url(r'^reply-thread/(?P<forum_id>\d+)/(?P<thread_id>\d+)/$', PostingView.as_view(), name='reply_thread'),

+ 3 - 0
misago/threads/views/generic/__init__.py

@@ -1,7 +1,10 @@
 # flake8: noqa
 # flake8: noqa
 from misago.threads.views.generic.base import *
 from misago.threads.views.generic.base import *
+from misago.threads.views.generic.events import *
 from misago.threads.views.generic.goto import *
 from misago.threads.views.generic.goto import *
 from misago.threads.views.generic.gotopostslist import *
 from misago.threads.views.generic.gotopostslist import *
+from misago.threads.views.generic.posting import *
+from misago.threads.views.generic.post import *
 from misago.threads.views.generic.thread import *
 from misago.threads.views.generic.thread import *
 from misago.threads.views.generic.threads import *
 from misago.threads.views.generic.threads import *
 from misago.threads.views.generic.forum import *
 from misago.threads.views.generic.forum import *

+ 7 - 0
misago/threads/views/generic/base.py

@@ -1,3 +1,4 @@
+from django.http import Http404
 from django.shortcuts import render
 from django.shortcuts import render
 from django.views.generic import View
 from django.views.generic import View
 
 
@@ -70,6 +71,9 @@ class ThreadMixin(object):
         return get_object_or_404(queryset, **where)
         return get_object_or_404(queryset, **where)
 
 
     def check_thread_permissions(self, request, thread):
     def check_thread_permissions(self, request, thread):
+        if thread.forum.special_role:
+            raise Http404()
+
         add_acl(request.user, thread.forum)
         add_acl(request.user, thread.forum)
         add_acl(request.user, thread)
         add_acl(request.user, thread)
 
 
@@ -108,6 +112,9 @@ class PostMixin(object):
         return get_object_or_404(queryset, **where)
         return get_object_or_404(queryset, **where)
 
 
     def check_post_permissions(self, request, post):
     def check_post_permissions(self, request, post):
+        if post.forum.special_role:
+            raise Http404()
+
         add_acl(request.user, post.forum)
         add_acl(request.user, post.forum)
         add_acl(request.user, post.thread)
         add_acl(request.user, post.thread)
         add_acl(request.user, post)
         add_acl(request.user, post)

+ 3 - 0
misago/threads/views/events.py → misago/threads/views/generic/events.py

@@ -11,6 +11,9 @@ from misago.threads.models import Event
 from misago.threads.views.generic.base import ViewBase
 from misago.threads.views.generic.base import ViewBase
 
 
 
 
+__all__ = ['EventsView']
+
+
 class EventsView(ViewBase):
 class EventsView(ViewBase):
     def dispatch(self, request, event_id):
     def dispatch(self, request, event_id):
         def toggle_event(request, event):
         def toggle_event(request, event):

+ 7 - 1
misago/threads/views/post.py → misago/threads/views/generic/post.py

@@ -12,7 +12,13 @@ from misago.threads.permissions import exclude_invisible_posts
 from misago.threads.views.generic.base import ViewBase
 from misago.threads.views.generic.base import ViewBase
 
 
 
 
-__all__ = ['QuotePostView']
+__all__ = [
+    'QuotePostView',
+    'ApprovePostView',
+    'UnhidePostView',
+    'HidePostView',
+    'DeletePostView'
+]
 
 
 
 
 class PostView(ViewBase):
 class PostView(ViewBase):

+ 0 - 0
misago/threads/views/posting.py → misago/threads/views/generic/posting.py


+ 111 - 23
misago/threads/views/privatethreads.py

@@ -1,12 +1,88 @@
+from django.http import Http404
+from django.shortcuts import get_object_or_404
 from django.utils.translation import ugettext as _
 from django.utils.translation import ugettext as _
 
 
 from misago.acl import add_acl
 from misago.acl import add_acl
 from misago.forums.models import Forum
 from misago.forums.models import Forum
 
 
+from misago.threads.models import Thread, ThreadParticipant
 from misago.threads.permissions import (allow_use_private_threads,
 from misago.threads.permissions import (allow_use_private_threads,
+                                        allow_see_private_thread,
+                                        allow_see_private_post,
                                         exclude_invisible_private_threads)
                                         exclude_invisible_private_threads)
 from misago.threads.views import generic
 from misago.threads.views import generic
-from misago.threads.views.posting import PostingView as BasePostingView
+
+
+def private_threads_view(klass):
+    """
+    decorator for making views check allow_use_private_threads
+    """
+    def dispatch(self, request, *args, **kwargs):
+        allow_use_private_threads(request.user)
+
+        return super(self.__class__, self).dispatch(
+            request, *args, **kwargs)
+    klass.dispatch = dispatch
+    return klass
+
+
+class PrivateThreadsMixin(object):
+    """
+    Mixin is used to make views use different permission tests
+    """
+    def get_forum(self, request, lock=False, **kwargs):
+        forum = Forum.objects.private_threads()
+        add_acl(request.user, forum)
+        return forum
+
+    def check_forum_permissions(self, request, forum):
+        add_acl(request.user, forum)
+        allow_use_private_threads(request.user)
+
+    def fetch_thread(self, request, lock=False, select_related=None,
+                     queryset=None, **kwargs):
+        queryset = queryset or Thread.objects
+        if lock:
+            queryset = queryset.select_for_update()
+
+        select_related = select_related or []
+        if not 'forum' in select_related:
+            select_related.append('forum')
+        queryset = queryset.select_related(*select_related)
+
+        where = {'id': kwargs.get('thread_id')}
+        thread = get_object_or_404(queryset, **where)
+        if thread.forum.special_role != 'private_threads':
+            raise Http404()
+        return thread
+
+    def fetch_thread_participants(self, thread):
+        thread.participants_list = []
+        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)
+
+    def check_thread_permissions(self, request, thread):
+        add_acl(request.user, thread.forum)
+        add_acl(request.user, thread)
+
+        self.fetch_thread_participants(thread)
+
+        allow_see_private_thread(request.user, thread)
+        allow_use_private_threads(request.user)
+
+    def check_post_permissions(self, request, post):
+        add_acl(request.user, post.forum)
+        add_acl(request.user, post.thread)
+        add_acl(request.user, post)
+
+        self.fetch_thread_participants(post.thread)
+
+        allow_see_private_post(request.user, post)
+        allow_see_private_thread(request.user, post.thread)
+        allow_use_private_threads(request.user)
 
 
 
 
 class PrivateThreads(generic.Threads):
 class PrivateThreads(generic.Threads):
@@ -29,53 +105,65 @@ class PrivateThreadsFiltering(generic.ThreadsFiltering):
         return filters
         return filters
 
 
 
 
-def private_threads_view(klass):
-    def get_forum(self, request, lock=False, **kwargs):
-        forum = Forum.objects.private_threads()
-        add_acl(request.user, forum)
-        return forum
+@private_threads_view
+class PrivateThreadsView(generic.ThreadsView):
+    link_name = 'misago:private_threads'
+    template = 'misago/privatethreads/list.html'
 
 
-    def dispatch(self, request, *args, **kwargs):
-        allow_use_private_threads(request.user)
+    Threads = PrivateThreads
+    Filtering = PrivateThreadsFiltering
 
 
-        return super(self.__class__, self).dispatch(
-            request, *args, **kwargs)
 
 
-    klass.get_forum = get_forum
-    klass.dispatch = dispatch
+@private_threads_view
+class ThreadView(PrivateThreadsMixin, generic.ThreadView):
+    pass
 
 
-    return klass
+
+@private_threads_view
+class GotoLastView(PrivateThreadsMixin, generic.GotoLastView):
+    pass
 
 
 
 
 @private_threads_view
 @private_threads_view
-class ThreadsView(generic.ThreadsView):
-    link_name = 'misago:private_threads'
-    template = 'misago/privatethreads/list.html'
+class GotoNewView(PrivateThreadsMixin, generic.GotoNewView):
+    pass
 
 
-    Threads = PrivateThreads
-    Filtering = PrivateThreadsFiltering
+
+@private_threads_view
+class GotoPostView(PrivateThreadsMixin, generic.GotoPostView):
+    pass
+
+
+@private_threads_view
+class ReportedPostsListView(PrivateThreadsMixin, generic.ReportedPostsListView):
+    pass
+
+
+@private_threads_view
+class QuotePostView(PrivateThreadsMixin, generic.QuotePostView):
+    pass
 
 
 
 
 @private_threads_view
 @private_threads_view
-class ThreadView(generic.ThreadView):
+class UnhidePostView(PrivateThreadsMixin, generic.UnhidePostView):
     pass
     pass
 
 
 
 
 @private_threads_view
 @private_threads_view
-class GotoLastView(generic.GotoLastView):
+class HidePostView(PrivateThreadsMixin, generic.HidePostView):
     pass
     pass
 
 
 
 
 @private_threads_view
 @private_threads_view
-class GotoNewView(generic.GotoNewView):
+class DeletePostView(PrivateThreadsMixin, generic.DeletePostView):
     pass
     pass
 
 
 
 
 @private_threads_view
 @private_threads_view
-class GotoPostView(generic.GotoPostView):
+class EventsView(PrivateThreadsMixin, generic.EventsView):
     pass
     pass
 
 
 
 
 @private_threads_view
 @private_threads_view
-class PostingView(BasePostingView):
+class PostingView(PrivateThreadsMixin, generic.PostingView):
     pass
     pass

+ 31 - 3
misago/threads/views/threads.py

@@ -9,6 +9,18 @@ class ThreadView(generic.ThreadView):
     pass
     pass
 
 
 
 
+class GotoLastView(generic.GotoLastView):
+    pass
+
+
+class GotoNewView(generic.GotoNewView):
+    pass
+
+
+class GotoPostView(generic.GotoPostView):
+    pass
+
+
 class ModeratedPostsListView(generic.ModeratedPostsListView):
 class ModeratedPostsListView(generic.ModeratedPostsListView):
     pass
     pass
 
 
@@ -17,13 +29,29 @@ class ReportedPostsListView(generic.ReportedPostsListView):
     pass
     pass
 
 
 
 
-class GotoLastView(generic.GotoLastView):
+class QuotePostView(generic.QuotePostView):
     pass
     pass
 
 
 
 
-class GotoNewView(generic.GotoNewView):
+class ApprovePostView(generic.ApprovePostView):
     pass
     pass
 
 
 
 
-class GotoPostView(generic.GotoPostView):
+class UnhidePostView(generic.UnhidePostView):
+    pass
+
+
+class HidePostView(generic.HidePostView):
+    pass
+
+
+class DeletePostView(generic.DeletePostView):
+    pass
+
+
+class EventsView(generic.EventsView):
+    pass
+
+
+class PostingView(generic.PostingView):
     pass
     pass