Skip to content
Extraits de code Groupes Projets
Valider 4f0a943f rédigé par Brieuc Dubois's avatar Brieuc Dubois
Parcourir les fichiers

Implement weekly survey #49

parent b0c1deaa
Aucune branche associée trouvée
Aucune étiquette associée trouvée
Aucune requête de fusion associée trouvée
......@@ -66,6 +66,12 @@ def create_contact(db: Session, user, contact):
db.refresh(user)
return user
def create_user_survey_weekly(db: Session, user_id: int, survey: schemas.SurveyCreate):
db_user_survey_weekly = models.UserSurveyWeekly(user_id=user_id, **survey.dict())
db.add(db_user_survey_weekly)
db.commit()
db.refresh(db_user_survey_weekly)
return db_user_survey_weekly
def get_contact_sessions(db: Session, user_id: int, contact_id: int):
return (
......
......@@ -379,6 +379,27 @@ def get_contacts(
return db_user.contacts + db_user.contact_of
@usersRouter.post("/{user_id}/surveys/weekly", status_code=status.HTTP_201_CREATED)
def create_weekly_survey(
user_id: int,
survey: schemas.UserSurveyWeeklyCreate,
db: Session = Depends(get_db),
current_user: schemas.User = Depends(get_jwt_user),
):
if (
not check_user_level(current_user, models.UserType.ADMIN)
and current_user.id != user_id
):
raise HTTPException(
status_code=401,
detail="You do not have permission to create a survey for this user",
)
db_user = crud.get_user(db, user_id)
if db_user is None:
raise HTTPException(status_code=404, detail="User not found")
return crud.create_user_survey_weekly(db, user_id, survey).id
@sessionsRouter.post("", response_model=schemas.Session)
def create_session(
db: Session = Depends(get_db),
......
......@@ -47,6 +47,7 @@ class User(Base):
gender = Column(String, default=None)
calcom_link = Column(String, default="")
study_id = Column(Integer, ForeignKey("studies.id"), default=None)
last_survey = Column(DateTime, default=None)
sessions = relationship(
"Session", secondary="user_sessions", back_populates="users"
......@@ -69,6 +70,18 @@ class User(Base):
)
class UserSurveyWeekly(Base):
__tablename__ = "users_survey_weekly"
id = Column(Integer, primary_key=True, index=True)
created_at = Column(DateTime, default=datetime.datetime.now)
user_id = Column(Integer, ForeignKey("users.id"))
q1 = Column(Float)
q2 = Column(Float)
q3 = Column(Float)
q4 = Column(Float)
class Session(Base):
__tablename__ = "sessions"
......
......@@ -18,6 +18,7 @@ class User(BaseModel):
gender: str | None = None
calcom_link: str | None
study_id: int | None = None
last_survey: datetime.datetime | None = None
class Config:
from_attributes = True
......@@ -37,6 +38,7 @@ class UserCreate(BaseModel):
gender: str | None = None
calcom_link: str | None = None
study_id: int | None = None
last_survey: datetime.datetime | None = None
class UserUpdate(BaseModel):
......@@ -53,6 +55,7 @@ class UserUpdate(BaseModel):
gender: str | None = None
calcom_link: str | None = None
study_id: int | None = None
last_survey: datetime.datetime | None = None
class Config:
from_attributes = True
......@@ -65,6 +68,13 @@ class ContactCreate(BaseModel):
from_attributes = True
class UserSurveyWeeklyCreate(BaseModel):
q1: float
q2: float
q3: float
q4: float
class Session(BaseModel):
id: int
created_at: datetime.datetime
......
......@@ -211,6 +211,36 @@
"q1": "À quel point cette application est-elle utile ?",
"q2": "À quel point cette application est-elle facile à utiliser ?",
"q3": "Remarques éventuelles"
},
"weekly": {
"title": "Questionnaire hebdomadaire",
"description": "Au cours des 7 derniers jours...",
"questions": [
"Combien d'heures de <span class='font-bold'>cours</span> de {TARGET_LANGUAGE} avez vous suivies ?",
"Combien d'heures avez-vous <span class='font-bold'>regardé des vidéos</span> en {TARGET_LANGUAGE} (films, séries, Youtube...) ou <span class='font-bold'>écouté des contenus</span> en {TARGET_LANGUAGE} (podcasts, radio, cours universitaires...) ?",
"Combien d'heures avez-vous <span class='font-bold'>lu des textes</span> en {TARGET_LANGUAGE} (livre, journal, BD, sites web...) ?",
"Combien d'heures avez-vous <span class='font-bold'>parlé</span> en {TARGET_LANGUAGE} (discussions avec amis, famille, collègues...) ?"
],
"answers": {
"placeholder": "",
"0": "Aucune",
"05": "30 minutes ou moins",
"1": "1 heure",
"2": "2 heures",
"3": "3 heures",
"4": "4 heures",
"5": "5 heures",
"6": "6 heures",
"7": "7 heures",
"8": "8 heures",
"9": "9 heures",
"10": "10 heures ou plus"
},
"errors": {
"null": "Veuillez répondre à toutes les questions",
"submit": "Erreur lors de l'envoi du questionnaire"
},
"success": "Questionnaire envoyé, merci !"
}
}
},
......
......@@ -145,3 +145,23 @@ export async function createTestTypingAPI(
return response.data;
}
export async function createWeeklySurveyAPI(
user_id: number,
q1: number,
q2: number,
q3: number,
q4: number
): Promise<number | null> {
const response = await axiosInstance.post(`/users/${user_id}/surveys/weekly`, {
q1,
q2,
q3,
q4
});
if (response.status !== 201) {
toastAlert('Failed to create weekly survey');
return null;
}
return response.data;
}
<script lang="ts">
import { createWeeklySurveyAPI } from '$lib/api/users';
import config from '$lib/config';
import { t } from '$lib/services/i18n';
import { user } from '$lib/types/user';
import { toastAlert, toastSuccess, toastWarning } from '$lib/utils/toasts';
let open =
!$user?.last_survey || $user.last_survey.getTime() + config.WEEKLY_SURVEY_INTERVAL < Date.now();
async function send() {
if (!$user) return;
const data = Array.from({ length: 4 }, (_, i) => {
const value = (document.getElementById('questions-' + i) as HTMLSelectElement).value;
return value === '-1' ? null : parseFloat(value);
});
if (data.includes(null)) {
toastWarning($t('session.modal.weekly.errors.null'));
return;
}
const res = await createWeeklySurveyAPI($user.id, data[0]!, data[1]!, data[2]!, data[3]!);
if (!res) {
toastAlert($t('session.modal.weekly.errors.submit'));
}
await $user.patch({ last_survey: new Date() });
open = false;
toastSuccess($t('session.modal.weekly.success'));
}
</script>
<dialog
class="modal bg-black bg-opacity-50"
{open}
on:close={() => (open = false)}
on:keydown={(e) => e.key === 'Escape' && (open = false)}
tabindex="0"
aria-modal="true"
>
<div class="modal-box max-w-none">
<h2 class="text-xl font-bold mb-4">{$t('session.modal.weekly.title')}</h2>
<p>{@html $t('session.modal.weekly.description')}</p>
{#each new Array(4) as _, i}
<label class="form-control w-full">
<div class="label">
<span class="label-text"
>{@html $t('session.modal.weekly.questions.' + i).replaceAll(
'{TARGET_LANGUAGE}',
$t('utils.language.' + $user?.target_language).toLowerCase()
)}</span
>
</div>
<select id={'questions-' + i} class="select select-bordered">
<option value="-1" hidden selected
>{$t('session.modal.weekly.answers.placeholder')}</option
>
<option value="0">{$t('session.modal.weekly.answers.0')}</option>
<option value="0.5">{$t('session.modal.weekly.answers.05')}</option>
<option value="1">{$t('session.modal.weekly.answers.1')}</option>
<option value="2">{$t('session.modal.weekly.answers.2')}</option>
<option value="3">{$t('session.modal.weekly.answers.3')}</option>
<option value="4">{$t('session.modal.weekly.answers.4')}</option>
<option value="5">{$t('session.modal.weekly.answers.5')}</option>
<option value="6">{$t('session.modal.weekly.answers.6')}</option>
<option value="7">{$t('session.modal.weekly.answers.7')}</option>
<option value="8">{$t('session.modal.weekly.answers.8')}</option>
<option value="9">{$t('session.modal.weekly.answers.9')}</option>
<option value="10">{$t('session.modal.weekly.answers.10')}</option>
</select>
</label>
{/each}
<button class="btn btn-primary w-full mt-10" on:click={send}>{$t('button.submit')}</button>
</div>
</dialog>
......@@ -3,6 +3,8 @@ export default {
API_PROXY: import.meta.env.VITE_API_PROXY || 'https://languagelab.sipr.ucl.ac.be:8000',
APP_URL: import.meta.env.VITE_APP_URL || 'https://languagelab.sipr.ucl.ac.be',
WS_URL: import.meta.env.VITE_WS_URL || 'wss://languagelab.sipr.ucl.ac.be/api/v1/ws',
// 1 week - 2 hours
WEEKLY_SURVEY_INTERVAL: (7 * 24 - 2) * 60 * 60 * 1000,
LEARNING_LANGUAGES: {
fra: 'French - fran\u00e7ais'
},
......
import { createUserAPI, getUsersAPI, patchUserAPI } from '$lib/api/users';
import { parseToLocalDate } from '$lib/utils/date';
import { toastAlert } from '$lib/utils/toasts';
import { get, writable } from 'svelte/store';
......@@ -30,6 +31,8 @@ export default class User {
private _birthdate: number | null;
private _gender: string | null;
private _calcom_link: string | null;
private _study_id: number | null;
private _last_survey: Date | null;
private constructor(
id: number,
......@@ -43,7 +46,9 @@ export default class User {
target_language: string | null,
birthdate: number | null,
gender: string | null,
calcom_link: string | null
calcom_link: string | null,
study_id: number | null,
last_survey: Date | null
) {
this._id = id;
this._email = email;
......@@ -57,6 +62,8 @@ export default class User {
this._birthdate = birthdate;
this._gender = gender;
this._calcom_link = calcom_link;
this._study_id = study_id;
this._last_survey = last_survey;
}
get id(): number {
......@@ -115,6 +122,14 @@ export default class User {
return this._calcom_link;
}
get study_id(): number | null {
return this._study_id;
}
get last_survey(): Date | null {
return this._last_survey;
}
equals<T>(obj: T): boolean {
if (obj === null || obj === undefined) return false;
if (!(obj instanceof User)) return false;
......@@ -147,7 +162,9 @@ export default class User {
target_language: this.target_language,
birthdate: this.birthdate,
gender: this.gender,
calcom_link: this.calcom_link
calcom_link: this.calcom_link,
study_id: this.study_id,
last_survey: this.last_survey
});
}
......@@ -165,6 +182,8 @@ export default class User {
if (data.birthdate) this._birthdate = data.birthdate;
if (data.gender) this._gender = data.gender;
if (data.calcum_link) this._calcom_link = data.calcom_link;
if (data.study_id) this._study_id = data.study_id;
if (data.last_survey) this._last_survey = data.last_survey;
}
return res;
}
......@@ -195,6 +214,8 @@ export default class User {
null,
null,
null,
null,
null,
null
);
users.add(user);
......@@ -235,7 +256,9 @@ export default class User {
json.target_language,
json.birthdate,
json.gender,
json.calcom_link
json.calcom_link,
json.study_id,
json.last_survey === null ? null : new Date(json.last_survey)
);
users.update((us) => {
......
......@@ -7,6 +7,8 @@
import { onMount } from 'svelte';
import { user } from '$lib/types/user';
import Gravatar from 'svelte-gravatar';
import WeeklySurvey from '$lib/components/users/weeklySurvey.svelte';
import config from '$lib/config.js';
export let data;
let session: Session | null = null;
......@@ -61,3 +63,7 @@
<div class=""></div>
</div>
{/if}
{#if $user}
<WeeklySurvey />
{/if}
0% Chargement en cours ou .
You are about to add 0 people to the discussion. Proceed with caution.
Terminez d'abord l'édition de ce message.
Veuillez vous inscrire ou vous pour commenter