Browse Source

laying out private threads

Rafał Pitoń 8 years ago
parent
commit
1c9270c832

+ 1 - 1
misago/conf/defaults.py

@@ -325,7 +325,7 @@ CRISPY_TEMPLATE_PACK = 'bootstrap3'
 # Rest Framework Configuration
 # Rest Framework Configuration
 REST_FRAMEWORK = {
 REST_FRAMEWORK = {
     'DEFAULT_PERMISSION_CLASSES': (
     'DEFAULT_PERMISSION_CLASSES': (
-        'misago.users.rest_permissions.IsAuthenticatedOrReadOnly',
+        'misago.core.rest_permissions.IsAuthenticatedOrReadOnly',
     ),
     ),
     'DEFAULT_RENDERER_CLASSES': (
     'DEFAULT_RENDERER_CLASSES': (
         'rest_framework.renderers.JSONRenderer',
         'rest_framework.renderers.JSONRenderer',

+ 12 - 0
misago/core/rest_permissions.py

@@ -0,0 +1,12 @@
+from django.core.exceptions import PermissionDenied
+from django.utils.translation import ugettext as _
+
+from rest_framework.permissions import SAFE_METHODS, BasePermission
+
+
+class IsAuthenticatedOrReadOnly(BasePermission):
+    def has_permission(self, request, view):
+        if request.user.is_anonymous() and request.method not in SAFE_METHODS:
+            raise PermissionDenied(_("This action is not available to guests."))
+        else:
+            return True

+ 10 - 0
misago/threads/api/rest_permissions.py

@@ -0,0 +1,10 @@
+from rest_framework.permissions import BasePermission
+
+from ..permissions.privatethreads import allow_use_private_threads
+
+
+class PrivateThreadsPermission(BasePermission):
+    def has_permission(self, request, view):
+        allow_use_private_threads(request.user)
+
+        return True

+ 14 - 4
misago/threads/api/threadendpoints/list.py

@@ -2,8 +2,9 @@ from rest_framework.response import Response
 
 
 from misago.core.shortcuts import get_int_or_404
 from misago.core.shortcuts import get_int_or_404
 
 
-from ...viewmodels.category import ThreadsCategory, ThreadsRootCategory
-from ...viewmodels.threads import ForumThreads
+from ...viewmodels.category import (
+    ThreadsCategory, ThreadsRootCategory, PrivateThreadsCategory)
+from ...viewmodels.threads import ForumThreads, PrivateThreads
 
 
 
 
 class ListEndpointBase(object):
 class ListEndpointBase(object):
@@ -31,7 +32,7 @@ class ListEndpointBase(object):
         return threads.get_frontend_context()
         return threads.get_frontend_context()
 
 
 
 
-class ForumThreads(ListEndpointBase):
+class ForumThreadsList(ListEndpointBase):
     threads = ForumThreads
     threads = ForumThreads
 
 
     def get_category(self, request, pk=None):
     def get_category(self, request, pk=None):
@@ -40,4 +41,13 @@ class ForumThreads(ListEndpointBase):
         else:
         else:
             return ThreadsRootCategory(request)
             return ThreadsRootCategory(request)
 
 
-threads_list_endpoint = ForumThreads()
+
+class PrivateThreadsList(ListEndpointBase):
+    threads = PrivateThreads
+
+    def get_category(self, request, pk=None):
+        return PrivateThreadsCategory(request)
+
+
+threads_list_endpoint = ForumThreadsList()
+private_threads_list_endpoint = PrivateThreadsList()

+ 6 - 0
misago/threads/api/threadposts.py

@@ -25,6 +25,7 @@ from .postendpoints.patch_event import event_patch_endpoint
 from .postendpoints.patch_post import post_patch_endpoint
 from .postendpoints.patch_post import post_patch_endpoint
 from .postendpoints.read import post_read_endpoint
 from .postendpoints.read import post_read_endpoint
 from .postendpoints.split import posts_split_endpoint
 from .postendpoints.split import posts_split_endpoint
+from .rest_permissions import PrivateThreadsPermission
 
 
 
 
 class ViewSet(viewsets.ViewSet):
 class ViewSet(viewsets.ViewSet):
@@ -280,3 +281,8 @@ class ThreadPostsViewSet(ViewSet):
     thread = ForumThread
     thread = ForumThread
     posts = ThreadPosts
     posts = ThreadPosts
     post_ = ThreadPost
     post_ = ThreadPost
+
+
+class PrivateThreadPostsViewSet(ViewSet):
+    permission_classes = (PrivateThreadsPermission,)
+

+ 16 - 4
misago/threads/api/threads.py

@@ -13,8 +13,9 @@ from ..models import Post, Thread
 from ..moderation import threads as moderation
 from ..moderation import threads as moderation
 from ..viewmodels import ForumThread
 from ..viewmodels import ForumThread
 from .postingendpoint import PostingEndpoint
 from .postingendpoint import PostingEndpoint
+from .rest_permissions import PrivateThreadsPermission
 from .threadendpoints.editor import thread_start_editor
 from .threadendpoints.editor import thread_start_editor
-from .threadendpoints.list import threads_list_endpoint
+from .threadendpoints.list import threads_list_endpoint, private_threads_list_endpoint
 from .threadendpoints.merge import thread_merge_endpoint, threads_merge_endpoint
 from .threadendpoints.merge import thread_merge_endpoint, threads_merge_endpoint
 from .threadendpoints.patch import thread_patch_endpoint
 from .threadendpoints.patch import thread_patch_endpoint
 
 
@@ -40,9 +41,6 @@ class ViewSet(viewsets.ViewSet):
             select_for_update=True
             select_for_update=True
         )
         )
 
 
-    def list(self, request):
-        return threads_list_endpoint(request)
-
     def retrieve(self, request, pk):
     def retrieve(self, request, pk):
         thread = self.get_thread(request, pk)
         thread = self.get_thread(request, pk)
         return Response(thread.get_frontend_context())
         return Response(thread.get_frontend_context())
@@ -66,6 +64,9 @@ class ViewSet(viewsets.ViewSet):
 class ThreadViewSet(ViewSet):
 class ThreadViewSet(ViewSet):
     thread = ForumThread
     thread = ForumThread
 
 
+    def list(self, request):
+        return threads_list_endpoint(request)
+
     @transaction.atomic
     @transaction.atomic
     def create(self, request):
     def create(self, request):
         # Initialize empty instances for new thread
         # Initialize empty instances for new thread
@@ -106,3 +107,14 @@ class ThreadViewSet(ViewSet):
     @list_route(methods=['get'])
     @list_route(methods=['get'])
     def editor(self, request):
     def editor(self, request):
         return thread_start_editor(request)
         return thread_start_editor(request)
+
+
+class PrivateThreadViewSet(ViewSet):
+    permission_classes = (PrivateThreadsPermission,)
+
+    def list(self, request):
+        return private_threads_list_endpoint(request)
+
+    @list_route(methods=['get'])
+    def editor(self, request):
+        return thread_start_editor(request)

+ 6 - 1
misago/threads/context_processors.py

@@ -4,7 +4,12 @@ from django.core.urlresolvers import reverse
 def preload_threads_urls(request):
 def preload_threads_urls(request):
     request.frontend_context.update({
     request.frontend_context.update({
         'ATTACHMENTS_API': reverse('misago:api:attachment-list'),
         'ATTACHMENTS_API': reverse('misago:api:attachment-list'),
-        'THREAD_EDITOR_API': reverse('misago:api:thread-editor')
+
+        'THREAD_EDITOR_API': reverse('misago:api:thread-editor'),
+        'THREADS_API': reverse('misago:api:thread-list'),
+
+        'PRIVATE_THREAD_EDITOR_API': reverse('misago:api:private-thread-editor'),
+        'PRIVATE_THREADS_API': reverse('misago:api:private-thread-list'),
     })
     })
 
 
     return {}
     return {}

+ 4 - 3
misago/threads/permissions/privatethreads.py

@@ -49,7 +49,8 @@ class PermissionsForm(forms.Form):
     )
     )
     can_moderate_private_threads = forms.YesNoSwitch(
     can_moderate_private_threads = forms.YesNoSwitch(
         label=_("Can moderate private threads"),
         label=_("Can moderate private threads"),
-        help_text=_("Allows user to read, reply, edit and delete content in reported private threads.")
+        help_text=_("Allows user to read, reply, edit and delete content "
+                    "in reported private threads.")
     )
     )
 
 
 
 
