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.

+ + + + + + +
+ + + + + + +
Confirm Password Reset
+
+
+
+
+ {% 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('register_page.already_have_account?')} + + +
+
+
+
+ +
+ {$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('register_page.already_have_account?')} + + +
+
+
+
+ +
+ {$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} +
+
+
+ Profile image of {user.username} +
+
+

{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 --> -
+
{$t('words.logout')} + + {$t('words.settings')} + +