blender-studio/characters/views/characters.py

152 lines
5.6 KiB
Python

"""Characters and character version views."""
from typing import Optional, List
from django.contrib.redirects.models import Redirect
from django.db import models
from django.db.models.query import QuerySet
from django.http import Http404
from django.views.generic import ListView, DetailView
from django.views.generic.base import RedirectView
from characters.models import Character, CharacterVersion, CharacterShowcase
from characters.queries import (
get_characters,
get_character,
get_character_version,
get_character_showcase,
)
from comments.models import Comment
from comments.queries import get_annotated_comments
from comments.views.common import comments_to_template_type
from stats.models import StaticAssetView
class CharacterList(ListView):
"""Show all characters."""
model = Character
context_object_name = 'characters'
def get_queryset(self) -> QuerySet:
"""Return all characters, it's up to the template to display them depending on the user."""
characters = get_characters().all()
# Assign 'liked' attributes
if self.request.user.is_authenticated:
liked_character_ids = {c.character_id for c in self.request.user.liked_characters.all()}
for character in characters:
character.liked = character.pk in liked_character_ids
return characters
class CharacterDetail(RedirectView):
"""Redirect to latest published character version."""
permanent = False
def get_redirect_url(self, *args, **kwargs):
"""Redirect to latest published character version."""
filter_published = (
{'is_published': True}
if not self.request.user.is_staff and not self.request.user.is_superuser
else {}
)
try:
character = get_character(slug=kwargs['slug'], **filter_published)
latest_version = character.versions.filter(**filter_published).first()
if not latest_version:
raise Http404()
return latest_version.get_absolute_url()
except Character.DoesNotExist:
# Any other old Cloud endpoints are maintained via Redirects
existing_redirect = Redirect.objects.filter(old_path=self.request.path).first()
if existing_redirect:
return existing_redirect.new_path
raise Http404()
class _CharacterViewMixin:
def dispatch(self, *args, **kwargs):
"""Record a StaticAssetView before returning the response."""
response = super().dispatch(*args, **kwargs)
StaticAssetView.create_from_request(self.request, self.object.static_asset_id)
return response
class CharacterVersionDetail(_CharacterViewMixin, DetailView):
"""Display a character version."""
model = CharacterVersion
context_object_name = 'character_version'
def get_object(self, queryset: Optional[models.query.QuerySet] = ...) -> CharacterVersion:
"""Get character version of the given slug and number."""
filter_published = (
{'is_published': True, 'character__is_published': True}
if not self.request.user.is_staff and not self.request.user.is_superuser
else {}
)
try:
character_version = get_character_version(
character__slug=self.kwargs['slug'],
number=self.kwargs['number'],
**filter_published,
)
except CharacterVersion.DoesNotExist:
raise Http404()
# Assign 'liked' attribute
if self.request.user.is_authenticated:
character_version.character.liked = character_version.character.likes.filter(
user_id=self.request.user.pk
).exists()
return character_version
def get_context_data(self, **kwargs):
"""Add comments to the template context."""
context = super().get_context_data(**kwargs)
character_version = self.object
context['character'] = character_version.character
# Display edit buttons for editors/authors
context[
'user_can_edit_character'
] = self.request.user.is_staff and self.request.user.has_perm('character.change_character')
# Comment threads
comments: List[Comment] = get_annotated_comments(character_version, self.request.user.pk)
context['comments'] = comments_to_template_type(
comments, character_version.comment_url, self.request.user
)
return context
class CharacterShowcaseDetail(_CharacterViewMixin, DetailView):
"""Display a character showcase."""
model = CharacterShowcase
context_object_name = 'character_showcase'
def get_object(self, queryset: Optional[models.query.QuerySet] = ...) -> CharacterShowcase:
"""Get character version of the given slug and number."""
try:
showcase = get_character_showcase(slug=self.kwargs['slug'], pk=self.kwargs['pk'])
except CharacterShowcase.DoesNotExist:
raise Http404()
return showcase
def get_context_data(self, **kwargs):
"""Add comments to the template context."""
context = super().get_context_data(**kwargs)
showcase = self.object
# Display edit buttons for editors/authors
context[
'user_can_edit_character'
] = self.request.user.is_staff and self.request.user.has_perm('character.change_character')
# Comment threads
comments: List[Comment] = get_annotated_comments(showcase, self.request.user.pk)
context['comments'] = comments_to_template_type(
comments, showcase.comment_url, self.request.user
)
return context