@@ -140,9 +141,9 @@ ACL tests
 """
 """
 def allow_use_private_threads(user):
 def allow_use_private_threads(user):
     if user.is_anonymous():
     if user.is_anonymous():
-        raise PermissionDenied(_("Unsigned members can't use private threads system."))
+        raise PermissionDenied(_("You have to sign in to use private threads."))
     if not user.acl['can_use_private_threads']:
     if not user.acl['can_use_private_threads']:
-        raise PermissionDenied(_("You can't use private threads system."))
+        raise PermissionDenied(_("You can't use private threads."))
 can_use_private_threads = return_boolean(allow_use_private_threads)
 can_use_private_threads = return_boolean(allow_use_private_threads)
 
 
 
 

+ 8 - 2
misago/threads/urls/api.py

@@ -1,14 +1,20 @@
 from misago.core.apirouter import MisagoApiRouter
 from misago.core.apirouter import MisagoApiRouter
 
 
 from ..api.attachments import AttachmentViewSet
 from ..api.attachments import AttachmentViewSet
-from ..api.threadposts import ThreadPostsViewSet
-from ..api.threads import ThreadViewSet
+from ..api.threadposts import ThreadPostsViewSet, PrivateThreadPostsViewSet
+from ..api.threads import ThreadViewSet, PrivateThreadViewSet
 from ..api.threadpoll import ThreadPollViewSet
 from ..api.threadpoll import ThreadPollViewSet
 
 
 
 
 router = MisagoApiRouter()
 router = MisagoApiRouter()
