Skip to content

Commit

Permalink
Merge branch 'frontend' of https://github.com/SELab-2/UGent-4 into fr…
Browse files Browse the repository at this point in the history
…ontend
  • Loading branch information
friedrecursion committed May 19, 2024
2 parents 233f180 + c440227 commit 718d0ad
Show file tree
Hide file tree
Showing 110 changed files with 12,215 additions and 4,619 deletions.
Binary file modified .coverage
Binary file not shown.
5 changes: 2 additions & 3 deletions .github/workflows/django.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,9 @@ name: Django CI

on:
push:

branches: [ "develop", "tests", "main" ]
branches: [ "develop", "tests", "main" ]
pull_request:
branches: [ "develop", "tests", "main" ]
branches: [ "develop", "tests", "main" ]


jobs:
Expand Down
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,8 @@ htmlcov
data
uploads
/data/
cypress/screenshots
/package-lock.json
/frontend/package-lock.json
/frontend/frontend/package-lock.json
package-lock.json
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,9 @@ Er kan niet gepushed worden als er nog linting errors aanwezig zijn.

### Testen:

- WIP
Je kan visueel in de browser de testen volgen door het commando `npm run cypress-open` te runnen. Je zal dan ook de keuze krijgen om te kiezen tussen E2E testen of component testen te volgen.

`npm run cypress-e2e` en `cypress-component` zullen de e2e testen en de component testen runnen en in de terminal tonen of ze slagen.

# Backend

Expand Down
5 changes: 3 additions & 2 deletions api/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,16 @@
from api.models.vak import Vak
from api.models.groep import Groep
from api.models.project import Project
from api.models.indiening import Indiening, IndieningBestand
from api.models.indiening import Indiening
from api.models.score import Score
from api.models.restrictie import Restrictie
from api.models.template import Template

admin.site.register(Gebruiker)
admin.site.register(Vak)
admin.site.register(Groep)
admin.site.register(Project)
admin.site.register(Indiening)
admin.site.register(Score)
admin.site.register(IndieningBestand)
admin.site.register(Restrictie)
admin.site.register(Template)
11 changes: 11 additions & 0 deletions api/middleware.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,3 +69,14 @@ def __call__(self, request):
serializer.save()

return self.get_response(request)


class DisableCSRFMiddleware(object):

def __init__(self, get_response):
self.get_response = get_response

def __call__(self, request):
setattr(request, "_dont_enforce_csrf_checks", True)
response = self.get_response(request)
return response
57 changes: 26 additions & 31 deletions api/models/indiening.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@
from api.docker.python_entrypoint import run_tests_on
from threading import Thread
from django.db import transaction
import re
import zipfile
import os
from django.core.files.storage import default_storage
from django.core.files.base import ContentFile

from api.models.restrictie import Restrictie
from api.utils import send_indiening_confirmation_mail


