Skip to content

Commit

Permalink
feat: project views
Browse files Browse the repository at this point in the history
  • Loading branch information
EwoutV committed May 22, 2024
1 parent 6ecb8c4 commit 3dea579
Show file tree
Hide file tree
Showing 64 changed files with 731 additions and 681 deletions.
7 changes: 4 additions & 3 deletions backend/api/permissions/role_permissions.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from django.contrib.auth.base_user import AbstractBaseUser
from rest_framework.permissions import IsAuthenticated
from rest_framework.request import Request
from rest_framework.viewsets import ViewSet
Expand All @@ -7,17 +8,17 @@
from api.models.teacher import Teacher


def is_student(user: User) -> bool:
def is_student(user: AbstractBaseUser) -> bool:
"""Check whether the user is a student"""
return Student.objects.filter(id=user.id, is_active=True).exists()


def is_assistant(user: User) -> bool:
def is_assistant(user: AbstractBaseUser) -> bool:
"""Check whether the user is an assistant"""
return Assistant.objects.filter(id=user.id, is_active=True).exists()


def is_teacher(user: User) -> bool:
def is_teacher(user: AbstractBaseUser) -> bool:
"""Check whether the user is a teacher"""
return Teacher.objects.filter(id=user.id, is_active=True).exists()

Expand Down
30 changes: 20 additions & 10 deletions backend/api/serializers/group_serializer.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,52 +13,62 @@


class GroupSerializer(serializers.ModelSerializer):
project = ProjectSerializer(
read_only=True,
project = serializers.HyperlinkedIdentityField(
view_name="project-detail"
)

students = serializers.HyperlinkedIdentityField(
view_name="group-students",
read_only=True,
)

occupation = serializers.SerializerMethodField()

submissions = serializers.HyperlinkedIdentityField(
view_name="group-submissions",
read_only=True,
)

class Meta:
model = Group
fields = "__all__"
def get_occupation(self, instance: Group):
"""Get the number of students in the group"""
return instance.students.count()

def to_representation(self, instance):
def to_representation(self, instance: Group):
"""Convert the group to a JSON representation"""
data = super().to_representation(instance)

user = self.context["request"].user
course_id = instance.project.course.id

# If you are not a student, you can always see the score
if is_student(user):
if is_student(user) and not is_teacher(user) and not is_assistant(user) and not user.is_staff:
student_in_course = user.student.courses.filter(id=course_id).exists()

# Student can not see the score if they are not part of the course associated with group and
# neither an assistant or a teacher,
# or it is not visible yet when they are part of the course associated with the group
if not student_in_course and not is_assistant(user) and not is_teacher(user) or \
if not student_in_course or \
not instance.project.score_visible and student_in_course:
data.pop("score")

return data

def validate(self, attrs):
# Make sure the score of the group is lower or equal to the maximum score
self.instance: Group
group = self.instance
group: Group = self.instance or self.context.get("group")

if group is None:
raise ValueError("Group is not in context")

if "score" in attrs and attrs["score"] > group.project.max_score:
raise ValidationError(gettext("group.errors.score_exceeds_max"))

return attrs

class Meta:
model = Group
fields = "__all__"


class StudentJoinGroupSerializer(StudentIDSerializer):

Expand Down
22 changes: 22 additions & 0 deletions backend/api/views/project_view.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
from api.models.group import Group
from api.models.project import Project
from api.models.student import Student
from api.models.submission import Submission
from api.permissions.project_permissions import (ProjectGroupPermission,
ProjectPermission)
from api.permissions.role_permissions import is_student, IsStudent
from api.serializers.checks_serializer import (ExtraCheckSerializer,
StructureCheckSerializer)
from api.serializers.group_serializer import GroupSerializer
Expand Down Expand Up @@ -31,6 +33,26 @@ class ProjectViewSet(RetrieveModelMixin,
serializer_class = ProjectSerializer
permission_classes = [IsAdminUser | ProjectPermission] # GroupPermission has exact the same logic as for a project

@action(detail=True, permission_classes=[IsAdminUser | ProjectGroupPermission | IsStudent], url_path='student-group')
def student_group(self, request: Request, **_) -> Response:
"""Returns the group of the student for the given project"""

# Get the student object from the user
student = Student.objects.get(id=request.user.id)

# Get the group of the student for the project
group = student.groups.filter(project=self.get_object()).first()

if group is None:
return Response(None)

# Serialize the group object
serializer = GroupSerializer(
group, context={"request": request}
)

return Response(serializer.data)

@action(detail=True, permission_classes=[IsAdminUser | ProjectGroupPermission])
def groups(self, request, **_):
"""Returns a list of groups for the given project"""
Expand Down
14 changes: 14 additions & 0 deletions frontend/src/assets/lang/app/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,13 @@
"nl": "Nederlands",
"en": "English"
}
},
"footer": {
"home": "Dashboard",
"about": "Help",
"privacy": "Cookies",
"contact": "Contact",
"rights": "All rights reserved"
}
},
"views": {
Expand All @@ -41,11 +48,18 @@
},
"projects": {
"all": "All projects",
"backToCourse": "Back to course",
"coming": "Near deadlines",
"deadline": "Deadline",
"days": "Today at {hour} | Tomorrow at {hour} | In {count} days",
"ago": "1 day ago | {count} days ago",
"chooseGroupMessage": "Choose a group before {0}",
"groupScore": "Group score",
"noGroupScore": "No group score",
"noGroupMembers": "No group members",
"publishScores": "Publish scores",
"groupName": "Group name",
"groups": "Groups",
"groupPopulation": "Size",
"groupStatus": "Status",
"start": "Start date",
Expand Down
14 changes: 14 additions & 0 deletions frontend/src/assets/lang/app/nl.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,13 @@
"nl": "Nederlands",
"en": "English"
}
},
"footer": {
"home": "Dashboard",
"about": "Help",
"privacy": "Cookies",
"contact": "Contacteer ons",
"rights": "Alle rechten voorbehouden"
}
},
"views": {
Expand Down Expand Up @@ -42,15 +49,22 @@
"projects": {
"all": "Alle projecten",
"coming": "Aankomende deadlines",
"backToCourse": "Terug naar het vak",
"deadline": "Deadline",
"days": "Vandaag om {hour} | Morgen om {hour} | Over {count} dagen",
"ago": "1 dag geleden | {count} dagen geleden",
"chooseGroupMessage": "Kies een groep voor {0}",
"groupScore": "Groepsscore",
"noGroupScore": "Nog geen score",
"publishScores": "Publiceer scores",
"groupName": "Groepsnaam",
"noGroupMembers": "Geen groepsleden",
"groupPopulation": "Grootte",
"groupStatus": "Status",
"start": "Startdatum",
"submissionStatus": "Indienstatus",
"group": "Groep",
"groups": "Groepen",
"groupSize": "Individueel | Groepen van {count} personen",
"noGroups": "Geen groepen beschikbaar",
"groupMembers": "Groepsleden",
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/components/Loading.vue
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ withDefaults(defineProps<{ height?: string }>(), {
height: '4rem',
});
const show = useTimeout(250);
const show = useTimeout(350);
</script>

<template>
Expand Down
28 changes: 0 additions & 28 deletions frontend/src/components/help/HelpBaseLayout.vue

This file was deleted.

Loading

0 comments on commit 3dea579

Please sign in to comment.