From d6a2008efa3c57cc09cf699a6caa871bb4ea8c77 Mon Sep 17 00:00:00 2001 From: delphvr <delphine.vanrossum@student.uclouvain.be> Date: Tue, 11 Mar 2025 09:45:33 +0100 Subject: [PATCH 1/2] csv wide --- backend/app/crud/studies.py | 58 +++++++++++++++++++++++++++++++++++ backend/app/routes/studies.py | 12 ++++++++ 2 files changed, 70 insertions(+) diff --git a/backend/app/crud/studies.py b/backend/app/crud/studies.py index 561fa1de..3377ac32 100644 --- a/backend/app/crud/studies.py +++ b/backend/app/crud/studies.py @@ -164,3 +164,61 @@ def download_study(db: Session, study_id: int): media_type="text/csv", headers={"Content-Disposition": f"attachment; filename={study_id}-surveys.csv"}, ) + + +def download_study_wide(db: Session, study_id: int): + output = StringIO() + writer = csv.writer(output) + + data = {} + question_ids = set() + + db_entries = ( + db.query(models.TestEntry).filter(models.TestEntry.study_id == study_id).all() + ) + + for entry in db_entries: + if entry.entry_task is None: + continue + + user_id = entry.user_id + code = entry.code + item_id = entry.entry_task.test_question_id + key = (user_id, code) + + if key not in data: + data[key] = {"study_id": study_id, "user_id": user_id, "code": code} + + if entry.entry_task.entry_task_qcm: + selected_id = entry.entry_task.entry_task_qcm.selected_id + correct_id = entry.entry_task.test_question.question_qcm.correct + correct_answer = int(selected_id == correct_id) + data[key][item_id] = correct_answer + question_ids.add(item_id) + + if entry.entry_task.entry_task_gapfill: + answer = entry.entry_task.entry_task_gapfill.text + correct = extract_text_between_angle_bracket( + entry.entry_task.test_question.question + ) + correct_answer = int(answer == correct) + data[key][item_id] = correct_answer + question_ids.add(item_id) + + # Sort question IDs for consistent column order + question_ids = sorted(question_ids) + header = ["study_id", "user_id", "code"] + question_ids + writer.writerow(header) + for (user_id, code), values in data.items(): + row = [values.get(col, "") for col in header] + writer.writerow(row) + + output.seek(0) + + return StreamingResponse( + output, + media_type="text/csv", + headers={ + "Content-Disposition": f"attachment; filename={study_id}-surveys-wide.csv" + }, + ) diff --git a/backend/app/routes/studies.py b/backend/app/routes/studies.py index 0cba51e4..04411b25 100644 --- a/backend/app/routes/studies.py +++ b/backend/app/routes/studies.py @@ -71,3 +71,15 @@ def download_study( if study is None: raise HTTPException(status_code=404, detail="Study not found") return crud.download_study(db, study_id) + + +@require_admin("You do not have permission to download this study.") +@studiesRouter.get("/{study_id}/download/surveys-wide") +def download_study( + study_id: int, + db: Session = Depends(get_db), +): + study = crud.get_study(db, study_id) + if study is None: + raise HTTPException(status_code=404, detail="Study not found") + return crud.download_study_wide(db, study_id) -- GitLab From bbd289ed4c20c6416b8a22d30a8bcd6964e46376 Mon Sep 17 00:00:00 2001 From: delphvr <delphine.vanrossum@student.uclouvain.be> Date: Tue, 11 Mar 2025 09:57:49 +0100 Subject: [PATCH 2/2] csv wide added meta data --- backend/app/crud/studies.py | 24 +++++++++++++++++-- .../src/routes/admin/studies/+page.svelte | 10 ++++++-- 2 files changed, 30 insertions(+), 4 deletions(-) diff --git a/backend/app/crud/studies.py b/backend/app/crud/studies.py index 3377ac32..5848676a 100644 --- a/backend/app/crud/studies.py +++ b/backend/app/crud/studies.py @@ -187,7 +187,19 @@ def download_study_wide(db: Session, study_id: int): key = (user_id, code) if key not in data: - data[key] = {"study_id": study_id, "user_id": user_id, "code": code} + if user_id is not None: + user = crud.get_user(db, user_id) + data[key] = { + "study_id": study_id, + "user_id": user_id, + "code": code, + "home_language": user.home_language, + "target_language": user.target_language, + "gender": user.gender, + "birthdate": user.birthdate, + } + else: + data[key] = {"study_id": study_id, "user_id": user_id, "code": code} if entry.entry_task.entry_task_qcm: selected_id = entry.entry_task.entry_task_qcm.selected_id @@ -207,7 +219,15 @@ def download_study_wide(db: Session, study_id: int): # Sort question IDs for consistent column order question_ids = sorted(question_ids) - header = ["study_id", "user_id", "code"] + question_ids + header = [ + "study_id", + "user_id", + "code", + "home_language", + "target_language", + "gender", + "birthdate", + ] + question_ids writer.writerow(header) for (user_id, code), values in data.items(): row = [values.get(col, "") for col in header] diff --git a/frontend/src/routes/admin/studies/+page.svelte b/frontend/src/routes/admin/studies/+page.svelte index 5ca59fd3..254ee148 100644 --- a/frontend/src/routes/admin/studies/+page.svelte +++ b/frontend/src/routes/admin/studies/+page.svelte @@ -38,10 +38,16 @@ title="Download" href={`${config.API_URL}/v1/studies/${study.id}/download/surveys`} > - <Icon src={ArrowDownTray} size="16" /> + <Icon src={ArrowDownTray} size="16" /> CSV long + </a> + <a + class="btn btn-primary btn-sm" + title="Download" + href={`${config.API_URL}/v1/studies/${study.id}/download/surveys-wide`} + > + <Icon src={ArrowDownTray} size="16" /> CSV wide </a></td > - <td></td> </tr> {/each} </tbody> -- GitLab