Repository: vas3k/vas3k.club

Issue:
Баг: заголовки черновиков видны неавторизованым пользователям, но не обычным пользователям
Например: https://vas3k.club/battle/8067/ в инкогнито прекрасно открывается с заголовком "Батл: Видеоигры - плохо или Видеоигры - хорошо — Вастрик.Клуб" и кодом 200, а вот если залогиниться — 404 Not Found.

Неконсистентно.

Кажется, надо как минимум в [`posts/views/posts.py`](https://github.com/vas3k/vas3k.club/blob/4dfc2b0ab8432d67ae9dc41c3a01fbe47ef410a5/posts/views/posts.py#L24-L33) поменять местами два ифа и сначала выдавать 404, а потом уже светить в публичный интернет заглушку.

Возможно, есть похожие проблемы где-то ещё.


Discussion:

Resolving patch:
diff --git a/posts/views/posts.py b/posts/views/posts.py
--- a/posts/views/posts.py
+++ b/posts/views/posts.py
@@ -22,17 +22,17 @@ def show_post(request, post_type, post_slug):
     if post.type != post_type:
         return redirect("show_post", post.type, post.slug)
 
+    # drafts are visible only to authors and moderators
+    if not post.is_visible:
+        if not request.me or (request.me != post.author and not request.me.is_moderator):
+            raise Http404()
+
     # don't show private posts into public
     if not post.is_public:
         access_denied = check_user_permissions(request, post=post)
         if access_denied:
             return access_denied
 
-    # drafts are visible only to authors and moderators
-    if not post.is_visible:
-        if not request.me or (request.me != post.author and not request.me.is_moderator):
-            raise Http404()
-
     # record a new view
     last_view_at = None
     if request.me:


Test patch:
diff --git a/posts/tests/__init__.py b/posts/tests/__init__.py
new file mode 100644
diff --git a/posts/tests/test_views.py b/posts/tests/test_views.py
new file mode 100644
--- /dev/null
+++ b/posts/tests/test_views.py
@@ -0,0 +1,83 @@
+import itertools
+from datetime import datetime, timedelta
+
+from django.urls import reverse
+from django.test import TestCase
+
+from tests.helpers import HelperClient
+from users.models.user import User
+from posts.models.post import Post
+
+class ModelCreator:
+    _exist_posts = 0
+    _exist_users = 0
+
+    def create_post(self, **kwargs):
+        self._exist_posts += 1
+        return Post.objects.create(
+            type=Post.TYPE_POST,
+            slug='test_{}'.format(self._exist_posts),
+            title='title_{}'.format(self._exist_posts),
+            author=self.create_user(),
+            **kwargs,
+        )
+
+    def create_user(self):
+        self._exist_users += 1
+        return User.objects.create(
+            email="testemail_{}@xx.com".format(self._exist_users),
+            membership_started_at=datetime.now() - timedelta(days=5),
+            membership_expires_at=datetime.now() + timedelta(days=5),
+            moderation_status=User.MODERATION_STATUS_APPROVED,
+            slug="ujlbu4_{}".format(self._exist_users),
+        )
+
+class TestPaymentModel(TestCase):
+    def setUp(self):
+        self.creator = ModelCreator()
+        self.user = self.creator.create_user()
+
+    def test_show_post(self):
+        post = self.creator.create_post(
+            is_visible=True,
+            is_public=True,
+        )
+        for user in [None, self.user]:
+            client = self._authorized_client(user)
+
+            response = client.get(self._post_url(post))
+
+            self.assertContains(response=response, text='', status_code=200)
+
+    def test_show_draft_post(self):
+        '''
+        Is regression test for #545.
+
+        https://github.com/vas3k/vas3k.club/issues/545
+        '''
+        scenarios = itertools.product([None, self.user], [True, False])
+        for user, post_is_public in scenarios:
+            post = self.creator.create_post(
+                is_visible=False,
+                is_public=post_is_public,
+            )
+            client = self._authorized_client(user)
+
+            response = client.get(self._post_url(post))
+
+            self.assertContains(response=response, text='', status_code=404)
+            # Post title should not be shown
+            assert (
+                post.title not in str(response.content)
+            )
+
+    @staticmethod
+    def _post_url(post) -> str:
+        return reverse('show_post', args=(post.type, post.slug))
+
+    @staticmethod
+    def _authorized_client(user):
+        client = HelperClient(user)
+        if user is not None:
+            client.authorise()
+        return client