Skip to content

Commit

Permalink
Mar 675/public barriers list view (#228)
Browse files Browse the repository at this point in the history
MAR-675 - public barriers list view (#228):
 - add list view for public barriers that can be filtered by overseas region
 - latest note is fetched for each item in public barrier list view
  • Loading branch information
fericsepi authored Nov 6, 2020
1 parent b66be12 commit dfc2dca
Show file tree
Hide file tree
Showing 6 changed files with 107 additions and 2 deletions.
2 changes: 1 addition & 1 deletion api/barriers/filters.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down
24 changes: 24 additions & 0 deletions api/barriers/serializers/public_barriers.py
Original file line number Diff line number Diff line change
Expand Up @@ -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


Expand Down Expand Up @@ -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",
Expand Down Expand Up @@ -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",
Expand Down Expand Up @@ -141,6 +151,7 @@ class Meta:
"latest_published_version",
"unpublished_changes",
"ready_to_be_published",
"latest_note",
)

def get_internal_title_changed(self, obj):
Expand All @@ -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,
Expand Down
20 changes: 20 additions & 0 deletions api/barriers/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down Expand Up @@ -702,6 +703,7 @@ def perform_update(self, serializer):


class PublicBarrierViewSet(TeamMemberModelMixin,
mixins.ListModelMixin,
mixins.RetrieveModelMixin,
mixins.UpdateModelMixin,
GenericViewSet):
Expand All @@ -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)
Expand Down
9 changes: 9 additions & 0 deletions api/metadata/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
2 changes: 1 addition & 1 deletion api/user/permissions.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
52 changes: 52 additions & 0 deletions tests/barriers/test_public_barriers.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down

0 comments on commit dfc2dca

Please sign in to comment.