+
 router.register(r'attachments', AttachmentViewSet, base_name='attachment')
 router.register(r'attachments', AttachmentViewSet, base_name='attachment')
+
 router.register(r'threads', ThreadViewSet, base_name='thread')
 router.register(r'threads', ThreadViewSet, base_name='thread')
 router.register(r'threads/(?P<thread_pk>[^/.]+)/posts', ThreadPostsViewSet, base_name='thread-post')
 router.register(r'threads/(?P<thread_pk>[^/.]+)/posts', ThreadPostsViewSet, base_name='thread-post')
 router.register(r'threads/(?P<thread_pk>[^/.]+)/poll', ThreadPollViewSet, base_name='thread-poll')
 router.register(r'threads/(?P<thread_pk>[^/.]+)/poll', ThreadPollViewSet, base_name='thread-poll')
+
+router.register(r'private-threads', PrivateThreadViewSet, base_name='private-thread')
+router.register(r'private-threads/(?P<thread_pk>[^/.]+)/posts', PrivateThreadViewSet, base_name='private-thread-post')
+
 urlpatterns = router.urls
 urlpatterns = router.urls

+ 2 - 1
misago/threads/viewmodels/category.py

@@ -79,4 +79,5 @@ class ThreadsCategory(ThreadsRootCategory):
 
 
 
 
 class PrivateThreadsCategory(ViewModel):
 class PrivateThreadsCategory(ViewModel):
-    pass
+    def get_categories(self, request):
+        return [Category.objects.private_threads()]

+ 4 - 0
misago/threads/viewmodels/threads.py

@@ -145,7 +145,11 @@ class ForumThreads(ViewModel):
 
 
 
 
 class PrivateThreads(ViewModel):
 class PrivateThreads(ViewModel):
+    def get_pinned_threads(self, queryset, category, threads_categories):
+        return [] # this is noop for Private Threads where its impossible to weight threads
+
     def get_remaining_threads_queryset(self, queryset, category, threads_categories):
     def get_remaining_threads_queryset(self, queryset, category, threads_categories):
+        # todo: return all with reports (if moderator) or ones user is participating in otherwhise
         return queryset.filter(category__in=threads_categories)
         return queryset.filter(category__in=threads_categories)
 
 
 
 

+ 0 - 1
misago/threads/views/list.py

@@ -67,7 +67,6 @@ class ForumThreads(ListBase):
 
 
     def get_default_frontend_context(self):
     def get_default_frontend_context(self):
         return {
         return {
-            'THREADS_API': reverse('misago:api:thread-list'),
             'MERGE_THREADS_API': reverse('misago:api:thread-merge'),
             'MERGE_THREADS_API': reverse('misago:api:thread-merge'),
         }
         }
 
 

+ 1 - 1
misago/users/api/auth.py

@@ -12,10 +12,10 @@ from misago.core.mail import mail_user
 
 
 from ..bans import get_user_ban
 from ..bans import get_user_ban
 from ..forms.auth import AuthenticationForm, ResendActivationForm, ResetPasswordForm
 from ..forms.auth import AuthenticationForm, ResendActivationForm, ResetPasswordForm
-from ..rest_permissions import UnbannedAnonOnly, UnbannedOnly
 from ..serializers import AnonymousUserSerializer, AuthenticatedUserSerializer
 from ..serializers import AnonymousUserSerializer, AuthenticatedUserSerializer
 from ..tokens import is_password_change_token_valid, make_activation_token, make_password_change_token
 from ..tokens import is_password_change_token_valid, make_activation_token, make_password_change_token
 from ..validators import validate_password
 from ..validators import validate_password
+from .rest_permissions import UnbannedAnonOnly, UnbannedOnly
 
 
 
 
 def gateway(request):
 def gateway(request):

+ 3 - 13
misago/users/rest_permissions.py → misago/users/api/rest_permissions.py

