diff --git a/Palto/Palto/api/v1/tests.py b/Palto/Palto/api/v1/tests.py index f776bb2..6e500a3 100644 --- a/Palto/Palto/api/v1/tests.py +++ b/Palto/Palto/api/v1/tests.py @@ -4,22 +4,64 @@ Tests for the Palto project's API v1. Everything to test the API v1 is described here. """ -from django import test +from rest_framework import status +from rest_framework import test -from Palto.Palto import models, factories +from Palto.Palto import factories -class UserTestCase(test.TestCase): - @staticmethod - def fake_factory(): - """ - Test the creation of fake users - """ - - for _ in range(100): - factories.FakeUserFactory() +class TokenJwtTestCase(test.APITestCase): + """ + Test the JWT token creation + """ -class DepartmentTestCase(test.TestCase): - def creation(self): - pass +class UserApiTestCase(test.APITestCase): + def setUp(self): + self.user_admin = factories.FakeUserFactory(is_superuser=True) + self.user_anonymous = factories.FakeUserFactory() + + def test_permission_admin(self): + """ Test the permissions of the object for an admin """ + + self.client.force_login(self.user_admin) + + # check for a get request + response = self.client.get("/api/v1/users/") + self.assertEqual(response.status_code, status.HTTP_200_OK) + + # check for a post request + response = self.client.post("/api/v1/users/") + self.assertEqual(response.status_code, status.HTTP_200_OK) + + +class DepartmentApiTestCase(test.APITestCase): + pass + + +class StudentGroupApiTestCase(test.APITestCase): + pass + + +class TeachingUnitApiTestCase(test.APITestCase): + pass + + +class StudentCardApiTestCase(test.APITestCase): + pass + + +class TeachingSessionApiTestCase(test.APITestCase): + pass + + +class AttendanceApiTestCase(test.APITestCase): + pass + + +class AbsenceApiTestCase(test.APITestCase): + pass + + +class AbsenceAttachmentApiTestCase(test.APITestCase): + pass diff --git a/Palto/Palto/api/v1/views.py b/Palto/Palto/api/v1/views.py index 1efdcc0..237a0ec 100644 --- a/Palto/Palto/api/v1/views.py +++ b/Palto/Palto/api/v1/views.py @@ -14,53 +14,53 @@ from ... import models class UserViewSet(viewsets.ModelViewSet): serializer_class = serializers.UserSerializer - queryset = models.User.objects.all() + queryset = models.User.objects.all().order_by("pk") permission_classes = [IsAuthenticated, permissions.UserPermission] class DepartmentViewSet(UserViewSet): serializer_class = serializers.DepartmentSerializer - queryset = models.Department.objects.all() + queryset = models.Department.objects.all().order_by("pk") permission_classes = [permissions.DepartmentPermission] class StudentGroupViewSet(UserViewSet): serializer_class = serializers.StudentGroupSerializer - queryset = models.StudentGroup.objects.all() + queryset = models.StudentGroup.objects.all().order_by("pk") permission_classes = [IsAuthenticated, permissions.StudentGroupPermission] class TeachingUnitViewSet(UserViewSet): serializer_class = serializers.TeachingUnitSerializer - queryset = models.TeachingUnit.objects.all() + queryset = models.TeachingUnit.objects.all().order_by("pk") permission_classes = [IsAuthenticated, permissions.TeachingUnitPermission] class StudentCardViewSet(UserViewSet): serializer_class = serializers.StudentCardSerializer - queryset = models.StudentCard.objects.all() + queryset = models.StudentCard.objects.all().order_by("pk") permission_classes = [IsAuthenticated, permissions.StudentCardPermission] class TeachingSessionViewSet(UserViewSet): serializer_class = serializers.TeachingSessionSerializer - queryset = models.TeachingSession.objects.all() + queryset = models.TeachingSession.objects.all().order_by("pk") permission_classes = [IsAuthenticated, permissions.TeachingSessionPermission] class AttendanceViewSet(UserViewSet): serializer_class = serializers.AttendanceSerializer - queryset = models.Attendance.objects.all() + queryset = models.Attendance.objects.all().order_by("pk") permission_classes = [IsAuthenticated, permissions.AttendancePermission] class AbsenceViewSet(UserViewSet): serializer_class = serializers.AbsenceSerializer - queryset = models.Absence.objects.all() + queryset = models.Absence.objects.all().order_by("pk") permission_classes = [IsAuthenticated, permissions.AbsencePermission] class AbsenceAttachmentViewSet(UserViewSet): serializer_class = serializers.AbsenceAttachmentSerializer - queryset = models.AbsenceAttachment.objects.all() + queryset = models.AbsenceAttachment.objects.all().order_by("pk") permission_classes = [IsAuthenticated, permissions.AbsenceAttachmentPermission] diff --git a/Palto/Palto/factories.py b/Palto/Palto/factories.py index 1d843f6..54def7a 100644 --- a/Palto/Palto/factories.py +++ b/Palto/Palto/factories.py @@ -4,134 +4,198 @@ Factories for the Palto project. Factories are class that allow for the automatic creation of instances of our models, primarily for testing purpose. """ import random +from datetime import datetime, timedelta import factory +import faker +from django.utils import timezone from Palto.Palto import models -# TODO(Raphaël): Voir pour la cohérence +fake = faker.Faker() class FakeUserFactory(factory.django.DjangoModelFactory): class Meta: model = models.User - username = factory.Faker("user_name") - first_name = factory.Faker("first_name") - last_name = factory.Faker("last_name") - email = factory.Faker("email") + username: str = factory.Sequence(lambda obj: f"{fake.user_name()}{random.randint(1000, 9999)}") + first_name: str = factory.Faker("first_name") + last_name: str = factory.Faker("last_name") + email: str = factory.Faker("email") class FakeDepartmentFactory(factory.django.DjangoModelFactory): class Meta: model = models.Department - name = factory.Faker("company") - email = factory.Faker("company_email") + name: str = factory.Faker("company") + email: str = factory.Faker("company_email") - managers = factory.RelatedFactoryList( - FakeUserFactory, - "managing_departments", - size=lambda: random.randint(1, 3) - ) - teachers = factory.RelatedFactoryList( - FakeUserFactory, - "teaching_departments", - size=lambda: random.randint(1, 50) - ) - students = factory.RelatedFactoryList( - FakeUserFactory, - "studying_departments", - size=lambda: random.randint(1, 500) - ) + @factory.post_generation + def managers(self, create, extracted, **kwargs): + if not create: + return + + if extracted is not None: + self.managers.add(*extracted) + else: + self.managers.add(*[FakeUserFactory() for _ in range(random.randint(1, 3))]) + + @factory.post_generation + def teachers(self, create, extracted, **kwargs): + if not create: + return + + if extracted is not None: + self.teachers.add(*extracted) + else: + self.teachers.add(*[FakeUserFactory() for _ in range(random.randint(2, 10))]) + + @factory.post_generation + def students(self, create, extracted, **kwargs): + if not create: + return + + if extracted is not None: + self.students.add(*extracted) + else: + self.students.add(*[FakeUserFactory() for _ in range(random.randint(50, 150))]) class FakeStudentGroupFactory(factory.django.DjangoModelFactory): class Meta: model = models.StudentGroup - name = factory.Faker("administrative_unit") + name: str = factory.Faker("administrative_unit") - owner = factory.SubFactory(FakeUserFactory) - department = factory.SubFactory(FakeDepartmentFactory) - students = factory.RelatedFactoryList(FakeUserFactory, "student_groups", size=lambda: random.randint(0, 32)) + owner: models.User = factory.SubFactory(FakeUserFactory) + department: models.Department = factory.SubFactory(FakeDepartmentFactory) + + @factory.post_generation + def students(self, create, extracted, **kwargs): + if not create: + return + + if extracted is not None: + self.students.add(*extracted) + else: + # create a group of between 5 and 50 students from this department + self.students.add(*self.department.students.order_by('?')[:random.randint(5, 50)]) class FakeTeachingUnitFactory(factory.django.DjangoModelFactory): class Meta: model = models.TeachingUnit - name = factory.Faker("administrative_unit") + name: str = factory.Faker("administrative_unit") - department = factory.SubFactory( + department: models.Department = factory.SubFactory( FakeDepartmentFactory ) - managers = factory.RelatedFactoryList( - FakeUserFactory, - "managing_units", - size=lambda: random.randint(1, 3) - ) - teachers = factory.RelatedFactoryList( - FakeUserFactory, - "teaching_units", - size=lambda: random.randint(1, 5) - ) - student_groups = factory.RelatedFactoryList( - FakeStudentGroupFactory, - "studying_units", - size=lambda: random.randint(1, 3) - ) + + @factory.post_generation + def managers(self, create, extracted, **kwargs): + if not create: + return + + if extracted is not None: + self.managers.add(*extracted) + else: + # create a group of between 1 and 2 managers from the teacher's department + self.managers.add(*self.department.teachers.order_by('?')[:random.randint(1, 2)]) + + @factory.post_generation + def teachers(self, create, extracted, **kwargs): + if not create: + return + + if extracted is not None: + self.teachers.add(*extracted) + else: + # create a group of between 2 and 10 teachers from the teacher's department + self.teachers.add(*self.department.teachers.order_by('?')[:random.randint(2, 10)]) + + @factory.post_generation + def student_groups(self, create, extracted, **kwargs): + if not create: + return + + if extracted is not None: + self.student_groups.add(*extracted) + else: + # create a group of between 1 and 2 student groups from the department + self.student_groups.add(*[ + FakeStudentGroupFactory.create(department=self.department) + for _ in range(random.randint(1, 2)) + ]) class FakeStudentCardFactory(factory.django.DjangoModelFactory): class Meta: model = models.StudentCard - uid = factory.Faker("binary", length=7) + uid: bytes = factory.Faker("binary", length=7) - department = factory.SubFactory(FakeDepartmentFactory) - owner = factory.SubFactory(FakeUserFactory) + department: models.Department = factory.SubFactory(FakeDepartmentFactory) + owner: models.User = factory.SubFactory(FakeUserFactory) class FakeTeachingSessionFactory(factory.django.DjangoModelFactory): class Meta: model = models.TeachingSession - start = factory.Faker("date_time") - duration = factory.Faker("time_delta") - note = factory.Faker("paragraph") + start: timedelta = factory.Faker("date_time", tzinfo=timezone.get_current_timezone()) + duration: timedelta = factory.Faker("time_delta") + note: str = factory.Faker("paragraph") - unit = factory.SubFactory(FakeTeachingUnitFactory) + unit: models.TeachingUnit = factory.SubFactory(FakeTeachingUnitFactory) - group = factory.SubFactory(FakeStudentGroupFactory) - owner = factory.SubFactory(FakeUserFactory) + group: models.StudentGroup = factory.SubFactory(FakeStudentGroupFactory) + teacher: models.User = factory.SubFactory(FakeUserFactory) class FakeAttendanceFactory(factory.django.DjangoModelFactory): class Meta: model = models.Attendance - date = factory.Faker("date_time") + date: datetime = factory.Faker("date_time", tzinfo=timezone.get_current_timezone()) - student = factory.SubFactory(FakeUserFactory) - session = factory.SubFactory(FakeTeachingSessionFactory) + student: models.User = factory.SubFactory(FakeUserFactory) + session: models.TeachingSession = factory.SubFactory(FakeTeachingSessionFactory) class FakeAbsenceFactory(factory.django.DjangoModelFactory): class Meta: model = models.Absence - message = factory.Faker("paragraph") + message: str = factory.Faker("paragraph") - student = factory.SubFactory(FakeUserFactory) - session = factory.SubFactory(FakeTeachingSessionFactory) + student: models.User = factory.SubFactory(FakeUserFactory) + + @factory.post_generation + def sessions(self, create, extracted, **kwargs): + if not create: + return + + if extracted is not None: + self.sessions.add(*extracted) + else: + # all the sessions should be in the same department + department = FakeDepartmentFactory() + + # create a group of between 1 and 8 sessions from the department + self.sessions.add(*[ + FakeTeachingSessionFactory.create(unit__department=department) + for _ in range(random.randint(1, 8)) + ]) class FakeAbsenceAttachmentFactory(factory.django.DjangoModelFactory): class Meta: model = models.AbsenceAttachment - content = factory.django.FileField() + content: str = factory.django.FileField() - absence = factory.SubFactory(FakeAbsenceFactory) + absence: models.Absence = factory.SubFactory(FakeAbsenceFactory) diff --git a/Palto/Palto/models.py b/Palto/Palto/models.py index c115c80..0a126af 100644 --- a/Palto/Palto/models.py +++ b/Palto/Palto/models.py @@ -56,7 +56,7 @@ class Department(models.Model): """ id: uuid.UUID = models.UUIDField(default=uuid.uuid4, primary_key=True, editable=False, max_length=36) - name: str = models.CharField(max_length=64) + name: str = models.CharField(max_length=64, unique=True) email: str = models.EmailField() managers = models.ManyToManyField(to=get_user_model(), blank=True, related_name="managing_departments") @@ -229,14 +229,13 @@ class Absence(models.Model): message: str = models.TextField() student: User = models.ForeignKey(to=get_user_model(), on_delete=models.CASCADE, related_name="absented_sessions") - session: TeachingSession = models.ManyToManyField(to=TeachingSession, blank=True, related_name="absences") + sessions: TeachingSession = models.ManyToManyField(to=TeachingSession, blank=True, related_name="absences") def __repr__(self): return ( f"<{self.__class__.__name__} " f"id={str(self.id)[:8]} " - f"student={self.student.username} " - f"session={str(self.session.id)[:8]}" + f"student={self.student.username}" f">" ) diff --git a/Palto/Palto/tests.py b/Palto/Palto/tests.py index 8f05764..ed27c6f 100644 --- a/Palto/Palto/tests.py +++ b/Palto/Palto/tests.py @@ -4,7 +4,61 @@ Tests for the Palto project. Tests allow to easily check after modifying the logic behind a feature that everything still work as intended. """ -from django.test import TestCase +from django import test + +from Palto.Palto import factories + # Create your tests here. -from .api.v1 import tests +class UserTestCase(test.TestCase): + @staticmethod + def test_creation(): + factories.FakeUserFactory() + + +class DepartmentTestCase(test.TestCase): + @staticmethod + def test_creation(): + factories.FakeDepartmentFactory() + + +class StudentGroupTestCase(test.TestCase): + @staticmethod + def test_creation(): + factories.FakeStudentGroupFactory() + + +class TeachingUnitTestCase(test.TestCase): + @staticmethod + def test_creation(): + factories.FakeTeachingUnitFactory() + + +class StudentCardTestCase(test.TestCase): + @staticmethod + def test_creation(): + factories.FakeStudentCardFactory() + + +class TeachingSessionTestCase(test.TestCase): + @staticmethod + def test_creation(): + factories.FakeTeachingSessionFactory() + + +class AttendanceTestCase(test.TestCase): + @staticmethod + def test_creation(): + factories.FakeAttendanceFactory() + + +class AbsenceTestCase(test.TestCase): + @staticmethod + def test_creation(): + factories.FakeAbsenceFactory() + + +class AbsenceAttachmentTestCase(test.TestCase): + @staticmethod + def test_creation(): + factories.FakeAbsenceAttachmentFactory()