This commit is contained in:
2026-09-29 14:26:17 +02:00
parent 88a7c2eba0
commit 06fe43bba3
24 changed files with 985 additions and 174 deletions

View File

@@ -7,8 +7,8 @@
| | |
|---|---|
| **Fait** | Structure dépôt perso, sujet FR, paquet rendu, **projet Flutter** (`swifty_companion/`) |
| **Pas commencé** | OAuth Intra, les 2 vues, appels API 42 |
| **Prochaine action** | **Étape 2** — [OAuth2 Intra + token unique](etape-02-oauth-intra.md) |
| **Fait** | OAuth + token + `/v2/me` (login connecté) |
| **Prochaine action** | **Étape 4** — [vue profil complète](etape-04-vue-profil.md) |
## Arborescence actuelle
@@ -45,9 +45,9 @@ swifty_companion/ ← dépôt Git de TRAVAIL (perso)
|-------|---------|--------|
| **0** | Structure, traduction sujet, séparation travail / école, README rendu | ✅ **Terminé** |
| **1** | Projet Flutter `swiftyCompanion/swifty_companion/` | ✅ **Terminé** |
| **2** | App OAuth sur l’Intra + flux OAuth2 + token unique réutilisé | ⏳ **En cours — prochaine** |
| **3** | Vue 1 : recherche login + erreurs (introuvable, réseau) | ⏳ |
| **4** | Vue 2 : profil (≥ 4 champs + photo), skills, projets (dont failed) | ⏳ |
| **2** | OAuth2 (`IntraAuthService`, `/v2/me`) | ✅ **Validé** (`fgras-ca`) |
| **3** | Vue 1 : `SearchScreen` + `IntraUserService` + navigation profil | ✅ **Codé** — à tester sur téléphone |
| **4** | Vue 2 : profil complet (≥ 4 champs, skills, projets) | ⏳ **Prochaine** |
| **5** | Retour vue 1 + layout adaptatif | ⏳ |
| **6** | Passage checklist [swiftyCompanion/README.md](../../swiftyCompanion/README.md) | ⏳ |
| **7** | Bonus : refresh token à expiration | ⏳ |

View File

@@ -19,8 +19,9 @@ Base via la [piscine mobile](../../../piscine_mobile/README.md) sur le même dis
|-------|----------|--------|
| **0** | Dépôt travail + `docs/`, sujet FR, paquet `swiftyCompanion/` (README / `.gitignore` / `.env.example`) | ✅ **Fait** — détail dans [00-reprise-et-etat.md](00-reprise-et-etat.md) |
| **1** | Projet `swiftyCompanion/swifty_companion/` + `flutter run` | ✅ **Fait** |
| **2** | OAuth2 Intra : login, stockage token, **un token pour toutes les requêtes** | ⏳ **Prochaine** → [etape-02-oauth-intra.md](etape-02-oauth-intra.md) |
| **3** | **Vue 1** : recherche par login + erreurs (404, réseau) | ⏳ → [etape-03-vue-recherche.md](etape-03-vue-recherche.md) |
| **2** | OAuth2 Intra : token + `/v2/me` | ✅ Fait |
| **3** | **Vue 1** : recherche par login + erreurs | ✅ Codé → tester · [etape-03-vue-recherche.md](etape-03-vue-recherche.md) |
| **4** | Vue 2 : profil complet | ⏳ **Prochaine** → [etape-04-vue-profil.md](etape-04-vue-profil.md) |
| **4** | **Vue 2** : profil (≥ 4 champs + image), skills, projets (validés + failed) | ⏳ |
| **5** | Navigation retour + layout responsive | ⏳ |
| **6** | Tests manuels + checklist peer-eval | ⏳ |
@@ -38,7 +39,8 @@ README correcteurs (dépôt école) : [swiftyCompanion/README.md](../../swiftyCo
|---------|--------|
| [00-reprise-et-etat.md](00-reprise-et-etat.md) | ✅ À jour |
| [etape-02-oauth-intra.md](etape-02-oauth-intra.md) | ✅ Guide étape 2 |
| [etape-03-vue-recherche.md](etape-03-vue-recherche.md) | 🔜 après OAuth |
| [etape-03-vue-recherche.md](etape-03-vue-recherche.md) | ✅ Guide étape 3 |
| [etape-04-vue-profil.md](etape-04-vue-profil.md) | 🔜 après étape 3 |
| `etape-04-vue-profil.md` | 🔜 |
| `etape-05-navigation-layout.md` | 🔜 |
| `etape-06-bonus-token.md` | 🔜 |

View File

@@ -1,12 +1,107 @@
# Étape 3 — Vue 1 (recherche par login)
# Étape 3 — Vue 1 : recherche par login
> **Prérequis :** [étape 2 — OAuth Intra](etape-02-oauth-intra.md) terminée (token disponible).
> **Prérequis :** étape 2 OK — OAuth actif, token unique (`IntraAuthService`).
## Objectif
## Objectif sujet
- **Première vue** : saisie d’un **login** 42 + bouton rechercher.
- Appel API avec le **token OAuth** déjà obtenu.
- Gestion des erreurs : **utilisateur introuvable**, **réseau**, token invalide / non connecté.
- Navigation vers la **vue 2** si le login existe.
| Exigence | Cette étape |
|----------|-------------|
| Au moins 2 vues | **Vue 1** : recherche · **Vue 2** : profil (étape 4) |
| Erreurs gérées | Login introuvable, réseau, non connecté |
| Token unique | Réutiliser `IntraAuthService.instance` (ne pas refaire OAuth) |
Guide détaillé à compléter quand l’étape 2 est OK — demande l’implémentation pas à pas dans le chat.
---
## Parcours utilisateur (vue 1)
1. L’utilisateur est déjà connecté à l’API (étape 2) — ou bouton « Se connecter » si token absent.
2. **Champ texte** + bouton **Rechercher** (login 42, ex. `jdoe`).
3. Appel API avec `Authorization: Bearer <token>`.
4. **Succès** → navigation vers **vue 2** (profil).
5. **Échec** → message clair, pas de crash.
---
## API 42 utile
Doc : [api.intra.42.fr/apidoc](https://api.intra.42.fr/apidoc)
| Action | Requête typique |
|--------|-----------------|
| Utilisateur par login | `GET /v2/users/{login}` ou `GET /v2/users?filter[login]=<login>` |
| Toi (déjà fait) | `GET /v2/me` |
Vérifier dans l’apidoc la forme exacte supportée ; beaucoup de projets utilisent :
```http
GET https://api.intra.42.fr/v2/users?filter[login]=jdoe
Authorization: Bearer <access_token>
```
Réponse : tableau JSON ; **vide** = login inconnu.
---
## Fichiers à ajouter (étape 3)
```
lib/
├── services/
│ ├── intra_auth_service.dart # existant
│ └── intra_user_service.dart # GET user(s) avec token
├── screens/
│ ├── auth_screen.dart # option : fusionner ou garder login au démarrage
│ ├── search_screen.dart # VUE 1
│ └── profile_screen.dart # VUE 2 (squelette → étape 4)
└── main.dart # home → SearchScreen si token OK
```
---
## `IntraUserService` (idée)
- Méthode `Future<Map<String, dynamic>> fetchUserByLogin(String login)`.
- Utilise `IntraAuthService.instance.authHeaders()`.
- **404 / liste vide** → exception métier `UserNotFoundException`.
- **Socket / timeout** → `NetworkException`.
- **401** → token expiré → message « reconnecte-toi ».
---
## Gestion des erreurs (sujet)
| Situation | Message utilisateur (exemple) |
|-----------|-------------------------------|
| Login inconnu | `Aucun utilisateur pour ce login` |
| Pas de réseau | `Connexion impossible. Vérifie le réseau.` |
| Non connecté OAuth | `Connecte-toi d’abord à l’API 42` |
| Champ vide | `Saisis un login` |
---
## Navigation
```text
SearchScreen --[login trouvé]--> ProfileScreen(login)
ProfileScreen --[retour]--> SearchScreen
```
`Navigator.push` / `pop` ou `go_router` — rester simple (Navigator 1.0 suffit).
---
## Critères « étape 3 terminée »
| # | Test |
|---|------|
| 1 | Login valide (ex. `fgras-ca`) → ouvre vue 2 |
| 2 | Login `zzzzzzzz` → message erreur |
| 3 | Mode avion → message réseau |
| 4 | Retour depuis vue 2 → nouvelle recherche possible |
| 5 | Un seul OAuth ; les recherches réutilisent le même token |
---
## Ensuite — étape 4
→ [etape-04-vue-profil.md](etape-04-vue-profil.md) : photo, ≥ 4 champs, skills, projets (dont failed), layout adaptatif.

View File

@@ -0,0 +1,21 @@
# Étape 4 — Vue 2 : profil complet
> **Prérequis :** [étape 3 — recherche](etape-03-vue-recherche.md) (navigation vers vue 2 avec login valide).
## Objectif sujet (partie obligatoire)
| Exigence | Détail |
|----------|--------|
| ≥ 4 infos | login, email, mobile, level, location, wallet, evaluations, … |
| Photo | Image de profil (`image_url` / `image.link` selon API) |
| Skills | Niveau + pourcentage |
| Projets | Terminés **y compris failed** |
| Retour | Bouton retour vers vue 1 |
| Layout | Responsive (étape 5 peut affiner) |
## API
- `GET /v2/users/{id}` avec champs / includes selon apidoc (`cursus_users`, `projects_users`, `skills`, etc.).
- Token : toujours via `IntraAuthService`.
Guide détaillé à rédiger quand l’étape 3 est codée — demande l’implémentation pas à pas dans le chat.

View File

@@ -15,22 +15,20 @@
## URI de redirection
**Une seule ligne**, sans guillemets :
**Téléphone physique (recommandé Swifty)** — une ligne :
```text
com.example.swiftycompanion://callback
```
(Sans `_` dans le schéma — souvent accepté par l’Intra ; sinon voir [oauth-test-manuel.md](oauth-test-manuel.md).)
**Émulateur seulement** (optionnel) :
```text
http://localhost:8080/callback
```
Si le formulaire affiche encore *invalid format*, tester **une** de ces lignes (toujours une seule) :
```text
http://localhost:3000/callback
```
```text
http://127.0.0.1:8080/callback
```
**À ne pas mettre :**
- `com.example.swifty_companion://callback`

View File

@@ -0,0 +1,78 @@
# OAuth 42 — tests manuels des URLs
## Pourquoi pas `http://localhost` sur téléphone ?
| Environnement | `http://localhost:8080/callback` |
|---------------|----------------------------------|
| Émulateur Android | Parfois OK (localhost = l’émulateur) |
| **Téléphone physique** | ❌ « Site inaccessible » — localhost = le téléphone, pas ton PC |
**Swifty Companion (mobile réel)** : utiliser un **schéma d’app** :
```text
com.example.swiftycompanion://callback
```
À enregistrer sur l’Intra **et** dans `.env` (`REDIRECT_URI`).
---
## Endpoints 42 (référence sujet)
| Rôle | URL |
|------|-----|
| Autorisation | `https://api.intra.42.fr/oauth/authorize` |
| Token | `https://api.intra.42.fr/oauth/token` |
| API (ex. moi) | `https://api.intra.42.fr/v2/me` |
Doc : [api.intra.42.fr/apidoc](https://api.intra.42.fr/apidoc)
---
## 1. Tester l’API (sans app)
Dans un navigateur (connecté à l’Intra ou non pour cette étape) :
```text
https://api.intra.42.fr/
```
Réponse JSON attendue (message API) → l’API est joignable.
---
## 2. Tester la page d’autorisation (navigateur)
Remplace `TON_CLIENT_ID` par l’**UID** de ton app OAuth.
**Redirect actuel (mobile)** :
```text
https://api.intra.42.fr/oauth/authorize?client_id=TON_CLIENT_ID&redirect_uri=com.example.swiftycompanion%3A%2F%2Fcallback&response_type=code&scope=public
```
| Résultat | Signification |
|----------|----------------|
| Page login / autorisation 42 | ✅ URL d’auth OK |
| Erreur `redirect_uri` | ❌ URI pas enregistrée sur l’Intra ou différente de `.env` |
| Erreur `invalid_client` | ❌ `client_id` incorrect |
Après validation, le navigateur tente d’ouvrir `com.example.swiftycompanion://callback?code=...` → sur PC ça échoue (normal) ; **sur le téléphone avec l’app installée**, l’app doit s’ouvrir.
---
## 3. Alignement obligatoire (3 endroits identiques)
1. [Application OAuth Intra](https://profile.intra.42.fr/oauth/applications) → **URI de redirection**
2. `swifty_companion/.env` → `REDIRECT_URI=...`
3. Code Flutter → même valeur via `IntraConfig.redirectUri`
---
## 4. Ancien redirect (à retirer sur l’Intra si présent)
```text
http://localhost:8080/callback
```
Remplacer par `com.example.swiftycompanion://callback` (une ligne dans le formulaire).