Implement export
This commit is contained in:
parent
d38d2a4a4b
commit
49085ebdc4
|
|
@ -8,8 +8,8 @@ import {
|
||||||
exportPersons,
|
exportPersons,
|
||||||
} from "@/services/dashboard";
|
} from "@/services/dashboard";
|
||||||
import { useUserStore } from "@/stores/user";
|
import { useUserStore } from "@/stores/user";
|
||||||
import type { DashboardPersonsPageMode, StatisticsFilterItem } from "@/types";
|
import type { DashboardPersonsPageMode, XlsPersonExportRequestData } from "@/types";
|
||||||
import { exportDataAsXls } from "@/utils/export";
|
import { openDataAsXls } from "@/utils/export";
|
||||||
import { useRouteQuery } from "@vueuse/router";
|
import { useRouteQuery } from "@vueuse/router";
|
||||||
import dayjs from "dayjs";
|
import dayjs from "dayjs";
|
||||||
import { useTranslation } from "i18next-vue";
|
import { useTranslation } from "i18next-vue";
|
||||||
|
|
@ -302,7 +302,13 @@ const filtersVisible = computed(() => {
|
||||||
|
|
||||||
function personRoleDisplayValue(personCourseSession: DashboardPersonCourseSessionType) {
|
function personRoleDisplayValue(personCourseSession: DashboardPersonCourseSessionType) {
|
||||||
if (
|
if (
|
||||||
["SUPERVISOR", "EXPERT", "LEARNING_MENTOR"].includes(personCourseSession.user_role)
|
[
|
||||||
|
"SUPERVISOR",
|
||||||
|
"EXPERT",
|
||||||
|
"LEARNING_MENTOR",
|
||||||
|
"BERUFSBILDNER",
|
||||||
|
"LEARNING_MENTOR",
|
||||||
|
].includes(personCourseSession.user_role)
|
||||||
) {
|
) {
|
||||||
return personCourseSession.user_role_display;
|
return personCourseSession.user_role_display;
|
||||||
}
|
}
|
||||||
|
|
@ -310,31 +316,18 @@ function personRoleDisplayValue(personCourseSession: DashboardPersonCourseSessio
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
function exportData() {
|
async function exportData() {
|
||||||
const courseSessionIdsSet = new Set<string>();
|
const requestData: XlsPersonExportRequestData = filteredPersons.value.reduce(
|
||||||
// get all course session ids from users
|
(acc, person) => {
|
||||||
if (selectedSession.value.id === UNFILTERED) {
|
acc.courseSessionUserIds.push(person.csu_id);
|
||||||
for (const person of filteredPersons.value) {
|
return acc;
|
||||||
for (const courseSession of person.course_sessions) {
|
},
|
||||||
courseSessionIdsSet.add(courseSession.id);
|
{
|
||||||
}
|
courseSessionUserIds: [],
|
||||||
}
|
}
|
||||||
} else {
|
);
|
||||||
courseSessionIdsSet.add(selectedSession.value.id);
|
const data = await exportPersons(requestData, userStore.language);
|
||||||
}
|
openDataAsXls(data.encoded_data, data.file_name);
|
||||||
|
|
||||||
// construct StatisticsFilterItems for export call
|
|
||||||
const items: StatisticsFilterItem[] = [];
|
|
||||||
for (const csId of courseSessionIdsSet) {
|
|
||||||
items.push({
|
|
||||||
_id: "",
|
|
||||||
course_session_id: csId,
|
|
||||||
generation: "",
|
|
||||||
circle_id: "",
|
|
||||||
region: "",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
exportDataAsXls(items, exportPersons, userStore.language);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
watch(selectedCourse, () => {
|
watch(selectedCourse, () => {
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,7 @@ import type {
|
||||||
DueDate,
|
DueDate,
|
||||||
XlsExportRequestData,
|
XlsExportRequestData,
|
||||||
XlsExportResponseData,
|
XlsExportResponseData,
|
||||||
|
XlsPersonExportRequestData,
|
||||||
} from "@/types";
|
} from "@/types";
|
||||||
|
|
||||||
export type DashboardPersonRoleType =
|
export type DashboardPersonRoleType =
|
||||||
|
|
@ -273,7 +274,7 @@ export async function exportCompetenceElements(
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function exportPersons(
|
export async function exportPersons(
|
||||||
data: XlsExportRequestData,
|
data: XlsPersonExportRequestData,
|
||||||
language: string
|
language: string
|
||||||
): Promise<XlsExportResponseData> {
|
): Promise<XlsExportResponseData> {
|
||||||
return await itPost("/api/dashboard/export/persons/", data, {
|
return await itPost("/api/dashboard/export/persons/", data, {
|
||||||
|
|
|
||||||
|
|
@ -632,6 +632,7 @@ export type DashboardPersonsPageMode = "default" | "competenceMetrics";
|
||||||
|
|
||||||
export interface StatisticsFilterItem {
|
export interface StatisticsFilterItem {
|
||||||
_id: string;
|
_id: string;
|
||||||
|
course_session_user_id: string;
|
||||||
course_session_id: string;
|
course_session_id: string;
|
||||||
region: string;
|
region: string;
|
||||||
generation: string;
|
generation: string;
|
||||||
|
|
@ -643,6 +644,10 @@ export interface XlsExportRequestData {
|
||||||
circleIds: number[];
|
circleIds: number[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface XlsPersonExportRequestData {
|
||||||
|
courseSessionUserIds: number[];
|
||||||
|
}
|
||||||
|
|
||||||
export interface XlsExportResponseData {
|
export interface XlsExportResponseData {
|
||||||
encoded_data: string;
|
encoded_data: string;
|
||||||
file_name: string;
|
file_name: string;
|
||||||
|
|
|
||||||
|
|
@ -5,14 +5,12 @@ import structlog
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
from openpyxl import Workbook
|
from openpyxl import Workbook
|
||||||
|
|
||||||
from vbv_lernwelt.core.models import User
|
from vbv_lernwelt.course.models import CourseSessionUser
|
||||||
from vbv_lernwelt.course.models import CourseSession
|
|
||||||
from vbv_lernwelt.course_session.services.export_attendance import (
|
from vbv_lernwelt.course_session.services.export_attendance import (
|
||||||
add_user_headers,
|
add_user_headers,
|
||||||
make_export_filename,
|
make_export_filename,
|
||||||
sanitize_sheet_name,
|
|
||||||
)
|
)
|
||||||
from vbv_lernwelt.dashboard.utils import create_person_list_with_roles
|
from vbv_lernwelt.dashboard.utils import create_csu_dict
|
||||||
|
|
||||||
PERSONS_EXPORT_FILENAME = _("export_personen")
|
PERSONS_EXPORT_FILENAME = _("export_personen")
|
||||||
|
|
||||||
|
|
@ -20,29 +18,22 @@ logger = structlog.get_logger(__name__)
|
||||||
|
|
||||||
|
|
||||||
def export_persons(
|
def export_persons(
|
||||||
user: User,
|
course_session_users: list[CourseSessionUser],
|
||||||
course_session_ids: list[str],
|
|
||||||
save_as_file: bool = False,
|
save_as_file: bool = False,
|
||||||
) -> Optional[bytes]:
|
) -> Optional[bytes]:
|
||||||
if not course_session_ids:
|
if not course_session_users:
|
||||||
return
|
return
|
||||||
|
|
||||||
wb = Workbook()
|
wb = Workbook()
|
||||||
# remove the first sheet is just easier than keeping track of the active sheet
|
# remove the first sheet is just easier than keeping track of the active sheet
|
||||||
wb.remove(wb.active)
|
wb.remove(wb.active)
|
||||||
|
csu_data = [
|
||||||
user_with_roles = create_person_list_with_roles(
|
create_csu_dict(csu, include_private_data=True) for csu in course_session_users
|
||||||
user, course_session_ids, include_private_data=True
|
]
|
||||||
|
_create_sheet(
|
||||||
|
wb,
|
||||||
|
csu_data,
|
||||||
)
|
)
|
||||||
course_sessions = CourseSession.objects.filter(id__in=course_session_ids)
|
|
||||||
|
|
||||||
for cs in course_sessions:
|
|
||||||
_create_sheet(
|
|
||||||
wb,
|
|
||||||
cs.title,
|
|
||||||
cs.id,
|
|
||||||
user_with_roles,
|
|
||||||
)
|
|
||||||
|
|
||||||
if save_as_file:
|
if save_as_file:
|
||||||
wb.save(make_export_filename(PERSONS_EXPORT_FILENAME))
|
wb.save(make_export_filename(PERSONS_EXPORT_FILENAME))
|
||||||
|
|
@ -56,13 +47,11 @@ def export_persons(
|
||||||
|
|
||||||
def _create_sheet(
|
def _create_sheet(
|
||||||
wb: Workbook,
|
wb: Workbook,
|
||||||
title: str,
|
course_session_user_data: list[dict],
|
||||||
cs_id: int,
|
|
||||||
user_with_roles,
|
|
||||||
):
|
):
|
||||||
sheet = wb.create_sheet(title=sanitize_sheet_name(title))
|
sheet = wb.create_sheet()
|
||||||
|
|
||||||
if len(user_with_roles) == 0:
|
if len(course_session_user_data) == 0:
|
||||||
return sheet
|
return sheet
|
||||||
|
|
||||||
# headers
|
# headers
|
||||||
|
|
@ -71,7 +60,7 @@ def _create_sheet(
|
||||||
sheet.cell(row=1, column=col_idx, value=str(_("Telefon")))
|
sheet.cell(row=1, column=col_idx, value=str(_("Telefon")))
|
||||||
sheet.cell(row=1, column=col_idx + 1, value=str(_("Rolle")))
|
sheet.cell(row=1, column=col_idx + 1, value=str(_("Rolle")))
|
||||||
|
|
||||||
_add_rows(sheet, user_with_roles, cs_id)
|
_add_rows(sheet, course_session_user_data)
|
||||||
|
|
||||||
return sheet
|
return sheet
|
||||||
|
|
||||||
|
|
@ -79,27 +68,11 @@ def _create_sheet(
|
||||||
def _add_rows(
|
def _add_rows(
|
||||||
sheet,
|
sheet,
|
||||||
users,
|
users,
|
||||||
course_session_id,
|
|
||||||
):
|
):
|
||||||
idx_offset = 0
|
idx_offset = 0
|
||||||
|
|
||||||
for row_idx, user in enumerate(users, start=2):
|
for row_idx, user in enumerate(users, start=2):
|
||||||
|
user_role = _role_as_string(user.get("role"))
|
||||||
def get_user_cs_by_id(user_cs, cs_id):
|
|
||||||
return next((cs for cs in user_cs if int(cs.get("id")) == cs_id), None)
|
|
||||||
|
|
||||||
user_cs = get_user_cs_by_id(user["course_sessions"], course_session_id)
|
|
||||||
|
|
||||||
if not user_cs:
|
|
||||||
logger.warning(
|
|
||||||
"User not found in course session",
|
|
||||||
user_id=user["user_id"],
|
|
||||||
course_session_id=course_session_id,
|
|
||||||
)
|
|
||||||
idx_offset += 1
|
|
||||||
continue
|
|
||||||
|
|
||||||
user_role = _role_as_string(user_cs.get("user_role"))
|
|
||||||
idx = row_idx - idx_offset
|
idx = row_idx - idx_offset
|
||||||
|
|
||||||
sheet.cell(row=idx, column=1, value=user["first_name"])
|
sheet.cell(row=idx, column=1, value=user["first_name"])
|
||||||
|
|
|
||||||
|
|
@ -95,37 +95,40 @@ def create_course_session_dict(course_session_object, my_role, user_role):
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def create_csu_dict(csu: CourseSessionUser, include_private_data=False):
|
||||||
|
user_data = create_user_dict(csu.user, include_private_data)
|
||||||
|
user_data["csu_id"] = csu.id
|
||||||
|
user_data["chosen_profile"] = (
|
||||||
|
csu.chosen_profile.code if csu.chosen_profile else "all"
|
||||||
|
)
|
||||||
|
user_data["paid_datetime"] = (
|
||||||
|
csu.paid_datetime.isoformat() if csu.paid_datetime else None
|
||||||
|
)
|
||||||
|
user_data["role"] = csu.role
|
||||||
|
return user_data
|
||||||
|
|
||||||
|
|
||||||
|
def create_user_dict(user_object: User, include_private_data=False):
|
||||||
|
user_data = {
|
||||||
|
"user_id": user_object.id,
|
||||||
|
"first_name": user_object.first_name,
|
||||||
|
"last_name": user_object.last_name,
|
||||||
|
"email": user_object.email,
|
||||||
|
"avatar_url_small": user_object.avatar_url_small,
|
||||||
|
"avatar_url": user_object.avatar_url,
|
||||||
|
"course_sessions": [],
|
||||||
|
}
|
||||||
|
if include_private_data:
|
||||||
|
user_data["phone_number"] = user_object.phone_number
|
||||||
|
user_data["Lehrvertragsnummer"] = user_object.additional_json_data.get(
|
||||||
|
"Lehrvertragsnummer", ""
|
||||||
|
)
|
||||||
|
return user_data
|
||||||
|
|
||||||
|
|
||||||
def create_person_list_with_roles(
|
def create_person_list_with_roles(
|
||||||
user, course_session_ids=None, include_private_data=False
|
user, course_session_ids=None, include_private_data=False
|
||||||
):
|
):
|
||||||
def create_csu_dict(csu: CourseSessionUser):
|
|
||||||
user_data = create_user_dict(csu.user)
|
|
||||||
user_data["chosen_profile"] = (
|
|
||||||
csu.chosen_profile.code if csu.chosen_profile else "all"
|
|
||||||
)
|
|
||||||
user_data["paid_datetime"] = (
|
|
||||||
csu.paid_datetime.isoformat() if csu.paid_datetime else None
|
|
||||||
)
|
|
||||||
return user_data
|
|
||||||
|
|
||||||
def create_user_dict(user_object: User):
|
|
||||||
user_data = {
|
|
||||||
"user_id": user_object.id,
|
|
||||||
"first_name": user_object.first_name,
|
|
||||||
"last_name": user_object.last_name,
|
|
||||||
"email": user_object.email,
|
|
||||||
"avatar_url_small": user_object.avatar_url_small,
|
|
||||||
"avatar_url": user_object.avatar_url,
|
|
||||||
"course_sessions": [],
|
|
||||||
}
|
|
||||||
if include_private_data:
|
|
||||||
user_data["phone_number"] = user_object.phone_number
|
|
||||||
user_data["Lehrvertragsnummer"] = user_object.additional_json_data.get(
|
|
||||||
"Lehrvertragsnummer", ""
|
|
||||||
)
|
|
||||||
|
|
||||||
return user_data
|
|
||||||
|
|
||||||
course_sessions = get_course_sessions_with_roles_for_user(user)
|
course_sessions = get_course_sessions_with_roles_for_user(user)
|
||||||
if course_session_ids:
|
if course_session_ids:
|
||||||
course_sessions = [
|
course_sessions = [
|
||||||
|
|
@ -140,7 +143,9 @@ def create_person_list_with_roles(
|
||||||
).select_related("user")
|
).select_related("user")
|
||||||
my_role = user_role(cs.roles)
|
my_role = user_role(cs.roles)
|
||||||
for csu in course_session_users:
|
for csu in course_session_users:
|
||||||
person_data = result_persons.get(csu.user.id, create_csu_dict(csu))
|
person_data = result_persons.get(
|
||||||
|
csu.user.id, create_csu_dict(csu, include_private_data)
|
||||||
|
)
|
||||||
person_data["course_sessions"].append(
|
person_data["course_sessions"].append(
|
||||||
create_course_session_dict(cs, my_role, csu.role)
|
create_course_session_dict(cs, my_role, csu.role)
|
||||||
)
|
)
|
||||||
|
|
@ -154,7 +159,9 @@ def create_person_list_with_roles(
|
||||||
participant_user = relation.participant.user
|
participant_user = relation.participant.user
|
||||||
|
|
||||||
if participant_user.id not in result_persons:
|
if participant_user.id not in result_persons:
|
||||||
person_data = create_csu_dict(relation.participant)
|
person_data = create_csu_dict(
|
||||||
|
relation.participant, include_private_data
|
||||||
|
)
|
||||||
person_data["course_sessions"] = [course_session_entry]
|
person_data["course_sessions"] = [course_session_entry]
|
||||||
result_persons[participant_user.id] = person_data
|
result_persons[participant_user.id] = person_data
|
||||||
else:
|
else:
|
||||||
|
|
@ -193,7 +200,7 @@ def create_person_list_with_roles(
|
||||||
)
|
)
|
||||||
|
|
||||||
if mentor_relation.agent.id not in result_persons:
|
if mentor_relation.agent.id not in result_persons:
|
||||||
person_data = create_user_dict(mentor_relation.agent)
|
person_data = create_user_dict(mentor_relation.agent, include_private_data)
|
||||||
person_data["course_sessions"] = [course_session_entry]
|
person_data["course_sessions"] = [course_session_entry]
|
||||||
result_persons[mentor_relation.agent.id] = person_data
|
result_persons[mentor_relation.agent.id] = person_data
|
||||||
else:
|
else:
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,11 @@ from vbv_lernwelt.competence.services import (
|
||||||
query_competence_course_session_edoniq_tests,
|
query_competence_course_session_edoniq_tests,
|
||||||
)
|
)
|
||||||
from vbv_lernwelt.core.models import User
|
from vbv_lernwelt.core.models import User
|
||||||
from vbv_lernwelt.course.models import CourseConfiguration, CourseSessionUser
|
from vbv_lernwelt.course.models import (
|
||||||
|
CourseConfiguration,
|
||||||
|
CourseSession,
|
||||||
|
CourseSessionUser,
|
||||||
|
)
|
||||||
from vbv_lernwelt.course.views import logger
|
from vbv_lernwelt.course.views import logger
|
||||||
from vbv_lernwelt.course_session.services.export_attendance import (
|
from vbv_lernwelt.course_session.services.export_attendance import (
|
||||||
ATTENDANCE_EXPORT_FILENAME,
|
ATTENDANCE_EXPORT_FILENAME,
|
||||||
|
|
@ -463,22 +467,46 @@ def export_feedback_as_xsl(request):
|
||||||
|
|
||||||
@api_view(["POST"])
|
@api_view(["POST"])
|
||||||
def export_persons_as_xsl(request):
|
def export_persons_as_xsl(request):
|
||||||
requested_course_session_ids = request.data.get("courseSessionIds", [])
|
requested_course_session_user_ids = request.data.get("courseSessionUserIds", [])
|
||||||
course_sessions_with_roles = _get_permitted_courses_sessions_for_user(
|
permitted_course_session_users = _get_permitted_csus_for_user(
|
||||||
request.user, requested_course_session_ids
|
request.user, requested_course_session_user_ids
|
||||||
) # noqa
|
|
||||||
|
|
||||||
data = export_persons(
|
|
||||||
request.user,
|
|
||||||
[cswr.id for cswr in course_sessions_with_roles],
|
|
||||||
)
|
)
|
||||||
return _make_excel_response(data, PERSONS_EXPORT_FILENAME)
|
|
||||||
|
data = export_persons(permitted_course_session_users)
|
||||||
|
if data:
|
||||||
|
return _make_excel_response(data, PERSONS_EXPORT_FILENAME)
|
||||||
|
return Response(status=status.HTTP_400_BAD_REQUEST)
|
||||||
|
|
||||||
|
|
||||||
|
def _get_permitted_csus_for_user(
|
||||||
|
user: User, requested_coursesessionuser_ids: List[str]
|
||||||
|
) -> List[CourseSessionUser]:
|
||||||
|
# Premit course session users where user is agent (Berufsbildner, Lernbegleiter)
|
||||||
|
premitted_from_agent_participant_rel = CourseSessionUser.objects.filter(
|
||||||
|
id__in=requested_coursesessionuser_ids,
|
||||||
|
agentparticipantrelation__agent=user,
|
||||||
|
)
|
||||||
|
|
||||||
|
# Premit course session users where user has a certain role in the user's course session
|
||||||
|
ALLOWED_ROLES = ["EXPERT", "SUPERVISOR"]
|
||||||
|
requested_course_session_ids = CourseSessionUser.objects.filter(
|
||||||
|
id__in=requested_coursesessionuser_ids
|
||||||
|
).values_list("course_session__id", flat=True)
|
||||||
|
permitted_course_sessions = _get_course_sessions_with_roles_for_user(
|
||||||
|
user, ALLOWED_ROLES, requested_course_session_ids
|
||||||
|
)
|
||||||
|
permitted_from_role = CourseSessionUser.objects.filter(
|
||||||
|
id__in=requested_coursesessionuser_ids,
|
||||||
|
course_session__in=[x.id for x in permitted_course_sessions],
|
||||||
|
)
|
||||||
|
|
||||||
|
return set(premitted_from_agent_participant_rel) | set(permitted_from_role)
|
||||||
|
|
||||||
|
|
||||||
def _get_permitted_courses_sessions_for_user(
|
def _get_permitted_courses_sessions_for_user(
|
||||||
user: User, requested_coursesession_ids: List[str]
|
user: User, requested_coursesession_ids: List[str]
|
||||||
) -> List[CourseSessionWithRoles]:
|
) -> List[CourseSessionWithRoles]:
|
||||||
ALLOWED_ROLES = ["EXPERT", "SUPERVISOR", "BERUFSBILDNER", "LEARNING_MENTOR"]
|
ALLOWED_ROLES = ["EXPERT", "SUPERVISOR"]
|
||||||
|
|
||||||
user_course_sessions_with_roles = _get_course_sessions_with_roles_for_user(
|
user_course_sessions_with_roles = _get_course_sessions_with_roles_for_user(
|
||||||
user, ALLOWED_ROLES, requested_coursesession_ids
|
user, ALLOWED_ROLES, requested_coursesession_ids
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue