Просмотр исходного кода

moved threadview to viewmodels

Rafał Pitoń 9 лет назад
Родитель
Сommit
d9cea33e41

+ 1 - 1
misago/project_template/project_name/urls.py

@@ -9,7 +9,7 @@ admin.autodiscover()
 admin.site.login_form = AdminAuthenticationForm
 
 
-# Register basic views
+# Register default views
 from misago.core.views import javascript_catalog, momentjs_catalog
 
 urlpatterns = [

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

@@ -13,6 +13,7 @@ from misago.categories.permissions import (
     allow_see_category, allow_browse_category)
 from misago.core.shortcuts import get_int_or_404, get_object_or_404
 from misago.readtracker.categoriestracker import read_category
+from misago.readtracker.threadstracker import make_read_aware
 from misago.users.rest_permissions import IsAuthenticatedOrReadOnly
 
 from misago.threads.api.threadendpoints.list import threads_list_endpoint
@@ -52,7 +53,10 @@ class ThreadViewSet(viewsets.ViewSet):
 
     def retrieve(self, request, pk=None):
         thread = self.get_thread(request.user, pk)
+
+        make_read_aware(request.user, thread)
         make_subscription_aware(request.user, thread)
+
         return Response(ThreadSerializer(thread).data)
 
     def partial_update(self, request, pk=None):

+ 0 - 0
misago/threads/mixins/__init__.py


+ 0 - 2
misago/threads/mixins/threadview.py

@@ -1,2 +0,0 @@
-class ThreadViewMixin(object):
-    pass

+ 0 - 26
misago/threads/mixins/typemixins.py

@@ -1,26 +0,0 @@
-from django.http import Http404
-from django.shortcuts import get_object_or_404
-
-from misago.acl import add_acl
-from misago.categories.models import CATEGORIES_TREE_ID
-
-from misago.threads.permissions.threads import allow_see_thread
-from misago.threads.models import Thread
-
-
-class ThreadMixin(object):
-    def get_thread(self, request, pk):
-        thread = get_object_or_404(Thread.objects.select_related('category', 'starter'), pk=pk)
-        if thread.category.tree_id != CATEGORIES_TREE_ID:
-            raise Http404()
-
-        add_acl(request.user, thread)
-        add_acl(request.user, thread.category)
-
-        allow_see_thread(request.user, thread)
-
-        return thread
-
-
-class PrivateThreadMixin(object):
-    pass

+ 9 - 8
misago/threads/permissions/threads.py

@@ -429,13 +429,14 @@ def allow_see_thread(user, target):
     if not (category_acl.get('can_see') and category_acl.get('can_browse')):
         raise Http404()
 
+    if target.is_hidden and (user.is_anonymous() or not category_acl.get('can_hide_threads')):
+        raise Http404()
+
     if user.is_anonymous() or user.pk != target.starter_id:
         if not category_acl.get('can_see_all_threads'):
             raise Http404()
-        if target.is_unapproved:
-            if not category_acl.get('can_approve_content'):
-                raise Http404()
-        if target.is_hidden and not category_acl.get('can_hide_threads'):
+
+        if target.is_unapproved and not category_acl.get('can_approve_content'):
             raise Http404()
 can_see_thread = return_boolean(allow_see_thread)
 
@@ -519,7 +520,7 @@ def allow_edit_post(user, target):
     if user.is_anonymous():
         raise PermissionDenied(_("You have to sign in to edit posts."))
 
-    category_acl = target.category.acl
+    category_acl = user.acl['categories'].get(target.category_id, {})
 
     if not category_acl['can_edit_posts']:
         raise PermissionDenied(_("You can't edit posts in this category."))
@@ -559,7 +560,7 @@ def allow_unhide_post(user, target):
     if user.is_anonymous():
         raise PermissionDenied(_("You have to sign in to reveal posts."))
 
-    category_acl = target.category.acl
+    category_acl = user.acl['categories'].get(target.category_id, {})
 
     if not category_acl['can_hide_posts']:
         if not category_acl['can_hide_own_posts']:
@@ -601,7 +602,7 @@ def allow_hide_post(user, target):
     if user.is_anonymous():
         raise PermissionDenied(_("You have to sign in to hide posts."))
 
-    category_acl = target.category.acl
+    category_acl = user.acl['categories'].get(target.category_id, {})
 
     if not category_acl['can_hide_posts']:
         if not category_acl['can_hide_own_posts']:
@@ -643,7 +644,7 @@ def allow_delete_post(user, target):
     if user.is_anonymous():
         raise PermissionDenied(_("You have to sign in to delete posts."))
 
-    category_acl = target.category.acl
+    category_acl = user.acl['categories'].get(target.category_id, {})
 
     if category_acl['can_hide_posts'] != 2:
         if not category_acl['can_hide_own_posts'] != 2:

+ 56 - 0
misago/threads/viewmodels/posts.py

@@ -0,0 +1,56 @@
+from django.conf import settings
+
+from misago.acl import add_acl
+from misago.core.shortcuts import paginate, pagination_dict
+from misago.readtracker.threadstracker import make_posts_read_aware
+from misago.users.online.utils import make_users_status_aware
+
+from misago.threads.permissions.threads import exclude_invisible_posts
+
+
+class ViewModel(object):
+    def __init__(self, request, thread, page):
+        posts_queryset = self.get_queryset(request, thread.thread)
+
+        list_page = paginate(posts_queryset, page, settings.MISAGO_POSTS_PER_PAGE, settings.MISAGO_POSTS_TAIL)
+        paginator = pagination_dict(list_page, include_page_range=False)
+
+        posts = list(list_page.object_list)
+        posters = []
+
+        for post in posts:
+            post.category = thread.category
+            post.thread = thread.thread
+
+            if post.poster and post.poster not in posters:
+                posters.append(post.poster)
+
+        add_acl(request.user, posts)
+
+        make_posts_read_aware(request.user, thread.thread, posts)
+        make_users_status_aware(posters, request.user.acl)
+
+        self.posts = posts
+        self.paginator = paginator
+
+    def get_queryset(self, request, thread):
+        queryset = thread.post_set.select_related(
+            'poster',
+            'poster__rank',
+            'poster__ban_cache',
+            'poster__online_tracker'
+        ).order_by('id')
+        return exclude_invisible_posts(request.user, thread.category, queryset)
+
+    def get_frontend_context(self):
+        return {}
+
+    def get_template_context(self):
+        return {
+            'posts': self.posts,
+            'paginator': self.paginator
+        }
+
+
+class ThreadPosts(ViewModel):
+    pass

+ 57 - 0
misago/threads/viewmodels/thread.py

@@ -0,0 +1,57 @@
+from django.shortcuts import get_object_or_404
+
+from misago.acl import add_acl
+from misago.categories.models import Category
+from misago.core.shortcuts import validate_slug
+from misago.readtracker.threadstracker import make_read_aware
+
+from misago.threads.models import Thread
+from misago.threads.permissions.threads import allow_see_thread
+from misago.threads.serializers import ThreadSerializer
+from misago.threads.subscriptions import make_subscription_aware
+
+
+BASE_QUERYSET = Thread.objects.select_related(
+    'category', 'starter', 'starter__rank', 'starter__ban_cache', 'starter__online_tracker')
+
+
+class ViewModel(object):
+    def __init__(self, request, slug, pk):
+        thread = self.get_thread(request, pk, slug)
+
+        add_acl(request.user, thread.category)
+        add_acl(request.user, thread)
+
+        make_read_aware(request.user, thread)
+        make_subscription_aware(request.user, thread)
+
+        self.thread = thread
+        self.category = thread.category
+
+    def get_thread(self, request, pk, slug=None):
+        raise NotImplementedError('Thread view model has to implement get_Thread(request, pk, slug=None)')
+
+    def get_frontend_context(self):
+        return {
+            'THREAD': ThreadSerializer(self.thread).data
+        }
+
+    def get_template_context(self):
+        return {
+            'thread': self.thread,
+            'category': self.category
+        }
+
+
+class ForumThread(ViewModel):
+    def get_thread(self, request, pk, slug=None):
+        thread = get_object_or_404(
+            BASE_QUERYSET,
+            pk=pk,
+            category__tree_id=Category.objects.root_category().tree_id,
+        )
+
+        allow_see_thread(request.user, thread)
+        if slug:
+            validate_slug(thread, slug)
+        return thread

+ 3 - 3
misago/threads/viewmodels/threads.py

@@ -36,7 +36,7 @@ LIST_DENIED_MESSAGES = {
 }
 
 
-class ThreadsViewModel(object):
+class ViewModel(object):
     def __init__(self, request, category, list_type, page):
         self.allow_see_list(request, category, list_type)
 
@@ -114,7 +114,7 @@ class ThreadsViewModel(object):
         }
 
 
