Extension page should be 404 for everyone unless publicly listed #167
@ -5,7 +5,7 @@ from django.urls import reverse
|
||||
|
||||
from common.tests.factories.extensions import create_version, create_approved_version
|
||||
from common.tests.factories.teams import TeamFactory
|
||||
from common.tests.factories.users import UserFactory
|
||||
from common.tests.factories.users import UserFactory, create_moderator
|
||||
from extensions.models import Extension, Version
|
||||
from files.models import File
|
||||
from teams.models import Team, TeamsUsers
|
||||
@ -90,6 +90,54 @@ class PublicViewsTest(_BaseTestCase):
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertTemplateUsed(response, 'extensions/home.html')
|
||||
|
||||
def test_no_one_can_view_extension_page_when_not_listed_404(self):
|
||||
extension = create_version(extension__is_listed=False).extension
|
||||
|
||||
moderator = create_moderator()
|
||||
staff = UserFactory(is_staff=True)
|
||||
superuser = UserFactory(is_superuser=True, is_staff=True)
|
||||
author = extension.authors.first()
|
||||
|
||||
url = extension.get_absolute_url()
|
||||
response = self.client.get(url)
|
||||
|
||||
for account, role in (
|
||||
(None, 'anonymous'),
|
||||
(moderator, 'moderator'),
|
||||
(staff, 'staff'),
|
||||
(superuser, 'superuser'),
|
||||
(author, 'author'),
|
||||
):
|
||||
with self.subTest(account=account, role=role):
|
||||
self.client.logout()
|
||||
if account:
|
||||
self.client.force_login(account)
|
||||
self.assertEqual(response.status_code, 404)
|
||||
|
||||
def test_anyone_can_view_extension_page_when_listed(self):
|
||||
extension = create_approved_version().extension
|
||||
|
||||
moderator = create_moderator()
|
||||
staff = UserFactory(is_staff=True)
|
||||
superuser = UserFactory(is_superuser=True, is_staff=True)
|
||||
author = extension.authors.first()
|
||||
|
||||
url = extension.get_absolute_url()
|
||||
response = self.client.get(url)
|
||||
|
||||
for account, role in (
|
||||
(None, 'anonymous'),
|
||||
(moderator, 'moderator'),
|
||||
(staff, 'staff'),
|
||||
(superuser, 'superuser'),
|
||||
(author, 'author'),
|
||||
):
|
||||
with self.subTest(role=role):
|
||||
self.client.logout()
|
||||
if account:
|
||||
self.client.force_login(account)
|
||||
self.assertEqual(response.status_code, 200)
|
||||
|
||||
|
||||
class ApiViewsTest(_BaseTestCase):
|
||||
def test_blender_version_filter(self):
|
||||
|
@ -28,6 +28,14 @@ urlpatterns = [
|
||||
path('search/', public.SearchView.as_view(), name='search'),
|
||||
path('tag/<slug:tag_slug>/', public.SearchView.as_view(), name='by-tag'),
|
||||
path('team/<slug:team_slug>/', public.SearchView.as_view(), name='by-team'),
|
||||
re_path(
|
||||
rf'^(?P<type_slug>{EXTENSION_SLUGS_PATH})/',
|
||||
include(
|
||||
[
|
||||
path('<slug:slug>/', public.ExtensionDetailView.as_view(), name='detail'),
|
||||
]
|
||||
),
|
||||
),
|
||||
re_path(
|
||||
rf'^(?P<type_slug>{EXTENSION_SLUGS_PATH})/$',
|
||||
public.SearchView.as_view(),
|
||||
@ -84,7 +92,6 @@ urlpatterns = [
|
||||
name='version-download',
|
||||
),
|
||||
path('<slug:slug>/versions/', manage.VersionsView.as_view(), name='versions'),
|
||||
path('<slug:slug>/', manage.ExtensionDetailView.as_view(), name='detail'),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
@ -3,7 +3,7 @@ from django.contrib.auth.mixins import LoginRequiredMixin, UserPassesTestMixin
|
||||
from django.contrib.messages.views import SuccessMessageMixin
|
||||
from django.db import transaction
|
||||
from django.shortcuts import get_object_or_404, redirect, reverse
|
||||
from django.views.generic import DetailView, ListView
|
||||
from django.views.generic import ListView
|
||||
from django.views.generic.edit import CreateView, UpdateView, DeleteView, FormView
|
||||
|
||||
|
||||
@ -22,52 +22,6 @@ from extensions.forms import (
|
||||
from extensions.models import Extension, Version
|
||||
from files.forms import FileForm
|
||||
from files.models import File
|
||||
from stats.models import ExtensionView
|
||||
import ratings.models
|
||||
|
||||
|
||||
class ExtensionDetailView(ExtensionQuerysetMixin, DetailView):
|
||||
model = Extension
|
||||
context_object_name = 'extension'
|
||||
template_name = 'extensions/detail.html'
|
||||
|
||||
def get_queryset(self):
|
||||
"""Allow logged in users to view unlisted add-ons in certain conditions.
|
||||
|
||||
* maintainers should be able to preview their yet unlisted add-ons;
|
||||
* staff should be able to preview yet unlisted add-ons;
|
||||
"""
|
||||
return self.get_extension_queryset().prefetch_related(
|
||||
'authors',
|
||||
'ratings',
|
||||
'ratings__user',
|
||||
'versions',
|
||||
'versions__file',
|
||||
'versions__file__validation',
|
||||
'versions__permissions',
|
||||
'versions__platforms',
|
||||
)
|
||||
|
||||
def get_object(self, queryset=None):
|
||||
"""Record a page view when returning the Extension object."""
|
||||
obj = super().get_object(queryset=queryset)
|
||||
if obj.is_listed and (
|
||||
self.request.user.is_anonymous or not obj.has_maintainer(self.request.user)
|
||||
):
|
||||
ExtensionView.create_from_request(self.request, object_id=obj.pk)
|
||||
return obj
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super().get_context_data(**kwargs)
|
||||
if self.request.user.is_authenticated:
|
||||
context['my_rating'] = ratings.models.Rating.get_for(
|
||||
self.request.user.pk, self.object.pk
|
||||
)
|
||||
extension = context['object']
|
||||
# Add the image for "og:image" meta to the context
|
||||
if extension.featured_image and extension.featured_image.is_listed:
|
||||
context['default_image_path'] = extension.featured_image.thumbnail_1080p_url
|
||||
return context
|
||||
|
||||
|
||||
class VersionsView(ExtensionQuerysetMixin, ListView):
|
||||
|
@ -6,8 +6,7 @@ from django.db import connection
|
||||
from django.db.models import Count, Q
|
||||
from django.shortcuts import get_object_or_404, redirect
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from django.views.generic.list import ListView
|
||||
|
||||
from django.views.generic import DetailView, ListView
|
||||
|
||||
from extensions.models import Extension, Version, Tag
|
||||
from constants.base import (
|
||||
@ -15,6 +14,8 @@ from constants.base import (
|
||||
EXTENSION_TYPE_PLURAL,
|
||||
EXTENSION_TYPE_CHOICES,
|
||||
)
|
||||
from stats.models import ExtensionView
|
||||
import ratings.models
|
||||
|
||||
from stats.models import ExtensionDownload, VersionDownload
|
||||
import teams.models
|
||||
@ -219,3 +220,42 @@ class SearchView(ListedExtensionsView):
|
||||
context['total_count'] = super().get_queryset().filter(type=tag_type_id).count()
|
||||
|
||||
return context
|
||||
|
||||
|
||||
class ExtensionDetailView(DetailView):
|
||||
queryset = Extension.objects.listed.prefetch_related(
|
||||
'authors',
|
||||
'latest_version__file',
|
||||
'latest_version__tags',
|
||||
'preview_set',
|
||||
'preview_set__file',
|
||||
'ratings',
|
||||
'ratings__user',
|
||||
'team',
|
||||
'versions',
|
||||
'versions__file',
|
||||
'versions__file__validation',
|
||||
'versions__permissions',
|
||||
'versions__platforms',
|
||||
).distinct()
|
||||
context_object_name = 'extension'
|
||||
template_name = 'extensions/detail.html'
|
||||
|
||||
def get_object(self, queryset=None):
|
||||
"""Record a page view when returning the Extension object."""
|
||||
obj = super().get_object(queryset=queryset)
|
||||
if self.request.user.is_anonymous or not obj.has_maintainer(self.request.user):
|
||||
ExtensionView.create_from_request(self.request, object_id=obj.pk)
|
||||
return obj
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super().get_context_data(**kwargs)
|
||||
if self.request.user.is_authenticated:
|
||||
context['my_rating'] = ratings.models.Rating.get_for(
|
||||
self.request.user.pk, self.object.pk
|
||||
)
|
||||
extension = context['object']
|
||||
# Add the image for "og:image" meta to the context
|
||||
if extension.featured_image and extension.featured_image.is_listed:
|
||||
context['default_image_path'] = extension.featured_image.thumbnail_1080p_url
|
||||
return context
|
||||
|
Loading…
Reference in New Issue
Block a user