Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

17 backend testing ☣️[infected, will close] #31

Closed
wants to merge 30 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
59393c7
First implementation of a view. Much work to do.
AlexanderVanOyen Mar 2, 2024
66e1061
model manager and put function
AlexanderVanOyen Mar 2, 2024
43ad033
Merge remote-tracking branch 'origin/develop' into api_routes-impleme…
AlexanderVanOyen Mar 4, 2024
8165e90
add swagger ui on /swagger and remove .env from tracked files
robinpdev Mar 5, 2024
546f63b
course api
ReinhardDP Mar 7, 2024
9283344
Merge branch 'api_routes-implementation' of github.com:SELab-2/UGent-…
ReinhardDP Mar 7, 2024
2baf464
Project viewset and custom permission class
AlexanderVanOyen Mar 8, 2024
d1aaba8
corrected instances
ReinhardDP Mar 9, 2024
d30a0aa
added permissions
ReinhardDP Mar 9, 2024
470806c
added courses to urls
ReinhardDP Mar 9, 2024
e2064bc
Merge branch 'api_routes-implementation' into 17-backend-testing
PJDeSmijter Mar 9, 2024
008aecc
add admin panel
robinpdev Mar 9, 2024
ada3209
fixed permission class, added url
AlexanderVanOyen Mar 9, 2024
31b22aa
Merge remote-tracking branch 'origin/api_routes-implementation' into …
AlexanderVanOyen Mar 9, 2024
fa9f422
new url for creating project, added field to project model
AlexanderVanOyen Mar 9, 2024
a5a694e
Merge branch 'api_routes-implementation' into 17-backend-testing
PJDeSmijter Mar 9, 2024
25e4146
course permissions fixed
ReinhardDP Mar 9, 2024
75b7b36
Merge branch 'api_routes-implementation' of github.com:SELab-2/UGent-…
ReinhardDP Mar 9, 2024
48e7d2c
Merge branch 'api_routes-implementation' into 17-backend-testing
PJDeSmijter Mar 9, 2024
0ddd30c
GET requests support for groups+submissions, but error for groups whe…
RunoBoy Mar 10, 2024
b14d75b
removed deadline temporary to find bug
RunoBoy Mar 10, 2024
ca408dd
without deadline in project seems to work
RunoBoy Mar 10, 2024
2f9a381
deadline for projects fixed
RunoBoy Mar 10, 2024
5499f9d
courses tests, 2 still to be fixed
PJDeSmijter Mar 10, 2024
b13edd1
Merge branch 'develop' into 17-backend-testing
PJDeSmijter Mar 10, 2024
82c29e2
Everything fixed to create submissions
RunoBoy Mar 10, 2024
c5fcf3e
API works now, fixed URLs and the requests
AlexanderVanOyen Mar 10, 2024
2769029
Merge branch 'api_routes-implementation' into 17-backend-testing
PJDeSmijter Mar 10, 2024
8cbc51f
list fixed
AlexanderVanOyen Mar 10, 2024
77274f8
Merge branch 'api_routes-implementation' into 17-backend-testing
PJDeSmijter Mar 10, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion backend/pigeonhole/apps/courses/migrations/0001_initial.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
# Generated by Django 5.0.2 on 2024-03-02 21:03
# Generated by Django 5.0.3 on 2024-03-10 16:00

from django.db import migrations, models


class Migration(migrations.Migration):

initial = True

