diff --git a/.gitignore b/.gitignore index af36aab869b1b17b749f3b607ce1bea22c38243c..3f1d2a8e68a819c621bb2be951a4159ace5fdb30 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,5 @@ *.csr *.key *.pem + +.ipynb_checkpoints/ diff --git a/backend/app/crud.py b/backend/app/crud.py index 5afe06ed887f7ba6df7409e52a7e178493d475bf..cbada3362036bfca706d0fb4d06bb1999dfc46ed 100644 --- a/backend/app/crud.py +++ b/backend/app/crud.py @@ -320,12 +320,8 @@ def delete_survey_question(db: Session, survey_question_id: int): db.commit() -def create_survey_response( - db: Session, survey_id: int, survey_response: schemas.SurveyResponseCreate -): - db_survey_response = models.SurveyResponse( - survey_id=survey_id, **survey_response.dict() - ) +def create_survey_response(db: Session, survey_response: schemas.SurveyResponseCreate): + db_survey_response = models.SurveyResponse(**survey_response.dict()) db.add(db_survey_response) db.commit() db.refresh(db_survey_response) diff --git a/backend/app/main.py b/backend/app/main.py index ce99181aee968541a272f2cb9dbc236778760994..db7091947ea174c7d430eec16b8d541f72a18d00 100644 --- a/backend/app/main.py +++ b/backend/app/main.py @@ -965,17 +965,13 @@ def delete_survey_question( @surveyRouter.post("/responses", status_code=status.HTTP_201_CREATED) def create_survey_response( - survey_id: int, response: schemas.SurveyResponseCreate, db: Session = Depends(get_db), ): - if not crud.get_survey(db, survey_id): - raise HTTPException(status_code=404, detail="Survey not found") - - return crud.create_survey_response(db, survey_id, response).id + return crud.create_survey_response(db, response).id -@surveyRouter.get("/responses", response_model=list[schemas.SurveyResponse]) +@surveyRouter.get("/responses/{survey_id}", response_model=list[schemas.SurveyResponse]) def get_survey_responses( survey_id: int, db: Session = Depends(get_db), diff --git a/backend/app/models.py b/backend/app/models.py index c84fbc1ae46a1dd3ad6864920fc8f77bb5901971..46c127185eeaa41e43468ff0008a354dfd5cc4c7 100644 --- a/backend/app/models.py +++ b/backend/app/models.py @@ -187,9 +187,10 @@ class SurveyResponse(Base): id = Column(Integer, primary_key=True, index=True) uuid = Column(String) + sid = Column(String) created_at = Column(DateTime, default=datetime.datetime.now) survey_id = Column(Integer, ForeignKey("survey_surveys.id")) group_id = Column(Integer, ForeignKey("survey_groups.id")) question_id = Column(Integer, ForeignKey("survey_questions.id")) - option = Column(Integer) + selected_id = Column(Integer) response_time = Column(Float) diff --git a/backend/app/schemas.py b/backend/app/schemas.py index 615702156c1812e994ce549ce7235379512d8aa9..2b4ec307efb9d773048653add62c74d67a4715cd 100644 --- a/backend/app/schemas.py +++ b/backend/app/schemas.py @@ -204,19 +204,21 @@ class SurveySurveyAddGroup(BaseModel): class SurveyResponseCreate(BaseModel): uuid: str + sid: str survey_id: int group_id: int question_id: int - option: int + selected_id: int response_time: float class SurveyResponse(BaseModel): id: int uuid: str + sid: str created_at: datetime.datetime survey_id: int group_id: int question_id: int - option: int + selected_id: int response_time: float diff --git a/frontend/package.json b/frontend/package.json index 06f92529c194f86f11720db8694479a86c0565e5..352ca2baa2fc12a76287e6564349d05d9ae5f9d9 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -47,7 +47,6 @@ "type": "module", "dependencies": { "emoji-picker-element": "^1.21.3", - "jquery": "^3.7.1", "svelte-gravatar": "^1.0.3", "svelte-i18n": "^4.0.0", "svelte-material-icons": "^3.0.5", diff --git a/frontend/src/lib/api/survey.ts b/frontend/src/lib/api/survey.ts index e2fd5dca12f681a902d742ba35cb696c05fa32c8..8ac70e3b4eae6f900f2af303a3f39232f3a75537 100644 --- a/frontend/src/lib/api/survey.ts +++ b/frontend/src/lib/api/survey.ts @@ -14,15 +14,20 @@ export async function getSurveyAPI(survey_id: number) { export async function sendSurveyResponseAPI( uuid: string, + sid: string, survey_id: number, + group_id: number, question_id: number, option_id: number, response_time: number ) { - const response = await axiosInstance.post(`/surveys/${survey_id}/responses`, { + const response = await axiosInstance.post(`/surveys/responses`, { uuid, + sid, + survey_id, question_id, - option_id, + group_id, + selected_id: option_id, response_time }); diff --git a/frontend/src/lib/types/surveyOption.ts b/frontend/src/lib/types/surveyOption.ts deleted file mode 100644 index 2ab3663744f70d623ac398fed4967ddfeaeae544..0000000000000000000000000000000000000000 --- a/frontend/src/lib/types/surveyOption.ts +++ /dev/null @@ -1,60 +0,0 @@ -import { toastAlert } from '$lib/utils/toasts'; - -export default class SurveyOption { - private _id: number; - private _question_id: number; - private _correct: boolean; - private _type: string; - private _value: string; - - constructor(id: number, question_id: number, correct: boolean, type: string, value: string) { - this._id = id; - this._question_id = question_id; - this._correct = correct; - this._type = type; - this._value = value; - } - - get id(): number { - return this._id; - } - - get question_id(): number { - return this._question_id; - } - - get correct(): boolean { - return this._correct; - } - - get type(): string { - return this._type; - } - - get value(): string { - return this._value; - } - - static parse(data: any): SurveyOption | null { - if (data === null) { - toastAlert('Failed to parse survey option data'); - return null; - } - - return new SurveyOption(data.id, data.question_id, data.correct, data.type, data.value); - } - - static parseAll(data: any): SurveyOption[] { - if (data === null) { - toastAlert('Failed to parse survey option data'); - return []; - } - - const options: SurveyOption[] = []; - for (const option of data) { - options.push(SurveyOption.parse(option)!); - } - - return options; - } -} diff --git a/frontend/src/lib/types/surveyQuestion.ts b/frontend/src/lib/types/surveyQuestion.ts index 1d7e47bcefba59856ed88a7f201769662d90d17e..eb85c8ca384b8bda414bb79f0f4c2c4683892298 100644 --- a/frontend/src/lib/types/surveyQuestion.ts +++ b/frontend/src/lib/types/surveyQuestion.ts @@ -1,27 +1,15 @@ import { toastAlert } from '$lib/utils/toasts'; -import SurveyOption from './surveyOption'; export default class SurveyQuestion { private _id: number; private _group_id: number; - private _title: string; - private _question_type: string; - private _question_value: string; - private _options: SurveyOption[]; + private _question: string; + private _options: string[]; - constructor( - id: number, - group_id: number, - title: string, - question_type: string, - question_value: string, - options: SurveyOption[] - ) { + constructor(id: number, group_id: number, question: string, options: string[]) { this._id = id; this._group_id = group_id; - this._title = title; - this._question_type = question_type; - this._question_value = question_value; + this._question = question; this._options = options; } @@ -33,19 +21,11 @@ export default class SurveyQuestion { return this._group_id; } - get title(): string { - return this._title; + get question(): string { + return this._question; } - get question_type(): string { - return this._question_type; - } - - get question_value(): string { - return this._question_value; - } - - get options(): SurveyOption[] { + get options(): string[] { return this._options; } @@ -55,16 +35,17 @@ export default class SurveyQuestion { return null; } - const options = SurveyOption.parseAll(data.options); + let options = []; + if (data.option1) options.push(data.option1); + if (data.option2) options.push(data.option2); + if (data.option3) options.push(data.option3); + if (data.option4) options.push(data.option4); + if (data.option5) options.push(data.option5); + if (data.option6) options.push(data.option6); + if (data.option7) options.push(data.option7); + if (data.option8) options.push(data.option8); - return new SurveyQuestion( - data.id, - data.group_id, - data.title, - data.question_type, - data.question_value, - options - ); + return new SurveyQuestion(data.id, data.group_id, data.question, options); } static parseAll(data: any): SurveyQuestion[] { diff --git a/frontend/src/routes/surveys/[id]/+layout.server.ts b/frontend/src/routes/surveys/[id]/+layout.server.ts new file mode 100644 index 0000000000000000000000000000000000000000..073588193a9d322187faea35cc861826b59656b0 --- /dev/null +++ b/frontend/src/routes/surveys/[id]/+layout.server.ts @@ -0,0 +1,26 @@ +import { type ServerLoad, redirect } from '@sveltejs/kit'; + +const publicly_allowed = ['/login', '/register', '/tests/vocabulary', '/surveys']; + +const isPublic = (path: string) => { + for (const allowed of publicly_allowed) { + if (path.startsWith(allowed)) { + return true; + } + } + return false; +}; + +export const load: ServerLoad = async ({ locals, url }) => { + if (locals.user == null || locals.user == undefined) { + if (!isPublic(url.pathname)) { + redirect(307, `/login`); + } + } + + return { + user: locals.user, + session: locals.session, + locale: locals.locale + }; +}; diff --git a/frontend/src/routes/surveys/[id]/+layout.ts b/frontend/src/routes/surveys/[id]/+layout.ts new file mode 100644 index 0000000000000000000000000000000000000000..e87df190ee4256ad1c12a6925e66302bf57eeee3 --- /dev/null +++ b/frontend/src/routes/surveys/[id]/+layout.ts @@ -0,0 +1,16 @@ +export const ssr = true; + +import type { Load } from '@sveltejs/kit'; +import { loadTranslations } from '$lib/services/i18n'; + +export const load: Load = async ({ url, data }) => { + const { user, session, locale } = data; + const { pathname } = url; + + await loadTranslations(locale, pathname); + + return { + user: user, + token: session + }; +}; diff --git a/frontend/src/routes/surveys/[id]/+page.svelte b/frontend/src/routes/surveys/[id]/+page.svelte index b911f1346a4cbcb06d78684b819f411a64978504..151014c4a446224b6603efc75307c066160490bb 100644 --- a/frontend/src/routes/surveys/[id]/+page.svelte +++ b/frontend/src/routes/surveys/[id]/+page.svelte @@ -2,7 +2,6 @@ import { sendSurveyResponseAPI } from '$lib/api/survey'; import Survey from '$lib/types/survey.js'; - import type SurveyOption from '$lib/types/surveyOption'; import { t } from '$lib/services/i18n'; import { toastWarning } from '$lib/utils/toasts.js'; import { get } from 'svelte/store'; @@ -11,12 +10,14 @@ export let data; const survey: Survey = data.survey!; - const user = data.user ? User.parse(data.user) : null; + const user = data.user ? User.parse(JSON.parse(data.user)) : null; - let uuid = user?.email || ''; + let sid = + Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15); let startTime = new Date().getTime(); $: step = user ? 1 : 0; + $: uuid = user?.email || ''; $: currentGroupId = 0; $: currentGroup = survey.groups[currentGroupId]; @@ -24,13 +25,15 @@ $: currentQuestionId = 0; $: currentQuestion = questionsRandomized[currentQuestionId]; - async function selectOption(option: SurveyOption) { + async function selectOption(option: string) { if ( !(await sendSurveyResponseAPI( uuid, + sid, survey.id, + currentGroupId, currentQuestionId, - option.id, + currentQuestion.options.findIndex((o: string) => o === option), (new Date().getTime() - startTime) / 1000 )) ) { @@ -94,20 +97,16 @@ <button class="button" on:click={() => step++}>{$t('button.next')}</button> </div> {:else if step == 2} - <h1>Survey: {survey.title}</h1> - <p>Group: {currentGroup?.title}</p> - + {@const type = currentQuestion.question.split(':')[0]} + {@const value = currentQuestion.question.split(':').slice(1).join(':')} <div class="mx-auto mt-16 text-center"> - <p class="text-xl mb-4"> - {currentQuestion?.title} - </p> - {#if currentQuestion?.question_type == 'text'} - <pre>{currentQuestion?.question_value}</pre> - {:else if currentQuestion?.question_type == 'image'} - <img src={currentQuestion?.question_value} alt="Question" /> - {:else if currentQuestion?.question_type == 'audio'} + {#if type == 'text'} + <pre>{value}</pre> + {:else if type == 'image'} + <img src={value} alt="Question" /> + {:else if type == 'audio'} <audio controls autoplay class="rounded-lg mx-auto"> - <source src={currentQuestion?.question_value} type="audio/mpeg" /> + <source src={value} type="audio/mpeg" /> Your browser does not support the audio element. </audio> {/if} @@ -115,7 +114,9 @@ <div class="mx-auto mt-16"> <div class="flex justify-around min-w-[600px] space-x-10"> - {#each currentQuestion?.options as option (option.id)} + {#each currentQuestion?.options as option (option)} + {@const type = option.split(':')[0]} + {@const value = option.split(':').slice(1).join(':')} <div class="h-48 w-48 overflow-hidden rounded-lg border border-black" on:click={() => selectOption(option)} @@ -123,21 +124,21 @@ on:keydown={() => selectOption(option)} tabindex="0" > - {#if option.type === 'text'} + {#if type === 'text'} <span class="flex items-center justify-center h-full w-full text-2xl transition-transform duration-200 ease-in-out transform hover:scale-105" > - {option.value} + {value} </span> - {:else if option.type === 'image'} + {:else if type === 'image'} <img - src={option.value} - alt="Option {option.id}" + src={value} + alt="Option {option}" class="object-cover h-full w-full transition-transform duration-200 ease-in-out transform hover:scale-105" /> - {:else if option.type == 'audio'} + {:else if type == 'audio'} <audio controls class="w-full" on:click|preventDefault|stopPropagation> - <source src={option.value} type="audio/mpeg" /> + <source src={value} type="audio/mpeg" /> Your browser does not support the audio element. </audio> {/if} diff --git a/frontend/src/routes/surveys/[id]/+page.ts b/frontend/src/routes/surveys/[id]/+page.ts index 03742fbe15fa40250a8d5c840b6d8a0fcef5f96a..7ada027448295fe88193014b3e7387c544c24c88 100644 --- a/frontend/src/routes/surveys/[id]/+page.ts +++ b/frontend/src/routes/surveys/[id]/+page.ts @@ -1,10 +1,13 @@ import { getSurveyAPI } from '$lib/api/survey'; import Survey from '$lib/types/survey'; +import type { Load } from '@sveltejs/kit'; export const ssr = false; -export const load = async ({ params }: { params: Record<string, string> }) => { +export const load: Load = async ({ params, parent }) => { + const data = await parent(); const survey_id = parseInt(params.id); + const { user, token } = data; if (isNaN(survey_id)) { return { @@ -27,7 +30,9 @@ export const load = async ({ params }: { params: Record<string, string> }) => { } return { - survey_id: survey_id, - survey: survey + survey_id, + survey, + user, + token }; }; diff --git a/scripts/surveys/.ipynb_checkpoints/groups-checkpoint.csv b/scripts/surveys/.ipynb_checkpoints/groups-checkpoint.csv deleted file mode 100644 index 6d43a0cfef660a5bf7d98893f3d2e4d9085bf9e0..0000000000000000000000000000000000000000 --- a/scripts/surveys/.ipynb_checkpoints/groups-checkpoint.csv +++ /dev/null @@ -1,3 +0,0 @@ -group_id,question_id,question,option1,option2 -1,1,,, -1,2,How old are you?,18-24,25-34 diff --git a/scripts/surveys/.ipynb_checkpoints/survey_maker-checkpoint.ipynb b/scripts/surveys/.ipynb_checkpoints/survey_maker-checkpoint.ipynb deleted file mode 100644 index de0799cd1ad09017db7264f9f480204bde0640b4..0000000000000000000000000000000000000000 --- a/scripts/surveys/.ipynb_checkpoints/survey_maker-checkpoint.ipynb +++ /dev/null @@ -1,366 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": 142, - "id": "5f682366-5ab6-4418-84b9-b971266af67f", - "metadata": {}, - "outputs": [], - "source": [ - "import pandas as pd\n", - "import requests\n", - "import numpy as np\n", - "import os" - ] - }, - { - "cell_type": "code", - "execution_count": 145, - "id": "e8af376d-ce09-4537-a724-2028777adef3", - "metadata": {}, - "outputs": [], - "source": [ - "API_URL = 'http://127.0.0.1:8000'\n", - "LOCAL_ITEMS_FOLDER = '../../frontend/static/surveys/items'\n", - "REMOTE_ITEMS_FOLDER = '/surveys/items'" - ] - }, - { - "cell_type": "code", - "execution_count": 151, - "id": "30116c8a-a0a6-4dc7-9b69-8afb50a6252e", - "metadata": {}, - "outputs": [], - "source": [ - "df_items = pd.read_csv('items.csv',dtype = str)" - ] - }, - { - "cell_type": "code", - "execution_count": 152, - "id": "265ccfaa-e86d-460c-be36-1bdfbd2c433f", - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "<div>\n", - "<style scoped>\n", - " .dataframe tbody tr th:only-of-type {\n", - " vertical-align: middle;\n", - " }\n", - "\n", - " .dataframe tbody tr th {\n", - " vertical-align: top;\n", - " }\n", - "\n", - " .dataframe thead th {\n", - " text-align: right;\n", - " }\n", - "</style>\n", - "<table border=\"1\" class=\"dataframe\">\n", - " <thead>\n", - " <tr style=\"text-align: right;\">\n", - " <th></th>\n", - " <th>id</th>\n", - " <th>question</th>\n", - " <th>correct</th>\n", - " <th>option1</th>\n", - " <th>option2</th>\n", - " <th>option3</th>\n", - " <th>option4</th>\n", - " <th>option5</th>\n", - " <th>option6</th>\n", - " <th>option7</th>\n", - " <th>option8</th>\n", - " </tr>\n", - " </thead>\n", - " <tbody>\n", - " <tr>\n", - " <th>0</th>\n", - " <td>1</td>\n", - " <td>NaN</td>\n", - " <td>1</td>\n", - " <td>NaN</td>\n", - " <td>NaN</td>\n", - " <td>NaN</td>\n", - " <td>NaN</td>\n", - " <td>NaN</td>\n", - " <td>NaN</td>\n", - " <td>NaN</td>\n", - " <td>NaN</td>\n", - " </tr>\n", - " <tr>\n", - " <th>1</th>\n", - " <td>2</td>\n", - " <td>How old are you?</td>\n", - " <td>-1</td>\n", - " <td>18-24</td>\n", - " <td>25-34</td>\n", - " <td>NaN</td>\n", - " <td>NaN</td>\n", - " <td>NaN</td>\n", - " <td>NaN</td>\n", - " <td>NaN</td>\n", - " <td>NaN</td>\n", - " </tr>\n", - " </tbody>\n", - "</table>\n", - "</div>" - ], - "text/plain": [ - " id question correct option1 option2 option3 option4 option5 \\\n", - "0 1 NaN 1 NaN NaN NaN NaN NaN \n", - "1 2 How old are you? -1 18-24 25-34 NaN NaN NaN \n", - "\n", - " option6 option7 option8 \n", - "0 NaN NaN NaN \n", - "1 NaN NaN NaN " - ] - }, - "execution_count": 152, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "df_items.head(2)" - ] - }, - { - "cell_type": "code", - "execution_count": 219, - "id": "93beb77a-7e30-437d-9f7e-e079cd2db029", - "metadata": {}, - "outputs": [], - "source": [ - "items = []\n", - "for i, row in df_items.iterrows():\n", - " row = row.dropna()\n", - " id_ = int(row['id'])\n", - "\n", - " o = {'id': id_, 'question': None, 'correct': None}\n", - " items.append(o)\n", - " \n", - " if 'question' in row:\n", - " o['question'] = f'text:{row[\"question\"]}'\n", - " elif os.path.isfile(f'{ITEMS_FOLDER}/{id_}/q.mp3'):\n", - " o['question'] = f'audio:{REMOTE_ITEMS_FOLDER}/{id_}/q.mp3'\n", - " elif os.path.isfile(f'{ITEMS_FOLDER}/{id_}/q.jpeg'):\n", - " o['question'] = f'audio:{REMOTE_ITEMS_FOLDER}/{id_}/q.jpeg'\n", - " else:\n", - " print(f'Failed to find a question for item {id_}')\n", - "\n", - " if 'correct' in row:\n", - " o['correct'] = int(row['correct'])\n", - " else:\n", - " print(f'Failed to find corect for item {id_}')\n", - "\n", - " for j in range(1,9):\n", - " op = f'option{j}'\n", - " if op in row:\n", - " o[op] = 'text:' + row[op]\n", - " elif os.path.isfile(f'{ITEMS_FOLDER}/{id_}/{j}.mp3'):\n", - " o[op] = f'audio:{REMOTE_ITEMS_FOLDER}/{id_}/{j}.mp3'\n", - " elif os.path.isfile(f'{ITEMS_FOLDER}/{id_}/{j}.jpeg'):\n", - " o[op] = f'audio:{REMOTE_ITEMS_FOLDER}/{id_}/{j}.jpeg'" - ] - }, - { - "cell_type": "code", - "execution_count": 220, - "id": "a2bc630b-af5a-4f65-b6f6-4005d2f359f5", - "metadata": {}, - "outputs": [], - "source": [ - "groups = []\n", - "with open('groups.csv') as file:\n", - " file.readline()\n", - " for line in file.read().split('\\n'):\n", - " if not line:\n", - " continue\n", - " id_, title, *its = line.split(',')\n", - " id_ = int(id_)\n", - " its = [int(x) for x in its]\n", - " groups.append({'id': id_, 'title': title, 'items_id': its})" - ] - }, - { - "cell_type": "code", - "execution_count": 221, - "id": "0d8fc0ea-6ec9-4c58-8395-2a415d556fea", - "metadata": {}, - "outputs": [], - "source": [ - "surveys = []\n", - "with open('surveys.csv') as file:\n", - " file.readline()\n", - " for line in file.read().split('\\n'):\n", - " if not line:\n", - " continue\n", - " id_, title, *gps = line.split(',')\n", - " id_ = int(id_)\n", - " gps = [int(x) for x in gps]\n", - " surveys.append({'id': id_, 'title': title, 'groups_id': gps})" - ] - }, - { - "cell_type": "code", - "execution_count": 34, - "id": "39c018e7-2fb8-4b39-bd9b-fbffb810a823", - "metadata": {}, - "outputs": [ - { - "name": "stdin", - "output_type": "stream", - "text": [ - "Username: admin@admin.tld\n", - "Password: admin\n" - ] - } - ], - "source": [ - "username = input('Username: ')\n", - "password = input('Password: ')" - ] - }, - { - "cell_type": "code", - "execution_count": 182, - "id": "96102efa-019b-4ee3-8c58-02de14b16e0c", - "metadata": {}, - "outputs": [], - "source": [ - "session = requests.session()" - ] - }, - { - "cell_type": "code", - "execution_count": 183, - "id": "6eca54d9-ae9a-42c2-a825-33164c0b1591", - "metadata": {}, - "outputs": [], - "source": [ - "assert session.post(API_URL + '/api/v1/auth/login', data={'email': username, 'password': password}).status_code == 200, 'Wrong username or password'" - ] - }, - { - "cell_type": "code", - "execution_count": 235, - "id": "b001af43-1f12-4994-8403-5dd4a165879e", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Successfully created 2 items\n" - ] - } - ], - "source": [ - "for item in items:\n", - " assert session.delete(f'{API_URL}/api/v1/surveys/items/{item[\"id\"]}').status_code in [404, 204], f'Failed to delete item {item[\"id\"]}'\n", - " r = session.post(f'{API_URL}/api/v1/surveys/items', json=item)\n", - " if r.status_code not in [201]:\n", - " print(f'Failed to create item {item[\"id\"]}: {r.text}')\n", - " break\n", - "else:\n", - " print(f'Successfully created {len(items)} items')" - ] - }, - { - "cell_type": "code", - "execution_count": 241, - "id": "31e2bd80-5569-407b-a562-5140d016093e", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Successfully created 2 groups\n" - ] - } - ], - "source": [ - "for group in groups:\n", - " group = group.copy()\n", - " its = group.pop('items_id')\n", - " assert session.delete(f'{API_URL}/api/v1/surveys/groups/{group[\"id\"]}').status_code in [404, 204], f'Failed to delete group {group[\"id\"]}'\n", - " r = session.post(f'{API_URL}/api/v1/surveys/groups', json=group)\n", - " if r.status_code not in [201]:\n", - " print(f'Failed to create group {group[\"id\"]}: {r.text}')\n", - " break\n", - "\n", - " for it in its:\n", - " assert session.delete(f'{API_URL}/api/v1/surveys/groups/{group[\"id\"]}/items/{it}').status_code in [404, 204], f'Failed to delete item {it} from group {group[\"id\"]}'\n", - " r = session.post(f'{API_URL}/api/v1/surveys/groups/{group[\"id\"]}/items', json={\"question_id\": it})\n", - " if r.status_code not in [201]:\n", - " print(f'Failed to add item {it} to group {group[\"id\"]}: {r.text}')\n", - " break\n", - "\n", - "else:\n", - " print(f'Successfully created {len(groups)} groups')" - ] - }, - { - "cell_type": "code", - "execution_count": 244, - "id": "3520668b-04fb-48f1-acbf-510ff4bc18c4", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Failed to add group 1 to survey 1: {\"detail\":\"Not Found\"}\n", - "Failed to add group 2 to survey 2: {\"detail\":\"Not Found\"}\n", - "Successfully created 2 surveys\n" - ] - } - ], - "source": [ - "for survey in surveys:\n", - " survey = survey.copy()\n", - " gps = survey.pop('groups_id')\n", - " assert session.delete(f'{API_URL}/api/v1/surveys/{survey[\"id\"]}').status_code in [404, 204], f'Failed to delete survey {survey[\"id\"]}'\n", - " r = session.post(f'{API_URL}/api/v1/surveys', json=survey)\n", - " if r.status_code not in [201]:\n", - " print(f'Failed to create suvey {survey[\"id\"]}: {r.text}')\n", - " break\n", - "\n", - " for gp in gps:\n", - " assert session.delete(f'{API_URL}/api/v1/surveys/{survey[\"id\"]}/groups/{gp}').status_code in [404, 204], f'Failed to delete gp {it} from survey {survey[\"id\"]}'\n", - " r = session.post(f'{API_URL}/api/v1/surveys/{survey[\"id\"]}/groups', json={\"group_id\": gp})\n", - " if r.status_code not in [201]:\n", - " print(f'Failed to add group {gp} to survey {survey[\"id\"]}: {r.text}')\n", - " break\n", - "\n", - "else:\n", - " print(f'Successfully created {len(groups)} surveys')" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.11.9" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/scripts/surveys/survey_maker.ipynb b/scripts/surveys/survey_maker.ipynb index 5dcd6c4b0e52848b4b94ecf43b86820f45c86454..b79c5dfbb95f73957486d201138c5e74406b0d67 100644 --- a/scripts/surveys/survey_maker.ipynb +++ b/scripts/surveys/survey_maker.ipynb @@ -2,7 +2,7 @@ "cells": [ { "cell_type": "code", - "execution_count": 142, + "execution_count": 1, "id": "5f682366-5ab6-4418-84b9-b971266af67f", "metadata": {}, "outputs": [], @@ -15,7 +15,7 @@ }, { "cell_type": "code", - "execution_count": 145, + "execution_count": 2, "id": "e8af376d-ce09-4537-a724-2028777adef3", "metadata": {}, "outputs": [], @@ -27,7 +27,7 @@ }, { "cell_type": "code", - "execution_count": 151, + "execution_count": 3, "id": "30116c8a-a0a6-4dc7-9b69-8afb50a6252e", "metadata": {}, "outputs": [], @@ -37,7 +37,7 @@ }, { "cell_type": "code", - "execution_count": 152, + "execution_count": 4, "id": "265ccfaa-e86d-460c-be36-1bdfbd2c433f", "metadata": {}, "outputs": [ @@ -118,7 +118,7 @@ "1 NaN NaN NaN " ] }, - "execution_count": 152, + "execution_count": 4, "metadata": {}, "output_type": "execute_result" } @@ -129,7 +129,7 @@ }, { "cell_type": "code", - "execution_count": 219, + "execution_count": 5, "id": "93beb77a-7e30-437d-9f7e-e079cd2db029", "metadata": {}, "outputs": [], @@ -144,10 +144,10 @@ " \n", " if 'question' in row:\n", " o['question'] = f'text:{row[\"question\"]}'\n", - " elif os.path.isfile(f'{ITEMS_FOLDER}/{id_}/q.mp3'):\n", + " elif os.path.isfile(f'{LOCAL_ITEMS_FOLDER}/{id_}/q.mp3'):\n", " o['question'] = f'audio:{REMOTE_ITEMS_FOLDER}/{id_}/q.mp3'\n", - " elif os.path.isfile(f'{ITEMS_FOLDER}/{id_}/q.jpeg'):\n", - " o['question'] = f'audio:{REMOTE_ITEMS_FOLDER}/{id_}/q.jpeg'\n", + " elif os.path.isfile(f'{LOCAL_ITEMS_FOLDER}/{id_}/q.jpeg'):\n", + " o['question'] = f'image:{REMOTE_ITEMS_FOLDER}/{id_}/q.jpeg'\n", " else:\n", " print(f'Failed to find a question for item {id_}')\n", "\n", @@ -160,15 +160,15 @@ " op = f'option{j}'\n", " if op in row:\n", " o[op] = 'text:' + row[op]\n", - " elif os.path.isfile(f'{ITEMS_FOLDER}/{id_}/{j}.mp3'):\n", + " elif os.path.isfile(f'{LOCAL_ITEMS_FOLDER}/{id_}/{j}.mp3'):\n", " o[op] = f'audio:{REMOTE_ITEMS_FOLDER}/{id_}/{j}.mp3'\n", - " elif os.path.isfile(f'{ITEMS_FOLDER}/{id_}/{j}.jpeg'):\n", - " o[op] = f'audio:{REMOTE_ITEMS_FOLDER}/{id_}/{j}.jpeg'" + " elif os.path.isfile(f'{LOCAL_ITEMS_FOLDER}/{id_}/{j}.jpeg'):\n", + " o[op] = f'image:{REMOTE_ITEMS_FOLDER}/{id_}/{j}.jpeg'" ] }, { "cell_type": "code", - "execution_count": 220, + "execution_count": 6, "id": "a2bc630b-af5a-4f65-b6f6-4005d2f359f5", "metadata": {}, "outputs": [], @@ -187,7 +187,7 @@ }, { "cell_type": "code", - "execution_count": 221, + "execution_count": 7, "id": "0d8fc0ea-6ec9-4c58-8395-2a415d556fea", "metadata": {}, "outputs": [], @@ -206,7 +206,7 @@ }, { "cell_type": "code", - "execution_count": 34, + "execution_count": 8, "id": "39c018e7-2fb8-4b39-bd9b-fbffb810a823", "metadata": {}, "outputs": [ @@ -226,7 +226,7 @@ }, { "cell_type": "code", - "execution_count": 182, + "execution_count": 9, "id": "96102efa-019b-4ee3-8c58-02de14b16e0c", "metadata": {}, "outputs": [], @@ -236,7 +236,7 @@ }, { "cell_type": "code", - "execution_count": 183, + "execution_count": 10, "id": "6eca54d9-ae9a-42c2-a825-33164c0b1591", "metadata": {}, "outputs": [], @@ -271,7 +271,7 @@ }, { "cell_type": "code", - "execution_count": 253, + "execution_count": 12, "id": "31e2bd80-5569-407b-a562-5140d016093e", "metadata": {}, "outputs": [ @@ -306,7 +306,7 @@ }, { "cell_type": "code", - "execution_count": 254, + "execution_count": 13, "id": "3520668b-04fb-48f1-acbf-510ff4bc18c4", "metadata": {}, "outputs": [