diff --git a/classquiz/emails/__init__.py b/classquiz/emails/__init__.py
index 3624dbe..bf650e9 100644
--- a/classquiz/emails/__init__.py
+++ b/classquiz/emails/__init__.py
@@ -1,3 +1,4 @@
+import os
import smtplib
import ssl
from email.mime.multipart import MIMEMultipart
@@ -5,7 +6,7 @@ from email.mime.text import MIMEText
from jinja2 import Environment, PackageLoader, select_autoescape
-from classquiz.config import settings
+from classquiz.config import settings, redis
from classquiz.db.models import User
settings = settings()
@@ -41,3 +42,18 @@ async def send_register_email(email: str):
token=user.verify_key
)
_sendMail(template=template, to=email, subject='Verify your email')
+
+
+async def send_forgotten_password_email(email: str):
+ user = await User.objects.get_or_none(email=email)
+ if user is None:
+ raise ValueError('User not found')
+ template = jinja.get_template('forgotten_password.jinja2')
+ token = os.urandom(32).hex()
+ template = await template.render_async(
+ base_url=settings.root_address,
+ token=token
+ )
+ await redis.set(f"reset_passwd:{token}", str(user.id), ex=3600)
+ _sendMail(template=template, to=email, subject='Reset your password')
+ pass
diff --git a/classquiz/emails/templates/forgotten_password.jinja2 b/classquiz/emails/templates/forgotten_password.jinja2
new file mode 100644
index 0000000..569ca73
--- /dev/null
+++ b/classquiz/emails/templates/forgotten_password.jinja2
@@ -0,0 +1,73 @@
+
Let's confirm your email address.
+
+
+
+
+
+
+
+
+
+
+ You're on your way! Let's reset your password.
+
+ By clicking on the following link, you are going to reset your password.
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {% include 'footer.jinja2' %}
+
+
\ No newline at end of file
diff --git a/classquiz/routers/users.py b/classquiz/routers/users.py
index dd49db7..83d227e 100644
--- a/classquiz/routers/users.py
+++ b/classquiz/routers/users.py
@@ -10,7 +10,7 @@ from classquiz.auth import *
from classquiz.config import redis
from classquiz.cache import clear_cache_for_account
from classquiz.db.models import *
-from classquiz.emails import send_register_email
+from classquiz.emails import send_register_email, send_forgotten_password_email
router = APIRouter()
@@ -18,6 +18,11 @@ route_user = User.get_pydantic(
exclude={"id": ..., "verified": ..., "verify_key": ..., "created_at": ..., "usersessions": ...})
+async def _sign_out_everywhere(user: User) -> None:
+ await UserSession.objects.filter(user=user).delete()
+ await clear_cache_for_account(user)
+
+
@router.post("/create", response_model=User,
response_model_include={"id": ..., "verified": ..., "email": ...})
async def create_user(user: route_user, background_task: BackgroundTasks) -> User | JSONResponse:
@@ -135,8 +140,7 @@ async def change_password(password_data: UpdatePassword, response: Response, use
@router.delete("/signout-everywhere")
async def signout_everywhere(response: Response, user: User = Depends(get_current_user)):
- await UserSession.objects.filter(user=user).delete()
- await clear_cache_for_account(user)
+ await _sign_out_everywhere(user)
response.delete_cookie("access_token")
response.delete_cookie("expiry")
response.delete_cookie("rememberme")
@@ -147,3 +151,39 @@ async def signout_everywhere(response: Response, user: User = Depends(get_curren
@router.get("/me", response_model_exclude={"password", "verify_key", "usersessions"})
async def get_me(user: User = Depends(get_current_user)):
return user.dict(exclude={"password", "verify_key", "usersessions"})
+
+
+class ForgotPassword(BaseModel):
+ email: str
+
+
+@router.post("/forgot-password")
+async def forgotten_password(forgot_password: ForgotPassword):
+ user = await User.objects.filter(email=forgot_password.email, verified=True).get_or_none()
+ if user is None:
+ raise HTTPException(status_code=404, detail="User not found")
+ await send_forgotten_password_email(user.email)
+ return {"message": "Password reset email sent"}
+
+
+class ResetPassword(BaseModel):
+ password: str
+ token: str
+
+
+@router.post("/reset-password")
+async def reset_password_with_token(reset_password: ResetPassword, response: Response):
+ redis_res = await redis.get(f"reset_passwd:{reset_password.token}")
+ if redis_res is None:
+ raise HTTPException(status_code=400, detail="Invalid token")
+ user = await User.objects.filter(id=uuid.UUID(redis_res)).get_or_none()
+ if user is None:
+ raise HTTPException(status_code=400, detail="Invalid token")
+ user.password = get_password_hash(reset_password.password)
+ await user.update()
+ await _sign_out_everywhere(user)
+ response.delete_cookie("access_token")
+ response.delete_cookie("expiry")
+ response.delete_cookie("rememberme")
+ response.delete_cookie("rememberme_token")
+ return {"message": "Password updated successfully"}
diff --git a/frontend/i18next-scanner.config.engine.cjs b/frontend/i18next-scanner.config.engine.cjs
index 571071a..7323129 100644
--- a/frontend/i18next-scanner.config.engine.cjs
+++ b/frontend/i18next-scanner.config.engine.cjs
@@ -10,7 +10,7 @@ module.exports = {
trans: false,
// Create and update files `en.json`, `fr.json`, `es.json`
- lngs: ['en', 'de'],
+ lngs: ['en', 'de', 'fr'],
ns: [
// The namespace I use
diff --git a/frontend/src/lib/i18n/locales/de.json b/frontend/src/lib/i18n/locales/de.json
index 2ce999c..14ec70a 100644
--- a/frontend/src/lib/i18n/locales/de.json
+++ b/frontend/src/lib/i18n/locales/de.json
@@ -1,111 +1,116 @@
{
- "index_page": {
- "meta": {
- "title": "Home",
- "description": "ClassQuiz ist eine Quiz-App wie KAHOOT! für Schüler*innen, welche open-source und kostenlos ist"
- },
- "features_description": {
- "1": "ClassQuiz ist eine Quiz-Platform, welche das erstellen und managen von Quizzes erlaubt.",
- "2": "Das Hauptfeature ist die KAHOOT!-Importfunktion, mit der man Quizzes von KAHOOT! importieren kann."
- },
- "slogan": "Die open-source Quiz-Platform!"
- },
- "overview_page": {
- "created_at": "Erstellt am",
- "question_count": "Fragenanzahl"
- },
- "edit_page": {
- "success_update_title": "Quiz erfolgreich aktualisiert!",
- "success_update_body": "Das Quiz wurde erfolgreich aktualisiert!"
- },
- "create_page": {
- "success": {
- "title": "Quiz erfolgreich erstellt!",
- "body": "Das Quiz wurde erfolgreich erstellt!"
- }
- },
- "register_page": {
- "greeting": "Schön, dich zu sehen!",
- "create_account": "Account erstellen",
- "forgot_password?": "Passwort vergessen?",
- "already_have_account?": "Hast du schon einen Account?"
- },
- "login_page": {
- "welcome_back": "Willkommen zurück!",
- "login_or_create_account": "Einloggen oder Account erstellen",
- "already_have_account": "Noch kein Account?",
- "modal": {
- "success": {
- "success_check_mail": "Login erfolgreich! Guck in deine Mailbox!",
- "success": "Login erfolgreich!",
- "description": {
- "success_check_mail": "Bitte überprüfe deine Mailbox, weil du eine Email mit einem Link, um dich einzuloggen, empfangen haben solltest.",
- "success": "Du hast dich erfolgreich angemeldet!"
- }
- },
- "error": {
- "wrong_creds": "Falsche Email oder falsches Passwort!",
- "unexpected": "Unerwarteter Fehler!",
- "description": {
- "wrong_creds": "Bitte stelle sicher, dass dein Passwort und deine Email richtig sind!",
- "unexpected": "Der gute alte unerwartete Fehler hat uns heimgesucht!"
- }
- }
- }
- },
- "words": {
- "question": "Frage",
- "answer": "Antwort",
- "stats": "Statistiken",
- "features": "Features",
- "import": "Importieren",
- "url": "URL",
- "submit": "Abschicken",
- "create": "Erstellen",
- "logout": "Abmelden",
- "title": "Titel",
- "play": "Spielen",
- "edit": "Bearbeiten",
- "delete": "Löschen",
- "public": "Öffentlich",
- "start": "Start",
- "connect": "Verbinden",
- "pin": "PIN",
- "kick": "Kicken",
- "register": "Registrieren",
- "login": "Anmelden",
- "docs": "Dokumentation",
- "close": "Schließen",
- "save": "Speichern",
- "username": "Nutzername",
- "password": "Passwort",
- "email": "Email",
- "description": "Beschreibung",
- "image": "Bild"
- },
- "editor": {
- "time_in_seconds": "Zeit in Sekunden",
- "right_or_true?": "Richtig?",
- "add_new_answer": "Neue Antwort hinzufügen",
- "add_new_question": "Neue Frage hinzufügen",
- "delete_question": "Frage löschen",
- "delete_answer": "Antwort löschen"
- },
- "import": {
- "need_help": "",
- "visit_docs": ""
- },
- "admin": {
- "already_registered_as_admin": ""
- },
- "admin_page": {
- "already_registered_as_admin": "Ein Admin wurde schon für dieses Spiel registriert.",
- "start_game": "Spiel starten",
- "time_left": "Zeit übrig",
- "get_results": "Ergebnisse abfragen"
- },
- "import_page": {
- "need_help": "Brauchst du Hilfe?",
- "visit_docs": "Besuche die Dokumentation"
- }
+ "index_page": {
+ "meta": {
+ "title": "Home",
+ "description": "ClassQuiz ist eine Quiz-App wie KAHOOT! für Schüler*innen, welche open-source und kostenlos ist"
+ },
+ "features_description": {
+ "1": "ClassQuiz ist eine Quiz-Platform, welche das erstellen und managen von Quizzes erlaubt.",
+ "2": "Das Hauptfeature ist die KAHOOT!-Importfunktion, mit der man Quizzes von KAHOOT! importieren kann."
+ },
+ "slogan": "Die open-source Quiz-Platform!"
+ },
+ "overview_page": {
+ "created_at": "Erstellt am",
+ "question_count": "Fragenanzahl"
+ },
+ "edit_page": {
+ "success_update_title": "Quiz erfolgreich aktualisiert!",
+ "success_update_body": "Das Quiz wurde erfolgreich aktualisiert!"
+ },
+ "create_page": {
+ "success": {
+ "title": "Quiz erfolgreich erstellt!",
+ "body": "Das Quiz wurde erfolgreich erstellt!"
+ }
+ },
+ "register_page": {
+ "greeting": "Schön, dich zu sehen!",
+ "create_account": "Account erstellen",
+ "forgot_password?": "Passwort vergessen?",
+ "already_have_account?": "Hast du schon einen Account?"
+ },
+ "login_page": {
+ "welcome_back": "Willkommen zurück!",
+ "login_or_create_account": "Einloggen oder Account erstellen",
+ "already_have_account": "Noch kein Account?",
+ "modal": {
+ "success": {
+ "success_check_mail": "Login erfolgreich! Guck in deine Mailbox!",
+ "success": "Login erfolgreich!",
+ "description": {
+ "success_check_mail": "Bitte überprüfe deine Mailbox, weil du eine Email mit einem Link, um dich einzuloggen, empfangen haben solltest.",
+ "success": "Du hast dich erfolgreich angemeldet!"
+ }
+ },
+ "error": {
+ "wrong_creds": "Falsche Email oder falsches Passwort!",
+ "unexpected": "Unerwarteter Fehler!",
+ "description": {
+ "wrong_creds": "Bitte stelle sicher, dass dein Passwort und deine Email richtig sind!",
+ "unexpected": "Der gute alte unerwartete Fehler hat uns heimgesucht!"
+ }
+ }
+ }
+ },
+ "words": {
+ "question": "Frage",
+ "answer": "Antwort",
+ "stats": "Statistiken",
+ "features": "Features",
+ "import": "Importieren",
+ "url": "URL",
+ "submit": "Abschicken",
+ "create": "Erstellen",
+ "logout": "Abmelden",
+ "title": "Titel",
+ "play": "Spielen",
+ "edit": "Bearbeiten",
+ "delete": "Löschen",
+ "public": "Öffentlich",
+ "start": "Start",
+ "connect": "Verbinden",
+ "pin": "PIN",
+ "kick": "Kicken",
+ "register": "Registrieren",
+ "login": "Anmelden",
+ "docs": "Dokumentation",
+ "close": "Schließen",
+ "save": "Speichern",
+ "username": "Nutzername",
+ "password": "Passwort",
+ "email": "Email",
+ "description": "Beschreibung",
+ "image": "Bild",
+ "settings": "Einstellungen",
+ "repeat_password": "Passwort wiederholen"
+ },
+ "editor": {
+ "time_in_seconds": "Zeit in Sekunden",
+ "right_or_true?": "Richtig?",
+ "add_new_answer": "Neue Antwort hinzufügen",
+ "add_new_question": "Neue Frage hinzufügen",
+ "delete_question": "Frage löschen",
+ "delete_answer": "Antwort löschen"
+ },
+ "import": {
+ "need_help": "",
+ "visit_docs": ""
+ },
+ "admin": {
+ "already_registered_as_admin": ""
+ },
+ "admin_page": {
+ "already_registered_as_admin": "Ein Admin wurde schon für dieses Spiel registriert.",
+ "start_game": "Spiel starten",
+ "time_left": "Zeit übrig",
+ "get_results": "Ergebnisse abfragen"
+ },
+ "import_page": {
+ "need_help": "Brauchst du Hilfe?",
+ "visit_docs": "Besuche die Dokumentation"
+ },
+ "password_reset_page": {
+ "reset_password": "Passwort zurücksetzen"
+ }
}
diff --git a/frontend/src/lib/i18n/locales/en.json b/frontend/src/lib/i18n/locales/en.json
index f60046f..531db26 100644
--- a/frontend/src/lib/i18n/locales/en.json
+++ b/frontend/src/lib/i18n/locales/en.json
@@ -1,104 +1,109 @@
{
- "index_page": {
- "slogan": "The open-source quiz-platform!",
- "meta": {
- "description": "ClassQuiz is a quiz app like KAHOOT! for students, which is open source and free to use",
- "title": "Home"
- },
- "features_description": {
- "1": "ClassQuiz is a quiz-platform that allows you to create and manage quizzes.",
- "2": "The main feature is a KAHOOT!-import function that allows you to import quizzes from KAHOOT!-quizzes."
- }
- },
- "overview_page": {
- "created_at": "Created at",
- "question_count": "Question count"
- },
- "edit_page": {
- "success_update_title": "Successfully updated quiz!",
- "success_update_body": "Updated the quiz successfully!"
- },
- "create_page": {
- "success": {
- "title": "Successfully created quiz!",
- "body": "Created the quiz successfully!"
- }
- },
- "register_page": {
- "greeting": "Nice to meet you!",
- "create_account": "Create account",
- "forgot_password?": "Forgot password?",
- "already_have_account?": "Already have an account?"
- },
- "login_page": {
- "welcome_back": "Welcome back!",
- "login_or_create_account": "Login or create an account",
- "already_have_account": "Don't have an account?",
- "modal": {
- "success": {
- "success_check_mail": "Login Succeded! Check your mailbox!",
- "success": "Login Succeded!",
- "description": {
- "success_check_mail": "Please check your mailbox, since you should have received a mail, with a link you can click to login.",
- "success": "You've successfully logged in!"
- }
- },
- "error": {
- "wrong_creds": "Wrong email or password!",
- "unexpected": "Unexpected error!",
- "description": {
- "wrong_creds": "Please make sure that your password and your email are correct!",
- "unexpected": "There was the good old unexpected error!"
- }
- }
- }
- },
- "words": {
- "question": "Question",
- "answer": "Answer",
- "stats": "Stats",
- "features": "Features",
- "login": "Login",
- "email": "Email",
- "username": "Username",
- "password": "Password",
- "play": "Play",
- "edit": "Edit",
- "delete": "Delete",
- "public": "Public",
- "start": "Start",
- "create": "Create",
- "import": "Import",
- "logout": "Logout",
- "title": "Title",
- "url": "URL",
- "submit": "Submit",
- "connect": "Connect",
- "pin": "PIN",
- "kick": "Kick",
- "register": "Register",
- "docs": "Docs",
- "close": "Close",
- "save": "Save",
- "description": "Description",
- "image": "Image"
- },
- "editor": {
- "time_in_seconds": "Time in seconds",
- "right_or_true?": "Right?",
- "add_new_answer": "Add new answer",
- "add_new_question": "Add new question",
- "delete_question": "Delete question",
- "delete_answer": "Delete answer"
- },
- "import_page": {
- "need_help": "Need help?",
- "visit_docs": "Visit the documentation"
- },
- "admin_page": {
- "already_registered_as_admin": "There is already an admin registered for this game.",
- "start_game": "Start game",
- "time_left": "Time left",
- "get_results": "Get results"
- }
+ "index_page": {
+ "slogan": "The open-source quiz-platform!",
+ "meta": {
+ "description": "ClassQuiz is a quiz app like KAHOOT! for students, which is open source and free to use",
+ "title": "Home"
+ },
+ "features_description": {
+ "1": "ClassQuiz is a quiz-platform that allows you to create and manage quizzes.",
+ "2": "The main feature is a KAHOOT!-import function that allows you to import quizzes from KAHOOT!-quizzes."
+ }
+ },
+ "overview_page": {
+ "created_at": "Created at",
+ "question_count": "Question count"
+ },
+ "edit_page": {
+ "success_update_title": "Successfully updated quiz!",
+ "success_update_body": "Updated the quiz successfully!"
+ },
+ "create_page": {
+ "success": {
+ "title": "Successfully created quiz!",
+ "body": "Created the quiz successfully!"
+ }
+ },
+ "register_page": {
+ "greeting": "Nice to meet you!",
+ "create_account": "Create account",
+ "forgot_password?": "Forgot password?",
+ "already_have_account?": "Already have an account?"
+ },
+ "login_page": {
+ "welcome_back": "Welcome back!",
+ "login_or_create_account": "Login or create an account",
+ "already_have_account": "Don't have an account?",
+ "modal": {
+ "success": {
+ "success_check_mail": "Login Succeded! Check your mailbox!",
+ "success": "Login Succeded!",
+ "description": {
+ "success_check_mail": "Please check your mailbox, since you should have received a mail, with a link you can click to login.",
+ "success": "You've successfully logged in!"
+ }
+ },
+ "error": {
+ "wrong_creds": "Wrong email or password!",
+ "unexpected": "Unexpected error!",
+ "description": {
+ "wrong_creds": "Please make sure that your password and your email are correct!",
+ "unexpected": "There was the good old unexpected error!"
+ }
+ }
+ }
+ },
+ "words": {
+ "question": "Question",
+ "answer": "Answer",
+ "stats": "Stats",
+ "features": "Features",
+ "login": "Login",
+ "email": "Email",
+ "username": "Username",
+ "password": "Password",
+ "play": "Play",
+ "edit": "Edit",
+ "delete": "Delete",
+ "public": "Public",
+ "start": "Start",
+ "create": "Create",
+ "import": "Import",
+ "logout": "Logout",
+ "title": "Title",
+ "url": "URL",
+ "submit": "Submit",
+ "connect": "Connect",
+ "pin": "PIN",
+ "kick": "Kick",
+ "register": "Register",
+ "docs": "Docs",
+ "close": "Close",
+ "save": "Save",
+ "description": "Description",
+ "image": "Image",
+ "settings": "Settings",
+ "repeat_password": "Repeat password"
+ },
+ "editor": {
+ "time_in_seconds": "Time in seconds",
+ "right_or_true?": "Right?",
+ "add_new_answer": "Add new answer",
+ "add_new_question": "Add new question",
+ "delete_question": "Delete question",
+ "delete_answer": "Delete answer"
+ },
+ "import_page": {
+ "need_help": "Need help?",
+ "visit_docs": "Visit the documentation"
+ },
+ "admin_page": {
+ "already_registered_as_admin": "There is already an admin registered for this game.",
+ "start_game": "Start game",
+ "time_left": "Time left",
+ "get_results": "Get results"
+ },
+ "password_reset_page": {
+ "reset_password": "Reset password"
+ }
}
diff --git a/frontend/src/lib/i18n/locales/fr.json b/frontend/src/lib/i18n/locales/fr.json
index eb6f3e7..1f9a818 100644
--- a/frontend/src/lib/i18n/locales/fr.json
+++ b/frontend/src/lib/i18n/locales/fr.json
@@ -1,104 +1,109 @@
{
- "login_page": {
- "modal": {
- "success": {
- "description": {
- "success": "Vous vous êtes connecté avec succès !",
- "success_check_mail": "Veuillez vérifier votre boîte mail, vous avez normalement reçu un mail avec un lien pour vous connecter."
- },
- "success": "Connexion réussie !",
- "success_check_mail": "Connexion réussie ! Vérifiez votre boîte mail !"
- },
- "error": {
- "wrong_creds": "Mot de passe ou email non-correct !",
- "description": {
- "wrong_creds": "Assurez-vous que votre mot de passe et votre email sont corrects !",
- "unexpected": "Une bonne vieille erreur inattendue s'est produite !"
- },
- "unexpected": "Erreur inattendue !"
- }
- },
- "welcome_back": "Bon retour parmi nous !",
- "login_or_create_account": "Se connecter ou créer un compte",
- "already_have_account": "Pas encore de compte ?"
- },
- "words": {
- "question": "Question",
- "answer": "Réponse",
- "stats": "Statistiques",
- "features": "Fonctionnalités",
- "login": "Connexion",
- "email": "Email",
- "username": "Pseudo",
- "password": "Mot de passe",
- "play": "Jouer",
- "edit": "Modifier",
- "delete": "Supprimer",
- "public": "Public",
- "start": "Commencer",
- "create": "Créer",
- "import": "Importer",
- "logout": "Se déconnecter",
- "url": "URL",
- "submit": "Valider",
- "connect": "Connexion",
- "pin": "PIN",
- "kick": "Éjecter",
- "register": "Enregistrer",
- "docs": "Documentation",
- "close": "Fermer",
- "save": "Enregistrer",
- "description": "Description",
- "image": "Image",
- "title": "titre"
- },
- "index_page": {
- "slogan": "La plateforme de quiz open-source !",
- "meta": {
- "description": "ClassQuiz est une application de quiz comme KAHOOT! pour les étudiants, libre et open-source",
- "title": "Accueil"
- },
- "features_description": {
- "1": "ClassQuiz est un outil de quiz vous permettant de créer et gérer des questionnaires.",
- "2": "La fonctionnalité principale est la fonction d'import de quiz KAHOOT, vou permettant de créer des quiz directement depuis KAHOOT!."
- }
- },
- "overview_page": {
- "created_at": "Crée le",
- "question_count": "Nombre de question"
- },
- "edit_page": {
- "success_update_title": "Quiz mis à jour avec succès !",
- "success_update_body": "Quiz mis à jour avec succès !"
- },
- "create_page": {
- "success": {
- "body": "Quiz créé avec succès !",
- "title": "Quiz créé avec succès !"
- }
- },
- "register_page": {
- "greeting": "Ravi de vous connaître !",
- "create_account": "Créer un compte",
- "forgot_password?": "Mot de passe oublié ?",
- "already_have_account?": "Vous avez déjà un compte ?"
- },
- "editor": {
- "time_in_seconds": "Temps en seconde",
- "add_new_question": "Ajouter une autre question",
- "add_new_answer": "Ajouter une autre réponse",
- "delete_question": "Supprimer la question",
- "delete_answer": "Supprimer la réponse",
- "right_or_true?": "Vrai?"
- },
- "import_page": {
- "need_help": "Besoin d'aide ?",
- "visit_docs": "Voir la documentation"
- },
- "admin_page": {
- "already_registered_as_admin": "Il y a déjà un administrateur enregistré pour ce jeu.",
- "start_game": "Commencer le jeu",
- "time_left": "Temps restant",
- "get_results": "Obtenir les résultats"
- }
+ "login_page": {
+ "modal": {
+ "success": {
+ "description": {
+ "success": "Vous vous êtes connecté avec succès !",
+ "success_check_mail": "Veuillez vérifier votre boîte mail, vous avez normalement reçu un mail avec un lien pour vous connecter."
+ },
+ "success": "Connexion réussie !",
+ "success_check_mail": "Connexion réussie ! Vérifiez votre boîte mail !"
+ },
+ "error": {
+ "wrong_creds": "Mot de passe ou email non-correct !",
+ "description": {
+ "wrong_creds": "Assurez-vous que votre mot de passe et votre email sont corrects !",
+ "unexpected": "Une bonne vieille erreur inattendue s'est produite !"
+ },
+ "unexpected": "Erreur inattendue !"
+ }
+ },
+ "welcome_back": "Bon retour parmi nous !",
+ "login_or_create_account": "Se connecter ou créer un compte",
+ "already_have_account": "Pas encore de compte ?"
+ },
+ "words": {
+ "question": "Question",
+ "answer": "Réponse",
+ "stats": "Statistiques",
+ "features": "Fonctionnalités",
+ "login": "Connexion",
+ "email": "Email",
+ "username": "Pseudo",
+ "password": "Mot de passe",
+ "play": "Jouer",
+ "edit": "Modifier",
+ "delete": "Supprimer",
+ "public": "Public",
+ "start": "Commencer",
+ "create": "Créer",
+ "import": "Importer",
+ "logout": "Se déconnecter",
+ "url": "URL",
+ "submit": "Valider",
+ "connect": "Connexion",
+ "pin": "PIN",
+ "kick": "Éjecter",
+ "register": "Enregistrer",
+ "docs": "Documentation",
+ "close": "Fermer",
+ "save": "Enregistrer",
+ "description": "Description",
+ "image": "Image",
+ "title": "titre",
+ "settings": "Paramètres",
+ "repeat_password": ""
+ },
+ "index_page": {
+ "slogan": "La plateforme de quiz open-source !",
+ "meta": {
+ "description": "ClassQuiz est une application de quiz comme KAHOOT! pour les étudiants, libre et open-source",
+ "title": "Accueil"
+ },
+ "features_description": {
+ "1": "ClassQuiz est un outil de quiz vous permettant de créer et gérer des questionnaires.",
+ "2": "La fonctionnalité principale est la fonction d'import de quiz KAHOOT, vou permettant de créer des quiz directement depuis KAHOOT!."
+ }
+ },
+ "overview_page": {
+ "created_at": "Crée le",
+ "question_count": "Nombre de question"
+ },
+ "edit_page": {
+ "success_update_title": "Quiz mis à jour avec succès !",
+ "success_update_body": "Quiz mis à jour avec succès !"
+ },
+ "create_page": {
+ "success": {
+ "body": "Quiz créé avec succès !",
+ "title": "Quiz créé avec succès !"
+ }
+ },
+ "register_page": {
+ "greeting": "Ravi de vous connaître !",
+ "create_account": "Créer un compte",
+ "forgot_password?": "Mot de passe oublié ?",
+ "already_have_account?": "Vous avez déjà un compte ?"
+ },
+ "editor": {
+ "time_in_seconds": "Temps en seconde",
+ "add_new_question": "Ajouter une autre question",
+ "add_new_answer": "Ajouter une autre réponse",
+ "delete_question": "Supprimer la question",
+ "delete_answer": "Supprimer la réponse",
+ "right_or_true?": "Vrai?"
+ },
+ "import_page": {
+ "need_help": "Besoin d'aide ?",
+ "visit_docs": "Voir la documentation"
+ },
+ "admin_page": {
+ "already_registered_as_admin": "Il y a déjà un administrateur enregistré pour ce jeu.",
+ "start_game": "Commencer le jeu",
+ "time_left": "Temps restant",
+ "get_results": "Obtenir les résultats"
+ },
+ "password_reset_page": {
+ "reset_password": ""
+ }
}
diff --git a/frontend/src/routes/account/password-reset.svelte b/frontend/src/routes/account/password-reset.svelte
new file mode 100644
index 0000000..9b09036
--- /dev/null
+++ b/frontend/src/routes/account/password-reset.svelte
@@ -0,0 +1,165 @@
+
+
+
+
+
+
+
+
+
+
+ ClassQuiz
+
+
+
+
+
+ {$t('password_reset_page.reset_password')}
+
+
+
+
+
+
+
{$t('login_page.already_have_account')}
+
+
+
{$t('words.register')}
+
+
+
+
\ No newline at end of file
diff --git a/frontend/src/routes/account/reset-password.svelte b/frontend/src/routes/account/reset-password.svelte
new file mode 100644
index 0000000..9159d24
--- /dev/null
+++ b/frontend/src/routes/account/reset-password.svelte
@@ -0,0 +1,135 @@
+
+
+
+
+
+
+
+
+
+
+ ClassQuiz
+
+
+
+
+
+ {$t('password_reset_page.reset_password')}
+
+
+
+
+
+
+
{$t('login_page.already_have_account')}
+
+
+
{$t('words.register')}
+
+
+
+
diff --git a/frontend/src/routes/account/settings.svelte b/frontend/src/routes/account/settings.svelte
new file mode 100644
index 0000000..8889b61
--- /dev/null
+++ b/frontend/src/routes/account/settings.svelte
@@ -0,0 +1,125 @@
+
+
+
+
+{#await getUser()}
+
+
+
+
+{:then user}
+
+
+
+
+
+
+
{user.username}
+
{$t("words.email")}: {user.email}
+
+
+
+
+
+{/await}
diff --git a/frontend/src/routes/overview.svelte b/frontend/src/routes/overview.svelte
index 0ed07bc..2645313 100644
--- a/frontend/src/routes/overview.svelte
+++ b/frontend/src/routes/overview.svelte
@@ -77,7 +77,7 @@
class='px-4 py-2 font-medium tracking-wide text-gray-500 whitespace-nowrap dark:text-gray-400 capitalize transition-colors dark:bg-gray-700 duration-200 transform bg-gray-50 rounded-md hover:bg-green-600 focus:outline-none focus:ring focus:ring-blue-300 focus:ring-opacity-80'>
Primary
-->
-