Skip to content

Commit

Permalink
Merge branch 'develop' into 148-advanced-tests
Browse files Browse the repository at this point in the history
  • Loading branch information
robinpdev committed May 19, 2024
2 parents c0cfec4 + 6d0c45a commit f807bb2
Show file tree
Hide file tree
Showing 130 changed files with 5,152 additions and 2,394 deletions.
3 changes: 2 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ lint:
docker exec pigeonhole-frontend npm run lint

superuser:
docker exec -it pigeonhole-backend python manage.py createsuperuser



mockdata:
docker exec -it pigeonhole-backend python manage.py runscript mockdata
Expand Down
4 changes: 2 additions & 2 deletions backend/pigeonhole/apps/courses/permissions.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,15 @@ def has_permission(self, request, view):
"get_teachers",
"get_students",
"get_archived_courses",
"get_open_courses"
]:
return True

if request.user.is_teacher:
if view.action in ["create", "list", "retrieve"]:
return True
elif (
view.action in ["update", "partial_update", "destroy",
"get_projects"]
view.action in ["update", "partial_update", "destroy", "get_projects"]
and User.objects.filter(
id=request.user.id, course=view.kwargs["pk"]
).exists()
Expand Down
41 changes: 40 additions & 1 deletion backend/pigeonhole/apps/courses/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from django_filters.rest_framework import DjangoFilterBackend

from backend.pigeonhole.apps.courses.models import CourseSerializer
from backend.pigeonhole.apps.groups.models import Group
from backend.pigeonhole.apps.groups.models import Group, GroupSerializer
from backend.pigeonhole.apps.projects.models import Project
from backend.pigeonhole.apps.projects.models import ProjectSerializer
from backend.pigeonhole.apps.users.models import User, UserSerializer
Expand Down Expand Up @@ -59,6 +59,21 @@ def join_course(self, request, *args, **kwargs):
if request.user.is_student:
if course.open_course:
user.course.add(course)

# Join all individual projects of the course
projects = Project.objects.filter(course_id=course, group_size=1)
for project in projects:
group_data = {
"project_id": project.project_id,
"user": [user.id],
"feedback": None,
"final_score": None,
"visible": False,
}
group_serializer = GroupSerializer(data=group_data)
group_serializer.is_valid(raise_exception=True)
group_serializer.save()

return Response(status=status.HTTP_200_OK)
else:
return Response(
Expand All @@ -81,6 +96,22 @@ def join_course_with_token(self, request, *args, **kwargs):

if invite_token == course.invite_token:
user.course.add(course)

# Join all individual projects of the course
if request.user.is_student:
projects = Project.objects.filter(course_id=course, group_size=1)
for project in projects:
group_data = {
"project_id": project.project_id,
"user": [user.id],
"feedback": None,
"final_score": None,
"visible": False,
}
group_serializer = GroupSerializer(data=group_data)
group_serializer.is_valid(raise_exception=True)
group_serializer.save()

return Response(
{"message": "Successfully joined the course with invite token."},
status=status.HTTP_200_OK,
Expand Down Expand Up @@ -172,3 +203,11 @@ def get_archived_courses(self, request, *args, **kwargs):
queryset = self.order_queryset(paginated_queryset)
serializer = CourseSerializer(queryset, many=True)
return self.get_paginated_response(serializer.data)

@action(detail=False, methods=["GET"])
def get_open_courses(self, request, *args, **kwargs):
courses = Course.objects.filter(open_course=True)
course_filter = CourseFilter(request.GET, queryset=courses)
queryset = self.order_queryset(course_filter.qs)
serializer = CourseSerializer(self.paginate_queryset(queryset), many=True)
return self.get_paginated_response(serializer.data)
120 changes: 104 additions & 16 deletions backend/pigeonhole/apps/projects/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
Submissions,
SubmissionsSerializer,
)
from backend.pigeonhole.apps.users.models import User
from backend.pigeonhole.filters import (
GroupFilter,
CustomPageNumberPagination,
Expand Down Expand Up @@ -47,19 +48,34 @@ def create(self, request, *args, **kwargs):

number_of_groups = serializer.validated_data.get("number_of_groups", 0)
project = serializer.save()

group_size = serializer.validated_data.get("group_size", 0)
groups = []
for i in range(number_of_groups):
group_data = {
"project_id": project.project_id,
"user": [], # You may add users here if needed
"feedback": None,
"final_score": None,
"visible": False, # Adjust visibility as needed
}
group_serializer = GroupSerializer(data=group_data)
group_serializer.is_valid(raise_exception=True)
groups.append(group_serializer.save())

if group_size == 1:
for user in User.objects.filter(course=serializer.validated_data.get("course_id"), role=3):
group_data = {
"project_id": project.project_id,
"user": [user.id],
"feedback": None,
"final_score": None,
"visible": False,
}
group_serializer = GroupSerializer(data=group_data)
group_serializer.is_valid(raise_exception=True)
groups.append(group_serializer.save())

else:
for i in range(number_of_groups):
group_data = {
"project_id": project.project_id,
"user": [], # You may add users here if needed
"feedback": None,
"final_score": None,
"visible": False, # Adjust visibility as needed
}
group_serializer = GroupSerializer(data=group_data)
group_serializer.is_valid(raise_exception=True)
groups.append(group_serializer.save())

# You may return the newly created groups if needed
groups_data = GroupSerializer(groups, many=True).data
Expand All @@ -69,6 +85,76 @@ def create(self, request, *args, **kwargs):
headers = self.get_success_headers(serializer.data)
return Response(response_data, status=status.HTTP_201_CREATED, headers=headers)

def update(self, request, *args, **kwargs):

project = self.get_object()
serializer = self.get_serializer(project, data=request.data, partial=True)
serializer.is_valid(raise_exception=True)

if "group_size" in request.data and int(request.data["group_size"]) != project.group_size:
group_size = int(request.data["group_size"])

if "number_of_groups" in request.data:
number_of_groups = int(request.data["number_of_groups"])
else:
number_of_groups = project.number_of_groups

Group.objects.filter(project_id=project).delete()

groups = []
if group_size == 1:
for user in User.objects.filter(course=project.course_id, role=3):
group_data = {
"project_id": project.project_id,
"user": [user.id],
"feedback": None,
"final_score": None,
"visible": False,
}
group_serializer = GroupSerializer(data=group_data)
group_serializer.is_valid(raise_exception=True)
groups.append(group_serializer.save())

else:
for i in range(number_of_groups):
group_data = {
"project_id": project.project_id,
"user": [],
"feedback": None,
"final_score": None,
"visible": False,
}
group_serializer = GroupSerializer(data=group_data)
group_serializer.is_valid(raise_exception=True)
groups.append(group_serializer.save())

elif "number_of_groups" in request.data and int(
request.data["number_of_groups"]) != project.number_of_groups and project.group_size != 1:
number_of_groups = int(request.data["number_of_groups"])
old_groups = Group.objects.filter(project_id=project)
groups = []
if len(old_groups) < number_of_groups:
for i in range(number_of_groups - len(old_groups)):
group_data = {
"project_id": project.project_id,
"user": [],
"feedback": None,
"final_score": None,
"visible": False,
}
group_serializer = GroupSerializer(data=group_data)
group_serializer.is_valid(raise_exception=True)
groups.append(group_serializer.save())
else:
for i in range(len(old_groups) - number_of_groups):
old_groups[len(old_groups) - 1 - i].delete()

self.perform_update(serializer)
return Response(serializer.data)

def partial_update(self, request, *args, **kwargs):
return self.update(request, *args, **kwargs)

@action(detail=True, methods=["GET"])
def get_groups(self, request, *args, **kwargs):
project = self.get_object()
Expand Down Expand Up @@ -185,8 +271,10 @@ def download_testfiles(self, request, *args, **kwargs):
@action(detail=True, methods=["GET"])
def get_group(self, request, *args, **kwargs):
project = self.get_object()
group = Group.objects.get(
project_id=project.project_id, user=request.user)
if not group:
return Response({"message": "Group not found"}, status=status.HTTP_404_NOT_FOUND)
try:
group = Group.objects.get(
project_id=project.project_id, user=request.user)
except Group.DoesNotExist:
return Response({"message": "Group not found", "errorcode": "ERROR_NOT_IN_GROUP"},
status=status.HTTP_404_NOT_FOUND)
return Response({"group_id": group.group_id}, status=status.HTTP_200_OK)
37 changes: 29 additions & 8 deletions backend/pigeonhole/apps/submissions/permissions.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from rest_framework import permissions, status
from rest_framework.exceptions import APIException
from rest_framework.response import Response

from backend.pigeonhole.apps.courses.models import Course
Expand All @@ -12,13 +13,20 @@ class CanAccessSubmission(permissions.BasePermission):
# to the submission data.
def has_permission(self, request, view):
user = request.user
if view.action in ['list']:

if not user.is_authenticated:
return False

if view.action == "get_project":
return True

if view.action in ["list"]:
return False
elif view.action in ['download_selection']:
elif view.action in ["download_selection"]:
return user.is_teacher or user.is_admin or user.is_superuser
elif view.action in ['create']:
elif view.action in ["create"]:
if user.is_student:
group_id = request.data.get('group_id')
group_id = request.data.get("group_id")
if not Group.objects.filter(group_id=group_id).exists():
if user.is_admin or user.is_superuser:
return Response(status=status.HTTP_404_NOT_FOUND)
Expand All @@ -27,15 +35,17 @@ def has_permission(self, request, view):
if group.user.filter(id=user.id).exists():
return True
else:
return False
raise NotInGroupError()
elif user.is_admin or user.is_superuser:
return True
else:
return False
else:
if ('pk' not in view.kwargs.keys()) and (user.is_teacher or user.is_admin or user.is_superuser):
if ("pk" not in view.kwargs.keys()) and (
user.is_teacher or user.is_admin or user.is_superuser
):
return True
submission = Submissions.objects.get(submission_id=view.kwargs['pk'])
submission = Submissions.objects.get(submission_id=view.kwargs["pk"])
group_id = submission.group_id.group_id
if not Group.objects.filter(group_id=group_id).exists():
if user.is_admin or user.is_superuser:
Expand All @@ -54,5 +64,16 @@ def has_permission(self, request, view):
return True
elif user.is_student:
if group.user.filter(id=user.id).exists():
return view.action in ['retrieve', 'create', 'download', 'get_project']
return view.action in [
"retrieve",
"create",
"download",
"get_project",
]
return False


class NotInGroupError(APIException):
status_code = status.HTTP_403_FORBIDDEN
default_detail = "you are not in a group for this project, please join one."
default_code = "ERROR_NOT_IN_GROUP"
Loading

0 comments on commit f807bb2

Please sign in to comment.