From 6abe522828bd9450295e3fdecd0147f9fc8303ca Mon Sep 17 00:00:00 2001 From: rdyselinck Date: Wed, 22 May 2024 18:51:33 +0200 Subject: [PATCH 1/3] Simple tests in frontend --- ...bmissions_feedback_simple_test_and_more.py | 23 ++++++++ backend/pigeonhole/apps/submissions/models.py | 4 ++ backend/pigeonhole/apps/submissions/views.py | 38 +++++++------ .../app/[locale]/components/CourseCard.tsx | 2 +- .../components/SubmissionDetailsPage.tsx | 50 +++++++++++++++--- .../[locale]/components/SubmitDetailsPage.tsx | 4 +- frontend/lib/api.ts | 10 ++-- frontend/locales/en/common.json | 6 ++- frontend/locales/nl/common.json | 6 ++- .../opdracht_enkel_verboden/extra/verslag.pdf | Bin scripts/opdracht_enkel_verboden/src/main.py | 0 .../opdracht_enkel_verboden/tests/test.test | 0 scripts/opdracht_incorrect/tests/test.test | 1 + 13 files changed, 111 insertions(+), 33 deletions(-) create mode 100644 backend/pigeonhole/apps/submissions/migrations/0005_submissions_feedback_simple_test_and_more.py create mode 100644 scripts/opdracht_enkel_verboden/extra/verslag.pdf create mode 100644 scripts/opdracht_enkel_verboden/src/main.py create mode 100644 scripts/opdracht_enkel_verboden/tests/test.test create mode 100644 scripts/opdracht_incorrect/tests/test.test diff --git a/backend/pigeonhole/apps/submissions/migrations/0005_submissions_feedback_simple_test_and_more.py b/backend/pigeonhole/apps/submissions/migrations/0005_submissions_feedback_simple_test_and_more.py new file mode 100644 index 00000000..1a9af38e --- /dev/null +++ b/backend/pigeonhole/apps/submissions/migrations/0005_submissions_feedback_simple_test_and_more.py @@ -0,0 +1,23 @@ +# Generated by Django 4.2.13 on 2024-05-22 15:53 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('submissions', '0004_remove_submissions_file_and_more'), + ] + + operations = [ + migrations.AddField( + model_name='submissions', + name='feedback_simple_test', + field=models.JSONField(blank=True, null=True), + ), + migrations.AddField( + model_name='submissions', + name='output_simple_test', + field=models.BooleanField(blank=True, default=False), + ), + ] diff --git a/backend/pigeonhole/apps/submissions/models.py b/backend/pigeonhole/apps/submissions/models.py index f1df2f89..da968bee 100644 --- a/backend/pigeonhole/apps/submissions/models.py +++ b/backend/pigeonhole/apps/submissions/models.py @@ -31,6 +31,8 @@ class Submissions(models.Model): file_urls = models.TextField(null=True) timestamp = models.DateTimeField(auto_now_add=True, blank=True) draft = models.BooleanField(default=True) + output_simple_test = models.BooleanField(default=False, blank=True) + feedback_simple_test = models.JSONField(null=True, blank=True) objects = models.Manager() # submission_nr is automatically assigned and unique per group, and @@ -58,4 +60,6 @@ class Meta: "submission_nr", "group_id", "draft", + "output_simple_test", + "feedback_simple_test", ] diff --git a/backend/pigeonhole/apps/submissions/views.py b/backend/pigeonhole/apps/submissions/views.py index 61504082..22bb167b 100644 --- a/backend/pigeonhole/apps/submissions/views.py +++ b/backend/pigeonhole/apps/submissions/views.py @@ -1,4 +1,5 @@ import fnmatch +import json import os import shutil import zipfile @@ -75,9 +76,6 @@ def create(self, request, *args, **kwargs): else: file_urls = request.data["file_urls"].split(",") - serializer = SubmissionsSerializer(data=data) - serializer.is_valid(raise_exception=True) - if not group: return Response( {"message": "Group not found", "errorcode": @@ -101,6 +99,26 @@ def create(self, request, *args, **kwargs): status=status.HTTP_400_BAD_REQUEST ) + project = Project.objects.get(project_id=group.project_id.project_id) + # return Response(",".join(file_urls), status=status.HTTP_201_CREATED) + if project.file_structure is None or project.file_structure == "": + complete_message = {"message": "Submission successful"} + else: + violations = check_restrictions(file_urls, project.file_structure.split(",")) + + if not violations[0] and not violations[2]: + complete_message = {"success": 0} + data["output_simple_test"] = True + else: + violations.update({'success': 1}) + data["output_simple_test"] = False + complete_message = violations + + json_violations = json.dumps(violations) + data["feedback_simple_test"] = json_violations + + serializer = SubmissionsSerializer(data=data) + serializer.is_valid(raise_exception=True) serializer.save() # upload files @@ -123,19 +141,7 @@ def create(self, request, *args, **kwargs): "ERROR_FILE_UPLOAD"}, status=status.HTTP_400_BAD_REQUEST ) - project = Project.objects.get(project_id=group.project_id.project_id) - # return Response(",".join(file_urls), status=status.HTTP_201_CREATED) - if project.file_structure is None or project.file_structure == "": - complete_message = {"message": "Submission successful"} - else: - violations = check_restrictions(file_urls, project.file_structure.split(",")) - - if not violations[0] and not violations[2]: - complete_message = {"success": 0} - else: - violations.update({'success': 1}) - complete_message = violations - + complete_message["submission_id"] = serializer.data["submission_id"] return Response(complete_message, status=status.HTTP_201_CREATED) def update(self, request, *args, **kwargs): diff --git a/frontend/app/[locale]/components/CourseCard.tsx b/frontend/app/[locale]/components/CourseCard.tsx index 6d7f6386..91aefd18 100644 --- a/frontend/app/[locale]/components/CourseCard.tsx +++ b/frontend/app/[locale]/components/CourseCard.tsx @@ -16,7 +16,7 @@ const CourseCard = ({params: {course}}: { params: { course: Course } }) => { submission_nr: 0, file: '', timestamp: '', - output_test: '', + output_simple_test: '', }); const [hover, setHover] = useState(false); diff --git a/frontend/app/[locale]/components/SubmissionDetailsPage.tsx b/frontend/app/[locale]/components/SubmissionDetailsPage.tsx index a8b1a1d1..9aeb2edf 100644 --- a/frontend/app/[locale]/components/SubmissionDetailsPage.tsx +++ b/frontend/app/[locale]/components/SubmissionDetailsPage.tsx @@ -27,7 +27,9 @@ const ProjectDetailsPage: React.FC = ({ locale, submiss useEffect(() => { const fetchSubmission = async () => { try { - setSubmission(await getSubmission(submission_id)); + const async_submission = await getSubmission(submission_id); + setSubmission(async_submission); + console.log(async_submission); } catch (error) { console.error("There was an error fetching the submission data:", error); } @@ -65,11 +67,11 @@ const ProjectDetailsPage: React.FC = ({ locale, submiss return ( - - - + + + - + @@ -82,14 +84,14 @@ const ProjectDetailsPage: React.FC = ({ locale, submiss {`${t("evaluation")} status`}
- {submission?.output_test !== "" ? ( + {submission?.output_simple_test ? ( ) : ( )}
- {submission?.output_test !== "" ? t("accepted") : t("denied")} + {submission?.output_simple_test ? t("accepted") : t("denied")} {`(${t("timestamp")}: ${formatDate(submission?.timestamp)})`} @@ -113,6 +115,40 @@ const ProjectDetailsPage: React.FC = ({ locale, submiss + { + !submission?.output_simple_test ? ( + <> + + + {submission?.feedback_simple_test["0"].length > 0 ? ( + <> + + {t("feedback_simple_test_0")} + + {submission?.feedback_simple_test["0"].map((feedback, index) => ( + + {feedback} + + ))} + + ) : null} + + {submission?.feedback_simple_test["2"].length > 0 ? ( + <> + + {t("feedback_simple_test_2")} + + {submission?.feedback_simple_test["2"].map((feedback, index) => ( + + {feedback} + + ))} + + ) : null} + + ) : null + } + diff --git a/frontend/app/[locale]/components/SubmitDetailsPage.tsx b/frontend/app/[locale]/components/SubmitDetailsPage.tsx index 33e213f1..9f159f29 100644 --- a/frontend/app/[locale]/components/SubmitDetailsPage.tsx +++ b/frontend/app/[locale]/components/SubmitDetailsPage.tsx @@ -57,7 +57,9 @@ const SubmitDetailsPage: React.FC = ({ }; const handleSubmit = async (e) => { - setSubmitted(await uploadSubmissionFile(e, project_id)); + const response = await uploadSubmissionFile(e, project_id); + setSubmitted(response); + window.location.href = `/submission/${response.submission_id}/`; }; useEffect(() => { diff --git a/frontend/lib/api.ts b/frontend/lib/api.ts index 37cafd91..dd74a828 100644 --- a/frontend/lib/api.ts +++ b/frontend/lib/api.ts @@ -78,7 +78,8 @@ export type Submission = { submission_nr: number; file: string; timestamp: string; - output_test: string; + output_simple_test: boolean; + feedback_simple_test: object; } export type UserData = { @@ -681,13 +682,14 @@ export async function joinCourseUsingToken(course_id: number, token: string) { type uploadResult = { result: string; errorcode: string | undefined; + submission_id: number; } export async function uploadSubmissionFile(event: any, project_id: string) : Promise{ axios.defaults.headers.get['X-CSRFToken'] = getCookieValue('csrftoken'); axios.defaults.headers.post['X-CSRFToken'] = getCookieValue('csrftoken'); event.preventDefault(); - console.log(event.target.fileList.files); + const formData = new FormData(event.target); //filter files by key @@ -710,13 +712,13 @@ export async function uploadSubmissionFile(event: any, project_id: string) : Pro let groupres = await axios.get(backend_url + "/projects/" + project_id + "/get_group/", {withCredentials: true}); const group_id = groupres.data.group_id; formDataObject.group_id = group_id; - await axios.post(backend_url + '/submissions/', formDataObject, + const response = await axios.post(backend_url + '/submissions/', formDataObject, { withCredentials: true, headers: { 'Content-Type': 'multipart/form-data' } }); - return {result: "ok", errorcode: undefined}; + return {result: "ok", errorcode: undefined, submission_id: response.data.submission_id}; } catch (error) { const apierror : APIError = new APIError(); apierror.message = "error posting form"; diff --git a/frontend/locales/en/common.json b/frontend/locales/en/common.json index 9c0a57b0..31e100bc 100644 --- a/frontend/locales/en/common.json +++ b/frontend/locales/en/common.json @@ -1,5 +1,5 @@ { - "accepted": "accepted", + "accepted": "Accepted", "description_of_your_course": "Description of your course", "access": "Access", "action_dialog": "This action cannot be undone.", @@ -140,5 +140,7 @@ "join_leave": "Join/Leave", "not_in_group": "Join a group to submit", "edit_user_details": "Edit user details", - "status_button_tooltip": "Required, optional or forbidden file" + "status_button_tooltip": "Required, optional or forbidden file", + "feedback_simple_test_0": "You forgot to upload the following files:", + "feedback_simple_test_2": "You uploaded the following files that were not required:" } \ No newline at end of file diff --git a/frontend/locales/nl/common.json b/frontend/locales/nl/common.json index 945625dd..8a7994e2 100644 --- a/frontend/locales/nl/common.json +++ b/frontend/locales/nl/common.json @@ -1,5 +1,5 @@ { - "accepted": "aanvaard", + "accepted": "Aanvaard", "description_of_your_course": "Beschrijving van je cursus", "access": "Toegang", "action_dialog": "Deze actie kan niet ongedaan worden gemaakt.", @@ -143,5 +143,7 @@ "join_leave": "Toetreden/Verlaten", "not_in_group": "Je kan niet indienen zonder in een groep te zitten", "edit_user_details": "Gebruiker bewerken", - "status_button_tooltip": "Verplicht, optioneel of verboden bestand" + "status_button_tooltip": "Verplicht, optioneel of verboden bestand", + "feedback_simple_test_0": "Je hebt de volgende bestanden niet ingeleverd:", + "feedback_simple_test_2": "Je hebt de volgende bestanden ingeleverd die niet nodig zijn:" } \ No newline at end of file diff --git a/scripts/opdracht_enkel_verboden/extra/verslag.pdf b/scripts/opdracht_enkel_verboden/extra/verslag.pdf new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/scripts/opdracht_enkel_verboden/src/main.py b/scripts/opdracht_enkel_verboden/src/main.py new file mode 100644 index 00000000..e69de29b diff --git a/scripts/opdracht_enkel_verboden/tests/test.test b/scripts/opdracht_enkel_verboden/tests/test.test new file mode 100644 index 00000000..e69de29b diff --git a/scripts/opdracht_incorrect/tests/test.test b/scripts/opdracht_incorrect/tests/test.test new file mode 100644 index 00000000..73d1dd37 --- /dev/null +++ b/scripts/opdracht_incorrect/tests/test.test @@ -0,0 +1 @@ +dit bestand is verboden From 008e2ae90d8b44aedf1be48f6197619303b826b5 Mon Sep 17 00:00:00 2001 From: rdyselinck Date: Wed, 22 May 2024 19:11:29 +0200 Subject: [PATCH 2/3] Updated status in listview --- frontend/app/[locale]/components/CourseCard.tsx | 14 ++------------ frontend/app/[locale]/components/ListView.tsx | 4 ++-- 2 files changed, 4 insertions(+), 14 deletions(-) diff --git a/frontend/app/[locale]/components/CourseCard.tsx b/frontend/app/[locale]/components/CourseCard.tsx index 91aefd18..44b60f4d 100644 --- a/frontend/app/[locale]/components/CourseCard.tsx +++ b/frontend/app/[locale]/components/CourseCard.tsx @@ -16,7 +16,8 @@ const CourseCard = ({params: {course}}: { params: { course: Course } }) => { submission_nr: 0, file: '', timestamp: '', - output_simple_test: '', + output_simple_test: false, + feedback_simple_test: {}, }); const [hover, setHover] = useState(false); @@ -45,17 +46,6 @@ const CourseCard = ({params: {course}}: { params: { course: Course } }) => { - - - - - - - - - - - const headers = [ {" " + t('name')}, {" " +t('deadline')}, diff --git a/frontend/app/[locale]/components/ListView.tsx b/frontend/app/[locale]/components/ListView.tsx index 93e822bd..7aa4760f 100644 --- a/frontend/app/[locale]/components/ListView.tsx +++ b/frontend/app/[locale]/components/ListView.tsx @@ -186,8 +186,8 @@ const ListView: NextPage = ({ setGroupSize((await getProject(data.project_id)).group_size); return [data.group_id, data.user, data.group_nr, l.join(', ')]; }, - 'submissions': (data) => [data.submission_id, data.group_id, convertDate(data.timestamp), data.output_test !== undefined], - 'submissions_group': (data) => [data.submission_id, data.group_id, convertDate(data.timestamp), data.output_test !== undefined], + 'submissions': (data) => [data.submission_id, data.group_id, convertDate(data.timestamp), data.output_simple_test], + 'submissions_group': (data) => [data.submission_id, data.group_id, convertDate(data.timestamp), data.output_simple_test], 'archived_courses': (data) => [data.course_id, data.name, data.description, data.open_course], }; From 97f3281764b24b330efd458c771bc522a3e798de Mon Sep 17 00:00:00 2001 From: rdyselinck Date: Wed, 22 May 2024 19:35:00 +0200 Subject: [PATCH 3/3] fixed import missing --- frontend/app/[locale]/components/ProjectDetailsPage.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/app/[locale]/components/ProjectDetailsPage.tsx b/frontend/app/[locale]/components/ProjectDetailsPage.tsx index d2374f8d..f0c4b093 100644 --- a/frontend/app/[locale]/components/ProjectDetailsPage.tsx +++ b/frontend/app/[locale]/components/ProjectDetailsPage.tsx @@ -1,6 +1,6 @@ 'use client' import React, { useEffect, useState } from "react"; -import {checkGroup, getGroup, getProject, getUserData, Project, UserData} from "@lib/api"; +import {checkGroup, fetchUserData, getGroup, getProject, getUserData, Project, UserData} from "@lib/api"; import { useTranslation } from "react-i18next"; import Box from "@mui/material/Box"; import Typography from "@mui/material/Typography";