-class ForumThreads(ThreadsViewModel):
+class ForumThreads(ViewModel):
     def get_pinned_threads(self, queryset, category, threads_categories):
         if category.level:
             return list(queryset.filter(weight=2)) + list(queryset.filter(
@@ -137,7 +137,7 @@ class ForumThreads(ThreadsViewModel):
             )
 
 
-class PrivateThreads(ThreadsViewModel):
+class PrivateThreads(ViewModel):
     def get_remaining_threads_queryset(self, queryset, category, threads_categories):
         return queryset.filter(category__in=threads_categories)
 

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

@@ -34,11 +34,11 @@ class ListBase(View):
     def get_threads(self, request, category, list_type, page):
         return self.threads(request, category, list_type, page)
 
-    def get_default_context(self):
+    def get_default_frontend_context(self):
         return {}
 
     def get_frontend_context(self, request, category, threads):
-        context = self.get_default_context()
+        context = self.get_default_frontend_context()
 
         context.update(category.get_frontend_context())
         context.update(threads.get_frontend_context())
@@ -60,7 +60,7 @@ class ForumThreads(ListBase):
 
     template_name = 'misago/threadslist/threads.html'
 
-    def get_default_context(self):
+    def get_default_frontend_context(self):
         return {
             'THREADS_API': reverse('misago:api:thread-list'),
             'MERGE_THREADS_API': reverse('misago:api:thread-merge'),

+ 42 - 27
misago/threads/views/thread.py

@@ -1,50 +1,65 @@
-from django.conf import settings
+from django.core.urlresolvers import reverse
 from django.shortcuts import render
 from django.views.generic import View
 
-from misago.acl import add_acl
-from misago.core.shortcuts import paginate, pagination_dict, validate_slug
+from misago.threads.viewmodels.thread import ForumThread
+from misago.threads.viewmodels.posts import ThreadPosts
 
-from misago.threads.mixins.threadview import ThreadViewMixin
-from misago.threads.mixins.typemixins import ThreadMixin, PrivateThreadMixin
-from misago.threads.permissions.threads import exclude_invisible_posts
 
+class ThreadBase(View):
+    thread = None
+    posts = ThreadPosts
 
-class BaseThread(View, ThreadViewMixin):
-    def get(self, request, slug, pk, page=0, **kwargs):
-        thread = self.get_thread(request, pk)
-        validate_slug(thread, slug)
+    template_name = None
 
-        base_posts_queryset = thread.post_set.select_related('poster').order_by('id')
-        posts_queryset = exclude_invisible_posts(request.user, thread.category, base_posts_queryset)
+    def get(self, request, pk, slug, page=0):
+        thread = self.get_thread(request, slug, pk)
+        posts = self.get_posts(request, thread, page)
 
-        list_page = paginate(posts_queryset, page, settings.MISAGO_POSTS_PER_PAGE, settings.MISAGO_POSTS_TAIL)
-        paginator = pagination_dict(list_page, include_page_range=False)
+        frontend_context = self.get_frontend_context(request, thread, posts)
+        request.frontend_context.update(frontend_context)
 
-        posts = list(list_page.object_list)
+        template_context = self.get_template_context(request, thread, posts)
+        return render(request, self.template_name, template_context)
 
-        request.frontend_context.update(self.get_frontend_context(request, thread, posts, paginator))
-        return render(request, self.template_name, self.get_context_data(request, thread, posts, paginator))
+    def get_thread(self, request, pk, slug):
+        return self.thread(request, pk, slug)
 
-    def get_frontend_context(self, request, thread, posts, paginator):
+    def get_posts(self, request, thread, page):
+        return self.posts(request, thread, page)
+
+    def get_default_frontend_context(self):
         return {}
 
-    def get_context_data(self, request, thread=None, posts=None, category=None, paginator=None):
-        return {
-            'category': thread.category,
-            'thread': thread,
-            'posts': posts,
+    def get_frontend_context(self, request, thread, posts):
+        context = self.get_default_frontend_context()
 
-            'count': paginator['count'],
-            'paginator': paginator,
+        context.update(thread.get_frontend_context())
+        context.update(posts.get_frontend_context())
 
+        return context
+
+    def get_template_context(self, request, thread, posts):
+        context = {
             'url_name': ':'.join(request.resolver_match.namespaces + [request.resolver_match.url_name])
         }
 
+        context.update(thread.get_template_context())
+        context.update(posts.get_template_context())
+
+        return context
 
-class Thread(BaseThread, ThreadMixin):
+
+class Thread(ThreadBase):
+    thread = ForumThread
     template_name = 'misago/thread/thread.html'
 
+    def get_default_frontend_context(self):
+        return {
+            'THREADS_API': reverse('misago:api:thread-list'),
+            #'POSTS_API': reverse('misago:api:posts-list'),
+        }
+
 
-class PrivateThread(BaseThread, PrivateThreadMixin):
+class PrivateThread(ThreadBase):
     template_name = 'misago/thread/private_thread.html'

+ 4 - 5
misago/users/models/ban.py

@@ -122,10 +122,8 @@ class Ban(models.Model):
 
 
 class BanCache(models.Model):
-    user = models.OneToOneField(
-        settings.AUTH_USER_MODEL, primary_key=True, related_name='ban_cache')
-    ban = models.ForeignKey(
-        Ban, null=True, blank=True, on_delete=models.SET_NULL)
+    user = models.OneToOneField(settings.AUTH_USER_MODEL, primary_key=True, related_name='ban_cache')
+    ban = models.ForeignKey(Ban, null=True, blank=True, on_delete=models.SET_NULL)
     bans_version = models.PositiveIntegerField(default=0)
     user_message = models.TextField(null=True, blank=True)
     staff_message = models.TextField(null=True, blank=True)
@@ -144,7 +142,8 @@ class BanCache(models.Model):
             check_type=BAN_USERNAME,
             user_message=self.user_message,
             staff_message=self.staff_message,
-            expires_on=self.expires_on)
+            expires_on=self.expires_on
+        )
         return BanMessageSerializer(temp_ban).data
 
     @property

+ 4 - 5
misago/users/models/user.py

@@ -73,10 +73,8 @@ PRIVATE_THREAD_INVITES_LIMITS_CHOICES = (
 
 
 class UserManager(BaseUserManager):
-    def create_user(self, username, email, password=None,
-                    set_default_avatar=False, **extra_fields):
-        from misago.users.validators import (validate_email, validate_password,
-                                             validate_username)
+    def create_user(self, username, email, password=None, set_default_avatar=False, **extra_fields):
+        from misago.users.validators import validate_email, validate_password, validate_username
 
         with transaction.atomic():
             if not email:
@@ -446,7 +444,8 @@ class User(AbstractBaseUser, PermissionsMixin):
 
 
 class Online(models.Model):
-    user = models.OneToOneField(settings.AUTH_USER_MODEL,
+    user = models.OneToOneField(
+        settings.AUTH_USER_MODEL,
         primary_key=True,
         related_name='online_tracker',
     )