From b8813482b08327c350100339e6e3fcd1de822fc0 Mon Sep 17 00:00:00 2001 From: Christian Cueni Date: Thu, 13 Jun 2024 14:45:53 +0200 Subject: [PATCH] Fix export, add client code and urls --- client/src/services/dashboard.ts | 23 ++++++++++++- server/config/urls.py | 6 +++- .../dashboard/tests/test_views.py | 18 ++++++---- server/vbv_lernwelt/dashboard/views.py | 34 ++++++++++++------- server/vbv_lernwelt/feedback/export.py | 1 + 5 files changed, 62 insertions(+), 20 deletions(-) diff --git a/client/src/services/dashboard.ts b/client/src/services/dashboard.ts index 2abd9374..da2664bb 100644 --- a/client/src/services/dashboard.ts +++ b/client/src/services/dashboard.ts @@ -6,7 +6,7 @@ import { DASHBOARD_MENTOR_COMPETENCE_SUMMARY, } from "@/graphql/queries"; -import { itGetCached } from "@/fetchHelpers"; +import { itGetCached, itPost } from "@/fetchHelpers"; import type { AssignmentsStatisticsType, CourseProgressType, @@ -189,6 +189,27 @@ export async function fetchOpenTasksCount(courseId: string) { ); } +export async function exportFeedback(data: { + courseSessionIds: string[]; + circleIds: string[]; +}) { + return await itPost("/api/dashboard/export/feedback/", data); +} + +export async function exportAttendance(data: { + courseSessionIds: string[]; + circleIds: string[]; +}) { + return await itPost("/api/dashboard/export/attendance/", data); +} + +export async function exportCertificate(data: { + courseSessionIds: string[]; + circleIds: string[]; +}) { + return await itPost("/api/dashboard/export/certificate/", data); +} + export function courseIdForCourseSlug( dashboardConfigs: DashboardCourseConfigType[], courseSlug: string diff --git a/server/config/urls.py b/server/config/urls.py index c65d0665..4748e663 100644 --- a/server/config/urls.py +++ b/server/config/urls.py @@ -42,6 +42,8 @@ from vbv_lernwelt.course.views import ( from vbv_lernwelt.course_session.views import get_course_session_documents from vbv_lernwelt.dashboard.views import ( export_attendance_as_xsl, + export_competence_certificate_as_xsl, + export_feedback_as_xsl, get_dashboard_config, get_dashboard_due_dates, get_dashboard_persons, @@ -132,7 +134,9 @@ urlpatterns = [ path(r"api/dashboard/course//mentees/", get_mentee_count, name="get_mentee_count"), path(r"api/dashboard/course//open_tasks/", get_mentor_open_tasks_count, name="get_mentor_open_tasks_count"), - path(r"api/dashboard/export/attendance", export_attendance_as_xsl, name="export_attendance_as_xsl"), + path(r"api/dashboard/export/attendance/", export_attendance_as_xsl, name="export_attendance_as_xsl"), + path(r"api/dashboard/export/certificate/", export_competence_certificate_as_xsl, name="export_certificate_as_xsl"), + path(r"api/dashboard/export/feedback/", export_feedback_as_xsl, name="export_feedback_as_xsl"), # course path(r"api/course/sessions/", get_course_sessions, name="get_course_sessions"), diff --git a/server/vbv_lernwelt/dashboard/tests/test_views.py b/server/vbv_lernwelt/dashboard/tests/test_views.py index 0d7423bc..d3eaeae7 100644 --- a/server/vbv_lernwelt/dashboard/tests/test_views.py +++ b/server/vbv_lernwelt/dashboard/tests/test_views.py @@ -452,7 +452,10 @@ class ExportXlsTestCase(TestCase): def test_can_export_cs_dats(self): # supervisor sees all cs in region supervisor = User.objects.get(id=TEST_SUPERVISOR1_USER_ID) - requested_cs_ids = [TEST_COURSE_SESSION_ZURICH_ID, TEST_COURSE_SESSION_BERN_ID] + requested_cs_ids = [ + str(TEST_COURSE_SESSION_ZURICH_ID), + str(TEST_COURSE_SESSION_BERN_ID), + ] allowed_csrs_ids = _get_course_sessions_with_roles_for_user( supervisor, self.ALLOWED_ROLES, requested_cs_ids @@ -463,7 +466,7 @@ class ExportXlsTestCase(TestCase): def test_student_cannot_export_data(self): # student cannot export any data student = User.objects.get(id=TEST_STUDENT1_USER_ID) - requested_cs_ids = [TEST_COURSE_SESSION_ZURICH_ID] + requested_cs_ids = [str(TEST_COURSE_SESSION_ZURICH_ID)] allowed_csrs_ids = _get_course_sessions_with_roles_for_user( student, self.ALLOWED_ROLES, requested_cs_ids @@ -473,7 +476,10 @@ class ExportXlsTestCase(TestCase): def test_trainer_cannot_export_other_cs(self): # trainer can only export cs where she is assigned trainer = User.objects.get(email="test-trainer2@example.com") - requested_cs_ids = [TEST_COURSE_SESSION_BERN_ID, TEST_COURSE_SESSION_ZURICH_ID] + requested_cs_ids = [ + str(TEST_COURSE_SESSION_BERN_ID), + str(TEST_COURSE_SESSION_ZURICH_ID), + ] allowed_csrs_ids = _get_course_sessions_with_roles_for_user( trainer, self.ALLOWED_ROLES, requested_cs_ids @@ -486,7 +492,7 @@ class ExportXlsTestCase(TestCase): def test_trainer_can_get_circles_where_expert(self): trainer = User.objects.get(email="test-trainer2@example.com") circle = Circle.objects.get(slug="test-lehrgang-lp-circle-fahrzeug") - requested_cs_ids = [TEST_COURSE_SESSION_ZURICH_ID] + requested_cs_ids = [str(TEST_COURSE_SESSION_ZURICH_ID)] allowed_csrs_ids = _get_course_sessions_with_roles_for_user( trainer, self.ALLOWED_ROLES, requested_cs_ids @@ -502,7 +508,7 @@ class ExportXlsTestCase(TestCase): def test_trainer_cannot_get_circles_where_not_expert(self): trainer = User.objects.get(email="test-trainer2@example.com") circle = Circle.objects.get(slug="test-lehrgang-lp-circle-reisen") - requested_cs_ids = [TEST_COURSE_SESSION_ZURICH_ID] + requested_cs_ids = [str(TEST_COURSE_SESSION_ZURICH_ID)] allowed_csrs_ids = _get_course_sessions_with_roles_for_user( trainer, self.ALLOWED_ROLES, requested_cs_ids @@ -517,7 +523,7 @@ class ExportXlsTestCase(TestCase): supervisor = User.objects.get(id=TEST_SUPERVISOR1_USER_ID) circle_reisen = Circle.objects.get(slug="test-lehrgang-lp-circle-reisen") circle_fahrzeug = Circle.objects.get(slug="test-lehrgang-lp-circle-fahrzeug") - requested_cs_ids = [TEST_COURSE_SESSION_ZURICH_ID] + requested_cs_ids = [str(TEST_COURSE_SESSION_ZURICH_ID)] allowed_csrs_ids = _get_course_sessions_with_roles_for_user( supervisor, self.ALLOWED_ROLES, requested_cs_ids diff --git a/server/vbv_lernwelt/dashboard/views.py b/server/vbv_lernwelt/dashboard/views.py index f9aa54ec..41000109 100644 --- a/server/vbv_lernwelt/dashboard/views.py +++ b/server/vbv_lernwelt/dashboard/views.py @@ -1,3 +1,4 @@ +import base64 from dataclasses import asdict, dataclass from datetime import date from enum import Enum @@ -546,7 +547,8 @@ def export_attendance_as_xsl(request): request.user, requested_course_session_ids ) data = export_attendance( - [cs.id for cs in course_sessions_with_roles], circle_ids=circle_ids + [cs.id for cs in course_sessions_with_roles], + circle_ids=[int(circle_id) for circle_id in circle_ids], ) return _make_excel_response(data) @@ -559,7 +561,8 @@ def export_competence_certificate_as_xsl(request): request.user, requested_course_session_ids ) data = export_competence_certificates( - course_sessions_with_roles, circle_ids=circle_ids + [cswr.id for cswr in course_sessions_with_roles], + circle_ids=[int(circle_id) for circle_id in circle_ids], ) return _make_excel_response(data) @@ -568,10 +571,17 @@ def export_competence_certificate_as_xsl(request): def export_feedback_as_xsl(request): circle_ids = request.data.get("circleIds", None) requested_course_session_ids = request.data.get("courseSessionIds", []) - course_sessions_with_roless = _get_permitted_courses_sessions_for_user( + course_sessions_with_roles = _get_permitted_courses_sessions_for_user( request.user, requested_course_session_ids - ) - data = export_feedback_with_circle_restriction() + ) # noqa + + allowed_circles = _get_permitted_circles_ids_for_user_and_course_session( + request.user, + course_sessions_with_roles, + circle_ids, + ) # noqa + + data = export_feedback_with_circle_restriction(allowed_circles, False) return _make_excel_response(data) @@ -588,12 +598,12 @@ def _get_permitted_courses_sessions_for_user( def _make_excel_response(data: bytes) -> HttpResponse: - response = HttpResponse( - data, - content_type="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", - ) - response["Content-Disposition"] = f'attachment; filename="{make_export_filename()}"' - return response + encoded_data = base64.b64encode(data).decode("utf-8") + + # Create the JSON response + response_data = {"encoded_data": encoded_data, "file_name": make_export_filename()} + + return Response(response_data, status=200) def _get_course_sessions_with_roles_for_user( @@ -603,7 +613,7 @@ def _get_course_sessions_with_roles_for_user( csr for csr in get_course_sessions_with_roles_for_user(user) if any(role in allowed_roles for role in csr.roles) - and csr.id in requested_cs_ids + and str(csr.id) in requested_cs_ids ] # noqa return all_cs_roles_for_user diff --git a/server/vbv_lernwelt/feedback/export.py b/server/vbv_lernwelt/feedback/export.py index cd4ec5af..bf81bbd7 100644 --- a/server/vbv_lernwelt/feedback/export.py +++ b/server/vbv_lernwelt/feedback/export.py @@ -118,6 +118,7 @@ def _generate_feedback_export(feedback_unordered: QuerySet, save_as_file: bool): if save_as_file: wb.save(make_export_filename(name="feedback_export")) else: + # todo handle IndexError output = BytesIO() wb.save(output)