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

Course search #231

Merged
merged 15 commits into from
Apr 4, 2024
82 changes: 74 additions & 8 deletions backend/api/fixtures/courses.yaml
Original file line number Diff line number Diff line change
@@ -1,21 +1,87 @@
- model: api.course
pk: 1
fields:
name: Math
name: "Parallel and Distributed Software Systems"
academic_startyear: 2023
description: Math course
description: "Deze cursus brengt de studenten de verschillende aspecten aan van het ontwerp en
implementatie van gedistribueerde software. De cursus geeft de studenten een state-of-the-art
overzicht van parallelle en cloud-gebaseerde systemen, het ontwerp van parallelle software,
software engineering specifiek voor deze applicaties en het beheren van hoog-performante en
cloud-gebaseerde systemen. De nadruk ligt op de algoritmische aspecten, software aspecten
en op de verschillende programmeermodellen. Hardware en architectuur aspecten worden
slechts aangehaald in de mate noodzakelijk voor het begrijpen van de impact van software
performantie."
parent_course: null
faculty: "Ingenieurswetenschappen_Architectuur"
- model: api.course
pk: 2
fields:
name: Sel2
name: "Wiskundige modellering in de ingenieurswetenschappen"
academic_startyear: 2023
description: Software course
parent_course: 3
description: "De basiswiskunde en de eruit voortspruitende wiskundige modellen spelen een prominente rol
in de ingenieurswetenschappen. Wiskunde maakt immers de kwantitatieve aanpak mogelijk die
eigen is aan de ingenieurspraktijk, en wiskundig modelleren ligt aan de basis van de meeste
courante technologische innovaties."
parent_course: null
faculty: "Wetenschappen"
- model: api.course
pk: 3
fields:
name: Sel1
academic_startyear: 2022
description: Software course
name: "Software Engineering Lab 2"
academic_startyear: 2023
description: "Het ontwerpen en ontwikkelen van een groot software-project in teamverband waarbij
vaardigheden en kennis uit verschillende opleidingsonderdelen moeten worden toegepast. De
uitvoering van het project gebeurt in een context die de bedrijfsrealiteit zoveel mogelijk
nabootst: de projectgroepen moeten zelfstandig beslissingen nemen over werkverdeling,
tijdsbesteding, keuze van architectuur en programmeeromgeving, enz."
parent_course: null
faculty: "Wetenschappen"
- model: api.course
pk: 4
fields:
name: "Informatiebeveiliging"
academic_startyear: 2023
description: "Kennis bijbrengen van basisbegrippen over informatiebeveiliging (wiskundige basis,
toepassingen en legale aspecten)"
parent_course: null
faculty: "Ingenieurswetenschappen_Architectuur"
- model: api.course
pk: 5
fields:
name: "Computationele biologie"
academic_startyear: 2023
description: "Waar komt SARS vandaan? Hebben wij genen geërfd van de Neanderthalers? Hoe gebruiken
planten hun interne klok? Hoeveel genetisch materiaal wordt er uitgewisseld tussen bacteriële
soorten? De genomische revolutie in de biologie maakt het mogelijk om een antwoord te
vinden op elk van deze vragen. Maar deze revolutie zou onmogelijk geweest zijn zonder de
ondersteuning van krachtige computationele en statistische methodes die toelaten om gebruik
te maken van deze genomische informatie. Oplossen van openstaande en toekomstige
problemen die opduiken in dit intrigerend onderzoeksdomein vereist de opleiding van een
volgende generatie onderzoekers, die zich vloeiend kunnen uitdrukken in de taal van de
wiskunde, informatica en biologie."
parent_course: null
faculty: "Wetenschappen"
- model: api.course
pk: 6
fields:
name: "Inleiding tot de elektrotechniek"
academic_startyear: 2023
description: "Practica horend bij het opleidingsonderdeel"
parent_course: null
faculty: "Wetenschappen"
- model: api.course
pk: 7
fields:
name: "Mobile and Broadband Access Networks"
academic_startyear: 2023
description: "Practica horend bij het opleidingsonderdeel"
parent_course: null
faculty: "Ingenieurswetenschappen_Architectuur"
- model: api.course
pk: 8
fields:
name: "Design of Multimedia Applications"
academic_startyear: 2023
description: "Software projects"
parent_course: null
faculty: "Ingenieurswetenschappen_Architectuur"
20 changes: 20 additions & 0 deletions backend/api/migrations/0008_course_faculty.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Generated by Django 5.0.3 on 2024-04-03 10:01

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


class Migration(migrations.Migration):

dependencies = [
('api', '0007_merge_20240313_0639'),
('authentication', '0001_initial'),
]

operations = [
migrations.AddField(
model_name='course',
name='faculty',
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to='authentication.faculty'),
),
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# Generated by Django 5.0.3 on 2024-04-04 14:51

from django.db import migrations


class Migration(migrations.Migration):

dependencies = [
('api', '0008_add_extra_checks'),
('api', '0008_course_faculty'),
]

operations = [
]
10 changes: 10 additions & 0 deletions backend/api/models/course.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
from typing import Self
from django.db import models

from authentication.models import Faculty


class Course(models.Model):
"""This model represents a single course.
Expand All @@ -14,8 +16,16 @@ class Course(models.Model):
# Begin year of the academic year
academic_startyear = models.IntegerField(blank=False, null=False)

# The description of the course
description = models.TextField(blank=True, null=True)

# The faculty this course belongs to
faculty = models.ForeignKey(
Faculty,
null=True,
on_delete=models.SET_NULL
)

# OneToOneField is used to represent a one-to-one relationship
# with the course of the previous academic year
parent_course = models.OneToOneField(
Expand Down
9 changes: 6 additions & 3 deletions backend/api/permissions/student_permissions.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
from rest_framework.permissions import IsAuthenticated, SAFE_METHODS

from api.models.student import Student
from api.permissions.role_permissions import is_teacher
from authentication.models import User

Expand All @@ -7,9 +9,10 @@ class StudentPermission(IsAuthenticated):

def has_permission(self, request, view):
"""Check if user has permission to view a general student endpoint."""
return view.action == 'retrieve'
return True

def has_object_permission(self, request, view, obj):
def has_object_permission(self, request, view, student: Student) -> bool:
"""Check if user has permission to view a detailed group endpoint"""
user: User = request.user
return request.method in SAFE_METHODS and (user.id == request.user.id or is_teacher(user))

return request.method in SAFE_METHODS and (user.id == student.id or is_teacher(user))
5 changes: 5 additions & 0 deletions backend/api/serializers/course_serializer.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from rest_framework.exceptions import ValidationError
from api.serializers.student_serializer import StudentIDSerializer
from api.serializers.teacher_serializer import TeacherIDSerializer
from api.serializers.faculty_serializer import FacultySerializer
from api.models.course import Course


Expand Down Expand Up @@ -31,6 +32,10 @@ class CourseSerializer(serializers.ModelSerializer):
many=False, read_only=True, view_name="course-detail"
)

faculty = FacultySerializer(
read_only=True
)

class Meta:
model = Course
fields = "__all__"
Expand Down
8 changes: 7 additions & 1 deletion backend/api/serializers/faculty_serializer.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,14 @@
from django.utils.translation import gettext_lazy as _
from rest_framework import serializers
from authentication.models import Faculty


class facultySerializer(serializers.ModelSerializer):
class FacultySerializer(serializers.ModelSerializer):
name = serializers.SerializerMethodField()

def get_name(self, data) -> str:
return _(data.name)

class Meta:
model = Faculty
fields = "__all__"
2 changes: 1 addition & 1 deletion backend/api/tests/test_admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
def create_faculty(name):
"""
Create a Faculty with the given arguments."""
return Faculty.objects.create(name=name)
return Faculty.objects.create(id=name, name=name)


def create_admin(id, first_name, last_name, email, faculty=None):
Expand Down
2 changes: 1 addition & 1 deletion backend/api/tests/test_assistant.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ def create_course(name, academic_startyear, description=None, parent_course=None

def create_faculty(name):
"""Create a Faculty with the given arguments."""
return Faculty.objects.create(name=name)
return Faculty.objects.create(id=name, name=name)


def create_assistant(id, first_name, last_name, email, faculty=None, courses=None):
Expand Down
2 changes: 1 addition & 1 deletion backend/api/tests/test_student.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ def create_course(name, academic_startyear, description=None, parent_course=None

def create_faculty(name):
"""Create a Faculty with the given arguments."""
return Faculty.objects.create(name=name)
return Faculty.objects.create(id=name, name=name)


def create_student(id, first_name, last_name, email, faculty=None, courses=None):
Expand Down
2 changes: 1 addition & 1 deletion backend/api/tests/test_teacher.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ def create_course(name, academic_startyear, description=None, parent_course=None

def create_faculty(name):
"""Create a Faculty with the given arguments."""
return Faculty.objects.create(name=name)
return Faculty.objects.create(id=name, name=name)


def create_teacher(id, first_name, last_name, email, faculty=None, courses=None):
Expand Down
30 changes: 30 additions & 0 deletions backend/api/views/course_view.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
CourseSerializer, StudentJoinSerializer, StudentLeaveSerializer, CourseCloneSerializer,
TeacherJoinSerializer, TeacherLeaveSerializer
)
from api.views.pagination.basic_pagination import BasicPagination
from api.serializers.teacher_serializer import TeacherSerializer
from api.serializers.assistant_serializer import AssistantSerializer, AssistantIDSerializer
from api.serializers.student_serializer import StudentSerializer
Expand Down Expand Up @@ -46,6 +47,35 @@ def create(self, request: Request, *_):
status=status.HTTP_201_CREATED
)

@action(detail=False)
def search(self, request: Request) -> Response:
self.pagination_class = BasicPagination

# Extract filter params
search = request.query_params.get("search", "")
years = request.query_params.getlist("years[]")
faculties = request.query_params.getlist("faculties[]")

# Filter the queryset based on the search term
queryset = self.get_queryset().filter(
name__icontains=search
)

# Filter the queryset based on selected years
if years:
queryset = queryset.filter(academic_startyear__in=years)

# Filter the queryset based on selected faculties
if faculties:
queryset = queryset.filter(faculty__in=faculties)

# Serialize the resulting queryset
serializer = self.serializer_class(self.paginate_queryset(queryset), many=True, context={
"request": request
})

return self.get_paginated_response(serializer.data)

@action(detail=True, permission_classes=[IsAdminUser | CourseAssistantPermission])
def assistants(self, request: Request, **_):
"""Returns a list of assistants for the given course"""
Expand Down
4 changes: 2 additions & 2 deletions backend/api/views/faculty_view.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@
from rest_framework.permissions import IsAdminUser
from authentication.models import Faculty
from api.permissions.faculty_permissions import FacultyPermission
from ..serializers.faculty_serializer import facultySerializer
from ..serializers.faculty_serializer import FacultySerializer


class FacultyViewSet(viewsets.ModelViewSet):
queryset = Faculty.objects.all()
serializer_class = facultySerializer
serializer_class = FacultySerializer
permission_classes = [IsAdminUser | FacultyPermission]
Empty file.
8 changes: 8 additions & 0 deletions backend/api/views/pagination/basic_pagination.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
from rest_framework.pagination import PageNumberPagination


class BasicPagination(PageNumberPagination):
page_size = 20
max_page_size = 50
page_size_query_param = 'page_size'
page_query_param = 'page'
33 changes: 22 additions & 11 deletions backend/authentication/fixtures/faculties.yaml
Original file line number Diff line number Diff line change
@@ -1,33 +1,44 @@
- model: authentication.faculty
pk: Bio-ingenieurswetenschappen
fields: {}
fields:
name: "faculties.bioscience_engineering"
- model: authentication.faculty
pk: Diergeneeskunde
fields: {}
fields:
name: "faculties.veterinary_medicine"
- model: authentication.faculty
pk: Economie_Bedrijfskunde
fields: {}
fields:
name: "faculties.economics_business_administration"
- model: authentication.faculty
pk: Farmaceutische_Wetenschappen
fields: {}
fields:
name: "faculties.pharmaceutical_sciences"
- model: authentication.faculty
pk: Geneeskunde_Gezondheidswetenschappen
fields: {}
fields:
name: "faculties.medicine_health_sciences"
- model: authentication.faculty
pk: Ingenieurswetenschappen_Architectuur
fields: {}
fields:
name: "faculties.engineering_architecture"
- model: authentication.faculty
pk: Letteren_Wijsbegeerte
fields: {}
fields:
name: "faculties.arts_philosophy"
- model: authentication.faculty
pk: Politieke_Sociale_Wetenschappen
fields: {}
fields:
name: "faculties.political_social_sciences"
- model: authentication.faculty
pk: Psychologie_PedagogischeWetenschappen
fields: {}
fields:
name: "faculties.psychology_educational_sciences"
- model: authentication.faculty
pk: Recht_Criminologie
fields: {}
fields:
name: "faculties.law_criminology"
- model: authentication.faculty
pk: Wetenschappen
fields: {}
fields:
name: "faculties.sciences"
Loading
Loading