Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
70 changes: 68 additions & 2 deletions lunes_cms/api/v2/views/word_viewset.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,50 @@

from typing import Any

from django.db.models import QuerySet
from django.db.models import Prefetch, QuerySet
from django.utils.translation import gettext_lazy as _
from drf_spectacular.types import OpenApiTypes
from drf_spectacular.utils import extend_schema, OpenApiParameter
from rest_framework import viewsets
from rest_framework.exceptions import ValidationError
from rest_framework.request import Request
from rest_framework.response import Response

from ....cmsv2.models import Word
from ....cmsv2.models.unit import UnitWordRelation
from ..matomo_tracking import matomo_tracking
from ..serializers import WordSerializer

#: The minimum length a ``search`` term has to have
MIN_SEARCH_LENGTH = 3


@extend_schema(
parameters=[
OpenApiParameter(
name="search",
type=OpenApiTypes.STR,
location=OpenApiParameter.QUERY,
required=False,
description=(
"Case-insensitive substring the returned words have to contain "
"(at least 3 characters, otherwise the request is rejected with "
"HTTP 400). When given, all public images of a word are returned, "
"including the images defined on its released unit relations (not "
"only the word's default image)."
),
)
]
)
class WordViewSet(viewsets.ModelViewSet):
"""
Retrieve the list of all words with their default images, or a single word by id
Retrieve the list of all words with their default images, or a single word by id.

Supports an optional ``search`` query parameter that keeps only the words whose
term contains the given string (case-insensitive). The term has to be at least
three characters long, otherwise the request is rejected with HTTP 400. When
searching, the returned images include the images defined on the word's released
unit relations in addition to the word's default image.
"""

serializer_class = WordSerializer
Expand Down Expand Up @@ -46,4 +77,39 @@ def get_queryset(self) -> QuerySet[Word]:
audio_check_status="CONFIRMED",
image_check_status="CONFIRMED",
)

search = self.request.query_params.get("search")
if search is not None:
search = search.strip()
if len(search) < MIN_SEARCH_LENGTH:
raise ValidationError(
{
"search": _(
"The search term has to be at least %(min)d characters long."
)
% {"min": MIN_SEARCH_LENGTH}
}
)
queryset = queryset.filter(word__icontains=search)
# When searching we expose all public images of a word, so prefetch the
# images of its released unit relations into the attribute that
# ``Word.images_for_api`` reads from.
public_relations = (
UnitWordRelation.objects.filter(
unit__released=True,
unit__jobs__released=True,
word__audio_check_status="CONFIRMED",
image_check_status="CONFIRMED",
)
.exclude(image="")
.order_by("unit__title")
)
queryset = queryset.prefetch_related(
Prefetch(
"unit_word_relations",
public_relations,
to_attr="unit_word_relations_of_job",
)
)

return queryset.distinct().order_by("word")
8 changes: 8 additions & 0 deletions lunes_cms/bildschatz/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
"""
This is the app which serves the public "Bildschatz" image database website.

Bildschatz lets anyone search for a word and browse all publicly available
images that are assigned to the matching words (including the images defined on
the words' unit relations). It is a thin, static frontend on top of the public
``/api/v2/words/`` endpoint.
"""
13 changes: 13 additions & 0 deletions lunes_cms/bildschatz/apps.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
from django.apps import AppConfig
from django.utils.translation import gettext_lazy as _


class BildschatzConfig(AppConfig):
"""
Application settings for the `bildschatz` app,
which serves the public Bildschatz image database website.
Inherits from `AppConfig`.
"""

name = "lunes_cms.bildschatz"
verbose_name = _("Bildschatz")
Loading