diff --git a/backend/api/fixtures/groups.yaml b/backend/api/fixtures/groups.yaml index 8d2a18b7..7b989dda 100644 --- a/backend/api/fixtures/groups.yaml +++ b/backend/api/fixtures/groups.yaml @@ -6,12 +6,36 @@ students: - '1' - '2' + - '000200694919' - model: api.group pk: 3 fields: - project: 123456 + project: 2 score: 8 students: [] +- model: api.group + pk: 4 + fields: + project: 2 + score: 8 + students: + - '1' +- model: api.group + pk: 5 + fields: + project: 2 + score: 8 + students: + - '2' + +- model: api.group + pk: 6 + fields: + project: 2 + score: 8 + students: + - '3' + - model: api.group pk: 2 fields: @@ -21,3 +45,4 @@ - '1' - '2' - '3' + - '000200694919' diff --git a/backend/api/fixtures/projects.yaml b/backend/api/fixtures/projects.yaml index 6e16ad73..4099cbbc 100644 --- a/backend/api/fixtures/projects.yaml +++ b/backend/api/fixtures/projects.yaml @@ -1,7 +1,7 @@ - model: api.project pk: 123456 fields: - name: sel2 + name: sel1 description: make a project visible: true archived: false @@ -22,3 +22,16 @@ group_size: 3 max_score: 20 course: 1 + +- model: api.project + pk: 2 + fields: + name: sel2 + description: make a project, but better and more fun than the previous one because it's the second one and we learned from the first one + visible: true + archived: false + start_date: 2024-02-26 00:00:00+00:00 + deadline: 2024-02-27 00:00:00+00:00 + group_size: 3 + max_score: 20 + course: 1 \ No newline at end of file diff --git a/backend/api/fixtures/students.yaml b/backend/api/fixtures/students.yaml index be45618b..2508b355 100644 --- a/backend/api/fixtures/students.yaml +++ b/backend/api/fixtures/students.yaml @@ -12,6 +12,12 @@ - 1 - model: api.student pk: '3' + fields: + student_id: null + courses: + - 1 +- model: api.student + pk: '000200694919' fields: student_id: null courses: diff --git a/backend/api/fixtures/submissions.yaml b/backend/api/fixtures/submissions.yaml index 3cb123db..aeb50e3f 100644 --- a/backend/api/fixtures/submissions.yaml +++ b/backend/api/fixtures/submissions.yaml @@ -12,6 +12,21 @@ submission_number: 2 submission_time: "2021-01-02T00:00:00Z" structure_checks_passed: True +- model: api.submission + pk: 3 + fields: + group: 4 + submission_number: 1 + submission_time: "2021-01-02T00:00:00Z" + structure_checks_passed: True +- model: api.submission + pk: 4 + fields: + group: 4 + submission_number: 2 + submission_time: "2021-01-02T00:00:00Z" + structure_checks_passed: True + - model: api.submissionfile pk: 1 diff --git a/backend/api/permissions/group_permissions.py b/backend/api/permissions/group_permissions.py index 64eea5b1..c8739a4f 100644 --- a/backend/api/permissions/group_permissions.py +++ b/backend/api/permissions/group_permissions.py @@ -22,8 +22,8 @@ def has_object_permission(self, request: Request, view: ViewSet, group) -> bool: """Check if user has permission to view a detailed group endpoint""" user: User = request.user course = group.project.course - teacher_or_assitant = is_teacher(user) and user.teacher.courses.filter(id=course.id).exists() or \ - is_assistant(user) and user.assistant.courses.filter(id=course.id).exists() + teacher_or_assitant = is_teacher(user) and user.teacher.courses.filter( + id=course.id).exists() or is_assistant(user) and user.assistant.courses.filter(id=course.id).exists() if request.method in SAFE_METHODS: # Users that are linked to the course can view the group. @@ -39,8 +39,8 @@ class GroupStudentPermission(BasePermission): def has_object_permission(self, request: Request, view: ViewSet, group) -> bool: user: User = request.user course = group.project.course - teacher_or_assitant = is_teacher(user) and user.teacher.courses.filter(id=course.id).exists() or \ - is_assistant(user) and user.assistant.courses.filter(id=course.id).exists() + teacher_or_assitant = is_teacher(user) and user.teacher.courses.filter( + id=course.id).exists() or is_assistant(user) and user.assistant.courses.filter(id=course.id).exists() if request.method in SAFE_METHODS: # Users related to the course can view the students of the group. @@ -53,3 +53,22 @@ def has_object_permission(self, request: Request, view: ViewSet, group) -> bool: # Teachers and assistants can add and remove any student from a group return teacher_or_assitant + + +class GroupSubmissionPermission(BasePermission): + """Permission class for submission related group endpoints""" + + def had_object_permission(self, request: Request, view: ViewSet, group) -> bool: + user: User = request.user + course = group.project.course + teacher_or_assitant = is_teacher(user) and user.teacher.courses.filter( + id=course.id).exists() or is_assistant(user) and user.assistant.courses.filter(id=course.id).exists() + if request.method in SAFE_METHODS: + # Users related to the group can view the submissions of the group + return teacher_or_assitant or (is_student(user) and user.student.groups.filter(id=group.id).exists()) + + # Student can only add submissions to there own group + if is_student(user) and request.data.get("student_id") == user.id and view.action == "create": + return user.student.course.filter(id=course.id).exists() + + # Removing a Submissions is not possible for teachers and assistants diff --git a/backend/api/views/group_view.py b/backend/api/views/group_view.py index 65dd2488..156f7b55 100644 --- a/backend/api/views/group_view.py +++ b/backend/api/views/group_view.py @@ -6,7 +6,7 @@ from rest_framework.response import Response from drf_yasg.utils import swagger_auto_schema from api.models.group import Group -from api.permissions.group_permissions import GroupPermission +from api.permissions.group_permissions import GroupPermission, GroupSubmissionPermission from api.permissions.group_permissions import GroupStudentPermission from api.serializers.group_serializer import GroupSerializer from api.serializers.student_serializer import StudentSerializer @@ -38,7 +38,7 @@ def students(self, request, **_): ) return Response(serializer.data) - @action(detail=True, permission_classes=[IsAdminUser]) + @action(detail=True, permission_classes=[IsAdminUser | GroupSubmissionPermission]) def submissions(self, request, **_): """Returns a list of submissions for the given group""" group = self.get_object() diff --git a/backend/authentication/fixtures/users.yaml b/backend/authentication/fixtures/users.yaml index f0edbaa9..45c08856 100644 --- a/backend/authentication/fixtures/users.yaml +++ b/backend/authentication/fixtures/users.yaml @@ -82,3 +82,15 @@ create_time: 2024-02-29 20:35:45.688545+00:00 faculties: - Psychologie_PedagogischeWetenschappen +- model: authentication.user + pk: '000200694919' + fields: + last_login: null + username: landmaes + email: lander.maes@ugent.be + first_name: Lander + last_name: Maes + last_enrolled: 2023 + create_time: 2024-02-29 20:35:45.688545+00:00 + faculties: + - Wetenschappen \ No newline at end of file diff --git a/frontend/src/assets/lang/en.json b/frontend/src/assets/lang/en.json index 5a5da5d3..bfea42df 100644 --- a/frontend/src/assets/lang/en.json +++ b/frontend/src/assets/lang/en.json @@ -8,6 +8,7 @@ "dashboard": "Dashboard", "calendar": "Calendar", "courses": "courses", + "projects": "projects", "settings": "preferences", "help": "help" }, @@ -41,7 +42,11 @@ "projects": { "deadline": "Deadline", "submissionStatus": "Indienstatus", + "group": "Group", "groupMembers": "Group members", + "chooseGroup": "Choose a group", + "joinGroup": "Join group", + "leaveGroup": "Leave group", "create": "Create new project", "name": "Project name", "description": "Description", @@ -51,6 +56,12 @@ "visibility": "Make project visible to students", "score_visibility": "Make score, when uploaded, automatically visible to students" }, + "submissions": { + "title": "Submissions", + "submit": "Submit", + "course": "Course", + "chooseFile": "Choose a file" + }, "courses": { "create": "Create course", "name": "Course name", @@ -80,7 +91,8 @@ }, "card": { "open": "details" - } + }, + "submission": "Submit" }, "types": { "roles": { diff --git a/frontend/src/assets/lang/nl.json b/frontend/src/assets/lang/nl.json index 38c5579c..ea528cf0 100644 --- a/frontend/src/assets/lang/nl.json +++ b/frontend/src/assets/lang/nl.json @@ -8,6 +8,7 @@ "dashboard": "Dashboard", "calendar": "Kalender", "courses": "Vakken", + "projects": "Projecten", "settings": "Voorkeuren", "help": "Help" }, @@ -41,7 +42,11 @@ "projects": { "deadline": "Deadline", "submissionStatus": "Indienstatus", + "group": "Groep", "groupMembers": "Groepsleden", + "chooseGroup": "Kies een groep", + "joinGroup": "Kies groep", + "leaveGroup": "Verlaat groep", "create": "Creëer nieuw project", "name": "Projectnaam", "description": "Beschrijving", @@ -51,6 +56,12 @@ "visibility": "Project zichtbaar maken voor studenten", "score_visibility": "Maak score, wanneer ingevuld, automatisch zichtbaar voor studenten" }, + "submissions": { + "title": "Inzendingen", + "submit": "Indienen", + "course": "Vak", + "chooseFile": "Kies bestand(en)" + }, "courses": { "create": "Creëer vak", "name": "Vaknaam", @@ -89,7 +100,8 @@ }, "card": { "open": "Details" - } + }, + "submission" : "Indienen" }, "types": { "roles": { diff --git a/frontend/src/assets/scss/theme/_variables.scss b/frontend/src/assets/scss/theme/_variables.scss index 70a12627..3df21c0f 100644 --- a/frontend/src/assets/scss/theme/_variables.scss +++ b/frontend/src/assets/scss/theme/_variables.scss @@ -32,6 +32,7 @@ $fontWeight:normal !default; $textColor:$shade700 !default; $textSecondaryColor:$shade600 !default; $borderRadius:6px !default; +$borderWidth:2px !default; $transitionDuration:.2s !default; $formElementTransition:background-color $transitionDuration, color $transitionDuration, border-color $transitionDuration, box-shadow $transitionDuration !default; $actionIconTransition:background-color $transitionDuration, color $transitionDuration, box-shadow $transitionDuration !default; diff --git a/frontend/src/assets/scss/theme/base/components/file/_fileupload.scss b/frontend/src/assets/scss/theme/base/components/file/_fileupload.scss index 674e1273..804f56a0 100644 --- a/frontend/src/assets/scss/theme/base/components/file/_fileupload.scss +++ b/frontend/src/assets/scss/theme/base/components/file/_fileupload.scss @@ -1,15 +1,15 @@ // core .p-fileupload-content { position: relative; -} - -.p-fileupload-content .p-progressbar { width: 100%; - position: absolute; top: 0; left: 0; } +.p-progressbar { + display: none; +} + .p-button.p-fileupload-choose { position: relative; overflow: hidden; @@ -46,6 +46,7 @@ // theme .p-fileupload { .p-fileupload-buttonbar { + justify-content: space-between; background: $panelHeaderBg; padding: $panelHeaderPadding; border: $panelHeaderBorder; diff --git a/frontend/src/components/layout/Header.vue b/frontend/src/components/layout/Header.vue index 72615863..86156ab2 100644 --- a/frontend/src/components/layout/Header.vue +++ b/frontend/src/components/layout/Header.vue @@ -39,6 +39,11 @@ const items = computed(() => [ label: t('layout.header.navigation.courses'), route: 'courses', }, + { + icon: 'file-plus', + label: t('layout.header.navigation.projects'), + route: 'projects', + }, ]); diff --git a/frontend/src/components/projects/ChooseGroupCard.vue b/frontend/src/components/projects/ChooseGroupCard.vue new file mode 100644 index 00000000..38100a49 --- /dev/null +++ b/frontend/src/components/projects/ChooseGroupCard.vue @@ -0,0 +1,111 @@ + + + + + diff --git a/frontend/src/components/projects/GroupCard.vue b/frontend/src/components/projects/GroupCard.vue deleted file mode 100644 index 2b0a418c..00000000 --- a/frontend/src/components/projects/GroupCard.vue +++ /dev/null @@ -1,55 +0,0 @@ - - - - - diff --git a/frontend/src/components/projects/JoinedGroupCard.vue b/frontend/src/components/projects/JoinedGroupCard.vue new file mode 100644 index 00000000..59236d65 --- /dev/null +++ b/frontend/src/components/projects/JoinedGroupCard.vue @@ -0,0 +1,91 @@ + + + + + diff --git a/frontend/src/components/projects/ProjectCard.vue b/frontend/src/components/projects/ProjectCard.vue index 628b329b..83009f55 100644 --- a/frontend/src/components/projects/ProjectCard.vue +++ b/frontend/src/components/projects/ProjectCard.vue @@ -48,7 +48,7 @@ const { t } = useI18n();