From 82d361e775c982a60c2c4f0e1baa396a89452c56 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aur=C3=A9lien=20Delobelle?= Date: Mon, 4 Sep 2017 16:24:34 +0200 Subject: [PATCH] API supports Activity - Add ActivitySerializer + tests. - Add 'places' field to ActivityTemplateSerializer. --- api/event/serializers.py | 43 ++++++--- api/event/tests.py | 199 ++++++++++++++++++++++++++++++++++++++- api/urls.py | 1 + event/models.py | 2 +- 4 files changed, 226 insertions(+), 19 deletions(-) diff --git a/api/event/serializers.py b/api/event/serializers.py index a7ff849..5a29144 100644 --- a/api/event/serializers.py +++ b/api/event/serializers.py @@ -1,9 +1,6 @@ -from django.db import transaction -from django.utils.decorators import method_decorator - from rest_framework import serializers -from event.models import Event, ActivityTag, Place, ActivityTemplate +from event.models import Activity, ActivityTag, ActivityTemplate, Event, Place from .fields import EventHyperlinkedIdentityField @@ -40,19 +37,11 @@ class ActivityTagSerializer(serializers.ModelSerializer): fields = ('url', 'id', 'name', 'is_public', 'color', 'event') -# TODO rajouter des permissions -class ActivityTemplateSerializer(serializers.ModelSerializer): +class BaseActivitySerializer(serializers.ModelSerializer): tags = ActivityTagSerializer(many=True) serializer_url_field = EventHyperlinkedIdentityField - class Meta: - model = ActivityTemplate - fields = ( - 'url', 'id', 'title', 'event', 'is_public', 'has_perm', 'min_perm', - 'max_perm', 'description', 'remarks', 'tags', - ) - def process_tags(self, instance, tags_data): # TODO: en fonction de si backbone envoie un `id` ou non lorsque le tag # n'existe pas encore il faudra faire un premier passage sur `tags` i @@ -88,5 +77,29 @@ class ActivityTemplateSerializer(serializers.ModelSerializer): return activity_template -class ActivitySerializer(serializers.ModelSerializer): - pass +# TODO rajouter des permissions +class ActivityTemplateSerializer( + BaseActivitySerializer, + serializers.ModelSerializer, + ): + + class Meta: + model = ActivityTemplate + fields = ( + 'url', 'id', 'title', 'event', 'is_public', 'has_perm', 'min_perm', + 'max_perm', 'description', 'remarks', 'tags', 'places', + ) + + +class ActivitySerializer( + BaseActivitySerializer, + serializers.ModelSerializer, + ): + + class Meta: + model = Activity + fields = ( + 'url', 'id', 'title', 'event', 'is_public', 'has_perm', 'min_perm', + 'max_perm', 'description', 'remarks', 'tags', 'places', + 'parent', 'staff', 'beginning', 'end', + ) diff --git a/api/event/tests.py b/api/event/tests.py index ed748e1..c730f5a 100644 --- a/api/event/tests.py +++ b/api/event/tests.py @@ -5,7 +5,7 @@ from django.utils import timezone from rest_framework.test import APITestCase -from event.models import Event, Place, ActivityTag, ActivityTemplate +from event.models import Activity, ActivityTag, ActivityTemplate, Event, Place from api.test.testcases import ModelAPITestCaseMixin from api.test.utils import json_format @@ -134,6 +134,11 @@ class ActivityTemplateAPITests(ModelAPITestCaseMixin, APITestCase): 'color': "#222", }) + self.place = Place.objects.create( + name='The Place to Be', + description='Super great', + ) + def get_url_model(self, *args, **kwargs): kwargs['event_pk'] = 1 return super().get_url_model(*args, **kwargs) @@ -180,6 +185,7 @@ class ActivityTemplateAPITests(ModelAPITestCaseMixin, APITestCase): 'min_perm': instance.min_perm, 'max_perm': instance.max_perm, 'description': instance.description, + 'places': [place.pk for place in instance.places.all()], }) @property @@ -196,7 +202,8 @@ class ActivityTemplateAPITests(ModelAPITestCaseMixin, APITestCase): 'is_public': False, 'remarks': "test remark", 'event': self.event, - 'tags': [self.activity_tag] + 'tags': [self.activity_tag], + 'places': [self.place], }, ] @@ -240,6 +247,7 @@ class ActivityTemplateAPITests(ModelAPITestCaseMixin, APITestCase): 'color': '#555', }, ], + 'places': [str(self.place.pk)], } @property @@ -254,7 +262,192 @@ class ActivityTemplateAPITests(ModelAPITestCaseMixin, APITestCase): 'title': "act temp3", 'is_public': False, 'remarks': "another test remark", - 'tags': [tag_root, tag_bound] + 'tags': [tag_root, tag_bound], + 'places': [self.place], + } + + +class ActivityAPITests(ModelAPITestCaseMixin, APITestCase): + model = Activity + url_label = 'activity' + + list_ordering = 'title' + + def setUp(self): + super().setUp() + + self.event = Event.objects.create( + title='Event', + slug='the-slug', + beginning_date=self.now + timedelta(days=10), + ending_date=self.now + timedelta(days=20), + description="La Nuit n'aura pas lieu.", + created_by=self.user, + ) + + self.activity_tag = ActivityTag.objects.create( + name='tag2', + is_public=False, + color='#222', + ) + + self.place = Place.objects.create( + name='The Place to Be', + description='Super great', + ) + + self.activity_template = ActivityTemplate.objects.create( + title=None, + event=self.event, + is_public=None, + has_perm=True, + min_perm=2, + max_perm=4, + description="Il faut tenir le quai.", + remarks="", + ) + self.activity_template.tags.set([self.activity_tag]) + self.activity_template.places.set([self.place]) + + def get_url_model(self, *args, **kwargs): + kwargs['event_pk'] = self.event.pk + return super().get_url_model(*args, **kwargs) + + def get_url_object(self, *args, **kwargs): + kwargs['event_pk'] = self.event.pk + return super().get_url_object(*args, **kwargs) + + def get_expected_data(self, instance): + return json_format({ + 'url': ( + 'http://testserver/api/event/{event_pk}/activity/{pk}/' + .format(event_pk=instance.event.pk, pk=instance.pk) + ), + 'id': instance.id, + 'title': instance.title, + 'is_public': instance.is_public, + 'remarks': instance.remarks, + 'event': instance.event.pk, + 'tags': [ + { + **(tag.event and { + 'url': ( + 'http://testserver/api/event/{event_pk}/' + 'tag/{tag_pk}/' + .format(event_pk=tag.event.pk, tag_pk=tag.pk) + ), + 'event': tag.event.pk, + } or { + 'url': ( + 'http://testserver/api/tag/{tag_pk}/' + .format(tag_pk=tag.pk) + ), + 'event': None, + }), + 'id': tag.id, + 'name': tag.name, + 'is_public': tag.is_public, + 'color': tag.color, + } + for tag in instance.tags.all() + ], + 'has_perm': instance.has_perm, + 'min_perm': instance.min_perm, + 'max_perm': instance.max_perm, + 'description': instance.description, + 'places': [place.pk for place in instance.places.all()], + 'parent': instance.parent.pk if instance.parent else None, + 'staff': [u.pk for u in instance.staff.all()], + 'beginning': instance.beginning, + 'end': instance.end, + }) + + @property + def instances_data(self): + return [ + { + 'title': "act", + 'is_public': True, + 'remarks': "test remark", + 'event': self.event, + 'beginning': self.now + timedelta(days=12), + 'end': self.now + timedelta(days=13), + }, + { + 'title': "act", + 'is_public': False, + 'remarks': "test remark", + 'event': self.event, + 'tags': [self.activity_tag], + 'places': [self.place], + 'beginning': self.now + timedelta(days=15), + 'end': self.now + timedelta(days=18), + }, + ] + + @property + def create_data(self): + return { + 'title': "act", + 'is_public': False, + 'remarks': "test remark", + 'tags': [ + { + 'name': "tag2", + 'is_public': False, + 'color': '#222', + }, + ], + 'beginning': '2017-10-20 15:45:00', + 'end': '2017-10-21 04:30:00', + } + + @property + def create_expected(self): + return { + **self.create_data, + 'tags': [ActivityTag.objects.get(name='tag2')], + 'beginning': timezone.make_aware( + datetime(2017, 10, 20, 15, 45, 00)), + 'end': timezone.make_aware( + datetime(2017, 10, 21, 4, 30, 00)), + } + + @property + def update_data(self): + return { + 'title': "act", + 'is_public': False, + 'remarks': "another test remark", + 'tags': [ + { + 'name': "tag2", + 'is_public': False, + 'color': '#222', + }, + { + 'name': "body", + 'is_public': True, + 'color': '#555', + }, + ], + 'places': [str(self.place.pk)], + } + + @property + def update_expected(self): + tag_root = ActivityTag.objects.get(name='tag2') + self.assertIsNone(tag_root.event) + + tag_bound = ActivityTag.objects.get(name='body') + self.assertEqual(tag_bound.event, self.event) + + return { + 'title': "act", + 'is_public': False, + 'remarks': "another test remark", + 'tags': [tag_root, tag_bound], + 'places': [self.place], } diff --git a/api/urls.py b/api/urls.py index 1a704a0..706ac49 100644 --- a/api/urls.py +++ b/api/urls.py @@ -16,6 +16,7 @@ event_router = NestedSimpleRouter(router, r'event', lookup='event') event_router.register(r'place', views.PlaceViewSet) event_router.register(r'tag', views.ActivityTagViewSet) event_router.register(r'template', views.ActivityTemplateViewSet) +event_router.register(r'activity', views.ActivityViewSet) # API URLconf: routers + auth for browsable API. diff --git a/event/models.py b/event/models.py index c58b17f..847b0cc 100644 --- a/event/models.py +++ b/event/models.py @@ -219,4 +219,4 @@ class Activity(AbstractActivityTemplate): verbose_name_plural = _("activités") def __str__(self): - return self.get_herited('title') \ No newline at end of file + return self.get_herited('title')