@@ -1,30 +1,20 @@
 from django.core.exceptions import PermissionDenied
 from django.core.exceptions import PermissionDenied
 from django.utils.translation import ugettext as _
 from django.utils.translation import ugettext as _
 
 
-from rest_framework.permissions import SAFE_METHODS, AllowAny, BasePermission
+from rest_framework.permissions import BasePermission
 
 
 from misago.core.exceptions import Banned
 from misago.core.exceptions import Banned
 
 
-from .bans import get_request_ip_ban
-from .models import BAN_IP, Ban
+from ..bans import get_request_ip_ban
+from ..models import BAN_IP, Ban
 
 
 
 
 __all__ = [
 __all__ = [
-    'AllowAny',
-    'IsAuthenticatedOrReadOnly',
     'UnbannedOnly',
     'UnbannedOnly',
     'UnbannedAnonOnly'
     'UnbannedAnonOnly'
 ]
 ]
 
 
 
 
-class IsAuthenticatedOrReadOnly(BasePermission):
-    def has_permission(self, request, view):
-        if request.user.is_anonymous() and request.method not in SAFE_METHODS:
-            raise PermissionDenied(_("This action is not available to guests."))
-        else:
-            return True
-
-
 class UnbannedOnly(BasePermission):
 class UnbannedOnly(BasePermission):
     def is_request_banned(self, request):
     def is_request_banned(self, request):
         ban = get_request_ip_ban(request)
         ban = get_request_ip_ban(request)

+ 1 - 1
misago/users/api/usernamechanges.py

@@ -10,8 +10,8 @@ from misago.core.apipaginator import ApiPaginator
 from misago.core.shortcuts import get_int_or_404, get_object_or_404
 from misago.core.shortcuts import get_int_or_404, get_object_or_404
 
 
 from ..models import UsernameChange
 from ..models import UsernameChange
-from ..rest_permissions import BasePermission
 from ..serializers.usernamechange import UsernameChangeSerializer
 from ..serializers.usernamechange import UsernameChangeSerializer
+from .rest_permissions import BasePermission
 
 
 
 
 class UsernameChangesViewSetPermission(BasePermission):
 class UsernameChangesViewSetPermission(BasePermission):

+ 2 - 1
misago/users/api/users.py

@@ -13,6 +13,7 @@ from rest_framework.response import Response
 from misago.acl import add_acl
 from misago.acl import add_acl
 from misago.categories.models import Category
 from misago.categories.models import Category
 from misago.core.cache import cache
 from misago.core.cache import cache
+from misago.core.rest_permissions import IsAuthenticatedOrReadOnly
 from misago.core.shortcuts import get_int_or_404, get_object_or_404
 from misago.core.shortcuts import get_int_or_404, get_object_or_404
 from misago.threads.moderation.posts import hide_post
 from misago.threads.moderation.posts import hide_post
 from misago.threads.moderation.threads import hide_thread
 from misago.threads.moderation.threads import hide_thread
@@ -23,7 +24,6 @@ from ..online.utils import get_user_status
 from ..permissions.delete import allow_delete_user
 from ..permissions.delete import allow_delete_user
 from ..permissions.moderation import allow_moderate_avatar, allow_rename_user
 from ..permissions.moderation import allow_moderate_avatar, allow_rename_user
 from ..permissions.profiles import allow_browse_users_list, allow_follow_user, allow_see_ban_details
 from ..permissions.profiles import allow_browse_users_list, allow_follow_user, allow_see_ban_details
-from ..rest_permissions import BasePermission, IsAuthenticatedOrReadOnly, UnbannedAnonOnly
 from ..serializers import BanDetailsSerializer, UserProfileSerializer, UserSerializer
 from ..serializers import BanDetailsSerializer, UserProfileSerializer, UserSerializer
 from ..viewmodels import UserPosts, UserThreads
 from ..viewmodels import UserPosts, UserThreads
 from .userendpoints.avatar import avatar_endpoint, moderate_avatar_endpoint
 from .userendpoints.avatar import avatar_endpoint, moderate_avatar_endpoint
@@ -33,6 +33,7 @@ from .userendpoints.create import create_endpoint
 from .userendpoints.list import list_endpoint
 from .userendpoints.list import list_endpoint
 from .userendpoints.signature import signature_endpoint
 from .userendpoints.signature import signature_endpoint
 from .userendpoints.username import moderate_username_endpoint, username_endpoint
 from .userendpoints.username import moderate_username_endpoint, username_endpoint
+from .rest_permissions import BasePermission, UnbannedAnonOnly
 
 
 
 
 class UserViewSetPermission(BasePermission):
 class UserViewSetPermission(BasePermission):