diff --git a/backend/pigeonhole/apps/courses/permissions.py b/backend/pigeonhole/apps/courses/permissions.py index 201b666e..13119e03 100644 --- a/backend/pigeonhole/apps/courses/permissions.py +++ b/backend/pigeonhole/apps/courses/permissions.py @@ -1,30 +1,30 @@ from rest_framework import permissions -from backend.pigeonhole.apps.users.models import Student, Teacher +from backend.pigeonhole.apps.users.models import User class CourseUserPermissions(permissions.BasePermission): def has_permission(self, request, view): if request.user.is_superuser: return True - if isinstance(request.user, Teacher): - return True - - if isinstance(request.user, Student): - return view.action in ['list', 'retrieve'] + # if isinstance(request.user, Teacher): + # return True + # + # if isinstance(request.user, Student): + # return view.action in ['list', 'retrieve'] return False def has_object_permission(self, request, view, obj): if request.user.is_superuser: return True - if isinstance(request.user, Teacher): - if request.user.is_admin: - return True - elif Teacher.objects.filter(id=request.user.id, course=obj).exists(): - return True - return view.action in ['list', 'retrieve'] - - if isinstance(request.user, Student): - return view.action in ['list', 'retrieve'] + # if isinstance(request.user, Teacher): + # if request.user.is_admin: + # return True + # elif Teacher.objects.filter(id=request.user.id, course=obj).exists(): + # return True + # return view.action in ['list', 'retrieve'] + # + # if isinstance(request.user, Student): + # return view.action in ['list', 'retrieve'] return False diff --git a/backend/pigeonhole/apps/groups/migrations/0005_remove_group_student_group_user.py b/backend/pigeonhole/apps/groups/migrations/0005_remove_group_student_group_user.py new file mode 100644 index 00000000..34f5581e --- /dev/null +++ b/backend/pigeonhole/apps/groups/migrations/0005_remove_group_student_group_user.py @@ -0,0 +1,24 @@ +# Generated by Django 5.0.2 on 2024-03-11 13:17 + +from django.conf import settings +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('groups', '0004_alter_group_final_score'), + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ] + + operations = [ + migrations.RemoveField( + model_name='group', + name='student', + ), + migrations.AddField( + model_name='group', + name='user', + field=models.ManyToManyField(to=settings.AUTH_USER_MODEL), + ), + ] diff --git a/backend/pigeonhole/apps/groups/models.py b/backend/pigeonhole/apps/groups/models.py index c7df2aee..164da31b 100644 --- a/backend/pigeonhole/apps/groups/models.py +++ b/backend/pigeonhole/apps/groups/models.py @@ -2,14 +2,14 @@ from rest_framework import serializers from backend.pigeonhole.apps.projects.models import Project -from backend.pigeonhole.apps.users.models import Student +from backend.pigeonhole.apps.users.models import User class Group(models.Model): group_id = models.BigAutoField(primary_key=True) group_nr = models.IntegerField(blank=True, null=True) project_id = models.ForeignKey(Project, on_delete=models.CASCADE) - student = models.ManyToManyField(Student) + user = models.ManyToManyField(User) feedback = models.TextField(null=True) final_score = models.IntegerField(null=True, blank=True) @@ -28,4 +28,4 @@ def save(self, *args, **kwargs): class GroupSerializer(serializers.ModelSerializer): class Meta: model = Group - fields = ["group_id", "group_nr", "final_score", "project_id", "student", "feedback"] + fields = ["group_id", "group_nr", "final_score", "project_id", "user", "feedback"] diff --git a/backend/pigeonhole/apps/projects/permissions.py b/backend/pigeonhole/apps/projects/permissions.py index d08a56b5..77efdd16 100644 --- a/backend/pigeonhole/apps/projects/permissions.py +++ b/backend/pigeonhole/apps/projects/permissions.py @@ -1,5 +1,5 @@ from rest_framework import permissions -from backend.pigeonhole.apps.users.models import Teacher, Student +from backend.pigeonhole.apps.users.models import User class CanAccessProject(permissions.BasePermission): @@ -9,15 +9,15 @@ def has_permission(self, request, view): user = request.user subject_id = view.kwargs.get('course_id') # If the user is a teacher, grant access. - if isinstance(user, Teacher): - if user.course.filter(id=subject_id).exists(): - return True - elif isinstance(user, Teacher) and user.is_admin: - return True - # If the user is a student, grant access only to their own projects. - elif isinstance(user, Student): - if user.course.filter(id=subject_id).exists(): - return True - elif request.user.is_superuser: - return True + # if isinstance(user, Teacher): + # if user.course.filter(id=subject_id).exists(): + # return True + # elif isinstance(user, Teacher) and user.is_admin: + # return True + # # If the user is a student, grant access only to their own projects. + # elif isinstance(user, Student): + # if user.course.filter(id=subject_id).exists(): + # return True + # elif request.user.is_superuser: + # return True return False diff --git a/backend/pigeonhole/apps/users/migrations/0003_remove_teacher_course_remove_teacher_id_and_more.py b/backend/pigeonhole/apps/users/migrations/0003_remove_teacher_course_remove_teacher_id_and_more.py new file mode 100644 index 00000000..67dd6291 --- /dev/null +++ b/backend/pigeonhole/apps/users/migrations/0003_remove_teacher_course_remove_teacher_id_and_more.py @@ -0,0 +1,64 @@ +# Generated by Django 5.0.2 on 2024-03-11 13:17 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('courses', '0001_initial'), + ('groups', '0005_remove_group_student_group_user'), + ('users', '0002_rename_is_assistent_teacher_is_assistant'), + ] + + operations = [ + migrations.RemoveField( + model_name='teacher', + name='course', + ), + migrations.RemoveField( + model_name='teacher', + name='id', + ), + migrations.AlterModelManagers( + name='user', + managers=[ + ], + ), + migrations.AddField( + model_name='user', + name='course', + field=models.ManyToManyField(to='courses.course'), + ), + migrations.AddField( + model_name='user', + name='role', + field=models.IntegerField(choices=[(1, 'Superuser'), (2, 'Teacher'), (3, 'Student')], default=3), + ), + migrations.AlterField( + model_name='user', + name='email', + field=models.EmailField(max_length=254, unique=True), + ), + migrations.AlterField( + model_name='user', + name='first_name', + field=models.CharField(max_length=30), + ), + migrations.AlterField( + model_name='user', + name='id', + field=models.BigAutoField(primary_key=True, serialize=False), + ), + migrations.AlterField( + model_name='user', + name='last_name', + field=models.CharField(max_length=150), + ), + migrations.DeleteModel( + name='Student', + ), + migrations.DeleteModel( + name='Teacher', + ), + ] diff --git a/backend/pigeonhole/apps/users/models.py b/backend/pigeonhole/apps/users/models.py index be3154de..80247fda 100644 --- a/backend/pigeonhole/apps/users/models.py +++ b/backend/pigeonhole/apps/users/models.py @@ -5,47 +5,43 @@ from backend.pigeonhole.apps.courses.models import Course -class User(AbstractUser): - class Meta(AbstractUser.Meta): - db_table = "auth_user" - - @property - def name(self): - return f"{self.first_name.strip()} {self.last_name.strip()}" +class Roles(models.IntegerChoices): + SUPERUSER = 1 + TEACHER = 2 + STUDENT = 3 -class UserSerializer(serializers.ModelSerializer): - class Meta: - model = User - fields = ['id', 'email', 'first_name', 'last_name'] - - -class Student(models.Model): - id = models.ForeignKey(User, on_delete=models.CASCADE, primary_key=True) - number = models.IntegerField() +class User(AbstractUser): + id = models.BigAutoField(primary_key=True) + email = models.EmailField(unique=True) + first_name = models.CharField(max_length=30) + last_name = models.CharField(max_length=150) course = models.ManyToManyField(Course) + role = models.IntegerField(choices=Roles.choices, default=Roles.STUDENT) objects = models.Manager() + class Meta(AbstractUser.Meta): + db_table = "auth_user" -class StudentSerializer(serializers.ModelSerializer): - id = serializers.PrimaryKeyRelatedField(queryset=User.objects.all()) - - class Meta: - model = Student - fields = ['number', 'course', 'id'] + @property + def name(self): + return f"{self.first_name.strip()} {self.last_name.strip()}" + @property + def is_super(self): + return self.role == Roles.SUPERUSER -class Teacher(models.Model): - id = models.ForeignKey(User, on_delete=models.CASCADE, primary_key=True) - course = models.ManyToManyField(Course) - is_admin = models.BooleanField(default=False) - is_assistant = models.BooleanField(default=False) + @property + def is_teacher(self): + return self.role == Roles.TEACHER - objects = models.Manager() + @property + def is_student(self): + return self.role == Roles.STUDENT -class TeacherSerializer(serializers.ModelSerializer): +class UserSerializer(serializers.ModelSerializer): class Meta: - model = Teacher - fields = ['course', 'id', 'is_admin', 'is_assistent'] + model = User + fields = ['id', 'email', 'first_name', 'last_name', 'course', 'role'] diff --git a/backend/pigeonhole/apps/users/views.py b/backend/pigeonhole/apps/users/views.py index 0af8843f..5fec4879 100644 --- a/backend/pigeonhole/apps/users/views.py +++ b/backend/pigeonhole/apps/users/views.py @@ -2,29 +2,7 @@ from rest_framework.permissions import IsAuthenticated from rest_framework.response import Response -from backend.pigeonhole.apps.users.models import Student, StudentSerializer, User, UserSerializer - - -class StudentViewSet(viewsets.ModelViewSet): - queryset = Student.objects.all() - serializer_class = StudentSerializer - permission_classes = [IsAuthenticated] - - def create(self, request, *args, **kwargs): - serializer = StudentSerializer(data=request.data) - print(serializer) - if serializer.is_valid(): - serializer.save() - return Response(serializer.data, status=status.HTTP_201_CREATED) - else: - return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) - - def perform_create(self, serializer): - serializer.save(user=self.request.user) - - def list(self, request, *args, **kwargs): - serializer = StudentSerializer(self.queryset, many=True) - return Response(serializer.data, status=status.HTTP_200_OK) +from backend.pigeonhole.apps.users.models import User, UserSerializer class UserViewSet(viewsets.ModelViewSet): diff --git a/backend/pigeonhole/tests/test_models/test_conditions.py b/backend/pigeonhole/tests/test_models/test_conditions.py index 37307ab7..9998c3cd 100644 --- a/backend/pigeonhole/tests/test_models/test_conditions.py +++ b/backend/pigeonhole/tests/test_models/test_conditions.py @@ -1,5 +1,5 @@ from django.test import TestCase -from backend.pigeonhole.apps.users.models import User, Student, Teacher +from backend.pigeonhole.apps.users.models import User from backend.pigeonhole.apps.courses.models import Course from backend.pigeonhole.apps.projects.models import Project, Conditions, AllowedExtension, ForbiddenExtension @@ -22,8 +22,8 @@ def setUp(self): ) # Create teacher and student using the created users - teacher = Teacher.objects.create(id=teacher_user) - student = Student.objects.create(id=student_user, number=1234) + teacher = User.objects.create(id=teacher_user) + student = User.objects.create(id=student_user, number=1234) # Create course course = Course.objects.create(name="Math", description="Mathematics") diff --git a/backend/pigeonhole/tests/test_models/test_course.py b/backend/pigeonhole/tests/test_models/test_course.py index 2498a217..d576e67f 100644 --- a/backend/pigeonhole/tests/test_models/test_course.py +++ b/backend/pigeonhole/tests/test_models/test_course.py @@ -1,6 +1,6 @@ from django.test import TestCase from backend.pigeonhole.apps.courses.models import Course -from backend.pigeonhole.apps.users.models import User, Student, Teacher +from backend.pigeonhole.apps.users.models import User from django.db.utils import DataError @@ -25,8 +25,8 @@ def setUp(self): ) # Create teacher and student using the created users - teacher = Teacher.objects.create(id=teacher_user) - student = Student.objects.create(id=student_user, number=1234) + teacher = User.objects.create(id=teacher_user) + student = User.objects.create(id=student_user, number=1234) # Create course course = Course.objects.create(name="Math", description="Mathematics") @@ -34,7 +34,7 @@ def setUp(self): student.course.add(course) def test_course_teacher_relationship(self): - teacher = Teacher.objects.get(id__email="teacher@gmail.com") + teacher = User.objects.get(id__email="teacher@gmail.com") course = Course.objects.get(name="Math") self.assertIn(course, teacher.course.all()) course_alter_ego = teacher.course.get(name="Math") @@ -42,7 +42,7 @@ def test_course_teacher_relationship(self): self.assertTrue(course_alter_ego, "Mathematics") def test_course_students_relationship(self): - student = Student.objects.get(id__email="student@gmail.com") + student = User.objects.get(id__email="student@gmail.com") course = Course.objects.get(name="Math") self.assertIn(course, student.course.all()) course_alter_ego = student.course.get(name="Math") diff --git a/backend/pigeonhole/tests/test_models/test_groups.py b/backend/pigeonhole/tests/test_models/test_groups.py index 0ece53b9..09f9d6bc 100644 --- a/backend/pigeonhole/tests/test_models/test_groups.py +++ b/backend/pigeonhole/tests/test_models/test_groups.py @@ -1,6 +1,6 @@ from django.test import TestCase from backend.pigeonhole.apps.courses.models import Course -from backend.pigeonhole.apps.users.models import User, Student, Teacher +from backend.pigeonhole.apps.users.models import User from backend.pigeonhole.apps.groups.models import Group from backend.pigeonhole.apps.projects.models import Project @@ -34,9 +34,9 @@ def setUp(self): ) # Create teacher and student using the created users - teacher = Teacher.objects.create(id=teacher_user) - student = Student.objects.create(id=student_user, number=1234) - student2 = Student.objects.create(id=student_user2, number=5678) + teacher = User.objects.create(id=teacher_user) + student = User.objects.create(id=student_user, number=1234) + student2 = User.objects.create(id=student_user2, number=5678) # Create course course = Course.objects.create(name="Math", description="Mathematics") @@ -67,8 +67,8 @@ def test_group_project_relation(self): def test_group_student_relation(self): group = Group.objects.get(group_nr=1) - student = Student.objects.get(id__email="student@gmail.com") - student2 = Student.objects.get(id__email="student2@gmail.com") + student = User.objects.get(id__email="student@gmail.com") + student2 = User.objects.get(id__email="student2@gmail.com") self.assertIn(student, group.student.all()) self.assertIn(student2, group.student.all()) diff --git a/backend/pigeonhole/tests/test_models/test_project.py b/backend/pigeonhole/tests/test_models/test_project.py index 11285c91..da680d61 100644 --- a/backend/pigeonhole/tests/test_models/test_project.py +++ b/backend/pigeonhole/tests/test_models/test_project.py @@ -1,5 +1,5 @@ from django.test import TestCase -from backend.pigeonhole.apps.users.models import User, Student, Teacher +from backend.pigeonhole.apps.users.models import User from backend.pigeonhole.apps.courses.models import Course from backend.pigeonhole.apps.projects.models import Project @@ -22,8 +22,8 @@ def setUp(self): ) # Create teacher and student using the created users - teacher = Teacher.objects.create(id=teacher_user) - student = Student.objects.create(id=student_user, number=1234) + teacher = User.objects.create(id=teacher_user) + student = User.objects.create(id=student_user, number=1234) # Create course course = Course.objects.create(name="Math", description="Mathematics") @@ -41,11 +41,11 @@ def test_project_course_relation(self): self.assertEqual(self.project.course_id.name, "Math") def test_project_teacher_relation(self): - teacher = Teacher.objects.get(id__email="teacher@gmail.com") + teacher = User.objects.get(id__email="teacher@gmail.com") self.assertIn(self.project.course_id, teacher.course.all()) def test_project_student_relation(self): - student = Student.objects.get(id__email="student@gmail.com") + student = User.objects.get(id__email="student@gmail.com") self.assertIn(self.project.course_id, student.course.all()) def test_course_name_length_validation(self): diff --git a/backend/pigeonhole/tests/test_models/test_submissions.py b/backend/pigeonhole/tests/test_models/test_submissions.py index c6efed08..31b946a4 100644 --- a/backend/pigeonhole/tests/test_models/test_submissions.py +++ b/backend/pigeonhole/tests/test_models/test_submissions.py @@ -1,5 +1,5 @@ from django.test import TestCase -from backend.pigeonhole.apps.users.models import User, Student, Teacher +from backend.pigeonhole.apps.users.models import User from backend.pigeonhole.apps.courses.models import Course from backend.pigeonhole.apps.projects.models import Project from backend.pigeonhole.apps.submissions.models import Submissions @@ -25,8 +25,8 @@ def setUp(self): ) # Create teacher and student using the created users - teacher = Teacher.objects.create(id=teacher_user) - student = Student.objects.create(id=student_user, number=1234) + teacher = User.objects.create(id=teacher_user) + student = User.objects.create(id=student_user, number=1234) # Create course course = Course.objects.create(name="Math", description="Mathematics") diff --git a/backend/pigeonhole/tests/test_models/test_user.py b/backend/pigeonhole/tests/test_models/test_user.py index 043197e5..383933fd 100644 --- a/backend/pigeonhole/tests/test_models/test_user.py +++ b/backend/pigeonhole/tests/test_models/test_user.py @@ -1,5 +1,5 @@ from django.test import TestCase -from backend.pigeonhole.apps.users.models import User, Student, Teacher +from backend.pigeonhole.apps.users.models import User # python3 manage.py test backend/ @@ -22,51 +22,51 @@ def setUp(self): ) # Create teacher and student using the created users - Teacher.objects.create(id=teacher_user) - Student.objects.create(id=student_user, number=1234) + User.objects.create(id=teacher_user) + User.objects.create(id=student_user, number=1234) def test_student(self): - student = Student.objects.get(id__email="student@gmail.com") + student = User.objects.get(id__email="student@gmail.com") self.assertEqual(student.id.email, "student@gmail.com") self.assertEqual(student.number, 1234) # update student number student.number = 5678 student.save() - student = Student.objects.get(id__email="student@gmail.com") + student = User.objects.get(id__email="student@gmail.com") self.assertEqual(student.number, 5678) # delete student student.delete() - with self.assertRaises(Student.DoesNotExist): - Student.objects.get(id__email="student@gmail.com") + with self.assertRaises(User.DoesNotExist): + User.objects.get(id__email="student@gmail.com") def test_teacher(self): - teacher = Teacher.objects.get(id__email="teacher@gmail.com") + teacher = User.objects.get(id__email="teacher@gmail.com") self.assertEqual(teacher.id.email, "teacher@gmail.com") self.assertEqual(teacher.is_admin, False) # update teacher is_admin teacher.is_admin = True teacher.save() - teacher = Teacher.objects.get(id__email="teacher@gmail.com") + teacher = User.objects.get(id__email="teacher@gmail.com") self.assertEqual(teacher.is_admin, True) self.assertEqual(teacher.is_assistant, False) # update teacher is_assistent teacher.is_assistant = True teacher.save() - teacher = Teacher.objects.get(id__email="teacher@gmail.com") + teacher = User.objects.get(id__email="teacher@gmail.com") self.assertEqual(teacher.is_assistant, True) # delete teacher teacher.delete() - with self.assertRaises(Teacher.DoesNotExist): - Teacher.objects.get(id__email="teacher@gmail.com") + with self.assertRaises(User.DoesNotExist): + User.objects.get(id__email="teacher@gmail.com") def test_create_student_without_user(self): with self.assertRaises(Exception): - Student.objects.create(number=1234) + User.objects.create(number=1234) def test_create_teacher_without_user(self): with self.assertRaises(Exception): - Teacher.objects.create(is_admin=True, is_assistent=True) + User.objects.create(is_admin=True, is_assistent=True) diff --git a/backend/pigeonhole/urls.py b/backend/pigeonhole/urls.py index 5a76951a..abf24149 100644 --- a/backend/pigeonhole/urls.py +++ b/backend/pigeonhole/urls.py @@ -8,7 +8,7 @@ from backend.pigeonhole.apps.groups.views import GroupViewSet from backend.pigeonhole.apps.projects.views import ProjectViewSet from backend.pigeonhole.apps.submissions.views import SubmissionsViewset -from backend.pigeonhole.apps.users.views import StudentViewSet, UserViewSet +from backend.pigeonhole.apps.users.views import UserViewSet schema_view = get_schema_view( openapi.Info( @@ -25,7 +25,6 @@ router = routers.DefaultRouter() router.register(r'users', UserViewSet) -router.register(r'students', StudentViewSet) router.register(r'groups', GroupViewSet) router.register(r'courses', CourseViewSet) router.register(r'submissions', SubmissionsViewset)