dependencies = [
Expand Down
30 changes: 30 additions & 0 deletions backend/pigeonhole/apps/courses/permissions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
from rest_framework import permissions
from backend.pigeonhole.apps.users.models import Teacher, Student


class CourseUserPermissions(permissions.BasePermission):
def has_permission(self, request, view):
if request.user.is_superuser:
return True
if Teacher.objects.filter(id=request.user.id).exists():
return True
elif Student.objects.filter(id=request.user.id).exists():
return view.action in ['list', 'retrieve']
return False

def has_object_permission(self, request, view, obj):
if request.user.is_superuser:
return True
if Teacher.objects.filter(id=request.user.id).exists():
if request.user.is_admin:
return True
# Check if the teacher is assigned to the course
elif request.user.course.filter(id=obj.id).exists():
return True
return view.action in ['list', 'retrieve']
elif isinstance(request.user, Student):
return view.action in ['list', 'retrieve']

return False


44 changes: 44 additions & 0 deletions backend/pigeonhole/apps/courses/views.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
from rest_framework import viewsets, status
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response

from .models import Course, CourseSerializer
from .permissions import CourseUserPermissions


class CourseViewSet(viewsets.ModelViewSet):
queryset = Course.objects.all()
serializer_class = CourseSerializer
permission_classes = [IsAuthenticated, CourseUserPermissions]

def create(self, request, *args, **kwargs):
serializer = CourseSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

def update(self, request, *args, **kwargs):
course_id = kwargs.get('pk')
course = Course.objects.get(pk=course_id)
serializer = CourseSerializer(course, data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_200_OK)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

def destroy(self, request, *args, **kwargs):
course_id = kwargs.get('pk')
course = Course.objects.get(pk=course_id)
course.delete()
return Response(status=status.HTTP_204_NO_CONTENT)

def list(self, request, *args, **kwargs):
serializer = CourseSerializer(self.queryset, many=True)
return Response(serializer.data, status=status.HTTP_200_OK)

def retrieve(self, request, *args, **kwargs):
course_id = kwargs.get('pk')
course = Course.objects.get(pk=course_id)
serializer = CourseSerializer(course, many=False)
return Response(serializer.data, status=status.HTTP_200_OK)
3 changes: 2 additions & 1 deletion backend/pigeonhole/apps/groups/migrations/0001_initial.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
# Generated by Django 5.0.2 on 2024-03-02 21:03
# Generated by Django 5.0.3 on 2024-03-10 16:00

import django.db.models.deletion
from django.db import migrations, models


class Migration(migrations.Migration):

initial = True

dependencies = [
Expand Down
3 changes: 2 additions & 1 deletion backend/pigeonhole/apps/groups/migrations/0002_initial.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
# Generated by Django 5.0.2 on 2024-03-02 21:03
# Generated by Django 5.0.3 on 2024-03-10 16:00

from django.db import migrations, models


class Migration(migrations.Migration):

initial = True

dependencies = [
Expand Down
2 changes: 1 addition & 1 deletion backend/pigeonhole/apps/groups/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -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"]
fields = ["group_id", "group_nr", "final_score", "project_id", "student", "feedback"]
26 changes: 26 additions & 0 deletions backend/pigeonhole/apps/groups/views.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
from rest_framework import viewsets, status
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response

from backend.pigeonhole.apps.groups.models import Group, GroupSerializer


class GroupViewSet(viewsets.ModelViewSet):
queryset = Group.objects.all()
serializer_class = GroupSerializer
permission_classes = [IsAuthenticated]

def perform_create(self, serializer):
serializer.save(user=self.request.user)

def list(self, request, *args, **kwargs):
serializer = GroupSerializer(self.queryset, many=True)
return Response(serializer.data, status=status.HTTP_200_OK)

def create(self, request, *args, **kwargs):
serializer = GroupSerializer(data=request.data)
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)
13 changes: 6 additions & 7 deletions backend/pigeonhole/apps/projects/migrations/0001_initial.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
# Generated by Django 5.0.2 on 2024-03-02 21:03
# Generated by Django 5.0.3 on 2024-03-10 16:00

import django.db.models.deletion
from django.db import migrations, models


class Migration(migrations.Migration):

initial = True

dependencies = [
Expand All @@ -26,27 +27,25 @@ class Migration(migrations.Migration):
name='ForbiddenExtension',
fields=[
('extension_id', models.BigAutoField(primary_key=True, serialize=False)),
('extension', models.IntegerField()),
('extension', models.CharField(max_length=512)),
('project_id', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='projects.project')),
],
),
migrations.CreateModel(
name='Conditions',
fields=[
('condition_id', models.BigAutoField(primary_key=True, serialize=False)),
('condition', models.CharField(max_length=256)),
('deadline', models.DateTimeField()),
('condition', models.TextField(max_length=256)),
('test_file_location', models.CharField(max_length=512, null=True)),
('test_file_type', models.CharField(max_length=256, null=True)),
('submission_id', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE,
to='projects.project')),
('submission_id', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='projects.project')),
],
),
migrations.CreateModel(
name='AllowedExtension',
fields=[
('extension_id', models.BigAutoField(primary_key=True, serialize=False)),
('extension', models.IntegerField()),
('extension', models.CharField(max_length=512)),
('project_id', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='projects.project')),
],
),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Generated by Django 5.0.3 on 2024-03-10 16:09

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('projects', '0001_initial'),
]

