From dac79836f67e87ce45d2c5a2dfff0f5b3144442d Mon Sep 17 00:00:00 2001 From: lander Date: Fri, 29 Mar 2024 19:10:09 +0100 Subject: [PATCH 01/33] frontent(ProjectView) chore: closes #185 --- frontend/src/assets/lang/en.json | 3 +- frontend/src/assets/lang/nl.json | 3 +- .../src/assets/scss/theme/_variables.scss | 1 + .../src/components/projects/GroupCard.vue | 8 +-- .../src/components/projects/ProjectCard.vue | 4 +- .../components/projects/SubmissionCard.vue | 50 +++++++++++++++++++ frontend/src/router/router.ts | 9 +++- frontend/src/views/projects/ProjectView.vue | 10 ++-- .../src/views/submissions/submissionView.vue | 30 +++++++++++ 9 files changed, 105 insertions(+), 13 deletions(-) create mode 100644 frontend/src/components/projects/SubmissionCard.vue create mode 100644 frontend/src/views/submissions/submissionView.vue diff --git a/frontend/src/assets/lang/en.json b/frontend/src/assets/lang/en.json index d46828d7..3b90f8ab 100644 --- a/frontend/src/assets/lang/en.json +++ b/frontend/src/assets/lang/en.json @@ -51,7 +51,8 @@ }, "card": { "open": "Details" - } + }, + "submission": "Submit" }, "primevue": { diff --git a/frontend/src/assets/lang/nl.json b/frontend/src/assets/lang/nl.json index a19ead69..082c1826 100644 --- a/frontend/src/assets/lang/nl.json +++ b/frontend/src/assets/lang/nl.json @@ -62,7 +62,8 @@ }, "card": { "open": "Details" - } + }, + "submission" : "Indienen" }, "primevue": { diff --git a/frontend/src/assets/scss/theme/_variables.scss b/frontend/src/assets/scss/theme/_variables.scss index 3664f1bd..718daac7 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/components/projects/GroupCard.vue b/frontend/src/components/projects/GroupCard.vue index 9839f093..168c2aa0 100644 --- a/frontend/src/components/projects/GroupCard.vue +++ b/frontend/src/components/projects/GroupCard.vue @@ -39,9 +39,11 @@ onMounted(async () => { .groupcard { background-color: white; border-radius: $borderRadius; - padding: 1.5rem; - margin: 1rem; - box-shadow: 0 0 10px rgba(0, 0, 0, 0.1); + padding: $cardBodyPadding; + border-style: solid; + border-color: $primaryLightColor; + border-width: $borderWidth; + color: $primaryColor; div { p { diff --git a/frontend/src/components/projects/ProjectCard.vue b/frontend/src/components/projects/ProjectCard.vue index bb4a8fe2..1f9e35fa 100644 --- a/frontend/src/components/projects/ProjectCard.vue +++ b/frontend/src/components/projects/ProjectCard.vue @@ -54,7 +54,7 @@ const { t } = useI18n(); @import '@/assets/scss/theme/theme.scss'; .icon-color { color: $primaryColor; - font-size: 18px; + font-size: $fontSize; } .border-round { @@ -63,7 +63,7 @@ const { t } = useI18n(); .project-card { border-style: solid; - border-width: 2px; + border-width: $borderWidth; border-color: $primaryLightColor; .p-card-body { diff --git a/frontend/src/components/projects/SubmissionCard.vue b/frontend/src/components/projects/SubmissionCard.vue new file mode 100644 index 00000000..a73fafff --- /dev/null +++ b/frontend/src/components/projects/SubmissionCard.vue @@ -0,0 +1,50 @@ + + + + + \ No newline at end of file diff --git a/frontend/src/router/router.ts b/frontend/src/router/router.ts index ab90e414..c52c0c48 100644 --- a/frontend/src/router/router.ts +++ b/frontend/src/router/router.ts @@ -12,6 +12,7 @@ import { RouteRecordRaw, createWebHistory, createRouter } from 'vue-router'; import {AuthenticationGuard} from '@/router/guards/authentication.guard.ts'; import {LogoutGuard} from '@/router/guards/logout.guard.ts'; import ProjectView from "@/views/projects/ProjectView.vue"; +import SubmissionView from "@/views/submissions/submissionView.vue"; const routes: RouteRecordRaw[] = [ @@ -42,7 +43,13 @@ const routes: RouteRecordRaw[] = [ { path: 'edit', component: Dummy, name: 'project-edit' }, { path: 'groups', component: Dummy, name: 'project-groups' }, { path: 'submit', component: Dummy, name: 'project-submit' }, - ]} + { path: 'submissions', children: [ + { path: '', component: Dummy, name: 'submissions' }, + { path: ':submissionId', children: [ + { path: '', component: SubmissionView, name: 'submission' }, + ]}, + ]}, + ]}, ]}, ]}, ]}, diff --git a/frontend/src/views/projects/ProjectView.vue b/frontend/src/views/projects/ProjectView.vue index 99b16038..f76af695 100644 --- a/frontend/src/views/projects/ProjectView.vue +++ b/frontend/src/views/projects/ProjectView.vue @@ -9,6 +9,7 @@ import Skeleton from "primevue/skeleton"; import GroupCard from "@/components/projects/GroupCard.vue"; import {useGroup} from "@/composables/services/groups.service.ts"; import {Group} from "@/types/Group.ts"; +import SubmissionCard from "@/components/projects/SubmissionCard.vue"; /** * Todo change all static id's to user.id @@ -24,13 +25,13 @@ const finalGroup = ref(new Group("-1")); onMounted(async () => { const projectId = route.params.projectId; - await getProjectByID(projectId as string, t); + await getProjectByID(projectId as string); console.log("fetching groups") // Get id group from project by comparing the users groups and the project groups - await getGroupsByProject(projectId as string, t); + await getGroupsByProject(projectId as string); const projectGroups = groups.value; // get all groups from the user - await getGroupsByStudent("1", t); + await getGroupsByStudent("1"); for (const group of groups.value ?? []) { const isCommonGroup = projectGroups?.some(projectGroup => projectGroup.id === group.id); @@ -39,8 +40,6 @@ onMounted(async () => { break; } } - console.log('laatste id') - console.log(finalGroup.value.id); }); @@ -63,6 +62,7 @@ onMounted(async () => {
+
diff --git a/frontend/src/views/submissions/submissionView.vue b/frontend/src/views/submissions/submissionView.vue new file mode 100644 index 00000000..2015077e --- /dev/null +++ b/frontend/src/views/submissions/submissionView.vue @@ -0,0 +1,30 @@ + + + + + \ No newline at end of file From f2c76635324e78e0f5cd1cc4903308e07df614c9 Mon Sep 17 00:00:00 2001 From: lander Date: Tue, 2 Apr 2024 18:22:34 +0200 Subject: [PATCH 02/33] fix: merges add user.id's --- frontend/src/components/projects/SubmissionCard.vue | 4 ++-- frontend/src/router/router.ts | 2 ++ frontend/src/views/projects/ProjectView.vue | 11 +++++------ 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/frontend/src/components/projects/SubmissionCard.vue b/frontend/src/components/projects/SubmissionCard.vue index a73fafff..c25ebf6d 100644 --- a/frontend/src/components/projects/SubmissionCard.vue +++ b/frontend/src/components/projects/SubmissionCard.vue @@ -33,12 +33,12 @@ const formattedDeadline = computed(() => {
- {{t('views.projects.submissionStatus')}}: {{ project.submissions.structure_checks_passed }} + {{t('views.projects.submissionStatus')}}: {{ project.submissions.at(-1)?.structureChecks_passed }}
diff --git a/frontend/src/router/router.ts b/frontend/src/router/router.ts index 79a08f56..ad7692dd 100644 --- a/frontend/src/router/router.ts +++ b/frontend/src/router/router.ts @@ -12,6 +12,8 @@ import { RouteRecordRaw, createWebHistory, createRouter } from 'vue-router'; import {AuthenticationGuard} from '@/router/guards/authentication.guard.ts'; import {LogoutGuard} from '@/router/guards/logout.guard.ts'; import ProjectView from "@/views/projects/ProjectView.vue"; +import CreateCourseView from "@/views/courses/CreateCourseView.vue"; +import SubmissionView from "@/views/submissions/submissionView.vue"; const routes: RouteRecordRaw[] = [ // Authentication diff --git a/frontend/src/views/projects/ProjectView.vue b/frontend/src/views/projects/ProjectView.vue index ed5fcf7c..bb115d22 100644 --- a/frontend/src/views/projects/ProjectView.vue +++ b/frontend/src/views/projects/ProjectView.vue @@ -3,19 +3,18 @@ import BaseLayout from "@/components/layout/BaseLayout.vue"; import {onMounted, ref} from "vue"; import {useProject} from "@/composables/services/project.service.ts"; import {useRoute} from "vue-router"; -import Title from "@/components/Title.vue"; +import Title from "@/components/layout/Title.vue"; import Skeleton from "primevue/skeleton"; import GroupCard from "@/components/projects/GroupCard.vue"; import {useGroup} from "@/composables/services/groups.service.ts"; import {Group} from "@/types/Group.ts"; import SubmissionCard from "@/components/projects/SubmissionCard.vue"; - -/** - * Todo change all static id's to user.id - */ +import {storeToRefs} from "pinia"; +import {useAuthStore} from "@/store/authentication.store.ts"; /* Composable injections */ const route = useRoute() +const { user } = storeToRefs(useAuthStore()) const { project, getProjectByID } = useProject() const { groups, getGroupsByProject, getGroupsByStudent } = useGroup() @@ -30,7 +29,7 @@ onMounted(async () => { await getGroupsByProject(projectId as string); const projectGroups = groups.value; // get all groups from the user - await getGroupsByStudent("1"); + await getGroupsByStudent(user.value?.id); for (const group of groups.value ?? []) { const isCommonGroup = projectGroups?.some(projectGroup => projectGroup.id === group.id); From 49bb7c0fb3ff5a5f7a74125a88937f947955eb07 Mon Sep 17 00:00:00 2001 From: lander Date: Fri, 5 Apr 2024 18:41:57 +0200 Subject: [PATCH 03/33] Frontend: leave/join groups --- backend/api/fixtures/groups.yaml | 27 +++++- backend/api/fixtures/projects.yaml | 15 +++- backend/api/fixtures/students.yaml | 6 ++ backend/authentication/fixtures/users.yaml | 12 +++ frontend/src/assets/lang/en.json | 2 + frontend/src/assets/lang/nl.json | 2 + .../components/projects/ChooseGroupCard.vue | 83 +++++++++++++++++ .../src/components/projects/GroupCard.vue | 88 ++++++++++++------- frontend/src/router/router.ts | 2 + frontend/src/views/projects/ProjectView.vue | 83 ++++------------- .../projects/roles/AssistantProjectView.vue | 11 +++ .../projects/roles/StudentProjectView.vue | 77 ++++++++++++++++ .../projects/roles/TeacherProjectView.vue | 11 +++ 13 files changed, 315 insertions(+), 104 deletions(-) create mode 100644 frontend/src/components/projects/ChooseGroupCard.vue create mode 100644 frontend/src/views/projects/roles/AssistantProjectView.vue create mode 100644 frontend/src/views/projects/roles/StudentProjectView.vue create mode 100644 frontend/src/views/projects/roles/TeacherProjectView.vue 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/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 f46fa498..582a636c 100644 --- a/frontend/src/assets/lang/en.json +++ b/frontend/src/assets/lang/en.json @@ -41,7 +41,9 @@ "projects": { "deadline": "Deadline", "submissionStatus": "Indienstatus", + "group": "Group", "groupMembers": "Group members", + "chooseGroup": "Choose a group", "create": "Create new project", "name": "Project name", "description": "Description", diff --git a/frontend/src/assets/lang/nl.json b/frontend/src/assets/lang/nl.json index 30f36150..92b9053e 100644 --- a/frontend/src/assets/lang/nl.json +++ b/frontend/src/assets/lang/nl.json @@ -41,7 +41,9 @@ "projects": { "deadline": "Deadline", "submissionStatus": "Indienstatus", + "group": "Groep", "groupMembers": "Groepsleden", + "chooseGroup": "Kies een groep", "create": "Creëer nieuw project", "name": "Projectnaam", "description": "Beschrijving", diff --git a/frontend/src/components/projects/ChooseGroupCard.vue b/frontend/src/components/projects/ChooseGroupCard.vue new file mode 100644 index 00000000..3e78aca7 --- /dev/null +++ b/frontend/src/components/projects/ChooseGroupCard.vue @@ -0,0 +1,83 @@ + + + + + diff --git a/frontend/src/components/projects/GroupCard.vue b/frontend/src/components/projects/GroupCard.vue index 98779a74..91dd321d 100644 --- a/frontend/src/components/projects/GroupCard.vue +++ b/frontend/src/components/projects/GroupCard.vue @@ -1,57 +1,77 @@ - diff --git a/frontend/src/router/router.ts b/frontend/src/router/router.ts index d1c1e7a1..d7b6ba31 100644 --- a/frontend/src/router/router.ts +++ b/frontend/src/router/router.ts @@ -12,6 +12,8 @@ import { type RouteRecordRaw, createWebHistory, createRouter } from 'vue-router' import { AuthenticationGuard } from '@/router/guards/authentication.guard.ts' import { LogoutGuard } from '@/router/guards/logout.guard.ts' import ProjectView from '@/views/projects/ProjectView.vue' +import CreateProjectView from "@/views/projects/CreateProjectView.vue"; +import SearchCourseView from "@/views/courses/SearchCourseView.vue"; const routes: RouteRecordRaw[] = [ // Authentication diff --git a/frontend/src/views/projects/ProjectView.vue b/frontend/src/views/projects/ProjectView.vue index 55704f1c..2994cc48 100644 --- a/frontend/src/views/projects/ProjectView.vue +++ b/frontend/src/views/projects/ProjectView.vue @@ -1,77 +1,24 @@ - + diff --git a/frontend/src/views/projects/roles/AssistantProjectView.vue b/frontend/src/views/projects/roles/AssistantProjectView.vue new file mode 100644 index 00000000..89b1f330 --- /dev/null +++ b/frontend/src/views/projects/roles/AssistantProjectView.vue @@ -0,0 +1,11 @@ + + + + + \ No newline at end of file diff --git a/frontend/src/views/projects/roles/StudentProjectView.vue b/frontend/src/views/projects/roles/StudentProjectView.vue new file mode 100644 index 00000000..94d6c2f7 --- /dev/null +++ b/frontend/src/views/projects/roles/StudentProjectView.vue @@ -0,0 +1,77 @@ + + + + + diff --git a/frontend/src/views/projects/roles/TeacherProjectView.vue b/frontend/src/views/projects/roles/TeacherProjectView.vue new file mode 100644 index 00000000..89b1f330 --- /dev/null +++ b/frontend/src/views/projects/roles/TeacherProjectView.vue @@ -0,0 +1,11 @@ + + + + + \ No newline at end of file From 90aa96cfca20c444792693557a10d18f0a79f49b Mon Sep 17 00:00:00 2001 From: EwoutV Date: Fri, 5 Apr 2024 19:43:48 +0200 Subject: [PATCH 04/33] fix: group join state --- .../components/projects/ChooseGroupCard.vue | 131 ++++++++++-------- .../src/components/projects/GroupCard.vue | 77 ---------- .../components/projects/JoinedGroupCard.vue | 81 +++++++++++ .../components/projects/SubmissionCard.vue | 68 +++++---- frontend/src/router/router.ts | 26 ++-- frontend/src/views/projects/ProjectView.vue | 16 +-- .../projects/roles/AssistantProjectView.vue | 12 +- .../projects/roles/StudentProjectView.vue | 109 ++++++++------- .../projects/roles/TeacherProjectView.vue | 12 +- .../src/views/submissions/submissionView.vue | 41 +++--- 10 files changed, 285 insertions(+), 288 deletions(-) delete mode 100644 frontend/src/components/projects/GroupCard.vue create mode 100644 frontend/src/components/projects/JoinedGroupCard.vue diff --git a/frontend/src/components/projects/ChooseGroupCard.vue b/frontend/src/components/projects/ChooseGroupCard.vue index 3e78aca7..9fc51446 100644 --- a/frontend/src/components/projects/ChooseGroupCard.vue +++ b/frontend/src/components/projects/ChooseGroupCard.vue @@ -1,83 +1,94 @@ diff --git a/frontend/src/components/projects/GroupCard.vue b/frontend/src/components/projects/GroupCard.vue deleted file mode 100644 index 91dd321d..00000000 --- a/frontend/src/components/projects/GroupCard.vue +++ /dev/null @@ -1,77 +0,0 @@ - - - - - diff --git a/frontend/src/components/projects/JoinedGroupCard.vue b/frontend/src/components/projects/JoinedGroupCard.vue new file mode 100644 index 00000000..35d9c813 --- /dev/null +++ b/frontend/src/components/projects/JoinedGroupCard.vue @@ -0,0 +1,81 @@ + + + + + diff --git a/frontend/src/components/projects/SubmissionCard.vue b/frontend/src/components/projects/SubmissionCard.vue index c25ebf6d..f9b1f00c 100644 --- a/frontend/src/components/projects/SubmissionCard.vue +++ b/frontend/src/components/projects/SubmissionCard.vue @@ -1,50 +1,48 @@ - \ No newline at end of file + diff --git a/frontend/src/router/router.ts b/frontend/src/router/router.ts index d7b6ba31..126665ef 100644 --- a/frontend/src/router/router.ts +++ b/frontend/src/router/router.ts @@ -1,19 +1,19 @@ // import { useUserStore } from '@/stores/userStore'; // TODO: after pinia setup is done -import DashboardView from '@/views/dashboard/DashboardView.vue' -import CourseView from '@/views/courses/CourseView.vue' -import CreateCourseView from '@/views/courses/CreateCourseView.vue' -import Dummy from '@/components/Dummy.vue' -import LoginView from '@/views/authentication/LoginView.vue' -import CalendarView from '@/views/calendar/CalendarView.vue' -import VerifyView from '@/views/authentication/VerifyView.vue' -import { type RouteRecordRaw, createWebHistory, createRouter } from 'vue-router' -import { AuthenticationGuard } from '@/router/guards/authentication.guard.ts' -import { LogoutGuard } from '@/router/guards/logout.guard.ts' -import ProjectView from '@/views/projects/ProjectView.vue' -import CreateProjectView from "@/views/projects/CreateProjectView.vue"; -import SearchCourseView from "@/views/courses/SearchCourseView.vue"; +import DashboardView from '@/views/dashboard/DashboardView.vue'; +import CourseView from '@/views/courses/CourseView.vue'; +import CreateCourseView from '@/views/courses/CreateCourseView.vue'; +import Dummy from '@/components/Dummy.vue'; +import LoginView from '@/views/authentication/LoginView.vue'; +import CalendarView from '@/views/calendar/CalendarView.vue'; +import VerifyView from '@/views/authentication/VerifyView.vue'; +import { type RouteRecordRaw, createWebHistory, createRouter } from 'vue-router'; +import { AuthenticationGuard } from '@/router/guards/authentication.guard.ts'; +import { LogoutGuard } from '@/router/guards/logout.guard.ts'; +import ProjectView from '@/views/projects/ProjectView.vue'; +import CreateProjectView from '@/views/projects/CreateProjectView.vue'; +import SearchCourseView from '@/views/courses/SearchCourseView.vue'; const routes: RouteRecordRaw[] = [ // Authentication diff --git a/frontend/src/views/projects/ProjectView.vue b/frontend/src/views/projects/ProjectView.vue index 2994cc48..930c402b 100644 --- a/frontend/src/views/projects/ProjectView.vue +++ b/frontend/src/views/projects/ProjectView.vue @@ -5,20 +5,20 @@ import { storeToRefs } from 'pinia'; import { type Student } from '@/types/users/Student'; import { type Teacher } from '@/types/users/Teacher'; import { type Assistant } from '@/types/users/Assistant'; -import StudentProjectView from "@/views/projects/roles/StudentProjectView.vue"; -import TeacherProjectView from "@/views/projects/roles/TeacherProjectView.vue"; -import AssistantProjectView from "@/views/projects/roles/AssistantProjectView.vue"; +import StudentProjectView from '@/views/projects/roles/StudentProjectView.vue'; +import TeacherProjectView from '@/views/projects/roles/TeacherProjectView.vue'; +import AssistantProjectView from '@/views/projects/roles/AssistantProjectView.vue'; /* Service injection */ const { user } = storeToRefs(useAuthStore()); diff --git a/frontend/src/views/projects/roles/AssistantProjectView.vue b/frontend/src/views/projects/roles/AssistantProjectView.vue index 89b1f330..b57c793b 100644 --- a/frontend/src/views/projects/roles/AssistantProjectView.vue +++ b/frontend/src/views/projects/roles/AssistantProjectView.vue @@ -1,11 +1,5 @@ - - + - - - \ No newline at end of file + diff --git a/frontend/src/views/projects/roles/StudentProjectView.vue b/frontend/src/views/projects/roles/StudentProjectView.vue index 94d6c2f7..61fa82b4 100644 --- a/frontend/src/views/projects/roles/StudentProjectView.vue +++ b/frontend/src/views/projects/roles/StudentProjectView.vue @@ -1,77 +1,76 @@ diff --git a/frontend/src/views/projects/roles/TeacherProjectView.vue b/frontend/src/views/projects/roles/TeacherProjectView.vue index 89b1f330..b57c793b 100644 --- a/frontend/src/views/projects/roles/TeacherProjectView.vue +++ b/frontend/src/views/projects/roles/TeacherProjectView.vue @@ -1,11 +1,5 @@ - - + - - - \ No newline at end of file + diff --git a/frontend/src/views/submissions/submissionView.vue b/frontend/src/views/submissions/submissionView.vue index 2015077e..cf0ad4d9 100644 --- a/frontend/src/views/submissions/submissionView.vue +++ b/frontend/src/views/submissions/submissionView.vue @@ -1,30 +1,27 @@ - \ No newline at end of file + From 7f77bf98a51314f2e6e38ff8450ac73daf564b87 Mon Sep 17 00:00:00 2001 From: lander Date: Sat, 6 Apr 2024 11:02:16 +0200 Subject: [PATCH 05/33] Frontend: styling Closes #184 --- frontend/src/assets/lang/en.json | 2 ++ frontend/src/assets/lang/nl.json | 2 ++ .../components/projects/ChooseGroupCard.vue | 15 ++++++---- .../components/projects/JoinedGroupCard.vue | 29 +++++++++++-------- 4 files changed, 31 insertions(+), 17 deletions(-) diff --git a/frontend/src/assets/lang/en.json b/frontend/src/assets/lang/en.json index 582a636c..f0add963 100644 --- a/frontend/src/assets/lang/en.json +++ b/frontend/src/assets/lang/en.json @@ -44,6 +44,8 @@ "group": "Group", "groupMembers": "Group members", "chooseGroup": "Choose a group", + "joinGroup": "Join group", + "leaveGroup": "Leave group", "create": "Create new project", "name": "Project name", "description": "Description", diff --git a/frontend/src/assets/lang/nl.json b/frontend/src/assets/lang/nl.json index 92b9053e..e658e5ab 100644 --- a/frontend/src/assets/lang/nl.json +++ b/frontend/src/assets/lang/nl.json @@ -44,6 +44,8 @@ "group": "Groep", "groupMembers": "Groepsleden", "chooseGroup": "Kies een groep", + "joinGroup": "Kies groep", + "leaveGroup": "Verlaat groep", "create": "Creëer nieuw project", "name": "Projectnaam", "description": "Beschrijving", diff --git a/frontend/src/components/projects/ChooseGroupCard.vue b/frontend/src/components/projects/ChooseGroupCard.vue index 9fc51446..87b2ee8c 100644 --- a/frontend/src/components/projects/ChooseGroupCard.vue +++ b/frontend/src/components/projects/ChooseGroupCard.vue @@ -6,6 +6,8 @@ import { useStudents } from '@/composables/services/students.service.ts'; import { storeToRefs } from 'pinia'; import { useAuthStore } from '@/store/authentication.store.ts'; import { type Group } from '@/types/Group.ts'; +import {PrimeIcons} from "primevue/api"; +import Button from "primevue/button"; /* Props */ defineProps<{ @@ -53,7 +55,7 @@ async function joinSelectedGroup(): Promise {

{{ t('views.projects.chooseGroup') }}

-
@@ -68,7 +70,7 @@ async function joinSelectedGroup(): Promise { {{ student.first_name }} {{ student.last_name }} - +
@@ -76,7 +78,7 @@ async function joinSelectedGroup(): Promise { diff --git a/frontend/src/components/projects/JoinedGroupCard.vue b/frontend/src/components/projects/JoinedGroupCard.vue index 35d9c813..ada29e07 100644 --- a/frontend/src/components/projects/JoinedGroupCard.vue +++ b/frontend/src/components/projects/JoinedGroupCard.vue @@ -5,6 +5,8 @@ import { useI18n } from 'vue-i18n'; import { type Group } from '@/types/Group.ts'; import { storeToRefs } from 'pinia'; import { useAuthStore } from '@/store/authentication.store.ts'; +import {PrimeIcons} from "primevue/api"; +import Button from "primevue/button"; /* Props */ const props = defineProps<{ @@ -45,12 +47,12 @@ onMounted(async () => { @@ -66,16 +68,19 @@ onMounted(async () => { border-width: $borderWidth; color: $primaryColor; - div { - p { - color: $textSecondaryColor; - border-bottom: 1px solid #e0e0e0; - } + div { + p { + color: $textSecondaryColor; + padding-bottom: 1rem; + margin-bottom: 1rem; + border-bottom: 1px solid #e0e0e0; + } - /* Zorgt ervoor dat er geen lijn onder de laatste naam staat */ - p:last-child { - border-bottom: none; - } + /* Zorgt ervoor dat er geen lijn onder de laatste naam staat */ + p:last-child { + border-bottom: none; + padding-bottom: 0; } + } } From 3f2a415f7761fd7c6320f459f51aaf73fd6c9909 Mon Sep 17 00:00:00 2001 From: lander Date: Sat, 6 Apr 2024 12:12:36 +0200 Subject: [PATCH 06/33] Backend: fix, updated group submission permission --- backend/api/permissions/group_permissions.py | 23 ++++++++++++++++++-- backend/api/views/group_view.py | 4 ++-- 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/backend/api/permissions/group_permissions.py b/backend/api/permissions/group_permissions.py index 64eea5b1..98e4923f 100644 --- a/backend/api/permissions/group_permissions.py +++ b/backend/api/permissions/group_permissions.py @@ -23,7 +23,7 @@ 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() + 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. @@ -40,7 +40,7 @@ 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() + 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() From 8a354bd8c852ce7c393f7b0abde8097b17a99624 Mon Sep 17 00:00:00 2001 From: tyboro2002 Date: Sat, 6 Apr 2024 14:20:28 +0200 Subject: [PATCH 07/33] chore: try adding the seeder lib --- backend/poetry.lock | 48 +++++++++++++++++++++++++++++++++---- backend/pyproject.toml | 4 +++- backend/ypovoli/settings.py | 1 + 3 files changed, 48 insertions(+), 5 deletions(-) diff --git a/backend/poetry.lock b/backend/poetry.lock index d2d6ad5d..df20168f 100644 --- a/backend/poetry.lock +++ b/backend/poetry.lock @@ -376,13 +376,13 @@ files = [ [[package]] name = "django" -version = "5.0.3" +version = "5.0.4" description = "A high-level Python web framework that encourages rapid development and clean, pragmatic design." optional = false python-versions = ">=3.10" files = [ - {file = "Django-5.0.3-py3-none-any.whl", hash = "sha256:5c7d748ad113a81b2d44750ccc41edc14e933f56581683db548c9257e078cc83"}, - {file = "Django-5.0.3.tar.gz", hash = "sha256:5fb37580dcf4a262f9258c1f4373819aacca906431f505e4688e37f3a99195df"}, + {file = "Django-5.0.4-py3-none-any.whl", hash = "sha256:916423499d75d62da7aa038d19aef23d23498d8df229775eb0a6309ee1013775"}, + {file = "Django-5.0.4.tar.gz", hash = "sha256:4bd01a8c830bb77a8a3b0e7d8b25b887e536ad17a81ba2dce5476135c73312bd"}, ] [package.dependencies] @@ -429,6 +429,21 @@ djangorestframework = ">=3.5.4" openapi-codec = ">=1.3.1" simplejson = "*" +[[package]] +name = "django-seed" +version = "0.3.1" +description = "Seed your Django project with fake data" +optional = false +python-versions = "*" +files = [ + {file = "django-seed-0.3.1.tar.gz", hash = "sha256:93e65d2c10449c464b83e9031be02763ec10e786aa064d649c4dd5ad06fa0eea"}, +] + +[package.dependencies] +django = ">=1.11" +Faker = ">=0.7.7" +toposort = ">=1.5" + [[package]] name = "django-sslserver" version = "0.22" @@ -504,6 +519,20 @@ uritemplate = ">=3.0.0" coreapi = ["coreapi (>=2.3.3)", "coreschema (>=0.0.4)"] validation = ["swagger-spec-validator (>=2.1.0)"] +[[package]] +name = "faker" +version = "24.7.1" +description = "Faker is a Python package that generates fake data for you." +optional = false +python-versions = ">=3.8" +files = [ + {file = "Faker-24.7.1-py3-none-any.whl", hash = "sha256:73f2bd886e8ce751e660c7d37a6c0a128aab5e1551359335bb79cfea0f4fabfc"}, + {file = "Faker-24.7.1.tar.gz", hash = "sha256:39d34c63f0d62ed574161e23fe32008917b923d18098ce94c2650fe16463b7d5"}, +] + +[package.dependencies] +python-dateutil = ">=2.4" + [[package]] name = "filelock" version = "3.13.3" @@ -1220,6 +1249,17 @@ dev = ["build", "flake8"] doc = ["sphinx"] test = ["pytest", "pytest-cov"] +[[package]] +name = "toposort" +version = "1.10" +description = "Implements a topological sort algorithm." +optional = false +python-versions = "*" +files = [ + {file = "toposort-1.10-py3-none-any.whl", hash = "sha256:cbdbc0d0bee4d2695ab2ceec97fe0679e9c10eab4b2a87a9372b929e70563a87"}, + {file = "toposort-1.10.tar.gz", hash = "sha256:bfbb479c53d0a696ea7402601f4e693c97b0367837c8898bc6471adfca37a6bd"}, +] + [[package]] name = "tox" version = "4.14.2" @@ -1355,4 +1395,4 @@ brotli = ["Brotli"] [metadata] lock-version = "2.0" python-versions = "^3.11.4" -content-hash = "2341567194c05d05a9617a1b812d26c63366ba3cc07ae842859102d9eadac972" +content-hash = "fc72c38f240e3a93e01f87850a6c16277b594999fd49891fc71107bd9e5ceeaf" diff --git a/backend/pyproject.toml b/backend/pyproject.toml index 4dcfceac..7cd91ced 100644 --- a/backend/pyproject.toml +++ b/backend/pyproject.toml @@ -23,8 +23,10 @@ gunicorn = "^21.2.0" whitenoise = "^6.6.0" flake8 = "^7.0.0" celery-types = "^0.22.0" +faker = "^24.7.1" +django-seed = "^0.3.1" [build-system] -requires = ["poetry-core"] +requires = ["poetry-core>=1.0.0"] build-backend = "poetry.core.masonry.api" diff --git a/backend/ypovoli/settings.py b/backend/ypovoli/settings.py index 27d287c9..71b15063 100644 --- a/backend/ypovoli/settings.py +++ b/backend/ypovoli/settings.py @@ -49,6 +49,7 @@ "authentication", # Ypovoli authentication "api", # Ypovoli logic of the base application "notifications", # Ypovoli notifications + "django_seed", # seeding the database ] MIDDLEWARE = [ From 172fda9a8271ecf10bc2951561d609ff46bbfcb3 Mon Sep 17 00:00:00 2001 From: tyboro2002 Date: Sat, 6 Apr 2024 20:34:36 +0200 Subject: [PATCH 08/33] chore: add student provider --- backend/api/management/commands/__init__.py | 0 backend/api/management/commands/seedDb.py | 54 +++++++++++++++++++++ backend/api/seeders/__init__.py | 0 backend/api/seeders/seeder.py | 19 ++++++++ backend/ypovoli/settings.py | 1 - 5 files changed, 73 insertions(+), 1 deletion(-) create mode 100644 backend/api/management/commands/__init__.py create mode 100644 backend/api/management/commands/seedDb.py create mode 100644 backend/api/seeders/__init__.py create mode 100644 backend/api/seeders/seeder.py diff --git a/backend/api/management/commands/__init__.py b/backend/api/management/commands/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/backend/api/management/commands/seedDb.py b/backend/api/management/commands/seedDb.py new file mode 100644 index 00000000..b1c66286 --- /dev/null +++ b/backend/api/management/commands/seedDb.py @@ -0,0 +1,54 @@ +from django.core.management.base import BaseCommand +from faker import Faker +from django.utils import timezone +from faker.providers import BaseProvider + +from api.models.student import Student + + +fake = Faker() + +def create_student(first_name, last_name, email, faculty=None, courses=None): + """ + Create a student with the given arguments. + """ + username = f"{first_name}_{last_name}" + student = Student.objects.create( + id=fake.unique.random_int(min=1, max = 9999999999999999999999), + first_name=first_name, + last_name=last_name, + username=username, + email=email, + create_time=timezone.now(), + ) + + if faculty is not None: + for fac in faculty: + student.faculties.add(fac) + + if courses is not None: + for cours in courses: + student.courses.add(cours) + + return student + +# create new provider class +class Providers(BaseProvider): + def provide_student(self) -> Student: + return create_student(first_name=fake.first_name(), last_name=fake.last_name(), email=fake.email()) + + # then add new provider to faker instance +fake.add_provider(Providers) + +def getFakeStudent(): + return fake.provide_student() + +class Command(BaseCommand): + help = 'seed the db with data' + + def handle(self, *args, **options): + # Your command logic here + # Create a fake student instance + fake_student = getFakeStudent() + + self.stdout.write(self.style.SUCCESS('Successfully ran my custom command!')) diff --git a/backend/api/seeders/__init__.py b/backend/api/seeders/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/backend/api/seeders/seeder.py b/backend/api/seeders/seeder.py new file mode 100644 index 00000000..a24b47bd --- /dev/null +++ b/backend/api/seeders/seeder.py @@ -0,0 +1,19 @@ +from faker import Faker + +# first, import a similar Provider or use the default one +from faker.providers import BaseProvider + +from api.models.student import Student + +fake = Faker() + +# create new provider class +class Providers(BaseProvider): + def provide_student(self) -> Student: + return Student() + +# then add new provider to faker instance +fake.add_provider(Providers) + +def printFakeStudent(): + print(fake.provide_student()) \ No newline at end of file diff --git a/backend/ypovoli/settings.py b/backend/ypovoli/settings.py index 71b15063..27d287c9 100644 --- a/backend/ypovoli/settings.py +++ b/backend/ypovoli/settings.py @@ -49,7 +49,6 @@ "authentication", # Ypovoli authentication "api", # Ypovoli logic of the base application "notifications", # Ypovoli notifications - "django_seed", # seeding the database ] MIDDLEWARE = [ From a6957c8090d64914838d834896830146531661ff Mon Sep 17 00:00:00 2001 From: tyboro2002 Date: Sat, 6 Apr 2024 22:06:21 +0200 Subject: [PATCH 09/33] chore: seed courses --- backend/api/management/commands/seedDb.py | 112 ++++++++++++++++------ 1 file changed, 82 insertions(+), 30 deletions(-) diff --git a/backend/api/management/commands/seedDb.py b/backend/api/management/commands/seedDb.py index b1c66286..74bceb93 100644 --- a/backend/api/management/commands/seedDb.py +++ b/backend/api/management/commands/seedDb.py @@ -2,46 +2,86 @@ from faker import Faker from django.utils import timezone from faker.providers import BaseProvider +from faker.providers import DynamicProvider from api.models.student import Student - +from api.models.course import Course +from authentication.models import Faculty fake = Faker() -def create_student(first_name, last_name, email, faculty=None, courses=None): - """ - Create a student with the given arguments. - """ - username = f"{first_name}_{last_name}" - student = Student.objects.create( - id=fake.unique.random_int(min=1, max = 9999999999999999999999), - first_name=first_name, - last_name=last_name, - username=username, - email=email, - create_time=timezone.now(), - ) - - if faculty is not None: - for fac in faculty: - student.faculties.add(fac) - - if courses is not None: - for cours in courses: - student.courses.add(cours) - - return student +faculty_provider = DynamicProvider( + provider_name="faculty_provider", + elements=Faculty.objects.all(), +) + +student_provider = DynamicProvider( + provider_name="student_provider", + elements=Student.objects.all(), +) + +course_provider = DynamicProvider( + provider_name="course_provider", + elements=Course.objects.all(), +) # create new provider class class Providers(BaseProvider): - def provide_student(self) -> Student: - return create_student(first_name=fake.first_name(), last_name=fake.last_name(), email=fake.email()) + def provide_course(description=None, parent_course=None): + """ + Create a Course with the given arguments. + """ + course_name = fake.catch_phrase() + return Course.objects.create( + name=course_name, + academic_startyear=timezone.now().year, + faculty=fake.faculty_provider(), + description=fake.paragraph(), + parent_course=parent_course, + ) + + def provide_student(self, faculty=None, courses=None): + """ + Create a student with the given arguments. + """ + first = fake.first_name() + last = fake.last_name() + id = fake.unique.random_int(min=1, max = 9999999999999999999999) + faculty = [fake.faculty_provider().id for _ in range(0,fake.random_int(min=1, max = 3))] # generate 1 or 2 or 3 facultys + username = f"{first}_{last}_{fake.random_int(min=1, max = 9999999999999999999999)}" + student = Student.objects.create( + id=id, + first_name=first, + last_name=last, + username=username, + email=username+"@example.com", + create_time=timezone.now(), + last_enrolled= timezone.now().year, + student_id=id, + is_staff=fake.boolean(chance_of_getting_true=0.01) + ) + + if faculty is not None: + for fac in faculty: + student.faculties.add(fac) + + if courses is not None: + for cours in courses: + student.courses.add(cours) + + return student + +def update_providers(): + faculty_provider.elements = Faculty.objects.all() + student_provider.elements = Student.objects.all() + course_provider.elements = Course.objects.all() + # then add new provider to faker instance fake.add_provider(Providers) - -def getFakeStudent(): - return fake.provide_student() +fake.add_provider(faculty_provider) +fake.add_provider(student_provider) +fake.add_provider(course_provider) class Command(BaseCommand): help = 'seed the db with data' @@ -49,6 +89,18 @@ class Command(BaseCommand): def handle(self, *args, **options): # Your command logic here # Create a fake student instance - fake_student = getFakeStudent() + + amountOfStudents = 1 + amountOfCourses = 1 + + for _ in range(0,amountOfStudents): + fake.provide_student() + + update_providers() + + for _ in range(0,amountOfCourses): + fake.provide_course() + + update_providers() self.stdout.write(self.style.SUCCESS('Successfully ran my custom command!')) From 9269394dd0b65782cb6963ff60f5c7bb365ad6ad Mon Sep 17 00:00:00 2001 From: lander Date: Sat, 6 Apr 2024 22:13:19 +0200 Subject: [PATCH 10/33] Frontend: ProjectView --- backend/api/fixtures/submissions.yaml | 15 +++++++++++++ .../components/projects/SubmissionCard.vue | 22 +++++++++++++------ frontend/src/router/router.ts | 2 ++ frontend/src/types/Submission.ts | 4 ++-- .../projects/roles/StudentProjectView.vue | 6 +++-- 5 files changed, 38 insertions(+), 11 deletions(-) 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/frontend/src/components/projects/SubmissionCard.vue b/frontend/src/components/projects/SubmissionCard.vue index f9b1f00c..3318218e 100644 --- a/frontend/src/components/projects/SubmissionCard.vue +++ b/frontend/src/components/projects/SubmissionCard.vue @@ -2,21 +2,30 @@ /* Component props */ import { type Project } from '@/types/Projects.ts'; import { PrimeIcons } from 'primevue/api'; -import Button from 'primevue/button'; import Card from 'primevue/card'; import { useI18n } from 'vue-i18n'; -import { computed } from 'vue'; +import {computed, onMounted} from 'vue'; +import {useSubmission} from "@/composables/services/submission.service.ts"; +import {Group} from "@/types/Group.ts"; +import Button from "primevue/button"; const { t } = useI18n(); +const { submissions, getSubmissionByGroup } = useSubmission(); const props = defineProps<{ project: Project; + group: Group; }>(); +onMounted(() => { + getSubmissionByGroup(props.group.id); +}); + const formattedDeadline = computed(() => { // changes deadline format to dd/mm.yyyy const date = new Date(props.project.deadline); return `${date.getDate()}/${date.getMonth() + 1}/${date.getFullYear()}`; + }); @@ -30,16 +39,15 @@ const formattedDeadline = computed(() => {
- {{ t('views.projects.submissionStatus') }}: {{ project.submissions.at(-1)?.structureChecks_passed }} + {{ t('views.projects.submissionStatus') }}: {{ submissions? submissions.at(-1)?.structure_checks_passed: "false"}}
-