Evaluation TW3 2024
Vous avez la possibilité de rattraper ce devoir à la maison.
- Selectionner un ou plusieurs exercices que vous n’avez pas réussi à faire (vous pouvez refaire tout le devoir si vous le souhaitez)
- Faire passer les tests au vert
- Commentez chaque ligne ajoutée en expliquant ce que vous avez fait
- Les points rattrapés ainsi compteront pour moitié de leur valeur initiale
Exemple : Si vous aviez une note initiale de 8/20, et que votre rattrapage vous augmente la note de 5 points (en faisant passer à 13), votre note finale sera 8 + (5 / 2) = 10.5
Pour récupérer son travail
git clone https://sources.univ-jfc.fr/techno-web-3/eval-2024.git
cd eval-2024
git fetch
- Cherchez le nom de votre branche dans la liste des branches du repo
git checkout <nom_de_votre_branche>
(exemple :git checkout jgirod
)
Pour sauvegarder votre travail
git add -A *
git commit -m "Rattrapage"
git push origin <nom_de_votre_branche>
Dans ce TP, vous aurez à réaliser un site web qui répertorie les concerts et soirées dans les grandes villes de France, et qui permet d’acheter des billets pour ces événements.
Vous devrez réaliser les fonctionnalités suivantes :
- Affichage de la liste des événements
- Afficher les billets achetés par un utilisateur depuis la base de donnée
- Formulaire pour acheter un billet
Information et consignes générales
Important : lisez attentivement cette section avant de commencer le TP
- Vous pouvez utiliser les corrigés des TPs précédents
- Vous pouvez utiliser internet librement
- Vous ne pouvez pas communiquer entre vous
- Vous ne pouvez pas utiliser des agents conversationnels (ex: chatGPT, copilot, etc)
- Vous pouvez solliciter l’enseignant pour toute question relative à la compréhension de l’énoncé, ou de lancement de l’application (base de données, container, etc), ou si vous pensez avoir trouvé une erreur/bug dans l’énoncé ou les tests.
- Lisez les énoncés des exercices jusqu’au bout avant de commencer à coder, des informations importantes peuvent être données à la fin.
- Les exercices sont complètement indépendants. En cas de blocage, ou de difficultés, passez à l’exercice suivant.
- Le TP est sur 21 points (un point bonus). La note est calculée automatiquement avec les tests. Je regarderai le code si la note est inférieure à 10.
Le conseil bonus :
- Faites bien attention aux erreurs liées à l’oublie de
await
devant les fonctions asynchrones.
Installation et test
- Cloner le dépôt git suivant :
git clone https://sources.univ-jfc.fr/techno-web-3/eval-2024.git
- Installer les dépendances :
npm install
- Initialiser la base de donnée :
npm run db:init
- Lancez les tests :
npm test
- Lancez le serveur :
npm start
Si une de ces étapes ne fonctionne pas, merci de le signaler à l’enseignant.
Checkpoint
Lancer la commande suivante
npm run checkpoint
Vous pourrez sauvegarder votre travail (et votre note actuelle) à tout moment grâce à cette commande. N’hésitez pas la à lancer régulièrement au fur et à mesure de vos progrès.
Si vous rencontrez un problème, vous pourrez revenir au dernier checkpoint en l’utilisant.
Rendu du TP
npm run checkpoint
git branch <identifiant_etudiant> # exemple : git branch jgirod
git push origin <identifiant_etudiant> # exemple : git push origin jgirod
Exercice 1 - 4 points
Pour lancer uniquement les tests de cet exercice : npm test -- exercice-1
- Creer une route
/ping
qui retourne un statut 200 - Servir la vue
home
sur la route/
. Bonus : créer un controller dédiégetHomePage
dans le fichiercontrollers.ts
- Monter le dossier
public
sur la route/assets
, de tel sorte que le fichierpublic/concert.jpg
soit accessible à l’url/assets/concert.jpg
Exercice 2 - 10 points
Pour lancer uniquement les tests de cet exercice : npm test -- exercice-2
Partie 1 - 7 points
Créer une page /evenements
qui liste l’ensemble des évenements. Vous utiliserez la fonction getAllEvenements
pour récupérer la liste des événements (elle est déjà implémentée dans models/evenements.ts
).
Le type de retour de la fonction getAllEvenements
est Promise<Array<Evenement>>
, vous pouvez consulter le fichier models/evenements.ts
pour voir la structure de l’objet Evenement
.
Consignes
- Le
<title>
de la page doit êtreConcerts et soirées
- La page doit afficher comme titre
<h2>
:Découvrez nos événements
- La page doit afficher la liste des événements sous forme de carte (voir proposition de HTML plus bas), contenant le titre, la description, la ville, la date, et l’image de l’événement.
- Chaque événement doit avoir un lien pour acheter un billet. Ce lien doit rediriger vers la page
/evenements/<id>/acheter-billet
(où<id>
est l’id de l’événement). Par exemple pour l’événement d’id 12, le lien doit rediriger vers/evenements/12/acheter-billet/
- La page doit être servie via un controller dédié
getEvenementsPage
dans le fichiercontrollers.ts
- Pour formater la date en français avec handlebar, vous pouvez utiliser le helper
formatDate
. Par exemple, si le nom de la propriété estmaDate
, vous pouvez la formater directement dans la vue en utilisant{{ formatDate maDate }}
Proposition de HTML pour la page /evenement
:
<div class="container mx-auto px-6 py-12">
<h2 class="mb-8 text-center text-4xl font-bold">
<!-- Titre h2 -->
</h2>
<div class="grid grid-cols-1 gap-8 md:grid-cols-2 lg:grid-cols-3">
<!-- Liste des évènements ici -->
</div>
</div>
Proposition de HTML pour un évènement (à transformer en template handlebar) :
<div class="flex h-full flex-col overflow-hidden rounded-xl bg-white text-purple-900 shadow-xl">
<img src="" class="h-48 w-full object-cover" />
<!-- Modifier la src de l'image ci-dessus -->
<div class="flex flex-grow flex-col p-6">
<h3 class="mb-2 text-xl font-semibold">
<!-- Titre de l'évènement ici -->
</h3>
<p class="mb-4 flex-grow text-gray-600">
<!-- Description de l'évènement ici -->
</p>
<div class="mt-auto">
<div class="mb-4 flex items-center justify-between">
<span class="flex items-center">
<i data-lucide="map-pin" class="mr-1 h-4 w-4"></i>
<!-- Nom de la ville ici -->
</span>
<span class="flex items-center">
<i data-lucide="calendar" class="mr-1 h-4 w-4"></i>
<!-- Date de l'évènement ici -->
</span>
</div>
<div class="flex-end flex items-center">
<a
class="flex items-center rounded-full bg-gradient-to-r from-purple-700 to-pink-600 px-4 py-2 font-semibold text-white transition-colors duration-300 hover:from-purple-600 hover:to-pink-500"
href=""
>
<!-- Modifier le href ci-dessus -->
<i data-lucide="ticket" class="mr-2 h-4 w-4"></i>
Acheter une place
</a>
</div>
</div>
</div>
</div>
Partie 2 - 3 points
N’hésitez pas à passer à l’exercice suivant si vous avez des difficultés avec cette partie
Ajouter un filtre de ville pour la page /evenements
.
En ajoutant une query string ville
à la route /evenements
, la page doit afficher uniquement les événements de la ville correspondante. Par exemple, si l’url est /evenements?ville=Paris
, la page doit afficher uniquement les événements qui ont pour ville de Paris.
Le titre title
de la page doit être Concerts et soirées à Paris
si la query string ville
est égale à Paris
.
Le titre h2
de la page doit être Découvrez nos événements à Paris
si la query string ville
est égale à Paris
.
Vous pourrez utiliser la fonction getEvenementsByVille
dans models/evenements.ts
pour récupérer les événements par ville.
Exercice 3 - 6 points
Pour lancer uniquement les tests de cet exercice : npm test -- exercice-3
Nous allons maintenant ajouter la possibilité d’acheter des billets pour les événements.
La base de donnée contient une table billets
qui contient les champs suivants :
id
: l’identifiant du billetnom
: le nom de la personne qui a acheté le billetprenom
: le prénom de la personne qui a acheté le billetevenementId
: l’identifiant de l’événement pour lequel le billet a été acheté
La connection à la base de donnée peut être configurée avec les options suivantes :
const db = await mysql.createConnection({
host: '127.0.0.1',
user: 'root',
password: 'secret',
database: 'feelvibe'
});
Partie 1 - 3 points
Créer une page /billets
qui affiche tous les les billets achetés.
Consignes :
- Créer un type
Billet
dansmodels/billets.ts
qui correspond à la structure d’un billet. - Créer une fonction de modèle
getBillets
qui va chercher dans la base de donnée les billets achetés par un utilisateur. - Créer une vue et un controller pour la page
/billets
. - La page doit afficher le prénom et le nom de l’utilisateur pour chaque billet.
- La page doit afficher le titre de l’événement pour chaque billet.
Astuce
Pour bien typer le retour de la fonction execute
, vous pouvez utiliser la syntaxe suivante :
import { RowDataPacket } from 'mysql2';
// ...
const result = await db.execute<Array<RowDataPacket & Billet>>(...)
Cela évitera d’avoir les erreurs de type comme au TP précédent.
Proposition de HTML pour la page
<main class="flex-grow">
<div class="container mx-auto px-6 py-12">
<h2 class="mb-8 text-center text-4xl font-bold">Mes billets</h2>
<div class="grid grid-cols-1 gap-8 md:grid-cols-2 lg:grid-cols-3">
<!-- Liste des billets ici -->
</div>
</div>
</main>
Proposition de HTML pour un billet (à transformer en template handlebar)
<div class="flex h-full flex-col overflow-hidden rounded-xl bg-white text-purple-900 shadow-xl">
<div class="flex flex-grow flex-col p-6">
<h3 class="mb-2 text-xl font-semibold">
<!-- Titre de l'évènement ici -->
</h3>
<p class="mb-4 flex-grow text-gray-600">
Billet au nom de
<span class="font-semibold">
<!-- Nom et prénom de l'utilisateur ici -->
</span>
</p>
</div>
</div>
Partie 2 - 3 points
Créer une page /evenements/<id>/acheter-billet
qui permet d’acheter un billet pour un événement.
Consignes :
Créer une route, une vue et un controller pour la page
/evenements/<id>/acheter-billet
qui contient le formulaire pour acheter un billet.Le formulaire doit contenir les champs
nom
etprenom
.La page doit afficher le titre de l’événement pour lequel on achète un billet.
Créer une fonction de modèle
acheterBillet
qui va ajouter un billet dans la base de donnée.Rediriger l’utilisateur vers la page
/billets
après qu’il ait soumis le formulaire avec la methodres.redirect('/billets')
.Astuce Pour récupérer l’id de l’événement depuis la route, vous pouvez utiliser
req.params.id
dans le controller.
app.get('/evenements/:id/acheter-billet', (req, res) => {
const id = req.params.id; // vaut 12 si l'url est /evenements/12/acheter-billet
});
Astuce Vous pouvez utiliser la fonction getEvenementById
dans models/evenements.ts
pour récupérer l’événement par son id. Vous pouvez utiliser Number.parseInt
pour convertir l’id en nombre.
Astuce Pour bien typer le retour de la fonction execute
, vous pouvez utiliser la syntaxe suivante :
import { ResultSetHeader } from 'mysql2';
// ...
const result = await db.execute<ResultSetHeader>(...);
Cela évitera d’avoir les erreurs de type comme au TP précédent.
Proposition de HTML pour le formulaire
<main class="flex-grow">
<div class="container mx-auto px-6 py-12">
<div class="mx-auto max-w-2xl overflow-hidden rounded-xl bg-white text-purple-900 shadow-2xl">
<div class="p-8">
<h2 class="mb-6 text-3xl font-bold">
<!-- titre de l'évènement -->
</h2>
<form id="ticket-form" class="space-y-6" method="POST">
<div>
<label for="nom" class="mb-1 block text-sm font-medium text-gray-700">Nom</label>
<input
type="text"
id="nom"
name="nom"
required
class="w-full rounded-md border border-gray-300 px-3 py-2 shadow-sm focus:border-purple-500 focus:outline-none focus:ring-2 focus:ring-purple-500"
/>
</div>
<div>
<label for="prenom" class="mb-1 block text-sm font-medium text-gray-700">Prénom</label>
<input
type="text"
id="prenom"
name="prenom"
required
class="w-full rounded-md border border-gray-300 px-3 py-2 shadow-sm focus:border-purple-500 focus:outline-none focus:ring-2 focus:ring-purple-500"
/>
</div>
<div>
<button
type="submit"
class="flex w-full items-center justify-center rounded-full bg-gradient-to-r from-purple-700 to-pink-600 px-6 py-3 font-semibold text-white transition-colors duration-300 hover:from-purple-600 hover:to-pink-500"
>
<i data-lucide="ticket" class="mr-2 h-5 w-5"></i>
Acheter le billet
</button>
</div>
</form>
</div>
</div>
</div>
</main>