Skip to content
Snippets Groups Projects
Unverified Commit 54c4c0e8 authored by Seon82's avatar Seon82 Committed by GitHub
Browse files

Inscription sur le site (#21)


* Password reset feature (#8)

* Add Django Rest auth module

* Try to make the send reset password email work

* Modified template mail for reset

* Add Django Rest auth module

* Try to make the send reset password email work

* Modified template mail for reset

* test

* Ajouté API student

* API GET sans authentification

* Added POST support

* POST API fix

* Fixed charfields length in wiki

* loosen security

* simplify API serialized data

* Implemented partial_update

* Added special teaching and nationality to serializer

* dependantsNumber to int

* Fixed factory imports

* Added write auth and minor serializer fix

* Added read permissions

* Read permissions that work?

* Actually added read permissions?

* Updated tests to pass travis

* Updated tests

* Fixed all factory tests

* Adapté les tests à la nouvelle structure de Student

* Created StaffUserFactory and finished fixing tests

* Update README.md

* Added classType

* Fixed migrations

* Added last modified year & filters in admin interface

Co-authored-by: default avatarchiahetcho <44137047+chiahetcho@users.noreply.github.com>
Co-authored-by: default avatarflorimondmanca <florimond.manca@gmail.com>
Co-authored-by: default avatarDylan Sechet <dylan.sechet@student-cs.fr>
Co-authored-by: default avatarArthur Guédon <arthur.guedon@student-cs.fr>
parent 8ddf8629
No related branches found
No related tags found
No related merge requests found
Showing
with 519 additions and 45 deletions
......@@ -50,13 +50,17 @@ Le site utilise une base de données SQL. Plusieurs technologies existent mais o
Après avoir installé PostgreSQL, démarrez le serveur en ouvrant pgAdmin, l'interface graphique qui sera installée en même temps que Postgres.
- Créez une nouvelle base de données :
Dans le menu de gauche, dépliez `Servers (1)`, puis votre serveur (nommé `PostgreSQL XX` par défaut), puis faites un clic droit sur l'onglet `Databases` et créez une base de données nommée `oser_backend_db`.
### Installation du projet
- (Recommandé) Créez un environnement virtuel (ici appelé `env`) puis activez-le :
- (Recommandé) Créez un environnement virtuel (appelé ici oser-back) à l'aide de conda et activez-le :
```bash
$ python -m venv env
$ source env/bin/activate
$ conda create -n oser-back
$ conda activate oser-back
```
- Installez les dépendances :
......@@ -70,6 +74,7 @@ $ pip install -r requirements.txt
```bash
$ python manage.py migrate
```
(En cas d'erreur, les logs du serveur PostgreSQL sont disponibles dans : %PROGRAMFILES%\PostgreSQL\POSTGRESQL_VERSION_NUM\data\log)
Il ne vous reste plus qu'à lancer le serveur de développement :
......
......@@ -26,7 +26,7 @@ router.register('users', users_views.UserViewSet)
# Profiles views
router.register('tutors', profiles_views.TutorViewSet)
router.register('students', profiles_views.StudentViewSet)
router.register('students', profiles_views.StudentViewSet, base_name='student')
# Register views
router.register('registrations', register_views.RegistrationViewSet)
......
......@@ -5,7 +5,7 @@ import factory.django
from . import models
class DocumentFactory(factory.DjangoModelFactory):
class DocumentFactory(factory.django.DjangoModelFactory):
"""Document object factory."""
class Meta: # noqa
......@@ -15,7 +15,7 @@ class DocumentFactory(factory.DjangoModelFactory):
content = factory.Faker('text', max_nb_chars=1000, locale='fr')
class AddressFactory(factory.DjangoModelFactory):
class AddressFactory(factory.django.DjangoModelFactory):
"""Address object factory."""
class Meta: # noqa
......
......@@ -38,7 +38,7 @@ DJANGO_APPS = [
'whitenoise.runserver_nostatic',
'django.contrib.staticfiles',
'django.forms',
'django.contrib.sites',
'django.contrib.sites'
]
THIRD_PARTY_APPS = [
......
......@@ -43,7 +43,7 @@ class TutorAdmin(ProfileAdminMixin, admin.ModelAdmin,ExportCsvMixin):
@admin.register(Student)
class StudentAdmin(ProfileAdminMixin, admin.ModelAdmin,ExportCsvMixin):
"""Student admin panel."""
list_filter = ('school', 'year')
class Meta: # noqa
model = Student
actions = ["export_as_csv"]
\ No newline at end of file
......@@ -12,7 +12,7 @@ from users.factory import UserFactory
from . import models
class StudentFactory(factory.DjangoModelFactory):
class StudentFactory(factory.django.DjangoModelFactory):
"""Student object factory."""
class Meta: # noqa
......@@ -24,7 +24,7 @@ class StudentFactory(factory.DjangoModelFactory):
_this_year = datetime.today().year
class TutorFactory(factory.DjangoModelFactory):
class TutorFactory(factory.django.DjangoModelFactory):
"""Tutor object factory."""
class Meta: # noqa
......
# Generated by Django 2.2 on 2020-09-13 22:57
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('profiles', '0002_auto_20180911_1938'),
]
operations = [
migrations.AddField(
model_name='student',
name='addressNumber',
field=models.IntegerField(blank=True, null=True, verbose_name='numéro de rue'),
),
migrations.AddField(
model_name='student',
name='city',
field=models.CharField(blank=True, max_length=50, null=True, verbose_name='nom de ville'),
),
migrations.AddField(
model_name='student',
name='dependantsNumber',
field=models.CharField(blank=True, max_length=12, null=True, verbose_name="numero d'urgence"),
),
migrations.AddField(
model_name='student',
name='fatherActivity',
field=models.CharField(blank=True, max_length=70, null=True, verbose_name='metier du pere'),
),
migrations.AddField(
model_name='student',
name='gender',
field=models.CharField(blank=True, max_length=20, null=True, verbose_name='genre'),
),
migrations.AddField(
model_name='student',
name='grade',
field=models.CharField(blank=True, max_length=20, null=True, verbose_name='nom du niveau de la classe'),
),
migrations.AddField(
model_name='student',
name='motherActivity',
field=models.CharField(blank=True, max_length=70, null=True, verbose_name='metier de la mere'),
),
migrations.AddField(
model_name='student',
name='parentsEmail',
field=models.EmailField(blank=True, max_length=20, null=True, verbose_name='adresse mail parentale'),
),
migrations.AddField(
model_name='student',
name='parentsPhone',
field=models.CharField(blank=True, max_length=12, null=True, verbose_name='numéro de téléphone parental'),
),
migrations.AddField(
model_name='student',
name='parentsStatus',
field=models.CharField(blank=True, max_length=30, null=True, verbose_name='statut des parents'),
),
migrations.AddField(
model_name='student',
name='personnalPhone',
field=models.CharField(blank=True, max_length=12, null=True, verbose_name='numéro de téléphone personnel'),
),
migrations.AddField(
model_name='student',
name='scholarship',
field=models.BooleanField(blank=True, null=True, verbose_name='boursier'),
),
migrations.AddField(
model_name='student',
name='school',
field=models.CharField(blank=True, max_length=70, null=True, verbose_name="nom de l'ecole"),
),
migrations.AddField(
model_name='student',
name='street',
field=models.CharField(blank=True, max_length=70, null=True, verbose_name='nom de rue'),
),
migrations.AlterField(
model_name='tutor',
name='promotion',
field=models.IntegerField(choices=[(2023, '2023'), (2022, '2022'), (2021, '2021'), (2020, '2020'), (2019, '2019')], default=2023),
),
]
# Generated by Django 2.2 on 2020-09-15 16:27
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('profiles', '0003_auto_20200914_0057'),
]
operations = [
migrations.AlterField(
model_name='student',
name='dependantsNumber',
field=models.CharField(blank=True, max_length=12, null=True, verbose_name="numéro d'urgence"),
),
migrations.AlterField(
model_name='student',
name='fatherActivity',
field=models.CharField(blank=True, max_length=70, null=True, verbose_name='métier du père'),
),
migrations.AlterField(
model_name='student',
name='grade',
field=models.CharField(blank=True, max_length=20, null=True, verbose_name='niveau de la classe'),
),
migrations.AlterField(
model_name='student',
name='motherActivity',
field=models.CharField(blank=True, max_length=70, null=True, verbose_name='métier de la mère'),
),
migrations.AlterField(
model_name='student',
name='scholarship',
field=models.NullBooleanField(verbose_name='boursier'),
),
migrations.AlterField(
model_name='student',
name='school',
field=models.CharField(blank=True, max_length=70, null=True, verbose_name="nom de l'école"),
),
]
# Generated by Django 2.2 on 2020-09-18 11:20
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('profiles', '0003_auto_20200914_0057'),
]
operations = [
migrations.AlterField(
model_name='student',
name='dependantsNumber',
field=models.CharField(blank=True, max_length=12, null=True, verbose_name="numéro d'urgence"),
),
migrations.AlterField(
model_name='student',
name='fatherActivity',
field=models.CharField(blank=True, max_length=70, null=True, verbose_name='métier du père'),
),
migrations.AlterField(
model_name='student',
name='grade',
field=models.CharField(blank=True, max_length=20, null=True, verbose_name='niveau de la classe'),
),
migrations.AlterField(
model_name='student',
name='motherActivity',
field=models.CharField(blank=True, max_length=70, null=True, verbose_name='métier de la mère'),
),
migrations.AlterField(
model_name='student',
name='scholarship',
field=models.NullBooleanField(verbose_name='boursier'),
),
migrations.AlterField(
model_name='student',
name='school',
field=models.CharField(blank=True, max_length=70, null=True, verbose_name="nom de l'école"),
),
]
# Generated by Django 2.2 on 2020-09-18 16:05
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('profiles', '0004_auto_20200918_1320'),
]
operations = [
migrations.AlterField(
model_name='student',
name='scholarship',
field=models.CharField(blank=True, max_length=10, null=True, verbose_name='boursier'),
),
]
# Generated by Django 2.2 on 2020-09-18 16:18
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('profiles', '0005_auto_20200918_1805'),
]
operations = [
migrations.AddField(
model_name='student',
name='nationality',
field=models.CharField(blank=True, max_length=30, null=True, verbose_name='nationalité'),
),
migrations.AddField(
model_name='student',
name='specialTeaching',
field=models.CharField(blank=True, max_length=30, null=True, verbose_name='enseignement de spécialité'),
),
migrations.AddField(
model_name='student',
name='zipCode',
field=models.CharField(blank=True, max_length=10, null=True, verbose_name='code postal'),
),
]
# Generated by Django 2.2 on 2020-09-18 16:24
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('profiles', '0006_auto_20200918_1818'),
('profiles', '0004_auto_20200915_1827'),
]
operations = [
]
# Generated by Django 2.2 on 2020-09-18 17:13
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('profiles', '0007_merge_20200918_1824'),
]
operations = [
migrations.AlterField(
model_name='student',
name='scholarship',
field=models.CharField(blank=True, max_length=10, null=True, verbose_name='boursier'),
),
]
# Generated by Django 2.2 on 2020-09-23 11:29
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('profiles', '0008_auto_20200918_1913'),
]
operations = [
migrations.AlterField(
model_name='student',
name='dependantsNumber',
field=models.IntegerField(blank=True, null=True, verbose_name='nombre de personnes à charge'),
),
migrations.AlterField(
model_name='student',
name='nationality',
field=models.CharField(blank=True, max_length=50, null=True, verbose_name='nationalité'),
),
migrations.AlterField(
model_name='student',
name='parentsEmail',
field=models.EmailField(blank=True, max_length=70, null=True, verbose_name='adresse mail parentale'),
),
migrations.AlterField(
model_name='student',
name='parentsStatus',
field=models.CharField(blank=True, max_length=70, null=True, verbose_name='statut des parents'),
),
migrations.AlterField(
model_name='student',
name='scholarship',
field=models.CharField(blank=True, max_length=50, null=True, verbose_name='boursier'),
),
migrations.AlterField(
model_name='student',
name='specialTeaching',
field=models.CharField(blank=True, max_length=50, null=True, verbose_name='enseignement de spécialité'),
),
]
# Generated by Django 2.2 on 2020-09-23 12:44
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('profiles', '0009_auto_20200923_1329'),
]
operations = [
migrations.RenameField(
model_name='student',
old_name='personnalPhone',
new_name='personalPhone',
),
]
# Generated by Django 2.2 on 2020-09-24 16:56
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('profiles', '0010_auto_20200923_1444'),
]
operations = [
migrations.AddField(
model_name='student',
name='classType',
field=models.CharField(blank=True, max_length=50, null=True, verbose_name='général/techno'),
),
]
# Generated by Django 2.2 on 2020-09-25 12:14
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('profiles', '0011_student_classtype'),
]
operations = [
migrations.AddField(
model_name='student',
name='year',
field=models.CharField(blank=True, max_length=10, null=True, verbose_name='année'),
),
]
......@@ -4,7 +4,7 @@ from django.db import models
from django.shortcuts import reverse
from dry_rest_permissions.generics import authenticated_users
from .utils import get_promotion_range
from datetime import datetime
class ProfileMixin:
"""Mixin with common functionnality for profiles."""
......@@ -52,6 +52,144 @@ class Student(ProfileMixin, models.Model):
related_name='student',
)
classType = models.CharField(max_length=50,
null=True,
blank=True,
verbose_name="général/techno",
)
nationality = models.CharField(max_length=50,
null=True,
blank=True,
verbose_name="nationalité",
)
specialTeaching = models.CharField(max_length=50,
null=True,
blank=True,
verbose_name="enseignement de spécialité",
)
zipCode = models.CharField(max_length=10,
null=True,
blank=True,
verbose_name="code postal",
)
gender = models.CharField(max_length=20,
null=True,
blank=True,
verbose_name="genre",
)
addressNumber = models.IntegerField(
null=True,
blank=True,
verbose_name="numéro de rue"
)
street = models.CharField(max_length=70,
null=True,
blank=True,
verbose_name="nom de rue"
)
city = models.CharField(max_length=50,
null=True,
blank=True,
verbose_name="nom de ville"
)
personalPhone = models.CharField(max_length=12,
null=True,
blank=True,
verbose_name="numéro de téléphone personnel"
)
parentsPhone = models.CharField(max_length=12,
null=True,
blank=True,
verbose_name="numéro de téléphone parental"
)
parentsEmail = models.EmailField(max_length=70,
null=True,
blank=True,
verbose_name="adresse mail parentale"
)
school = models.CharField(max_length=70,
null=True,
blank=True,
verbose_name="établissement"
)
grade = models.CharField(max_length=20,
null=True,
blank=True,
verbose_name="niveau de la classe"
)
scholarship = models.CharField(max_length=50,
null=True,
blank=True,
verbose_name="boursier"
)
fatherActivity = models.CharField(max_length=70,
null=True,
blank=True,
verbose_name="métier du père"
)
motherActivity = models.CharField(max_length=70,
null=True,
blank=True,
verbose_name="métier de la mère"
)
parentsStatus = models.CharField(max_length=70,
null=True,
blank=True,
verbose_name="statut des parents"
)
dependantsNumber = models.IntegerField(
null=True,
blank=True,
verbose_name="nombre de personnes à charge"
)
year = models.CharField(max_length=10,
null=True,
blank=True,
verbose_name="année"
)
@staticmethod
def has_write_permission(request):
return True
def has_object_write_permission(self, request):
return request.user == self.user
def save(self, *args, **kwargs):
"""Updates the year field based on the last modified date"""
date_now = datetime.now()
if date_now.month>=9:
self.year = f"{date_now.year}/{date_now.year+1}"
else:
self.year = f"{date_now.year-1}/{date_now.year}"
return super(Student,self).save(*args, **kwargs)
class Meta: # noqa
verbose_name = 'lycéen'
......
......@@ -31,11 +31,11 @@ class StudentSerializer(serializers.HyperlinkedModelSerializer):
read_only=True)
registration = StudentRegistrationSerializer()
class Meta: # noqa
model = Student
fields = (
'user_id', 'user', 'registration', 'visits', 'url',
)
'user_id', 'user', 'url', 'registration', 'visits', 'gender', 'addressNumber', 'street', 'city', 'personalPhone', 'parentsPhone', 'parentsEmail', 'school', 'grade', 'scholarship', 'fatherActivity', 'motherActivity', 'parentsStatus', 'dependantsNumber', 'specialTeaching', 'nationality', 'zipCode', 'classType')
extra_kwargs = {
'url': {'view_name': 'api:student-detail'},
}
......@@ -5,6 +5,7 @@ from dry_rest_permissions.generics import DRYPermissions
from rest_framework import viewsets
from rest_framework.decorators import action
from rest_framework.response import Response
from django_filters.rest_framework import DjangoFilterBackend
from visits.serializers import VisitSerializer
......@@ -23,40 +24,21 @@ class TutorViewSet(viewsets.ReadOnlyModelViewSet):
permission_classes = (DRYPermissions,)
class StudentViewSet(viewsets.ReadOnlyModelViewSet):
"""API endpoint that allows students to be viewed.
class StudentViewSet(viewsets.ModelViewSet):
"""API endpoint that allows students to be viewed, and profiles to be updated."""
list:
def get_serializer(self, *args, **kwargs):
kwargs['partial'] = True
return super(StudentViewSet, self).get_serializer(*args, **kwargs)
### Example response
def get_queryset(self):
user = self.request.user
if user.is_staff:
return Student.objects.all()
else:
return Student.objects.filter(user_id = user.id)
List of results from `retrieve` (see the example response for `retrieve`).
retrieve:
### Example response
{
"user_id": 4,
"user": {
"id": 4,
"email": "charles.dumont@example.net",
"profile_type": null,
"first_name": "",
"last_name": "",
"url": "http://localhost:8000/api/users/4/"
},
"registration": {
"id": 3,
"submitted": "2018-05-05T14:15:10.998206+02:00",
"validated": false
},
"visits": [],
"url": "http://localhost:8000/api/students/2/"
}
"""
queryset = Student.objects.all()
serializer_class = StudentSerializer
permission_classes = (DRYPermissions,)
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment