Skip to content
Open
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
13 changes: 13 additions & 0 deletions cl/api/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,7 @@
OpinionViewSet,
OriginatingCourtInformationViewSet,
RECAPDocumentViewSet,
ScotusDocketMetadataViewSet,
TagViewSet,
)
from cl.search.factories import (
Expand Down Expand Up @@ -2879,6 +2880,18 @@ async def test_recapdocument_endpoint(self):
viewset=RECAPDocumentViewSet,
)

async def test_scotus_docket_metadata_endpoint(self) -> None:
"""Test the V4 SCOTUS docket metadata endpoint confirming that its
cursor pagination works properly."""

await self._base_test_for_v4_endpoints(
endpoint="scotusdocketmetadata-list",
default_ordering="-id",
secondary_cursor_key="date_created",
non_cursor_key=None,
viewset=ScotusDocketMetadataViewSet,
)

async def test_audio_endpoint(self):
"""Test the V4 Audio endpoint confirming that their cursor and page
number pagination works properly."""
Expand Down
7 changes: 7 additions & 0 deletions cl/api/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,13 @@
router_v4.register(prefix, viewset, basename)
router_v4.register(r"api-usage", views.ApiUsageViewSet, basename="api-usage")

# SCOTUS content (v4 only)
router_v4.register(
r"scotus-docket-metadata",
search_views.ScotusDocketMetadataViewSet,
basename="scotusdocketmetadata",
)

# When we finally need to deprecate V3 of the API, the process to remove it, is:
# - Remove the re_path(r"^api/rest/(?P<version>[v3]+)/", include(router.urls)) below
# - The only ViewSet that requires removal is SearchViewSet and its related
Expand Down
17 changes: 17 additions & 0 deletions cl/search/api_serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@
OpinionsCited,
OriginatingCourtInformation,
RECAPDocument,
ScotusDocketMetadata,
Tag,
)
from cl.search.types import ESDictDocument
Expand Down Expand Up @@ -205,6 +206,22 @@ class FullDocketSerializer(DocketSerializer):
docket_entries = DocketEntrySerializer(many=True, read_only=True)


class ScotusDocketMetadataSerializer(
RetrieveFilteredFieldsMixin,
NestedDynamicFieldsMixin,
HyperlinkedModelSerializerWithId,
):
"""SCOTUS-specific metadata of a docket."""

questions_presented_file = serializers.FileField(
use_url=True, read_only=True
)

class Meta:
model = ScotusDocketMetadata
fields = "__all__"


class CourtSerializer(
RetrieveFilteredFieldsMixin,
DynamicFieldsMixin,
Expand Down
25 changes: 25 additions & 0 deletions cl/search/api_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
RECAPDocumentESResultSerializer,
RECAPDocumentSerializer,
RECAPESResultSerializer,
ScotusDocketMetadataSerializer,
TagSerializer,
V3OAESResultSerializer,
V3OpinionESResultSerializer,
Expand All @@ -62,6 +63,7 @@
OpinionFilter,
OpinionsCitedFilter,
RECAPDocumentFilter,
ScotusDocketMetadataFilter,
)
from cl.search.forms import SearchForm
from cl.search.models import (
Expand All @@ -76,6 +78,7 @@
OpinionsCited,
OriginatingCourtInformation,
RECAPDocument,
ScotusDocketMetadata,
Tag,
)

Expand Down Expand Up @@ -241,6 +244,28 @@ class RECAPDocumentViewSet(
)


class BaseSourceReadOnlyViewSet(
LoggingMixin,
NoFilterCacheListMixin,
DeferredFieldsMixin,
viewsets.ReadOnlyModelViewSet,
):
"""Base read-only viewset for models of a single docket source."""

permission_classes = (DjangoModelPermissions,)
ordering = "-id"
ordering_fields: tuple[str, ...] = ("id", "date_created", "date_modified")
cursor_ordering_fields = ["id", "date_created", "date_modified"]


class ScotusDocketMetadataViewSet(BaseSourceReadOnlyViewSet):
"""SCOTUS-specific docket metadata."""

serializer_class = ScotusDocketMetadataSerializer
filterset_class = ScotusDocketMetadataFilter
queryset = ScotusDocketMetadata.objects.order_by("-id")


class CourtViewSet(LoggingMixin, DeferredFieldsMixin, viewsets.ModelViewSet):
serializer_class = CourtSerializer
filterset_class = CourtFilter
Expand Down
31 changes: 31 additions & 0 deletions cl/search/filters.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
OpinionCluster,
OpinionsCited,
RECAPDocument,
ScotusDocketMetadata,
Tag,
)

Expand Down Expand Up @@ -233,3 +234,33 @@ class Meta:
"ocr_status": INTEGER_LOOKUPS,
"is_free_on_pacer": ["exact"],
}


class BaseSourceFilter(NoEmptyFilterSet):
"""Base filterset for models of a single docket source.

django-filter doesn't merge Meta.fields through inheritance, so
subclasses must spread their parent's fields into their own:
fields = {**BaseSourceFilter.Meta.fields, ...}
"""

class Meta:
fields: dict[str, list[str]] = {
"id": INTEGER_LOOKUPS,
"date_created": DATETIME_LOOKUPS,
"date_modified": DATETIME_LOOKUPS,
}


class ScotusDocketMetadataFilter(BaseSourceFilter):
"""Filters for SCOTUS docket metadata."""

docket = filters.RelatedFilter(DocketFilter, queryset=Docket.objects.all())

class Meta(BaseSourceFilter.Meta):
model = ScotusDocketMetadata
fields = {
**BaseSourceFilter.Meta.fields,
"capital_case": ["exact"],
"date_discretionary_court_decision": DATE_LOOKUPS,
}
Loading
Loading