Skip to content

Commit

Permalink
Cyberstorm API: censor deactived package dependencies
Browse files Browse the repository at this point in the history
The reason why a package has been deactivated may be an obnoxious icon
or description text, so don't send those to clients.

Method serializers are used instead of annotations, since especially
for the icon field the annotation isn't straightforward: the ImageField
can't be directly attached to the object, and parsing the absolute URL
correctly from the path representation stored in the database is
error-prone.

Refs TS-2013
  • Loading branch information
anttimaki committed Jan 3, 2024
1 parent ceccff5 commit 6e1b65d
Show file tree
Hide file tree
Showing 2 changed files with 40 additions and 4 deletions.
20 changes: 20 additions & 0 deletions django/thunderstore/api/cyberstorm/tests/test_package_listing.py
Original file line number Diff line number Diff line change
Expand Up @@ -312,5 +312,25 @@ def test_dependency_serializer__reads_is_active_from_correct_field(
assert actual["is_active"] == (package_is_active and version_is_active)


@pytest.mark.django_db
def test_dependency_serializer__when_dependency_is_not_active__censors_icon_and_description() -> None:
# community_identifier is normally added using annotations, but
# it's irrelavant for this test case.
dependency = PackageVersionFactory()
dependency.community_identifier = "greendale"

actual = DependencySerializer(dependency).data

assert actual["description"].startswith("Desc_")
assert actual["icon_url"].startswith("http")

dependency.is_active = False
del dependency.is_effectively_active # Clear cached property
actual = DependencySerializer(dependency).data

assert actual["description"] == "This package has been removed."
assert actual["icon_url"] is None


def _date_to_z(value: datetime) -> str:
return value.strftime("%Y-%m-%dT%H:%M:%S.%fZ")
24 changes: 20 additions & 4 deletions django/thunderstore/api/cyberstorm/views/package_listing.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from typing import Optional

from django.db.models import (
BooleanField,
CharField,
Expand Down Expand Up @@ -27,18 +29,32 @@ class DependencySerializer(serializers.Serializer):
"""
Dependencies of a given PackageVersion, listed in a given Community.
community_identifier and namespace are not present by default and
need to be annotated to the object.
community_identifier is not present by default and needs to be
annotated to the object.
Description and icon is not shown to clients if the dependency is
deactivated, since the fields may contain the very reason for the
deactivation.
"""

community_identifier = serializers.CharField()
description = serializers.CharField()
icon_url = serializers.CharField(source="icon.url")
description = serializers.SerializerMethodField()
icon_url = serializers.SerializerMethodField()
is_active = serializers.BooleanField(source="is_effectively_active")
name = serializers.CharField()
namespace = serializers.CharField(source="package.namespace.name")
version_number = serializers.CharField()

def get_description(self, obj: PackageVersion) -> str:
return (
obj.description
if obj.is_effectively_active
else "This package has been removed."
)

def get_icon_url(self, obj: PackageVersion) -> Optional[str]:
return obj.icon.url if obj.is_effectively_active else None


class TeamSerializer(serializers.Serializer):
"""
Expand Down

0 comments on commit 6e1b65d

Please sign in to comment.