STATUS_CHOICES = (
Expand All @@ -29,6 +29,9 @@ def upload_to(instance, filename):
Returns:
str: Het pad waar het bestand moet worden opgeslagen.
"""
# Use a placeholder for the initial save
if instance.indiening_id is None:
return f"data/indieningen/temp/{filename}"
return f"data/indieningen/indiening_{instance.indiening_id}/{filename}"


Expand All @@ -55,39 +58,30 @@ class Indiening(models.Model):
indiening_id = models.AutoField(primary_key=True)
groep = models.ForeignKey("Groep", on_delete=models.CASCADE)
tijdstip = models.DateTimeField(auto_now_add=True)
bestand = models.FileField(upload_to=upload_to)
status = models.IntegerField(default=0, choices=STATUS_CHOICES)
result = models.TextField(default="", blank=True)
artefacten = models.FileField(blank=True)

def __str__(self):
return str(self.indiening_id)

def save(self, *args, **kwargs):
# First save to generate the indiening_id if it doesn't exist
if not self.indiening_id:
super(Indiening, self).save(*args, **kwargs)

class IndieningBestand(models.Model):
"""
Model voor een bestand dat aan een indiening is gekoppeld.
Fields:
indiening_bestand_id (AutoField): Een automatisch gegenereerd veld dat fungeert als
de primaire sleutel voor het bestand.
indiening (ForeignKey): Een ForeignKey relatie met het 'Indiening' model,
waarmee wordt aangegeven tot welke indiening dit bestand behoort.
Als de bijbehorende indiening wordt verwijderd,
wordt ook het bijbehorende bestand verwijderd.
bestand (FileField): Een veld voor het uploaden van het bestand.
Methods:
__str__(): Geeft een representatie van het model als een string terug, die de bestandsnaam bevat.
"""

indiening_bestand_id = models.AutoField(primary_key=True)
indiening = models.ForeignKey(
Indiening, related_name="indiening_bestanden", on_delete=models.CASCADE
)
bestand = models.FileField(upload_to=upload_to)
# Update the bestand path if it's still using the temporary path
if "temp" in self.bestand.name:
old_file = self.bestand
new_path = self.bestand.name.replace(
"temp", f"indiening_{self.indiening_id}"
)
default_storage.save(new_path, ContentFile(old_file.read()))
old_file.storage.delete(old_file.name)
self.bestand.name = new_path

def __str__(self):
return str(self.bestand.name)
super(Indiening, self).save(*args, **kwargs)


def run_tests_async(instance):
Expand All @@ -101,14 +95,14 @@ def run_tests_async(instance):
project_id = instance.groep.project.project_id
result = run_tests_on(indiening_id, project_id)


with transaction.atomic():
instance.status = -1 if "FAIL" in result else 1
instance.result = result
instance.artefacten = f'data/indieningen/indiening_{indiening_id}/artefacten.zip'
instance.artefacten = (
f"data/indieningen/indiening_{indiening_id}/artefacten.zip"
)
instance.save()


send_indiening_confirmation_mail(instance)


@receiver(post_save, sender=Indiening)
Expand All @@ -130,6 +124,7 @@ def indiening_post_init(sender, instance, created, **kwargs):
instance.status = 1
instance.result = "No tests: OK"
instance.save()
send_indiening_confirmation_mail(instance)
else:
thread = Thread(target=run_tests_async, args=(instance,))
thread.start()
2 changes: 1 addition & 1 deletion api/models/project.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ class Project(models.Model):
project_id = models.AutoField(primary_key=True)
titel = models.CharField(max_length=100)
beschrijving = models.TextField()
opgave_bestand = models.FileField(upload_to=upload_to)
opgave_bestand = models.FileField(upload_to=upload_to, blank=True)
vak = models.ForeignKey(Vak, on_delete=models.CASCADE)
deadline = models.DateTimeField(null=True, blank=True)
extra_deadline = models.DateTimeField(null=True, blank=True)
Expand Down
28 changes: 28 additions & 0 deletions api/models/template.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
from django.db import models
from django.contrib.auth.models import User


def upload_to(instance, filename):
"""
Functie om het pad te genereren waar het bestand wordt opgeslagen.
Args:
instance: De huidige instantie van het model.
filename (str): De oorspronkelijke bestandsnaam.
Returns:
str: Het pad waar het bestand moet worden opgeslagen.
"""
return f"data/templates/gebruiker_{instance.user.id}/{filename}"


class Template(models.Model):

template_id = models.AutoField(primary_key=True)
user = models.ForeignKey(
User, related_name="template_user", on_delete=models.CASCADE
)
bestand = models.FileField(upload_to=upload_to)

def __str__(self):
return str(self.bestand.name)
4 changes: 3 additions & 1 deletion api/serializers/gebruiker.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,9 @@ def update(self, instance, validated_data):
validate_lesgever_change(instance)
instance.is_lesgever = is_lesgever

gepinde_vakken = validated_data.pop("gepinde_vakken", instance.gepinde_vakken.all())
gepinde_vakken = validated_data.pop(
"gepinde_vakken", instance.gepinde_vakken.all()
)
validate_gepinde_vakken(instance, gepinde_vakken)
instance.gepinde_vakken.set(gepinde_vakken)

Expand Down
21 changes: 2 additions & 19 deletions api/serializers/indiening.py
Original file line number Diff line number Diff line change
@@ -1,20 +1,5 @@
from rest_framework import serializers
from api.models.indiening import Indiening, IndieningBestand


class IndieningBestandSerializer(serializers.ModelSerializer):
"""
Serializer voor het serialiseren en deserialiseren van IndieningBestand objecten.
Fields:
Meta.model (IndieningBestand): Het model waarop de serializer is gebaseerd.
Meta.fields (tuple): De velden die moeten worden opgenomen in de serializer. Hier worden alle velden opgenomen.
"""

class Meta:
model = IndieningBestand
fields = "__all__"
from api.models.indiening import Indiening


class IndieningSerializer(serializers.ModelSerializer):
Expand All @@ -27,16 +12,14 @@ class IndieningSerializer(serializers.ModelSerializer):
"""

indiening_bestanden = IndieningBestandSerializer(many=True, read_only=True)

class Meta:
model = Indiening
fields = [
"indiening_id",
"groep",
"tijdstip",
"bestand",
"status",
"result",
"indiening_bestanden",
"artefacten",
]
32 changes: 30 additions & 2 deletions api/serializers/project.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
from api.models.project import Project
from django.utils import timezone
from api.serializers.restrictie import RestrictieSerializer
from api.serializers.groep import GroepSerializer


class ProjectSerializer(serializers.ModelSerializer):
Expand Down Expand Up @@ -51,14 +52,15 @@ def create(self, validated_data):
Returns:
Project: Het aangemaakte project.
"""
deadline = validated_data.pop("deadline")
extra_deadline = validated_data.pop("extra_deadline")
deadline = validated_data.pop("deadline", None)
extra_deadline = validated_data.pop("extra_deadline", None)
validate_deadlines(deadline, extra_deadline)

project = Project.objects.create(**validated_data)
project.deadline = deadline
project.extra_deadline = extra_deadline
project.save()
create_groepen(project)
return project

def update(self, instance, validated_data):
Expand All @@ -72,6 +74,9 @@ def update(self, instance, validated_data):
Returns:
Project: Het bijgewerkte project.
"""
validated_data.pop("max_groep_grootte")
validated_data.pop("project_groep")

deadline = validated_data.pop("deadline", instance.deadline)
extra_deadline = validated_data.pop("extra_deadline", instance.extra_deadline)
validate_deadlines(deadline, extra_deadline)
Expand All @@ -86,6 +91,29 @@ def update(self, instance, validated_data):
return instance


def create_groepen(instance):
if instance.max_groep_grootte == 1 or instance.student_groep:
for student in instance.vak.studenten.all():
try:
serializer = GroepSerializer(
data={"studenten": [student], "project": instance.project_id}
)
if serializer.is_valid():
serializer.save()
except Exception:
pass
else:
for _ in range(len(instance.vak.studenten.all())//instance.max_groep_grootte + 1):
try:
serializer = GroepSerializer(
data={"studenten": [], "project": instance.project_id}
)
if serializer.is_valid():
serializer.save()
except Exception:
pass


def validate_deadlines(deadline, extra_deadline):
"""
Controleert of de opgegeven deadline in de toekomst ligt.
Expand Down
17 changes: 17 additions & 0 deletions api/serializers/template.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
from rest_framework import serializers
from api.models.template import Template


class TemplateSerializer(serializers.ModelSerializer):
"""
Serializer voor het serialiseren en deserialiseren van IndieningBestand objecten.
Fields:
Meta.model (IndieningBestand): Het model waarop de serializer is gebaseerd.
Meta.fields (tuple): De velden die moeten worden opgenomen in de serializer. Hier worden alle velden opgenomen.
"""

class Meta:
model = Template
fields = "__all__"
18 changes: 17 additions & 1 deletion api/serializers/vak.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from rest_framework import serializers
from api.models.vak import Vak
from api.models.project import Project
from api.models.groep import Groep
from api.serializers.groep import GroepSerializer


Expand Down Expand Up @@ -65,6 +66,7 @@ def update(self, instance, validated_data):

return instance


def add_students_to_group(instance):
"""
Voeg studenten automatisch toe aan een projectgroep als het een individueel project is.
Expand All @@ -77,12 +79,26 @@ def add_students_to_group(instance):
if project.student_groep or project.max_groep_grootte == 1:
for student in instance.studenten.all():
try:
serializer = GroepSerializer(data={"studenten": [student], "project": project.project_id})
serializer = GroepSerializer(
data={"studenten": [student], "project": project.project_id}
)
if serializer.is_valid():
serializer.save()
except Exception:
pass

else:
groepen = Groep.objects.filter(project=project.project_id)
nieuwe_groepen = len(instance.studenten.all())//project.max_groep_grootte + 1 - len(groepen)
for _ in range(nieuwe_groepen):
try:
serializer = GroepSerializer(
data={"studenten": [], "project": project.project_id}
)
if serializer.is_valid():
serializer.save()
except Exception:
pass


def validate_students_teachers(students_data, teachers_data):
Expand Down
Loading

0 comments on commit 718d0ad

Please sign in to comment.