Skip to content
Snippets Groups Projects
Commit a210d55f authored by florimondmanca's avatar florimondmanca
Browse files

some fixes to serializers, add HyperlinkedAPITestCase utility, update tests

parent a0511db7
Branches
No related tags found
No related merge requests found
Showing with 450 additions and 365 deletions
"""Model API tests."""
from rest_framework import status
# from tests.factory import ***
# from xxx.serializers import ***
from tests.utils.api import HyperlinkedAPITestCase
class StudentEndpointsTest(HyperlinkedAPITestCase):
"""Test access to the students endpoints."""
factory = 'StudentFactory'
serializer_class = 'StudentSerializer'
def test_list(self):
url = ''
response = self.client.get(url)
self.assertEqual(response.status_code, 200)
def test_retrieve(self):
obj = self.factory.create()
url = '/api/foo/{obj.pk}/'.format(obj=obj)
response = self.client.get(url)
self.assertEqual(response.status_code, 200)
def test_create(self):
url = '/api/students/'
# build obj using factory.build()
obj = self.factory.build()
# serialize the object to get POST data
data = self.serialize(obj, 'post', url)
# send request and check status code
response = self.client.post(url, data, format='json')
self.assertEqual(response.status_code, status.HTTP_201_CREATED,
msg=response.data)
def test_update(self):
# create test obj
obj = self.factory.create()
# PUT request URL
url = '/api/foo/{obj.pk}/'.format(obj=obj)
# serialize the object to get PUT data
data = self.serialize(obj, 'put', url)
# update one of the fields
field = 'address'
field_value = 'Modified address'
data[field] = field_value
# send request and check status code
response = self.client.put(url, data, format='json')
self.assertEqual(response.status_code, status.HTTP_200_OK,
msg=response.data)
def test_partial_update(self):
# create test obj
obj = self.factory.create()
# PATCH request URL
url = '/api/foo/{obj.pk}/'.format(obj=obj)
# update one of the fields
field = 'address'
field_value = 'Modified address'
data = []
data[field] = field_value
# send request and check status code
response = self.client.patch(url, data, format='json')
self.assertEqual(response.status_code, status.HTTP_200_OK,
msg=response.data)
def test_delete(self):
# create test obj
obj = self.factory.create()
# DELETE request URL
url = '/api/foo/{obj.pk}/'.format(obj=obj)
# send request and check status code
response = self.client.delete(url)
self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT)
"""School API tests."""
from rest_framework.test import APITestCase
from rest_framework import status
from tutoring.models import School
from tutoring.serializers import SchoolSerializer
from tests.factory import SchoolFactory
from tests.utils.api import HyperlinkedAPITestCase
from tests.factory import SchoolFactory, UserFactory
from tests.utils import AuthAPITestMixin
from tests.utils import APIReadTestMixin
from tests.utils import APIPostRequestTestMixin
class SchoolEndpointsTest(HyperlinkedAPITestCase):
"""Test access to the school endpoints."""
class SchoolReadTest(AuthAPITestMixin, APIReadTestMixin, APITestCase):
"""Test reading schools from API as authenticated user."""
model = School
factory = SchoolFactory
list_url = '/api/schools/'
retrieve_url_format = '/api/schools/{obj.pk}/'
data_content_keys = ('uai_code', 'students', 'name', 'url',
'students_count', 'address',)
@classmethod
def get_user(cls):
return UserFactory.create()
class SchoolCreateTest(AuthAPITestMixin, APIPostRequestTestMixin, APITestCase):
"""Test creating a school as an authenticated user."""
serializer_class = SchoolSerializer
def test_list(self):
url = '/api/schools/'
response = self.client.get(url)
self.assertEqual(response.status_code, 200)
@classmethod
def get_user(cls):
return UserFactory.create()
def get_obj(self):
return SchoolFactory.build()
def test_retrieve(self):
obj = self.factory.create()
url = '/api/schools/{obj.pk}/'.format(obj=obj)
response = self.client.get(url)
self.assertEqual(response.status_code, 200)
def get_post_data(self, obj):
return {
'name': obj.name,
'uai_code': obj.uai_code,
'address': obj.address,
}
def test_create(self):
url = '/api/schools/'
obj = self.factory.build()
data = self.serialize(obj, 'post', url)
response = self.client.post(url, data, format='json')
self.assertEqual(response.status_code, status.HTTP_201_CREATED,
msg=response.data)
def test_update(self):
obj = self.factory.create()
url = '/api/schools/{obj.pk}/'.format(obj=obj)
data = self.serialize(obj, 'put', url)
data['name'] = 'Modified name'
response = self.client.put(url, data, format='json')
self.assertEqual(response.status_code, status.HTTP_200_OK,
msg=response.data)
def test_partial_update(self):
obj = self.factory.create()
url = '/api/schools/{obj.pk}/'.format(obj=obj)
data = {'name': 'Modified name'}
response = self.client.patch(url, data, format='json')
self.assertEqual(response.status_code, status.HTTP_200_OK,
msg=response.data)
def test_delete(self):
obj = self.factory.create()
url = '/api/schools/{obj.pk}/'.format(obj=obj)
response = self.client.delete(url)
self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT)
"""Student API tests."""
from rest_framework.test import APITestCase
from rest_framework import status
from users.models import Student
from tests.factory import (
StudentFactory, UserFactory, SchoolFactory, TutoringGroupFactory)
from tests.utils import AuthAPITestMixin
from tests.utils import APIReadTestMixin
from tests.utils import APIPostRequestTestMixin
from users.serializers import StudentSerializer
from tests.factory import StudentFactory, UserFactory, TutoringGroupFactory
from tests.utils.api import HyperlinkedAPITestCase
class StudentReadTest(AuthAPITestMixin, APIReadTestMixin, APITestCase):
"""Test read students as authenticated user."""
class StudentEndpointsTest(HyperlinkedAPITestCase):
"""Test access to the students endpoints."""
model = Student
factory = StudentFactory
list_url = '/api/students/'
retrieve_url_format = '/api/students/{obj.pk}/'
data_content_keys = ('user_id', 'user', 'address', 'tutoring_group',
'school', 'url')
serializer_class = StudentSerializer
@classmethod
def get_user(cls):
return UserFactory.create()
def test_list(self):
response = self.client.get('/api/students/')
self.assertEqual(response.status_code, 200)
def test_retrieve(self):
obj = self.factory.create()
response = self.client.get(f'/api/students/{obj.pk}/')
self.assertEqual(response.status_code, 200)
class StudentCreateTest(APIPostRequestTestMixin, APITestCase):
"""Test create student as anonymous user."""
def test_create(self):
url = '/api/students/'
def get_obj(self):
user = UserFactory.create()
school = SchoolFactory.create()
tutoring_group = TutoringGroupFactory.create(school=school)
obj = StudentFactory.build(user=user, school=school,
tutoring_group=tutoring_group)
return obj
def get_post_data(self, obj):
return {
'user': obj.user.get_absolute_url(),
'address': obj.address,
'school': obj.school.get_absolute_url(),
'tutoring_group': obj.tutoring_group.get_absolute_url(),
}
tutoring_group = TutoringGroupFactory.create()
obj = self.factory.build(user=user,
tutoring_group=tutoring_group,
school=tutoring_group.school)
data = self.serialize(obj, 'post', url)
response = self.client.post(url, data, format='json')
self.assertEqual(response.status_code, status.HTTP_201_CREATED,
response.data)
def test_update(self):
obj = self.factory.create()
url = f'/api/students/{obj.pk}/'
data = self.serialize(obj, 'put', url)
data['address'] = 'Modified address'
response = self.client.put(url, data, format='json')
self.assertEqual(response.status_code, status.HTTP_200_OK)
def test_partial_update(self):
obj = self.factory.create()
response = self.client.patch(f'/api/students/{obj.pk}/',
data={'address': 'Modified address'},
format='json')
self.assertEqual(response.status_code, status.HTTP_200_OK)
def test_delete(self):
obj = self.factory.create()
response = self.client.delete(f'/api/students/{obj.pk}/')
self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT)
"""Tutor API tests."""
from rest_framework.test import APITestCase
from rest_framework import status
from users.models import Tutor
from tests.utils import AuthAPITestMixin
from tests.utils import APIReadTestMixin
from tests.utils import APIPostRequestTestMixin
from tests.factory import TutorFactory, UserFactory
from users.serializers import TutorSerializer
from tests.factory import TutorFactory
from tests.utils.api import HyperlinkedAPITestCase
class TutorReadTest(AuthAPITestMixin, APIReadTestMixin,
APITestCase):
"""Test read tutors from API as authenticated user."""
class TutorEndpointsTest(HyperlinkedAPITestCase):
"""Test access to the tutors endpoints."""
model = Tutor
factory = TutorFactory
list_url = '/api/tutors/'
retrieve_url = '/api/tutors/{obj.pk}/'
data_content_keys = ('user_id', 'user', 'promotion', 'tutoring_groups',
'url',)
@classmethod
def get_user(cls):
return UserFactory.create()
class TutorCreateTest(APIPostRequestTestMixin, APITestCase):
"""Test create tutor as anonymous user."""
serializer_class = TutorSerializer
def test_list(self):
url = '/api/tutors/'
response = self.client.get(url)
self.assertEqual(response.status_code, 200)
def get_obj(self):
user = UserFactory.create()
obj = TutorFactory.build(user=user)
return obj
def test_retrieve(self):
obj = self.factory.create()
url = '/api/tutors/{obj.pk}/'.format(obj=obj)
response = self.client.get(url)
self.assertEqual(response.status_code, 200)
def get_post_data(self, obj):
return {
'user': obj.user.get_absolute_url(),
'promotion': obj.promotion,
}
def test_create(self):
url = '/api/tutors/'
obj = self.factory.build()
data = self.serialize(obj, 'post', url)
response = self.client.post(url, data, format='json')
self.assertEqual(response.status_code, status.HTTP_201_CREATED,
msg=response.data)
def test_update(self):
obj = self.factory.create()
url = '/api/tutors/{obj.pk}/'.format(obj=obj)
data = self.serialize(obj, 'put', url)
data['promotion'] = 2020
response = self.client.put(url, data, format='json')
self.assertEqual(response.status_code, status.HTTP_200_OK,
msg=response.data)
def test_partial_update(self):
obj = self.factory.create()
url = '/api/tutors/{obj.pk}/'.format(obj=obj)
data = {'promotion': 2020}
response = self.client.patch(url, data, format='json')
self.assertEqual(response.status_code, status.HTTP_200_OK,
msg=response.data)
def test_delete(self):
obj = self.factory.create()
url = '/api/tutors/{obj.pk}/'.format(obj=obj)
response = self.client.delete(url)
self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT)
"""School API tests."""
"""Tutoring group API tests."""
from rest_framework.test import APITestCase
from rest_framework import status
from tutoring.models import TutoringGroup
from tests.utils import AuthAPITestMixin
from tests.utils import APIReadTestMixin
from tests.utils import APIPostRequestTestMixin
from tests.factory import (
TutoringGroupFactory, UserFactory, VpTutoratTutorFactory, SchoolFactory
)
from tests.factory import TutoringGroupFactory, SchoolFactory
from tests.factory import UserFactory, VpTutoratTutorFactory
from tutoring.serializers import TutoringGroupSerializer
from tests.utils.api import HyperlinkedAPITestCase
class TutoringGroupReadTest(AuthAPITestMixin, APIReadTestMixin,
APITestCase):
"""Test authenticated user can read tutoring groups."""
class TutoringGroupEndpointsTest(HyperlinkedAPITestCase):
"""Test access to the tutoring group endpoints."""
model = TutoringGroup
factory = TutoringGroupFactory
list_url = '/api/tutoring/groups/'
retrieve_url_format = '/api/tutoring/groups/{obj.pk}/'
data_content_keys = ('id', 'url', 'name', 'tutors', 'students',
'tutors_count', 'students_count', 'school',)
serializer_class = TutoringGroupSerializer
def get_obj(self):
return TutoringGroupFactory.create()
def test_list(self):
url = '/api/tutoring/groups/'
response = self.client.get(url)
self.assertEqual(response.status_code, 200)
def test_retrieve(self):
obj = self.factory.create()
url = '/api/tutoring/groups/{obj.pk}/'.format(obj=obj)
response = self.client.get(url)
self.assertEqual(response.status_code, 200)
def perform_create(self, user=None):
if user is not None:
self.client.force_login(user)
url = '/api/tutoring/groups/'
school = SchoolFactory.create()
obj = self.factory.build(school=school, id=123)
data = self.serialize(obj, 'post', url)
response = self.client.post(url, data, format='json')
return response
@classmethod
def get_user(cls):
return UserFactory.create()
def test_create_anonymous_user_forbidden(self):
self.assertForbidden(self.perform_create, user=None)
def test_create_regular_user_forbidden(self):
self.assertForbidden(self.perform_create, user=UserFactory.create())
class CreateTutoringGroupStandardUser(AuthAPITestMixin,
APIPostRequestTestMixin,
APITestCase):
"""Test a standard user cannot create a tutoring group."""
def test_create_as_vp_tutorat_allowed(self):
tutor = VpTutoratTutorFactory.create()
self.assertAuthorized(self.perform_create, user=tutor.user,
expected_status_code=status.HTTP_201_CREATED)
url = '/api/tutoring/groups/'
expected_status_code = status.HTTP_403_FORBIDDEN
def perform_update(self):
obj = self.factory.create()
url = '/api/tutoring/groups/{obj.pk}/'.format(obj=obj)
data = self.serialize(obj, 'put', url)
data['name'] = 'Modified name'
response = self.client.put(url, data, format='json')
return response
def get_obj(self):
school = SchoolFactory.create()
return TutoringGroupFactory.build(school=school)
def test_update_anonymous_user_forbidden(self):
self.assertForbidden(self.perform_update, user=None)
def get_post_data(self, obj):
return {
'name': obj.name,
'school': obj.school.get_absolute_url(),
}
def test_update_regular_user_forbidden(self):
self.assertForbidden(self.perform_update, user=UserFactory.create())
@classmethod
def get_user(cls):
return UserFactory.create()
def test_update_vp_tutorat_allowed(self):
tutor = VpTutoratTutorFactory.create()
self.assertAuthorized(self.perform_update, user=tutor.user,
expected_status_code=status.HTTP_200_OK)
def perform_partial_update(self):
obj = self.factory.create()
url = '/api/tutoring/groups/{obj.pk}/'.format(obj=obj)
data = {'name': 'Modified name'}
response = self.client.patch(url, data, format='json')
return response
def test_partial_update_anonymous_user_forbidden(self):
self.assertForbidden(self.perform_partial_update, user=None)
def test_partial_update_regular_user_forbidden(self):
self.assertForbidden(self.perform_partial_update,
user=UserFactory.create())
def test_partial_update_vp_tutorat_allowed(self):
tutor = VpTutoratTutorFactory.create()
self.assertAuthorized(self.perform_partial_update, user=tutor.user,
expected_status_code=status.HTTP_200_OK)
def perform_delete(self):
obj = self.factory.create()
url = '/api/tutoring/groups/{obj.pk}/'.format(obj=obj)
response = self.client.delete(url)
return response
class CreateTutoringGroupVpTutorat(CreateTutoringGroupStandardUser):
"""Test a VP Tutorat user can create a tutoring group."""
def test_delete_anonymous_user_forbidden(self):
self.assertForbidden(self.perform_delete, user=None)
expected_status_code = status.HTTP_201_CREATED
def test_delete_regular_user_forbidden(self):
self.assertForbidden(self.perform_delete,
user=UserFactory.create())
@classmethod
def get_user(cls):
def test_delete_vp_tutorat_allowed(self):
tutor = VpTutoratTutorFactory.create()
return tutor.user
self.assertAuthorized(self.perform_delete, user=tutor.user,
expected_status_code=status.HTTP_204_NO_CONTENT)
"""Users API tests."""
from rest_framework import status
from django.template.defaulttags import date
from django.contrib.auth import get_user_model
from rest_framework.test import APITestCase
from users.serializers import UserSerializer, UserCreateSerializer
from tests.factory import UserFactory
from tests.utils import AuthAPITestMixin
from tests.utils import APIPostRequestTestMixin
from tests.utils import APIReadTestMixin
User = get_user_model()
from tests.utils.api import HyperlinkedAPITestCase
class UserReadTest(AuthAPITestMixin, APIReadTestMixin, APITestCase):
"""Test authenticated users can read users."""
class UserEndpointsTest(HyperlinkedAPITestCase):
"""Test access to the users endpoints."""
model = User
factory = UserFactory
list_url = '/api/users/'
retrieve_url_format = '/api/users/{obj.pk}/'
data_content_keys = (
'id', 'url', 'first_name', 'last_name', 'email', 'date_of_birth',
'phone_number', 'gender', 'profile',
)
serializer_class = UserSerializer
@classmethod
def get_user(cls):
return UserFactory.create()
def test_list(self):
response = self.client.get('/api/users/')
self.assertEqual(response.status_code, 200)
def test_retrieve(self):
obj = self.factory.create()
response = self.client.get(f'/api/users/{obj.pk}/')
self.assertEqual(response.status_code, 200)
class UserCreateTest(APIPostRequestTestMixin, APITestCase):
"""Test anonymous user can create a user."""
def test_create(self):
url = '/api/users/'
def get_obj(self):
return UserFactory.build()
def get_post_data(self, obj):
return {
'email': obj.email,
'first_name': obj.first_name,
'last_name': obj.last_name,
'phone_number': obj.phone_number,
'date_of_birth': obj.date_of_birth.strftime('%d/%m/%Y'),
'gender': obj.gender,
'profile_type': obj.profile_type,
'password': 'secret',
}
obj = self.factory.build()
data = self.serialize(obj, 'post', url,
serializer_class=UserCreateSerializer)
data['password'] = 'secret' # write-only on the serializer
response = self.client.post(url, data, format='json')
self.assertEqual(response.status_code, status.HTTP_201_CREATED,
response.data)
def test_update(self):
obj = self.factory.create()
url = f'/api/users/{obj.pk}/'
data = self.serialize(obj, 'put', url)
data['first_name'] = 'Modified first name'
response = self.client.put(url, data, format='json')
self.assertEqual(response.status_code, status.HTTP_200_OK)
def test_partial_update(self):
obj = self.factory.create()
response = self.client.patch(f'/api/users/{obj.pk}/',
data={'first_name': 'Some first name'},
format='json')
self.assertEqual(response.status_code, status.HTTP_200_OK)
def test_delete(self):
obj = self.factory.create()
response = self.client.delete(f'/api/users/{obj.pk}/')
self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT)
......@@ -4,7 +4,7 @@ from django.db import IntegrityError
from django.contrib.auth import get_user_model
from users.models import Profile
from tests.utils import random_email, ModelTestCase
from tests.utils import ModelTestCase
from tests.factory import UserFactory
......@@ -81,10 +81,11 @@ class UserModelTest(ModelTestCase):
self.assertEqual(200, response.status_code)
def test_two_users_with_same_username_allowed(self):
self.model.objects.create(email=random_email(), username='foo')
self.model.objects.create(email=random_email(), username='foo')
UserFactory.create(username='foo')
UserFactory.create(username='foo')
def test_two_users_with_same_email_not_allowed(self):
same_email = 'same.email@example.net'
with self.assertRaises(IntegrityError):
self.model.objects.create(email='same.email@example.net')
self.model.objects.create(email='same.email@example.net')
UserFactory.create(email=same_email)
UserFactory.create(email=same_email)
......@@ -136,8 +136,5 @@ class UtilsImportsTest(TestCase):
def test_import_abstract_model_test_case(self):
from tests.utils import MixinModelTestCase
def test_import_random_email(self):
from tests.utils import random_email
def test_import_random_uai_code(self):
from tests.utils import random_uai_code
"""API test utilities."""
from rest_framework.test import APITestCase, APIRequestFactory
from rest_framework import status
__all__ = ('HyperlinkedAPITestCase',)
__all__ = ('AuthAPITestMixin', 'APIReadTestMixin', 'APIPostRequestTestMixin')
class HyperlinkedAPITestCase(APITestCase):
"""API test case suited for hyperlinked serializers."""
class AuthAPITestMixin:
"""Mixin class to use a test case with a logged in user."""
serializer_class = None
@classmethod
def get_user(cls):
"""Return a user to log into the API with."""
raise NotImplementedError
def serialize(self, obj, method, url,
serializer_class=None):
"""Serialize an object.
@classmethod
def setUpTestData(cls):
cls.user = cls.get_user()
def setUp(self):
self.client.force_login(self.user)
class APIReadTestMixin:
"""Test mixin suited for testing read actions (list, retrieve) on models.
Attributes
Parameters
----------
model : django.db.models.Model
factory : factory.Factory
A FactoryBoy factory used to create a test object.
list_url : str
retrieve_url_format : str
Formatted string with an {obj} tag.
Example: 'api/students/{obj.pk}/'
n_items : int, optional
Number of items to generate in test_list().
data_content_keys : tuple
obj : instance of django.db.models.Model
method : str
An HTTP method (case insensitive), e.g. 'post'.
url : str
serializer_class : subclass of rest_framework.Serializer, optional
If not given, the test case class' serializer_class attribute
will be used.
"""
model = None
factory = None
list_url = ''
retrieve_url_format = ''
n_items = 5
data_content_keys = ()
def test_list(self):
"""Test the list action.
Creates a list of objects and performs an HTTP GET at `list_url`.
Succeeds if request status code is 200.
"""
n_before = self.model.objects.all().count()
self.factory.create_batch(self.n_items)
url = self.list_url
response = self.client.get(url)
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(len(response.data) - n_before, self.n_items)
def test_retrieve(self):
"""Test the retrieve action.
Retrieves an object as in test_retrieve and checks that keys specified
in `data_content_keys` are contained in response.data.
if serializer_class is None:
serializer_class = self.get_serializer_class()
request_factory = getattr(APIRequestFactory(), method.lower())
request = request_factory(url, format='json')
serializer = serializer_class(
obj, context={'request': request})
data = serializer.data
return data
def get_serializer_class(self):
"""Return the serializer class."""
if self.serializer_class is None:
raise AttributeError('serializer_class attribute not defined'
f'for {self.__class__}')
return self.serializer_class
def assertAuthorized(self, perform_request, user, expected_status_code):
"""Assert a user is authorized to make a given request.
Parameters
----------
perform_request : function: None -> response
Should send the request of interest and return the response object.
user : Django User
expected_status_code : int
HTTP status code.
"""
obj = self.factory.create()
url = self.retrieve_url_format.format(obj=obj)
response = self.client.get(url)
self.assertEqual(response.status_code, status.HTTP_200_OK)
if user is not None:
self.client.force_login(user)
response = perform_request()
self.assertEqual(response.status_code, expected_status_code)
def test_data_content(self):
"""Test the content of a retrieve action data.
def assertForbidden(self, perform_request, user):
"""Assert a user is not authorized to make a given request.
Retrieves an object as in test_retrieve and checks that the set of
keys specified in `data_content_keys` equals the keys of the
response data.
Parameters
----------
perform_request : function: None -> response
Should send the request of interest and return the response object.
user : Django User
"""
obj = self.factory.create()
url = obj.get_absolute_url()
response = self.client.get(url)
self.assertEqual(
set(self.data_content_keys), set(response.data.keys()))
class APIRequestTestMixin:
"""Generic API request test mixin."""
url = ''
expected_status_code = None
def get_url(self):
return self.url
class APIPostRequestTestMixin(APIRequestTestMixin):
"""Generic API POST request test mixin."""
expected_status_code = status.HTTP_201_CREATED
def get_obj(self):
"""Return a test object to extract POST data from."""
raise NotImplementedError
def get_post_data(self, obj):
"""Return data to send in POST request."""
raise NotImplementedError
def test_post(self):
"""Perform the POST request test."""
obj = self.get_obj()
data = self.get_post_data(obj)
response = self.client.post(self.url, data, format='json')
self.assertEqual(response.status_code, self.expected_status_code,
response.data)
if user is not None:
self.client.force_login(user)
response = perform_request()
self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
......@@ -4,18 +4,7 @@ import random
from string import ascii_lowercase, digits
__all__ = ('random_username', 'random_email', 'random_uai_code')
def random_username():
"""Return a random username with 12 lowercase letters."""
return ''.join(random.choices(ascii_lowercase, k=12))
def random_email():
"""Return a random email."""
prefix = ''.join(random.choices(ascii_lowercase, k=12))
return f'{prefix}@random.net'
__all__ = ('random_uai_code',)
def random_uai_code():
......
......@@ -74,10 +74,11 @@ class TutoringGroup(models.Model):
return is_in_group(request.user, Groups.VP_TUTORAT)
@allow_staff_or_superuser
def has_object_update_permission(self, request):
"""Can only be updated by admin, leader tutor or VP tutorat."""
def has_object_write_permission(self, request):
"""Can only be written by admin, leader tutor or VP tutorat."""
is_leader = (self.tutors
.filter(user_id=request.user.id, is_leader=True)
.filter(user_id=request.user.id,
tutortutoringgroup__is_leader=True)
.exists())
is_vp_tutorat = is_in_group(request.user, Groups.VP_TUTORAT)
return is_leader or is_vp_tutorat
......@@ -110,7 +111,9 @@ class School(models.Model):
# TODO add UAI code validation
uai_code = models.CharField(
'code UAI', max_length=8, primary_key=True,
'code UAI',
max_length=8,
primary_key=True,
validators=[uai_code_validator],
help_text=(
"Code UAI (ex-RNE) de l'établissement. "
......
......@@ -50,17 +50,10 @@ class SchoolCreateSerializer(SchoolSerializer):
Suited for: create
"""
students = serializers.HyperlinkedRelatedField(
many=True,
required=False,
queryset=Student.objects.all(),
view_name='api:student-detail',
help_text='Lycéens inscrits à ce lycée',
)
class Meta(SchoolSerializer.Meta): # noqa
extra_kwargs = {
**SchoolSerializer.Meta.extra_kwargs,
'students': {'required': False},
'uai_code': {'read_only': False},
}
......@@ -79,7 +72,7 @@ class TutoringGroupSerializer(serializers.HyperlinkedModelSerializer):
view_name='api:student-detail',
)
school = serializers.HyperlinkedRelatedField(
queryset=School.objects.all(),
read_only=True,
view_name='api:school-detail',
)
students_count = serializers.IntegerField(source='students.count',
......
......@@ -10,7 +10,7 @@ User = get_user_model()
class UserSerializer(serializers.HyperlinkedModelSerializer):
"""Serializer for User.
"""Hyperlinked serializer for User.
Actions: list, retrieve, delete
"""
......@@ -28,27 +28,14 @@ class UserSerializer(serializers.HyperlinkedModelSerializer):
class Meta: # noqa
model = User
fields = ('id', 'url', 'email',
'first_name', 'last_name', 'gender',
fields = ('id', 'email',
'first_name', 'last_name',
'gender',
'phone_number', 'date_of_birth',
'profile',)
'profile', 'url',)
extra_kwargs = {
'url': {'view_name': 'api:user-detail'},
'email': {'read_only': True},
}
class UserUpdateSerializer(UserSerializer):
"""Serializer for updating users.
Actions: update, partial_update
"""
class Meta(UserSerializer.Meta): # noqa
fields = (*UserSerializer.Meta.fields,)
extra_kwargs = {
**UserSerializer.Meta.extra_kwargs,
'email': {'read_only': False},
'url': {'view_name': 'api:user-detail'},
}
......@@ -69,7 +56,21 @@ class UserCreateSerializer(UserSerializer):
return user
class Meta(UserSerializer.Meta): # noqa
fields = (*UserSerializer.Meta.fields, 'profile_type', 'password',)
fields = (*UserSerializer.Meta.fields,
'profile_type', 'password',)
extra_kwargs = {
**UserSerializer.Meta.extra_kwargs,
'email': {'read_only': False},
}
class UserUpdateSerializer(UserSerializer):
"""Serializer for updating users.
Actions: update, partial_update
"""
class Meta(UserSerializer.Meta): # noqa
extra_kwargs = {
**UserSerializer.Meta.extra_kwargs,
'email': {'read_only': False},
......@@ -77,7 +78,7 @@ class UserCreateSerializer(UserSerializer):
class ProfileSerializer(serializers.Serializer):
"""Base serializer for profile models."""
"""Base hyperlinked serializer for profile models."""
user = serializers.HyperlinkedRelatedField(
read_only=True,
......@@ -87,7 +88,7 @@ class ProfileSerializer(serializers.Serializer):
class TutorSerializer(ProfileSerializer,
serializers.HyperlinkedModelSerializer):
"""Serializer for Tutor."""
"""Hyperlinked serializer for Tutor."""
tutoring_groups = serializers.HyperlinkedRelatedField(
many=True,
......@@ -97,7 +98,7 @@ class TutorSerializer(ProfileSerializer,
class Meta: # noqa
model = Tutor
fields = ('user_id', 'url', 'user', 'promotion', 'tutoring_groups',)
fields = ('user_id', 'user', 'promotion', 'tutoring_groups', 'url',)
extra_kwargs = {
'url': {'view_name': 'api:tutor-detail'},
}
......@@ -105,7 +106,7 @@ class TutorSerializer(ProfileSerializer,
class StudentSerializer(ProfileSerializer,
serializers.HyperlinkedModelSerializer):
"""Serializer for Student."""
"""Hyperlinked serializer for Student."""
tutoring_group = serializers.HyperlinkedRelatedField(
queryset=TutoringGroup.objects.all(),
......@@ -118,8 +119,8 @@ class StudentSerializer(ProfileSerializer,
class Meta: # noqa
model = Student
fields = ('user_id', 'url', 'user', 'address', 'tutoring_group',
'school',)
fields = ('user_id', 'user', 'address', 'tutoring_group',
'school', 'url')
extra_kwargs = {
'url': {'view_name': 'api:student-detail'},
}
......
......@@ -54,10 +54,7 @@ class TutorViewSet(viewsets.ModelViewSet):
serializer_class = TutorSerializer
class StudentViewSet(ListModelMixin,
RetrieveModelMixin,
CreateModelMixin,
viewsets.GenericViewSet):
class StudentViewSet(viewsets.ModelViewSet):
"""API endpoint that allows students to be viewed or edited.
retrieve:
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment