def test_grade_create_max_one_thesis_grade(self, mocked_method):
        self.client.login(username=self.teacher.username, password='******')
        self.data['grade_type'] = SubjectGrade.GradeTypes.THESIS
        self.catalog.wants_thesis = True
        self.catalog.save()

        grade = SubjectGradeFactory(catalog_per_subject=self.catalog,
                                    student=self.catalog.student,
                                    semester=1,
                                    academic_year=2020,
                                    grade_type=SubjectGrade.GradeTypes.THESIS)
        self.data['taken_at'] = date(2019, 11, 10)
        with patch('django.utils.timezone.now',
                   return_value=timezone.datetime(
                       2019, 11, 11).replace(tzinfo=utc)) as mocked_method:
            response = self.client.post(self.build_url(self.catalog.id),
                                        self.data)

        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
        self.assertEqual(
            response.data, {
                'grade_type': [
                    'There can be only one thesis grade per subject per semester.'
                ]
            })

        grade.delete()
        grade = SubjectGradeFactory(catalog_per_subject=self.catalog,
                                    student=self.catalog.student,
                                    semester=2,
                                    academic_year=2020,
                                    grade_type=SubjectGrade.GradeTypes.THESIS)
        self.data['taken_at'] = date(2020, 4, 4)
        with patch('django.utils.timezone.now',
                   return_value=timezone.datetime(
                       2020, 4, 5).replace(tzinfo=utc)) as mocked_method:
            response = self.client.post(self.build_url(self.catalog.id),
                                        self.data)

        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
        self.assertEqual(
            response.data, {
                'grade_type': [
                    'There can be only one thesis grade per subject per semester.'
                ]
            })

        grade.grade_type = SubjectGrade.GradeTypes.REGULAR
        grade.save()
        with patch('django.utils.timezone.now',
                   return_value=timezone.datetime(
                       2020, 4, 5).replace(tzinfo=utc)) as mocked_method:
            response = self.client.post(self.build_url(self.catalog.id),
                                        self.data)
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)
    def test_bulk_create_absence_validate_student(self, timezone_mock):
        self.client.login(username=self.teacher.username, password='******')

        self.request_data['taken_at'] = date(2019, 9, 20)
        self.request_data['student_absences'][0]['student'] = 0

        response = self.client.post(self.build_url(self.study_class.id, self.subject.id), data=self.request_data)
        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
        self.assertEqual(response.data['student_absences'][0]['student'], ['Invalid pk "0" - object does not exist.'])

        # Not student in class
        student1 = UserProfileFactory(user_role=UserProfile.UserRoles.STUDENT, school_unit=self.school_unit)
        # Not enrolled
        student2 = UserProfileFactory(user_role=UserProfile.UserRoles.STUDENT, school_unit=self.school_unit, student_in_class=self.study_class)
        StudentCatalogPerSubjectFactory(student=student2, study_class=self.study_class, teacher=self.teacher, subject=self.subject, is_enrolled=False)
        # Not active
        student3 = UserProfileFactory(user_role=UserProfile.UserRoles.STUDENT, school_unit=self.school_unit,
                                      student_in_class=self.study_class, is_active=False)
        StudentCatalogPerSubjectFactory(student=student3, study_class=self.study_class, teacher=self.teacher, subject=self.subject)

        for student in [student1, student2, student3]:
            self.request_data['student_absences'][0]['student'] = student.id

            response = self.client.post(self.build_url(self.study_class.id, self.subject.id), data=self.request_data)
            self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
            self.assertEqual(response.data['student'], [f'Invalid pk "{student.id}" - object does not exist.'])
    def test_user_profile_update_student_validations(self):
        self.client.login(username=self.principal.username, password='******')
        student = UserProfileFactory(user_role=UserProfile.UserRoles.STUDENT, school_unit=self.school_unit)
        url = self.build_url(student.id)

        self.student_data['educator_full_name'] = 'Educator'
        response = self.client.put(url, self.student_data)
        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
        self.assertEqual(response.data, ({'educator_full_name': [
            'Either email or phone number is required for the educator.'
        ]}))

        self.student_data['educator_email'] = '*****@*****.**'
        response = self.client.put(url, self.student_data)
        self.assertEqual(response.status_code, status.HTTP_200_OK)

        # Invalid personal_id_number
        del self.student_data['educator_full_name']
        del self.student_data['educator_email']
        for bad_data in ['32840', '249124395385039850', '123456789123a']:
            self.student_data['personal_id_number'] = bad_data
            response = self.client.put(url, self.student_data)
            self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
            self.assertEqual(response.data, {'personal_id_number': ['Invalid format. Must be 13 digits, no spaces allowed.']})

        # Birth date must be in the past
        next_year = timezone.now().year + 1
        del self.student_data['personal_id_number']
        self.student_data['birth_date'] = date(next_year, 1, 1)

        response = self.client.put(url, self.student_data)
        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
        self.assertEqual(response.data, {'birth_date': ['Birth date must be in the past.']})
 def setUp(self):
     self.catalog.refresh_from_db()
     self.data = {
         'grade1': 8,
         'grade2': 8,
         'taken_at': date(2020, 8, 21)
     }
 def setUp(self):
     self.administrator.refresh_from_db()
     self.data = {
         'use_phone_as_username': True,
         'email': '*****@*****.**',
         'phone_number': '+40700100200',
         'full_name': 'New Name',
         'email_notifications_enabled': True,
         'sms_notifications_enabled': True,
         'push_notifications_enabled': True,
         'current_password': '******',
         'new_password': '******',
         'user_role': 'ADMINISTRATOR'
     }
     self.parent_data = {
         **self.data,
         'address': 'address',
         'user_role': 'PARENT'
     }
     self.student_data = {
         **self.data,
         'address': 'address',
         'personal_id_number': '1900203044858',
         'birth_date': date(2000, 1, 1),
         'user_role': 'STUDENT'
     }
    def test_examination_grade_update_grade_in_the_future(self, mocked_method):
        self.client.login(username=self.teacher.username, password='******')
        self.data['taken_at'] = date(2020, 8, 23)

        response = self.client.put(self.build_url(self.create_2nd_exam_grade().id), self.data)
        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
        self.assertEqual(response.data, {'taken_at': ["Can't set grade dates in the future."]})
예제 #7
0
    def test_bulk_create_grade_secondary_school_averages(self, timezone_mock):
        # This is for a subject with weekly hours count = 1 and no thesis (1st semester)
        self.client.login(username=self.teacher.username, password='******')
        self.request_data['taken_at'] = date(2019, 9, 20)

        response = self.client.post(self.build_url(self.study_class.id,
                                                   self.subject.id),
                                    data=self.request_data)
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)

        self.refresh_objects_from_db([
            self.catalog1, self.catalog2, self.catalog_per_year1,
            self.catalog_per_year2, self.study_class, self.school_stats
        ])
        for catalog in [self.catalog1, self.catalog_per_year1]:
            self.assertEqual(catalog.avg_sem1, 6)
            self.assertIsNone(catalog.avg_sem2)
            self.assertIsNone(catalog.avg_annual)
            self.assertIsNone(catalog.avg_final)
        for catalog in [self.catalog2, self.catalog_per_year2]:
            self.assertIsNone(catalog.avg_sem1)
            self.assertIsNone(catalog.avg_sem2)
            self.assertIsNone(catalog.avg_annual)
            self.assertIsNone(catalog.avg_final)
        for obj in [self.study_class, self.school_stats]:
            self.assertEqual(obj.avg_sem1, 6)
            self.assertIsNone(obj.avg_sem2)
            self.assertIsNone(obj.avg_annual)
    def test_bulk_create_absence_wrong_semester(self, timezone_mock):
        self.client.login(username=self.teacher.username, password='******')

        self.request_data['taken_at'] = date(2019, 9, 21)

        response = self.client.post(self.build_url(self.study_class.id, self.subject.id), data=self.request_data)
        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
        self.assertEqual(response.data['taken_at'], ['The date cannot be in the first semester.'])
 def setUp(self):
     self.refresh_objects_from_db(
         [self.student, self.catalog, self.catalog_per_year])
     self.data = {
         'grade': 10,
         'grade_type': SubjectGrade.GradeTypes.REGULAR,
         'taken_at': date(2020, 3, 3)
     }
예제 #10
0
    def test_grade_create_grade_in_the_future(self, mocked_method):
        self.client.login(username=self.teacher.username, password='******')
        self.data['taken_at'] = date(2020, 4, 5)
        response = self.client.post(self.build_url(self.catalog.id), self.data)

        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
        self.assertEqual(response.data,
                         {'taken_at': ["Can't set grade date in the future."]})
예제 #11
0
 def setUp(self):
     self.refresh_objects_from_db([self.student, self.catalog])
     self.data = {
         'taken_at': date(2020, 8, 23),
         'grade1': 10,
         'grade2': 9,
         'examination_type': ExaminationGrade.ExaminationTypes.WRITTEN,
         'grade_type': ExaminationGrade.GradeTypes.SECOND_EXAMINATION,
     }
예제 #12
0
    def test_current_academic_year_calendar_update_semester_validation(self):
        self.client.login(username=self.admin.username, password='******')

        other_calendar = AcademicYearCalendarFactory(academic_year=2019)
        self.data['first_semester']['id'] = other_calendar.first_semester.id

        response = self.client.put(self.url, self.data)
        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
        self.assertEqual(response.data, {
            'first_semester':
            ['The semester must belong to the academic year.']
        })

        self.data['first_semester'][
            'id'] = self.academic_year_calendar.first_semester.id
        self.data['first_semester']['starts_at'] = self.data['first_semester'][
            'ends_at']
        response = self.client.put(self.url, self.data)
        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
        self.assertEqual(
            response.data, {
                'first_semester': {
                    'starts_at':
                    ['The start date must be before the end date.']
                }
            })

        self.data['first_semester']['starts_at'] = date(self.next_year, 1, 1)
        self.data['first_semester']['ends_at'] = date(self.next_year, 10, 10)
        self.data['second_semester']['starts_at'] = date(self.next_year, 5, 5)
        self.data['second_semester']['ends_at'] = date(self.next_year, 12, 12)
        response = self.client.put(self.url, self.data)
        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
        self.assertEqual(
            response.data, {
                'second_semester': [
                    'Second semester must start after the end of the first semester.'
                ]
            })

        self.data['first_semester']['starts_at'] = date(self.next_year, 1, 1)
        self.data['first_semester']['ends_at'] = date(self.next_year, 5, 5)
        self.data['second_semester']['starts_at'] = date(self.next_year, 6, 6)
        self.data['second_semester']['ends_at'] = date(self.next_year, 4, 4)
        response = self.client.put(self.url, self.data)
        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
        self.assertEqual(
            response.data, {
                'second_semester': {
                    'starts_at':
                    ['The start date must be before the end date.']
                }
            })
예제 #13
0
    def test_create_absence_future_date(self, timezone_mock):
        self.client.login(username=self.teacher.username, password='******')

        self.request_data['taken_at'] = date(2019, 9, 21)

        response = self.client.post(self.build_url(self.catalog.id),
                                    data=self.request_data)
        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
        self.assertEqual(response.data['taken_at'],
                         ['The date cannot be in the future.'])
예제 #14
0
 def setUp(self):
     self.academic_year_calendar = AcademicYearCalendarFactory(
         first_semester__starts_at=datetime(self.next_year, 1, 10),
         first_semester__ends_at=datetime(self.next_year, 4, 3),
         second_semester__starts_at=datetime(self.next_year, 9, 9),
         second_semester__ends_at=datetime(self.next_year, 12, 11))
     self.data = {
         'first_semester': {
             'id': self.academic_year_calendar.first_semester.id,
             'starts_at': date(self.next_year, 1, 1),
             'ends_at': date(self.next_year, 4, 4),
             'events': []
         },
         'second_semester': {
             'id': self.academic_year_calendar.second_semester.id,
             'starts_at': date(self.next_year, 9, 9),
             'ends_at': date(self.next_year, 12, 12),
             'events': []
         },
         'events': []
     }
예제 #15
0
    def test_bulk_create_grade_second_semester_success(self, timezone_mock):
        self.client.login(username=self.teacher.username, password='******')
        self.request_data['taken_at'] = date(2020, 4, 20)

        response = self.client.post(self.build_url(self.study_class.id,
                                                   self.subject.id),
                                    data=self.request_data)
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)
        self.assertCountEqual(response.data.keys(), ['catalogs'])
        for catalogs in response.data['catalogs']:
            self.assertCountEqual(catalogs.keys(), self.expected_fields)

        self.check_data(2)
예제 #16
0
    def test_grade_create_secondary_school_averages(self, mocked_method):
        # This is for a subject with weekly hours count = 1 and no thesis (1st semester)
        self.client.login(username=self.teacher.username, password='******')
        # Add a few more catalogs per subject for this student
        StudentCatalogPerSubjectFactory(student=self.student,
                                        study_class=self.study_class,
                                        avg_sem1=9)
        StudentCatalogPerSubjectFactory(student=self.student,
                                        study_class=self.study_class,
                                        is_enrolled=False)
        StudentCatalogPerSubjectFactory(student=self.student,
                                        study_class=self.study_class,
                                        is_exempted=True)
        # Add year catalog for a different student
        StudentCatalogPerYearFactory(study_class=self.study_class, avg_sem1=9)

        self.data['taken_at'] = date(2019, 11, 10)

        response = self.client.post(self.build_url(self.catalog.id), self.data)
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)

        # because the student doesn't have enough grades, the average shouldn't be computed yet
        self.catalog.refresh_from_db()
        self.assertIsNone(self.catalog.avg_sem1)
        self.assertIsNone(self.catalog.avg_sem2)
        self.assertIsNone(self.catalog.avg_annual)
        self.assertIsNone(self.catalog.avg_final)

        # Add another grade, so we can compute the average
        self.data['grade'] = 9

        response = self.client.post(self.build_url(self.catalog.id), self.data)
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)

        self.refresh_objects_from_db([
            self.catalog, self.catalog_per_year, self.study_class,
            self.school_stats
        ])
        self.assertEqual(self.catalog.avg_sem1, 10)
        self.assertEqual(self.catalog_per_year.avg_sem1, 9.5)
        for catalog in [self.catalog, self.catalog_per_year]:
            self.assertIsNone(catalog.avg_sem2)
            self.assertIsNone(catalog.avg_annual)
            self.assertIsNone(catalog.avg_final)
        for obj in [self.study_class, self.school_stats]:
            self.assertEqual(obj.avg_sem1, 9.25)
            self.assertIsNone(obj.avg_sem2)
            self.assertIsNone(obj.avg_annual)
예제 #17
0
    def test_examination_grade_create_differences_per_semester_success(
            self, mocked_method):
        self.client.login(username=self.teacher.username, password='******')
        self.data['grade_type'] = ExaminationGrade.GradeTypes.DIFFERENCE
        self.data['taken_at'] = date(2020, 9, 7)

        for examination_type in [
                ExaminationGrade.ExaminationTypes.WRITTEN,
                ExaminationGrade.ExaminationTypes.ORAL
        ]:
            self.data['examination_type'] = examination_type
            for semester in [1, 2]:
                self.data['semester'] = semester
                response = self.client.post(self.build_url(self.catalog.id),
                                            self.data)
                self.assertEqual(response.status_code, status.HTTP_201_CREATED)

        self.assertCountEqual(response.data.keys(), self.expected_fields)
        self.assertEqual(len(response.data['second_examination_grades']), 0)
        self.assertEqual(len(response.data['difference_grades_sem1']), 2)
        self.assertEqual(len(response.data['difference_grades_sem2']), 2)
        for examination_data in response.data[
                'second_examination_grades'] + response.data[
                    'difference_grades_sem1'] + response.data[
                        'difference_grades_sem2']:
            self.assertCountEqual(examination_data.keys(),
                                  self.examination_grade_fields)

        self.refresh_objects_from_db([
            self.catalog, self.catalog_per_year, self.study_class,
            self.study_class.academic_program, self.school_stats, self.teacher,
            self.teacher.school_unit
        ])
        for catalog in [self.catalog, self.catalog_per_year]:
            self.assertEqual(catalog.avg_sem1, 10)
            self.assertEqual(catalog.avg_sem2, 10)
            self.assertEqual(catalog.avg_annual, 10)
            self.assertEqual(catalog.avg_final, 10)
        for obj in [
                self.study_class, self.study_class.academic_program,
                self.school_stats
        ]:
            self.assertEqual(obj.avg_annual, 10)

        self.assertEqual(self.teacher.last_change_in_catalog, timezone.now())
        self.assertEqual(self.teacher.school_unit.last_change_in_catalog,
                         timezone.now())
    def test_examination_grade_update_difference_grade_success(self, mocked_method):
        self.client.login(username=self.teacher.username, password='******')
        self.create_difference_grade()
        grade = self.create_difference_grade(examination_type=ExaminationGrade.ExaminationTypes.ORAL)
        self.data['taken_at'] = date(2020, 9, 3)

        response = self.client.put(self.build_url(grade.id), self.data)
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.check_data(response, grade)

        self.refresh_objects_from_db([self.catalog, self.catalog_per_year, self.study_class, self.study_class.academic_program,
                                      self.school_stats, self.teacher, self.teacher.school_unit])
        for catalog in [self.catalog, self.catalog_per_year]:
            self.assertEqual(catalog.avg_annual, 9)
            self.assertEqual(catalog.avg_final, 9)
        for obj in [self.study_class, self.study_class.academic_program, self.school_stats]:
            self.assertEqual(obj.avg_annual, 9)
예제 #19
0
    def test_examination_grade_create_differences_per_previous_year_success(
            self, mocked_method):
        self.client.login(username=self.teacher.username, password='******')
        study_class = StudyClassFactory(school_unit=self.school_unit,
                                        class_grade='IX',
                                        class_grade_arabic=9,
                                        academic_year=2019)
        catalog = StudentCatalogPerSubjectFactory(subject=self.subject,
                                                  teacher=self.teacher,
                                                  student=self.student,
                                                  study_class=study_class)
        catalog_per_year = StudentCatalogPerYearFactory(
            student=self.student, study_class=study_class)
        school_stats = SchoolUnitStatsFactory(school_unit=self.school_unit,
                                              academic_year=2019)

        self.data['grade_type'] = ExaminationGrade.GradeTypes.DIFFERENCE
        self.data['taken_at'] = date(2020, 9, 7)

        response = self.client.post(self.build_url(catalog.id), self.data)
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)

        self.data['examination_type'] = ExaminationGrade.ExaminationTypes.ORAL
        response = self.client.post(self.build_url(catalog.id), self.data)
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)

        self.assertEqual(len(response.data['second_examination_grades']), 0)
        self.assertEqual(len(response.data['difference_grades_sem1']), 0)
        self.assertEqual(len(response.data['difference_grades_sem2']), 2)

        self.refresh_objects_from_db([
            catalog, catalog_per_year, study_class,
            study_class.academic_program, school_stats, self.teacher,
            self.teacher.school_unit
        ])
        for catalog in [catalog, catalog_per_year]:
            self.assertEqual(catalog.avg_annual, Decimal('9.5'))
            self.assertEqual(catalog.avg_final, Decimal('9.5'))
        for obj in [study_class, study_class.academic_program, school_stats]:
            self.assertEqual(obj.avg_annual, Decimal('9.5'))

        self.assertEqual(self.teacher.last_change_in_catalog, timezone.now())
        self.assertEqual(self.teacher.school_unit.last_change_in_catalog,
                         timezone.now())
예제 #20
0
    def test_create_absence_first_semester_success(self, timezone_mock):
        self.client.login(username=self.teacher.username, password='******')

        self.request_data['taken_at'] = date(2019, 9, 20)

        response = self.client.post(self.build_url(self.catalog.id),
                                    data=self.request_data)
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)
        self.assertCountEqual(response.data.keys(), self.expected_fields)

        absence = SubjectAbsence.objects.first()
        self.assertEqual(absence.catalog_per_subject, self.catalog)
        self.assertEqual(absence.student, self.student)
        self.assertEqual(absence.subject_name, self.subject.name)
        self.assertEqual(absence.semester, 1)
        self.assertTrue(absence.is_founded)

        self.refresh_objects_from_db([
            self.catalog, self.catalog_per_year, self.study_class,
            self.study_class.academic_program, self.teacher, self.school_unit,
            self.school_stats
        ])
        for catalog in [self.catalog, self.catalog_per_year]:
            self.assertEqual(catalog.abs_count_sem1, 1)
            self.assertEqual(catalog.abs_count_sem2, 0)
            self.assertEqual(catalog.abs_count_annual, 1)
            self.assertEqual(catalog.founded_abs_count_sem1, 1)
            self.assertEqual(catalog.founded_abs_count_sem2, 0)
            self.assertEqual(catalog.founded_abs_count_annual, 1)
            self.assertEqual(catalog.unfounded_abs_count_sem1, 0)
            self.assertEqual(catalog.unfounded_abs_count_sem2, 0)
            self.assertEqual(catalog.unfounded_abs_count_annual, 0)
        for obj in [
                self.study_class, self.study_class.academic_program,
                self.school_stats
        ]:
            self.assertEqual(obj.unfounded_abs_avg_sem1, 0)
            self.assertEqual(obj.unfounded_abs_avg_sem2, 0)
            self.assertEqual(obj.unfounded_abs_avg_annual, 0)

        self.assertEqual(self.teacher.last_change_in_catalog, timezone.now())
        self.assertEqual(self.school_unit.last_change_in_catalog,
                         timezone.now())
예제 #21
0
    def test_examination_grade_create_difference_validations(
            self, mocked_method):
        self.client.login(username=self.teacher.username, password='******')
        self.data['grade_type'] = ExaminationGrade.GradeTypes.DIFFERENCE
        self.data['taken_at'] = date(2020, 9, 7)
        diff_grade = ExaminationGradeFactory(
            catalog_per_subject=self.catalog,
            student=self.catalog.student,
            grade_type=ExaminationGrade.GradeTypes.DIFFERENCE,
            semester=1)

        response = self.client.post(self.build_url(self.catalog.id), self.data)
        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
        self.assertEqual(response.data['semester'], [
            "You cannot add difference grades for the whole year because "
            "you have difference grades for a semester in this catalog."
        ])

        diff_grade.semester = None
        diff_grade.save()

        response = self.client.post(self.build_url(self.catalog.id), self.data)
        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
        self.assertEqual(
            response.data['examination_type'],
            ["You already added a grade with this examination type."])

        self.data['semester'] = 1
        response = self.client.post(self.build_url(self.catalog.id), self.data)
        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
        self.assertEqual(response.data['semester'], [
            "You cannot add difference grades for a semester because "
            "you have difference grades for the whole year in this catalog."
        ])

        diff_grade.semester = 1
        diff_grade.save()

        response = self.client.post(self.build_url(self.catalog.id), self.data)
        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
        self.assertEqual(
            response.data['examination_type'],
            ["You already added a grade with this examination type."])
예제 #22
0
    def test_grade_create_highschool_averages(self, mocked_method):
        # This is for a required subject with weekly hours count = 3 and with thesis (2nd semester)
        self.study_class.class_grade = 'IX'
        self.study_class.class_grade_arabic = 9
        self.study_class.save()
        ProgramSubjectThroughFactory(generic_academic_program=self.study_class.
                                     academic_program.generic_academic_program,
                                     subject=self.subject,
                                     weekly_hours_count=3)
        self.catalog.avg_sem1 = 10
        self.catalog.wants_thesis = True
        self.catalog.save()

        for i in range(3):
            SubjectGradeFactory(student=self.student,
                                catalog_per_subject=self.catalog,
                                semester=2,
                                grade=9)

        self.client.login(username=self.teacher.username, password='******')
        self.data['taken_at'] = date(2020, 4, 5)
        self.data['grade_type'] = SubjectGrade.GradeTypes.THESIS

        response = self.client.post(self.build_url(self.catalog.id), self.data)
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)

        self.refresh_objects_from_db([
            self.catalog, self.catalog_per_year, self.study_class,
            self.study_class.academic_program, self.school_stats
        ])
        for catalog in [self.catalog, self.catalog_per_year]:
            self.assertEqual(catalog.avg_sem1, 10)
            self.assertEqual(catalog.avg_sem2, 9)
            self.assertEqual(catalog.avg_annual, 9.5)
            self.assertEqual(catalog.avg_final, 9.5)
        for obj in [
                self.study_class, self.study_class.academic_program,
                self.school_stats
        ]:
            self.assertEqual(obj.avg_sem1, 10)
            self.assertEqual(obj.avg_sem2, 9)
            self.assertEqual(obj.avg_annual, 9.5)
    def test_bulk_create_absence_second_semester_success(self, timezone_mock):
        self.client.login(username=self.teacher.username, password='******')

        self.request_data['taken_at'] = date(2020, 4, 20)
        self.catalog2.is_exempted = True
        self.catalog2.save()

        response = self.client.post(self.build_url(self.study_class.id, self.subject.id), data=self.request_data)
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)
        self.assertCountEqual(response.data.keys(), ['catalogs'])
        for catalogs in response.data['catalogs']:
            self.assertCountEqual(catalogs.keys(), self.expected_fields)
        self.check_data(2)

        self.refresh_objects_from_db([self.catalog1, self.catalog2, self.catalog_per_year1, self.catalog_per_year2,
                                      self.study_class, self.study_class.academic_program, self.school_stats])
        for catalog in [self.catalog1, self.catalog_per_year1]:
            self.assertEqual(catalog.abs_count_sem1, 0)
            self.assertEqual(catalog.abs_count_sem2, 2)
            self.assertEqual(catalog.abs_count_annual, 2)
            self.assertEqual(catalog.founded_abs_count_sem1, 0)
            self.assertEqual(catalog.founded_abs_count_sem2, 2)
            self.assertEqual(catalog.founded_abs_count_annual, 2)
            self.assertEqual(catalog.unfounded_abs_count_sem1, 0)
            self.assertEqual(catalog.unfounded_abs_count_sem2, 0)
            self.assertEqual(catalog.unfounded_abs_count_annual, 0)
        for catalog in [self.catalog2, self.catalog_per_year2]:
            self.assertEqual(catalog.abs_count_sem1, 0)
            self.assertEqual(catalog.abs_count_sem2, 1)
            self.assertEqual(catalog.abs_count_annual, 1)
            self.assertEqual(catalog.founded_abs_count_sem1, 0)
            self.assertEqual(catalog.founded_abs_count_sem2, 0)
            self.assertEqual(catalog.founded_abs_count_annual, 0)
            self.assertEqual(catalog.unfounded_abs_count_sem1, 0)
            self.assertEqual(catalog.unfounded_abs_count_sem2, 1)
            self.assertEqual(catalog.unfounded_abs_count_annual, 1)
        for obj in [self.study_class, self.study_class.academic_program, self.school_stats]:
            self.assertEqual(obj.unfounded_abs_avg_sem1, 0)
            self.assertEqual(obj.unfounded_abs_avg_sem2, 0)
            self.assertEqual(obj.unfounded_abs_avg_annual, 0)
    def setUp(self):
        self.admin_data = {
            'Name': 'John Doe',
            'Email address': '*****@*****.**',
            'Use phone as username': '******',
            'Phone number': '+40712999666',
            'User role': 'Administrator'
        }

        self.principal_data = {
            **self.admin_data,
            'User role': 'School Principal',
            'Phone number': '+40712999667',
        }

        self.teacher_data = {
            **self.admin_data,
            'User role': 'Teacher',
            'Phone number': '+40712999668',
        }

        self.student_data = {
            **self.admin_data,
            'Address': 'address',
            'Personal id number': '1900203099032',
            'Birth date': date(2000, 1, 1),
            'User role': 'Student',
            'Educator name': 'Educator',
            'Educator phone number': '+40712333444',
            'Educator email address': '*****@*****.**',
        }

        self.parent_data = {
            **self.admin_data,
            'Address': 'Address',
            'User role': 'Parent',
            'Phone number': '+40712999669',
        }
예제 #25
0
    def test_grade_update_secondary_school_averages(self, mocked_method):
        # This is for a subject with weekly hours count = 1 and no thesis (1st semester)
        self.client.login(username=self.teacher.username, password='******')
        # Add a few more catalogs per subject for this student
        StudentCatalogPerSubjectFactory(student=self.student,
                                        study_class=self.study_class,
                                        avg_sem1=9)
        StudentCatalogPerSubjectFactory(student=self.student,
                                        study_class=self.study_class,
                                        avg_sem1=10)

        SubjectGradeFactory(student=self.student,
                            catalog_per_subject=self.catalog,
                            semester=1,
                            grade=9)
        grade = self.create_grade(semester=1)
        self.catalog.avg_sem1 = 10
        self.catalog.save()

        self.data['taken_at'] = date(2019, 11, 10)
        response = self.client.put(self.build_url(grade.id), self.data)
        self.assertEqual(response.status_code, status.HTTP_200_OK)

        self.refresh_objects_from_db([
            self.catalog, self.catalog_per_year, self.study_class,
            self.school_stats
        ])
        self.assertEqual(self.catalog.avg_sem1, 9)
        self.assertIsNone(self.catalog.avg_sem2)
        self.assertIsNone(self.catalog.avg_annual)
        self.assertIsNone(self.catalog.avg_final)
        self.assertIsNone(self.catalog_per_year.avg_final)
        for obj in [
                self.catalog_per_year, self.study_class, self.school_stats
        ]:
            self.assertEqual(obj.avg_sem1, Decimal('9.33'))
            self.assertIsNone(obj.avg_sem2)
            self.assertIsNone(obj.avg_annual)
class UserProfileImportTestCase(CommonAPITestCase):
    @classmethod
    def setUpTestData(cls):
        cls.admin = UserProfileFactory(
            user_role=UserProfile.UserRoles.ADMINISTRATOR)
        cls.school_unit = RegisteredSchoolUnitFactory()
        cls.principal = cls.school_unit.school_principal
        cls.principal.school_unit = cls.school_unit
        cls.principal.save()

        cls.url = reverse('users:import-users')
        cls.file_name = 'file.csv'

    def setUp(self):
        self.admin_data = {
            'Name': 'John Doe',
            'Email address': '*****@*****.**',
            'Use phone as username': '******',
            'Phone number': '+40712999666',
            'User role': 'Administrator'
        }

        self.principal_data = {
            **self.admin_data,
            'User role': 'School Principal',
            'Phone number': '+40712999667',
        }

        self.teacher_data = {
            **self.admin_data,
            'User role': 'Teacher',
            'Phone number': '+40712999668',
        }

        self.student_data = {
            **self.admin_data,
            'Address': 'address',
            'Personal id number': '1900203099032',
            'Birth date': date(2000, 1, 1),
            'User role': 'Student',
            'Educator name': 'Educator',
            'Educator phone number': '+40712333444',
            'Educator email address': '*****@*****.**',
        }

        self.parent_data = {
            **self.admin_data,
            'Address': 'Address',
            'User role': 'Parent',
            'Phone number': '+40712999669',
        }

    @staticmethod
    def create_file(file_name):
        file = io.StringIO()
        file.name = file_name
        return file

    def get_response(self, file):
        file.seek(0)
        response = self.client.post(self.url,
                                    data={'file': file},
                                    format='multipart')
        return response

    def test_user_profile_import_unauthenticated(self):
        response = self.client.post(self.url)
        self.assertEqual(response.status_code, status.HTTP_401_UNAUTHORIZED)

    @data(UserProfile.UserRoles.TEACHER, UserProfile.UserRoles.STUDENT,
          UserProfile.UserRoles.PARENT)
    def test_user_profile_import_wrong_user_type(self, user_role):
        school_unit = RegisteredSchoolUnitFactory()
        profile = UserProfileFactory(user_role=user_role,
                                     school_unit=school_unit)
        self.client.login(username=profile.username, password='******')

        response = self.client.post(self.url)
        self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)

    @data('application/json', 'text/html', 'text/csv',
          'application/vnd.ms-excel',
          'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet')
    def test_user_profile_import_wrong_content_type(self, content_type):
        self.client.login(username=self.admin, password='******')
        file = self.create_file(self.file_name)
        file.write('aaa')
        response = self.client.post(self.url,
                                    data={'file': file},
                                    content_type=content_type)
        self.assertEqual(response.status_code,
                         status.HTTP_415_UNSUPPORTED_MEDIA_TYPE)
        self.assertEqual(
            response.data,
            {'detail': f'Unsupported media type "{content_type}" in request.'})

    @data('file.txt', 'file.docx', 'file.csvx')
    def test_user_profile_import_invalid_extension(self, file_name):
        self.client.login(username=self.admin.username, password='******')
        file = self.create_file(file_name)
        file.write('aaa')
        response = self.get_response(file)
        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
        self.assertEqual(response.data, {'file': ['File must be csv.']})

    def test_user_profile_import_invalid_file(self):
        # No file at all
        self.client.login(username=self.admin.username, password='******')
        no_file_sent_error = {'file': ['No file was submitted.']}
        response = self.client.post(self.url, format='multipart')
        self.assertEqual(response.data, no_file_sent_error)

        # Wrong key
        file = self.create_file(self.file_name)
        response = self.client.post(self.url, {'wrong_file': file},
                                    format='multipart')
        self.assertEqual(response.data, no_file_sent_error)

        # Wrong boundary
        request_data = encode_multipart('==boundary', {'file': file})
        content_type = 'multipart/form-data; boundary=WrongBoundary'
        response = self.client.post(self.url,
                                    request_data,
                                    content_type=content_type)
        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
        self.assertEqual(response.data, no_file_sent_error)

    @data('file', 'file.ext.ext', 'file()')
    def test_user_profile_import_invalid_file_name(self, file_name):
        self.client.login(username=self.admin.username, password='******')
        file = self.create_file(file_name)
        file.write('aaa')
        response = self.get_response(file)
        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
        self.assertEqual(response.data,
                         {'non_field_errors': ['Invalid file name.']})

    @data(
        ('admin_data', ['Name', 'Use phone as username']),
        ('principal_data', ['Name', 'Use phone as username']),
        ('teacher_data', ['Name', 'Use phone as username']),
        ('parent_data', ['Name', 'Use phone as username']),
        ('student_data', ['Name', 'Use phone as username']),
    )
    @unpack
    def test_user_profile_import_missing_fields(self, data_dict,
                                                required_fields):
        user = self.admin if data_dict in ['admin_data', 'principal_data'
                                           ] else self.principal
        self.client.login(username=user.username, password='******')
        request_data = getattr(self, data_dict)

        file = self.create_file(self.file_name)
        writer = csv.DictWriter(file, fieldnames=request_data.keys())
        writer.writeheader()
        row = {
            field: request_data[field]
            for field in request_data.keys() if field not in required_fields
        }
        writer.writerow(row)

        response = self.get_response(file)
        self.assertEqual(response.status_code, status.HTTP_200_OK)

        errors = response.data['errors'][1]
        self.assertCountEqual(errors.keys(), required_fields)
        for key, value in errors.items():
            self.assertEqual(value, 'This field is required.')

    @data(
        (UserProfile.UserRoles.ADMINISTRATOR, ['admin_data', 'principal_data'
                                               ]),
        (UserProfile.UserRoles.PRINCIPAL,
         ['teacher_data', 'parent_data', 'student_data']),
    )
    @unpack
    def test_user_profile_import_success(self, user_role, data_dictionaries):
        self.client.login(
            username=UserProfile.objects.get(user_role=user_role).username,
            password='******')
        old_count = UserProfile.objects.count()
        data_dictionaries = [
            getattr(self, data_dict) for data_dict in data_dictionaries
        ]
        keys = set()
        for data_dict in data_dictionaries:
            keys.update(data_dict.keys())

        file = self.create_file(self.file_name)
        writer = csv.DictWriter(file, fieldnames=keys)
        writer.writeheader()
        for data_dict in data_dictionaries:
            writer.writerow(data_dict)

        response = self.get_response(file)
        self.assertEqual(response.status_code, status.HTTP_200_OK)

        self.assertEqual(len(response.data['errors']), 0)
        self.assertEqual(
            response.data['report'],
            f'{len(data_dictionaries)} out of {len(data_dictionaries)} users saved successfully.'
        )
        self.assertEqual(UserProfile.objects.count() - old_count,
                         len(data_dictionaries))

    @data((
        'Email address', ['invalid_email', 'invalid@email'],
        "Invalid format. Must be 150 characters at most and in the format [email protected]"
    ), ('Phone number', [
        'letters', '0000', '++40890092'
    ], "Invalid format. Must be minimum 10, maximum 20 digits or +."), (
        'User role', ['', '1', 'Invalid'],
        'Must be one of the following options: Administrator, Principal, Teacher, Parent or Student.'
    ), ('Educator email address', [
        'invalid_email', 'invalid@email'
    ], "Invalid format. Must be 150 characters at most and in the format [email protected]"
        ), ('Educator phone number', ['letters', '0000', '++40890092'],
            "Invalid format. Must be minimum 10, maximum 20 digits or +."),
          ('Personal id number', ['letters', '0000', '1233444556678889990'],
           'Invalid format. Must be 13 digits, no spaces allowed.'),
          ('Birth date', [date(3000, 1, 1)
                          ], 'Birth date must be in the past.'),
          ('Birth date', ['2000-01-02', '20-20-20000'
                          ], 'Invalid date format. Must be DD-MM-YYYY.'),
          ('Use phone as username', ['true', 'True'
                                     ], 'Must be either yes or no.'))
    @unpack
    def test_user_profile_import_validations(self, field, invalid_data,
                                             expected_error):
        self.client.login(username=self.principal.username, password='******')

        row = self.student_data
        for invalid_attr in invalid_data:
            row[field] = invalid_attr

            file = self.create_file(self.file_name)
            writer = csv.DictWriter(file, fieldnames=self.student_data.keys())
            writer.writeheader()
            writer.writerow(row)

            response = self.get_response(file)
            self.assertEqual(response.status_code, status.HTTP_200_OK)

            errors = response.data['errors'][1]
            self.assertEqual(len(errors), 1)
            self.assertEqual(response.data['report'],
                             '0 out of 1 user saved successfully.')
            self.assertEqual(errors[field], expected_error)

    def test_user_profile_import_educator_validation(self):
        self.client.login(username=self.principal.username, password='******')
        self.student_data['Educator name'] = 'Educator'
        self.student_data['Educator phone number'] = ''
        self.student_data['Educator email address'] = ''

        file = self.create_file(self.file_name)
        writer = csv.DictWriter(file, fieldnames=self.student_data.keys())
        writer.writeheader()
        writer.writerow(self.student_data)

        response = self.get_response(file)
        self.assertEqual(response.status_code, status.HTTP_200_OK)

        errors = response.data['errors'][1]
        self.assertEqual(len(errors), 1)
        self.assertEqual(
            errors['Educator name'],
            'Either email or phone number is required for the educator.')

    @data('yes', 'no')
    def test_user_profile_import_username_validation(self,
                                                     use_phone_as_username):
        self.client.login(username=self.admin.username, password='******')
        self.admin_data['Use phone as username'] = use_phone_as_username

        file = self.create_file(self.file_name)
        writer = csv.DictWriter(file, fieldnames=self.admin_data.keys())
        writer.writeheader()
        writer.writerow(self.admin_data)

        response = self.get_response(file)

        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(len(response.data['errors']), 0)
        username = self.admin_data[
            'Phone number'] if use_phone_as_username == 'yes' else self.admin_data[
                'Email address']
        self.assertTrue(UserProfile.objects.filter(username=username).exists())

    @data((UserProfile.UserRoles.ADMINISTRATOR,
           ['student_data', 'parent_data', 'teacher_data']),
          (UserProfile.UserRoles.PRINCIPAL, ['admin_data', 'principal_data']))
    @unpack
    def test_user_profile_import_invalid_user_role(self, request_user_role,
                                                   data_dictionaries):
        self.client.login(username=UserProfile.objects.get(
            user_role=request_user_role).username,
                          password='******')

        for data_dict in data_dictionaries:
            file = self.create_file(self.file_name)
            writer = csv.DictWriter(file, fieldnames=self.student_data.keys())
            writer.writeheader()
            writer.writerow(getattr(self, data_dict))

            response = self.get_response(file)
            self.assertEqual(response.status_code, status.HTTP_200_OK)

            errors = response.data['errors'][1]
            self.assertEqual(len(errors), 1)
            self.assertEqual(
                errors['User role'],
                'You don\'t have permission to create a user with this role.')

    @data((UserProfile.UserRoles.ADMINISTRATOR, 'admin_data'),
          (UserProfile.UserRoles.PRINCIPAL, 'principal_data'),
          (UserProfile.UserRoles.PARENT, 'parent_data'),
          (UserProfile.UserRoles.TEACHER, 'teacher_data'))
    @unpack
    def test_user_profile_import_extra_fields(self, user_role, data_dict):
        # Check that any supplied fields that don't belong to the user role are ignored
        user = self.admin if data_dict in ['admin_data', 'principal_data'
                                           ] else self.principal
        self.client.login(username=user.username, password='******')

        data_dict = getattr(self, data_dict)
        self.student_data['User role'] = data_dict['User role']
        self.student_data['Phone number'] = data_dict['Phone number']
        fieldnames = self.student_data.keys()

        file = self.create_file(self.file_name)
        writer = csv.DictWriter(file, fieldnames=fieldnames)
        writer.writeheader()
        writer.writerow(self.student_data)

        response = self.get_response(file)
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(len(response.data['errors']), 0)

        username = data_dict['Phone number']
        if user_role in [
                UserProfile.UserRoles.PARENT, UserProfile.UserRoles.TEACHER
        ]:
            username = '******'.format(self.principal.school_unit_id, username)
        user = UserProfile.objects.get(username=username)

        for field in [
                'Birth date', 'Educator phone number', 'Educator email',
                'Educator name', 'Personal id number'
        ]:
            self.assertIsNone(getattr(user, field, None))

    @data(('Name', 180, 181 * 'a'),
          ('Email address', 150, 145 * 'a' + '@gmail.com'),
          ('Educator email address', 150, 145 * 'a' + '@gmail.com'),
          ('Educator name', 180, 181 * 'a'))
    @unpack
    def test_user_profile_import_max_length(self, field_name, max_length,
                                            invalid_value):
        self.client.login(username=self.principal.username, password='******')
        self.student_data[field_name] = invalid_value

        fieldnames = self.student_data.keys()

        file = self.create_file(self.file_name)
        writer = csv.DictWriter(file, fieldnames=fieldnames)
        writer.writeheader()
        writer.writerow(self.student_data)

        response = self.get_response(file)
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(len(response.data['errors']), 1)
        self.assertEqual(response.data['errors'][1][field_name],
                         f'Write maximum {max_length} characters.')
class UserProfileMyAccountUpdateTestCase(CommonAPITestCase):
    @classmethod
    def setUpTestData(cls):
        cls.url = reverse('users:my-account')
        cls.administrator = UserProfileFactory(user_role=UserProfile.UserRoles.ADMINISTRATOR)
        cls.principal = UserProfileFactory(user_role=UserProfile.UserRoles.PRINCIPAL)
        cls.teacher = UserProfileFactory(user_role=UserProfile.UserRoles.TEACHER)
        cls.parent = UserProfileFactory(user_role=UserProfile.UserRoles.PARENT)
        cls.student = UserProfileFactory(user_role=UserProfile.UserRoles.STUDENT)
        cls.registered_school_unit = RegisteredSchoolUnitFactory(school_principal=cls.principal)

        for user in UserProfile.objects.exclude(user_role=UserProfile.UserRoles.ADMINISTRATOR):
            user.school_unit = cls.registered_school_unit
            user.save()

    def setUp(self):
        self.administrator.refresh_from_db()
        self.data = {
            'use_phone_as_username': True,
            'email': '*****@*****.**',
            'phone_number': '+40700100200',
            'full_name': 'New Name',
            'email_notifications_enabled': True,
            'sms_notifications_enabled': True,
            'push_notifications_enabled': True,
            'current_password': '******',
            'new_password': '******',
            'user_role': 'ADMINISTRATOR'
        }
        self.parent_data = {
            **self.data,
            'address': 'address',
            'user_role': 'PARENT'
        }
        self.student_data = {
            **self.data,
            'address': 'address',
            'personal_id_number': '1900203044858',
            'birth_date': date(2000, 1, 1),
            'user_role': 'STUDENT'
        }

    def test_user_profile_my_account_update_unauthenticated(self):
        response = self.client.get(self.url)
        self.assertEqual(response.status_code, status.HTTP_401_UNAUTHORIZED)

    @data(
        UserProfile.UserRoles.ADMINISTRATOR, UserProfile.UserRoles.PRINCIPAL, UserProfile.UserRoles.TEACHER,
        UserProfile.UserRoles.STUDENT, UserProfile.UserRoles.PARENT
    )
    def test_user_profile_my_account_update_required_fields(self, user_role):
        self.client.login(username=UserProfile.objects.get(user_role=user_role).username, password='******')

        required_fields = [
            'phone_number', 'use_phone_as_username', 'full_name',
            'email_notifications_enabled', 'push_notifications_enabled',
            'sms_notifications_enabled'
        ]

        for field in required_fields:
            data_to_send = {
                field_name: self.data.get(field_name)
                for field_name in required_fields if field_name != field
            }
            data_to_send['user_role'] = user_role
            response = self.client.put(self.url, data_to_send)

            self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
            self.assertEqual(response.data, {field: ['This field is required.']})

    @data(
        (UserProfile.UserRoles.ADMINISTRATOR, ['id', 'full_name', 'user_role', 'email', 'phone_number',
                                               'use_phone_as_username', 'email_notifications_enabled',
                                               'sms_notifications_enabled', 'push_notifications_enabled', 'school_unit']),
        (UserProfile.UserRoles.PRINCIPAL, ['id', 'full_name', 'user_role', 'email', 'phone_number',
                                           'use_phone_as_username', 'email_notifications_enabled',
                                           'sms_notifications_enabled', 'push_notifications_enabled', 'school_unit']),
        (UserProfile.UserRoles.TEACHER, ['id', 'full_name', 'user_role', 'email', 'phone_number',
                                         'use_phone_as_username', 'email_notifications_enabled',
                                         'sms_notifications_enabled', 'push_notifications_enabled', 'school_unit']),
        (UserProfile.UserRoles.PARENT, ['id', 'full_name', 'user_role', 'email', 'phone_number',
                                        'use_phone_as_username', 'email_notifications_enabled',
                                        'sms_notifications_enabled', 'push_notifications_enabled',
                                        'address', 'school_unit', 'children']),
        (UserProfile.UserRoles.STUDENT, ['id', 'full_name', 'user_role', 'email', 'phone_number',
                                         'use_phone_as_username', 'email_notifications_enabled',
                                         'sms_notifications_enabled', 'push_notifications_enabled',
                                         'address', 'class_grade', 'class_letter', 'personal_id_number', 'birth_date', 'school_unit'])
    )
    @unpack
    def test_user_profile_my_account_update_expected_response_fields(self, user_role, expected_fields):
        profile = UserProfile.objects.get(user_role=user_role)
        self.client.login(username=profile.username, password='******')

        if user_role == UserProfile.UserRoles.PARENT:
            data_to_send = self.parent_data
        elif user_role == UserProfile.UserRoles.STUDENT:
            data_to_send = self.student_data
        else:
            data_to_send = self.data

        data_to_send['user_role'] = user_role.upper()
        response = self.client.put(self.url, data_to_send)

        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertCountEqual(response.data.keys(), expected_fields)

    def test_user_profile_my_account_update_password_validations(self):
        self.client.login(username=self.administrator.username, password='******')

        self.data['new_password'] = ''
        response = self.client.put(self.url, self.data)
        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
        self.assertEqual(response.data, {'new_password': ['This field is required.']})

        for new_password in ['a' * 5, 'a' * 129, 'abcdefg h']:
            self.data['new_password'] = new_password
            response = self.client.put(self.url, self.data)
            self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
            self.assertEqual(response.data, {'new_password': ['Invalid format. Must be minimum 6, maximum 128 characters, no spaces allowed.']})

        self.data['new_password'] = '******'
        self.data['current_password'] = ''
        response = self.client.put(self.url, self.data)
        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
        self.assertEqual(response.data, {'current_password': ['This field is required.']})

        self.data['current_password'] = '******'
        response = self.client.put(self.url, self.data)
        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
        self.assertEqual(response.data, {'current_password': ["Does not match the user's current password."]})

    def test_user_profile_my_account_update_success(self):
        self.client.login(username=self.administrator.username, password='******')

        response = self.client.put(self.url, self.data)
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.refresh_objects_from_db([self.administrator, self.administrator.user])

        for field, value in self.data.items():
            if field not in ['user_role', 'new_password', 'current_password']:
                self.assertEqual(value, getattr(self.administrator, field))

        self.assertTrue(self.administrator.user.check_password(self.data['new_password']))
        self.assertEqual(self.administrator.username, self.data['phone_number'])

    def test_user_profile_my_account_update_username_validations(self):
        self.client.login(username=self.administrator.username, password='******')

        self.data['use_phone_as_username'] = False
        self.data['email'] = self.principal.email
        response = self.client.put(self.url, self.data)
        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
        self.assertEqual(response.data, {'username': ['This username is already associated with another account.']})

        self.data['use_phone_as_username'] = True
        self.data['email'] = '*****@*****.**'
        del self.data['phone_number']
        response = self.client.put(self.url, self.data)
        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
        self.assertEqual(response.data, {'phone_number': ['This field is required.']})

        self.data['use_phone_as_username'] = False
        self.data['email'] = ''
        response = self.client.put(self.url, self.data)
        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
        self.assertEqual(response.data, {'email': ['This field is required.']})

    @data(
        ('email', ['invalid_email', 'invalid@email'], ["Enter a valid email address."]),
        ('phone_number', ['letters', '0000', '++40890092'], ["Invalid format. Must be minimum 10, maximum 20 digits or +."]),
        ('personal_id_number', ['letters', '0000', '1233444556678889990'], ['Invalid format. Must be 13 digits, no spaces allowed.']),
        ('birth_date', [date(3000, 1, 1)], ['Birth date must be in the past.']),
        ('birth_date', ['2000-01-02', '20-20-20000'], ['Date has wrong format. Use one of these formats instead: DD-MM-YYYY.']),
    )
    @unpack
    def test_user_profile_my_account_update_validations(self, field, values, expected_error):
        self.client.login(username=self.student.username, password='******')

        for value in values:
            self.data[field] = value
            response = self.client.put(self.url, self.data)
            self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
            self.assertEqual(response.data[field], expected_error)
예제 #28
0
    def test_current_academic_year_calendar_update_success(self):
        self.client.login(username=self.admin.username, password='******')

        response = self.client.put(self.url, self.data)
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.academic_year_calendar.refresh_from_db()

        expected_fields = [
            'first_semester', 'second_semester', 'academic_year', 'events'
        ]
        self.assertCountEqual(expected_fields, response.data.keys())

        semester_expected_fields = ['id', 'starts_at', 'ends_at', 'events']
        self.assertCountEqual(semester_expected_fields,
                              response.data['first_semester'])
        self.assertCountEqual(semester_expected_fields,
                              response.data['second_semester'])
        for semester in ['first_semester', 'second_semester']:
            self.assertEqual(
                getattr(self.academic_year_calendar,
                        semester).starts_at.strftime(settings.DATE_FORMAT),
                self.data[semester]['starts_at'])

        # Try to add an event
        self.data['first_semester']['events'] = [{
            'starts_at':
            date(self.next_year, 2, 2),
            'ends_at':
            date(self.next_year, 2, 3),
            'event_type':
            SchoolEvent.EventTypes.LEGAL_PUBLIC_HOLIDAY
        }]
        response = self.client.put(self.url, self.data)
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        event = self.academic_year_calendar.first_semester.school_events.first(
        )
        self.assertEqual(event.starts_at, event.starts_at)

        # Update it
        self.data['first_semester']['events'] = [{
            'id':
            event.id,
            'starts_at':
            date(self.next_year, 2, 2),
            'ends_at':
            date(self.next_year, 2, 3),
            'event_type':
            SchoolEvent.EventTypes.SPRING_HOLIDAY
        }]
        response = self.client.put(self.url, self.data)
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        event.refresh_from_db()
        self.assertEqual(event.event_type,
                         SchoolEvent.EventTypes.SPRING_HOLIDAY)

        # Add new ones
        self.data['first_semester']['events'] += [{
            'starts_at':
            date(self.next_year, 2, 6),
            'ends_at':
            date(self.next_year, 2, 10),
            'event_type':
            SchoolEvent.EventTypes.LEGAL_PUBLIC_HOLIDAY
        }, {
            'starts_at':
            date(self.next_year, 3, 2),
            'ends_at':
            date(self.next_year, 3, 3),
            'event_type':
            SchoolEvent.EventTypes.LEGAL_PUBLIC_HOLIDAY
        }]
        response = self.client.put(self.url, self.data)

        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(
            self.academic_year_calendar.first_semester.school_events.count(),
            3)

        # Remove one of them
        self.data['first_semester']['events'].pop()
        response = self.client.put(self.url, self.data)
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(
            self.academic_year_calendar.first_semester.school_events.count(),
            2)
예제 #29
0
 def test_current_academic_year_calendar_update_year_events_validation(
         self):
     self.client.login(username=self.admin.username, password='******')
     for bad_data in [[{
             'starts_at': date(self.next_year, 12, 21),
             'ends_at': date(self.next_year, 12, 23),
             'event_type': SchoolEvent.EventTypes.CORIGENTE
     }, {
             'starts_at': date(self.next_year, 12, 22),
             'ends_at': date(self.next_year, 12, 25),
             'event_type': SchoolEvent.EventTypes.CORIGENTE
     }],
                      [{
                          'starts_at': date(self.next_year, 12, 23),
                          'ends_at': date(self.next_year, 12, 25),
                          'event_type': SchoolEvent.EventTypes.DIFERENTE
                      }, {
                          'starts_at': date(self.next_year, 12, 23),
                          'ends_at': date(self.next_year, 12, 26),
                          'event_type': SchoolEvent.EventTypes.CORIGENTE
                      }],
                      [{
                          'starts_at': date(self.next_year, 12, 22),
                          'ends_at': date(self.next_year, 12, 25),
                          'event_type': SchoolEvent.EventTypes.DIFERENTE
                      }, {
                          'starts_at': date(self.next_year, 12, 23),
                          'ends_at': date(self.next_year, 12, 24),
                          'event_type': SchoolEvent.EventTypes.DIFERENTE
                      }]]:
         self.data['events'] = bad_data
         response = self.client.put(self.url, self.data)
         self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
         self.assertEqual(response.data,
                          {'events': ['Events cannot overlap.']})
예제 #30
0
    def test_current_academic_year_calendar_update_semester_events_validation(
            self):
        self.client.login(username=self.admin.username, password='******')

        for bad_data in [[{
                'starts_at': date(self.next_year, 1, 2),
                'ends_at': date(self.next_year, 3, 3),
                'event_type': SchoolEvent.EventTypes.SPRING_HOLIDAY
        }, {
                'starts_at':
                date(self.next_year, 2, 5),
                'ends_at':
                date(self.next_year, 3, 2),
                'event_type':
                SchoolEvent.EventTypes.LEGAL_PUBLIC_HOLIDAY
        }],
                         [{
                             'starts_at': date(self.next_year, 2, 2),
                             'ends_at': date(self.next_year, 3, 3),
                             'event_type':
                             SchoolEvent.EventTypes.SPRING_HOLIDAY
                         }, {
                             'starts_at':
                             date(self.next_year, 3, 3),
                             'ends_at':
                             date(self.next_year, 4, 1),
                             'event_type':
                             SchoolEvent.EventTypes.LEGAL_PUBLIC_HOLIDAY
                         }],
                         [{
                             'starts_at': date(self.next_year, 2, 2),
                             'ends_at': date(self.next_year, 2, 5),
                             'event_type':
                             SchoolEvent.EventTypes.SPRING_HOLIDAY
                         }, {
                             'starts_at':
                             date(self.next_year, 2, 3),
                             'ends_at':
                             date(self.next_year, 2, 4),
                             'event_type':
                             SchoolEvent.EventTypes.LEGAL_PUBLIC_HOLIDAY
                         }]]:
            self.data['first_semester']['events'] = bad_data
            response = self.client.put(self.url, self.data)
            self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
            self.assertEqual(response.data,
                             {'events': ['Events cannot overlap.']})

        # CORIGENTE and DIFERENTE can't be added inside the semester
        for event_type in [
                SchoolEvent.EventTypes.CORIGENTE,
                SchoolEvent.EventTypes.DIFERENTE
        ]:
            self.data['first_semester']['events'] = [{
                'starts_at':
                date(self.next_year, 3, 3),
                'ends_at':
                date(self.next_year, 4, 4),
                'event_type':
                event_type
            }]
            response = self.client.put(self.url, self.data)
            self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
            self.assertEqual(
                response.data, {
                    'first_semester': {
                        'events': [
                            f'{event_type.label} events cannot be inside semesters.'
                        ]
                    }
                })

        # SECOND_SEMESTER_END_IX_XI_FILIERA_TEHNOLOGICA must be between second semester start and the end of the school year
        self.data['first_semester']['events'] = []
        self.data['second_semester']['events'] = [{
            'starts_at':
            date(self.next_year, 5, 5),
            'ends_at':
            date(self.next_year, 5, 6),
            'event_type':
            SchoolEvent.EventTypes.
            SECOND_SEMESTER_END_IX_XI_FILIERA_TEHNOLOGICA
        }]
        response = self.client.put(self.url, self.data)
        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
        self.assertEqual(
            response.data, {
                'events': {
                    'starts_at':
                    "Second semester end for Filiera Tehnologica"
                    " must be between the second semester's start and the end of"
                    " the current academic year."
                }
            })