-
Notifications
You must be signed in to change notification settings - Fork 0
Develop #36
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Develop #36
Changes from all commits
2617ec0
428dde1
51d74bb
e1469c5
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -4,6 +4,8 @@ | |||||||||
| import os | ||||||||||
| from datetime import datetime | ||||||||||
| from pydantic import BaseModel | ||||||||||
| from typing import Optional | ||||||||||
| from uuid import uuid4 | ||||||||||
| from dotenv import load_dotenv | ||||||||||
| from utils.auth import is_school_email, validate_card_context, validate_origin | ||||||||||
|
|
||||||||||
|
|
@@ -14,11 +16,20 @@ | |||||||||
| supabase = None | ||||||||||
| latest_card = None | ||||||||||
| FRONTEND_URLS = None | ||||||||||
| NO_CARD_PLACEHOLDER = "000000" | ||||||||||
| TEMP_CARD_PREFIX = "TMP-000000-" | ||||||||||
|
|
||||||||||
|
|
||||||||||
| class LoginData(BaseModel): | ||||||||||
| email: str | ||||||||||
| password: str | ||||||||||
| scanned_card_id: Optional[str] = None | ||||||||||
|
|
||||||||||
|
|
||||||||||
| def _is_temporary_card(card_id: Optional[str]) -> bool: | ||||||||||
| if not card_id: | ||||||||||
| return True | ||||||||||
| return card_id == NO_CARD_PLACEHOLDER or card_id.startswith(TEMP_CARD_PREFIX) | ||||||||||
|
|
||||||||||
|
|
||||||||||
| def init_user_routes(db, card_data, frontend_url=None): | ||||||||||
|
|
@@ -50,38 +61,83 @@ def login_user(request: Request, data: LoginData): | |||||||||
| if user.get("password") != data.password: | ||||||||||
| raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="Identifiants invalides") | ||||||||||
|
|
||||||||||
| latest_card["id"] = user.get("id_card") | ||||||||||
| card_id = user.get("id_card") | ||||||||||
| scanned_card_id = data.scanned_card_id.strip() if data.scanned_card_id else None | ||||||||||
|
|
||||||||||
| if scanned_card_id: | ||||||||||
| validate_card_context(latest_card, scanned_card_id) | ||||||||||
|
|
||||||||||
| existing_card = ( | ||||||||||
| supabase | ||||||||||
| .table("CreaLab_visitors") | ||||||||||
| .select("email") | ||||||||||
| .eq("id_card", scanned_card_id) | ||||||||||
| .execute() | ||||||||||
| ) | ||||||||||
|
|
||||||||||
| if existing_card.data and existing_card.data[0].get("email") != data.email: | ||||||||||
| raise HTTPException( | ||||||||||
| status_code=status.HTTP_409_CONFLICT, | ||||||||||
| detail="Cette carte est déjà associée à un autre compte" | ||||||||||
| ) | ||||||||||
|
|
||||||||||
| supabase.table("CreaLab_visitors").update({"id_card": scanned_card_id}).eq("email", data.email).execute() | ||||||||||
| card_id = scanned_card_id | ||||||||||
|
|
||||||||||
| if _is_temporary_card(card_id): | ||||||||||
| raise HTTPException( | ||||||||||
| status_code=status.HTTP_403_FORBIDDEN, | ||||||||||
| detail="Scannez une carte pour finaliser la connexion" | ||||||||||
| ) | ||||||||||
|
|
||||||||||
| latest_card["id"] = card_id | ||||||||||
| latest_card["ts"] = datetime.utcnow() | ||||||||||
|
|
||||||||||
| return { | ||||||||||
| "authenticated": True, | ||||||||||
| "card_id": user.get("id_card") | ||||||||||
| "card_id": card_id | ||||||||||
| } | ||||||||||
|
|
||||||||||
|
|
||||||||||
| @router.post("/submit") | ||||||||||
| def submit_data(request: Request, data: ProfileData): | ||||||||||
| logging.info("Submitting profile for card: %s", data.card_id) | ||||||||||
| validate_origin(request, FRONTEND_URLS) | ||||||||||
| validate_card_context(latest_card, data.card_id) | ||||||||||
|
|
||||||||||
| existing_email = ( | ||||||||||
| supabase | ||||||||||
| .table("CreaLab_visitors") | ||||||||||
| .select("email") | ||||||||||
| .eq("email", data.email) | ||||||||||
|
Comment on lines
+107
to
+111
|
||||||||||
| .execute() | ||||||||||
| ) | ||||||||||
| if existing_email.data: | ||||||||||
| raise HTTPException(status_code=status.HTTP_409_CONFLICT, detail="Un compte existe déjà avec cet email") | ||||||||||
|
|
||||||||||
| normalized_card_id = data.card_id.strip() | ||||||||||
| if normalized_card_id == NO_CARD_PLACEHOLDER: | ||||||||||
| normalized_card_id = f"{TEMP_CARD_PREFIX}{uuid4().hex[:12]}" | ||||||||||
|
||||||||||
| normalized_card_id = f"{TEMP_CARD_PREFIX}{uuid4().hex[:12]}" | |
| normalized_card_id = f"{TEMP_CARD_PREFIX}{uuid4().hex[:12]}" | |
| latest_card["id"] = None | |
| latest_card["ts"] = None |
| Original file line number | Diff line number | Diff line change | ||
|---|---|---|---|---|
|
|
@@ -5,8 +5,11 @@ import Calendar from './pages/Calendar/Calendar'; | |||
| import Inscription from './components/Inscription/Inscription'; | ||||
| import Connexion from './components/Connexion/Connexion'; | ||||
| import { setCardScanCallback } from './services/cardScanListener'; | ||||
| import Bouton from './components/Bouton/Bouton'; | ||||
|
|
||||
| type AppState = 'waiting' | 'login' | 'inscription' | 'calendar'; | ||||
| type AppState = 'waiting' | 'login' | 'inscription' | 'calendar' | 'cardNotFound' | 'linkLogin'; | ||||
|
|
||||
| const NO_CARD_PLACEHOLDER = '000000'; | ||||
|
|
||||
|
Comment on lines
+12
to
13
|
||||
| const NO_CARD_PLACEHOLDER = '000000'; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -11,6 +11,7 @@ interface InscriptionInterface { | |
| card_id: string; | ||
| }; | ||
|
|
||
| const NO_CARD_PLACEHOLDER = "000000"; | ||
|
|
||
| const Inscription = ({card_id}: InscriptionInterface) => { | ||
| const { getApiUrl, getHeaders } = useApi(); | ||
|
|
@@ -82,13 +83,22 @@ const Inscription = ({card_id}: InscriptionInterface) => { | |
| return; | ||
| } | ||
|
|
||
| setFormError("L'inscription a echoue. Veuillez reessayer."); | ||
| if (error instanceof Error && error.message) { | ||
| setFormError(error.message); | ||
| } else { | ||
| setFormError("L'inscription a echoue. Veuillez reessayer."); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| return ( | ||
| <div className="inscription_container"> | ||
| <h2>Formulaire d'Inscription</h2> | ||
| {card_id === NO_CARD_PLACEHOLDER && ( | ||
| <p className="inscription_info"> | ||
| Aucun scan de carte detecte. Un identifiant provisoire sera utilise jusqu'a l'association d'une carte. | ||
| </p> | ||
|
Comment on lines
+98
to
+100
|
||
| )} | ||
| <form className="inscription_form" onSubmit={handleSubmit}> | ||
| <FormText | ||
| label="Prénom" | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
L’association de carte via
scanned_card_idrepose survalidate_card_context(latest_card, scanned_card_id)oùlatest_cardest un état global partagé. En environnement multi-clients, un scan récent d’un autre utilisateur peut permettre une association erronée (condition de course). Pour fiabiliser, stocker le contexte de scan par client/session (token côté frontend, binding à socket id, ou autre mécanisme) plutôt qu’un uniquelatest_cardglobal.