diff --git a/api/barriers/filters.py b/api/barriers/filters.py index 94d087bf9..169faf405 100644 --- a/api/barriers/filters.py +++ b/api/barriers/filters.py @@ -142,7 +142,7 @@ def clean_location_value(self, value): def location_filter(self, queryset, name, value): """ - custom filter for retreiving barriers of all countries of an overseas region + custom filter for retrieving barriers of all countries of an overseas region """ location = self.clean_location_value(value) diff --git a/api/barriers/serializers/public_barriers.py b/api/barriers/serializers/public_barriers.py index 5953be446..41103063e 100644 --- a/api/barriers/serializers/public_barriers.py +++ b/api/barriers/serializers/public_barriers.py @@ -13,6 +13,8 @@ from api.barriers.models import PublicBarrier from api.barriers.serializers.mixins import LocationFieldMixin from api.core.serializers.mixins import AllowNoneAtToRepresentationMixin +from api.interactions.models import PublicBarrierNote +from api.interactions.serializers import PublicBarrierNoteSerializer from api.metadata.fields import TradingBlocField @@ -51,11 +53,16 @@ class PublicBarrierSerializer(AllowNoneAtToRepresentationMixin, latest_published_version = serializers.SerializerMethodField() unpublished_changes = serializers.SerializerMethodField() ready_to_be_published = serializers.SerializerMethodField() + internal_code = serializers.SerializerMethodField() + internal_id = serializers.SerializerMethodField() + latest_note = serializers.SerializerMethodField() class Meta: model = PublicBarrier fields = ( "id", + "internal_code", + "internal_id", "title", "title_updated_on", "internal_title_changed", @@ -98,9 +105,12 @@ class Meta: "latest_published_version", "unpublished_changes", "ready_to_be_published", + "latest_note", ) read_only_fields = ( "id", + "internal_code", + "internal_id", "title_updated_on", "internal_title_changed", "internal_title_at_update", @@ -141,6 +151,7 @@ class Meta: "latest_published_version", "unpublished_changes", "ready_to_be_published", + "latest_note", ) def get_internal_title_changed(self, obj): @@ -158,6 +169,19 @@ def get_unpublished_changes(self, obj): def get_ready_to_be_published(self, obj): return obj.ready_to_be_published + def get_internal_code(self, obj): + return obj.barrier.code + + def get_internal_id(self, obj): + return obj.barrier_id + + def get_latest_note(self, obj): + try: + note = obj.notes.latest("created_on") + return PublicBarrierNoteSerializer(note).data + except PublicBarrierNote.DoesNotExist: + return None + class PublishedVersionSerializer(LocationFieldMixin, AllowNoneAtToRepresentationMixin, diff --git a/api/barriers/views.py b/api/barriers/views.py index c093fc636..bb20772ac 100644 --- a/api/barriers/views.py +++ b/api/barriers/views.py @@ -45,6 +45,7 @@ from api.user_event_log.utils import record_user_event from .filters import BarrierFilterSet from .public_data import public_release_to_s3 +from ..metadata.utils import get_country_ids_by_overseas_region class Echo: @@ -702,6 +703,7 @@ def perform_update(self, serializer): class PublicBarrierViewSet(TeamMemberModelMixin, + mixins.ListModelMixin, mixins.RetrieveModelMixin, mixins.UpdateModelMixin, GenericViewSet): @@ -713,6 +715,24 @@ class PublicBarrierViewSet(TeamMemberModelMixin, permission_classes = (AllRetrieveAndEditorUpdateOnly,) serializer_class = PublicBarrierSerializer + def get_queryset(self): + status_filters = ( + PublicBarrierStatus.ELIGIBLE, + PublicBarrierStatus.READY, + PublicBarrierStatus.PUBLISHED + ) + qs = PublicBarrier.objects \ + .filter(_public_view_status__in=status_filters) \ + .prefetch_related("notes") + + # Region filter + region_id = self.request.query_params.get('region', None) + if region_id is not None: + countries = get_country_ids_by_overseas_region(region_id) + qs = qs.filter(barrier__country__in=countries) + + return qs + def get_object(self): barrier = get_object_or_404(self.barriers_qs, pk=self.kwargs.get("pk")) public_barrier, _created = get_or_create_public_barrier(barrier) diff --git a/api/metadata/utils.py b/api/metadata/utils.py index c5c657168..919f13287 100644 --- a/api/metadata/utils.py +++ b/api/metadata/utils.py @@ -77,6 +77,15 @@ def get_countries(): return dh_countries +def get_country_ids_by_overseas_region(region_id): + countries = get_countries() + return [ + country["id"] for country in countries + if country.get("overseas_region") + and region_id == country.get("overseas_region").get("id") + ] + + def get_admin_area(admin_area_id): admin_area_lookup = cache.get("dh_admin_area_lookup") if not admin_area_lookup: diff --git a/api/user/permissions.py b/api/user/permissions.py index 6f67b0445..b6cedc8a9 100644 --- a/api/user/permissions.py +++ b/api/user/permissions.py @@ -37,7 +37,7 @@ class AllRetrieveAndEditorUpdateOnly(BasePermission): Allow GET to all authenticated users Allow PATCH to authenticated editors, publishers and admins """ - allowed_actions = ('retrieve',) + allowed_actions = ('list', 'retrieve',) required_groups = ( UserRoles.EDITOR, UserRoles.PUBLISHER, diff --git a/tests/barriers/test_public_barriers.py b/tests/barriers/test_public_barriers.py index 6db493fae..b94248b49 100644 --- a/tests/barriers/test_public_barriers.py +++ b/tests/barriers/test_public_barriers.py @@ -23,6 +23,7 @@ from api.core.exceptions import ArchivingException from api.core.test_utils import APITestMixin from api.core.utils import read_file_from_s3, list_s3_public_data_files +from api.interactions.models import PublicBarrierNote from api.metadata.constants import PublicBarrierStatus, BarrierStatus from moto import mock_s3 @@ -63,6 +64,57 @@ def setUp(self): self.barrier = BarrierFactory() self.url = reverse("public-barriers-detail", kwargs={"pk": self.barrier.id}) + def test_pb_list(self): + url = reverse("public-barriers-list") + pb1, _ = self.publish_barrier() + pb2, _ = self.publish_barrier() + + r = self.api_client.get(url) + + assert 200 == r.status_code + assert 2 == r.data["count"] + assert {pb1.id, pb2.id} == {i["id"] for i in r.data["results"]} + + def test_pb_list_region_filter(self): + country_id = "955f66a0-5d95-e211-a939-e4115bead28a" # Algeria + region_id = "8d4c4f31-06ce-4320-8e2f-1c13559e125f" # Africa + url = f'{reverse("public-barriers-list")}?region={region_id}' + + barrier1 = BarrierFactory(country=country_id) + pb1 = self.get_public_barrier(barrier1) + pb1, _ = self.publish_barrier(pb1) + + pb2, _ = self.publish_barrier() + + r = self.api_client.get(url) + + assert 200 == r.status_code + assert 1 == r.data["count"] + assert {pb1.id} == {i["id"] for i in r.data["results"]} + + def test_pb_list_returns_latest_note_for_items(self): + url = reverse("public-barriers-list") + pb1, _ = self.publish_barrier() + + with freeze_time("2020-02-02"): + _note1 = PublicBarrierNote.objects.create(public_barrier=pb1, text="wibble") + with freeze_time("2020-02-03"): + note2 = PublicBarrierNote.objects.create(public_barrier=pb1, text="wobble") + + r = self.api_client.get(url) + + assert 200 == r.status_code + assert note2.text == r.data["results"][0]["latest_note"].get("text") + + def test_pb_list_returns_none_for_latest_note(self): + url = reverse("public-barriers-list") + pb1, _ = self.publish_barrier() + + r = self.api_client.get(url) + + assert 200 == r.status_code + assert not r.data["results"][0]["latest_note"] + def test_public_barrier_gets_created_at_fetch(self): """ If a barrier doesn't have a corresponding public barrier it gets created when