Compare commits
5 commits
master
...
Qwann/Seri
Author | SHA1 | Date | |
---|---|---|---|
|
8568199de4 | ||
|
8d29049989 | ||
|
6bb176be01 | ||
|
2412c8344f | ||
|
26a62ea30b |
14 changed files with 144 additions and 26 deletions
1
api/__init__.py
Normal file
1
api/__init__.py
Normal file
|
@ -0,0 +1 @@
|
|||
default_app_config = 'api.apps.APIConfig'
|
6
api/apps.py
Normal file
6
api/apps.py
Normal file
|
@ -0,0 +1,6 @@
|
|||
from django.utils.translation import ugettext_lazy as _
|
||||
from django.apps import AppConfig
|
||||
|
||||
class APIConfig(AppConfig):
|
||||
name = 'api'
|
||||
verbose_name = _("API")
|
|
@ -1,6 +1,12 @@
|
|||
from django.contrib.auth import get_user_model
|
||||
from django.shortcuts import get_object_or_404
|
||||
|
||||
from rest_framework import serializers
|
||||
from event.models import Event, ActivityTag, Place, ActivityTemplate
|
||||
|
||||
from event.models import Event, ActivityTag, Place, ActivityTemplate, Activity
|
||||
from api.users.serializers import UserSerializer
|
||||
|
||||
User = get_user_model()
|
||||
|
||||
|
||||
# Event Serializer
|
||||
|
@ -111,5 +117,38 @@ class ActivityTemplateSerializer(serializers.ModelSerializer):
|
|||
return activity_template
|
||||
|
||||
|
||||
# TODO rajouter des permissions
|
||||
class ActivitySerializer(serializers.ModelSerializer):
|
||||
pass
|
||||
event = EventSerializer(read_only=True)
|
||||
parent = serializers.PrimaryKeyRelatedField(
|
||||
queryset=ActivityTemplate.objects.all(), allow_null=True)
|
||||
en_perm = UserSerializer(read_only=True)
|
||||
tags = ActivityTagSerializer(many=True)
|
||||
|
||||
class Meta:
|
||||
model = Activity
|
||||
fields = ('id', 'title', 'event', 'parent', 'is_public', 'has_perm',
|
||||
'min_perm', 'max_perm', 'en_perm', 'description', 'remarks',
|
||||
'tags', 'beginning', 'end', )
|
||||
|
||||
def update(self, instance, validated_data):
|
||||
tags_data = validated_data.pop('tags')
|
||||
validated_data.pop('event_pk')
|
||||
event = instance.event
|
||||
[setattr(instance, key, value)
|
||||
for key, value in validated_data.items()]
|
||||
instance.save()
|
||||
tags = [ActivityTag.objects.get_or_create(event=event, **tag_data)[0]
|
||||
for tag_data in tags_data]
|
||||
instance.tags = tags
|
||||
return instance
|
||||
|
||||
def create(self, validated_data):
|
||||
tags_data = validated_data.pop('tags')
|
||||
event_pk = validated_data.pop('event_pk')
|
||||
event = event_pk and get_object_or_404(Event, id=event_pk) or None
|
||||
activity = Activity.objects.create(event=event, **validated_data)
|
||||
tags = [ActivityTag.objects.get_or_create(event=event, **tag_data)[0]
|
||||
for tag_data in tags_data]
|
||||
activity.tags = tags
|
||||
return activity
|
||||
|
|
|
@ -2,6 +2,7 @@ from django.contrib.auth import get_user_model
|
|||
from django.db.models import Q
|
||||
|
||||
from rest_framework.viewsets import ModelViewSet
|
||||
from rest_framework.filters import OrderingFilter
|
||||
|
||||
from api.event.serializers import EventSerializer, PlaceSerializer,\
|
||||
ActivityTagSerializer, ActivityTemplateSerializer, ActivitySerializer
|
||||
|
@ -51,6 +52,11 @@ class EventViewSet(ModelViewSet):
|
|||
queryset = Event.objects.all()
|
||||
serializer_class = EventSerializer
|
||||
|
||||
filter_backends = (OrderingFilter,)
|
||||
ordering_fields = ('title', 'creation_date', 'beginning_date',
|
||||
'ending_date', )
|
||||
ordering = ('beginning_date', )
|
||||
|
||||
def perform_create(self, serializer):
|
||||
serializer.save(created_by=self.request.user)
|
||||
|
||||
|
@ -59,11 +65,19 @@ class PlaceViewSet(EventSpecificViewSet):
|
|||
queryset = Place.objects.all()
|
||||
serializer_class = PlaceSerializer
|
||||
|
||||
filter_backends = (OrderingFilter,)
|
||||
ordering_fields = ('name', )
|
||||
ordering = ('name', )
|
||||
|
||||
|
||||
class ActivityTagViewSet(EventSpecificViewSet):
|
||||
queryset = ActivityTag.objects.all()
|
||||
serializer_class = ActivityTagSerializer
|
||||
|
||||
filter_backends = (OrderingFilter,)
|
||||
ordering_fields = ('name', )
|
||||
ordering = ('name', )
|
||||
|
||||
|
||||
class ActivityTemplateViewSet(ModelViewSet):
|
||||
"""
|
||||
|
@ -82,6 +96,10 @@ class ActivityTemplateViewSet(ModelViewSet):
|
|||
event_pk = self.kwargs.get('event_pk')
|
||||
serializer.save(event_pk=event_pk)
|
||||
|
||||
filter_backends = (OrderingFilter,)
|
||||
ordering_fields = ('title', )
|
||||
ordering = ('title', )
|
||||
|
||||
|
||||
class ActivityViewSet(ModelViewSet):
|
||||
"""
|
||||
|
@ -99,3 +117,7 @@ class ActivityViewSet(ModelViewSet):
|
|||
def perform_update(self, serializer):
|
||||
event_pk = self.kwargs.get('event_pk')
|
||||
serializer.save(event_pk=event_pk)
|
||||
|
||||
filter_backends = (OrderingFilter,)
|
||||
ordering_fields = ('title', )
|
||||
ordering = ('title', )
|
||||
|
|
|
@ -4,14 +4,15 @@ from rest_framework.test import APITestCase
|
|||
|
||||
from event.models import Event, Place, ActivityTag, ActivityTemplate
|
||||
|
||||
from api.event.serializers import ActivityTemplateSerializer, EventSerializer
|
||||
from api.event.serializers import ActivityTemplateSerializer,\
|
||||
EventSerializer, Activity
|
||||
from api.test_mixins import EventBasedModelTestMixin, EventSpecificTestMixin,\
|
||||
ModelTestMixin
|
||||
|
||||
User = get_user_model()
|
||||
|
||||
|
||||
class EventTest(ModelTestMixin, APITestCase):
|
||||
class EventTests(ModelTestMixin, APITestCase):
|
||||
model = Event
|
||||
base_name = 'event'
|
||||
tested_fields = {'title': "I'm a test", }
|
||||
|
@ -22,10 +23,9 @@ class EventTest(ModelTestMixin, APITestCase):
|
|||
serializer = EventSerializer
|
||||
|
||||
|
||||
class ActivityTemplateTest(EventBasedModelTestMixin, APITestCase):
|
||||
class ActivityTemplateTests(EventBasedModelTestMixin, APITestCase):
|
||||
model = ActivityTemplate
|
||||
base_name = 'event-activitytemplate'
|
||||
initial_count = 1
|
||||
# Creation
|
||||
data_creation = 'act_temp2_data'
|
||||
# Update/Delete
|
||||
|
@ -44,13 +44,34 @@ class ActivityTemplateTest(EventBasedModelTestMixin, APITestCase):
|
|||
self.assertEqual(instance.tags.count(), 2)
|
||||
|
||||
|
||||
class EventSpecficTagTest(EventSpecificTestMixin, APITestCase):
|
||||
class ActivityTests(EventBasedModelTestMixin, APITestCase):
|
||||
model = Activity
|
||||
base_name = 'event-activity'
|
||||
# Creation
|
||||
data_creation = 'act2_data'
|
||||
# Update/Delete
|
||||
instance_name = 'act1'
|
||||
field_tested = 'title'
|
||||
serializer = ActivityTemplateSerializer
|
||||
|
||||
def test_create_extra(self):
|
||||
self.assertEqual(self.model.objects.get(id=1).tags.count(), 1)
|
||||
|
||||
def pre_update_extra(self, data):
|
||||
data['tags'].append(self.tag2_data)
|
||||
return data
|
||||
|
||||
def post_update_extra(self, instance):
|
||||
self.assertEqual(instance.tags.count(), 2)
|
||||
|
||||
|
||||
class EventSpecficTagTests(EventSpecificTestMixin, APITestCase):
|
||||
model = ActivityTag
|
||||
root_base_name = 'activitytag'
|
||||
event_base_name = 'event-activitytag'
|
||||
|
||||
|
||||
class EventSpecficPlaceTest(EventSpecificTestMixin, APITestCase):
|
||||
class EventSpecficPlaceTests(EventSpecificTestMixin, APITestCase):
|
||||
model = Place
|
||||
root_base_name = 'place'
|
||||
event_base_name = 'event-place'
|
||||
|
|
|
@ -7,13 +7,13 @@ from django.urls import reverse
|
|||
from rest_framework.test import APIRequestFactory
|
||||
from rest_framework import status
|
||||
|
||||
from event.models import Event, Place, ActivityTag, ActivityTemplate
|
||||
from event.models import Event, Place, ActivityTag, ActivityTemplate, Activity
|
||||
|
||||
|
||||
User = get_user_model()
|
||||
|
||||
|
||||
class DataBaseMixin(object):
|
||||
class DataBaseMixin():
|
||||
"""
|
||||
provides a datatabse for API tests
|
||||
"""
|
||||
|
@ -51,6 +51,19 @@ class DataBaseMixin(object):
|
|||
self.act_temp1 = ActivityTemplate.objects.create(**self.act_temp1_data)
|
||||
self.act_temp1.tags.add(self.tag1)
|
||||
|
||||
# Actitvity
|
||||
self.act1_data = {'title': "act1", 'is_public': True,
|
||||
'beginning': timezone.now(),
|
||||
'end': timezone.now()+timedelta(hours=2),
|
||||
'remarks': "test remark", 'event': self.event1}
|
||||
self.act2_data = {'title': "act2", 'is_public': False,
|
||||
"beginning": "2017-07-18T18:05:00Z",
|
||||
"end": "2017-07-19T18:05:00Z",
|
||||
'parent': None,
|
||||
'remarks': "test remark", 'tags': []}
|
||||
self.act1 = Activity.objects.create(**self.act1_data)
|
||||
self.act1.tags.add(self.tag1)
|
||||
|
||||
|
||||
class EventBasedModelTestMixin(DataBaseMixin):
|
||||
"""
|
||||
|
@ -83,6 +96,7 @@ class EventBasedModelTestMixin(DataBaseMixin):
|
|||
ensure a permited user can create a new %model object using API
|
||||
"""
|
||||
data = getattr(self, self.data_creation)
|
||||
initial_count = self.model.objects.count()
|
||||
|
||||
event_id = self.event1.id
|
||||
url = reverse('{base_name}-list'.format(base_name=self.base_name),
|
||||
|
@ -90,9 +104,10 @@ class EventBasedModelTestMixin(DataBaseMixin):
|
|||
self.client.force_authenticate(user=self.user1)
|
||||
response = self.client.post(url, data,
|
||||
format='json')
|
||||
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
|
||||
self.assertEqual(self.model.objects.count(), self.initial_count + 1)
|
||||
self.assertEqual(self.model.objects.get(id=self.initial_count+1).event,
|
||||
self.assertEqual(response.status_code, status.HTTP_201_CREATED,
|
||||
msg=response.content)
|
||||
self.assertEqual(self.model.objects.count(), initial_count + 1)
|
||||
self.assertEqual(self.model.objects.get(id=initial_count+1).event,
|
||||
self.event1)
|
||||
|
||||
self.user_create_extra()
|
||||
|
@ -120,7 +135,8 @@ class EventBasedModelTestMixin(DataBaseMixin):
|
|||
|
||||
self.client.force_authenticate(user=self.user1)
|
||||
response = self.client.patch(url, data, format='json')
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK,
|
||||
msg=response.content)
|
||||
|
||||
instance.refresh_from_db()
|
||||
self.assertEqual(getattr(instance, self.field_tested), newvalue)
|
||||
|
@ -132,6 +148,7 @@ class EventBasedModelTestMixin(DataBaseMixin):
|
|||
ensure a permited user can delete a new %model object using API
|
||||
"""
|
||||
instance = getattr(self, self.instance_name)
|
||||
initial_count = self.model.objects.count()
|
||||
|
||||
instance_id = instance.id
|
||||
event_id = self.event1.id
|
||||
|
@ -141,14 +158,15 @@ class EventBasedModelTestMixin(DataBaseMixin):
|
|||
|
||||
self.client.force_authenticate(user=self.user1)
|
||||
response = self.client.delete(url)
|
||||
self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT)
|
||||
self.assertEqual(self.model.objects.count(), self.initial_count - 1)
|
||||
self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT,
|
||||
msg=response.content)
|
||||
self.assertEqual(self.model.objects.count(), initial_count - 1)
|
||||
|
||||
|
||||
# TODO rajouter la gestion des permissions dans le Mixin
|
||||
# TODO rajouter un test pour s'assurer que les personnes non
|
||||
# connectées ne peuvent pas create/update/delete
|
||||
class EventSpecificTestMixin(object):
|
||||
class EventSpecificTestMixin():
|
||||
"""
|
||||
Tests is the EventSpecifics querysets are rendered correctly
|
||||
using the API
|
||||
|
@ -234,7 +252,8 @@ class ModelTestMixin(DataBaseMixin):
|
|||
self.client.force_authenticate(user=self.user1)
|
||||
response = self.client.post(url, data)
|
||||
|
||||
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
|
||||
self.assertEqual(response.status_code, status.HTTP_201_CREATED,
|
||||
msg=response.content)
|
||||
self.assertEqual(self.model.objects.count(), initial_count + 1)
|
||||
|
||||
instance = self.model.objects.get(id=initial_count+1)
|
||||
|
@ -259,7 +278,8 @@ class ModelTestMixin(DataBaseMixin):
|
|||
|
||||
self.client.force_authenticate(user=self.user1)
|
||||
response = self.client.put(url, data, format='json')
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK,
|
||||
msg=response.content)
|
||||
|
||||
instance.refresh_from_db()
|
||||
for field, value in self.tested_fields.items():
|
||||
|
@ -278,5 +298,6 @@ class ModelTestMixin(DataBaseMixin):
|
|||
|
||||
self.client.force_authenticate(user=self.user1)
|
||||
response = self.client.delete(url)
|
||||
self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT)
|
||||
self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT,
|
||||
msg=response.content)
|
||||
self.assertEqual(self.model.objects.count(), initial_count - 1)
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
from django.conf.urls import url, include
|
||||
from rest_framework_nested.routers import SimpleRouter, NestedSimpleRouter
|
||||
from api.event.views import EventViewSet, PlaceViewSet, ActivityTagViewSet,\
|
||||
ActivityTemplateViewSet
|
||||
ActivityTemplateViewSet, ActivityViewSet
|
||||
|
||||
# Create a router and register our viewsets with it.
|
||||
router = SimpleRouter()
|
||||
|
@ -12,9 +12,11 @@ router.register(r'activitytag', ActivityTagViewSet, 'activitytag')
|
|||
# Register nested router and register someviewsets vith it
|
||||
event_router = NestedSimpleRouter(router, r'event', lookup='event')
|
||||
event_router.register(r'place', PlaceViewSet, base_name='event-place')
|
||||
event_router.register(r'tag', ActivityTagViewSet, base_name='event-activitytag')
|
||||
event_router.register(r'tag', ActivityTagViewSet,
|
||||
base_name='event-activitytag')
|
||||
event_router.register(r'activitytemplate', ActivityTemplateViewSet,
|
||||
base_name='event-activitytemplate')
|
||||
event_router.register(r'activity', ActivityViewSet, base_name='event-activity')
|
||||
|
||||
|
||||
# The API URLs are now determined automatically by the router.
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
default_app_config = 'communication.apps.CommunicationConfig'
|
|
@ -1,4 +1,6 @@
|
|||
from django.utils.translation import ugettext_lazy as _
|
||||
from django.apps import AppConfig
|
||||
|
||||
class CommunicationConfig(AppConfig):
|
||||
name = 'communication'
|
||||
verbose_name = _("communication")
|
||||
|
|
1
equipment/__init__.py
Normal file
1
equipment/__init__.py
Normal file
|
@ -0,0 +1 @@
|
|||
default_app_config = 'equipment.apps.EquipmentConfig'
|
|
@ -44,10 +44,6 @@ BASE_DIR = os.path.dirname(
|
|||
|
||||
|
||||
INSTALLED_APPS = [
|
||||
'communication.apps.CommunicationConfig',
|
||||
'equipment.apps.EquipmentConfig',
|
||||
'event.apps.EventConfig',
|
||||
'users.apps.UsersConfig',
|
||||
'shared.apps.SharedConfig',
|
||||
'django.contrib.admin',
|
||||
'django.contrib.auth',
|
||||
|
@ -60,6 +56,10 @@ INSTALLED_APPS = [
|
|||
'bootstrapform',
|
||||
'widget_tweaks',
|
||||
'api',
|
||||
'communication',
|
||||
'equipment',
|
||||
'event',
|
||||
'users',
|
||||
]
|
||||
|
||||
MIDDLEWARE_CLASSES = [
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
default_app_config = 'event.apps.EventConfig'
|
|
@ -0,0 +1 @@
|
|||
default_app_config = 'users.apps.UsersConfig'
|
0
users/migrations/__init__.py
Normal file
0
users/migrations/__init__.py
Normal file
Loading…
Reference in a new issue