diff --git a/.coverage b/.coverage new file mode 100644 index 00000000..4500b425 Binary files /dev/null and b/.coverage differ diff --git a/.github/workflows/django.yml b/.github/workflows/django.yml new file mode 100644 index 00000000..dd5fa996 --- /dev/null +++ b/.github/workflows/django.yml @@ -0,0 +1,26 @@ +name: Django CI + +on: + push: + branches: [ "develop" ] + pull_request: + branches: [ "develop" ] + +jobs: + build: + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v3 + - name: Set up Python 3.10 + uses: actions/setup-python@v3 + with: + python-version: '3.10' + - name: Install Dependencies + run: | + python3 -m pip install --upgrade pip + pip install -r requirements.txt + - name: Run Tests + run: | + python manage.py test diff --git a/.gitignore b/.gitignore index f68c13ed..9b92bf8e 100644 --- a/.gitignore +++ b/.gitignore @@ -3,4 +3,5 @@ projectenv /venv/ **/__pycache__/ migrations -.env \ No newline at end of file +.env +htmlcov diff --git a/api/migrations/__pycache__/0001_initial.cpython-311.pyc b/api/migrations/__pycache__/0001_initial.cpython-311.pyc index 54bc248d..ed1272db 100644 Binary files a/api/migrations/__pycache__/0001_initial.cpython-311.pyc and b/api/migrations/__pycache__/0001_initial.cpython-311.pyc differ diff --git a/api/migrations/__pycache__/0002_remove_student_id_remove_student_name_and_more.cpython-311.pyc b/api/migrations/__pycache__/0002_remove_student_id_remove_student_name_and_more.cpython-311.pyc index 63bf54d7..52dfba93 100644 Binary files a/api/migrations/__pycache__/0002_remove_student_id_remove_student_name_and_more.cpython-311.pyc and b/api/migrations/__pycache__/0002_remove_student_id_remove_student_name_and_more.cpython-311.pyc differ diff --git a/api/migrations/__pycache__/0003_alter_student_subjects.cpython-311.pyc b/api/migrations/__pycache__/0003_alter_student_subjects.cpython-311.pyc index b1655e08..ead4b8af 100644 Binary files a/api/migrations/__pycache__/0003_alter_student_subjects.cpython-311.pyc and b/api/migrations/__pycache__/0003_alter_student_subjects.cpython-311.pyc differ diff --git a/api/migrations/__pycache__/0004_alter_student_subjects.cpython-311.pyc b/api/migrations/__pycache__/0004_alter_student_subjects.cpython-311.pyc index 808e7a49..0522acb5 100644 Binary files a/api/migrations/__pycache__/0004_alter_student_subjects.cpython-311.pyc and b/api/migrations/__pycache__/0004_alter_student_subjects.cpython-311.pyc differ diff --git a/api/migrations/__pycache__/0005_alter_vak_teachers.cpython-311.pyc b/api/migrations/__pycache__/0005_alter_vak_teachers.cpython-311.pyc index c9e72964..44e54ac0 100644 Binary files a/api/migrations/__pycache__/0005_alter_vak_teachers.cpython-311.pyc and b/api/migrations/__pycache__/0005_alter_vak_teachers.cpython-311.pyc differ diff --git a/api/migrations/__pycache__/0006_remove_lesgever_id_alter_lesgever_lesgever_id.cpython-311.pyc b/api/migrations/__pycache__/0006_remove_lesgever_id_alter_lesgever_lesgever_id.cpython-311.pyc index 83b31ae0..24246888 100644 Binary files a/api/migrations/__pycache__/0006_remove_lesgever_id_alter_lesgever_lesgever_id.cpython-311.pyc and b/api/migrations/__pycache__/0006_remove_lesgever_id_alter_lesgever_lesgever_id.cpython-311.pyc differ diff --git a/api/migrations/__pycache__/0007_alter_lesgever_subjects_alter_vak_teachers.cpython-311.pyc b/api/migrations/__pycache__/0007_alter_lesgever_subjects_alter_vak_teachers.cpython-311.pyc index 656b5d5d..2f9ae735 100644 Binary files a/api/migrations/__pycache__/0007_alter_lesgever_subjects_alter_vak_teachers.cpython-311.pyc and b/api/migrations/__pycache__/0007_alter_lesgever_subjects_alter_vak_teachers.cpython-311.pyc differ diff --git a/api/migrations/__pycache__/__init__.cpython-311.pyc b/api/migrations/__pycache__/__init__.cpython-311.pyc index 4b354942..c48f5d71 100644 Binary files a/api/migrations/__pycache__/__init__.cpython-311.pyc and b/api/migrations/__pycache__/__init__.cpython-311.pyc differ diff --git a/api/models.py b/api/models.py new file mode 100644 index 00000000..94479ebc --- /dev/null +++ b/api/models.py @@ -0,0 +1,67 @@ +from django.db import models +from django.contrib.auth.models import User + + +class Student(models.Model): + user = models.OneToOneField(User, on_delete=models.CASCADE,primary_key=True,default=None) + subjects = models.ManyToManyField('Vak', related_name='students_enrolled') + + def __str__(self): + return self.user.first_name + +class Lesgever(models.Model): + lesgever_id = models.AutoField(primary_key=True) + name = models.CharField(max_length=100) + email = models.EmailField(default=False) + subjects = models.ManyToManyField('Vak', related_name='lesgevers_enrolled', blank=True) + is_admin = models.BooleanField(default=False) + + def __str__(self): + return self.name + +class Vak(models.Model): + vak_id = models.AutoField(primary_key=True) + name = models.CharField(max_length=100) + students = models.ManyToManyField('Student', related_name='subjects_enrolled', blank=True) + teachers = models.ManyToManyField('Lesgever', related_name='subjects_teachers') + projects = models.ManyToManyField('Project', related_name='subjects_projects', blank=True) + + def __str__(self): + return self.name + +class Groep(models.Model): + group_id = models.AutoField(primary_key=True) + students = models.ManyToManyField('Student', related_name='groups_students', blank=True) + project = models.ForeignKey('Project', on_delete=models.CASCADE) + + def __str__(self): + return f"Group {self.group_id}" + +class Project(models.Model): + project_id = models.AutoField(primary_key=True) + titel = models.CharField(max_length=100) + description = models.TextField() + opgavebestanden = models.FileField(upload_to='opgave/') + vak = models.ForeignKey(Vak, on_delete=models.CASCADE) + deadline = models.DateTimeField(null=True) + # indiening restricties + + def __str__(self): + return self.titel + +class Indiening(models.Model): + indiening_id = models.AutoField(primary_key=True) + indiener = models.ForeignKey('Groep', on_delete=models.CASCADE) + indieningsbestanden = models.FileField(upload_to='uploads/') + tijdstip = models.DateTimeField(null=False) + + def __str__(self): + return self.tijdstip + +class Score(models.Model): + score = models.SmallIntegerField() + indiening = models.ForeignKey('Indiening', on_delete=models.CASCADE) + groep = models.ForeignKey('Groep', on_delete=models.CASCADE) + + def __str__(self): + return self.score diff --git a/api/serializers.py b/api/serializers.py new file mode 100644 index 00000000..b349b04a --- /dev/null +++ b/api/serializers.py @@ -0,0 +1,120 @@ +from datetime import datetime +from rest_framework import serializers +from rest_framework.renderers import JSONRenderer +import io +from rest_framework.parsers import JSONParser + +from .models import Student, Lesgever, Vak, Groep, Project, Indiening, Score + +class StudentSerializer(serializers.ModelSerializer): + class Meta: + model = Student + fields = '__all__' + + def create(self, validated_data): + return Student.objects.create(**validated_data) + + def update(self, instance, validated_data): + # Update the subjects list + subjects_data = validated_data.pop('subjects', None) + if subjects_data is not None: + instance.subjects.clear() # Remove existing subjects + for subject_data in subjects_data: + instance.subjects.add(subject_data) + + instance.save() + return instance + +class LesgeverSerializer(serializers.ModelSerializer): + class Meta: + model = Lesgever + fields = '__all__' + + def create(self, validated_data): + return Lesgever.objects.create(**validated_data) + + def update(self, instance, validated_data): + instance.name = validated_data.get('name', instance.name) + # Update other fields similarly + instance.save() + return instance + +class VakSerializer(serializers.ModelSerializer): + class Meta: + model = Vak + fields = '__all__' + + def create(self, validated_data): + return Vak.objects.create(**validated_data) + + def update(self, instance, validated_data): + instance.name = validated_data.get('name', instance.name) + # Update other fields similarly + instance.save() + return instance + +class GroepSerializer(serializers.ModelSerializer): + class Meta: + model = Groep + fields = '__all__' + + def create(self, validated_data): + return Groep.objects.create(**validated_data) + + def update(self, instance, validated_data): + # Implement update method for Groep model + pass + +class ProjectSerializer(serializers.ModelSerializer): + class Meta: + model = Project + fields = '__all__' + + def create(self, validated_data): + return Project.objects.create(**validated_data) + + def update(self, instance, validated_data): + # Implement update method for Project model + pass + +class IndieningSerializer(serializers.ModelSerializer): + class Meta: + model = Indiening + fields = '__all__' + + def create(self, validated_data): + return Indiening.objects.create(**validated_data) + + def update(self, instance, validated_data): + # Implement update method for Indiening model + pass + +class ScoreSerializer(serializers.ModelSerializer): + class Meta: + model = Score + fields = '__all__' + + def create(self, validated_data): + return Score.objects.create(**validated_data) + + def update(self, instance, validated_data): + # Implement update method for Score model + pass + + + +# gebruiksvoorbeelden + +# serializing objects +#serializer = ProfSerializer(prof) +#serializer.data +#json = JSONRenderer().render(serializer.data) +#json + +#deserializing objects +#stream = io.BytesIO(json) +#data = JSONParser().parse(stream) +#serializer = ProfSerializer(data=data) +#serializer.is_valid() +#serializer.validated_data +#serializer.save() diff --git a/api/settings.py b/api/settings.py index 5960c2f8..344fee43 100644 --- a/api/settings.py +++ b/api/settings.py @@ -54,7 +54,7 @@ 'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware', - 'api.middleware.RedirectAnonymousUserMiddleware', + #'api.middleware.RedirectAnonymousUserMiddleware', ] ROOT_URLCONF = 'api.urls' diff --git a/api/setup.cfg b/api/setup.cfg new file mode 100644 index 00000000..33af1ca5 --- /dev/null +++ b/api/setup.cfg @@ -0,0 +1,3 @@ +[flake8] +exclude = .git,*migrations,*venv* +max-line-length = 119 \ No newline at end of file diff --git a/api/tests.py b/api/tests.py new file mode 100644 index 00000000..a293579a --- /dev/null +++ b/api/tests.py @@ -0,0 +1,12 @@ +from django.test import TestCase + +class ModelTesting(TestCase): + + def setUp(self): + pass + #bv: self.api = Score.objects.create(score=10, ...) + + def test_post_model(self): + #d = self.api + #self.assertTrue(isinstance(d, Score)) + self.assertTrue(True) \ No newline at end of file diff --git a/api/urls.py b/api/urls.py index 1eea2062..9b939fbe 100644 --- a/api/urls.py +++ b/api/urls.py @@ -18,12 +18,13 @@ from django.urls import path, include from .views.views import microsoft_association, login_redirect -from .views.student import student_list +from .views.student import student_list, student_detail urlpatterns = [ path('.well-known/microsoft-identity-association.json', microsoft_association), path('admin/', admin.site.urls), path('oauth2/', include('django_auth_adfs.urls')), path('login_redirect', login_redirect), - path('api/studenten', student_list) + path('api/studenten', student_list), + path('api/studenten/', student_detail) ] diff --git a/api/utils.py b/api/utils.py index 7504ceac..93852bbb 100644 --- a/api/utils.py +++ b/api/utils.py @@ -2,11 +2,6 @@ from django.http import JsonResponse import requests -ERRORS = { - 'no_perm': 'You do not have permission to view this data', - 'generic': 'There was an error' -} - def get_graph_token(): """ @@ -27,9 +22,4 @@ def get_graph_token(): response = requests.post(url=url, headers=headers, data=data) return response.json() except: - return None - - - -def json_error(error_code): - return JsonResponse({'error': {'message': ERRORS.get(error_code, ERRORS['generic'])}}) \ No newline at end of file + return None \ No newline at end of file diff --git a/api/views/student.py b/api/views/student.py index 8f2635bd..aa59e299 100644 --- a/api/views/student.py +++ b/api/views/student.py @@ -4,9 +4,14 @@ from rest_framework import status +<<<<<<< HEAD from api.models.student import Student from api.serializers.student import StudentSerializer from ..utils import json_error +======= +from ..models import Student +from ..serializers.student import StudentSerializer +>>>>>>> develop @api_view(['GET', 'POST']) @@ -14,12 +19,13 @@ def student_list(request): if request.method == 'GET': students = Student.objects.all() serializer = StudentSerializer(students, many=True) - return JsonResponse({'studenten': serializer.data}) + return Response(serializer.data) elif request.method == 'POST': serializer = StudentSerializer(data=request.data) if serializer.is_valid(): serializer.save() return Response(serializer.data, status=status.HTTP_201_CREATED) +<<<<<<< HEAD """if request.user.is_superuser: @@ -29,3 +35,24 @@ def student_list(request): else: return json_error('no_perm')""" +======= + return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) + + +@api_view(['GET', 'PUT']) +def student_detail(request, id): + try: + student = Student.objects.get(pk=id) + except Student.DoesNotExist: + return Response(status=status.HTTP_404_NOT_FOUND) + + if request.method == 'GET': + serializer = StudentSerializer(student) + return Response(serializer.data) + elif request.method == 'PUT': + serializer = StudentSerializer(student, data=request.data) + if serializer.is_valid(): + serializer.save() + return Response(serializer.data) + return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) +>>>>>>> develop diff --git a/api/views/views.py b/api/views/views.py index 587ae2f9..84f46150 100644 --- a/api/views/views.py +++ b/api/views/views.py @@ -11,7 +11,7 @@ def login_redirect(request): return HttpResponse(f"Logged in as {request.user.first_name} {request.user.last_name}, with email: {request.user.username} \nWith token: {graph_token['access_token']}") - return redirect("https://sel2-4.be") + return redirect("https://sel2-4.ugent.be") def microsoft_association(request): return JsonResponse({"associatedApplications": [{ "applicationId": "239ce609-e362-4cf6-919f-97e6935ef5f5" }]}) \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index 515b3a9b..0e1dbf06 100644 --- a/requirements.txt +++ b/requirements.txt @@ -4,3 +4,5 @@ psycopg2-binary djangorestframework~=3.14.0 django-auth-adfs python-dotenv +coverage +flake8