operations = [
migrations.AddField(
model_name='project',
name='deadline',
field=models.DateTimeField(blank=True, null=True),
),
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# Generated by Django 5.0.3 on 2024-03-09 21:26

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('projects', '0001_initial'),
]

operations = [
migrations.RemoveField(
model_name='conditions',
name='deadline',
),
migrations.AddField(
model_name='project',
name='deadline',
field=models.DateTimeField(null=True),
),
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Generated by Django 5.0.3 on 2024-03-10 16:09

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('projects', '0002_project_deadline'),
]

operations = [
migrations.AlterField(
model_name='project',
name='deadline',
field=models.DateTimeField(null=True),
),
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Generated by Django 5.0.3 on 2024-03-10 16:11

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('projects', '0003_alter_project_deadline'),
]

operations = [
migrations.AlterField(
model_name='project',
name='deadline',
field=models.DateTimeField(blank=True, null=True),
),
]
15 changes: 8 additions & 7 deletions backend/pigeonhole/apps/projects/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,49 +6,50 @@

# Create your models here.
class Project(models.Model):
objects = models.Manager()
project_id = models.BigAutoField(primary_key=True)
course_id = models.ForeignKey(Course, on_delete=models.CASCADE)
name = models.CharField(max_length=256)
description = models.TextField()
deadline = models.DateTimeField(null=True, blank=True)
visible = models.BooleanField(default=False)


class ProjectSerializer(serializers.ModelSerializer):
class Meta:
model = Project
fields = ['project_id', 'course_id', 'name', 'description', 'deadline', 'visible']
fields = ['project_id', 'course_id', 'name', 'description', 'visible', 'deadline']


class Conditions(models.Model):
condition_id = models.BigAutoField(primary_key=True)
submission_id = models.ForeignKey(Project, on_delete=models.CASCADE)
condition = models.CharField(max_length=256)
deadline = models.DateTimeField()
condition = models.TextField(max_length=256)
test_file_location = models.CharField(max_length=512, null=True)
test_file_type = models.CharField(max_length=256, null=True)

objects = models.Manager()

@property
def get_forbidden_extensions(self):
return ForbiddenExtension.objects.filter(project_id=self.submission_id)
return ForbiddenExtension.objects.filter(project_id=self.project_id)

@property
def get_allowed_extensions(self):
return AllowedExtension.objects.filter(project_id=self.submission_id)
return AllowedExtension.objects.filter(project_id=self.project_id)


class AllowedExtension(models.Model):
extension_id = models.BigAutoField(primary_key=True)
project_id = models.ForeignKey(Project, on_delete=models.CASCADE)
extension = models.IntegerField()
extension = models.CharField(max_length=512)

objects = models.Manager()


class ForbiddenExtension(models.Model):
extension_id = models.BigAutoField(primary_key=True)
project_id = models.ForeignKey(Project, on_delete=models.CASCADE)
extension = models.IntegerField()
extension = models.CharField(max_length=512)

objects = models.Manager()
23 changes: 23 additions & 0 deletions backend/pigeonhole/apps/projects/permissions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
from rest_framework import permissions
from backend.pigeonhole.apps.users.models import Teacher, Student


class CanAccessProject(permissions.BasePermission):
# Custom permission class to determine if the currect user has access
# to the project data.
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
return False
Loading
Loading