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

add basic student registration data: model, api and tests

parent e79c89ad
No related branches found
No related tags found
No related merge requests found
Showing
with 305 additions and 9 deletions
......@@ -3,11 +3,12 @@ from django.conf.urls import url
from rest_framework import routers
from api.auth import obtain_auth_token
from core import views as core_views
from register import views as register_views
from showcase_site import views as showcase_site_views
from tutoring import views as tutoring_views
from users import views as users_views
from visits import views as visits_views
from core import views as core_views
app_name = 'api'
......@@ -29,7 +30,6 @@ router.register('places', visits_views.PlaceViewSet)
router.register('users', users_views.UserViewSet)
router.register('tutors', users_views.TutorViewSet)
router.register('students', users_views.StudentViewSet)
# router.register('student-visits', users_views.StudentVisitsViewSet)
router.register('schoolstaffmembers', users_views.SchoolStaffMemberViewSet)
# Tutoring views
......@@ -39,6 +39,9 @@ router.register('tutoring/groups', tutoring_views.TutoringGroupViewSet,
router.register('tutoring/sessions', tutoring_views.TutoringSessionViewSet,
base_name='tutoring_session')
# Register views
router.register('registrations', register_views.RegistrationViewSet)
# Showcase site views
router.register('articles', showcase_site_views.ArticleViewSet)
router.register('categories', showcase_site_views.CategoryViewSet)
......
......@@ -66,6 +66,7 @@ PROJECT_APPS = [
'api.apps.ApiConfig',
'showcase_site.apps.ShowcaseSiteConfig',
'visits.apps.VisitsConfig',
'register.apps.RegisterConfig',
]
INSTALLED_APPS = DJANGO_APPS + THIRD_PARTY_APPS + PROJECT_APPS
......
"""Register admin panels."""
from django.contrib import admin
from .models import Registration
# Register your models here.
@admin.register(Registration)
class RegistrationAdmin(admin.ModelAdmin):
"""Admin panel for registrations."""
list_display = ('id', 'first_name', 'last_name', 'submitted')
readonly_fields = ('submitted',)
list_filter = ('submitted',)
from django.apps import AppConfig
class RegisterConfig(AppConfig):
name = 'register'
verbose_name = 'Inscriptions administratives'
"""Register factories."""
import factory
import factory.django
from utils import printable_only
from . import models
class RegistrationFactory(factory.DjangoModelFactory):
"""Registration object factory."""
class Meta: # noqa
model = models.Registration
first_name = factory.Faker('first_name', locale='fr')
last_name = factory.Faker('last_name', locale='fr')
@factory.lazy_attribute
def email(self):
"""Generate email for registration."""
return '{}.{}@example.net'.format(
printable_only(self.first_name.lower()),
printable_only(self.last_name.lower()))
phone = factory.Faker('phone_number')
date_of_birth = factory.Faker('past_date', start_date='-20y')
# Generated by Django 2.0.3 on 2018-04-07 21:04
from django.db import migrations, models
class Migration(migrations.Migration):
initial = True
dependencies = [
]
operations = [
migrations.CreateModel(
name='Registration',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('first_name', models.CharField(max_length=50, verbose_name='prénom')),
('last_name', models.CharField(max_length=50, verbose_name='nom')),
('email', models.EmailField(max_length=254, verbose_name='adresse email')),
('phone', models.CharField(blank=True, max_length=15, null=True, verbose_name='téléphone')),
('date_of_birth', models.DateField(null=True, verbose_name='date de naissance')),
('submitted', models.DateTimeField(auto_now_add=True, verbose_name='envoyé le')),
],
options={
'ordering': ('-submitted',),
},
),
]
# Generated by Django 2.0.3 on 2018-04-07 21:14
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('register', '0001_initial'),
]
operations = [
migrations.AlterModelOptions(
name='registration',
options={'ordering': ('-submitted',), 'verbose_name': 'inscription administrative', 'verbose_name_plural': 'inscriptions administratives'},
),
]
# Generated by Django 2.0.3 on 2018-04-07 21:42
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('register', '0002_auto_20180407_2314'),
]
operations = [
migrations.AlterField(
model_name='registration',
name='phone',
field=models.CharField(blank=True, max_length=30, null=True, verbose_name='téléphone'),
),
]
"""Register models."""
from django.db import models
from dry_rest_permissions.generics import authenticated_users
# Create your models here.
class Registration(models.Model):
"""Represents a student registration to tutoring activities."""
# NOTE: this model is bound to evolve as the registration data
# expands.
first_name = models.CharField(max_length=50,
verbose_name='prénom')
last_name = models.CharField(max_length=50, verbose_name='nom')
email = models.EmailField(verbose_name='adresse email')
phone = models.CharField(max_length=30,
blank=True, null=True,
verbose_name='téléphone')
date_of_birth = models.DateField(blank=False, null=True,
verbose_name='date de naissance')
submitted = models.DateTimeField(auto_now_add=True,
verbose_name='envoyé le')
class Meta: # noqa
ordering = ('-submitted',)
verbose_name = 'inscription administrative'
verbose_name_plural = 'inscriptions administratives'
@staticmethod
def has_read_permission(request):
return True
def has_object_read_permission(self, request):
return True
@staticmethod
@authenticated_users
def has_create_permission(request):
return True
def __str__(self):
return '{o.first_name} {o.last_name} ({o.submitted})'.format(o=self)
"""Register serializers."""
from rest_framework import serializers
from .models import Registration
class RegistrationSerializer(serializers.ModelSerializer):
"""Serializer for documents."""
class Meta: # noqa
model = Registration
fields = ('id', 'first_name', 'last_name', 'email', 'phone',
'date_of_birth', 'submitted',)
extra_kwargs = {
'submitted': {'read_only': True},
}
"""Register views."""
from dry_rest_permissions.generics import DRYPermissions
from rest_framework import mixins, viewsets
from .models import Registration
from .serializers import RegistrationSerializer
# Create your views here.
class RegistrationViewSet(
mixins.CreateModelMixin,
mixins.ListModelMixin,
viewsets.GenericViewSet):
"""API endpoints to create and list registrations."""
queryset = Registration.objects.all()
serializer_class = RegistrationSerializer
permission_classes = (DRYPermissions,)
File moved
"""Category API tests."""
from rest_framework import status
from register.factory import RegistrationFactory
from register.serializers import RegistrationSerializer
from tests.utils import SimpleAPITestCase
class RegistrationEndpointsTest(SimpleAPITestCase):
"""Test access to the registrations endpoints."""
factory = RegistrationFactory
serializer_class = RegistrationSerializer
list_url = '/api/registrations/'
create_url = '/api/registrations/'
def serialize(self, obj):
serializer = self.serializer_class(obj)
return serializer.data
def perform_list(self):
response = self.client.get(self.list_url)
return response
def test_list_no_authentication_required(self):
self.assertRequestResponse(
self.perform_list,
user=None,
expected_status_code=status.HTTP_200_OK)
def perform_create(self):
obj = self.factory.build()
data = self.serialize(obj)
data.pop('submitted') # read-only
response = self.client.post(self.create_url, data, format='json')
return response
def test_list_no_authentication_required(self):
self.assertRequestResponse(
self.perform_list,
user=None,
expected_status_code=status.HTTP_200_OK)
def test_create_requires_authentication(self):
self.assertRequiresAuth(
self.perform_create,
expected_status_code=status.HTTP_201_CREATED)
"""Registration model tests."""
from register.models import Registration
from register.factory import RegistrationFactory
from tests.utils import ModelTestCase
class RegistrationTest(ModelTestCase):
"""Test the Registration model."""
model = Registration
field_tests = {
'first_name': {
'max_length': 50,
'verbose_name': 'prénom',
},
'last_name': {
'max_length': 50,
'verbose_name': 'nom',
},
'date_of_birth': {
'blank': False,
'verbose_name': 'date de naissance',
},
'phone': {
'max_length': 30,
'blank': True,
'null': True,
'verbose_name': 'téléphone',
},
'email': {
'verbose_name': 'adresse email',
},
'submitted': {
'verbose_name': 'envoyé le',
'auto_now_add': True,
}
}
model_tests = {
'ordering': ('-submitted',),
'verbose_name': 'inscription administrative',
'verbose_name_plural': 'inscriptions administratives',
}
@classmethod
def setUpTestData(cls):
cls.obj = RegistrationFactory.create()
"""Users factories."""
from string import printable
import random
import factory
import factory.django
from django.contrib.auth import get_user_model
......@@ -10,6 +9,7 @@ from django.contrib.auth.models import Group
from tutoring.factory import SchoolFactory, TutoringGroupFactory
from tutoring.models import TutoringGroup
from utils import printable_only
from . import models
from .permissions import Groups
......@@ -35,11 +35,6 @@ class UserFactory(factory.DjangoModelFactory):
@factory.lazy_attribute
def email(self):
"""Generate email for user."""
# email can only contain printable characters,
# i.e. not "ç", no "é", ...
def printable_only(s):
return ''.join(c for c in filter(lambda x: x in printable, s))
return '{}.{}-{}@example.net'.format(
printable_only(self.first_name.lower()),
printable_only(self.last_name.lower()),
......
"""Various utilities."""
from string import printable
from django.contrib.auth.models import Group
......@@ -48,3 +49,8 @@ def is_in_group(user, group_name):
def group_exists(group_name):
"""Return True if group exists."""
return Group.objects.filter(name=group_name).exists()
def printable_only(s):
"""Remove non-printable characters from a string."""
return ''.join(c for c in filter(lambda x: x in printable, s))
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment