Skip to content

Commit

Permalink
API: Récupérer les WasteActions avec leur ResourceActions (si l'utili…
Browse files Browse the repository at this point in the history
…sateur est authentifié, filtré sur ses cantines) (#4544)
  • Loading branch information
raphodn authored Oct 23, 2024
1 parent 54217c9 commit 91ba5cb
Show file tree
Hide file tree
Showing 8 changed files with 128 additions and 17 deletions.
4 changes: 2 additions & 2 deletions api/serializers/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,5 +51,5 @@
from .communityevent import CommunityEventSerializer # noqa: F401
from .partner import PartnerSerializer, PartnerShortSerializer, PartnerContactSerializer # noqa: F401
from .videotutorial import VideoTutorialSerializer # noqa: F401
from .wasteaction import WasteActionSerializer # noqa: F401
from .resourceaction import ResourceActionSerializer # noqa: F401
from .wasteaction import WasteActionSerializer, WasteActionWithActionsSerializer # noqa: F401
from .resourceaction import ResourceActionSerializer, ResourceActionFullSerializer # noqa: F401
23 changes: 23 additions & 0 deletions api/serializers/resourceaction.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,34 @@


class ResourceActionSerializer(serializers.ModelSerializer):
resource_id = serializers.IntegerField(read_only=True)
canteen_id = serializers.IntegerField(required=True)

class Meta:
model = ResourceAction
fields = (
"resource_id",
"canteen_id",
"is_done",
)


class ResourceActionFullSerializer(ResourceActionSerializer):
resource = serializers.SerializerMethodField(read_only=True)
canteen = serializers.SerializerMethodField(read_only=True)

class Meta(ResourceActionSerializer.Meta):
fields = ResourceActionSerializer.Meta.fields + (
"resource",
"canteen",
)

def get_resource(self, obj):
from .wasteaction import WasteActionSerializer

return WasteActionSerializer(obj.resource).data

def get_canteen(self, obj):
from .canteen import MinimalCanteenSerializer

return MinimalCanteenSerializer(obj.canteen).data
19 changes: 18 additions & 1 deletion api/serializers/wasteaction.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
from rest_framework import serializers
from rest_framework.fields import Field

from data.models import WasteAction
from api.serializers.resourceaction import ResourceActionFullSerializer
from data.models import ResourceAction, WasteAction


class WagtailImageSerializedField(Field):
Expand Down Expand Up @@ -32,3 +33,19 @@ class Meta:
"waste_origins",
"lead_image",
)


class WasteActionWithActionsSerializer(WasteActionSerializer):
actions = serializers.SerializerMethodField()

class Meta(WasteActionSerializer.Meta):
fields = WasteActionSerializer.Meta.fields + ("actions",)

def get_actions(self, obj):
"""Only return actions for authenticated users + related to their canteens."""
actions = ResourceAction.objects.none()
user = self.context["request"].user
if user.is_authenticated:
actions = ResourceAction.objects.filter(resource=obj).for_user_canteens(user)
serializer = ResourceActionFullSerializer(instance=actions, many=True)
return serializer.data
7 changes: 5 additions & 2 deletions api/tests/test_resource_actions.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,13 @@ def test_create_resource_action(self):
self.client.force_login(user=self.user_with_canteen)
response = self.client.post(self.url, data={"canteen_id": self.canteen.id, "is_done": True})
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
self.assertEqual(response.data["resource_id"], self.waste_action.id)
self.assertEqual(response.data["canteen_id"], self.canteen.id)
self.assertTrue(response.data["is_done"])
self.assertEqual(ResourceAction.objects.count(), 1)
self.assertEqual(ResourceAction.objects.first().resource, self.waste_action)
self.assertEqual(ResourceAction.objects.first().canteen, self.canteen)
self.assertEqual(ResourceAction.objects.first().is_done, True)
self.assertTrue(ResourceAction.objects.first().is_done)

def test_update_resource_action(self):
# create an existing ResourceAction
Expand All @@ -55,4 +58,4 @@ def test_update_resource_action(self):
self.assertEqual(ResourceAction.objects.count(), 1)
self.assertEqual(ResourceAction.objects.first().resource, self.waste_action)
self.assertEqual(ResourceAction.objects.first().canteen, self.canteen)
self.assertEqual(ResourceAction.objects.first().is_done, False)
self.assertFalse(ResourceAction.objects.first().is_done)
54 changes: 46 additions & 8 deletions api/tests/test_waste_actions.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
from django.urls import reverse
from rest_framework.test import APITestCase

from data.factories import WasteActionFactory
from data.factories import (
CanteenFactory,
ResourceActionFactory,
UserFactory,
WasteActionFactory,
)
from data.models import WasteAction


class TestWasteActionsApi(APITestCase):
class TestWasteActionsListApi(APITestCase):
@classmethod
def setUpTestData(cls):
cls.waste_action = WasteActionFactory.create()
Expand All @@ -15,13 +20,8 @@ def test_get_waste_actions_list(self):
self.assertEqual(response.status_code, 200)
self.assertEqual(len(response.data["results"]), 1)

def test_get_waste_action_detail(self):
response = self.client.get(reverse("waste_action_detail", kwargs={"pk": self.waste_action.id}))
self.assertEqual(response.status_code, 200)
self.assertEqual(response.data["id"], self.waste_action.id)


class TestWasteActionsFiltersApi(APITestCase):
class TestWasteActionsListFiltersApi(APITestCase):
def test_effort_filter(self):
WasteActionFactory.create(effort=WasteAction.Effort.LARGE)
WasteActionFactory.create(effort=WasteAction.Effort.MEDIUM)
Expand Down Expand Up @@ -55,3 +55,41 @@ def test_text_search(self):
response = self.client.get(f"{reverse('waste_actions_list')}?search=evaluation")
results = response.data["results"]
self.assertEqual(len(results), 2)


class TestWasteActionsDetailApi(APITestCase):
@classmethod
def setUpTestData(cls):
cls.waste_action = WasteActionFactory.create()
cls.user = UserFactory()
cls.user_with_canteen = UserFactory()
CanteenFactory()
cls.canteen = CanteenFactory(managers=[cls.user_with_canteen])
cls.resource_action = ResourceActionFactory.create(
resource=cls.waste_action, canteen=cls.canteen, is_done=True
)

def test_get_waste_action_detail(self):
# anonymous
response = self.client.get(reverse("waste_action_detail", kwargs={"pk": self.waste_action.id}))
self.assertEqual(response.status_code, 200)
self.assertEqual(response.data["id"], self.waste_action.id)
self.assertTrue("actions" not in response.data)
# logged in user (without canteen)
self.client.force_login(user=self.user)
response = self.client.get(reverse("waste_action_detail", kwargs={"pk": self.waste_action.id}))
self.assertEqual(response.status_code, 200)
self.assertEqual(response.data["id"], self.waste_action.id)
self.assertTrue("actions" in response.data)
self.assertEqual(len(response.data["actions"]), 0)
# logged in user with canteen & resource action
self.client.force_login(user=self.user_with_canteen)
response = self.client.get(reverse("waste_action_detail", kwargs={"pk": self.waste_action.id}))
self.assertEqual(response.status_code, 200)
self.assertEqual(response.data["id"], self.waste_action.id)
self.assertTrue("actions" in response.data)
self.assertEqual(len(response.data["actions"]), 1)
self.assertEqual(response.data["actions"][0]["canteen_id"], self.canteen.id)
self.assertEqual(response.data["actions"][0]["canteen"]["id"], self.canteen.id)
self.assertEqual(response.data["actions"][0]["canteen"]["name"], self.canteen.name)
self.assertTrue(response.data["actions"][0]["is_done"])
8 changes: 7 additions & 1 deletion api/views/wasteaction.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
from rest_framework.generics import ListAPIView, RetrieveAPIView
from rest_framework.pagination import LimitOffsetPagination

from api.serializers import WasteActionSerializer
from api.serializers import WasteActionSerializer, WasteActionWithActionsSerializer
from data.models import WasteAction

from .utils import UnaccentSearchFilter
Expand Down Expand Up @@ -39,3 +39,9 @@ class WasteActionView(RetrieveAPIView):
model = WasteAction
queryset = WasteAction.objects.all()
serializer_class = WasteActionSerializer

def get_serializer(self, *args, **kwargs):
kwargs.setdefault("context", self.get_serializer_context())
if self.request.user.is_authenticated:
return WasteActionWithActionsSerializer(*args, **kwargs)
return super().get_serializer(*args, **kwargs)
7 changes: 7 additions & 0 deletions data/models/resourceaction.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,19 @@
from .wasteaction import WasteAction


class ResourceActionQuerySet(models.QuerySet):
def for_user_canteens(self, user):
return self.filter(canteen__in=user.canteens.all())


class ResourceAction(models.Model):
class Meta:
unique_together = ("resource", "canteen")
verbose_name = "ressource : action (cantine)"
verbose_name_plural = "ressources : actions (cantines)"

objects = models.Manager.from_queryset(ResourceActionQuerySet)()

creation_date = models.DateTimeField(auto_now_add=True)
modification_date = models.DateTimeField(auto_now=True)
history = HistoricalRecords()
Expand Down
23 changes: 20 additions & 3 deletions data/tests/test_resource_action.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,32 @@
UserFactory,
WasteActionFactory,
)
from data.models import ResourceAction


class ResourceActionModelSaveTest(TestCase):
class ResourceActionQuerySetTest(TestCase):
@classmethod
def setUpTestData(cls):
cls.waste_action = WasteActionFactory()
cls.user = UserFactory()
cls.user_with_canteen = UserFactory()
cls.canteen = CanteenFactory()
cls.canteen.managers.add(cls.user)
cls.canteen_with_manager = CanteenFactory(managers=[cls.user_with_canteen])
cls.waste_action = WasteActionFactory()
ResourceActionFactory(resource=cls.waste_action, canteen=cls.canteen, is_done=True)
ResourceActionFactory(resource=cls.waste_action, canteen=cls.canteen_with_manager, is_done=True)

def test_for_user_canteens(self):
self.assertEqual(ResourceAction.objects.count(), 2)
self.assertEqual(ResourceAction.objects.for_user_canteens(self.user).count(), 0)
self.assertEqual(ResourceAction.objects.for_user_canteens(self.user_with_canteen).count(), 1)


class ResourceActionModelSaveTest(TestCase):
@classmethod
def setUpTestData(cls):
cls.user = UserFactory()
cls.canteen = CanteenFactory(managers=[cls.user])
cls.waste_action = WasteActionFactory()

def test_resource_action_validation(self):
# NOT OK: missing required field
Expand Down

0 comments on commit 91ba5cb

Please sign in to comment.