Transcript for:
Développement d'une application NestJS en partant de zéro

dans cette formation tu vas découvrir comment je développe une application nest JS en partant de zéro nous allons mettre en place un petit serveur API en tapscript un projet idéal pour comprendre les bases du framework nest JS cette API va communiquer avec un petit front-end en react avec le framework remix c'est exactement la même stack que j'ai utilisé pour développer le projet good collect sur lequel je travaille en entreprise depuis presque 2 ans j'ai fait plein d'erreurs en le mettant en place et je vais toutes te les partager dans cette vidéo je te propose de développer à mes côtés une application de messagerie assez basique le principe est que tu apprennes à tout mettre en place toi-même de manière autonome nous allons utiliser des services externes pour implémenter les fonctionnalités les plus compliquées comme le paiement l'hébergement de fichiers l'envoi d'email et le temps réel bien sûr on ne va pas s'arrêter au développement de l'application j'aimerais également que tu apprennes à le pousser en environnement de production pour cela nous allons découvrir ensemble les technologies nécessaires pour y parvenir nous utiliserons notamment docker les git actions et CAD serverur nous allons aussi configurer un serveur distant directement depuis notre terminal c'est sur ce serveur que le code source de notre projet sera exécuté tu trouveras tous les chapitres dans la description si tu veux accéder à une partie spécifique donc qu'est-ce que nestgs et ben nestjs c'est un framework de node ça va nous permettre d'écrire de la logique serveur comme contacter la base de données envoyer des mails en utilisant JavaScript je t'entends déjà me demander pourquoi utiliser N JS et pas tout simplement Express c'est un choix personnel quand j'ai commencé le développement j'y comprenais rien au backend et je me suis dit ça serait cool de trouver un projet avec du code bien écrit bien structuré pour que j'aiie pas à réfléchir à l'architecture à la structure et aux bonnes pratiques il nous propose une structure de code bien définie que tu dois respecter en plus il utilise typesript il utilise le concept d'injection de dépendance c'est-à-dire que tu vas bien séparer toute la logique de ton code dans différents fichiers par exemple les envois de mail seront dans un fichier lié au ma tout ce qui est li est à l'authentification sera dans le même fichier tout ce qui gère les utilisateurs sera dans un autre fichier ça m'a beaucoup plu donc là je suis sur le site nestgs.com et je vais tout de suite aller dans la documentation pour générer un nouveau projet j'ai le terminal d'ouvert à côté on va d'abord installer en global l'outil de commande qui va nous permettre de générer tous nos projets nestgs je vais lancer la première ligne dans mon terminal pour l'installer maintenant que c'est installé on peut tout de suite lancer la deuxième commande nest new et le nom de notre projet nous notre projet on va l'appeler nestjs chat j'appuie sur Entrer et là il nous demande de choisir entre NPM yarn et pnpm je vais choisir NPM ça sera beaucoup plus simple pour le déploiement de l'application et pour l'utiliser dans docker on peut voir dans le terminal que nesgs nous a créé plein de fichiers notamment es lint prtiier un RMI la configuration de son outil CLI et même le TS config du coup dans ce projet tu as déjà configuré es lint prtier et typescript maintenant on va entrer dans le Directory qu'on a créé et on va l'ouvrir dans vs code et tu vas comprendre que dans SGS chaque fichier a un rôle particulier si on navigue dans le SRC on peut voir que nous avons trois types de fichiers les contrôleurs les modules et les services et nous allons commencer par analyser le fichier service le fichier service c'est là où tu codes toute la logique de ton application si tu fais des modifications en base de données si s'appelle Prisma tout ce code sera écrit dans les services là nous avons un petit exemple dans service nous avons une classe nommée app service qui contient une méthode fortement typée qui return et le World et nous avons aussi le décorateur injectable que nous verrons juste après rassure-toi quand tu vas développer en SJS tu ne seras pas obligé de fortement typer tes méthodes là on peut voir que Hello World a été fortement typé si je décide de Return un number par exemple typesript va me dire excuse-moi c'est pas possible tu vas fortement typer ton l'application moi ce que je préfère c'est écrire aucun type mais laisser l'inférence des fonctions opéré donc là je vais retirer le typage fort et maintenant si je passe ma sourie sur la méthode on peut voir que le type de la méthode est soit de soit hello world ce qui n'est évidemment pas sitable donc ve que ça soit par exemple de et le type est directement inféré à ce niveau-là donc pour mieux comprendre ce qui est un service parce que je trouve que cet exemple n'est pas très parlant on va créer une méthode qui s'appelle get users et qui va renvoyer un tableau d'utilisateur avec une ID et un prénom maintenant le principe d'avoir mis ce code dans une fonction c'est de pouvoir appeler cette méthode c'est là qu're en jeu le deuxième type de fichier qui sera le contrôleur alors qu'est-ce qu'un contrôleur encore une fois le contrôleur il a un décorateur spécial que nest JS lui donne de type controllleur et c'est également une classe de app controll on peut voir qu'il y a un constructeur donc une fonction qui va se déclencher quand une nouvelle instance d'AP controller sera créée qui prend en paramètre notre fameux app service je sais il y a beaucoup d'infos mais t'inquiète tu vas comprendre ce qui nous intéresse c'est de récupérer nos utilisateurs côté front alors comment est-ce qu'on peut faire si tu utilisais Express tu aurais fait un appget avec le nom de ta méthode et tu aurais passé une fonction où tu aurais renvoyer ton tableau d'utilisateur ici Nass nous permet de faire exactement la même chose avec ce décorateur get on a donc un décorateur get qui pour le moment n'a pas de chemin c'est-à-dire que ça équivaut à local host 3000 et il suffit qu'on passe le nom de notre route par exemple users pour pouvoir accéder à notre donnée à localhost 3000/users je vais renommer cette méthode qu'on ne va jamais utiliser j'enlève le type fort et je vais utiliser la méthode du fichier app service que j'ai créé qui s'appelle get users là maintenant on peut voir si je passe ma souris au-dessus que le type est totalement inféré donc on a une ID de number et un FirstName qui est un string et c'est sous forme de tableau on va tout de suite vérifier que ça fonctionne bien et pour ça on va regarder quelles sont les commandes pour lancer l'environnement de développement si je vais dans le fichier package.gison je peux voir qu'il y a vraiment beaucoup de commandes ça peut nous décourager nous ce qui nous intéresse c'est de lancer le Start dou dev que je vais renommer juste en dev parce que j'adore faire un NPM run dev et là on va voir notre outil de terminal qui affiche plein d'informations notamment que le fichier app controller a été instancié que les dépendances du fichier app module ont été initialisées et qu' a créer une route qui s'appelle slash users qui est une route de type get toutes les infos qu'on a faites jusqu'à présent ont été détectées maintenant je vais utiliser l'extion postman pour accéder à ma route je vais créer une nouvelle requête HTTP qui va appeler localhost 3000/users que je vais sauvegarder j'ai ma requête je l'envoie et on peut voir que ça m'a tout de suite renvoyé la donnée que j'ai hardcodé sous forme de jison donc ça fonctionne maintenant comment ça marche et ben nous avons un troisème type de fichier qui s'appelle app module et c'est là que la magie opère donc on retrouve toujours cette même syntaxe un décorateur cette fois nommé module et un export de classe du nom de app module et notre fichier de module importe le contrôleur que nous avons vu et le service que nous avons vu avec cette syntaxe assez particulière alors pourquoi a-t-on besoin de faire ça ce contrôleur est sans effet s'il n'est pas importé dans notre module là on va le retirer on va commenter l'import j'enregistre et on peut voir que le terminal va relancer le projet si je retourne maintenant sur postman et que j'exécute ma requête on peut voir que la méthode n'existe plus on a un message d'erreur qui dit la route get/ users n'existe pas elle n'a pas été trouvée status code 404 pourtant elle est déclarée dans notre fichier app controller mais ce contrôleur n'a pas été initialisé parce qu'il n'a pas été appelé dans le module je le rappelle maintenant ça recompile le projet et ça nous dit que la méthode est de nouveau disponible on peut tester sur postman j'envoie une requête et j'ai de nouveau ma donnée donc tout est lié au fichier module si tu veux que les routes de ton contrôleur soient initialiser tu vas forcément devoir l'importer dans un fichier de type module maintenant le fichier de type module utilise également le service et c'est là que ça se complique un petit peu on va faire le même exemple on va supprimer le service des imports et on va voir ce que le terminal nous affiche là il y a un gros message d'erreur qui dit que nest ne peut pas résoudre les dépendances de app controller s'il te plaît assure-toi d'avoir mis l'app service dans l'index Z0 du fichier app. module et c'est génial nestgs a détecté qu'on utilise un fichier de type contrôleur le fichier de type contrôle a besoin du app service parce qu'il utilise la méthode GET user qui est contenu dans ce fichier mais le fichier app service n'a pas été importé dans le module du coup il nous donne des axes de débugage il nous dit est-ce que le fichier module est un module valide donc oui c'est un module valide si app service est un provider est-ce qu'il fait partie de app module alors app service est un provider c'est-à-dire qu'il nous permet de récupérer des données donc on va dire qu'il provide on l'utilise dans le contrôleur donc c'est un provider on va donc le réimporter pour pouvoir réutiliser notre contrôleur maintenant il faut savoir que si dans notre contrôleur on avait pas besoin d'utiliser notre service on aurait pas eu ce message d'erreur on aurait pu retirer le service de notre fichier app module mais là il tout le principe de nestgs pour pas avoir des fichiers trop gros avec des milliers de lignes de code tu sépares toute la logique de ton application en service tu exécutes ces méthodes dans des contrôleurs et tu importes les services et les contrôleurs dans des modules maintenant on va continuer de regarder l'architecture de notre fichier par parce que ce n'est pas fini ce module il est forcément utilisé quelque part sinon il ne fonctionnerait pas il est utilisé dans le point d'entrée de notre application le point d'entrée de notre application c'est le fichier à partir duquel toute notre application est exécutée et c'est le fichier main points et là ça doit te rappeler quelque chose ça ressemble énormément à Express parce que nestjs utilise Express on exécute une fonction bootstrap et la fonction bootstrap exploite la nest Factory nest Factory nous permet de créer une instance d'application à partir d'un module et là retrouve notre a point module en deème ligne on voit qu'on écoute le port 3000 si tu veux changer ton port c'est ici que tu mettras par exemple process.on. pte ou P 3000 on va faire un petit résumé parce que c'est beaucoup d'infos en même temps comme tout projet JavaScript il démarre dans le fichier MAIN.S le fichier MAIN.S déclare une fonction qui va ensuite être appelée cette fonction va instancier notre application en partant du point d'entrée app module et ensuite il va écouter le port 3000 notre application va contenir tout ce qui est importé dans le fichier fichier app module qu'est-ce qu'il y a pour le moment d'importer dans notre fichier app module pour le moment on a donc notre contrôleur qui dispose d'une seule route qui récupère une liste d'utilisateur on utilise l'injection de dépendance pour pouvoir utiliser les méthodes du service à aucun moment tu vas pouvoir faire ça import get users from le service tu ne peux pas écrire cette syntaxe avec nestgs tu es obligé d'exploiter l'injection de dépendance le module utilise donc aussi ce service qui est utilisé par le contrôleur qui exploite de méthodes mais celle-ci on va la supprimer parce qu'elle ne sert pas c'est la méthode GET users donc au début l'architecture est plutôt lisible nous avons un contrôleur et un service et le app module nous permet de générer notre application c'est-à-dire que pour une application à grande échelle avec plein d'entités toutes ces entités seront importées dans le fichier app module par exemple quand on va implémenter l'authentification on va ajouter un module haute module ensuite si on veut créer des comptes utilisateurs on va créer un user module si on veut envoyer des emails pourquoi pas créer un module ou pourquoi pas créer un service qui s'appellera Mail Service et cetera un module d'authentification ça sera dans ce module là une fois qu'on aura créé notre module d'authentification c'est lui qui aura ses propres contrôleurs et ses propres services donc en gros le main points créer l'application à partir du fichier app module et app module il importe des fichiers qui a leur tour vont importer des fichiers qui a leur tour vont encore importer des fichiers peut-être et c'est comme ça qu'on a une application entière avec des dizaines des centaines de contrôleurs de de services et que tout fonctionne de manière harmonieuse ce qui est super avec nestjs c'est qu'il nous donne accès à un outil de terminal pour générer des nouveaux fichiers donc nous on va commencer par générer un nouveau module qui va s'appeler user et qui va donc générer la création de compte utilisateur je retourne dans mon projet sur le terminal et je vais lancer la commande nest generate module et je vais l'appeler user on peut voir que ça automatiquement modifier mon fichier app module pour utiliser le module utilisateur que je viens de créer et ici il a créé un nouveau dossier de type user qui contient son propre module nommé user je vais continuer sur cette lancée maintenant j'ai envie de créer mon contrôleur et mon service donc je vais faire nest generate controller user et Nest est assez intelligent pour reconnaître maintenant que le dossier user a déjà été créé pour voir qu'il y a déjà un module de type user du coup il a modifié ce fichier pour y ajouter le contrôleur que je viens de créer il a également créer un fichier de test qu'on ne va pas utiliser donc je vais le supprimer maintenant ce contrôleur va me permettre de déclarer les routes mais j'ai besoin d'utiliser un service le service va également s'appeler user donc je vais faire un nest generate service user et je vais mettre direct ti no t spec pour préciser que je n'ai pas envie qu'il me génère des fichiers de test encore une fois nest fait sa magie c'est-à-dire qu'il a tout de suite Orter le user service à l'intérieur du module si je fais tout ça c'est parce que je trouve que c'est vraiment pas clair d'avoir un contrôleur qui s'appelle app controller on va jamais utiliser un contrôleur qui porte ce nom et j'ai envie de déplacer cette logique dans mon user cont je donc importer cette méthode j'importe le décorateur depuis ngs/ commomon et je vais importer le service tout de suite après mais on va s'attarder sur quelque chose notre décorateur contrôleur principal prend également un paramètre et on peut voir que NGS a mis users ce paramètre permet de définir le préfixe de toutes les routes qui seront contenu dans ce contrôlerur je vais le modifier je vais mettre users au pluriel et si à ce niveau là je mets par exemple settings on peut voir que cette méthode GET sera dispo à/ashusers/settings slash users qui aura été déclaré au-dessus comme contrôleur parent et slashstings qui aura été déclaré dans ce décorateur get maintenant je crée la méthode constructeur qui va permettre d'initialiser notre service qui s'appelle app service et on va fortement le typer app service et de type app service ce contrôleur a également besoin des moustaches et j'ai besoin de spécifier le mot clé private qui signifie qu'on peut pas accéder à ce service depuis le user controller c'est-à-dire que si tu importes la classe user controller quelque part comme ça tu pourras pas accéder au Service ad service on va mettre ça en privé et pour s'empêcher de modifier notre service on rajoute le mot clé readonly qui nous empêche tout simplement de modifier le service par erreur et bon ça c'est quelque chose qu'on ne fait jamais par sécurité je rajoute toujours ces mots clés dans Mes applications si on retourne maintenant sur notre terminal on peut voir qu'il y a plein d'erreurs donc on va débuger ça tout de suite déjà le fichier app controller j'en ai plus besoin donc je vais le supprimer le fichier app service j'en ai plus besoin donc je vais le supprimer mais je vais quand même conserver la méthode GET user maintenant je vais retourner dans la méthode user service et je vais importer la méthode GET user à ce niveau-là je vais dans le user controller pour modifier app service et je vais l'appeler user service pour que ça soit beaucoup plus parlant et enfin on va modifier le fichier app pour module pour supprimer les contrôleurs et les services qui n'existent plus du coup encore une fois on a un premier module qui est utilisé pour créer la base de notre application dans MAIN.S ce premier module il n'importe aucun contrôleur aucun service mais il importe un autre module qui lui importe son son contrôur et son service du coup toutes les routes déclarées dans le user controller sont utilisables au sein de notre application on va quand même vérifier et ouvrir postman pour s'assurer que ça marche toujours je vais lancer la requête et on peut voir que j'ai une erreur cannot get user alors à votre avis on va regarder dans le fichier user controller pourquoi j'ai cette erreur bah c'est très simple j'ai rajouté settings ici je vais le retirer parce que je récupère pas les paramètres des utilisateurs je récupère les utilisateurs directement si je mets rien comme argument ça veut dire que cette méthode sera dispo à localost 3000/users on va retourner sur notre requette et renvoyer une requette pour s'assurer que ça fonctionne et on peut voir que ça fonctionne très bien maintenant qu'on a créé notre contrôleur et notre service pour gérer nos utilisateurs nous allons installer Prisma pour accéder à une base de données je vais donc taper sur Google nestjs Prisma pour connaître les étapes pour utiliser Prisma avec nestjs là c'est un guide total donc il nous explique comment instancier un nouveau projet et ils installent Prisma en tant que dev dependance je retourne dans mon dossier projet et je lance la commande NPM install prisma--dev le save dev permet de l'ajouter en tant que dev dependency c'est-à-dire que dans l'environnement de production on n pas besoin du code source de cette librairie donc il ne sera pas compilé donc maintenant on va utiliser l'outil de commande Prisma avec un NPX de Prisma on va faire donc NPX Prisma ce qui n' servi à rien vu qu'on a pas taper la bonne commande donc en fait il fallait faire NPX Prisma init pour initialiser un nouveau projet je ouvre les dossiers pour vous montrer ce que ça va faire ça créer un dossier Prisma qui contient un schéma de données qui s'appelle schima. schema.prisma on peut voir aussi que Prisma nous donne quelques instructions dans le terminal il nous explique qu'il nous a créé notre schéma qu'on doit rajouter en fichier point en dans le guit signor pour être sûr de ne pas le versionner parce que Prisma il nous a créé un fichier point en avec les accès à notre base de données si on retourne dans le schéma on peut voir la variable d'environnement database URL qui est déclaré dans notre point en on peut donc utiliser postgce mysquel SQL l SQL Serveur mongod dB cock Roch dB nous utiliserons MySQL on peut utiliser Prisma dbpool pour inspecter une base de données existante et on générer un schéma mais c'est pas ce qu'on veut et on peut faire Prisma generate pour regénérer le client de Prisma on ne va pas non plus utiliser beaucoup cette commande pour éémerger notre base de données j'ai pas envie de m'embêter à configurer des dockers et des VPS donc nous allons utiliser un service tier qui s'appelle Planet scale je retourne donc sur google et je vais taper Planet scale jeis cliquer sur le lien planetscale.com qui va nous donner un tableau de bord dans lequel on pourra gérer notre base de données je n'ai pas de compte donc je vais créer un compte avec mon adresse gmail je vais taper un mod pass sécurisé il demande de vérifier l'adresse email je vais le faire tout de suite et maintenant je suis sur l'écran d'accueil de Planet scale donc il me demande soit je peux importer une base de données existante soit je peux en créer une nouvelle on va en créer une nouvelle le nom ça s'appellera nestgs chat et ça sera dans la région Europe donc on va prendre Europe centrale Fran fort nous allons prendre le plan gratuit qui nous donne accès à 1 milliard de lecture et 100 millions d'écriture par mois ce qui est largement suffisant par contre il nous demande d'entrer notre carte bancaire pour créer une nouvelle base de données et j'étais pas au courant de cette étape quand je prévoyais d'enregistrer cette vidéo alors excusez-moi les amis moi je leur fais confiance et je leur donne volontiers ma carte de crédit de toute manière ils ne vont pas me débiter je viens donc d'ajouter ma carte de crédit et on peut maintenant créer notre base de données et nous demande de sélectionner notre framework nous utiliserons Prisma il nous demande de sélectionner un mot de passe maintenant je vais garder préciusement celui qu'il viennent de me donner je clique sur Create password maintenant il me donne les étape à suivre pour pouvoir utiliser Prisma dans ma base de données donc je vais tout de suite sauvegarder le mot de passe qu'ils m'ont donné ici en tant que variable d'environnement on ne sait jamais maintenant ils m'ont également donné un USERNAME database username égal à ça password est égal au password et là c'est le véritable password dont on a besoin pour se connecter à la base de données ce password est un différent types de password alors je suis un petit peu confus Planet scale password on va sûrement jamais l'utiliser mais je le garde dans mon point en pour m'en rappeler si si jamais on me le redemande il nous ensuite de faire une installation de Prisma on a déjà fait un init on a déjà fait et au final on avait pas besoin d'enregistrer le USERNAME ou le password parce que plus bas il nous donne l'unique string dont on a besoin le database URL que Prisma utilise on va remplacer celui-là par celui-ci il nous demande également de modifier légèrement notre fichier schéma. Prisma il rajoute une clé relation mode qui s'appelle Prisma et on utilise évidemment ma SQL je vais modifier ça tout de suite schéma point Prisma et de tout manière ce fichier est vide maintenant Planet scale et Prisma fonctionnent différemment par rapport aux autres bases de données si vous avez déjà utiliser par exemple doctrine et Symphony vous savez que à chaque modification de votre schéma de données vous devez générer un fichier de type migration ces migration permettent de mettre à jour votre base de données de revenir en arrière et d'annuler certaines modifications du schéma mais avec Planet scale ça se passe un petit peu différemment nous n'allons pas créer de fichier migration nous allons tout de suite push le schéma de données que nous avons en local en production alors ne vous inquiétez pas c'est très sécurisé Planet scale nous donne une fonctionnalité similaire au pool request tu vas créer une nouvelle branche production qui te montre les modifications que tu apportes à ton schéma et pour le moment ça ne change rien parce que nous n'avons aucun modèle de données donc nous allons créer notre modèle user qui va donc contenir une ID et là il y a Copilot qui m'aide c'est vraiment génial parce que je me souvenais plus de la syntaxe alors j'ai pas envie que ça soit une autoincrémentation j'ai envie que ça soit une uu id ou plutôt une CO ID alors qu'est-ce qu'une co ID en programmation c'est une ID qui ressemble à ça c'est une série de lettres de chiffres de lettres aléatoires et c'est une ID évidemment unique pour le moment on va rester très simple on va supprimer tous ces champs on veut que l'email soit unique on vaut rajouter un FirstName et on veut rajouter un password qui sera également en string et c'est tout pour le moment là on peut voir qu'on a une petite erreur parce que luuid dit forcément est un string ce n'est pas un int donc je vais tout de suite mettre string maintenant on va tester la connexion à notre base de données pour voir si tout a fonctionné vu que j'ai remplacé la variable d'environnement à ce niveau-là je vais exécuter la commande que m'a donné Prisma c'est-à-dire NPX Prisma dB push la colle dans mon terminal ça a synchronisé la base de données avec mon schéma Prisma on va terminer avec la configuration de Planet scale dans ce fichier nous disent comment on peut utiliser Prisma en Javascript et en typescript mais ce n'est pas comme ça que nous allons l'utiliser nous allons plutôt créer un service nestgs donc on peut retourner sur l'overview de notre base de données et on peut voir qu'on a une table qui s'appelle user qui contient une ID un email un first name et un password nous avons également une seule branche c'est la branche main mais dans cette vidéo nous allons tout push sur la main nous allons pas apprendre à faire des pool request et créer un environnement de staging nous allons tout faire sur la main pour intégrer Prisma nous allons créer un nouveau service qu'on va rajouter à la racine et qu'on va appeler prisma.service.ts et j'ai trouvé un site qui nous propose un service déjà écrit donc nous allons l'utiliser sans honte du coup on appelle le service Prisma service il fait un extend de Prisma client et cet extend lui permet d'utiliser les méthodes de Prisma comme dollar Connect et dollar disconnect on peut voir ici qu'on a accès à toutes les méthodes de Prisma on peut faire des query et ce service implémente deux méthodes on module init et on module destroy quand ce module module est initialisé au lancement de notre application on va créer une connexion avec Prisma et notre base de données et quand on arrête l'exécution de notre application on va se déconnecter de Prisma et de notre base de données ici je n'ai pas besoin de créer un module ou un contrôleur pour Prisma j'utilise uniquement Prisma comme service pour utiliser la base de données donc on va maintenant retourner dans notre module et on va importer le service que nous venons de créer qui est le Prisma service maintenant que je l'ai importé dans mon module je vais pouvoir commencer à l'utiliser dans mon service donc le fichier user service qui pour le moment écrivait nos données en Durre va maintenant injecter le module Prisma donc ça va être private readon Prisma de Prisma service on n'oublie pas de fermer les moustaches et maintenant on peut commencer à utiliser Prisma avec un dis Prisma et on peut voir toutes les méthodes auxquelles on a accès nous ce qui nous intéresse c'est le user.f Money maintenant on a une petite erreur parce que nous ne pouvons pas faire un await dans une méthode qui n'est ins synchrone donc on va rajouter le mot-clé A5 on va récupérer les users dans une variable et si on regarde le type inféré on a un ID un email un first name et un password évidemment dans une réelle application on ne va pas récupérer le mot de passe côté client donc on va sélectionner les propriétés une par une ce que nous voulons récupérer c'est l'ID la mettre à trou et l'email et le first name qu'on va également mettre à trou le mot de passe n'apparaît plus et on va renvoyer notre tableau d'utilisateur maintenant on va créer un nouvel utilisateur par défaut pour vérifier que ça fonctionne bien j'ouvre une nouvelle fenêtre de terminal je retourne dans mon dossier je vais faire NPX Prisma studio et Prisma Studio est un super outil qui ressemble beaucoup à PHP my admin et ça va nous permettre d'accéder à notre modèle de données sur le navigateur là je suis sur localast 5555 et on peut voir que j'ai une table user qui contient l'champ ID email first name password et on va créer une entrée avec un email qui va s'appeler virgile@varkof.fr sourcename c'est Virgil comme mot de passe on peut mettre un BC 1 2 3 pour le moment par la suite le mot de passe sera évidemment crypté si on retourne maintenant dans postman toujours dans notre méthode qui permet de lister les utilisateurs de notre application et qu'on envoie la requête on peut voir que ça nous a listé notre tableau avec l'utilisateur depuis notre base de données donc on a le firstn qui correspond à Virgile l'email qui correspond à virgile@varcof.fr et l'ID maintenant on va créer plusieurs méthodes que j'ai envie dans mon application c'est de pouvoir permettre aux utilisateurs de créer un compte j'aimerais qu'il puisse réinitialiser leur mot de passe s'ils l'ont oublié et j'aimerais lister un utilisateur individuel comme sur les profils donc nous allons commencer par lister un utilisateur individuel avec une méthode qu'on va appeler get user qui va faire un find unique whereare id est égal à un string le string sera un paramètre du nom de user ID user ID qu'on va renvoyer dans notre contrôleur on va également créer cette route get user et là nous allons pouvoir ajouter/ dou.userid us id est une route dynamique c'est-à-dire que peu importe ce que tu renvoies que ça soit user 1 ou user 3000 ça va exécuter cette méthode dans le contrôleur et nest nous propose un décorateur qui s'appelle param qui va nous permettre de récupérer le user ID là il faut s'assurer de bien écrire aux deux endroit le même nom de param pour que l'association fonctionne bien et nous récupérons un paramètre user ID qui est de type String ici je suis en train d'utiliser un concept de nasgs qui s'appelle une pipe et qu'on va voir plus en détail un peu plus tard et je type fortement le paramètre que je vais recevoir depuis les paramtres mais il faut savoir que les paramètres d'URL ont toujours des strings même si c'est 1 2 3 ça sera un nombre sous forme de string maintenant on va accéder à notre deuxième méthode de user service qui s'appelle get user qui accepte en paramètre un tableau contenant la clé user ID et nous allons voir sur postman si ça fonctionne bien nous allons créer une deuxième requête donc je vais faire users/ et mon ID et maintenant ça ne me renvoie plus un tableau d'utilisateur ça me renvoie un utilisateur individuel on va maintenant passer à l'authentification des utilisateurs on va donc sécuriser leur connexion avec un token JWT pour cela on va retourner sur la documentation de nesjs on va taper nesjs authentification nesjs nous donne un guide complet pour générer un module de type os un contrôleur et un service de type os mais ce qui nous intéresse c'est la partie JWT token qui va nous permett d'identifier l'utilisateur et de conserver sa session on va reproduire cette syntaxe là c'estd qu'on va impor porter le module JWT avec quelques paramètres notamment le temps d'expiration de notre token mais d'abord première étape générer un module un contrôleur et un service de type os donc on va faire tout de suite ce qu'il nous demande de faire on va générer ces trois modules juste effacer les dollars je lance donc chacune de ces trois commandes ça me créer un nouveau dossier qui va s'appeler os qui contient des tests on va supprimer tout de suite un contrôleur un module et un service notre module importe bien le service et le contrôleur c'est parfait au niveau de notre contrôleur on va authentifier un utilisateur qui essaie de se connecter pour se faire ça va être une méthode POST donc je vais utiliser le décorateur post depuis nestjs common et je vais l'appeler la méthode login ça sera une méthode asynchrone qui renverra un token d'authentification je vais donc appeler la route login pour pouvoir y accéder depuis localhost 3000/host/login et pour identifier un utilisateur nous avons besoin de deux choses nous avons besoin de son email et de son mot de passe vu que c'est une méthode POST la méthode POST est envoyée avec un body qu'on utilise laapi fetch on envoie l'URL la méthode de type poste et un tableau qui s'appelle Body avec un email et un mot de passe généralement ici c'est exactement ce que nous allons faire grâce au décorateur de nestgs qu'on va appeler hos body pour le moment nous ne connaissons pas le type du body hos body sera donc un objet qui contient un email de type string et un password de type String maintenant nous allons console log cet objet dans notre terminal pour vérifier que ça fonctionne bien et avec postman nous allons modifier notre requê pour créer un poste vers hos/login avec un body notre body sera du row JSON il contiendra deux clés notre email s'appelle Virgile at varcof.fr en minuscule et un mod pass qui sera ABC1 23 si j'envoie la requête pe voir que j'ai bien le console log que j'avais déclaré dans le hos controller j'ai réussi à récupérer des données envoyé depuis mon formulaire pour le moment il y a pas de formulaire en pastman pour que ça soit plus lisible nous allons créer un type qui va s'appeler h body qui sera égal à notre body et nous allons écrire toute la logique d'authentification dans notre service host service en appelant le constructeur private readon host service qui rite du type hos service et nous allons créer une méthode hos service qui s'appelle également login qui sera asynchrone et qui prendra en paramètre le host body donc je retourne vite fait dans le contrôleur pour pouvoir exporter ce type et je l'exporte pour pouvoir l'importer dans mon service en tant que host body comme ça je peux accéder aux propriétés grâce à typescript avant de pouvoir authentifier l'utilisateur nous avons besoin de vérifier qu'il existe vraiment comment savoir s'il existe dans la base de données en utilisant Prisma donc on va faire un constructeur de Private readonly Prisma double. Prisma service et nous allons vérifier que l'utilisateur existe avec un dis Prisma user find unique sur le champ email où l'email est égal à hostbody.email oubliez de refermer les moustaches dans le constructeur et je vais mettre tout ça dans une variable qui va s'appeler existing user et égal au user unique vu que j'ai envie d'afficher un message d'erreur personnalisé je vais mettre que si l'utilisateur n'existe pas je veux renvoyer une erreur de type l'utilisateur n'existe pas sinon pour le moment nous allons renvoyer l'utilisateur je importer le service Prisma dans mon module d'authentification en tant que provider ça s'appelle donc Prisma service et nous allons continuer la logique je vais d'abord dstructurer l'objet host body plus de clarté en récupérant les propriétés email et password et on va vérifier que le mot de passe qu'il est rentré est bien le mot de passe de son compte avec un is password same est égal à password et je vais faire un triple égal pour comparer le mot de passe que laapi a reçu avec le mot de passe qu'on a sauvegardé en base de données si ce n'est pas le même mot de passe on va voer une erreur du type le mot de passe est invalide là on se porte très bien on vérifie que l'email qu'on a reçu est le bon puis on vérifie que le mot de passe qu'on a reçu est le bon évidemment on n pas encore exploité les Jeson web token mais ça va pas tarder les amis il est maintenant temps d'authentifier nos utilisateurs de manière sécurisée on va donc retourner sur la documentation de nestjs et on va continuer de suivre les instructions il nous demande d'abord de créer un module et un service pour récupérer les informations des utilisateurs mais nous l'avons déjà fait nous avons également créé une route pour se connecter et sur la documentation il y a ce message qui nous dit faites attention ne sauvegardez surtout pas vos mot de passe en clair il te conseille donc de crypter ton mot de passe et d'utiliser la librairie brypt et c'est celle qu'on va utiliser donc je vais me rendre sur la documentation de brypt et ici je scroll jusqu'à trouver la commande pour l'installer je vais donc ouvrir une nouvelle fenêtre de terminal je me rends à la racine de mon projet et je vais faire un NPM install de brypt je vais également me rendre sur la page NPM de brypt pour vérifier une petite information ici il y a un petit logo avec écrit DT ce qui veut dire que brypt supporte typescript mais on a besoin d'installer une petite librairie supplémentaire si je clique sur DT ça me ramène sur une page qui s'appelle add types/bcrypt je vais également devoir installer cette librairie pour bénéficier de l'annotation et des types donc je fais un NPM install-- save@@ types/brypt pour installer les types on peut donc fermer le terminal et maintenant je vais retourner dans mon service hos et je vais créer une nouvelle méthode qui va s'appeler h password elle va prendre en paramètrre un mot de passe elle va le crypter et elle va renvoyer le mot de passe crypté qu'on sauvegardera en base de données pour ça je vais également importer bcrypt depuis bcrypt et on va voir quelles sont les méthodes que brypt met à ma disposition je vais donc créer une nouvelle variable qui va s'appeler HH password qui sera égale à bcrypt point et on va utiliser la méthode H qui prend en premier paramètre le mot de passe en clair et en deuxième paramètre une valeur qui s'appelle salt or rounds qui est tout simplement un numéro de cryptage donc on peut mettre 10 par défaut la valeur est de 10 si je passe ma souré sur le h on peut voir que cette méthode est en fait une promise c'est une méthode asynchrone donc nous allons faire un await et nous allons dire que cette méthode est asynchrone également maintenant je vais renvoyer le mot de passe que j'ai crypté nous allons donc récupérer le mot de pass h en exécutant la fonction que nous venons de créer h password avec en paramètre notre mot de passe et j'ai envie de faire un console log pour vérifier que ça me renvoie un mot de passe valide je vais donc ouvrir mon extension postman et je vais clique droit sur ma méthode et je vais faire dupliquer pour en créer une nouvelle on voit que la route c'est déjà un poste sur login donc je vais modifier le nom de cette méthode je vais appeler login et je vais aller dans le body on peut voir si on retourne dans le body qu'on a des informations et ces informations sont correctes donc je vais envoyer la requette et on peut voir sur le terminal qu'il ne s'est rien passé on va aller débug ça tout de suite en fait dans le contrôleur je n'utilise pas encore cette méthode du service je vais donc l'utiliser tout de suite on va effacer ce consog et on va renvoyer à la place un await de diservice. login et on peut voir qu'ici on a nos deux méthodes on retrouve le H password et le login et moi j'aimerais pas que la méthode h password soit disponible en dehors du service donc ce que je vais faire c'est que je vais retourner dans le service et je vais rajouter le mot-cé Private juste avant la déclaration de ma fonction si je retourne maintenant dans le contrôleur on peut voir qu'il n'y a plus que login qui m'est suggéré avec l'autocomplétion ma méthode h password est maintenant privé on renvoie donc nos informations et on va retourner sur postman pour tenter de se connecter et là on a une une erreur qui veut dire je n'arrive pas à lire les propriétés de H qui sous-entend que la méthode h n'existe pas et je sais déjà d'où vient le problème le problème vient de cet importe au final je vais tout simplement importer la méthode h directement depuis brypt je modifie la fonction et on va refaire le test j'envoie une requête et là j'ai un message d'erreur qui est tout à fait normal c'est le message d'erreur qu'on a comparé et on peut voir que le mot de passe ressemble à ça par rapport au mot de passe en clair ce mot de passe là a été crypté et sera beaucoup plus dur à détecter ce que je vais faire c'est que je vais tout deite ite copier cette version du mot de passe haché et je vais la sauvegarder dans la base de données j'ouvre un terminal je vais dans mon dossier projet et je vais faire NPX Prisma studio et on va aller sur le localhost 55 55 et dans mon utilisateur je vais rajouter le mot de passe Hach que j'ai récupéré maintenant je sauvegarde et on va créer une deuxième méthode qui va permettre de comparer notre mot de passe en clair et notre mot de passe Hach et cette méthode s'appelle compare donc je vais prendre ma méthode h password et je vais la dupliquer je vais appeler cette deuxième méthode is password valide ça sera un boulet 1 et elle prend en paramètre un mot de passe le mot de passe en clair et un mot de passe haché je récupère le deuxième paramètres et je vais importer depuis brypt la méthode comp on va donc supprimer ce code et appeler notre variable is password valide est égal à compire qui prend en premier paramètre le mot de passe en clair et en deuxième paramètre le mot de passe crypté ça nous renvoie un boulien et comme pour la première méthode c'est de l' syynchrone donc je vais rajouter mon await et je vais renvoyer is password valide et cette fonction va renvoyer si oui ou non les deux mot de passes qui ont été fournis sont les mêmes maintenant je peux modifier cette condition et je peux dire que is password same qu'on va renommer en is password valide est égal à await de la méthode qu'on vient de créer qui s'appelle ISW valide qui prend en paramètre le mot de passe le mot de passe que l'utilisateur nous renvoie depuis l'API donc ce mot de passe là avec le mot de passe HCH qu'on a retrouvé en base de données qui est donc qui appartient à notre utilisateur qui est le exting user point password j'ai tout de suite envie de faire le test avec un mot de passe erroné donc là je retourne sur pastman et je vais rajouter en 4 à mon mot de passe qui s'appelle ABC 1 2 3 4 j'envoie une requettete et là j'ai une erreur le mot de passe est invalide maintenant je modifie le mot de passe il va de nouveau être ABC 1 2 3 je renvoie la requête et je n'ai plus l'erreur ce qui signifie que le mot de passe est valide ça me renvoie même la réponse avec un status code 2011 nous venons de crypter nos mot de passe et nous allons également utiliser cette méthode de hashing pour tous les nouveaux utilisateurs que nous allons créer à chaque fois qu'un utilisateur va vouloir créer son mot de passe ou modifier son mot de passe nous devons utiliser brypt pour le Hasher avec la même valeur de hashing maintenant j'ai pas envie de renvoyer l'utilisateur directement on va renvoyer son ID pour le moment on va retourner sur le guide de NGS parce qu'on NAA pas fini maintenant comment est-ce qu'on arrive à authentifier un utilisateur et garder sa session active et ben implémentons ça dans la foulée je retourne donc sur la documentation et il nous demande de créer des modules mais ça nous l'avons on déjà fait la méthode fonctionne bien et nous retrouvons maintenant la partie JWT token il nous explique donc que les tokens JWT nous permettent d'authentifier des utilisateurs de renvoyer un token sécurisé et de garder leur session active on pourra même créer des routes qui sont bloqué et que seuls les utilisateurs connectés pourront accéder pour se faire nous allons installer le module de nestgs@@nestgs/jwt je vais fermer Prisma et je vais lancer cette commande dans mon terminal on retourne maintenant sur la documentation et on est directement dans notre service d'authentification et ce qui nous intéresse c'est les deux dernières lignes c'est-à-dire la création du payload alors c'est quoi le payload et ben le payload les amis on va demander à Google payload in JWT le payload contient l'identité de l'utilisateur ou plutôt l'affirmation de son identité c'est-à-dire que n'importe qui côté client ou surpman peut nous dire e c'est moi Virgile s'il te plaît aide-moi à me connecter du coup il y a une sorte de douanier qui va dire ok montrez-moi vos papiers je vais vérifier vos papiers avec les informations que j'ai moi donc du coup il regarde il regarde il laisse passer ou il bloque l'accès pour que nos utilisateurs puissent se connecter nous allons leur fournir nos propres papiers sous forme d'un payload je vais donc créer une dernière méthode qui sera également privée et que je vais appeler authenticate user et qui contiendra le user ID je vais faire un petit peu deorifacto et je vais copier ce morceau de code de la documentation de nfjs qui crée un payload à part partir d'un user ID et puis c'est tout là on peut voir qu'il renvoie un access token qui fait un await avec la méthode sign assnc du JWT service que nous n'avons pas encore importé alors nous allons l'importer tout de suite dans le constructeur avec une virgule pour séparer nos deux services private readonly JWT service qui appartient à la classe JWT service qu'on apporte depuis atngs/ GWT et c'est ça que nous allons renvoyer au clients du coup ma méthode authenticate user est asynchrone et à ce niveau-là au lieu de renvoyer un utilisateur je vais renvoyer cette méthode on va faire un return await 10. authenticate user avec en paramètre notre user ID et là on peut voir que notre serveur a une erreur nous n'avons pas importé le service de JWT dans le host module et nous allons remédier à ça tout de suite nous retournons dans le host module mais c'est pas aussi simple que de faire en impimport de GWT service comme celui-ci même si l'application n'affiche plus d'erreur c'est un peu plus compliqué nous disent bien dans la doc ici que nous allons carrément importer le module GWT qui nous permet d'enregistrer notre secret et la durée d'expiration du token dans cet exemple le token expire après 60 secondes c'est-à-dire que un utilisateur se connecte il restera connecté ça session reste active seulement 60 secondes après ces 60 secondes l'utilisateur devra se reconnecter retaper son mot de passe et son email je vais copier ce code là on va rajouter la clé impimport qui est un tableau de module et nous nous importons jwt.module maintenant nous avons un deuxième problème le secret JWT ce secret là il faut vraiment qu'il soit privé il ne faut pas le versionner il ne faut pas le donner côté client si ce code secret est connu tout le monde pourra se connecter à la place de tout le monde sur votre application et elle ne sera plus du tout sécurisée on a donc besoin d'un secret qu'on va rajouter dans notre variable d'environnement je vais donc sur le net et je vais taper generate random h 356 et je vais sur le premier lien qui me donne accès à plusieurs h que je vais donc copier dans mon point en et je vais appeler ça GWT secret qui sera égale à cette valeur et je vais juste modifier de trois lettres par d'autres lettres là on va mettre ça voilà et maintenant à ce niveau-là je vais faire un process.en.jwt secret maintenant à l'initialisation de notre module d'authentification ça va importer le module GWT et ça va le configurer avec nos paramètres mais j'ai quand même envie de vérifier que la valeur de mon secret est été activé donc je vais faire un console log de process.om.gwt secret et là on peut voir que ça a affiché le secret au moment où j'ai enregistré la page je vais même remodifier cette valeur et je vais l'appeler secret double point et là on peut voir qu'avant les initialisation j'ai déjà accès à mon secret donc je n'ai pas à valider son importation on retourne maintenant sur postman et on va encore une fois taper un mot de passe incorrect pour le fun effectivement j'ai bien l'erreur le mot de passe est invalide d'ailleurs je vais supprimer ce console log qui me perturbe et on va déplacer ce bout de code parce qu'il faut vérifier d'abord que l'utilisateur existe s'il n'existe pas on vérifie que le mot de passe est valide et si le mot de passe n'est pas valide on renvoie une erreur sinon on authentifie l'utilisateur mais cette deuxième méthode qui permet de crypter ou hacher un mot de passe on ne l'utilise pas actuellement parce qu'on possède déjà un mot de passe haché on l'utilise seulement pour la création de compte ou l'édition du compte donc je peux le mettre en commentaire maintenant je vais taper un bon mot de passe j'envoie une requête et là je vois que j'ai une erreur qui dit secret or private key must have a value cette erreur confirme ce que je pensais si on fait une petite recherche en tapant cette erreur sur Google on va voir une réponse Stack Overflow où il nous explique effectivement que l'application n'a pas vraiment détecté notre variable d'environnement pourtant on a vérifié que la variable d'environnement était détectée sur le console log qu'on avait tapé si on refait console. log de notre secret qui vient de processd en.jwt secret on peut voir que l'application arrive bien à interpréter notre secret mais il y a une partie de configuration que nous n'avons pas encore faite je vais taper nestgs environnement et ça nous renvoie sur un lien de documentation qui s'appelle configuration qui est un module que nous n'avons pas installé il disent bien ici que la config de NJS utilise la librairie do.om si je vais dans mon package jison je peux voir qu'effectivement on ne trouve pas cette librairie/config nous allons donc l'installer tout de suite j'ouvre une deuxième fenêtre de terminal à l'emplacement de mon projet et je lance la commande npmi- save atnesjs/conig en continuant sur cette documentation on peut voir que dans le app. module nous devons importer un module qui s'appelle config et nous allons l'importer tout de suite je copie cette ligne et je vais dans mon fichier app module et j'importe le module de configuration qu'on importe depuis njs/config si on continue à naviguer sur cette doc on peut voir qu'on peut personnaliser le chemin de notre variable d'environnement pour avoir plusieurs chemins comme des variables d'environnement de production et de staging on peut avoir même plusieurs fichiers d'environnement on peut même désactiver le chargement de ces fichiers et on peut même utiliser ces variables d'environnement en global en global ça signifie dans tous les modules si cette option est désactivée nous allons devoir importer config module dans chacun de nos modules et je n'ai pas envie de le faire du coup je vais ajouter ce paramètres config module for rout en un paramètre objet qui possède la clé is global va mettre à true maintenant qu'on a bien implémenté notre configuration on peut retourner sur postman et tenter de se connecter et si j'envoie la requête on peut voir que j'ai de nouveau une erreur qui me dit secret or private key must have value donc j'ai toujours la même erreur et elle n'a pas été corrigée les amis nous avons notre premier bug et ce bug j'ai mis beaucoup de temps à trouver une solution en regardant sur la documentation de SGS ce bug m'a fait perdre le fil donc je vais réexpliquer ce que nous sommes en train d'essayer de faire comme sur tous les sites que tu utilises ou presque pour se connecter à ton compte tu dois taper ton email et ton mot de passe côté serveur tu appelles la base de données en lui donnant ton email unique et il vérifie qu'il existe puis il vérifie que le mot de passe est bien égal au mot de passe qui a été crypté si ton mail est ton mot de passe sont exact alors on te renvoie un token de sécurité on l'a implémenté dans la méthode authentique gate user et il a été signé avec le service JWT donc on a besoin du service JWT le problème c'est que notre service JWT n'arrive pas à signer notre payload et s'il n'arrive pas à signer notre payload c'est qu'il a besoin d'un secret le secret on l'a ajouté dans notre variable d'environnement ici sous le nom de GWT secret et dans un monde sans bug il nous aurait juste fallu d'aller dans le h. module et d'indiquer notre secret à cet emplacement pour qu'il puisse l'utiliser pour signer notre token et nous identifier malheureusement ça ne fonctionne pas et nous essayons de débugger cette partie de l'application j'ai retrouvé la raison de notre problème après avoir tout essayé j'ai d'abord pensé que c'était l'ordre des importations qui importaient du coup j'ai préféré importer nos variables d'environnement en premier avant d'importer le module d'authentification j'ai regarder plein de guidees et au final la raison de notre erreur était l'importation du JWT service après l'importation du module parce que ici dans Haos service nous utilisons GWT service vous vous rappelez sûrement avant qu'on l'utilise à ce niveau-là nous avions une petite erreur qui nous demandait d'importer GWT service parce qu'on l'utilise mais avec nestgs on peut soit importer un service directement soit importer un module qui contient le service et au final c'était le JWT module qui contenait le JWT service là si je réimporte un service qui n'a pas été modifié avec C information nous allons toujours avoir notre fameuse erreur de secret par contre si je retire le JWT service je vais quand même pouvoir l'utiliser parce qu'il est présent dans ce module alors ici on le voit pas mais si je lance une requête sur postman on peut voir que ça me renvoie enfin avec succès mon token de sécurité on retourne donc dans l'os module et on va remplacer les 60 secondes par 30 jours on n pas envie d'être déconnecté au bout de 60 secondes j'ai également fait une petite modification dans le SER j'ai enlevé l'utilisation de sign A5 parce qu'ils ont une méthode qui n'est pas sous forme de promesse qui fait exactement la même chose ça nous évite d'avoir à faire un away sur la documentation de l'authentification on va passer les étapes d'après parce que ici on renvoie donc le token sécurisé on importe le module et ensuite on importe un garde et le garde c'est ce douanier qui va vérifier nos papiers et nous laisser rentrer ou nous refuser l'accès si on va tout en bas de la documentation on peut voir qu'il y a l'intégration d'une librairie qui s'appelle passeport et c'est telle que je vais utiliser on va donc suivre la documentation et nous allons installer les deux premières librairies qui sont nestgs passeport et passeport mais nous n'allons pas installer passeport local j'ouvre donc un deuxième terminal et j'installe C de librairie et nous allons installer à la place la librairie passeport- JWT parce que c'est comme ça qu'on veut se connecter nous allons l'installer sur NPM et on peut voir que c'est pareil il y a des types installer donc on installe d'abord passeport GWT avec un npmi de passeport- GWT puis on clique sur le petit symbole DT et on va télécharger maintenant les types de passeport JWT si on retourne sur la documentation on voit qu'il nous faisait directement installer les types pour la librairie passeport local il génère donc des modules et des services d'authentification et d'utilisateur qu'on a déjà créé maintenant qu'on a installé ces librairies on peut retourner sur la documentation et dans le sommaire de cette documentation on voit un chapitre qui s'appelle JWT functionality et implementing passport JWT nous allons aller dans le host controller et nous allons créer une nouvelle route qui sera donc un get que je vais importer depuis nesgs common qui n'aura donc pas de suffix c'est-à-dire qu'on pourra y accéder depuis localas 3000/h et que je vais appeler authenticate qui est donc une méthode asynchrone et qui va renvoyer les informations de l'utilisateur connecté donc l'authentification fonctionne comme ça en première étape tu login donc tu envoies un mot de passe et un email en deuxième étape la pays tu renvoies un token sécurisé par exemple ABC1 2 3 et ensuite pour vérifier que tu es toujours connecté ici tu renvoies ton token surisé ABC1 2 3 pour accéder à cette route et côté code ils vont faire la jointure entre ABC1 2 3 et ton email et ils vont pouvoir être capable de vérifier ton identité et te connecter si le token n'a pas expiré si le token a expirer ça va donc renvoyer une erreur et tu devras te reconnecter nous avons donc implémenté la partie mot de passe et email et nous avons implémenté la deuxième partie il nous reste juste à débugger la partie 2 et à implémenter la partie 3 dans la partie 3 tu possèdes ton token sécurisé dans les headers donc dans l'entête de ta requête c'est-à-dire si tu faisais par exemple avec laap fetch une requête par exemple authentification ici tu Auris un body avec ta donnée du genre emailvgil@varkof.fr et toutes ta donnée et tu aurais aussi une clé headers qui est un objet avec différentes cléses par exemple content type est égal à application/ jison et tu aurais aussi ton token authorization wbrr token à la place du token tu aurais donc par exemple ABC 1 2 3 nestjs il récupère cette requête et il lit tes headers et il va vérifier que tu as bien un token ICI si tu n'as pas de token il ne va pas te connecter si tu as un token mais qu'il est faux il va vérifier s'il est juste et s'il est faux il ne va pas te connecter pour paramètr tout ça il faut mettre en place une stratégie d'authentification la stratégie c'est la logique que tu vas coder toi-même et qui va permettre de dire ok ben je vérifie que le token soit présent dans le champ authorisation par exemple ou dans le champ brir et cetera tu peux le mettre dans un autre champ tu peux l'appeler x token par exemple 1 2 3 4 5 peux l'appeler comme tu veux donc si on retourne sur la documentation de passeport JWT on voit ici qu'on créé un fichier qui s'appelle jwt.strategie.ts et on va copier ce fichier et on va le créer dans notre application dans le Directory hos je crée donc un nouveau fichier qui s'appelle jwt.strategie.ts et je copie le code qu'on m'a donné on utilise donc une classe qui s'appelle extract JWT et une classe stratégie depuis password- JWT et on utilise également une classe qui s'appelle password stratégie la stratégie c'est un provider qu'on va importer dans notre module et la constante elle nous permet uniquement de récupérer notre secret pour nous on a notre secret dans process.an.jwt/seret donc on crée une classe qui va s'appeler JWT stratégie qui fait un extend depuis les passeports stratégie pour utiliser ces deux méthodes la méthode super et la méthode validate ici tu vois qu'on veut extraire le JWT token depuis la requête donc depuis cette requête là que je vais copier ici si côté client on exécute cette requête là on a donc des headers donc on fait une extraction from H header as birer token et les Bir token c'est ce genre de token là c'est-à-dire que la clé s'appelle authorisation et la valeur alors c'est brr espace et notre token sécurisé le deuxième paramètre c'est est-ce qu'on ignore l'expiration du token non on ne va pas ignorer l'expiration on veut que le token expire après un certain temps donc on le met à false et le secret or Key est égal à notre secret maintenant qu'on a créé cette stratégie on peut l'ajouter dans notre module et on va l'ajouter à la suite de nos provider elle s'appelle donc JWT stratégie je l'importe ici et je vais supprimer cette valeur là dont on a plus besoin et je vais rajouter le secret de nouveau à cet endroitl maintenant nous retournons dans notre os controller et on va implémenter la deuxième méthode qui va nous permettre d'identifier l'utilisateur cette méthode s'appelle hos et à partir de notre token sécurisé nous allons voir si on peut identifier l'utilisateur pour cela il faut que nous reg regardions la stratégie donc le fichier jwt.strategie.ts que nous venons de créer je vais juste supprimer ces lignes que j'avais utilisé pour débugger donc ce qui se passe c'est que on envoie une requête fetch par exemple avec dans l' tête notre token de sécurité qui permet à l'appli de nous identifier une fois qu'on a récupéré ce token si jamais il y a un token on va exécuter une fonction qui s'appelle validate et cette fonction validate va envoyer un objet dans notre Requet pour qu'on puisse l'utiliser je vous explique avec un petit exemple ici dans la méthode super nous avons un FCH qui se connecte donc notre AP hos et qui a comme headers notre token auutorisation = brr ABC 1 2 3 on vérifie que ce token est bien présent il est bien présent on va utiliser le secret pour convertir ABC 1 2 3 3 avec le payload que nous avons défini pour signer le secret et à l'heure actuelle le payload c'est un objet qui contient un user ID donc on donne ça à l'application l'application vérifie et décrypte notre token et il nous renvoie ceci c'est-à-dire qu'ici le token qui est décrypté est égal à user ID qui est sous forme de string je vais donc remplacer ce nom de payload par user ID maintenant ces informations que nous renvoyons dans la méthode validate va nous permettre d'avoir accès aux informations de l'utilisateur dans la requê directement je vais vous expliquer comment ça fonctionne avec Express nous créons le routing avec un app.get notre méthode et nous passons en paramètre une fonction avec une request et une response ici si on renvoie la response on peut envoyer par exemple du JSON au format data et nous récupérons les information de la request et c'est dans cette request que nous avons les adders et les body et toutes les informations de l'application nous dans cette request nous allons récupérer le payload nous allons donc récupérer le user ID direct depuis la request comment c'est possible grâce à notre stratégie JWT au niveau de cette requête là nous n'avons pas encore le user ID et ensuite après la vérification du token il est évidemment bon ça va rajouter à cette requê fetch une clé de type user ID ou ce qu'on décide d'y mettre ce nouveau payload je vais le déclarer en tant que type pour que ça soit plus simple vu qu'on l'utilise à plusieurs endroits je vais donc l'appeler user payload et ça sera un objet qui contient une clé de type user ID je vais exporter ce type et le rajouter à ma variable on retourne maintenant dans le service h service et ici je veux que les paramètres de la méthode authentiqué user soit de type user payload et que ce payload là soit également fortement typé avec le type user payload maintenant pour récupérer les informations de l'utilisateur connecté avec son token nous avons besoin de mettre en place cette stratégie pour le moment elle n'est utilisée nulle part don je vais supprimer ses commentaires et on peut voir qu'on implémente une stratégie JWT mais on l'implémente seulement sur les roues où on l'utilise et pour le moment nous nutilisons nulle part donc ici on veut utiliser JWT stratégie pour cela nous allons utiliser un nouveau décorateur on retourne donc sur la documentation de passeport dans implementing passeport JWT on scroll vers le bas et ici on peut voir qu'il nous parle d'un JWT hostgard le hostgard c'est ce fameux douanier qui va vérifier nos papiers on va copier ce code le fichier s'appelle JWT hosgarde je vais le mettre dans mon dossier Haos jwt-os garde.ts je copie le code qui m'a été fourni et on peut voir que c'est une classe qu'on apporte de nestgs passeport et on découvre un nouveau décorateur de nestgs qui s'appelle les gardes les gardes c'est donc ces donniers et on peut créer n'importe quel logique que nous voulons avant d'autoriser l'utilisateur à accéder à sa route ce décorateur peut se mettre au-dessus de la classe et dans ce cas-là il va protéger toutes les méthodes de la classe le décorateur s'appelle use guards et il prend en paramètre un ou plusieurs Gardi nous nous allons importer JWT hagarde à ce niveau-là je l'ai mis a-udessus du contrôleur pour qu'on puisse tester sur postman ce qu'il se passe maintenant on n plus accès à la méthode login parce que nous ne sommes pas identifiés on va donc essayer cette requête sur pasman j'envoie la requête et là j'ai une erreur unauthorized ça a bien fonctionné je prends donc cette déclaration US guardards GWT hgard et je vais la rajouter sur cette méthode GET qui va me permettre avec mon token de Me réidentifier et de récupérer les informations de mon utilisateur je vais d'abord me connecter pour récupérer le token sécurisé maintenant je vais sur postman je vais dupliquer la requête et cette fois je vais l'appeler get authenticated user et c'est une requête de type get qui contacte la route hos donc là je retourne dans mon contrôleur et je vais supprimer le chemin parce qu'il est déjà présent tout en haut je vais exécuter la requête et là on peut voir qu'il y a une erreur parce que j'ai créé deux requêtes GET qui pte exactement les mêmes noms donc j'en supprime une des deux et on refait une tentative je me connecte et et je ne suis pas autorisé à passer c'est normal je ne suis pas identifié maintenant sur postman je vais aller dans authorization et je vais rajouter un brr token qui prend comme valeur notre token d'authentification je le copie ici et je le rajoute ici et normalement la requête arrive à passer et je n'ai plus d'erreur pour récupérer les informations de notre payload donc ces informations là le user ID qui va nous permettre d'identifier le user nous allons utiliser un décorateur de nest qui nous permet de récupérer la requette encore une fois ça ressemble beaucoup à Express chacune de nos routes peut récupérer la request et la Response le décorateur peut s'appeler REC ou request c'est exactement le même on l'apporte depuis nestgs/ common et on lui donne un nom je vais l'appeler request si on a été autorisé c'est qu'on a été validé par la stratégie donc je sais que l'objet request possède un user ID nous allons en avoir le cornet en faisant un console log de l'objet request on exécute la requête avec postman et là on peut voir notre objet request dans son intégralité pour voir le body les paramètres les queries la réponse je continue de scroller et on a aucun visuel sur notre utilisateur on va aller sur l' dooc et on va voir comment ils font pour récupérer l'utilisateur et récupère l'utilisateur avec un request.user c'est une convention d'Express et de passeport qui metett toutes les informations après la validation dans un objet user si je retourne donc sur mon contrôleur et que je fais un request.user je vais refaire une requête et on peut voir que ça a fonctionné j'ai un objet avec la clé user ID et en valeur mon ID on a réussi à récupérer les informations de notre utilisateur maintenant je vais juste supprimer ces commentaires et nous allons terminer d'implémenter la logique je retourne dans ma stratégie et je vais déclarer un autre type que je vais appeler request with user qui sera tout simplement un objet qui contient un user avec le type user payload je vous avais promis de pas déclarer de type dans cette vidéo mais je vous assure c'est vraiment utile maintenant maintenant je peux retourner dans mon host controller et je peux typer ma request avec un request with user et à ce niveau-là je vois ma maintenant que mon objet request a une autocomplession à user puis à user ID on peut refaire un essai et on peut voir que ça bien console log la user ID je vais donc fermer ce terminal et maintenant qu'on est authentifié on va utiliser cette méthode pour récupérer les informations de l'utilisateur et pour cela nous allons importer le user service que nous avons créé tout à l'heure donc private ronly user service dou. user service qui une classe que je vais importer là on a une erreur dans notre terminal c'est parce qu'on doit importer le service dans les providers ici après au service je vais importer user service dans mon module d'authentification je sauvegarde il n'y a plus l'erreur je retourne dans mon user service pour voir les deux méthodes que j'ai j'ai un get user et j'ai un get user par user ID c'est cette fonction que je vais utiliser dans mon contrôleur donc je vais faire un naw de 10 userervice.getuser et je passe comme user ID l'ID de mon objet request je peux maintenant supprimer ce console log et on va retourner sur postman pour vérifier que ça fonctionne bien là je suis authentifié j'envoie une requête et j'ai les informations de mon utilisateur le force name l'email et l'ID si maintenant je vais dans autorisation et que j'enlève le dernier caractère qui est un U majuscule je sauvegarde la requête je la renvoie et là je vois unauthorized error status code 500 message internal serveur error on va remettre le vrai token et on va passer à la suite on va rajouter les méthodes qui manquent pour que ça devienne une véritable application on va par exemple créer une méthode pour enregistrer un nouvel utilisateur je vais copier la méthode login et je vais l'appeler register pour créer un nouveau compte on a besoin du prénom et de l'email donc je vais déclarer un autre type que je vais appeler create user qui contient un email et un first name et je vais utiliser ce type pour avoir l'autocomplétion de typescript je vais également créer une nouvelle route donc je copie la route login et je renomme login en register avec un register body que je type avec mon create user dans ma fonction register body je vais renommer le host body en register body et je vais changer le type host body par create user j'ai toujours un email et maintenant j'ai un force nameame et la logique est similaire avant de créer un nouveau compte on va d'abord s'assurer qu'aucun utilisateur n'existe pour cette adresse email on a déjà le message d'erreur l'utilisateur n'existe pas on va le modifier un compte existe déjà à cette adresse email ensuite on n pas besoin de vérifier que le mot de passe fonctionne mais on a besoin de le déclarer heureusement on avait commenté ce code et là on se rend compte que j'ai oublié un champ mot de passe donc je retourne dans le type et je vais rajouter un mot de passe de type String que je récupère depuis mon register bé maintenant on doit créer l'utilis de notre base de données pour ça on utilise Prisma avec un dis Prisma user create qui est une fonction qui prend en paramètre un objet avec une clé data qui est également un objet avec nos valeurs on va donc rajouter l'email en password on va mettre h password le password crypt et en first name on va mettre son first name c'est une méthode asynchrone donc on va la wait et on va la sauvegarder dans une variable que je vais appeler created user après avoir créé l'utilisateur j'aime bien l' tifier tout de suite alors pour le faire on a juste à récupérer created user et à le renvoyer avec notre méthode authenticate user qui renverra l'access token côté front on va aller sur postman et on va dupliquer la requête qu'on appelle register user c'est sur la route/hos/reister c'est un post et ça contient un body avec un email un password et un first name je vais m'appeler Toto et on va vérifier que ça fonctionne bien j'envoie la requête et j'ai une erreur qui dit que le champ email est unique et qu'on ne peut pas créer l'utilisateur effectivement si on retourne dans notre schéma Prisma on peut voir que le champ email est unique mais j'ai fait une erreur dans le code au lieu de dire si l'utilisateur n'existe pas on envoie l'erreur un compte existe déjà j'aurais dû mettre si l'utilisateur existe alors on renvoie l'erreur un compte existe déjà c'est le problème du copier-coller je n'ai pas fait attention on peut donc retourner sur postman dans notre méthode register user on l'envoie et là j'ai une erreur un compte existe déjà à cette adresse email je vais donc créer un nouvel utilisateur qu'on va appeler toto@varcov.fr je le renvoie et cette fois ça m'a renvoyé un access token pour pouvoir me connecter en tant que Toto on va vérifier que ça fonctionne bien je copie l'access token je retourne dans postman et là je vais modifier le token pour récupérer les informations de l'utilisateur connecté j'envoie maintenant la requête et on peut voir que j'ai les informations du deuxième utilisateur qui s'appelle Toto c'est plutôt sympa mais c'est pas très visuel je te propose de faire une petite pause avec NGS et de créer un petit front end avec remix on va donc aller sur la documentation de remix remix.run et on va tout de suite read the docs et créer notre nouveau projet remix pour cela je vais ouvrir un terminal et je vais aller dans dev et je vais lancer la commande NPX create- remix at latest et ça va me poser quelques questions notamment est-ce que je vais installer remix oui comment je vais appeler mon projet nest js-chat ti front et est-ce que je veux instancier un nouveau repipo et je vais mettre non est que je veux installer les dépendances je vais mettre oui et j'ai refuser d'instancer un nouveau repipo parce que nous allons le faire ensemble remix a été initialisé alors je vais tout de suite ouvrir le projet avec VS code SGS chat- front et je vais vous présenter un petit peu le projet remix c'est un petit peu comme nextjs ça nous permet de créer avec react des applications full stack il possède un serveur et un front-end on va très rapidement présenter chacun des fichiers pour faire tourner react nous avons donc le fichier entry.cient qui est le point d'entrée ça va donc afficher notre interface sur l'élément du DOM document avec le strict mode nous avons également un fichier de type serveur parce que remix permet de faire du rendu côté serveur le rendu côté serveur nous permet de récupérer et charger les données depuis notre API avant d'afficher la page aux utilisateurs ça nous évite d'avoir à afficher plein d'écrans de chargement ce fichier est un peu compliqué mais il réceptionne chacune des ê et il renvoie une réponse au format html nous avons également un fichier route qui sera le point d'entrée de notre code react nous avons donc une balise HTML une balise aide pour le SEO et un body avec un outlet et plusieurs composants react de remix nous allons tout de suite aller dans le fichier_index.tsx qui représente la page d'accueil de l'application nous allons effacer ce UL et je vais même ouvrir le terminal intégré pour faire un NPM rundev le problème c'est qu'il y a un conflit remix se lance par défaut sur le port 3000 et nestjs se lance par défaut sur le port 3000 par convention je préfère avoir mon front-end sur le port 3000 donc je vais retourner sur NGS dans le fichier main.ts et mettre que le port par défaut j'aimerais que ça soit le port 8000 pour être sûr que ça fonctionne bien je vais rajouter une variable d'environnement port qui sera égale à 8000 maintenant je vais couper le serveur de nest et je vais le relancé avec un NPM rev et je vais faire une commande avec postman pour vérifier que ça a bien modifié le port si je fais un local host 3000 on voit qu'il y a une erreur ça ne fonctionne plus et si je fais un localhost 8000 on voit maintenant que ça fonctionne j'ai créé un utilisateur avec une adresse email qui existait déjà je retourne sur le projet rimix et je fais un NPM randev et on peut voir maintenant que le projet s'ouvre sur localost 3000 on va ouvrir cette application dans notre navigateur et on peut voir qu'on a notre H1 welcome to remix vu que cette vidéo se concentre vraiment sur le backend on va pas passer beaucoup de temps sur remix et sur le stle des composants je vais juste créer un formulaire qui va contenir un input de type email qui sera requis et un autre input de type password qui sera également requis l'input de type email aura également un name de type email et le password aura aussi un name de type password on aajoute pas le propre name on ne pourra pas récupérer la valeur de ce formulaire quand on va le soumettre on va également utiliser le composant de formulaire de remix qui est forme avec un F majuscule qu'on importe depuis remixrun/react on va faire un poste donc la méthode sera de type post et on va aussi rajouter un bouton de type submit qu'on va appeler se connecter pour soumettre ce formulaire à notre API on va d'abord devoir le soumettre au serveur de remix et pour le soumettre au serveur de remix on va devoir créer une fonction qui s'appelle une action toutes les modifications et les soumissions de formulaire sur remix sont exécuté dans des actions donc je vais déclarer une nouvelle fonction qu'on va appeler action qui est une fonction fléchée qui va renvoyer du jison et j'exporte la méthode jison depuis remix run- node cette action possède plusieurs arguments qu'on va pouvoir typer action function ARS et on va tout de suite les déstructurer parce qu'on a besoin de récupérer la request je veux pas utiliser le type de pure react router donc je vais supprimer cet import et je vais vraiment importer tous mes types depuis remix run/ node je vais rajouter le préfix type pour préciser que c'est un type on peut voir que dans notre request nous avons plusieurs propriétés le body et contrairement à express et à nest JS dans lequel on aurait pu récupérer les informations de notre request depuis la valeur body nous nous allons plutôt utiliser form data qui est une fonction asynchrone on peut le voir par son annotation promise et j'aimerais récupérer le résultat de cette fonction dans une variable que je vais appeler form data form data est égale à request pointform data et on va la wait pour la wait il faut pas qu'on oublie d'ajouter le mot-clé A5 au-dessus de notre fonction on va maintenant faire un petit console log de notre form data et on va exécuter notre formulaire mon email c'était donc virgile@varkov.fr et le mot de passe c'était ABC1 23 si je clique sur ce connecter on peut voir que j'ai eu un console log de type form data et un objet vide c'est bien normal nous devons convertir notre forme data en objet avec la syntaxe particulière qui va s'appeler object. from entries nous allons assigner cette valeur à une nouvelle variable qu'on va appeler Jason data est égal à object.f entries form data maintenant je vais faire un console log de Jason data on peut voir que notre terminal a rafraîchi le code de l'application et si je soumets le formulaire à nouveau on voit maintenant que j'ai bien mes donner mon email et mon mot de passe je suis en train d'implémenter le formulaire de connexion de remix pour contacter notre API maintenant qu'on a notre email et notre mot de passe nous allons faire une requête avec la p native fetch nous allons donc faire un await de fetch sur la route http//localost 8000/hos/login et nous allons rajouter des options déjà la méthode est le type post et la méthode contient un body dans la clé body nous allons passer notre mot de passe et notre email et on peut le passer soit sous forme de forme data soit sous forme de jison mais qu'on va convertir en string pour cela on peut faire jison. stringify de notre jison data notre méthode fetch va nous renvoyer une réponse qu'on peut sauvegarder dans une variable qu'on va appeler response et notre variable response possède également une fonction de type gison pour convertir le résultat de la requête en jison donc les informations que notre API va nous renvoyer seront en jison quand on se connecte on récupère un token sécurisé sous forme d'objet donc je vais appeler ça const token est égal à response.gison et c'est également une méthode asynchrone on a donc besoin du mot- clés a wait je vais rajouter des commentaires pour que ça soit plus visible première étape on récupère les informations du formulaire deuxème étape on appelle notre API nest avec les données du formulaire pour savoir si l'email et le mot de passe sont corrects on a besoin que nestgs fasse appelle à notre base de données et ensuite en troisème étape en cas de succès on récupère le token pour authentifier l'utilisateur connecté si utilateur est connecté nous récupérons un token je sauvegarde et je soumets à nouveau le formulaire et là on peut voir que j'ai une erreur de type 500 Internal Server Error si je retourne maintenant sur laapi je peux voir que j'ai effectivement une erreur dans mon terminal ça a bien appelé la méthode login avec un host. body mais aucune donnée n'a été récupérée on va donc aller sur notre host controller et on va faire un console log de la donnée qu'on renvoie à notre app si je console log host body et que j'ai exécute à nouveau le formulaire je re rourne maintenant sur mon API et je vois un objet vide mais je n'ai pas envie d'avoir un objet vide nous allons devoir valider les données côté serveur effectivement nous ne pouvons pas autoriser tout le monde à se connecter ou à contacter notre API on leur autorise l'accès seulement s'il nous donne des données valides on va donc retourner sur la documentation de nestgs et faire une petite recherche nestgs validation si on clique sur le premier lien on voit qu'il y a un chapitre entier dans leur documentation dédié à la validation des données pour valider des données ils utilisent un concept qu'il s'appelle les pipes on peut donc utiliser la validation pipe qui utilise la librairie class Validator vous la connaissez peut-être elle est très utile et nous allons l'utiliser tout de suite je vais donc installer classe Validator et classe transformer dans mon API nestjs j'ouvre un nouveau terminal je retourne dans le dossier projet et j'installe classe Validator et classe transformer ensuite la prochaine étape sur la documentation nous demande de modifier notre fichier main.ts et de rajouter cette méthode qui s'appelle use global pipes je copie ce boot code et je retourne dans mon fichier main.ts et juste avant d'écouter le P 8000 je rajoute le boot code app. useglobal pipes avec la nouvelle validation pipe qu'on importe depuis nestjs command on peut voir que la validation pipe est une classe qui prend en paramètrre plusieurs options il y a deux options qui nous intéressent le whit list pour filtrer toutes les données qu'on n pas envie de recevoir et le transform et si vous avez déjà utilisé Z vous allez comprendre de quoi il s'agit ça va permettre de déclarer un modèle de données que nous souhaitons recevoir et ça va purger toutes les autres données que nous n'avons pas déclaré dans ce modèle si on retourne sur la documentation on peut voir qu'ils utilisent le concept de DTO et les DTO représentent le modèle des données que nous allons envoyer avec nos formulaires je vais donc copier ce DTO qui s'appelle create user je retourne maintenant dans mon dossier hos et je vais créer un nouveau dossier qui va s'appeler DTO dans lequel je crée un fichier que je vais appeler create-user.dto.ts nous pouvons copier le code de puis la documentation qui utilise classe Validator ça va donc valider l'email et vérifier que c'est bien un email et ça va valider le mot de passe et vérifier qu'il n'est pas vide si nous retournons sur notre contrôleur d'authentification on peut voir que j'avais initialement créé un type qui contient un email un first name et un password je vais récupérer ce first name et je vais le rajouter comme troisième propriété avec le décorateur is string ce qui est bien avec class Validator c'est qu'il va vérifier que les données sont au bon format à notre place par exemple si on renvoie dans le email un string qui n'est pas un email notre méthode ne sera pas exécutée parce que la pipe donc la validation aura échoué on peut voir que chacun de ces décorateurs peuvent prendre plusieurs paramètres on peut par exemple bloquer certains domaines comme les adresses email Gmail par exemple mais le champ email possède également un deuxième paramètre qui s'appelle message et ce message correspond au message d'erreur en cas d'erreur là nous pouvons mettre vous devez fournir une adresse email valide et pour le first name notre objet prend également un message qu'on va appeler vous devez fournir un un prénom et pour le mot de passe il y a d'autres décorateurs notamment des rejects pour s'assurer qu'il y a bien une minuscule une majuscule et un caractère spécial il a également un décorateur qui s'appelle min lance qui permet de préciser une longueur minimum de mot de passe si par exemple on veut pas de mot de passe inférieur à 8 on va mettre main lance 8 et en deuxième paramètre on pourra mettre un message de type votre mot de passe doit faire plus de 8 caractères qui est bien avec cette classe DTO c'est qu'on peut s'en servir pour typer nos données maintenant qu'on a déclaré le DTO pour créer un utilisateur je retourne dans le contrôleur et je peux supprimer le type create user je vais le remplacer par mon DTO à ce niveau-là et ça va automatiquement mettre en place la validation à cette route c'est-à-dire qu'ici on ne peut exécuter cette fonction seulement si nos données sont conforme à notre modèle on va faire un console log de register body et on va également ajouter le DTO ici à la place de notre ancien type qu'on a supprimé que je peux d'ailleurs effacer de la déclaration je retourne maintenant sur postman dans register et je vais envoyer la requête normalement le mot de passe ne devrait plus passer là si je renvoie la requête on peut voir une erreur votre mot de passe doit faire plus de caractères c'est l'erreur que je viens de définir grâce au DTO ça a donc bien fonctionné si maintenant à la place de l'email j'enlève le Obas ça devient un string standard j'aurai deux messages d'erreur vous devez fournir une adresse email valide votre mot de passe doit faire plus de H caractères les DTO vont être nos meilleurs amis avec nesjs et grâce à la transformation n'importe quelle propriété qu'on ajoute en plus ne sera par utiliser si je mets par exemple une propriété âge à ce niveau-là et que je rajoute quelques caractères pour dépasser la limite des 6 on peut voir que il y a bien mon console log mais que la propriété ge a été retirée si je retourne dans le MAIN.S et que je commente la partie whitelist que je réexécute la requette on peut voir que cette fois je possède bien la propriété ge mais moi je préfère les whitelister pour avoir un objet avec seulement les propriétés que j'ai défini je vais modifier le DTO et je vais retirer cette limite de mot de passe petit caractère ça me convient très bien pour mon ABC 1 2 3 retournons maintenant sur notre application remix pour régler le problème j'ai bien envie d'ajouter Zod pour valider les données côté remix je vais donc sur la documentation de zone et je vais l'installer tout de suite dans mon terminal maintenant je relance le serveur je vais donc importer directement Zod dans mon fichier la méthode de Zod s'appelle Z donc on fait un import de Zod et je vais créer un nouveau schéma qui va s'appel login schéma est égal à z.object parce que ça sera un objet qui possède un email de type z. string et un password de type z. String j'ai également effacer la fonction méta qu'on utilise pas pour le moment et après avoir transformé ma donnée de formulaire en Jason je vais pouvoir la parcer dans une nouvelle variable qu'on va appeler parst Jason qui est égale à login schimaps de mon objet Jon et ce pars va effectuer la même chose que les DTO avec nesjs ça va regarder cet objet là et ça va vérifier est-ce qu'il y a bien un email est-ce qu'il y a bien un mot de passe sinon ça exécute une erreur et si on a les bonnes données on aura l'inférence depuis typescript on peut voir ici qu'on a un email et un mot de passe on va tout de suite faire un console log de notre nouvel objet pars JSON et on retourne sur le code de notre application et on va de nouveau soumettre notre formulaire ABC1 2 3 on peut voir que le pars a bien fonctionné si j'avais ajouté une propriété qui n'existe pas comme l'âge de type number par exemple et que je soumets le formulaire on a une grosse erreur de type il manque l'âge maintenant on voit bien qu'il y a une petite erreur notre backend ne reçoit pas la donnée et on a un énorme message d'erreur avec un objet vide nous n'avons pas encore résolu ce problème nous avons créé un DTO pour la création de l'utilisateur mais pas encore pour l'authentification nous allons y remédier tout de suite je duplique ce fichier que je vais appeler login user et qui a besoin d'un email et d'un mot de passe on va appeler ça log user DTO je vais maintenant dans mon contrôleur os.body et j'importe ce nouveau type je peux également effacer le type host body qu'on avait créé tout à l'heure et je fais de même dans le service je supprime le host body et je le remplace par loguser.dto maintenant si je retourne sur mon frontend et que je soumets le formulaire on peut voir une erreur beaucoup plus parlante vous devez fournir une adresse email valide votre mot de passe doit faire plus de 8 caractères et le mot de passe ne devrait pas être vide alors c'est quoi cette histoire pourquoi est-ce que mon API ne reçoit pas les données que je lui envoie côté front et ben c'est tout bête j'ai oublié une entête très importante qui est obligatoire avec la méthode PCH on ne sait jamais quel API on va contacter et si elle supporte le format jison dans notre notre cas on ne précisait pas un SGS que laapi était au format jison donc on va rajouter un header un header c'est un objet avec plusieurs entêtes plusieurs propriétés et nous allons ajouter un content type de type application/gon pour préciser tout simplement un FGS pour qu'il reconnaisse le format des données qu'on envoie et lui dire écoute je t'envoie des données ces données là sont format jisen maintenant que j'ai terminer ce petit changement si je soumets le formulaire j'ai une réponse depuis mon API avec un access token maintenant je vais sur mon API on peut voir qu'on a bien reçu nos données maintenant qu'on a récupéré notre token nous avons besoin de le sauvegarder dans notre application frontend et pour cela nous allons le sauvegarder dans la session je vais retourner dans la documentation de remix et on va agrandir un petit peu la fenêtre la documentation de remix est d'ailleurs très bien faite on peut voir ici qu'il y a plein de sujets mais celui qui nous intéresse sera les sessions donc je vais ouvrir la barre de recherche et taper session et aller sur le premier lien using sessions et on peut voir ce que ça m' ramené sur le chapitre nommé session qui nous parle de l'utilisation des sessions avec remix on a même un petit sommaire qui nous explique tout ce qu'il faut savoir pour créer une session sauvegarder une session et les différentes API que remix nous met à disposition il faut savoir que remix utilise les méthodes natives du navigateur par exemple si nous allons sur MDN et que nous tapons session storage sur le premier lien nous pouvons voir qu'on peut manipuler directement les sessions en Javascript avec le session storage le principe ici est donc donc d'enregistrer notre token d'authentification avec une clé dans notre session vu que la session est sauvegardée dans les cookies à chaque Requet HTTP que nous allons faire dans notre application nous allons vérifier si l'utilisateur est autorisé à effectuer une certaine action je retourne donc sur la documentation de remix et nous allons lire ensemble l'exemple qu'ils utilisent pour créer une session on apporte une première fonction qui s'appelle create cookie session storage qui va permettre de sauvegarder notre session et de l'utiliser ici ils utilisent create cookie session storage qui est la méthode qu'ils importe et ils y passent quelques paramètres notamment le nom de la session et des paramètres facultatifs comme le domaine le chemin et même un secret nous allons utiliser quelques-uns de ces paramètres pour vraiment sécuriser notre session on va plutôt se concentrer sur les trois méthodes qui sont déstructurées depuis create cookies session storage nous avons donc trois méthodes GET session qui comme son nom indique va nous permettre de récupérer les informations de la session nous avons commit session qui va nous permettre de modifier notre session et nous avons destroy session qui va nous permettre de détruire la session si la session est détruite l'utilisateur est déconnecté on va utiliser destroy session pour déconnecter l'utilisateur on va utiliser commit session pour mettre à jour la session en y ajoutant notre token sécurisé et on va utiliser get session sur toutes nos routes protégées il nous donne un exemple sur une méthode qui s'appelle login où il utiliseent le G et le commit session dans la fonction l'odeur donc la fonction de chargement des données on fait un await de G session pour récupérer la session en passant en paramètrre la request et plus particulièrement le headers au nom de cookie vérifie que dans notre cookie il y a bien la clé user ID dans notre cas ça sera le token de sécurité si il y a le user ID ça veut dire que l'utilisateur est connecté du coup on le redirige sur la page d'accueil sinon on récupère l'erreur qu'il y a dans la session et on la renvoie ce qui nous intéresse nous c'est de connecter l'utilisateur donc nous allons plutôt regarder ce qu'ils font au niveau de l'action pareil nous regardons si l'utilisateur est déjà connecté si un utilisateur est connecté il ne peut pas se connecter on récupère ensuite son mot de passe et son email s'il y a un problème au niveau de la connexion on affiche une erreur toujours en utilisant la session mais on ne va pas faire comme ça sinon on ajoute la clé user ID avec la valeur du user ID et on fait une redirection sur la page d'accueil avec un set cookie et notre nouvelle session en gros nous allons faire qu'une chose on va récupérer la session une fois connectée on va set une nouvelle les clé qui va s'appeler user token puis on va effectuer une redirection en modifiant la session qui possède maintenant un user token je vous propose d'implémenter ça tout de suite on va donc créer un nouveau fichier dans le dossier app que nous allons appeler session.serveur.ts le point serveur signifie que le fichier exécutera le code uniquement côté serveur nous n'y aurons pas accès côté client je vais donc importer cette première fonction qui s'appelle create Cooky session storage qu'on va exécuter et elle prend paramètre une clé cookie qui prend plusieurs options nous allons rajouter la propriété Name que nous allons appeler double session vu que les autres paramètres sont facultatifs nous n'avons pas besoin de les utiliser nous allons maintenant déstructurer cette méthode et nous allons récupérer get session et commit session maintenant nous allons regarder plus bas comment ils utilisent le GET session nous allons copier ce morceau de code dans une fonction je vais créer une fonction qui va nous permettre de récupérer le user token et je vais l'appeler get user token qui prend en paramètre notre request qui sera de type request c'est un type de remix qu'on a même pas besoin d'importer vu que c'est un objet je rajoute le double point je redéclare mon objet à cet endroit est également une fonction fléchée alors il faut bien faire attention à la syntaxe et Copilot a tout compris c'est exactement le morceau de code que nous voulions créer d'abord on va faire un await de la session on peut voir que get session prend en paramètre un cookie r donc une entête de cookie dans notre cas nous prenons l'entête nommée cookie vu que c'est un a je rajoute d'ailleurs le mot clé à 5 ensuite nous cherchons à récupérer le user token qui est présent dans le cookie si l'utilisateur est connecté je vais tout de suite rajouter le mot-clé export à cette méthode pour utiliser cette fonction dans nos autres fichiers maintenant la deuxième chose qui nous intéresse c'est le commit pour cela on retourne dans la documentation et on regarde qu'on peut exécuter comme une session qui est une promise avec en paramètre la session qu'on aura sauvegardé pour ce faire je vais créer une deuxième fonction qui ressemble à la première et que je vais nommer commit user token et qui prend en deuxième paramètre le user token de l'utilisateur user token est en string on récupère bien la session et au lieu de faire un get nous faisons un set sur la clé user token en y ajoutant le token d'authentification ensuite nous faisons un return d'wait commit session avec en paramètre notre session on va tout de suite tester ce code ça sera plus parlant je vais également créer une nouvelle fonction coôtier serveur qu'on va appeler l'adur je vous le rappelle c'est une convention de remix et toutes les méthodes n nommé loador qui sont exporté de nos composants vont nous permettre d'effectuer du rendu côté serveur donc de charger les données avant que la page soit affichée à nos visiteurs donc je fais un export const de l'odeur qui est une méthode asynchrone on va typer les paramètres avec loader function AR elle renvoie également du jison et j'ai envie de renvoyer un boulien qui s'appelle is logged in et pour le moment on va le mettre en dur et on va mettre que c'est faux ensuite côté client je vais récupérer la donnée que m'a renvoyé le serveur avec un use loader data que je sauvegarde dans une variable qui va s'appeler data j'ai envie que les types soient inférés donc je rajoute les chevron ici parce que use loader data est une méthode générique et je veux mettre que je veux utiliser les types que me renvoie la méthode l'adur je vais mettre type of loader maintenant dans mon objet data je vois que c'est un objet qui contient un Bouen is logged in et je vais l'afficher côté client je fais donc une dstructuration et je récupère is logedin maintenant dans mon composant je vais rajouter un span et je vais faire un affichage conditionnel si on est connecté alors on va afficher l'emoji validé si on n'est pas connecté on va afficher l'emoji warning évidemment vu que ce sont des strings il faut rajouter les tiret maintenant on peut voir que nous ne sommes pas connectés nous avons le petit warning je vais également créer un deuxème schéma qui va nous permettre de valider le token d'authentification si je me souviens bien la clé s'appelle access token et je vais directement le valider à ce niveau-là avec un token d par de ma réponse en jison je vais ensuite le déstructurer en tant qu'Access token et nous allons faire une dernière tentative de connexion virgile@varkov.fr et ABC 1 2 3 si je me connecte ça va m'afficher côté serveur mon token qui est équivalent à ce console log présent si on retourne sur la documentation de remix on voit qu'on peut faire un commit de session en utilisant une en tête qui va s'appeler set cookie qui va nous permettre de sauvegarder notre session dans un cookie nous allons donc copier ce code à la lettre et le rajouter en deuxième paramètre à notre méthode jzon on a donc une clé headers qui est un objet qui possède une clé 7 cookies qui fait un await de commun session mais nous avons créé notre propre méthode qui s'appelle commit user token que nous allons utiliser ici je vais l'importer commit user token qu'on importe depuis session.sveur et ce user token prend deux paramètres il prend une request et il prend un user token et le user token je l'ai appelé access token on va voir si ça fonctionne dans le terminal on a une petite erreur qui nous parle de la session qui n'est pas signée si on clique sur le lien ils nous disent qu'il est mieux de rajouter un secret alors nous allons le rajouter tout de suite dans notre create cookies session storage je vais ajouter la clé secret et pour le moment nous allons conserver ce secret là maintenant j'ai envie de me connecter donc je vais retaper mes identifiants on va faire ce connecté et normalement si on inspecte la session qu'on peut retrouver dans Application cookie on peut voir qu'on a bien notre double session avec remimix il y a un cycle de vie particulier il y a d'abord le loadur qui est exécuté pour charger la donnée ensuite il y a le composant qui est affiché au client et si un formulaire est soumis ça va exécuter l'action qui est cette méthode qui va permettre de modifier notre données et après avoir exécuté l'action ça va réexécuter le loader pour vérifier que l'utilisateur est bien connecté nous allons utiliser la deuxième méthode que nous avons créée qui s'appelle get user token et si la session nous renvoie un token cela signifie que l'utilisateur est connecté je vais donc créer une nouvelle variable qu'on va appeler user token est égale à await get user token que nous emportons depuis notre fichier session.sveur cette méthode prend paramètre notre request et nous renvoie potentiellement un user token et nous allons faire un console log de ce user token et là on peut voir que j'ai tout de suite mon token qui est affiché dans le terminal et ce token est celui que nous voyons à l'écran dans l'outil de développement si je choisis de supprimer ce token en appuyant sur Supprimer et que je rafraîchi la page on voit que le token est undefined maintenant je vais transformer notre token en boulet1 je vais dire que is logged in est égal à boulet 1 de user token si user token est une string alors ça veut dire que nous sommes connectés effacer ce qu' se log et me reconnecter je me connecte et là on voit que l'emoji a changé si maintenant je coupe le serveur Rix et que je rafraîchis la page on voit que l'application a crche par exemple et si je relance le serveur remix et que je me reconnecte on voit que je suis toujours connecté ça a persisté mon état parce que c'est sauvegardé dans le cookie nous avons réussi à sauvegarder la session de l'utilisateur mais il nous manque quelques méthodes à faire on vérifie bien que le token est défini côté client mais que se passe-t-il côté serveur il n'y a pour le moment aucun app qui nous permet d'identifier l'utilisateur pour cela nous allons retourner dans notre application nestjs et nous allons exploiter la méthode que nous avons créée ici dans notre contrôleur os.crur.s c'est une route protégée par token le token nous le récupérons dans l'entête de la request et ce token sera converti en user ID ensuite nous récupérons le user ID et nous renvoyons le user qui est attaché à cet ID je vais renommer cette méthode qui porte le même nom que cette méthode dans le Haos P service alors qu'elles ne sont pas pareilles la méthode du HP service permet à partir du user ID de le signer et de d'en faire un token et notre méthode ici permet à partir d'un token de récupérer le user je vais donc l'appeler plutôt get authenticated user j'aimerais utiliser cette méthode côté client donc je vais retourner sur mon application remix et je vais créer un nouveau fichier qu'on appelle os.serveur.ts et nous allons appeler cette méthode const get authenticated user qui prendra en paramètre notre request ça sera une méthode asynchrone donc je rajoute déjà le motclé je n'oublie pas de bien dstructurer les valeurs de mon objet en paramètres et nous allons copier le code que nous avons dans l'index qui est cette requête là nous allons donc effectuer une requête en GET vu que c'est du get on n pas besoin de spécifier la méthode vu que c'est du get on a pas besoin d'avoir un body cette méthode appelle la route Haos directement et on peut retourner côté API pour voir ce que cette méthode nous renvoie ça nous renvoie un objet avec une clé ID une clé email et une clé first name je retourne donc sur remix et je vais copier ce schéma là que je vais rajouter ici et je vais mettre get authenticated user schema est égal à un email une ID le type string et un first name de type String après avoir validé cette réponse nous allons pouvoir la transformer avec un await de response.gon puis nous allons pouvoir la parcer avec notre schéma pour qu'elle soit fortement typée je la renvoie maintenant et on peut voir que la réponse à cette méthode et donc un objet avec un email une ID et un first name mais il ne faut pas oublier de rajouter l'étape critique nous devons d'abord envoyer à notre backend le token d'authentification et ce token là nous le récupérons avec notre méthode await get user token que nous avons créé dans session.sve get user token est donc une méthode qui a besoin de notre request après avoir récupéré notre request nous devons rajouter une deuxième en tête que nous allons appeler auutorization double point et là je vais utiliser les bactic brr espace et mon user token je retourne maintenant dans l'index et je je vais exécuter cette fonction je vais dire que const user est égal à await get authenticated user que j'ai oublié d'exporter dans mon fichier get authenticated user et je vais maintenant envoyer côté client l'authenticated user on peut même le mettre dans un élément prêt pour vérifier qu'on a bien reçu toutes nos données et on va mettre un petit peu d'indentation et là on voit que j'ai bien une clé email virgilewkov.fr une ID et un first name ce qui signifie que je suis bien connecté grâce à mon token je viens faire une petite pause et en retournant sur le projet voilà que je me prends une erreur l'erreur est de type on n pas trouvé l'email on n'a pas trouvé l'ID et on n pas trouver le first name alors pourquoi on a cette erreur on a été déconnecté côté client si j'ouvre l'outil de développement de mon navigateur et que je me rendre dans application on peut voir qu'il n'y a plus aucun cookie de configuré alors comment résoudre ce problème et ben il y a plusieurs types de routes il y a des routes dites protégé donc des routes réservées aux utilisateurs connectés mais c'est pas ce qu'on est en train de créer là vu qu'on est sur une page d'accur et il y a aussi des routes facultatives ces routes facultatives c'est les routes où si l'utilisateur est connecté tant mieux on peut afficher par exemple sa photo de profil mais s'il est déconnecté on ne va pas faire crash l'application on va corriger ce problème tout de suite je retourne dans le fichier os.serveur.ts et je vais modifier la méthode GET authenticated user si on fait un console log de notre user token on va voir qu'il est sûrement undefined si j'agrandis mon terminal et que je scroll vers le haut on peut voir que j'ai mon log ici avec usertken douundefined et si notre token est undefined on ne veut pas exécuter la requête d'après ça ne sert à rien ça va générer une erreur côté serveur du coup nous allons rajouter la condition if user token est égal à undefined alors nous allons renvoyer nul maintenant la fonction envoie soit une promesse avec un utilisateur soit nul et nous pouvons même la renommer en faisant un clic droit en allant sur rename symbo et en l'appelant get optional user ce qui veut bien dire qu'on récupère l'utilisateur seulement s'il est connecté si maintenant on rafraîchit la page on peut voir qu'on a nul c'est parce que dans notre fichier index on avait affiché un jzon stringify du user nous allons donc nous reconnecter avec nos identifiants et là je suis de nouveau connecté en tant que Virgile maintenant qu'est-ce qui se passe si nous avons une erreur dans la session si par exemple quelqu'un modifie son token ici et contacte le serveur si je rafraîchi la page on verra que j'ai un token parce qu'il n'est pas undefined donc ça va exécuter une requête au niveau du serveur et le server voudra récupérer l'id la user ID qui est dans mon token mais il ne va pas y arriver regardez voilà ce qui s'est passé c'est que ça renvoyé nul et ça a supprimé la session côté serveur on a bien reçu un token mais il est marqué comme unauthorized ils se sont rendu compte que j'ai envoyé un faux token mais j'ai quand même envie de modifier quelque chose dans le fichier os.sveur admettons qu'il y a une grosse erreur dans ce fichier à ce niveau-là par exemple th new error invalide data si je rafraîchis la page on peut voir que j'ai une erreur qui est vraiment pas très parlante ce que nous pouvons faire pour cette fonction là c'est d'englober toute la logique de notre code dans un try catch on va faire un try catch et si jamais la méthode échoue nous allons ici écrire la logique de code en cas d'échec évidemment si la logique échoue ça veut dire que le token n'est pas un fined du coup on fait une requête à notre API on récupère la donnée en jison mais qu'est-ce qui se passe si la donnée nous renvoie un authorized si elle nous renvoie unor ça veut dire qu'elle nous renverra pas nos données c'est-à-dire notre email notre ID et notre first name et vu que j'ai fait un pars de Zod et pas un safe pars ça va directement TR une erreur ce que j'ai envie de faire dans ce cas-là c'est de déconnecter l'utilisateur en supprimant sa session et pour se faire nous allons aller dans le fichier session.sveur et nous allons déstructurer la trisème fonction que nous avons vu dans la documentation qui s'appelle destroy session pour l'utiliser nous allons créer une troisième méthode on peut copier le commit user et nous allons l'appeler logout je vais supprimer le paramètre user token parce que nous n'en avons plus besoin ensuite nous allons récupérer la session que nous venons de détruire dans une nouvelle variable que nous allons appeler destroyed session et nous allons exécuter la fonction destroy session qui prend en paramètre notre session destroy session est une méthode sous forme de promise donc nous allons la wait et ensuite nous allons effectuer un return sur une nouvelle méthode qui s'appelle redirect et la méthode redirect nous permet d'effectuer une redirection sur la route de notre choix nous allons donc la faire sur la route flash qui est l'index de notre application la méthode redirect prend un deuxième paramètre sous forme d'objet qui va accepter des headers et un statut ce qui nous intéresse c'est les headers parce que nous allons à nouveau configurer les cookies je vais donc rajouter à cet objet la clé 7 cookie et comme valeur je vais lui donner ma session qui a été détruite et qui s'appelle destroyed session cette méthode logout nous allons l'utiliser à tous les endroits où nous souhaitons empêcher l'accès à l'utilisateur en production par exemple si je crée une route qui est protégée et qui est accessible uniquement pour les administrateurs et que tu n'es pas un administrateur je vais te déconnecter on va donc utiliser cette méthode dans le fichier HP serveur donc je retourne dans le fichier HP serveur et ici dans mon catch erreor je vais rajouter un petit console log ou plutôt un petit console point erreor de mon erreur et je vais faire un STW de ma méthode logout qui prend en paramètre une request la méthode logout est sous forme de promise donc nous allons faire un await maintenant on peut voir que j'ai créé une boucle infinie donc je vais kill le serveur parce que je renvoie une erreur à ce niveau-là et qui n'arrivera jamais au final notre logout se charge de supprimer notre token s'il n'existe pas si par exemple un utilisateur a créé un token de manière malicieuse donc je vais supprimer cette erreur ici nous allons relancer le serveur avec un NPM rundev je rafraîchis la page et nous allons refaire une tentative de connexion ABC 1 2 3 maintenant nous sommes connectés et je vais modifier mon token ici et je vais actualiser la page maintenant je vais juste déplacer ce bloc try à ce niveau-là parce que c'est seulement cette méthode qui est susceptible d'échouer ou le parce nous allons également retourner sur l'index. txt pour modifier un petit peu ce composant et nous allons effectuer un affichage conditionnel en créant un nouveau composant qui va s'appeler login form qui va renvoyer notre formulaire seulement si nous som déconnecté je vais donc supprimer ce code là j'affiche mon formulaire et ici je vais déclarer une nouvelle variable qui va s'appeler is connected et un utilisateur est connecté seulement s'il n'est pas égal à nul je vais donc faire si l'utilisateur est connecté on va mettre ce H1 avec le nom de l'utilisateur donc user.fname sinon nous allons afficher notre formulaire à ce niveau-là maintenant nous allons nous reconnecter pour vérifier que ça marche bien AB C 1 2 3 et nous sommes bien connectés maintenant nous allons créer une nouvelle page qui va nous permettre de créer un nouvel utilisateur je vais donc créer une nouvelle route que je vais appeler register.tsx et je vais copier tout le code de mon index.tfx que nous allons refactoriser en premier nous allons effectuer un loader avec la méthode GET optional user en effet si l'utilisateur est défini c'est qu'il est connecté s'il est connecté nous ne voulons pas qu'il ait accès à cette route c'est un petit peu l'inverse d'une route protégée c'est une route accessible seulement pour les utilisateurs déconnectés donc nous allons faire un return redirect et nous allons le rediriger vers la homepage donc j'importe la méthode redirect depuis remix.nod sinon si l'utilisateur est déconnecté nous allons faire un return de la méthode JSON avec un objet vide on va également modifier le schéma que nous allons appeler register schima dans lequel on rajoute une propriété first name on peut également ajouter une deuxième propriété au mot de passe pour dire que la longueur minimum est de 6 je scroll maintenant sur mon composant et je vais appeler ce composant register form on ne va pas utiliser le hook uselader data et on va juste utiliser ce formulaire qui va nous permettre de créer un compte je vais le renommer en créer votre compte et je vais dupliquer ce champ qui sera un champ de type texte et qui va s'appeler first name je vais même rajouter un placeholder pour que ça soit plus parlant votre prénom placeholder votre email placeholder mot de passe pour le moment on va commenter notre action maintenant nous allons tester d'accéder à notre route register pour cela je vais aller dans l'URL et rajouter un slash register et on va regarder les logs on peut voir ici qu'on a fait un get sur register et que ça fit une redirection 302 à ce niveau-là ce qui signifie que nous avons été redirigé vers la page d'accueil on peut même rajouter dans le loader un petit console log console.log vous êtes déjà connecté maintenant si j'actualise et que je retourne sur la page register je vois mon console log vous êtes déjà connecté et c'est exactement cette même logique qui va nous permettre de protéger des routes mais la méthode sera différente pour protéger une route on fera si l'utilisateur est égal à nul alors on va le rediriger et le déconnecter maintenant nous allons décommenter notre formulaire et nous allons réimporter Zod qui a été désimporté automatiquement et nous allons décommenter notre action et cette fois nous allons également récupérer les données de nos formulaires et nous allons effectuer un pars qui s'appelle register schima cette fois nous allons accéder à la route register si on retourne sur notre backend on peut voir dans le au controller que la route s'appelle bien register et qu'elle s'attend à recevoir un email de type email un password qui a une longueur minimum de 6 caractères et un first name imaginez on essaie de créer un compte mais le compte existe déjà qu'est-ce qu'on va faire du coup on va pas renvoyer un access token je retourne donc sur l'API et ici on peut voir que le type inféré c'est forcément un access token ce qui est totalement faux si j'accède à la méthode register ici on est en train de faire un f unique et si l'email n'est pas unique alors on fait un S d'une erreur un compte existe déjà à cette adresse email je vais rajouter un try catch à ce niveau-là qui va forcément catcher cette erreur si un utilisateur existe déjà et ce trycatch va renvoyer un objet de type error est égal à TR et message est égal à error.message error.message étant forcément mon un compte existe déjà à cette adresse email si je retourne dans le contrôleur maintenant on peut voir que le type inféré est soit access token soit error boulean et message an maintenant je retourne sur zone et je vais dire que l'access token peut être optionnel c'est-à-dire si la propriété access token n'est pas présente ce qui est fort possible alors on ne va pas déclencher d'erreur et je vais faire exactement pareil pour le message que va m'envoyer l'AP et l'erreur qui est de type z.boulean maintenant deux choses peuvent se passer soit une erreur a été effectuée soit j'ai reçu un token donc ici au niveau de mon parce je vais également déstructurer l'erreur et le message et je vais mettre if error donc si l'erreur est définie nous allons return du jison également mais nous allons return notre erreur et notre message sinon s'il n'y a pas eu d'erreur ça veut dire qu'on a bien été connecté et que nous avons un access token et si nous avons reçu un access token alors nous pouvons faire un return de await et la méthode commit user token prend en paramètre notre request et notre user token porte le nom d'Access token et dans ce cas-là nous allons identifier l'utilisateur si aucune de ces condition n'est respecté je vais rajouter un message d'erreur au format jison avec error est égal à trou et message est égal à une erreur inattendue est survenue maintenant je vais retourner dans mon composant et j'ai envie de récupérer la donnée de ce formulaire et pour se faire j'ai accès au hook qui s'appelle use action data et c'est exactement comme US loader data ça nous permet de récupérer la donnée que nous a renvoyé le serveur de remix donc je vais l'initialiser dans une variable que je vais appeler data est égal à use action data et nous allons également hériter des types que nous renvoie la méthode action donc je vais faire un type of action data maintenant si je surv sur ma variable on peut voir qu'il y a plusieurs méthodes possibles un type status un type adders un type OK et c'est pas du tout ce qu'on veut et je vais vous expliquer pourquoi j'ai fait un return await de commit session mais le return await de commit session me renvoie un string et c'est pas possible de renvoyer des strings on est obligé de renvoyer des données au format jison c'est enc encore une fois une erreur de ma part et au lieu de renvoyer cette session là je vais retourner dans le fichier session.sveur et je vais créer une nouvelle méthode qui va utiliser mon commit user token et qui va s'appeler authenticate user qui prend en paramètre une request de type request et un user token de type String encore une fois ça sera une méthode asynchrone parce qu'on va récupérer la session que nous venons de créer en awaitant notre méthode commit user token vu que c'est une promise on va rajouter le mot-clé assing et on va exporter notre nouvelle méthode et nous allons faire la même logique que dans l'index c'est-à-dire nous allons renvoyer une réponse avec dans les headers notre nouvelle session je vais copier ce morceau de code là et je vais faire un return jison avec comeders le nouveau cookie que je viens de créer mais je vais faire mieux que ça je vais même rediriger l'utilisateur sur la page d'accueil par défaut pour cela je vais faire un petit refifacto en rajoutant le chevron qui est manquant maintenant je retourne dans mon fichier register et je modifie la méthode commit user token par la méthode authenticate user on peut voir que mon problème d'inférence des types a été résolu et maintenant je peux retourner dans mon index et au lieu de renvoyer du jison je peux également exécuter ma méthode authenticate user qui est asynchrone et qui prend en paramètre une request et un user token je vais effacer ce code là et maintenant nous allons retourner sur notre formulaire et nous allons récupérer ces valeursl qui peuvent être undefined je vais renommer la variable en forme feedback pour que ça soit plus parlant et je vais effectuer un affichage conditionnel si form feedback contient un message alors je vais afficher le message form feedback. message sinon je n'affiche rien et je vais même aller encore plus loin en rajoutant dans ce span un style de type couleur si forme feedback possède une clé de type error et qu'elle est définie alors nous allons mettre le message en rouge sinon nous allons mettre le message en vert je vois que je me suis trompé dans la déclaration de ce shimazod la méthode n'était pas min lance mais la méthode M maintenant je souhaite me déconnecter et je vais aller dans le fichier rote qui est le parent de notre application pour rajouter quelques liens et notamment un bouton pour se déconnecter je vais donc créer un élément nav qui va contenir un bouton de type submit et qui s'appelle se déconnecter et ce bouton sera dans un formulaire qui utilisera la méthode POST et ce formulaire va appeler la route nommée logout que nous allons créer tout de suite je vais donc créer une nouvelle route que je vais appeler logout.tfx et dans cette route je vais créer une nouvelle action vu que je suis en train de soumettre un formulaire cette action sera asynchrone et onenverra ma méthode logout que j'emporte depuis session point serveur et qui prend en paramètre mon objet request mon objet request je le récupère dans la méthode action que je peux typer avec action function ARS que je vais importer depuis remix run/ node je vais également dstructurer les arguments de ma méthode action pour récupérer uniquement la request je retourne maintenant dans route et je vais rajouter un lien qui me redirige vers ma route register pour se connecter je souhaite également afficher ce lien seulement si je suis déconnecté donc pour cela je vais retourner dans mon index et je vais voler ce l'ador et je vais effacer la méthode l'ador que je vais utiliser plutôt dans mon fichier rote ici je vais coller la méthode et je vais réimporter les types et les fonctions et vu que mon composant rote est utilisé sur toutes les pages je vais faire un truc super stylé au lieu de devoir charger les données de l'utilisateur sur toutes les pages s'il est connecté je vais créer un hook global qui pourra être utilisé partout et je vais l'appeler const use optional user qui est une fonction fléchée et au lieu d'utiliser mon US loader data qui va être égal à loader data type of loader qui on peut le voir renvoie soit un user soit nul je vais utiliser un autre hook de remix qui s'appelle use rout loader data et ce hook là nous permet de récupérer la valeur d'une route active et on peut voir que ce hook prend un paramètre et en paramètre ça sera le roote ID et le rote id est égal à rote comment récupérer le root ID de n'importe quelle route je vais vous le montrer tout de suite mais d'abord nous allons terminer notre hook ici on peut voir qu'on a soit une clé user soit undefined donc on va faire un IF datata.user si l'utilisateur est estfi on va return data. user sinon on va return nul maintenant je vais exporter ce hook et je vais retourner dans mon index. TSX et à ce niveau-là le ususeelader Data ne fonctionne plus parce que nous avons supprimer la méthode loader mais vu que cet index est un composant enfant de notre route et on peut le voir ici grâce au composant outlate qui affiche notre page active à la place de ce composant nous allons pouvoir utiliser notre nouveau hook qui s'appelle use optional user je vais donc l'importer comme ceci et on peut voir que ça me renvoie soit un email une ID et un first name ou nul je vais donc arrêter la dstructuration je sauvegarde et maintenant on peut voir que je récupère bien la donnée de mon utilisateur sans avoir à charger la donnée dans ce composant là maintenant comme promis je vais te montrer comment j'ai réussi à récupérer l'id rote et comment tu vas pouvoir récupérer l'id de tous tes enfants et ben ça a à voir avec comment remix fonctionne si nous retournons sur la documentation et que nous allons dans route configuration on peut voir un super schéma on peut voir que nous avons la route principale qui est notre fichier route puis nous avons la page active qui pour nous est index.tfx et on peut configurer remix pour avoir encore une sous-page et encore une sous-page et ce schéma est très parlant parce que là dans mon invoice ID j'ai un petit composant qui est affiché dans un composant parents qui est affiché dans un composant parent et tous ces composants auront accès aux données que nous renvoie rote parce que rote est le parent de toutes les pages mais maintenant comment tu fais pour avoir l'ID de sales ou de invoice et ben il y a un hook que tu peux utiliser pour ça et ce hook s'appelle use matches qu'on va emporter depuis remix run slash react et qu'on va instancer dans une variable qu'on va appeler matches maintenant si on décide d'afficher le contenu de ce use matches dans un Jon string F on va retourner sur notre composant et on voit qu'on a les match de toutes nos pages on a donc notre première page route qui est afficher l'URL flash qui ne possède aucun paramètre et qui possède de la donnée le user et c'est d'ici qu'on arrive à obtenir cette donnée et nous avons une deème page qui est à rote qui est le nom de notre dossier/_index qui est le nom de notre composant et on peut voir que ce composant- là renvoie aucune donnée ne possède aucun paramètre et se retrouve également sur l'URL slash si demain tu as envie de créer ton hook qui récupère des données depuis ta route index tu pourras copier l'ID à partir de là maintenant je vais supprimer ces ligne je vais retourner dans le fichier route pour styliser un petit peu en utilisant Flex display Flex direction r gap 4 je vais également utiliser mon hook use optional user dans mon fichier route pour afficher conditionnellement ces deux liens si l'utilisateur est connecté alors nous allons afficher notre formulaire pour se déconnecter sinon nous allons afficher un lien pour se connecter maintenant je vais me déconnecter et on peut voir que ça a bien fonctionné ça a détruit ma session et ça m'a déconnecté je vais renommer le lien en créer un compte parce que ça prête à confusion et nous allons maintenant tester la création de compte je vais donc créer un nouveau compte qui va s'appeler virgilius l'adresse email ça sera virgil@varkof.fr + 1 et le mot de passe ça sera également ABC 1 2 3 si maintenant je veux créer un compte j'enregistre et on peut voir que ça a bien créé mon compte avec nestjs et que ça m'a bien authentifié maintenant je suis connecté en tant que virgilius et si nous allons voir notre backend on peut même voir le console log avec notre create user DTO je retourne de nouveau sur mon composant frontend et cette fois on va essayer de créer un compte avec un email qui existe déjà et on va prendre virgile@barof.fr et je vais m'appeler virgilonet avec avec toujours le même mot de passe et si je veux créer un compte maintenant j'ai un message d'erreur un compte existe déjà à cette adresse email et cette erreur c'est l'erreur qui est renvoyé directement par le serveur qu'on a configuré dans notre méthode register ici j'ai rajouté l'erreur un compte existe déjà à cette adresse email mais que se passe-t-il si on a un autre type d'erreur par exemple un mot de passe inférieur à 6 caractères je vais retaper mon adresse email et je vais mettre un mot de passe qui est inférieur à 6 caractères si je crée mon compte maintenant on a cette erreur qui vient de Zod qui nous dit code tout small et minimum 6 c'est trop petit parce que le mot de passe fait moins de 6 caractères sur le chemin password avec comme message string must contain at least sixacs et ben pour le moment on voit que Zod error est un tableau d'objets et chaque objet possède un message du coup je vais retourner dans les actions et au lieu d'effectuer un pars à ce niveau-là je vais effectuer un safe pars et je vais faire if par Jason success est égal à false alors ici nous allons déstructurer notre objet par jzon pour récupérer nos erreurs et notre erreur de Zod est en fait un tableau d'Errors qui contienent chacun un message donc je vais copier le message d'erreur ici et je vais le renvoyer côté client on va dire que l'erreur est de type true et le message et le type et là on va boucler sur les messages d'erreur que Z nous a envoyé et on va faire un join pour les séparer par une virgule pour que ça soit encore plus visible zone nous permet également de rajouter des paramètres du genre required error votre adresse email est requise et invalide type error vous devez fournir une adresse email valide pour le mot de passe on peut faire la même chose require d'erreur votre mot de passe est requis et pour l'erreur minimum je rajoute un paramètre avec comme erreur le mot de passe doit faire plus de 6 caractères pour le first name on va faire exactement la même chose votre prénom et requis maintenant si je renvoie un prénom un email et un mot de passe à deux caractères on va voir que l'erreur c'est le mot de passe doit faire plus de 6 caractères et pour le moment il est impossible pour moi d'envoyer un email qui n'est pas un email grâce à la validation HTML on peut voir qu'on pourrait même ici dans nos input descendre et dans mot de passe on pourrait mettre un min Lens est égal à 6 pour encore plus nous simplifier la vie si je sauvegarde maintenant on peut voir que j'ai une erreur ici parce que mon email est de type email donc je vais remettre un email valide et ici j'ai une erreur native HTML qui me dit que la longueur minimum est de 6 caractères mais si je suis sur noix et que je connais un petit peu mon avig je peux inspecter l'élément dans le body je vais dans la forme et là je rajoute un motclé qui va s'appeler no validate et à ce niveau-là je peux carrément supprimer chaque donnée de mon formulaire et le soumettre et là on voit bien que ça m'a affiché qu'une seule erreur si je retourne en haut de mon action et que je fais un console log sur mon jison data et que je soumets de nouveau le formulaire on peut voir que j'ai un first name qui est un string vide un email qui est un string vide et un password qui est un string vide alors qu'en fait ils n'ont jamais été déclarés si maintenant je rajoute un email un for et un mot de passe et que je veux avoir un first name qui fait au moins deux caractères en disant le prénom doit faire au moins de caractères alors dans ce cas-là si je renvoie mon formulaire avec un novide j'aurai les trois erreurs le mot de passe doit faire plus de 6 caractères le prénom doit faire au moins deux caractères et sur l'email on peut faire encore mieux au lieu de dire que c'est un string on peut rajouter un champ. email avec comme erreur vous devez fournir un email valide on va reprendre la même erreur maintenant je renvoie une dernière fois ce formulaire et on peut voir que j'ai les trois erreurs vous devez fournir une adresse il valide le mot de passe doit faire plus de 6 caractères et le prénom doit faire au moins de caractères là on est vraiment safe côté client on valide plusieurs fois les données on les valide une première fois en html ici en disant que c'est un type email avec une longueur minimum ensuite on les valide côté serveur de remix et si elles sont conformes dans le côté serveur de remix on les revalide dans notre backend avec notre DTO qui est valide une dernière fois maintenant je vais prendre un tout petit peu de temps pour styliser tout ça parce que prés ement c'est très moche voilà je viens d'ajouter un peu le style à notre application et j'ai amélioré quelques trucs je vais vous montrer tout de suite on retourne dans notre fichier_index.tfx et j'ai commenté notre token schéma qui permet de valider la connexion de l'utilisateur on en a plus besoin car on utilise le même schéma que pour la création de compte regardez si nous scrollons ici on peut voir que nous dstructurons les propriétés access token message et error depuis le schéma de token et ce token schema nous l'emportons depuis le fichier register. TSX pour rappel il possède un access token un message et une erreur et ces trois propriétés sont optionnelles c'est-à-dire que si on fait un parce avec Zod Zod ne va pas déclencher d'erreur si les propriétés ne sont pas présentes mais dans le code que nous avons créé nous aurons soit un access token soit un message d'erreur ça ne nous pose donc aucun problème si on retourne dans notre API on peut voir que j'ai fait une petite réfacto de notre méthode login tout à l'heure elle n'était pas englobée dans un try catch et pour être confor forme avec la méthode register j'ai décidé de rajouter un trycatch au cas où par exemple l'utilisateur n'existe pas on pourra donc faire un test tout de suite avec notre adresse email virgile@varcov.fr et je vais rajouter un caractère dans l'adresse email et là on voit le message d'erreur l'utilisateur n'existe pas si maintenant je mets une adresse email valide et un mot de passe erronné on peut voir un autre message d'erreur le mot de passe est invalide et si je mets les bonnes valeurs bien sûr ABC 1 2 3 et que je me connecte là nous sommes connecté sur le dashboard j'ai également utilisé la nouvelle librairie chatcn/ui qui nous met à disposition des composants d'interface très stylé donc pour résumer nous avons implémenté la connexion et la création de compte nous validons les données côté serveur et côté client mais maintenant j'aimerais implémenter deux nouvelles fonctionnalités la réinitialisation de mot de passe et l'envoi d'email à chaque fois qu'un utilisateur va créer un compte ou pour envoyer la demande de réinitialisation de mot de passe nous allons envoyer un mail à l'utilisateur pour envoyer nos emails nous allons utiliser un nouveau service qui s'appelle resend donc nous allons aller sur le site recend.com et nous allons créer notre compte je clique sur Get Started et je vais m'inscrire avec mon compte GitHub je leur donne l'utilisation aux fonctionnalités qu'il me demande et maintenant je vais devoir choisir mon équipe que je vais appeler Virgile et maintenant nous devons créer une clé API pour utiliser le service resend dans notre application on va la générer tout de suite en cliquant sur Add API key et nous allons la copier dans notre backend je retourne donc sur le projet nestjs et je vais rajouter une variable d'environnement que je vais appeler resend API key et entre parenthèses je vais mettre la clé que je viens de générer je retourne maintenant sur resend et on va passer à l'intégration j'ai cliqué sur le deuxième bouton le deuxième bouton est une démonstration qui nous explique comment envoyer un email avec not JS je vais me connecter à mon adresse email pour voir si ça a fonctionné on peut voir que j'ai bien reçu leur email qui vient de wording@reend.dev on peut donc passer à l'étape suivante pour une vraie application on serait aller dans la rubrique domaine et on aurait inscrit notre nom de domaine mais on ne l'a pas encore créé donc pour le moment il va falloir faire 100 je vais donc me rendre dans la documentation cliquer sur notjs quickst et nous allons installer la librairie suivante resend et nous allons l'installer dans notre application nestjs je vais couper le terminal et je vais installer resend une fois installé nous allons utiliser leur deuxième fonction qui permet d'envoyer un email en notdejs je copie ce morceau de code et je vais aller dans le dossier SRC et je vais créer un nouveau service que je vais appeler mailer.service.ts ça sera un service responsable d'envoyer mes emails et je vais tout de suite copier le code que j'ai récupéré depuis resend donc on peut voir qu'on importe resend et on crée une nouvelle instance de resend avec notre clé API puis avec une fonction asynchrone nous envoyons un email depuis resend à l'adresse email de notre choix comme on est sur nestjs nous allons créer une classe qui va s'appeler mailer service nous allons l'exporter je vais donc écrire export classe mailer service et je vais ouvrir les moustaches et dedans je vais créer une nouvelle variable que je vais appeler mailer et qui sera de type resend le type recend c'est l'instance que nous allons créer cette variable sera privée et ne sera accessible que depuis mon service du coup je vais écrire private readonly mailer w.reend je sauvegarde et maintenant je vais créer une méthode constructeur dans laquelle je vais initialiser notre service la méthode constructeur va donc se déclencher quand je ferai une initialisation de ma classe mailer service et ici je vais faire 10 point mailer est égal à New recend et on y mettra notre clé API maintenant on a besoin de la clé API qu'on a sauvegardé dans nos variables d'environnement donc nous allons copier cette clé et nous allons mettre que c'est un new recent de process.om send_api key je vais donc pouvoir supprimer cette ligne maintenant je vais créer une nouvelle fonction asynchrone que je vais appeler send email et cette fonction va exécuter le code suivant avec le trcatch je copie ce code là et je supprime celui-ci et au lieu de faire un await de resend.emails je vais faire un await de dis.mailer.emails.send maintenant nous allons rajouter quelques paramètres notamment l'adresse de destination que je vais appeler re qui sera sous forme de string et que je vais déstructurer ici maintenant au lieu d'envoyer l'email à delivered je vais l'envoyer tout de suite à mon récipient ensuite je vais ajouter un message et je vais dire bonjour Virgile et bienvenue sur nestgs Chat nous sommes heureux de vous avoir parmi nous et en sujet je mettrai bienvenue sur la plateforme vous l'avez deviné ça sera notre email de création de compte et je pourrais même renommer la fonction en send created account email évidemment on peut voir aussi qu'on aura besoin du first name qu'on ne va pas écrire en dur et je vais donc appeler first name en transformant ce string en backtix et je vais même rajouter dans les types le first name à ce niveau-là on va donc maintenant tester ce service pour voir s'il fonctionne donc je vais copier Maur service et je vais retourner dans mon hos.sice à l'endroit où se trouve le code de création de compte mais d'abord il faut quand même qu'on importe le service donc je vais copier cette ligne et je vais l'appeler mailer service dou la classe ma leor service maintenant je vais relancer le serveur pour voir si tout fonctionne bien et normalement c'est censé ne pas fonctionner parce que nous devons importer le service dans le module donc je vais rajouter dans ce module mailer service et je retourne maintenant dans ce service et à la deuxième ligne je vais faire un await de 10.mailer service.send created account email et je vais passer en paramètrre un FirstName qui sera notre first name vu que la variable porte le même nom que le paramètre on n pas besoin de la déclarer et un ré pient qui sera notre email et je vais rajouter un return juste après cette fonction parce que j'ai envie de tester la méthode donc on va ouvrir postman et je vais aller sur ma requête de création de compte register user et on peut voir que j'ai un body avec une adresse email auquel je n'ai pas accès donc je vais mettre une véritable adresse email je vais mettre jacqu et on va envoyer notre email et on peut voir qu'on a un console log de l'ID qui a été envoyé par resend si maintenant on retourne sur la documentation de resend ou plus ô sur l'interface d'administration et qu'on regarde les logs on va voir qu'il y a un email qui a été envoyé il y a moins d'une minute je retourne sur ma boîte mail et je vois que j'ai bien reçu à la bonne adresse avec le bon first name que j'ai défini c'est plutôt cool ça a fonctionner du premier coup donc on retourne sur notre service et on va retirer le return et j'ai plutôt envie d'envoyer ce mail après avoir créé le compte et valider le password donc je vais le mettre juste avant de renvoyer le token d'authentification je vais également ouvrir Prisma donc pour se faire je vais ouvrir une deuxième fenêtre de terminal et je vais aller dans le dossier de mon application et je vais faire NPX Prisma studio pour l'ouvrir et supprimer les utilisateurs que j'ai créé auparavant parce que je n'ai pas accès à ces adresses email donc je vais supprimer tous ces utilisateurs et je vais conserver le seul pour qui j'ai accès à l'adresse maintenant nous allons implémenter notre dernière fonctionnalité d'authentification et ça sera la réinitialisation de mot de passe pour ce faire on va devoir identifier la requête de l'utilisateur avec un token sécurisé nous allons donc retourner dans notre schéma point Prisma et nous allons ajouter deux propriétés la première sera is resetting password qui sera un Bouen avec comme valeur par défaut false et la deuxième sera un reset password token j'ouvre une troisième fenêtre de terminal pour pouvoir effectuer ces changements en base de données je me rends donc dans mon dossier projet et je vais faire NPX Prisma dB push pour faire un commit des changements que j'ai apporté à la base de données on peut voir que les changements ont maintenant été pris en compte et je vais faire un NPX Prisma generate pour regénérer les types de Prisma et pour bénéficier de l'autocomplition maintenant je retourne dans mon service os.sice et je vais copier la méthode login et je vais créer une troisième méthode qui va s'appeler reset user password request parce qu'on ne va pas pouvoir réinitialiser tout de suite notre mot de passe on fait une demande de réinitialisation de mot de passe on envoie un lien de validation par mail l'utilisateur clique sur le lien et il pourra ensuite sur le site initialiser son mot de passe la méthode qu'on crée en premier c'est notre request et elle aura besoin d'un seul paramètre ça sera notre user ID pour pouvoir identifier le user notre user ID se trouve donc sous forme de string et nous allons d'abord réutiliser ce code là pour vérifier que l'utilisateur existe sauf que nous allons faire le weare sur le user ID si l'utilisateur n'existe pas bien sûr on renvoie un message d'erreur et s'il existe on peut passer à la suite et nous allons faire un await de 10.prisma.user et nous allons update le user avec une clé data sur les propriétés suivantes is resetting password qu'on va mettre à trou parce que il est en train de faire une demande de réinitialisation de mot de passe vu qu'il est en train de faire une demande il ne pourra pas faire une autre demande la deuxième propriété sera le reset password token qu'on va générer aléatoirement et notre token sera un qid et le qid si vous vous en souvenez c'est la méthode qu'on a utilisé pour générer l'ID de notre utilisateur on va donc faire une petite recherche Google sur NPM pour generate des qid et on voit qu'il y a une librairie qui s'appelle qid avec un énorme message d'erreur qui nous demande d'utiliser une autre librairie à la place on va donc chercher l'autre librairie et nous allons l'installer dans notre application packend je copie donc cette commande sur le terminal et je retourne sur la documentation pour voir comment ça fonctionne on peut voir donc qu'on peut importer une méthode qui s'appelle create ID et c'est ce que nous allons utiliser je retourne donc dans mon service d'authentification et j'importe la méthode Create ID que je vais copier et ici je vais créer une variable que je vais appeler created id est égale à create ID et je vais assigner cette valeur à mon reset password token bien sûr pour mettre à jour notre utilisateur nous avons également besoin de son ID donc j'ai oublié de rajouter la clé WE avec en ID le user ID et nous allons faire une dernière vérification avant de générer l'ID et de mettre à jour la demande de réinitialisation de mot de passe de notre utilisateur nous allons voir s'il est déjà en train de faire une demande et nous allons le voir de la manière suivante nous allons faire if existing user point is resetting password est égal à true alors nous allons s une nouvelle erreur que nous allons appeler une demande de réinitialisation de mot de passe est déjà en cours maintenant on est très très bien avant de faire le return avec un message de succès nous allons devoir utiliser notre service d'email pour envoyer un email avec notre lien de réinitialisation de mot de passe et nous allons devoir créer la deuxième méthode nous retournons dans le mailer.sice et je vais dupliquer cette méthode là que je vais appeler send requested password email en sujet je vais mettre pour réinitialiser votre mot de passe nous allons faire bonjour firstn voici votre lien de réinitialisation de mot de passe on va faire un double point et on va ajouter un Link qui sera un troisème paramètre de notre fonction en fait je suis en train de me tromper le Link ne sera pas le troisème paramètre le troisème paramètre sera notre token et le Link nous allons le créer directement ici en mettant l'URL de notre frontend pour le moment c'est HTTP doulocalos 3000/ la route s'appellera forgot password et on passera en paramètre un token qui a comme valeur le token que nous recevons comme argument évidemment quand on aura mis le site en prod on aura plus accès à localhost 3000 c'est pourquoi nous allons sauvegarder ce domaine dans une variable d'environnement que nous allons appeler frontend l est égal à http//localhost 3000 que nous remplacerons par notre nom de domaine une fois le site mis en prod je retourne donc dans le service de mailer et je vais ajouter la variable d'environnement process.om.fontend_url maintenant nous retournons dans notre service nous allons remplacer cette méthode par la deuxième méthode que nous venons de créer avec en first name l'existing user.fname en recipient l'existing user.email et en token le created ID que nous venons de créer et d'instancier dans une variable ensuite nous allons pouvoir effectuer un retour à l'utilisateur avec un return error et à false et message état veuillez consulter vos emails pour réinitialiser votre mot de passe pour résumer on commence par vérifier l'utilisateur s'il existe ensuite on vérifie qu'il n'a pas déjà fait une demande de réinitialisation et qu'elle est en cours et ensuite nous créons un nouveau token que nous allons utiliser pour pouvoir autoriser l'utilisateur à réinitialiser son mode passe mais je viens de me rendre compte que nous avons oublié quelque chose dans notre déclaration du schéma Prisma si nous retournons dessus on peut voir que le token de réinitialisation n'est pas unique et il a besoin d'être unique pour pouvoir récupérer l'utilisateur associé à ce token donc je vais copier le as unique de notre email et je vais le rajouter sur notre champ reset password token et on va devoir retourner sur le terminal pour refaire la commande NPX Prisma dB poche pour effectuer ces changements en base de données et nous avons un petit message un petit warning qui nous dit attention vu que vous avez rajouté l'option unique sur cette valeur s il y a des doublons au niveau de cette valeur là nous ne pourrons pas effectuer la migration nous n'avons qu'un seul utilisateur ce n'est pas notre cas donc je vais appuyer sur Y pour dire oui maintenant la migration a été faite et je vais faire un NPX Prisma generate pour regénérer les types maintenant nous allons aller dans notre Haos point controller et nous allons créer une nouvelle méthode donc je vais copier ce code là et je vais l'appeler request reset password et je vais appeler la méthode du même nom request user password et ça va appeler notre méthode qui s'appelle reset user password token au final je vais prendre le même nom de cette méthode pour ma fonction ici et côté client pour demander à l'utilisateur de reset son compte il va devoir nous donner son adresse email donc il va nous envoyer son adresse email dans un formulaire et nous allons la récupérer dans les body nous allons récupérer une propriété qui s'appelle email et que je vais appeler email et ça sera un string en effet l'utilisateur déconnecté n'a pas accès aux id les utilisateurs donc on ne peut pas effectuer une demande sur l'ID je me suis trompé tout à l'heure on va tout de suite modifier cette erreur on va renommer ce champ en email on va également renommer la condition ici et ici et si on retourne sur notre contrôleur on peut voir que cette méthode renvoie forcément une promise avec un message d'erreur potentiellement ou un message de succès on va tout de suite tester cette implémentation je retourne donc sur mon application et je vais créer une nouvelle route donc je vais dupliquer mon fichier register et je vais appeler la route forgot- password cette ot prendra un schéma qu'on va appeler forgot password schema qui prendra en paramètre uniquement l'email de l'utilisateur qui souhaite réinitialiser son mot de passe la réponse du serveur sera un message ou une erreur et cette fois tes champs ne sont pas optionnels il n'y aura pas d'accè token donc je vais renommer le schéma en feedback skima feedback en anglais ça veut dire retour utilisateur donc si vous voulez à chaque action de l'utilisateur j'ai envie d'effectuer un retour pour lui dire écoute ton action elle a réussi écoute ton action elle n'a pas réussi ensuite si on scroll on peut voir qu'on a donc un loadur qui récupère un utilisateur optionnel évidemment si l'utilisateur est déjà connecté c'est qu'il n'a pas vraiment oublier son mot de passe donc s'il est connecté nous le redirigeons vers la page d'accueil sinon nous renvoyons un objet vide l'action on va voir suite après ce que ça donne nous allons supprimer ce code là et je vais appeler le composant forgot password form nous allons donc renommer tous les champs Mot de passe oublier récupération du mot de passe récupérer votre mot de passe et on va uniquement demander l'email de l'utilisateur Récupérer mon mot de passe et nous pouvons supprimer cette partie là on va donc se déconnecter et on va accéder à notre route forgot password et on peut voir notre formulaire avec notre adresse email et le bouton d'action maintenant on retourne sur notre action et ici on va récupérer le premier schéma forg password qui s'attend à recevoir un email et nous allons remplacer le schéma précédent par celui-ci si le parf échoue on renvoie les erreurs de zone et s'il n'échoue pas nous allons contacter la p avec la M méthode que nous avons appelé request reset password je vais changer ce champ là et on lui envoie notre email ensuite nous pouvons utiliser le deuxième schémod qui s'appelle feedback schima à ce niveau-là et il n'y aura pas d'Access token il y aura uniquement un message et une erreur vu que ces champs ne sont plus facultatif on peut supprimer cette condition et on peut supprimer la deuxième condition maintenant nous allons tester tout de suite la requête je vais entrer un email et je vais entrer un email qui n'est pas présent dans la base de données et on va voir le premier message d'Ur l'utilisateur n'existe pas maintenant je vais envoyer mon email et je vais récupérer le mot de passe et là on peut voir en feedback veillez consulter vos emails pour réinitialiser votre mot de passe et maintenant si je refais une demande si je veux spam la PI je clique et on peut voir une demande de réinitialisation de mot de passe est déjà en cours c'est pour éviter que les utilisateurs spamment notre serveur maintenant je vais ouvrir mes mails et je vois que j'ai un lien bonjour AZ AAZ voici votre lien de réinitialisation de mot de passe localhost/ forgod passw et mon token je retourne donc côté client et je vais copier l'URL qui m'a été donné et là nous avons notre token mais comment le récupérer côté client et ben nous allons retourner dans notre méthode loader côté serveur et c'est ici que nous voulons récupérer notre token ici j'aimerais bien récupérer le token que j'ai dans l'URL et ça tombe bien c'est un paramètre d'URL et notre URL nous y avons accès dans notre request je fais un console log de request.url que j'agrandis mon terminal et que je sauvegarde le fichier on peut voir ici que j'ai mon URL qui apparaît dans ma console sauf que moi je veux récupérer les paramètres et pour se faire nous pouvons utiliser la méthode suivante je vais déclarer une variable que je vais appeler URL params et qui sera égale à new url donc la classe URL dans laquelle je passe en paramètre mon url donc request.url et ensuite je vais accéder à la propriété de URL qui s'appelle search params maintenant si je fais un console log de de mes search params on peut voir que j'ai un tableau avec un objet qui a comme valeur mon token et c'est un petit peu comme le form data je peux récupérer la valeur du token en faisant un const token est égal à URL spam.get token maintenant ce token qu'est-ce qu'on peut en faire et ben on va se rajouter un todo vérifier côté serveur que ce token est valide parce que évidemment c'est très simple une fois qu'on connaît la technique si ici je mets par exemple un faux token il n'est pas valide donc on va devoir vérifier côté serveur est-ce qu'il est valide est est-ce qu'il est rattaché un utilisateur si oui on va pouvoir l'utiliser et afficher un formulaire pour qu'il puisse rentrer son mot de passe sinon il ne pourra pas réinitialiser son mot de passe je vais faire page précédente pour récupérer le bon token et je vais copier cette méthode là que nous allons utiliser ici avec notre token pour appeler une route qui n'existe pas qu'on va appeler verify reset password token et comme valeur nous allons renvoyer un objet avec notre token maintenant nous retournons dans notre API et nous allons créer créer cette méthode cette fois ce sera une méthode GET qui aura comme route verify reset password token et on va appeler les méthodes de la même façon verify reset password token ça contient donc un body avec un champ token on va donc renommer notre email en token et ensuite on va aller dans notre service et je vais copier cette fonction là et je vais l'appeler verify reset password token qui prend donc en paramètre un token et là nous allons vérifier si un utilisateur possède une propriété unique du nom de token que nous avons appelé reset password token donc reset password token est égal à token si c'est faux on va donc Serou la même erreur l'utilisateur n'existe pas et cette fois si une demande de réinitialisation de mot de passe n'est pas en cours alors il ne peut pas utiliser ce token pour réinitialiser son mot de passe du coup je vais mettre comme valeur si la demande n'est pas en cours aucune demande de réinitialisation de mot de passe n'est en cours on va mettre des guillemets double parce qu'on utilise une apostrophe et maintenant au lieu de créer un token et de renvoyer un message de succès on va quand même envoyer un message de succès qu'on va conserver pour nous et ça sera le token est valide et peut être utilisé je retourne maintenant sur le contrôleur pour remplacer les arguments de ma nouvelle fonction et je vais supprimer ces terminales si on retourne maintenant côté front on sait que la réponse c'est pareil que pour l'action on reçoit deux propriétés une erreur et un message je peux même copier ce bout de code là en entier et je peux le renvoyer ici du coup au niveau de la vérification nous nous l'avons fait et là nous avons une erreur je vais supprimer ces champs là et je vais englober tout ça dans un try catch que je vais commencer à mettre à partir d'ici hop maintenant si on retourne dans notre composant on a envie de récupérer les informations qu'on a reçu côté serveur notamment est-ce que le token est valide donc je vais utiliser le hook use loader data et je vais le typer en type of loader et je vais récupérer l'erreur et le message mais je ne vais pas l'afficher au client nous allons l'utiliser en interne je vais donc l'afficher dans une feedback qui est un composant que j'ai créé tout à l'heure qui possède donc le même type que nous définissons c'est-à-dire une erreur et un message on a donc un objet feedback qui prend en propriété notre erreur et notre message et là on voit qu'on a une erreur au niveau de notre pars et c'est normal on a oublié de retirer la méthode POST en fait pour vérifier la validité de notre token nous allons faire un get et pour faire un get nous avons quand même besoin de faire savoir à notre serveur quel est le token qui a été utilisé pour cela nous allons donc rajouter un paramètre d'URL qui aura comme nom token et qui aura comme valeur le token on va faire exactement la même chose que nous faisons ici sauf que là nous avons une erreur côté Prisma parce que ça a exécuté la bonne requête avec un token qui n'existe pas on retourne donc sur notre API et au lieu de récupérer dans le body notre token nous les récupérons dans les query et les query paramets c'est ces paramètres d'URL que nous retrouvons donc dans l'URL à partir du point d'interrogation chaque valeur précédant le égal et la clé et chaque valeur suivant le égal et la valeur maintenant je vois que cette méthode renvoie forcément une erreur et un message on va quand même vérifier je retourne dans cette fonction et je vois qu'il y a bien un try catch donc je retourne côté client et j'actualise et cette fois on voit le token est valide et peut être utilisé si le token est valide on va afficher le formulaire pour que l'utilisateur puisse réinitialiser son mot de passe mais si le token n'est pas valide alors il ne pourra pas le faire regardez on va tout de suite modifier le token dans l'URL là je vais effacer plein de caractères et là on peut voir l'utilisateur n'existe pas normal le token n'existe pas donc je retourne maintenant en arrière etci nous affichons tout notre formulaire et ce formulaire là avec le mot de passe je veux seulement l'afficher pour la demande de réinitialisation donc je vais faire un IF error s'il y a une erreur c'est normal c'est la première fois donc je vais faire quelque chose d'assez sympa je vais retourner dans mon loader et le token j'ai envie de le recevoir côté client donc je le rajoute ici et j'enlève le type fort maintenant je peux le récupérer le problème c'est que j'ai fortement typé toutes mes méthodes ici et je ne vais plus pouvoir le faire il faut forcément qu'il y ait un token dans chacune des méthodes pour que not type inféré soit le même maintenant que j'ai retiré le type fort et que j'ai mis un token à chacune des propriétés je peux le récupérer en autocompléant et on va faire quelque chose de très simple par exemple ici si il y a pas de token la route c'est forgot ti password c'est que l'utilisateur est en train de demander à réinitialiser son mot de pass donc je vais mettre if not token ça veut dire qu'il n'est pas en train de faire une demande alors on va afficher ce composant là maintenant on va afficher une deuxième condition if il y a un token et que il y a une erreur ça veut dire qu'il a mis un mauvais token et il ne peut pas mettre un mauvais token s'il met un mauvais token c'est qu'il a trifouillé l'URL et qu'il essaie de tricher et dans ce cas-là nous allons renvoyer notre message d'erreur maintenant on va faire un essai on va retirer cette alerte du coup la première fois que tu voudras réinitialiser ton mod de pass tu seras sur cette page et tu pourras le initialisé mais quand tu cliqueras sur l'URL et que tu auras un token et qu'il est faux tu auras ce message d'erreur c'est veut dire tu peux tout simplement pas réinitialiser ton mot de passe on va quand même être sympa avec l'utilisateur et renvoyer un lien vers l'accueil en utilisant le lien de remix et on va lui dire retourner à l'accueil on va utiliser le style que nous avons créé avec chat CN qui prendra comme variant Ghost pour avoir un bouton stylé comme celui-ci et maintenant notre troisème formulaire dans le même composant si il y a un token et qu'il n'y a pas d'erreur ça veut dire qu'il peut réinitialiser son mot de passe et dans ce cas-là nous allons envoyer le même formulaire ici qu'on va return et on va mettre choisissez votre nouveau mot de passe et il y aura deux champs email donc mot de passe qu'on va appeler password nouveau mot de passe et il y aura une deuxième valeur qu'on va appeler password confirmation confirmation de mot de passe réinitialiser mon mot de passe maintenant on va récupérer le vrai token de R iniisation et là je vois le troisième formulaire à la troisème condition c'est-à-dire nous avons un token et il est juste donc on rvoit en formulaire pour choisir t nouveau mot de passe et là je vais également changer le place holder confirmation du mot de passe maintenant je vais créer un nouveau schéma Zod et je vais m'inspirer du schéma qu'on a dans notre fichier register que je vais copier et je vais supprimer les propriétés qui nous servent t rien et je vais copier la valeur password que je vais appeler password- confirmation et vu que le tiret fonctionne pas bien j'ai deux choix soit le mettre entre guillemets et là la clé sera valide soit le mettre en camel case et je préfère le mettre en camel case je vais modifier ici l'ID à tous les endroits pour le mettre en camel case maintenant nous retournons dans notre action et là on peut voir qui se passe quelque chose d'assez sympa en fait nous avons deux formulaires dans le même fichier alors comment peut-on faire avec remix pour envoyer deux formulairire différents dans le même fichier et ben nous allons rajouter une nouvelle valeur dans le formulaire que nous allons appeler à action et l'action c'est un input qui sera caché pour les utilisateurs et qui aura comme nom action et comme valeur la valeur qu'on souhaite lui assigner et une fois qu'on aura envoyé cette action à remix on sera capable d'exécuter des méthodes conditionnellement par exemple si on effectue l'action renvoyer mon token ça va renvoyer le token et si on effectue l'action réinitialiser mon mod pass ça va le réinitialiser mais pour que ça soit plus parlant nous allons l'implémenter donc la première action s'appelle request Password Reset d'accord donc là c'est la valeur de notre action et comment la récupérer et ben nous allons la récupérer grâce à Zod et pour utiliser Zod nous allons déclarer un troisième schéma que je vais appeler action schima est égal à et c'est un objet qui prend une clé action et la clé action cette fois n'est pas en string mais c'est un enum et nous allons donc faire point enum et ça prend un tableau de clé là je vais mettre la première clé qui s'appelle request password reset et la deuxième clé s'appellera Z password et l'orizet password s'exécutera quand on aura le mot de passe et qu'on voudra le modifier ça sera donc cet écran que nous voyons à droite maintenant je copie cet input dans mon deuxième formulaire tout en bas et cet input sera invisible à l'utilisateur vu qu'on a précisé le type hiidden le name c'est toujours action et la valeur sera reset password maintenant on retourne dans notre action et on transforme donc nos valeurs sous forme de Jon mais avant de parse ce schéma là nous allons par le schéma des actions donc nous allons faire const actions est égal à action schema.ps et nous allons passer comme valeur notre gison data évidemment tout ça s'effectue dans un try catch donc si jamais il y a une erreur de parce nous aurons l'information côté client je vais donc déstructurer les valeurs de ce schéma pour récupérer la valeur action et maintenant on peut traiter le cas de différentes manières on peut soit faire if if action est égal à l'une de ces de valeur personnellement je préfère faire un switch donc je vais faire un switch de action et je vais ouvrir les moustaches et je vais ajouter mon premier case ouvrir les guillemets et là on a request Password Reset là je fais double point et je rouvre les moustaches et maintenant je vais copier ce code là parce que ce code là c'est le code qui demande la récupération du mot de passe maintenant qu'on a ce case on peut rajouter notre deuxième case je vais faire case ouvrir les guillemets et là j'ai ma deuxième action mais donc le double point les moustaches je vais copier quasiment tout ce code parce que ça se ressemble beaucoup à partir de maintenant on va très rarement écrire du nouveau code va juste copier des pages copier des fichiers et c'est un petit peu la même logique à tous les endroits je colle maintenant le code et au lieu d'utiliser le schéma forgot password je vais utiliser le deuxième schéma qui n'est pas celui-ci celui-ci on va le supprimer je vais utiliser le deuxième schéma que je vais renommer et que je vais appeler reset password schéma je retourne dans mon action et je vais changer cette valeur si on reçoit une erreur quelque part on l'affiche et sinon on appelle la requête sur la route reset dir password et ça sera un poste qui contiendra nos de mot de passe ensuite nous recevrons un feedback sous forme de message d'erreur ou de succès je vais sauvegarder ce fichier et je vais tout de suite effectuer une demande alors que nous ne l'avons pas encore implémenté côté bac donc là je vais taper un premier mot de passe bla bla bla et je vais taper un deuxième mot de passe Toto va bien là on peut voir déjà que j'ai fait une petite erreur parce que c'estessensé être en mot de passe mais le champ n'est même pas caché et c'est parce que j'ai mis que le type était de password confirmation alors que le type est de password évidemment les champs autocompli on n a pas pas besoin non plus et là si je fais la demande on peut voir votre mot de passe est rei ce qui veut dire que ça n'a pas fonctionné ça n'a pas vraiment envoyé mon mot de passe j'ai oublié quelque chose on a bien l'input hiidden de reset password et là on a nos deux actions la première action qu'on va retester tout à l'heure et la deuxième action dans laquelle nous faisons un parse avec nos deux mot de passes et si jamais il n'y a pas de succès alors nous renvoyons un message d'erreur et on est à ce niveau-là c'est-à-dire qu'on a reçu un message d'erreur votre mot de passe est requis je retourne donc dans mon composant côté client et je vois que j'ai bien un input avec comme name password et ici un deuxième input avec comme name password confirmation sauf qu'ici on peut voir que j'ai fait une faute de frappe c'est pas confirmation c'est confirmtion donc je vais tout de suite modifier cette erreur confirmation j'enregistre et maintenant je peux faire la demande et là j'ai un autre message d'erreur cette fois il a contacté mon API et il n'a pas trouvé la route mais si on va côté serveur on ne voit pas l'erreur je vais d'abord rjouter une dernière logique à ce niveau-là je souhaite déstructurer mes deux mot de passe depuis l'objet pjason.data et là je vais récupérer un password et un password confirmation et je vais mettre if si les de mot de passe ne correspondent pas forcément on va pas envoyer la requête au serveur donc if password est différent de password confirmation alors on va renvoyer une réponse au format jison une erreur à trou et un message de type les mots de passe ne correspondent pas mais au lieu de renvoyer directement le G vu qu'on a englobé toute notre fonction dans un TR catch qui fait la même chose on peut utiliser une syntaxe différente on va directement st une nouvelle erreur avec notre message dans les parenthèses maintenant on va refaire un essai j'envoie la requête les mots de passes ne correspondent pas maintenant si je remet des mots de passes qui correspondent a a je réinitialise là j'ai de nouveau l'erreur qui signifie que mon serveur tout simplement il ne reconnaît pas cette route donc on va la créer tout de suite on retourne côté serveur dans le host controller et on crée notre dernière méthode sur l'authentification qu'on va appeler reset- password ça sera donc un poste et on va appeler la méthode reset user password il y aura donc un body et nous voulons juste récupérer le mot de passe on n pas besoin de vérifier côté client si les deux mot de passes correspondent donc je vais récupérer la propriété mot de passe et je vais la passer dans les paramètres mais j'ai également besoin d'identifier l'utilisateur avec le token donc pour le faire on peut tout simplement créer un autre DTO je vais copier le DTO create-user.dto je vais le coller et je vais l'appeler reset user-pword je vais le renommer dans le fichier reset user password et il va prendre deux propriétés un mot de passe la confirmation du mot de passe on s'en fout on a confirm côé client c'est suffisant pour nous et un token nous retournons maintenant dans le contrôleur et ici au lieu d'appeler directement la propriété password nous allons récupérer les reset password litio qu'on a appelé reset user password litio et nous allons directement le renvoyer sous forme d'objet maintenant nous allons créer cette fonction là je retourne dans mon service et je vais copier la méthode reset user password request je copie donc cette méthode et je vais l'appeler reset user password elle va prendre en argument un objet nommé reset user password DTO que je vais appeler reset password DTO je le récupère ici et nous allons le déstructurer dans cette fonction pour récupérer les deux propriétés password et token en premier nous allons vérifier que l'utilisateur existe avec le reset password token est égal au token sinon on rvoie un message d'erreur l'utilisateur n'existe pas ensuite nous allons vérifier que l'utilisateur est en train de faire une demande sinon pareil on ne va pas réinitialiser son mot de passe pour des raisons de sécurité donc si la demande est à faux on va mettre aucune demande de réinitialisation de mot de passe n'est en cours pareil je mets des guillemets double au lieu de mettre les simples et maintenant nous allons modifier l'utilisateur à l'emplacement du token et nous allons mettre que la demande de réinitialisiciant de mot de passe est terminée donc on va la mettre à false vu qu'on fait un update sur le user et nous allons également modifier le mot de passe mais pour le modifier nous allons d'abord le hacher donc je vais créer une variable qui va s'appeler HH password est égal à dis.h password et je passe dans mon objet le mot de passe en clair il ne faut pas oublier que H password est une méthode asynchrone donc on va faire un await et nous récupérons le mot de passe haché et nous le persistons dans la base de données ça sera le nouveau mot de passe de l'utilisateur ensuite nous avons pas besoin d'envoyer un mail donc on va supprimer ce code là et nous allons changer le message de succès nous allons mettre votre mot de passe a bien été changé voilà on retourne sur le contrôleur pour vérifier que tout est en ordre et nous allons tout de suite tester cette méthode je retourne donc sur mon backend et je vais taper un vrai mot de passe cette fois je vais taper ABC 1 2 3 4 ABC 1 2 3 4 et nous allons tout de suite je clique sur Réinitialiser mon mot de passe et j'ai une erreur ce qui signifie que ça n'a pas fonctionné et pourquoi ça n'a pas fonctionné à votre avis ben là si nous retournons tout en haut on peut regarder mon action et on peut voir qu'on renvoie notre mot de passe et notre confirmation du mot de passe ce qui est super sauf que moi j'ai demandé dans mon DTO à ce niveau-là j'ai demandé le token parce que on a besoin du token pour identifier l'utilisateur sauf qu'on l'a pas renvoyé côté client donc au lieu de renvoyer la data directement je vais renvoyer mon password et le token sauf que le token est une variable qui n'est pas définie nous l'avons défini dans notre méthode loader donc je vais faire exactement la même chose je vais copier ce code là je vais le coller ici c'est-à-dire que le loader possède comme valeur le paramètre d'URL maintenant ça devrait être bon alors on va submit notre formulaire et là on peut voir que ça a fonctionné vu que ça a fonctionné ça nous a renvoyé un message d'erreur et ça a invalidé ce token finalement parce que il n'y a aucune demande en cours et nous ce n'est pas ce que nous voulions en fait mon erreur c'était de cinder les deux pages j'aurais dû créer deux pages indépendantes une pour réinitialiser le mot de passe et une pour faire la demande de réinitialisation de mot de passe mais si je retourne sur l'accueil et que je tape maintenant mon adresse email avec ABC1 2 3 4 on peut voir que ça fonctionne j'ai réussi à réinitialiser mon mot de passe on en a maintenant fini avec l'authentification j'espère que ça tap plus si on refait un petit bilan de ce qu'on a fait on a donc créé un service d'authentification et on a plein de méthodes on a une méthode pour se connecter pour créer son compte pour Acher un mot de passe et le crypter pour vérifier que le mot de passe scrypté est valide pour authentifier l'utilisateur et le connecter avec un token JWT et pour faire une demande de réinitialisation de mot de passe on vérifie également si le mot de passe est valide et on réinitialise le mot de passe de l'utilisateur et toutes ces méthode on les déclenche dans le contrôleur avec les routes que nous avons créé mais ce n'est que le début maintenant il est temps d'ajouter des features je vais commencer l'implémentation du chat côté serveur API avec nestgs les informations sont présentes dans la documentation officielle nous allons créer un nouveau type de fichier nommé Gateway je vais le placer à la racine de notre projet dans le dossier SRC et je vais le nommer app.getway.ts il aura la même structure que les fichiers que nous avons créés précédemment il se représente sous forme de classe dans laquelle nous allons créer une nouvelle instance de serveur soocket.io nous allons installer trois nouveaux paquets le module WebSocket de nestjs et l'intégration avec la librairie socket.io et nous allons aussi installer la librairie socket.io notre Gateway va au même titre que notre serveur API se lancer sur un port que nous définissons étant donné que nous mettons en place un deuxième serveur qui est un serveur de WebSocket et qui va tourner en même temps que notre API l'adresse URL sera différente on va déclarer le serve WebSocket en utilisant le décorateur @ websocketgateway et ce décorateur prend en premier paramètre le port que nous allons utiliser comme notre application utilise déjà le port 8000 pour la PII nous devons lui assigner un port différent on va donc le lancer sur le port 8001 pour pas qu'il n'y ait de collisions nous allons maintenant ouvrir postman pour voir si l'intégration a fonctionné je vais directement utiliser l'application postman pour créer ma requête car l'extension vscode ne possède pas encore ce feature et je vais créer une nouvelle requête socket.io comme adresse nous n'allons pas utiliser HTTP localhost 8001 car les serveurs WebSocket n'utilisent pas le protocole HTTP ils utilisent le protocole WebSocket ou WS on va donc ouvrir une connexion à l'adresse suivante WS localhost 8001 on clique maintenant sur Connect et on peut voir que le voyant est passé au vert nous pouvons maintenant communiquer avec notre serveur via le protocole WebSocket pour envoyer notre premier message nous devons déclarer une route un peu comme pour nos contrôleurs nous utiliserons le décorateur subs message pour déclarer nos routes avec la technologie webscket les routes portent un autre nom on appelle ça des messages en dessous du décorateur nous allons déclarer une fonction pour notre premier test nous allons l'appeler Send Message elle va afficher un console log à notre application le décorateur subscribe message prend un paramètre la valeur que nous allons utiliser côté client pour communiquer avec notre serveur pour commencer nous allons mettre test on a donc un décorateur WebSocket Gateway qui lance un serveur à l'adresse WS local 8000 et qui est à l'écoute des communications en 30 si une requête est envoyée à notre route test que nous déclarons avec le décorateur subscribe message cela va déclencher la fonction s message qui va afficher notre console log nous pouvons maintenant retourner sur postman pour tester cette intégration je vais devoir me reconnecter en cliquant sur le bouton Connect puis je vais ajouter un message dans le corps de la requête je vais mettre salut les gars et je vais envoyer ce message à l'événement test je peux maintenant envoyer ce message en cliquant sur send si on regarde les de postman on y voit un message sortant ce message contient salut les gars et il a été envoyé à Test retournons dans notre application nestjs pour voir si notre console log est visible ça a bien fonctionné on peut voir le log dans notre terminal comme pour les contrôleurs nous pouvons récupérer les données envoyées par le message entrant ces données sont disponibles dans le corps de la requête nous y avons accès grâce au décorateur message body et de manière similaire à nos contrôleurs on peut utiliser un DTO pour valider les données pour l'instant nous voulons uniquement envoyer les nouveaux messages à notre front-end je modifie né en mooins le console log pour afficher le contenu de notre requête comment peut-on répondre au message qui vient de nous être envoyé grâce au deuxième décorateur nommé connected socket qui est une instance de socket que nous pouvons importer de la librairie socket.io si on retourne sur le site de socket.io pour regarder la documentation la syntaxe d'envoie de message paraît simple nous écoutons toute requête envoyée sur la route connexion et pour chaque de ces requettes nous récupérons le socket donc l'utilisateur responsable de l'envoi de ce message et nous lui renvoyons un message à notre tour avec la méthode socket.emit qui prend deux paramètres le nom de l'événement pour recevoir le message côté client et la donnée que nous voulons lui renvoyer on va mettre en pratique en retournant sur notre application NJS et nous allons rajouter un socket pointemit qui prendra en premier paramètre la valeur chat et en deuxième paramètre salut j'ai bien reçu ton message maintenant si on retourne sur postman on va pouvoir rajouter un événement à écouter je vais dans l'onglet events et je vais rajouter la clé chat pour recevoir la réponse du serveur on peut donc se reconnecter au WebSocket nous allons modifier le message et je vais mettre rebonjour on envoie toujours notre message à l'événement test en cliquant sur send et cette fois on peut voir deux entrées dans les logs la première est l'envoie de notre message rebonjour à l'événement test et la deuxième représente la réponse de notre serveur il a envoyé un message à l'év éement chat qui contient la valeur salut j'ai bien reçu ton message jusqu'à présent ce que nous avons fait n'apporte pas réellement de valeur à notre application si le serveur envoie des messages au clients seulement après avoir reçu notre requête ça ne change pas d'un contrôleur classique la puissance des websckets se trouve quand le serveur envoie un message à un utilisateur sans qu'il n'it rien demandé par exemple pour notre chat on aura deux utilisateurs Virgile et Cédric quand je serai connecté sur le chat en tant que Virgile si Cédric m'envoie un message c'est lui qui va déclencher le webscket le serveur m'enverra la liste des nouveaux messages côté client mais ce n'est pas Virgile qui déclenche cet événement c'est Cédric passons donc à l'intégration du chat j'ai créé de nouveaux modèles de données avec Prisma chaque utilisateur possède 0 1 ou plusieurs conversations une conversation possède plusieurs utilisateurs et plusieurs messages et chaque message est envoyé par un utilisateur dans une conversation ce qui justifie notre déclaration send messages dans le modèle user comme nous utilisons Planet scale pour héberger nos données nous avons dû rajouter deux index à notre modèle chat message les index sont la jointure avec chat ID et la jointure avec thender ID j'ai créé un nouveau module chat dans le dossier du même nom il utilise deux services chat service et Prisma service pour interagir avec la base de données et nous utilisons également un fichier de type contrôleur pour créer nos routes chat controller déclare quatre routes la première est send chat c'est une route protégée par token JWT que nos utilisateurs vont utiliser à chaque envoie de message on utilise la méthode POST qui prend en paramètre une ID de conversation on récupère ce paramètre d'URL avec le décorateur param on récupère aussi le corps de la requettete avec le décorateur body il contient le message envoyé par l'utilisateur que nous validons avec le DTO senchat c'est un objet qui contient une clé content le message ne peut pas être vide il doit faire minimum un caractère ensuite nous récupérons les informations de l'utilisateur connecté grâce au décorateur request qui contient l'ID de l'utilisateur la requête ne contient cet ID seulement si l'utilisateur est connecté nous vérifions son état de connexion grâce aux headers de la requête si un berer token est présent dans la requête alors nous ajoutons la propriété user ID dans notre requête cette route exécute la méthode senchat qu'on retrouve dans le fichier chat service cette méthode effectue de vérification d'abord est-ce que l'utilisateur existe est-ce que la conversation existe sinon une erreur est renvoyée car on ne pourra pas sauvegarder le contenu du message si ces deux valeurs existent nous effectuons un update sur la conversation actuelle et nous créons un nouveau message qui prendra comme valeur le message envoyé dans le formulaire et nous allons faire la jointure sur l'utilisateur qui vient d'envoyer ce message nous faisons ensuite une sélection des propriétés de notre conversation pour y récupérer les messages triés par ordre croissant c'est cette méthode que nous allons mettre à jour on peut rajouter un todo après chaque nouveau message sauvegardé on peut renvoyer une notification à l'utilisateur ayant reçu ce message le service contient deux autres méthodes GET conversation au pluriel qui prend en paramètre un user ID qui vérifie si l'utilisateur existe et dans ce cas on renvoie un tableau de conversation chaque conversation possède un tableau de messages et chaque message possède un contenu et un utilisateur l'ayant envoyé nous avons finalement la méthode g conversation au singulier qu'on utilise pour récupérer les informations d'une conversation unique de l'utilisateur nous vérifions d'abord l'existence de l'utilisateur puis nous récupérons les informations de la conversation ces deux méthodes sont appelées dans notre chat controller qui pent des routes du même nom ce sont également des routes protégées car nous récupérons des informations privées de l'utilisateur nous avons une dernière méthode Create conversation qui va nous permettre en tant qu'utilisateur de créer une nouvelle conversation avec un autre utilisateur regardons maintenant l'implémentation du chat côté frontend on va uniquement s'intéresser à l'implémentation des web sockets si tu es curieux j'ai rajouté le lien du repipo dans la description nous avons créé une nouvelle page avec paramètres dynamiques à l'URL conversation/ l'ID de la conversation c'est sur cette page qu'on peut envoyer des messages à nos utilisateurs et c'est dans ce composant que nous allons écrire notre logique webscket pour mettre à jour le chat on va donc analyser ce fichier c'est une route protégée qui est accessible pour les utilisateurs connectés nous récupérons le paramètre dynamique qui correspond à l'ID de notre conversation cela nous permet de charger les derniers messages de cette conversation côté serveur ensuite côté client nous déclarons un composant nommé chatbox ce composant prend plusieurs paramètres les messages la conversation et la méthode 7 message cette syntaxe est très importante pour la suite on est obligé de stocker notre tableau de message dans un US state et nous le faisons parce que nous avons besoin de la méthode 7 messages pour afficher les nouveaux messages côté client que le serveur nous envoie via les websckets avant d'implémenter socatio nous allons d'abord tester l'envoie des messages on lance le serveur de remix avec la commande NPM rundev puis on va cliquer sur le bouton Envoyer un message à Cédric cela va créer une nouvelle conversation ensuite nous allons sur la page de cette conversation et nous allons envoyer un premier message salut mec le message apparaît instantanément dans le chat si on actualise la page on peut voir que le message est toujours présent il a bien été sauvegardé en base de données passons maintenant à l'implémentation des websckets nous avons écrit un commentaire dans notre chat service c'est à ce niveau-là après avoir sauvegardé le nouveau message en base de donné que nous allons envoyer l'événement au front-end pour ce faire nous avons besoin d'accéder au socket pour pouvoir faire un socket pointemit mais ce n'est pas possible de le récupérer dans ce fichier cependant nous pouvons déclarer une nouvelle variable dans le fichier app.gateway.ts au-dessus de notre première fonction nous allons appeler un nouveau décorateur nommé WebSocket Server il nous donne accès au serveur WebSocket que nous stockons dans une variable nommée serveur et ce serveur possède les mêmes méthodes que la socket notamment la méthode emit que nous allons utiliser dans le service mais nous n'allons pas directement importer le fichier upgateway dans notre service nous allons plutôt créer un nouveau service nommé socket.service.ts on le place dans un nouveau dossier nommé socket à l'intérieur de ce service nous allons déclarer une nouvelle variable publique nommée serveur elle va hériter de la classe serveur qu'on importe depuis socket.io comme nous ne faisons pas d'injection de dépendance cette variable est initialisée à undefined nous allons maintenant retourner dans le fichier app Gateway TS et nous allons ajouter un constructeur qui va injecter le nouveau service socket service ce que nous voulons faire c'est après avoir initialisé notre fichier upgateway et lancer le serveur WebSocket nous voulons assigner la valeur du serveur à la variable serveur de notre socket service pour cela nous allons implémenter une classe spécifique au websckocket qui s'appelle on Gateway init cette classe nous permet de déclarer une nouvelle méthode nommée after unit la logique de cette méthode sera exécutée après l'initialisation de notre Gateway quand le Gateway sera initialisé nous allons assigner une nouvelle valeur au serveur de notre socket service ce serveur sera égal au serveur de notre fichier upgateway qui lui est défini maintenant notre terminal nous affiche des erreurs il va falloir ajouter notre nouveau service dans un module au lieu de l'importer directement dans le fichier app.module nous allons créer un nouveau module nommé socket.module.ts ce module aura la particularité de déclarer en provider notre socket service mais il va également l'exporter ensuite pour pouvoir utiliser notre socket service dans n'importe quel fichier nous allons déclarer notre module en global avec le décorateur @as global on sauvegarde et on peut voir que les messages d'erreur ont disparu c'est une une manipulation compliquée mais c'est le seul moyen que j'ai trouvé pour pouvoir accéder au serveurs WebSocket dans tous nos fichiers si tu as une meilleure implémentation n'hésite pas à le partager en commentaire nous pouvons maintenant retourner dans le fichier chat service et nous allons importer notre nouveau socket service dans le constructeur afin de pouvoir l'utiliser nous allons scroller jusqu'à notre méthode Send Message et après avoir sauvegardé les messages en base de données nous allons effectuer un limite en utilisant la méthode du serveur WebSocket le premier paramètre sera la valeur send chat Update et le deuxième paramètre sera notre nouveau tableau de messagees nous allons ons aussi ouvrir Prisma pour récupérer une ID de conversation nous en avons besoin pour tester l'intégration sur postman ensuite retournons sur l'application postman dans la vidéo précédente nous avons créé plusieurs requêtes pour communiquer avec notre API nous allons maintenant dupliquer la requête register user et la renommer en S message la nouvelle route sera localos 000/chat et mon ID de conversation comme c'est une route protégée nous avons besoin de nous connecter à notre compte pour cela nous avons cliqué sur la requête login pour se connecter on vérifie bien que l'URL soit localost 8000 /hos/login et que le body soit bien composé d'un email et d'un mot de passe valide on envoie cette requête pour récupérer notre token d'authentification nous copions maintenant ce token dans notre requête Send Message on clique sur la requête puis dans l'onglet autorisation on sélectionne barer token comme valeur de token nous pouvons copier notre token nous allons maintenant modifier le corps de la requête on va cliquer sur l'onglet body puis on remplace les données actuelles par un objet qui contient une clé content et comme valeur notre message je vais mettre hello testons cette requête une première fois on l'envoie et nous avons une réponse positive du serveur votre message a bien été envoyé testons ensuite l'implémentation des WebSockets retournons sur notre Requet WebSocket sur pastman dans l'onglet events on va rajouter la nouvelle clé send chat Update et nous allons l'activer ensuite nous allons nous reconnecter au serveur en cliquant sur Connect nous sommes obligés d'être connectés pour pouvoir recevoir les messages de notre API maintenant que c'est fait nous retournons sur la requête s message pour envoyer un deuxième message le contenu sera ça va nous allons envoyer la requettete maintenant retournons une dernière fois dans notre requête webscket on peut voir une nouvelle entrée dans les logs il y a un message entrant provenant de la clé schat update avec comme valeur notre tableau de message au format jison ce tableau de message contient nos messages mis à jour et la requette postman représente ce que nous allons développer côté client dans notre application frontend nous allons également nous connecter au serveur WebSocket écouter les communications en 30 nous inscrire à l'événement schat Update et à chaque envoie d'un nouveau tableau de message nous allons exécuter notre state SEP message pour mettre à jour les messages côté client pour se faire retournons sur notre application react nous allons créer un nouveau hook et un nouveau contexte de WebSocket on va l'appeler US soocket.tsx par convention nous allons le placer dans un dossier HX tout d'abord utilisons la méthode Create contexte nous allons sauvegarder cette méthode dans une variable nommée contexte ensuite déclarons une fonction nommée use socket cette fonction va renvoyer la méthode use contexte qui prendra comme paramètre notre contexte nous allons exporter cette fonction pour la réutiliser dans notre composant en ensuite nous allons créer notre provider c'est le composant parent qui donnera accès à toutes les valeurs du contexte au composant enfant nous allons donc déclarer un nouveau composant socket provider qui va accepter un paramètre sous forme d'objet ce sera le paramètre children de type react node le children représente n'importe quel composant enfant à l'intérieur de notre socket provider cette fonction va renvoyer le composant contexte. provider avec à l'intérieur la valeur de Children pour mieux comprendre nous allons nous rendre dans notre composant rot et englober toute notre application dans notre nouveau socket provider ça nous donnera accès au webscket dans l'ensemble de notre application de la Navar jusqu'à chacune de nos pages maintenant nous allons installer la librairie socketo dans notre application en ouvrant le terminal et en lançant la commande npmi de soocket.io-cient ensuite nous devons retourner dans notre fichier use socket pour importer le type socket depuis la librairie socket.io-cient et nous allons typer notre méthode Create context qui prendra comme type générique un objet avec une clé socket de type socket ou nul en valeur par défaut nous allons mettre que socket est égal à nul maintenant nous devons ajouter la valeur du contexte dans notre provider ce provider possède une propriété nommée value qui va contenir le type que nous avons défini par défaut c'est un objet qui contient une clé socket et pour l'instant nous allons la mettre à nul ensuite nous allons créer la connexion au serveur de WebSocket et assigner cette valeur là à notre provider dans notre composant socket provider nous allons rajouter un state qui prendra le type générique socket ou nul nous pouvons maintenant dstructurer notre state pour récupérer deux valeurs socket et C socket et nous allons tout de suite remplacer la valeur du provider socket = nul par socket = socket maintenant nous devons assigner la bonne valeur à notre socket pour ce faire nous allons utiliser le hook use effect et nous allons déclarer une nouvelle variable nommée created socket cette variable est égale à la méthode io que nous allons importer depuis la librairie socket.io- client la méthode io prend un paramètre et ce sera l'URL de notre serveur WebSocket on va mettre la valeur enure pour l'instant notre serveur est accessible à l'adresse WS localhost 8000 maintenant au premier rendu de notre composant le use effect va déclencher la méthode io ce qui ouvrira une requête vers notre serveur WebSocket nous devons maintenant changer la valeur de notre use state nous allons dire que cette socket est égale à created socket ce qui modifie la valeur de notre socket qui sera maintenant initialisé et accessible dans tous nos composants ensuite on peut utiliser notre crate de socket pour s'inscrire aux événements de notre serve AP l'événement qui nous intéresse c'est le schat update auquel on pourra s'inscrire en utilisant la méthode created soocket.on mais on ne va pas le faire tout de suite en effet pour une application avec des centaines de pages on ne va pas s'inscrire au notification de message si on n pas par exemple sur notre page de messagerie par contre nous allons indiquer au serveur que nous sommes connectés pour se faire nous allons émettre notre première notification côté client avec un CRE socket.emit qui prendra comme valeur le string connexion pour connaître l'état de notre con connexion au serveur API on va déclarer un deuxième state ce sera un bouléin qui s'appelle is socket connected on va donc dstructurer les deux valeurs de notre hook et nous allons écouter les notifications sur deux événements le premier sera une confirmation de connexion avec la clé confirmation je vais donc écrire socket.on confirmation et en fonction de callback nous allons mettre set is socket connected à TR donc si le serveur nous envoie la notification confirmation c'est que la communication fonctionne bien on donne la valeur à trou à notre bouléin is socket connected on va écrire la même logique pour la déconnexion si le socket nous envoie une notification au mot-cé disconnect qui est un mot-cé réservé de la librairie soocket.io et qu'on a pas besoin de déclarer alors dans ce cas nous allons mettre set is connected socket à false comme nous sommes dans un use effect nous allons créer deux méthodes qui vont respectivement assigner ce hook à true et à false la première fonction englombera la connexion et va s'appeler handle confirmation et la deuxième va s'appeler handle disconnect maintenant qu'on a ajouté ces méthodes nous pouvons renvoyer une cleanup fonction à react pour désactiver l'exécution de ces méthodes avec un socket point off qui prendra en paramètre le mot clé et notre fonction nous allons également remplacer les méthodes callback de nos socket.on par la méthode que nous venons de créer et finalement nous allons afficher le statut de notre état de connexion à tous nos composants nous allons rajouter dans notre composant socket provider un span qui sera positionné de manière fixte en haut à droite de notre écran et il va afficher l'indicateur de connexion avec internair si le socket est connecté nous affichons un cercle vert sinon N nous affichons un cercle rouge maintenant on sera informé côté client de notre état de connexion avec le backend évidemment en production nous n'avons pas envie d'afficher cet indicateur et vous n'êtes pas obligé de l'inclure personnellement je l'affiche conditionnellement dans les environnements de staging nous devons aussi modifier une ligne côté serveur API comme nous communiquons du localost 3000 au localost 8000 nous devons activer les cores on retourne dans le fichier app.gateway.ts et on modifie la déclaration du WebSocket Gateway qui prend un deuxième paramètre nous allons mettre une étoile pour dire que nous autorisons les requêtes depuis toutes les origines j'aimerais aussi qu'à la connexion du serveur API il envoie une notification de type confirmation à notre frontend pour cela nous allons retourner dans notre fichier app.gateway.ts et implémenter une nouvelle classe nommée on module init cette méthode est utilisée à l'initialisation du module et nous allons émettre une notification de type confirmation à notre front-end avant de continuer nous allons remplacer notre URL du serveur WebSocket écrit en de par une variable d'environnement on se rend le fichier point en de notre frontend et on rajoute une clé websocket_url = WebSocket localhost 8001 quand on mettra en prod ça sera beaucoup plus simple ok donc on a créé notre hook use socket maintenant il est temps de l'utiliser sur la page de chat sur notre page de conversation on peut maintenant utiliser le hook US soocket qu'on va importer du fichier usocket.tsx nous dstructurons les valeurs pour récupérer le socket et nous allons écouter l'événement schat update dans un use effect on va créer un nouveau use effect qui aura notre socket dans son tableau de dépendance nous allons effectuer un early return au cas où le socket soit égal à nul et nous allons rajouter notre événement avec un socket.on send chat update cette fonction prend comme deuxième paramètre une fonction callback qui contient la donnée on sait que cette donnée représente notre tableau de message mais nous allons quand même tester l'intégration avec un console log on envoie un nouveau message et on peut voir dans les logs le tableau de message mis à jour ça fonctionne bien maintenant nous allons utiliser un schéma Z pour valider les de est reçu par le serveur nous l'avons déjà déclaré au-dessus de notre fichier c'est un tableau qui contient une ID un contenu et un utilisateur nous allons donc faire un parce de notre objet reçu à l'intérieur de la méthode callback de notre socket on sauvegarde ces messages dans une variable nommée updated messages ensuite nous pouvons utiliser la méthode set messages pour mettre à jour nos messages et les afficher sur notre page maintenant il est temps de réellement tester l'implémentation nous allons ouvrir une fenêtre de navigation privée et nous connecter en tant que Cédric si tout fonctionne bien notre utilisateur Virgile verra les messages de Cédric en temps réel sur le chat on envoie le message je te reçois 5 sur 5 et on peut voir dans le terminal le console log ainsi que le message qui vient d'être mis à jour sur la vue ça a bien fonctionné mais on n pas encore fini avec cette implémentation dans l'état nous n'avons qu'une seule conversation donc l'envoi de nos messages ne pose aucun problème ils ne seront envoyés qu'aux utilisateur appartenant à la conversation mais dans une application réelle nous avons plusieurs messageries privées et nous devons trouver un moyen de dire à sockettillo de n'envoyer l'événement qu'aux utilisateurs appartenant à cette conversation nous allons utiliser le concept de rooms qu'on peut traduire par salle effectivement chacun de nos utilisateurs se connectant à une conversation va rejoindre la salle qui prendra comme valeur l'ID de la conversation si deux utilisateurs sont connectés au même moment dans la même conversation et dans la même salle ils pourront communiquer entre eux en temps réel pour se faire nous allons rajouter un événement on va demander au serveur de nous connecter à la salle dans notre use effect nous allons rajouter un socket.emit join chat room avec comme clé join chat roomom et comme valeur l'ID de notre conversation on retourne maintenant dans notre API pour modifier le fichier app.gateway.ts et on va dupliquer la méthode test pour ajouter un nouvel événement et c'est celui qu'on a nommé join chatroom il contient comme valeur l'ID d'une conversation et quand cet événement est déclenché nous allons prendre le socket associé qui nous permet d'identifier l'utilisateur et nous allons le faire rejoindre la room avec la méthode socket.join et l'ID de la conversation le socket rejoindra automatiquement la salle sélectionnée lors du chargement de la page du chat mais nous devons aussi modifier le fichier chat.sice.s car la méthode server.emit communique toujours à tous les sockets connectés nous allons préfixer la méthode emit par la méthode point2 qui prendra en paramètre l'ID de la salle en question qui est donc l'ID de notre conversation nous pouvons maintenant retourner sur le front end et renvoyer un message de chat ça fonctionne toujours mais cette fois seuls les utilisateurs connectés à ce chat seront notifiés voilà comment j'implémente les websckets dans Mes applications netgs pour héberger nos fichiers et ça peut être tout types de fichiers comme des images ou des PDF nous aurons besoin d'un serveur pour les stocker et pour cela nous allons utiliser Amazon S3 je me trouve actuellement sur le site de AWS et je vais cliquer sur sign in ça va me connecter à mon compte et je vais utiliser le service S3 on peut voir que je possède déjà deux buckets et ces bucket représente les sortes de disques dur que nous allons utiliser pour héberger nos images je vais donc créer un nouveau bucket que je vais appeler nest js- chat pour la région on va rester sur Paris et on va laisser les paramètres par défaut c'estàdire qu'on va bloquer tout accès au public et nous allons créer ce bucket on va maintenant cliquer sur ce bucket et on peut voir qu'il y a plusieurs onglet les objets qui sont les fichiers qu'on a stocké les propriétés les permissions les métriques et le management mais ce qui va nous intéresser c'est de copier ce string là l'Amazon resource name plutôt ARN je vais copier ce string et je vais maintenant aller dans la barre de recherche je vais tapeler IAM qui est un service d'Amazon qui va nous permettre de donner accès à ce bucket avec l' P je vais cliquer sur users et je vais créer un nouvel utilisateur que je vais appeler nestgs chat manager ensuite je vais cliquer sur Next et je vais cliquer sur attach policies directly ce qui nous permet de choisir les permissions qu'on va attribuer à cet utilisateur et je vais taper S3 et là on trouve Amazon S3 full access et je vais vais cocher cette entrée ensuite je vais cliquer sur Next on n pas besoin de lu assigner de tag donc on va cliquer sur Create user une fois créé je vais cliquer dessus on se retrouve sur les permissions et je vais aller dans l'onglet security credentials et là on peut voir qu'il y a les access Keys et nous allons créer une nouvelle clé d'accès donc je vais cliquer sur Create access Keys et je vais cocher application running outside AWS ensuite nous allons cliquer sur Next et nous allons décrire ce token de sécurité je vais l'appeler JS chat token et je vais créer la clé d'accès et là on peut voir que nous avons deux clés une access key et une secret access key je vais donc copier ces deux clés et les coller dans mes variables d'environnement je retourne sur mon projet nejs et je vais rajouter la première clé access key et la deuxième clé qui sera la secret access key maintenant on retourne sur AWS et on clique sur Don on a un message de confirmation qui nous dit qu'on n pas encore téléchargé notre secret key on est les a copié dans notre point en et ça va nous suffire je vais cliquer sur Continuer maintenant je vais retourner sur S3 et j'auraai besoin de copier le nom du bucket nestjs chat qui s'appelle donc nestjs- chat je vais également copier cette information dans mon point en et nous avons une dernière information à copier ça sera la région AWS et on peut voir que c'est eu- west-3 donc on va mettre region name est égal à eu west/3 et je vais tout de suite renommer ces clés pour préciser dis que ça vient d'AWS je vais mettre aws_acess key celle-ci je vais l'appeler aws_seret ces deux dernières je vais les appeler aws_bcket name et region je vais plutôt l'appeler région maintenant qu'on a fini de configurer S3 chez AWS il est temps de télécharger la librairie pour l'utiliser avec JavaScript on va donc faire une recherche Google et on va taper AWS S3 with nots et on va cliquer sur le premier lien de la documentation et tout en haut on a une alerte qui nous dit que le SDK daws pour JavaScript donc la version 3 et une refondte de la version 2 avec des nouveaux features notamment une architecture modulaire personnellement j'utilise la version 3 donc je vais cliquer sur ce guide et je vais cliquer sur le lien du sommaire using the SDK with notjs une fois sur cette page nous allons aller tout en bas et nous allons cliquer sur la première ressource Amazon SDK for JavaScript V3 aper reference guide on clique dessus et nous voyons les services sur la gauche l're formation dininamo dB et S3 je clique sur S3 et on peut voir notre guide pour installer le client S3 depuis la WS FDK je vais tout de suite copier cette commande nous allons retourner sur notre backend ouvrir un terminal et on va entrer la commande NPM install de awssdk/cient S3 maintenant on va pouvoir commencer à implémenter S3 dans notre application on retourne donc sur notre application netgs et je vais créer un nouveau service que je vais appeler aws-s3.sice .s et je vais le rajouter dans un dossier nommé AWS nous allons donc exporter une nouvelle classe qu'on va appeler AWS S3 service et nous allons créer notre client qui nous permettra de nous connecter à S3 il y aura bien sûr un constructeur dans lequel nous allons effectuer la logique on va donc déclarer une nouvelle variable qu'on va appeler client et qui sera égale à un new S3 client et là on peut voir avec l'autocomplession qu'il me suggère d'importer S3 client depuis AWS SDK client S3 et c'est ce que nous allons faire et cette classe va prendre quelques paramètres par exemple des credentials qui sera donc notre mot de passe pour se connecter nous avons donc une access key ID qui sera notre clé et notre secret access Sky qui sera notre secret et il nous faudra également préciser notre région et nous avons sauvgardé toutes ces données dans notre variable d'environnement on va donc récupérer tout ça nous avons donc AWS Access qui est égal à process.on.awsacess nous avons notre AWS secret qui est égal à process.on.ws secret et nous avons notre région qui est égale à région on va donc mettre l'acess ski ici le secret ici et notre région ici et nous allons sauvegarder ce client dans une variable privée qui sera uniquement accessible au sein de ce service et qui s'appellera également client et on va donc inférer le type depuis S3 cl client maintenant on dira que 10. client est égal au client que nous venons de créer maintenant j'aimerais tester l'implémentation d'ws S3 pour voir si ça fonctionne donc ce que nous allons faire c'est que nous allons rajouter un nouveau feitter à notre application c'est pouvoir ajouter un avatar à notre compte pour cela on va nous rendre dans le user service et nous allons créer une nouvelle méthode je vais copier celle-ci et je vais l'appeler update user et ça sera une méthode qui nous permettra de mettre à jour notre utilisateur et nous prendrons donc un objet data et nous modifierons une clé que nous allons appeler avatar URL maintenant il faut également que ce changement se reflète en base de données nous allons donc modifier le schéma Prisma et on va dire que nos utilisateurs ont maintenant accès une nouvelle propriété et nous allons appeler ça avatar file key et ce file key c'est l'identifiant unique de notre fichier je vais ouvrir un deuxième terminal pour sauvegarder ces changements en faisant un NPX Prisma TB poche et nous allons accepter le warning et ensuite nous allons dire que notre avatar qui est égal à string le string étant le fichier que nous mettrons à jour chez AWS maintenant on va retourner dans le contrôleur des utilisateurs et nous allons créer cette nouvelle méthode ça sera donc un post qui se fera sur l'ID de l'utilisateur et nous allons appeler la méthode Update user ça sera une méthode asynchrone qui appellera également la méthode Update user de notre service nous allons également ajouter la protection pour que seuls les utilisateurs connectés puissent accéder à cette route et modifier leur profil je vais donc rajouter un hos garde prendra comme paramètre le GWT hosgarde comme c'est une route protégée nous allons utiliser garde qui sera notre garde JWT donc je déclare le décorateur ususe Guard et ce gardien va utiliser le JWT hgarde ce qui va nous permettre d'accéder aux données de l'utilisateur dans la requête cet utilisateur on y accède avec notre requê qu'on va nommer request with user et qu'on va typer par notre type request with user maintenant nous n'avons plus besoin de récupérer l'id de l'utilisateur dans l'URL donc je vais supprimer ce paramètre et nous allons dire que ça sera un poste directement sur users le user ID nous le récompierons depuis notre request with user.user.userid et dans cette requê nous aurons également un body pour récupérer notre fichier je vais donc appeler ça updated user data et on va pour le moment typer ça à unknown vu que nous n'avons pas encore créé le dtoo et j'aimerais faire un console log de mon updated user data nous allons maintenant ouvrir postman et accéder à notre nouvelle requête d'abord nous allons nous connecter nous allons donc sur la requête qui fait un post sur le localost 8000/hos/login et nous allons voir dans le body que nous avons deux champs un email et un mot de passe qui va nous permettre de nous connecter mon email maintenant que je suis connecté je vais récupérer l'access token et je vais dupliquer cette requête qui sera notre poste pour modifier l'utilisateur notre nouvelle route est donc un poste sur users et nous avons besoin dans authorisation de rajouter le brr token là je vais copier le token et nous allons tester ce poste on peut voir dans la console qu'il y a bien le console log que j'ai affiché dans le user controller mais au lieu d'envoyer du gison en RAW nous allons utiliser le form data qui nous permet comme le gison d'envoyer des données en clé valeur mais ça nous permet de choisir le type de fichier là on peut voir que le type de fichier est du texte mais on peut sélectionner file et c'est ce que nous voulons faire je vais également aller sur unsplash pour télécharger une photo au hasard celle-ci FAA la faire et maintenant on retourne sur postman et dans File je vais sélectionner le fichier que je viens de télécharger qui est cette photo là et c'est une photo au format avis et maintenant on va renvoyer la requête et on va voir que notre console log n'affiche plus rien ou plutôt il affiche un objet vide mais alors comment récupérer le fichier que nous venons d'envoyer nous allons retourner sur notre user controller comme nous utilisons Express nous allons utiliser une syntaxe particulière pour récupérer le fichier nous allons utiliser un nouveau décorateur qui s'appelle use Interceptor et ce décorateur va prendre en paramètre notre intercepteur et l'intercepteur va nous permettre d'intercepter le fichier que nous venons d'envoyer nous allons donc prendre le file Interceptor que nous allons importer depuis nestgs/plateformexpress et cet Interceptor prendra comme clé la valeur de notre fichier pour le moment nous allons l'appeler file ensuite nous allons retourner dans notre requête sur localhost et là je vais rajouter une clé à notre fichier que je vais appeler file maintenant nous allons retourner dans notre contrôleur et nous allons utiliser un troisième décorateur qui s'appelle uploaded file nous allons récupérer notre fichier que nous enons nommé et nous allons le console loguer on retourne sur pastman on renvoie la requête et là nous pouvons voir que notre fichier a bien été récupéré nous avons plusieurs informations sur le fichier nous avons donc le type de fichier le nom du fichier le buffer qui est le stream de l'image et même sa taille mais si on retourne dans notre contrôleur on peut voir que ce fichier n'est pas du tout typé on peut voir même qu'il a le type de en et ça je suis vraiment pas fan donc nous allons utiliser Zod pour parcer ce fichier je vais donc faire NPM install de la librairie Zod et je vais me rendre dans le dossier SRC pour y créer un nouveau fichier que je vais appeler dirutiles.ts et dans ce fichier je vais créer un schéma qu'on va appeler file qui sera un objet Zod qui aura comme propriété les propriétés que nous venons de voir il y aura donc une size qui est un number il y aura un buffer qui est une instance de buffer il y aura également un file name qui sera sous forme de string et un mind type qui sera sous forme de string maintenant ce schéma je vais l'exporter et nous allons tout de suite l'utiliser dans notre contrôleur avant d'aller plus loin je vais donc déclarer une n nouvelle variable qu'on va appeler submed file est égal à notre schéma pointps le fichier de NGS et nous allons maintenant effectuer un console log de ce fichier nous allons réexécuter la requettete sur postman et on peut voir qu'on a une erreur on a sûrement fait une faute de frappe quelque part mais on va débugger ça tout de suite on peut voir que c'était pas file name mais field name maintenant que la faute est corrigée nous allons réessayer notre parce je renvoie la requête et là on peut voir que ça a été parsé par Z et c'est super cool parce que maintenant notre fichier est typé maintenant qu'on a ce fichier on va pouvoir l'héberger sur S3 et on va le passer en argument dans notre fonction ate user la fonction obdate user prend un deuxième paramètre qui s'appelle submitted file et cette méthode va hériter de notre type typeof file schema nous récupérons maintenant notre fichier ici et nous allons faire appel à notre service AWS S3 service que nous n'avons pas encore importé on l'importe donc dans le constructeur private readonly WSS3 service qui prend la classe AWS S3 service il faudra bien sûr aller dans le module pour importer ce service WS S3 service et vu qu'on utilise le user service également dans le deuxième module host module il faut aussi importer le AWS S3 service dans notre haosse module maintenant que c'est fait on a besoin de modifier notre S3 service pour créer une fonction qui va nous permettre d'uploader notre fichier la fonction sera donc asynchrone et nous allons l'appeler upload file et cette fonction prendra en paramètre un fichier le type file et on va encore une fois inférer le type depuis notre schéma method type of file schema et pour héberger un fichier chez AWS nous allons créer une put object command pour ce faire je vais créer une nouvelle variable qu'on va appeler put object est égale à New put object command et là on peut voir qu'on a l'autocompltion et nous allons apporter cette classe put object command depuis AWS SDK client S3 cette classe va prendre en paramètre des options comme le nom du bucket la clé unique de notre fichier et le content type pour bien dire que c'est soit un PDF soit une image le content type sera donc égal à notre file m type le bucket nous l'avons sauvegardé comme variable d'environnement c'est égal à process.inv.wsbcket name et pour notre clé nous allons utiliser la librairie qui nous a permis de créer des tokens donc nous allons utiliser un co ID on avait déjà généré des ID uniques dans notre hos.sice en utilisant la méthode Create ID donc nous allons copier ce morceau de code ici je vais importer la méthode Create ID depuis la librairie on va dire que la clé est égale au nom du fichier y compris l'extension mais d'abord rajouter notre ID unique si on est malin on peut même rajouter une clé cach contrô pour ajouter le cache à notre image mais là on oublie quelque chose d'assez important il faut également héberger l'image et l'image elle va être contenue dans le body comme image nous allons rajouter notre buffer une fois que nous avons notre put object command que je vais renommer un put object command nous pouvons utiliser le client S3 avec un disque cent S3 pour envoyer avec la méthode Send notre fameuse commande et là je vais donc renvoyer le put object ensuite on va sauvegarder la réponse d'Amazon dans une variable result et amazon va nous renvoyer une réponse avec un statut comme toutes les API mais celui-là est présent dans le metadata on va dire que s'il n'est pas égal à 200 on a un problème et on va afficher un console error de notre résultat une fois que le fichier a été hébergé nous allons pouvoir renvoyer la clé unique que nous avons créée ici je vais l'appeler file Key est égal à cette clé unique et nous allons la renvoyer pour pouvoir la sauvegarder dans notre base de données maintenant que c'est fait on va retourner dans notre user service et on va exécuter la méthode upload file avec comme fichier notre submitted file et nous allons récupérer la propriété file key que nous allons ensuite sauvegarder dans la base de données maintenant on va retourner sur pastman et on va tester cette requête on envoie donc notre requête et on peut on a une erreur au niveau des codes d'accès d'ws l'erreur vient peut-être de notre part donc on va vérifier que les points en ont bien été nommés on a donc un AWS access Sky un AWS secret et un AWS région je retourne dans le fichier on a bien l'access Sky le secret et la région on va rajouter quand même une petite condition if AWS accesskii est égal à nul alors on vaou une erreur invalide accè ski on va faire la même chose pour nos autres variables d'environnement la région et la WS secret là on peut bien voir que l'erreur vient des variables d'environnement qui ne sont pas détecté par l'application on va importer librairie.om.config et on peut voir que le problème est maintenant résolu je renvoie donc mon image ça a chargé un petit peu et on n pas eu d'erreur donc nous allons ouvrir Prisma studio pour voir si on a bien un file key on va dans les utilisateurs et on voit que le premier utilisateur possède bien un file key maintenant on va retourner sur l'interface d'ws pour voir si le fichier a vraiment été mis en ligne on retourne donc sur sur S3 puis dans le bucket que nous venons de créer nestjs chat et là on voit qu'il y a bien un objet qui a été hébergé à 19h45 et qui fait 139 KB je vais cliquer DESS et je vais l'ouvrir dans le navigateur et on voit bien notre image donc l'hébergement a bien fonctionné le problème c'est que dans l'URL il n'y a pas l'extension à du fichier donc on va modifier ça tout de suite on va retourner ici et je vais faire un console log de la file key que nous créons ici avec le file field name je vais même faire un console log ici du fichier que nous mettons en ligne en fait le Field name c'est la clé dans le form data que je suis en train d'héberger j'ai remis mon conso log dans le user controller et je me rends compte que j'aurais dû utiliser la propriété original name qui affiche bien le nom du fichier c'est pas grave on va modifier notre schéazod et on va dire qu'au lieu du Field name on veut l'original name et maintenant nous retournons dans notre service AWS et on va remplacer notre original name et on peut maintenant effacer tous les consoles log et même le body si on retourne maintenant sur notre bucket S3 on peut voir qu'il y a plusieurs images parce que j'ai lancé la requettete plusieurs fois et c'est vraiment ballot parce que quand on met à jour son image on a envie de supprimer l'image précédente pour pas manquer de place et héberger des images qu'on utilise pas donc nous allons tout de suite implémenter une deuxième méthode qui va nous permettre de supprimer les images qui sont hébergées et cette méthode va s'appeler tout simplement delete file et ça prendra en paramètre notre file key unique qui est string et au lieu de créer une commande put object nous allons créer une commande qui s'appelle delete qu'on va renommer et ça sera donc dans le même bucket donc le process invv AWS bucket name et il y aura comme clé notre fil key ensuite nous pouvons envoyer cette commande avec le client avant de mettre à jour l'utilisateur avec la nouvelle clé nous allons d'abord le récupérer et supprimer son ancien avatar pour cela nous allons donc faire un conte existing user pour déjà vérifier que l'utilisateur existe avec indice Prisma user.f unique where id est égal au user ID et nous allons sélectionner la propriété avatar file key si l'utilisateur n'existe pas nous allons renvoyer une erreur de type l'utilisateur n'existe pas sinon nous allons bien héberger notre nouveau fichier et le sauvegarder en base de données mais avant de renvoyer l'utilisateur nous allons faire if donc si l'utilisateur possédait une clé avant alors nous allons la supprimer avec un AWS S3 service point delete file et nous allons mettre comme file key notre existing user avatar file key pour ça c'est vrai que ça fonctionne on retourne sur S3 et on va supprimer ces trois fichiers en cliquant sur delete nous allons écrire permanently delete si on actualise la page on voit bien qu'on a zéro fichiers hébergé maintenant je vais mettre à jour mon image une première fois on retourne sur S3 pour actualiser on a bien une première image on retourne sur l'application pour remettre à jour notre image une deuxième fois et normalement on ne devrait avoir qu'une seule image là si j'actualise on a bien qu'un seul objet ce qui signifie qu'on a rajouté le deuxième objet puis nous avons supprimé la première clé et notre console log s'affiche parce que le statut n'est pas égal à 200 pour le moment ça fonctionne très bien nous pouvons maintenant mettre en ligne des images et les supprimer quand une nouvelle image vient la remplacer maintenant ce qu'on veut faire c'est pouvoir afficher notre image côté front end alors comment faire nous allons devoir récupérer le fichier depuis S3 avec une commande get nous allons donc copier cette méthode et nous allons l'appeler get file et nous allons utiliser l'objet get object command qui utilise notre bucket et le file key nous allons renvoyer la réponse sauf que à ce niveau-là on voit que la réponse est au format de body et body c'est un streaming blob donc c'est un fichier qui va être stream depuis Amazon mais nous nous ne voulons pas streamer le fichier et télécharger le fichier directement nous voulons plutôt une URL qui pointe vers notre image et qu'on peut afficher côté front il faut ça savoir qu'avec Amazon tous les fichiers sont protégés par défaut nous allons avoir besoin de signer cette requête pour être autorisé à visualiser notre image et pour cela nous allons utiliser une URL signée alors comment faire on va aller sur Google et on va taper AWS JavaScript get signed URL et là sur le deuxième lien on voit qu'on a accès au node AWS SDK et ici on voit bien qu'ils utilise une méthode depuis S3 qui s'appelle get signed URL et c'est celle-ci qu'on va devoir utiliser et ce n'est pas ce que je veux je vais retourner en arrière et ici je vais cliquer sur ce lien là AWS SDK S3 request handler et je vais installer ce paquet s'appelle AWS SDK S3 request prigner je retourne dans mon API et je vais entrer cette commande dans mon projet et au lieu d'appeler le client directement nous allons appeler la méthode GET signed URL qui prend en premier paramètre notre client et en deuxième paramètre notre commande nous allons passer le client et en deuxième paramètre notre not commande et on peut voir que le type de retour est un string et ce string sera une url vers notre image on peut également renommer le fichier en l'appelant get fil URL pour que ça soit un peu plus parlant maintenant si je retourne dans le user service puis dans le GET user je vais vouloir sélectionner également l'avatar file key sil est présent nous allons faire une petite condition if user.avatar file key si l'utilisateur a une image alors nous allons récupérer l'url de l'avatar en appelant notre service get file URL en lui passant en paramètre notre file key sinon nous allons envoyer l'avatar avec une URL qui est à nulle ce que nous allons faire ici c'est que nous allons initialiser l'avatar URL annul et si on passe dans la condition alors nous allons C cette variable à sa valeur on va pouvoir faire exactement la même chose plus haut lorsque nous essayons d'obtenir les utilisateurs nous allons donc mapper sur tous les utilisateurs en faisant un users. map avec une fonction asynchrone comp pilot a bien compris et nous allons copier la L logique l'avatar est en string vide et si l'utilisateur possède une file key que nous allons récupérer depuis Prisma alors nous allons la 7 et nous allons renvoyer notre user et son URL ensuite nous voyons bien que c'est une promise donc nous allons effectuer un promise. all d'utilisateur qui possède l'avatar donc plutôt mettre le promise. all à ce niveau-là pour que ça soit plus visible maintenant nous allons pouvoir ajouter ce champ dans Zod côté front je retourne sur mon fichier user.sveur et ici dans mon schéma get US je vais rajouter la propriété avatar URL qui se trouve sous forme de string mais qui peut être nul nous allons également modifier le fichier hos.sveur et nous allons modifier le schéma get authenticated user.séma en mettant que l'avatar peut exister ou il peut être nul maintenant nous allons modifier notre navb et dans le fichier navigation nous avons l'internaire qui affiche conditionnellement les route connecté si l'utilisateur est connecté si l'utilisateur est connecté nous allons afficher son avatar dans une image user.avatarurl n allons la limiter à 10 pixels et forcément vu que user avatar peut-être nul nous allons afficher cette image conditionnellement si nous revenons maintenant sur notre projet on peut voir l'avatar au milieu que j'avais changé depuis postman on va retourner sur postman et je vais changer de nouveau cet avatar sélectionner une autre image par exemple celle-ci je l'envoie je retourne sur mon projet j'actualise la page et là on peut voir que l'image a bien changé si je clique sur l'URL on peut voir l'image en grand maintenant ce que j'aimerais c'est afficher l'image de Cédric s'il en a une donc nous retournons sur notre fontend et nous allons sur l'ID de la conversation puis nous cliquons sur la chatbox et à ce niveau-là nous allons copier la même condition qui affiche une image conditionnellement sauf que le récipient user n'a pas encore d'Avatar URL nous ne l'avons pas typé côté API nous allons donc modifier cette méthode qui conversation et nous allons modifier le schéma pour que chaque utilisateur du schéma possède un avatar URL nous allons faire la même chose pour le GET conversation au pluriel nous allons maintenant retourner côté serveur API nous allons dans le chat service et ici dans la méthode GET conversation au pluriel nous allons sélectionner l'avatar file key et nous allons devoir faire le même calcul c'est-à-dire créer des URL signés avec Amazon S3 donc ici nous allons boucler sur les conversations et pour chaque conversation nous allons renvoyer les conversations et pour chaque utilisateur de la conversation nous allons boucler sur ces utilisateurs pour effectuer exactement le même calcul ici c'estàd que nous renvoyons l'objet l'utilisateur et son avatar cette fonction est asynchrone nous allons mettre le promise. all cette promesse là et il ne faut pas oublier d'importer le service AWS pour importer un service on le rappelle bien il faut rajouter notre service dans le constructeur en l'appelant par exemple AWS S3 service et en important la classe AWS TR Services conversations with avatars et nous pouvons maintenant RVO voyez nos conversations possédant des utilisateurs et un avatar n voyons sur notre terminal qu'il y a une petite erreur parce que le service chat module n'importe pas notre service S3 modifier le chat service et nous allons rajouter dans les providers le AWS S3 service rafraîchi la page maintenant si on retourne côté frontend qu'on retourne sur notre chatbox nous retrouvons notre condition l'utilisateur possède une URL nous allons l'afficher sinon nous n'allons pas l'afficher on voit bien chez cidric qu'il ne possède pas encore image donc elle n'est pas affichée et c'est normal je vais me déconnecter et me connecter avec le compte de Cedric ici on peut voir qu'il ne possède effectivement pas son avatar nous allons donc retourner sur postman pour corriger le tir nous allons renommer ces méthodes nous allons d'abord nous connecter avec le compte de ceddric puis nous récupérons un token de sécurité qui va nous permettre d'accéder à la route protégée update user dans cette route nous rajoutons comme brr token notre token et ici allons modifier l'image et nous allons sélectionner par exemple exemple celle-ci je vais envoyer l'image et si on retourne maintenant sur notre chat j'ai actualisé la page et là nous voyons une grosse erreur alors à quoi est-elle d je pense que le problème vient du promise. all qui ne devrait peut-être pas se mettre ici nous allons de nouveau le déplacer et nous allons await ce promise do all si je retourne maintenant sur le site j'ai résolu le problème j'ai rajouté un deuxième promise. allall qui englobe la première boucle et je l'ai await et je devrais le faire à tous les endroits dans mon code ici on voit dans le user.sice que je n'avais pas à wait le promise. all ça peut poser problème maintenant on peut voir sur notre application que nous avons récupéré l'image de l'utilisateur nous cliquons sur le chat nous ne voyons quand même pas l'avatar de Virgil je retourne donc dans mon composant chat pour essayer de comprendre ici le récipient user représente l'utilisateur qui n'est pas l'utilisateur connecté nous récupérons ces utilisateurs depuis la conversation donc depuis mon get conversation nous avons vu dans get conversation schéma que nous avons un tableau d'utilisateur qui contienne tout c'est une clé avatar URL qui peut être optionnelle si je retourne une dernière fois dans la méthode GET conversation nous allons voir ici que je ne récupère effectivement pas l'avatar depuis ces conversations là donc nous allons implémenter la même logique en appelant la méthode conversation with avatars et nous allons déstructurer la conversation pour nos utilisateurs nous allons faire le fameux promise.all qui va boucler sur les utilisateurs de cette conversation et si jamais ils ont un avatar on le rajoute sinon on rajoute un Ty string si on inspecte le type on voit que c'est bien ce que nous voulons les utilisateurs peuvent avoir un avatar file key et nous allons renvoyer cette conversation là je rafraîchi la page et je retourne côté client j'actualise et là on voit bien l'avatar de l'utilisateur Virgil maintenant ce qu'on aimerait faire c'est changer nous-même notre avatar côté front avec un formulaire et c'est ce que nous allons implémenter nous retournons donc dans notre frontend et nous allons créer un fichier que nous allons appeler settings pour paramètrre utilisateur et j'ai copié le fichier conversation au pluriel parce que c'est une route protégée nous allons donc faire un require de l'utilisateur sur la méthode loader et nous allons créer une page user settings qu'on va exporter par défaut et nous allons copier ce hook pour récupérer les informations de notre utilisateur ensuite nous allons nous inspirer de notre formulaire de création de compte côté design en supprimant une partie quand même et nous aurons un formulaire en poste qui permettra de modifier le prénom et ça on ne va pas le faire tout de suite l'email et le mot de passe non plus nous allons juste vouloir modifier l'avatar je copie les dernières variables de la méthode register on vaut pas s'éterniser sur la sémantique et nous allons commenter ces inputs et nous allons à la place rajouter un input avatar qui sera un input de type file et nous allons mettre un accept pour n'accepter que les fichiers de type Image nous allons appeler le champ avatar et à ce niveau-là comme nous récupérons les données de l'utilisateur connecté nous pouvons afficher par défaut son avatar avec un affichage conditionnel si l'utilisateur a déjà configuré son avatar nous allons l'afficher en plus grand sinon nous allons renvoyer nul je vais retourner dans ma nav bar pour ajouter une route aux utilisateurs connectés et ça sera les settings une route qui est accessible à slashstings maintenant je retourne côté front et je vais cliquer sur settings on peut voir qu'on a une petite erreur parce qu'on a oublié de renvoyer une réponse dans notre loader on va renvoyer du JSON vide et maintenant nous voyons notre bel avatar avec notre input et si je clique sur choose file ça va me proposer de changer et pour le moment je n'ai aucune prévisualisation de l'image et nous n'avons pas encore développé la logique pour récupérer ce fichier dans un formulaire nous allons donc créer un nouveau schéma qu'on va appeler update avatar schema ça sera un schéma Zod qui contiendra toutes les propriétés que nous souhaitons modifier nous aurons donc une propriété avatar mais pas sous forme de string sous forme de fichier nous allons donc utiliser la p instance of ce qui signifie que l'avatar sera forcément de type fichier et nous pouvons même faire un transform en récupérant les propriétés de ce fichier et on peut voir qu'on possède un buffer un name un Last modified et une size et nous pouvons renvoyer une condition if size est supérieur à par exemple 10 Mbit alors nous allons utiliser le contexte de Zod et nous allons ajouter une erreur de type l'image est trop lourde ensuite nous pourrons faire un return false sin non on peut return true la validation a bien fonctionné maintenant nous allons créer une action pour récupérer le formulaire une fois que l'utilisateur aura cliqué sur le bouton Modifier l'avatar et nous allons la typer action function ARS et nous allons également vérifier que l'utilisateur est connecté ce qui peut ne pas être le cas et s'il l'est nous souhaitons récupérer la forme data mais nous allons pas faire un requestform datata comme d'habitude ce qu'on a envie de faire maintenant c'est de récupérer l'image qu'on soumet depuis notre formulaire donc là si j'ajoute une image ici et que je clique sur Modifier l'avatar ça va pour le moment rien faire on a donc un bouton de type submit et on a envie de mettre à jour notre avatar quand nous cliquons sur le bouton chaque soumission de formulaire se fait dans le composant action et à ce niveau-là nous récupérons la forme data depuis la request.formedata nous allons devoir créer un handler spécial depuis remix qui va nous permettre de récupérer l'image qui a été envoyée au front end quand on soumet un formulaire avec par exemple des images ça va créer un stream c'estàdire que ça ne va pas envoyer la donnée sous forme de string ça va streamer l'image morceau par morceau comme ça même si l'image fait 1 Go ou 2 Go ou qu'on essaie d'upload une vidéo ça va finir par envoyer le document depuis notre ordinateur comme c'est un stream ça sera pas directement présent dans le request.form datata nous allons devoir utiliser une fonction spéciale de remix qui est encore instable et qui s'appelle unstable create memory handler et cette fonction prend deux paramètres en premier paramètre elle prend un tableau d'option on peut dire que l'image ne doit pas dépasser les 10 MCT ce handler nous pouvons le stocker dans une variable que nous allons appeler image underler et ensuite nous allons essayer de récupérer la forme data depuis une autre méthode instable qui s'appelle unstable pars multipart form data cette fonction prend donc deux arguments notre request et notre upload handler qui est notre image handler nous pouvons supprimer cette première ligne et maintenant nous allons être capable de récupérer l'image qui a été streamé depuis le client mais il nous reste une dernière étape à faire pour héberger des images avec remix nous devons rajouter un prop notre formulaire et c'est le prope in type qui sera égal à multipart form data on peut essayer d'envoyer notre image et nous allons même la parcer en utilisant notre schemazod nous allons donc appeler ce schemazod qui contient une propriété avatar qui est un type de fichier et nous allons faire un update avatar chezmaips de notre form dataget et la clé avatar sachant que la clé avatar vient ici du name de notre input maintenant ce que nous passons c'est pas directement l'avatar c'est un objet donc nous allons passer un objet et dire que cet objet prend la clé avatar et la valeur c'est formedata.get avatar et enfin nous allons déstructurer notre avatar pour voir si ça fonctionne bien et nous allons le console log nous allons ouvrir le terminal pour voir les log serveur et je vais renvoyer une autre image celle-ci modifier l'avatar et là on peut voir que ça m'a affiché true qui est un bouléen et qui n'est pas le type de fichier que je veux et c'est parce que ici dans la méthode transform je return true je pensais que return true voulait dire qu'il n'y a pas eu d'erreur en fait quand on return false ça signifie ça signifie qu'il y a eu des erreurs je rafraîchis ce schéma Z nous allons renvoyer notre image modifier l'avatar on va actualiser la page et renvoyer notre formulaire avec une image et là on peut voir que nous avons undefined ça veut dire que j'ai vraiment très mal déclaré ma méthode transform au lieu de dstucturer directement les propriétés de notre fichier nous allons récupérer toute la donnée de ce fichier et nous allons le renvoyer dans la méthode transform parce que là je pense que c'est pour ça que ça nous met avatar undefined maintenant on va refaire un test on envoie notre image et là on peut voir qu'on a effectivement un blob avec une taille et c'est une image de type JPEG maintenant la dernière chose qu'on doit faire c'est update l'utilisateur côté serveur pour cela on va créer une requête dans notre fichier user.sveur et cette requête va s'appeler update user ça sera une méthode de type post et nous aurons en data notre avatar sauf que notre méthode fit cher actuellement elle reçoit soit un objet soit nul et nous il va falloir qu'on envoie une image et une image ne peut pas se trouver sous forme d'objet donc nous allons modifier cette méthode et je vais la nommer file Fetcher et cette méthode nous permettra uniquement d'envoyer des fichiers et ça sera le type form data le paramètre est maintenant obligatoire comme c'est du Form data nous n'avons pas besoin de le stringifier nous pouvons le passer tel quel on recevra quand même une réponse au format jison maintenant je vais utiliser mon file Fetcher et il faut aussi rjouter le paramètre du fichier dans notre méthode ça sera donc un file et nous allons créer notre forme data qui sera une nouvelle instance de la classe form data et nous allons ajouter la propriété avatar avec comme valeur notre fichier enfin l'objet data sera tout bonnement notre form data et la réponse du serveur utilisera notre feedback schéma maintenant on va retourner côté serveur et on va vérifier que les propriétés portent bien le même nom ici nous avons notre uploaded file qui contient le nom file ça veut dire que le fichier doit s'appeler file pour fonctionner moi je vais le renommer et je vais l'appeler avatar je retourne maintenant côté front et je vais utiliser cette fonction qu'on peut nommer update user avatar vu que pour le moment elle ne fait que mettre à jour l'avatar et nous allons l'appeler avec un await de update user avatar qui prend en paramètre la request pour identifier l'utilisateur et comme fichier notre avatar on peut voir que nous avons un problème au niveau du tipage je pense que j'ai utilisé la mauvaise propriété Zod nous allons utiliser un super refine à la place et là on peut voir que c'est un peu mieux l'avatar est forcément affiché ensuite on reçoit le feedback depuis notre API et on peut le renvoyer côté front on peut même typer notre requête action feedback pour renvoyer directement l'objet feedback et si jamais il y a eu une erreur entre ces deux méthodes nous allons copier cet objet et renvoyer une erreur de type l'image n'a pas pu être mise en ligne on pourrait même afficher l'erreur conditionnellement si cette erreur est de la classe error alors on va afficher le message et si cette erreur est de la classe zod. erreor alors nous allons afficher le message de cette issue Zod et moi je préfère boucler et faire un map sur chacune des erreurs pour récupérer leur message et ensuite faire un join ça permettra de récupérer toutes les erreurs du formulaire séparées par des virgules on peut même tester cette erreur tout de suite en retirant quelqu que zéro pour dire qu'on veut pas que l'image fasse plus de 10 kg octate on va envoyer cette image et là on a une erreur Bou l'image est trop lourde 10 mctat max chemin avatar bon ça marche très bien ça nous affiche bien l'erreur on va donc remettre la taille par défaut et comme nous utilisons cette variable deux fois nous allons la stocker dans une constante qu'on va appeler max file size const max file size est égal à 10 moct maintenant on va modifier l'image et on la soumet et on va voir qu'on a une erreur de type request alors qu'est-ce qui s'est passé côté backend allons voir on a bien besoin de faire un post on reçoit un fichier de type avatar donc ce qu'on va faire c'est qu'on va faire un console log du fichier qu'on a reçu et on va vérifier que nos méthodes sont bien appelées on fait bien un post sur la route/ash users on va actualiser le front end je modifie l'avatar et là on a payload to large et je comprends pas cette erreur je ne connais pas cette erreur donc on va faire une recherche sur Google pay tourage error NJS je sais que c'est une erreur NJS parce parce que ici on peut voir dans la console qu'on a reçu une request entity to large et ce qu'on va devoir faire les amis comme ça ne fonctionne pas nous allons utiliser postman pour voir si le problème vient de notre implémentation côté client ou de notre API je vais donc renommer la clé en avatar comme c'est le cas pour notre API ici et nous allons envoyer cette requête et là on peut voir qu'on a bien un internal serveur error si on retourne côté nestjs on peut voir une erreur qui vient de Zod et l'erreur est à ce niveau-là le schéma n'arrive pas à parce nous avons bien eu un console log mais notre fichier est maintenant undefined il nous remettons la clé file à ce niveau-là et dans postman et que nous renvoyons la requête on peut voir qu'on a toujours la même erreur bizarre ça alors maintenant ça fonctionne de nouveau et vous n'alz jamais deviner ce que j'ai fait j'ai tout simplement rechargé le fichier que j'avais mis à ce niveau-là maintenant si je mets ce JPEG ça va marcher et j'ai même fait le test avec un fichier très lourd si je prends par exemple un document ce document qui fait 74 Mbit et que je l'envoie voir que ça envoie la request au serveur et que c'est en train de la streamer cela signifie les amis que le problème ne venait pas de notre serveur le problème vient de notre front-end je vais donc réutiliser une image et nous allons retourner côté front ici je retourne dans le fichier settings et nous allons récupérer cette formme data directement au lieu de la recréer dans notre méthode je vais donc donc directement passer le form data et je vais dire que cette fonction reçoit une propriété form data de type form data et nous allons effacer C ligne et maintenant nous n'avons plus besoin de déstructurer l'avatar nous pouvons simplement le parce je vais couper le serveur et le relancer NPM rundev on va actualiser la page et nous allons envoyer de nouveau notre avatar je clique sur Modifier l'avatar et là nous avons un bad request sauf que ce bad request il est dû au fait que j'ai remodifié le nom du paramètre file en pensant que ça venait peut-être de là donc ce qu'on va faire c'est qu'on va tester une dernière fois une modification du nom je remets avatar je coupe le serveur je relance le serveur je vais sur postman je modifie le nom de la clé en l'appelant avatar je regarde que le serveurs est bien redémarré il a bien redémarré j'envoie la requête sur pastman elle s'appelle avatar et on peut voir que ça a encore marché donc c'est très bien c'est bon signe maintenant nous retournons sur notre fontine et je clique sur Modifier l'avatar et là on peut voir qu'il y a encore une erreur et que la requête n'est même pas console loguée et je ne comprends pas pourquoi je ne comprends pas pourquoi nous appelons bien la route/ash users c'est effectivement un poste et nous sommes bien authentifiés avec notre request parce que dans notre méthode file Fetcher nous utilisons la request pour récupérer le token d'authentification et le rajouter dans les headers sauf que j'ai retrouvé le problème ici nous mettons content type application jison sauf que ce n'est plus du jison c'est du Form data et on peut le voir ici dans postman j'avais coché form data et non pas rison et si on regarde les header automatiques que ça met il nous dit que le content type est de type multipart form data et elle était là la pièce manquante depuis tout à l'heure si ça ne fonctionne pas c'est juste à cause de ça maintenant j'envoie mon image je la modifie et là on peut voir malgré le message d'erreur que ça a bien modifié l'image en live en temps réel grâce à remix qui a reload le loader maintenant on a un problème cette méthode Update user devrait renvoyer un feedback et c'est pour ça qu'on a eu une erreur donc nous devrions rajouter notre try catch ici et en cas d'erreur nous allons donc mettre erreur à trou et message à une erreur inattendu et survenu sinon au lieu de renvoyer l'utilisateur nous allons mettre erreur à false et en message l'avatar a bien été mis à jour et pour avoir une erreur encore plus parlante nous allons faire un IF error hérite de la classe error et nous allons renvoyer le message de cette erreur maintenant nousavons plus besoin de récupérer les propriétés de l'utilisateur et si on retourne côté front je vais rajouter une autre image je modifie l'avatar et on peut voir que ça fonctionne très bien nous avons réussi à héberger une image avec remix et elle est hébergé dans un bucket S3 pour résumer ce que nous avons fait dans cette vidéo nous avons d'abord créé une route côté serveur qui est un poste en utilisant un nouveau décorateur qui s'appelle use interceptors et ce décorateur nous permet de passer en paramètre un intercepteur de fichier qui va nous permettre de récupérer d'intercepter les fichiers de notre requête ensuite nous récupérons un fichier et nous le Parsons avec un schéma Zod ce schéma dit que le fichier possède une propriété taille buffer original name et M type le buffer va contenir notre image ensuite avec cette image nous faisons plusieurs choses déjà vérifions que l'utilisateur existe s'il n'existe pas nous renvoyons une erreur et ensuite nous uploadons ce fichier dans un bucket S3 avec notre méthode de service AWS S3 service et pour se faire nous avons créé un service Amazon S3 ce service dans son constructeur va créer un nouveau client S3 avec les codes d'accès que nous avons récupéré depuis Amazon et il déclare plusieurs méthodes une méthode pour supprimer un fichier avec la file key je rappelle que le file Key est un identifiant unique qui permet de localiser le fichier dans S3 pour héberger le fichier nous créons une commande de type put object avec les propriétés de notre bucket le nom de la clé et le type de fichier et forcément notre fichier et nous rajoutons même une clé de cache pour que l'image soit cachée un an et ensuite nous envoyons cette commande à S3 pour supprimer le fichier c'est le même principe nous utilisons une classe de type delate object command et pour que côté front nous puissions avoir accès à notre fichier on peut voir ici si je clique sur Open image in new tab ça va m'ouvrir une tab depuis S3 et on peut voir ici que il y a énormément de paramètres avec un host ID un token securisé et cetera ce token sécurisé est nécessaire qu'il nous identifie si là je supprime tous les paramètres et que je tente d'accéder à cette image on peut voir que ça ne fonctionne pas j'ai une erreur de type access dened pourquoi parce que nous avons besoin de signer notre requête et nous signons notre requê avec la méthode GET sign URL et cette méthode a été ortée depuis une deè librairie de la WS SDK qui s'appelle S3 request priner le client S3 compte à lui il est emporté depuis la librairie de Amazon SDK client S3 vu que nous devons signer notre image à chaque requête côté serveur nous allons contacter Amazon pour récupérer l'url signé on peut voir ici que pour récupérer les utilisateurs de notre application nous allons boucler sur chacun des utilisateurs et nous allons utiliser cette méthode GET file URL en passant paramètre notre clé ce qui va renvoyer une nouvelle propriété nommée avatar URL et c'est à peu près tout ce qu'on a fait côté API on a ensuite utilisé postman pour vérifier que notre requête fonctionnait bien si là je change l'image on peut voir que l'appel me renvoie une 20 created avec un message l'avatar a bien été misise à jour si je rechange l'image une dernière fois on peut voir que ça va fonctionner et maintenant si je retourne côté front et que j'actualise la page on peut voir que l'image a bien été modifiée ensuite côté client on a créé une nouvelle page qui s'appelle settings et nous avons copié le formulaire d'inscription c'est pour ça qu'il y a encore les anciens titres et cette page settings est assez complète nous avons d'abord un loader qui nous permet de récupérer l'utilisateur authentifié c'est ce qu'on appelle une route protéger un utilisateur déconnecté ne pourra pas accéder à la route ensuite nous avons un composant avec un formulaire et ce formulaire est très important nous affichons l'avatar actuel de l'utilisateur s'il en a et ensuite nous rajoutons un input de type file qui accepte les fichiers de type Image et qui va les renvoyer à notre API pour soumettre le formulaire nous allons cliquer sur le bouton de type submit et à la soumission de notre formulaire remix va lancer la logique de notre action comme le formulaire possède un fichier nous utilisons deux méthodes instables de remix le create memory upload unler pour stocker le fichier dans la mémoire on attendant que le téléchargement de l'image se termine et ensuite le unstable parse multipart form data qui prend deux paramètres notre request et le unler que nous venons de créer ensuite pour valider notre image nous avons défini un schéma avec Z ce schéma est un objet qui possède une clé avatar qui doit forcément être de l'instance file ensuite la déclaration pourra s'arrêter là mais j'ai rajouté un petit peu de logique sous forme d'un super refine le super refine nous permet de rajouter une règle en plus que nous allons coder nous-mêmes donc si notre avatar passe la validation et est bien un fichier nous allons récupérer le fichier et nous allons comparer sa taille avec la taille maximum autorisée qui est de 10 MB si le fichier est supérieur à 10 MB alors nous allons renvoyer une erreur l'image est trop lourde et nous allons return false pour dire qu'il y a eu une erreur sinon nous allons on renvoyer le fichier ça c'est le schéma Z et il fonctionne vraiment très bien on va tester en uploadant en fichier de type PDF je clique sur Modifier l'avatar et là on peut voir qu'il y a une petite erreur dans mon terminal à ce niveau-là fil d'Avatar exceeded upload size of la valeur que j'ai mis après cette validation par Zod nous allons envoyer notre fichier et nous allons le streamer à notre API j'ai créé une méthode Update user avatar qui n'utilise pas notre méthode Fetcher mais une nouvelle méthode qui s'appelle file Fetcher elle prend paramètre une request le type de méthode et la notre donnée sous forme de form data elle prend également l'url de la route que nous souhaitons appeler et cette méthode est un copier-collé de notre Fetcher sauf qu'on a modifié deux trois trucs tout d'abord notre data est au format form data ce qui veut dire qu'il peut recevoir des images on peut voir ici sur postman qu'on peut ajouter des données de type texte ou des données de type Image quand nous utilisons le form data par contre si nous utilisons du Gon basique on va pas pouvoir avec un objet clé valeur renvoyer une image directement comme ça utilise le form data nous n'avons pas besoin de le singfier dans le body nous pouvons le passer tel quel et ensuite l'obli qui m'a fait perdre plus de 30 minutes c'est que j'ai fait un copier-coller de mon Fetcher avec la clé content type application jison en précisant cette clé content type application jison on dit à notre serveur API qu'il doit s'attendre à recevoir une réponse au format jison sauf que là c'était pas le cas vu que notre réponse est au format forme data on peut voir maintenant le résultat final si on choisit un objet nous allons héberger une image on clique sur Modifier l'avatar et après un petit délai on peut voir que notre avatar est bien mis à jour à tous les endroits de notre application j'ai envie de rajouter une fonctionnalité et c'est la fonctionnalité de pouvoir faire un don à un utilisateur c'est-à-dire lui envoyer de l'argent directement mais pour implémenter cette fature nous allons utiliser stripe stripe est une plateforme très complète et il y a énormément de fonctionnalités si on se rend sur le site de hype et qu'on va sur product on peut voir qu'il possède une dizaine de fatures différentes mais ce qui va nous intéresser ici c'est la feature banking as a service et les comptes connectés on peut regarder un petit peu la présentation du future si on descend un petit peu sur cette page on peut voir ici que nous avons l'acheteur qui achète directement sur la plateforme le produit et la plateforme le renvoie au vendeur et c'est ce que nous allons implémenter sauf qu'on a rien à vendre on souhaite juste envoyer de l'argent à notre ami pour se faire nous allons donc créer ce qu'on appelle un compte connecté sur stripe qui va récupérer les informations de paiement de nos utilisateurs et ensuite on sera capable de leur envoyer de l'argent passons maintenant à l'action je vais cliquer sur la documentation et je me retrouve sur la documentation de stripe Connect et on peut voir que stripe me propose des suggestions par exemple récupérer de l'argent et reverser une partie de cet argent à mes clients il y a une autre option qu'on ne va pas utiliser c'est directement faire un virement à stripe pour pouvoir rémunérer nos clients on veut que les utilisateurs soient autonomes dans leur don je vais donc cliquer sur collect and payout with payment links maintenant avant de pouvoir implémenter cette fature on va devoir se créer un compte sur stripe et pour se faire nous allons devoir valider notre compte bancaire j'ai personnellement déjà créer un compte stripe et nous allons l'utiliser pour cette vidéo je vais donc me connecter à mon compte stripe je suis maintenant connecté sur le compte d'algomax.fr et je vais cliquer sur Web parce que nous allons implémenter cette fonctionnalité avec du code on peut voir qu'on a quand même trois prérequis et le premier c'est d'activer la fonctionnalité des comptes connectés je vais donc cliquer sur get started with Connect et je vais maintenant en haut à droite de la page stripe activer le mode test on peut voir également que j'ai besoin de compléter mon profil de plateforme c'est-à-dire que stripe va me poser quelques questions pour comprendre le genre de service que j'ai envie de créer on va donc sélectionner crowdfunding ou donation pour la première question on va donc dire que les achats se font depuis notre plateforme et on mettra le nom de notre plateforme sur le relevé bancaire s'il y a une plainte c'est notre plateforme que le client va devoir contacter et c'est bon on a terminé l'unboarding on peut soumettre le formulaire je retourne maintenant sur la documentation et ces trois cases ont été cochées j'ai activé mon compte en le créant j'ai inscrit ma plateforme et j'ai terminé mon profil de plateforme nous allons maintenant intégrer stripe à notre application nest JS je vais donc copier cette commande et je retourne dans mon dossier API je vais kill le serveur et je vais faire un npmi de stripe pour l'installer maintenant que c'est fait je peux faire un NPM rundev nous venons d'installer stripe sur notre projet NGS et nous allons tout de suite créer un service pour pouvoir utiliser stripe dans notre application j'ouvre donc mon explorateur de fichier je vais dans SRC et je vais créer un nouveau fichier qui sera dans le dossier stripe et qui va s'appeler stripe.service.ts ça sera une classe que je vais exporter qui s'appellera stripe service et pour pouvoir utiliser l'injection de dépendance de nestjs il ne faut pas que j'oublie le décorateur injectable pour commencer nous allons initialiser le client stripe pour ce faire nous allons devoir déclarer une nouvelle variable privée et readidon que nous allons appeler stripe et qui héritera de la classe stripe que nous venons d'installer depuis la librairie de stripe maintenant je vais ajouter un constructeur à l'application et je vais dire que 10. stripe est égal à New donc on va générer une nouvelle instance de stripe et on peut voir que Copilot nous aide nous avons besoin d'une secret key que stripe va nous renvoyer en deuxè paramètre le constructeur de stripe prend un objet et nous allons préciser la version API on n' pas le choix on peut que sélectionner la 2023-10- 16 maintenant on a besoin de récupérer notre stripe secret key et nous allons le récupérer en retournant sur la documentation de stripe on va cliquer sur dashboard en haut à droite puis nous allons cliquer sur le lien developpers et sur l'onglet API Keys ici on peut voir que nous avons deux clés nous avons une clé publique et nous avons une clé secret que nous allons coller dans nos variables d'environnement je l'ai déjà fait on peut donc passer à la suite je retourne donc sur la documentation de stripe et nous avons besoin de créer un compte connecté et nous allons créer des comptes connectés pour chaque nouvel utilisateur qui s'inscrit sur notre plateforme alors comment créer un compte connecté nous allons voir ça tout de suite je vais copier ce morceau de code dans une méthode que je vais appeler create connected account nous allons donc utiliser la classe stripe pour créer ce compte de type express en fonction des informations que nous avons déjà demandé à l'utilisateur lors de l'inscription sur notre plateforme nous pourons remplir certains champs dans le formulaire de stripe comme par exemple son email on pourra aussi préciser quelle est la monnaie par défaut nous allons utiliser des euros et nous allons sauvegarder l'ID de ce compte connecté dans notre base de données pour se faire on aura donc besoin d'importer le service Prisma que je vais importer tout de suite et je vais l'importer directement dans le constructeur pour bénéficier de l'injection de dépendance notre compte connecté sera lié à notre compte utilisateur donc nous nous allons passer en paramètrre un user ID qui va nous permettre d'identifier l'utilisateur sur notre plateforme avant même de créer un compte stripe connecté nous allons d'abord récupérer l'utilisateur sur notre plateforme en demandant à Prisma de nous retourner l'utilisateur en fonction de son ID ensuite nous voulons voir s'il n'existe pas déjà un compte connecté qui est lié à cet utilisateur nous allons devoir modifier le schéma Prisma on se rend donc dans notre fichier schéma. Prisma et nous allons rajouter un champ à notre modèle utilisateur et le champ sera stripe account ID et ça sera un string et nous pouvons même mettre que ce champ sera unique c'est-à-dire que deux utilisateurs ne peuvent pas avoir le même compte stripe maintenant je vais ouvrir une deuxième fenêtre de terminal et je vais faire un NPX Prisma dB push pour effectuer ces changements je peux faire également un NPX Prisma generérate pour regénérer les types avec typescript et maintenant je vais sélectionner le stripe account D qui peut être un string mais qui peut être nul je j'ai également sélectionner l'email de l'utilisateur et nous allons ajouter une condition si l'utilisateur existant possède un comp stripe alors nous allons rien renvoyer on fait ce qu'on appelle un early return c'est-à-dire que la fonction va s'arrêter à cette ligne si l'utilisateur possède déjà un comp stripe sinon nous allons créer un nouveau compte stripe que nous pouvons appeler stripe account nous allons préremplir l'email en utilisant l'email du client existing user.email et ensuite nous allons utiliser Prisma pour sauvegarder l'ID de ce compte connecté dans notre base de données on va donc faire un update sur l'ID de notre utilisateur et nous allons dire que le stripe account ID est égal au stripe account.id nous allons également faire un select sur l'ID de notre utilisateur et pour être sûr que l'utilisateur existe on va faire un f unique or throw ce qui va déclencher une erreur si notre utilisateur n'existe pas retournons sur la documentation de stripe on peut voir que créer le compte connecté n'est pas suffisant pour envoyer de l'argent à nos utilisateurs on a besoin de connaître leur coordonnées bancaires et quand je dis h je ne parle pas de moi en tant que créateur de la plateforme je parle de stripe effectivement stripe a besoin de connaître le RIB des clients pour leur faire des versements pour ce faire on va devoir créer un account link regardons ce que c'est on va donc spécifier un paramètre possède une ID l'ID du compte connecté que nous venons de créer une URL pour regénérer un lien un account link si jamais l'utilisateur a mis trop de temps à remplir son profil et une URL de succès bien sûr il faut également préciser le type de lien que N génér on a le choix entre account onboarding et account Update et nous pourrons faire ça directement depuis notre application je vais copier ce code là et je vais le coller dans mon application on va utiliser notre classe stripe pour générer un account Link et nous allons mettre comme ID l'ID de notre compte connecté dans l'URL de succès nous allons mettre notre application en local qui est donc localhost 3000 et dans l'URL qu'on va utiliser pour rafraîchir ce lien là nous allons mettre une autre URL qui sera notre URL pour faire un don on va mettre par par exemple slash pay qui est une route qu'on a pas encore créé dans notre application remix et qu'on va créer tout à l'heure on peut se poser la question comment savoir si le client a besoin de générer un account link s'il a besoin de générer un account link c'est par exemple que ces informations bancaires sont invalides n'ont pas été vérifié ou qu'il manque tout simplement des informations dont stripe a besoin pour faire son boulot on peut voir si on descend dans la documentation de stripe qu'il nous explique que pour terminer l'unboarding d'un compte Connect le compte connecté doit avoir charges enabled qui est un Boulin que stripe nous enenvoie si le compte est ligible pour recevoir des paiements ça fait beaucoup de théories donc on va passer à la pratique je vais retourner dans mon application et je vais déplacer la logique dans une autre méthode que je vais appeler Create Account Link et cette méthode prendra en paramètre un stripe account ID qui est un string nous allons donc copier ce code et nous allons renvoyer notre lien d'identification on va donc faire un await de 10 de la méthode que nous venons de créer en passant les bons paramètres et nous allons renvoyer cet account link à notre frontend on peut voir que account Link est un objet qui possède une URL une date de création et cetera nous voulons renvoyer une URL maintenant nous pouvons modifier cette partie et nous allons mettre que si l'utilisateur possède déjà un compte stripe au lieu de renvoyer rien nous allons renvoyer la même chose c'est-à-dire nous allons créer un lien de paiement et nous allons renvoyer son URL maintenant que j'ai créé ces deux méthodes je vais retourner dans mes dossiers et je vais créer un module pour stripe que je vais appeler stripe.module.ts nous allons copier la logique d'un module existant et on peut voir qu'on va utiliser le décorateur module et que nous allons rajouter un provider le provider étant notre stripe service nous allons ensuite exporter ce module sous forme de classe enfin nous allons également créer un contrôleur que je vais appeler stripe.croller.ts et on va également s'inspirer d'un contrôleur que nous avons déjà créé par exemple le chat controller je vais copier cette logique et je vais supprimer toutes les méthodes sauf cette méthode GET je vais bien sûr tout verérer sauf le service de stripe que je vais importer et je vais renommer ce contrôur en stripe controller je vais également dire que la route sera stripe et nous allons modifier cette logique ce que je veux maintenant c'est créer une route que je vais appeler users et je vais placer mon user ID qui sera l'ID de l'utilisateur sur ma plateforme et je vais appeler la méthode que j'ai créé dans mon service stripe qui me permet de créer un compte connecté et je vais lui passer en paramètre le user ID que je récupère dans cette requette get je vais donc récupérer le paramètre avec le décorateur param paramètre s'appelle user ID et je vais le sauvegarder dans une variable qu'on va appeler user ID et qui est un string bien sûr nous allons continuer d'utiliser l'objet request ce qui signifie qu'un utilisateur déconnecté ne pourra pas créer de compte stripe vu que c'est le cas on a au final pas besoin de récupérer l'id du user dans l'URL parce que nous pouvons directement le récupérer dans la request on va donc faire un requestuseruserid je vais donc supprimer ce paramètre et nommer la méthode au final je vais mettre que ça sera un poste et je vais appeler la route Connect pour y accéder il faudra donc accéder à la route localhost/stripe/connect et ce sera un post nous allons donc tester cette intégration sur postman je vais ouvrir l'application postman nous allons donc copier cette méthode qui nous permet de nous connecter on a d'ailleurs besoin de se connecter pour récupérer notre access token qui va nous permettre de nous identifier je vais donc dupliquer cette méthode et je vais l'appeler create stripe Connect account c'est donc sur le localosil qui est le port sur lequel on fait tourner notre application nesjs et nous allons accéder à la route stripe/ Connect et nous allons dans l'onglet autorisation pour ajouter notre token de connexion et on va mettre que c'est un brr token et je vais donc coller le token que j'ai récupéré en me connectant maintenant je vais cliquer sur send et on peut voir que j'ai une erreur canot post sur la route/ stripe/cnect cette erreur est tout simplement liée à notre module stripe que nous avons oublié d'importer dans notre app module je vais donc rajouter le stripe module ici et comme nous utilisons Prisma dans le module stripe on va devoir l'importer dans le module stripe je vais donc rajouter Prisma service dans les providers c'est bon c'est de retour à la normal je vais retourner sur pstman et je vais créer mon compte stripe on peut voir qu'on a toujours la même erreur et c'est et c'est parce que j'ai oublié d'importer le stripe controller dans mes contrôur c'est bon je viens d'importer le stripe controller on peut voir même qu'il a été défini ici dans le terminal ce qui signifie que je peux maintenant appeler cette route je vais envoyer la requette et ça prend un petit peu de temps on peut voir que j'ai un message d'erreur de la part de stripe you must update your Connect branding settings with business name icon and brand color en gros je ne peux pas pour le moment créer des liens pour les comptes connectés parce que je n'ai pas configuré le design de ma marque sur le dashboard de stripe il me donne un lien je vais cliquer sur ce lien et je vais configurer Connect dans le dashboard on peut voir que les comptes Express sont actifs mais seulement aux États-Unis je vais activer le mode test je vais aller dans les réglages et je vais activer la France comme pays éligible et je vais désactiver les États-Unis maintenant on peut voir que les transferts sont disponibles c'est-à-dire que les comptes connectés peuvent recevoir de l'argent de notre part je vais enregistrer ces réglages je vais retourner sur Connect si on retourne en mode production dans branding je vais devoir rajouter le nom de mon business je vais donc l'appeler NGS chat et on peut rajouter des couleurs et un logo je n'ai pas de logo sous la main donc on va mettre cette miniature je vais maintenant enregistrer ces changements ce qui veut dire que chaque utilisateur qui voudra faire une donation il verra cette page s'afficher avec mon icône et les informations de paiement on va donc retourner sur postman et on va réexécuter cette requête je vais faire un send et on peut voir que j'ai maintenant un lien stripe Connect je vais donc cliquer dessus et on voit qu'on est bien en mode test en mode test l'email n'est apparemment pas nécessaire et il me demande un numéro de téléphone je vais donc mettre mon numéro de téléphone continuer je vais donc ajouter le code qu'ils m'ont envoyé par SMS et ils m'ont nous poser quelques questions par exemple quel type de business je suis je suis particulier micro-entrepreneurou auto-entrepreneur et ensuite je dois fournir mon nom mon prénom ma date de naissance mon adresse les détails de mon business et bien sûr mon IBAN comme nous sommes en mode test on va devoir utiliser un IBAN de test je vais cliquer sur Save et je vais maintenant accepter les conditions et cet unbning là sera obligatoire pour tous les utilisateurs qui souhaitent recevoir voir des dons dans notre application nous venons de nous inscrire en tant que client connecté sur stripe on peut voir dans le dashboard qu'on a le statut actif ce qui signifie que pour le moment nous avons fourni suffisamment d'informations pour qu'il puisse nous renvoyer de l'argent que nous gagnons avec les dons maintenant nous allons retourner sur notre application stripe et j'ai envie de créer une nouvelle méthode dans laquelle nous allons récupérer le statut du compte connecté je vais donc créer une méthode stripe que je vais appeler get stripe account qui va prendre un stripe account ID comme paramètre ensuite nous allons faire un retrieve sur le stripe account ID et j'ai surtout envie de récupérer une information est-ce que le compte connecté peut recevoir de l'argent et cette information nous la récupérons dans la variable qui s'appelle strap account.charges enabled donc je vais la stocker dans une nouvelle variable que je vais appeler can get donations et je vais renvoyer ces deux informations sous forme d'objet je vais plutôt renommer cette variable en can receive money maintenant je vais aller dans mon user controlller et j'aimerais qu'au moment où je récupère les informations de mon utilisateur ici donc la méthode GET user du user service j'aimerais également récupérer la variable can receive money depuis le service de stripe on va donc faire un await du service stripe et nous allons appeler la méthode GET stripe account bien sûr pour cela nous devons importer le service de stripe dans notre user service et nous allons passer en paramètre notre stripe account ID si notre utilisateur le possède on va donc le récupérer dans le Select et nous allons instancier une variable can receive money qui sera pour le moment à false et si nous avons un stripe account ID alors nous allons récupérer les informations du stripe account notamment la valeur can receive money nous allons ensuite la renvoyer côté client et nous devons également importer le service de stripe dans le module de nos utilisateurs dans le user module donc je vais importer stripe service et nous devons aussi l'importer dans le module d'authentification qui utilise notre user service on va maintenant tester cette méthode sur postman je vais récupérer les informations de l'utilisateur à/ashuser/ mon ID pour se faire on a besoin d'ouvrir Prisma studio afin de récupérer l'id de notre utilisateur je peux retourner sur postman je passe mon ID en paramètres dururl j'envoie la requête et je vois que j'ai une petite erreur c'est parce que la route c'est users au pluriel je renvoie la requête et maintenant on a nos information et on peut voir que le can receive money est égal à TR ce qui signifie que stripe nous a envoyé une réponse et qu'il est possible pour nous de recevoir de l'argent si on prend le deuxième utilisateur qui n'a pas de compte stripe et qu'on réeffectue cette requête on peut voir que la valeur est à false ça veut dire que cette personne là ne pourra pas recevoir d'argent maintenant j'ai également envie d'appeler cette méthode dans mon hos contrôleur ici dans cette dernière méthode qui permet de récupérer les informations de l'utilisateur connecté et identifié il est temps de rajouter cette logique côté client on va donc retourner sur notre application de chat et afficher ces informations sur notre interface si tu aimes notre contenu n'hésite pas à t'abonner à la la chaîne Youtube retrouveras toutes les informations dans la description ainsi que des liens vers nos articles de blog et un lien pour t'inscrire à notre nouvelle newsletire j'espère que ça te plaira on va énormément parler du framework remix dans les prochaines semaines déjà je vais aller dans le fichier route.tfx et on peut voir dans mon loeur que nous avons une méthode qui s'appelle get optional user qui nous permet de manière optionnelle de récupérer l'utilisateur si jamais il est connecté je vais cliquer sur cette méthode et je vais cliquer sur le schéma Zod et je vais rajouter mon boulien can money qui est un Z Boolean je vais retourner sur mon application et rafraîchir la page pour voir si on a eu une erreur de Zod nous n'avons eu aucune erreur maintenant je retourne toujours dans le rote j'aimerais récupérer mon utilisateur optionnel avec le hook use optional user et nous allons faire un affichage conditionnel vu que l'intégration des paiements a été effectuée nous allons rajouter un div qui affichera une information si l'utilisateur peut recevoir des paiements alors votre compte est est bien configuré pour recevoir des donations sinon vous devez configurer votre compte pour recevoir des donations maintenant je vais faire un deuxième affichage conditionnel ici pour afficher ce message seulement si l'utilisateur est connecté et nous allons afficher ça envers si l'utilisateur peut recevoir ces donations sinon nous allons l'afficher en rouge je vais retourner côté front pour voir si ça a bien fonctionné et on peut voir qu'on a bien notre message en vert votre compte est bien configuré pour recevoir des donations si maintenant je me connecte à l'autre compte donc le compte de Cédric on peut voir là que j'ai un autre message vous devez configurer votre compte pour recevoir des donations on va donc retourner côté API pour permettre aus utilisateurs qui n'ont pas encore activé le processus downboarding de pouvoir l'activer donc la méthode qui nous intéresse c'est surtout le Create Account Link et le create connected account on peut voir que pour déclencher la méthode Create connected account nous avons besoin d'un compte utilisateur ensuite nous récupérons un lien de paiement donc un lien d'boarding généré par stripe c'est cette méthode qu'on veut appeler pour créer notre compte stripe et son lien d'mording donc on va voir où cette méthode a été appelée elle a été appelée sur la route stripe/cnect nous allons donc en tant qu'utilisateur identifié mais pas connecté à stripe faire un post sur cette routeel je retourne donc côté client et dans le fichier os.serveur.ts nous allons copier une méthode que nous allons appeler start stripe onboarding et pour se faire nous allons utiliser notre méthode utilitaire secher qui prend une request une URL une méthode POST et vu que c'est un poste nous allons mettre un objet data annul et nous allons appeler la route stripe Connect ensuite nous allons créer un schéma Zod stripe Connect schéma qui va nous renvoyer un account link sous forme de string et nous allons le parcer avec Zod faisant un point parce mant on retourne côté serveur et on s'assure que c'est bien la donnée que nous renvoyons ici on renvoie un account link directement on voit bien ici que j'ai précisé que l'acount Link était un string donc nous allons pour être sur fortement typer notre méthode Create connected account ça sera donc une promesse qui va renvoyer un account link sous forme de string donc modifier ce type et je vais l'appeler account link on va copier cette ligne pour la coller tout en bas et nous allons même copier ce type là ici pour être vraiment sûr que nous renvoyons bien la donnée conforme maintenant j'ouvre l'explorateur de fichier et je vais créer une nouvelle route qui va s'appeler onboarding point TFX et ça ne sera pas une vue ça sera seulement une API je vais donc exporter une action dans cette action nous allons faire un require user pour forcer les utilisateurs connectés à appeler cette route nous allons évidemment await le require user et nous allons ensuite appeler notre méthode start stripe unboarding qui prend comme objet notre request notre stripe unboarding nous renvoie un lien pour faire l'unboarding sur stripe maintenant au lieu de renvoyer nul nous allons faire une redirection sur ce lien de paiement donc nous allons directement renvoyer l'utilisateur sur le site de stripe pour qu'il puisse effectuer son unboarding j'ai mis cette logique dans une action ça signifie que l'utilisateur doit soumettre un formulaire à l'intérieur de notre application pour pouvoir être renvoyé vers le lien downboarding je vais également return cette méthode de redirection mais on se rappelle dans notre stripe service que nous avions défini une refresh URL qui permet au cas où l'utilisateur n'a pas rempli son profil à temps de regénérer son lien d'boarding donc ici je vais mettre à la place onboarding et nous allons copier toute la logique de cette méthode dans dans une méthode loader qui va faire exactement la même chose donc qu'on fasse une action ou un loader on est redirigé sur l'unboarding de stripe donc qui ne sert à rien autant commenter l'action maintenant je vais retourner dans mon fichier route et je vais rajouter une condition si l'utilisateur ne veut pas recevoir de l'argent alors nous allons renvoyer un lien vers la page onboarding et on va appeler ça comment je configure mon compte sinon nous n'allons rien envoyer maintenant je vais retourner dans mon application et je vois toujours ce message vous devez configurer votre compte pour recevoir des donations et je peux cliquer sur je configure mon compte je vais donc cliquer sur ce lien avec le compte de Cédric et on peut voir que ça a générer le compte stripe et je suis à présent sur le lien doneboarding je vais donc redonner le même numéro de téléphone et nous allons refaire le process nous allons remplir le profil exactement de la même manière et nous allons utiliser le même compte de test j'accepte les paramètres et maintenant stripe va me rediriger vers l'application et cette fois mon compte est bien configuré pour recevoir des donations si on retourne sur le dashboard stripe on peut voir qu'on a maintenant nos deux comptes qui sont actifs et qui peuvent recevoir des donations on peut donc retourner sur la documentation des comptes connectés nous nous étions arrêtés à l'étape create connected account et nous avions même créé notre lien d'barding maintenant nous devons accepter un paiement de la part de stripe et nous avons le choix soit d'utiliser du NO code c'est-à-dire de laisser stripe gérer toute la logique et juste de renvoyer l'utilisateur sur une page hébergée par stripe et c'est ce que nous allons faire aujourd'hui ou alors nous pouvons intégrer directement un formulaire de paiement dans notre application on peut donc copier cette logique de code qui va créer une session checkout donc un paiement au moment d'effectuer une donation pour se faire je vais créer cette logique dans une méthode que je vais appeler create donation et cette méthode prend en paramètre un stripe account ID mais ce stripe account ID sera l'ID de la personne qui va recevoir l'argent donc je vais appeler cette méthode receiver stripe account ID je vais donc copier la logique pour générer une s de checkout et on peut voir qu'on a des line items donc un tableau de prix ou d'articles que nous vendons et des informations quand tu as nos paiements par exemple la taxe que nous voulons récupérer en tant que plateforme qui permettons de faire des échanges de dons vu que c'est des dons nous allons mettre un montant égal à 0 et en destination ID nous allons mettre notre receiver stripe account ID mais avant de le mettre nous allons quand même récupérer les informations via stripe en faisant un stripe accounts retrieve et en passant notre ID maintenant nous pouvons mettre la destination c'est notre receiver stripe account.id pour le moment l'URL de succès sera localost 3000 et l'URL d'annulation sera localost 3000 maintenant ce morceau de code n'est pas fini on a quand même besoin de créer un price donc pour créer notre price nous allons faire const Price est égal à await 10.stripe. prices en gros nous allons créer un objet de prix sur stripe en disant que la devise on va bien payer en euros mais on va quand même retourner sur la documentation de stripe parce que j'ai un petit doute donation là en fait j'aimerais aller sur let let customers decide what to pay c'est-à-dire laisser le client choisir le montant qu'il souhaite donner et pour se faire on peut voir que nous avons d'abord besoin de créer un produit stripe parce que que ça soit des articles ou des donation on a besoin de créer un produit sur stripe puis on crée notre prix et on l'ajoute à notre produit donc je vais copier également cette ligne là je vais créer un premier produit que nous allons appeler soutenz first name donc notre méthode va également prendre une variable firstn qui sera le nom de la personne qui reçoit notre don ensuite comme nous venons de créer un produit sur stripe nous allons rattacher notre prix au produits que nous venons de créer et nous allons activer l'option custom unit amount qui signifie qu'on permet aux utilisateurs de choisir le montant qu'il souhait payer maintenant on a créé un produit on a créé un prix et nous allons mettre ce prix en première ligne de notre session ensuite nous pouvons créer notre session de checkout donc la logique que nous avions copié au préalable on peut voir sur ce schéma ce qui va se passer le client va donc acheter son article ou effectuer sa donation de 10 dollars le transfert s'effectue et il arrive sur le compte connecté ensuite si nous avions décidé d'ajouter notre taxe la taxe de l'application de fonctionnement alors c'est cette taxe sera soustrait du compte connecté et renvoyé à la plateforme le compte connecté recevrait donc une donation de 8,77 dans ce cas-là des frais que nous récupérons il y a stripe qui soustrait une partie de nos frais et on recevrait donc un bénéfice de 64 centimes si un utilisateur effectuait une donation de 10 dollars sauf que c'est pas notre cas nous avons décidé de récupérer aucun frais sur cette donation cette session contient une URL de paiement et nous allons la renvoyer côté client et nous allons l'appeler session URL sauf que on ne va pas créer un produit stripe par donation en fait le produit on n pas besoin de le créer à chaque fois vu que le produit c'est au final l'utilisateur qui reçoit le don donc ce produit on peut le créer à la création du compte utilisateur par exemple donc ici nous devons implémenter une logique ne pas créer le produit à chaque fois ce compte son ID en base de données dans les informations de l'utilisateur qui reçoit l'argent à chaque donation nous rajouterons pour implémenter toutes cette logique nous allons faire quelques modifications d'abord nous allons récupérer l'id de l'utilisateur qui reçoit la donation on va donc rajouter un paramètre receiver user ID qui sera en string on va également récupérer comme paramètre de notre fonction comme nous recevons maintenant le user ID de la personne qui reçoit notre don on a plus besoin de passer le first name comme paramètres nous allons plutôt récupérer l'utilisateur en demandant à Prisma de nous le renvoyer on va donc faire un f unique or sur le user ID que nous passons au paramètres de cette fonction maintenant nous pouvons réellement utiliser son firstn pour cela nous allons le sélectionner et nous allons aussi récupérer le stripe product ID qui est une valeur qu'on n pas encore créé donc nous allons modifier le schéma Prisma et nous allons rajouter un stripe product ID qui sera un string et qui sera également unique maintenant pour chaque donation que nous effectuons à nos utilisateurs nous avons envie de pouvoir les lister donc on va également créer un nouveau modèle qu'on va appeler donation on va copier cette formule là et nous allons dire que chaque donation est donc relié un striped product ID et chaque donation est relié à un stripe price ID le stripe price ID c'est le prix que nous sommes en train de créer pour cette donation nous retournons donc dans notre schéma Prisma et nous allons rajouter deux autres champs effectivement une donation s'effectue entre deux utilisateurs on a l'utilisateur qui reçoit la donation et on a l'utilisateur qui envoie la donation donc on va sauvegarder le giving user le giving user c'est donc l'utilisateur qui envoie l'argent il le donne giving et on va rajouter un index sur le giving user ID on va également dans le modèle user et on va rajouter un champ qu'on va appeler given donations évidemment ce sera une relation et on peut mettre que cette relation sera liée à notre giving user maintenant on va rajouter la personne qui reçoit la donation donc je vais copier ce Marceau de code et je vais mettre receiving user qui sera donc lié au receiving user ID que nous allons rajouter ici je vais également rajouter l'index pour le receiving user ID sauf que Prisma nous alerte à ce qu'on a un petit problème nous avons deux fois une relation au model user dans notre même modèle de données alors comment est-ce que Prisma peut savoir à quel user assigné cette donation ben nous devons retourner dans le modèle user et nous allons créer un deuxième tableau de donations que nous allons appeler received donations sauf que ici il nous disent vous devez fournir un nom pour cette donation donc le nom que je vais fournir c'est ce noml c'est-à-dire giving user effectivement les given donations sont en relation avec le champ du modèle donation qui s'appelle giving user au même titre ici je copie le nom given donations et je vais laajouter comme premier champ ici pour bien lier cette relation maintenant je vais faire la même chose pour les received donation en ajoutant le nom et ça va être le receiving user si on retourne maintenant dans le modèle de données on doit également fournir un nom pour le giving user et pour le receiving user et ben je vais utiliser la même valeur de ce côté-là de la relation c'est-à-dire giving user prendra comme nom giving user receiving user prendra comme nom receiving user on va maintenant ouvrir une deuxième fenêre de terminal et nous allons faire un NPX Prisma dB poche pour sauvegarder nos changements en base de données maintenant qu'on a changé notre modèle de données on peut retourner dans notre service stripe ici nous récupérons donc l'utilisateur existant et nous récupérons son stripe product ID nous allons donc rajouter une condition si l'existing user ne possède pas encore de stripe product ID donc que son product ID est égal à nul parce qu'aucune donation ne lui a été faite alors nous allons créer ce produit ensuite nous allons mettre à jour notre utilisateur et nous allons lui assigner le bon stripe product ID ensuite nous avons besoin ici du stripe product ID donc que l'utilisateur possède un produit ou pas dans tous les cas nous allons le créer nous allons donc récupérer ici dans une dstructuration le stripe product ID et s'il n'existe pas dans C cette fonction alors nous allons rassigner une valeur à notre variable qui sera la valeur que stripe nous aura renvoyé comme ça nous avons bien notre stripe product ID à la prochaine ligne donc cette partie a été faite maintenant nous avons créé un prix et comme nous avons créé un prix nous allons faire un await de dis Prisma donation et nous allons créer une nouvelle donation avec comme donné le stripe price ID qui aura comme ID l'ID de notre prix nous venons de créer on va aussi le lier à notre stripe product ID qui sera lié à notre utilisateur et nous allons également le lier aux deux utilisateurs c'est-à-dire l'utilisateur qui reçoit l'argent c'est celui-là c'est existing user on va donc l'appeler receiving user pour que ça ne soit plus ambigu et le receiving user sera donc connecté à l'ID du receiving user que nous allons sélectionner à ce niveau-là maintenant nous devons également identifier la personne qui envoie l'argent la personne qui envoie l'argent ça sera l'utilisateur identifier donc ça sera le giving user ID c'est également un string et nous allons également faire une recherche avec Prisma sur giving user et nous allons récupérer son ID maintenant au lieu de faire ces trois requêtes à la suite on peut faire un premier scoll pour les exécuter simultanément on va donc d'abord récupérer les informations sur stripe ça sera donc notre première valeur du tableau ensuite nous allons récupérer le receiving user ID qui sera donc notre deuxième valeur du tableau et ensuite nous récupérons le giving user ID qui sera notre 3ème valeur de notre tableau de promesse maintenant que nous avons récupéré toutes les informations on peut passer à la suite au moment moment de créer notre donation nous allons également la connecter à notre giving user ID et pour cela nous avons besoin de rajouter cette ligne de code et nous avons maintenant terminé on va ouvrir notre terminal pour voir s'il n'y a aucune erreur et on va maintenant supprimer ce commentaire et créer notre première donation je copie donc le nom de cette méthode et je vais dans le stripe controller et je vais créer une nouvelle requête qu'on va appeler donate et ça sera create donation qui appellera la méthode Create donation on voit bien que cette méthode nous renvoie une URL de sessions c'est-à-dire on va envoyer une URL nous redirige sur stripe pour procéder au paiement de la donation donc dans notre contrôleur on a besoin de trois arguments l'utilisateur qui effectue le don donc qui crée la donation c'est l'utilisateur qui est identifié par token JWT c'est donc le request.user.userid ensuite on a besoin de récupérer le receiving user ID et et cet ID nous ne l'avons pas pour le moment on va donc la passer en paramètre d'URL on va dire receiving user ID est un paramètre du ur donc je vais rajouter le décorateur param que je vais nommer receiving user ID prends la valeur de l'URL et je vais la sauvegarder dans une variable qui sera un string et je vais la passer dans ma méthode maintenant on a une dernière valeur et c'est le stripe account ID et au final on n' plus besoin de cette valeur effectivement le compte stripe doit déjà être lié à l'utilisateur sinon il ne peut pas recevoir de Don jeis également renommer ce nom de variable qu'on soit consistant dans notre nomage et notre premier utilisateur leing user va également nous donner le le stripe account ID donc nous allons déplacer cette logique là et si leing user ne possède pas de stripe account ID donc qu'il est égal à nul alors nous allons renvoyer une erreur de type l'utilisateur n'a pas de compte stripe et ne peut pas recevoir de Don sinon alors nous allons demander à stripe de nous renvoyer les informations suivantes stripe account on prendra donc le stripe account ID de notre receiving user pour s'assurer qu'il existe réellement ensuite tout en bas ici nous allons mettre en destination le compte connecté de stripe de notre utilisateur maintenant on peut retourner dans notre contrôleur et enlever ce paramètre que nous avons renommé pour faire un don nous devons donc faire un post sur la route stripe/date/ et l'ID de l'utilisateur nous allons donc tester cette intégration sur postman pour cela je vais copier cette méthode que je vais appeler donate et ce sera donc un post sur stripe/donate/userid je vais donc d'abord me reconnecter par token puis je place le token ici pour récupérer les informations de l'utilisateur notamment son ID et nous allons faer un petit test déjà un utilisateur ne peut pas se donner de l'argent à lui-même donc si le receiving user ID est égal au giving user ID alors nous allons th une erreur vous ne pouvez pas vous faire de don à vous-même maintenant je vais aller sur postman et je vais tester cette première protection on va donc faire un post sur donate en étant connecté à l'utilisateur qui effectue le don j'oublie pas de mettre le bon token j'envoie ma requettete là on peut voir que j'ai un internal serveur erreur si je regarde le terminal on peut voir mon message d'erreur vous ne pouvez pas vous faire de don à vous-même même on va donc rajouter notre type promesse qui renvoie une erreur sous forme de boulet 1 et un message sous forme de string et il peut également renvoyer une session URL sous forme de string ou alors une valeur nulle maintenant je vais englober toute ma logique dans un trcatch et à ce niveau-là if error instance of error alors nous allons renvoyer une erreur à trou et un message qui est égal à error point message nous allons également renvoyer un status URL qui est égal à nul sinon si on arrive jusqu'ici ça veut dire qu'on a effectivement réussi à créer notre donation on a donc pas d'erreur et le message sera égal à la donation la session a bien été créée maintenant je vais retourner sur postman je renvoie ma requettete et on a donc notre message d'erreur qui est à trou vous ne pouvez pas faire de nom à vous-même donc je vais ouvrir un nouveau onglet de terminal pour me connecter à Prisma et j'aimerais récupérer l'id de l'autre utilisateur à qui je peux faire un don Virgil maintenant que j'ai cet utilisateur je vais remplacer l'ID sur Prisma je vais faire mon poste et on va voir ce qui se passe on a donc le message de succès la session a bien été créée et on a un lien pour effectuer un paiement si on retourne sur Prisma on peut même voir on a une donation qui vient d'être créée et qui est associée à un prix stripe à un produit stripe et à nos deux utilisateurs je vais donc cliquer sur le lien pour faire ma donation je vais donc donner 2 € à Virgile je vais bien fournir mon email et mes informations bancaires on va donc mettre 42 42 42 42 42 qui est la valeur des cartes de test de stripe payer le paiement a bien été effectué ça m'a renvoyé sur l'URL de succès qui est le site web et si je retourne sur stripe en mode test et que je vais dans les paiements on peut voir que nous avons un paiement de 2 € qui a été fait si je clique dessus on peut voir qu'il est lié au client Virgil rich qui est un guest maintenant si je retourne dans Connect je peux voir mes clients connectés et je peux voir que Virgil a 2 € sur son solde ça veut dire qu'il peut à tout moment retirer ces 2 € et les reverser sur son compte bancaire maintenant si j'ai créé un nouveau modèle avec la donation c'est pour stocker en base de données la valeur du don qui a été fait comme ça je pourrais l'afficher côté front sauf que pour le moment c'est pas possible on ne peut pas déterminer à l'avance combien d'argent va donner un utilisateur on ne connaît pas le montant de son don à l'avance effectivement quand on crée une donation on arrive tout de suite sur l'interface de stripe et c'est à ce niveau-là qu'on va entrer notre prix et stripe se charge du reste mais ce qui serait cool c'est d'avoir des notification de la part de stripe pour nous informer de la valeur du don qui a été faite comme ça on peut le sauvegarder dans notre base de données et c'est totalement possible de le faire pour le faire il faut qu'on aille dans l'onglet developpers ici et nous allons cliquer sur Web hooks et on va découvrir une autre fonctionnalité de stripe qui s'appelle les web hooks effectivement ça se passe un peu comme sur ce schéma ça c'est moi et j'ai envie de faire ma donation à stripe du coup je vais faire une requête je vais envoyer l'argent et stripe va le recevoir et il va traiter ma requête il va faire des vérifications ça va pas se passer tout de suite ça peut même prendre plusieurs heurees mais une fois que c'est terminé stripe peut me renvoyer les informations du paiement il peut me dire écoute le paiement il a réussi ou le paiement il n'a pas réussi il a échouer et ensuite moi de mon côté je peux mettre à jour ma donation avec la valeur de son prix pour se faire je dois donc donc ouvrir une nouvelle route dans mon application API que stripe pourra contacter je vais donc cliquer sur test inlocal environment parce que pour le moment on n pas encore hébergé notre application sur un serveur et sur le côté il nous donne un exemple de test avec notre JS pour implémenter cette fonctionalité effectivement ils vont nous donner un nouveau secret une nouvelle variable d'environnement qui s'appelle endpoint secret c'est le secret pour signer les webhook on doit donc créer une nouvelle requête POST par exemple sur l'url/webhook et ça sera de type jison nous devons ensuite récupérer la signature de stripe dans les headers et nous devons également récupérer l'événement que stripe nous envoie et cet événement nous allons le construire avec le corps de la requête que strip nous envoie la signature que stripe nous envoie et notre secret ensuite on peut utiliser un switch pour traiter tous les cas possibles que stripe nous met à disposition par exemple on peut voir ici sur la gauche que il y a plusieurs types d'événement par exemple le paiement a réussi l'abonnement a échoué et cetera il y a vraiment plein d'événements qui sont dispo donc on va commencer par copier cette logique là je vais copier le contenu de mon poste et je vais retourner dans mon application nasjs on va maintenant dans le stripe controller et on va créer une nouvelle Rocket po cette fois qui ne sera pas dynamique et qui va s'appeler web je vais créer une méthode qu'on va appeler handle web hooks et nous allons récupérer la request dans cette request on pourra récupérer les informations que stripe nous envoie ensuite on peut aller dans notre service stripe et nous allons appeler la méthode handle web hook il va prendre en paramètre notre request cet objet request prendra le type request que nous pouvons apporter de express et nous allons coller le code que nous avons copié depuis stripe on récupère donc la signature qu'on retrouve dans les headers de stripe ensuite on instantie un événement et cet événement prendra le type stripe.event pour le moment il est égal à nul et nous allons faire un try catch pour construire cet événement nous allons mettre que l'event est égal à 10. stripe donc notre service pointwebhook et on va faire un construct de l'event maintenant pour le moment en cas d'erreur on a rien envie de faire on va juste faire un console. error et on va afficher notre erreur ensuite pour le endpo secret nous allons utiliser le secret que nous avons pas encore sauvegardé pour le moment ils nous ont donné un secret ici mais ce qu'on va faire c'est qu'on va se connecter au terminal de stripe et on va générer un secret automatiquement comme on na pas encore hébergé notre site web on ne peut pas utiliser un secret que nous créons ici dans cette interface donc pour le moment on va dire que notre secret c'est cette valeur là et en cas de succès nous allons renvoyer tout simplement un erreor à false et un message à webbook handled successful maintenant ant là c'est la deuxième étape on va se connecter à notre terminal à stripe mais avant de pouvoir se connecter à stripe nous devons installer l'outil de CLI donc je vous invite à cliquer sur le lien download de CLI et ça nous emmène sur cette page et vous pouvez installer le CLI avec n'importe quel installateur par exemple homebrew ou Windows ou docker je vais donc taper cette commande parce que j'utilise homebrew dans mon terminal on peut voir que ça va mettre à jour quelques-uns de mes librairies je retourne maintenant sur l'interface et je vais taper la commande stripe login et on peut voir qu'il me donne un code et qu'il me demande d'accéder à une nouvelle URL dans mon navigateur j'y accède et il me disent est-ce que j'autorise ce compte là à se connecter et est-ce que vous avez bien le bon code effectivement c'est bien le code qu'ils m'ont donné dans mon terminal on peut voir que c'est Wars wows cheer Galor je vais donc autoriser l'accès et maintenant on vient de créer notre accès au web si je retourne dans mon terminal on peut voir que ça créé un compte CLI pour algomax.fr avec sat compte ID je retourne maintenant dans cette documentation là et je vais taper cette ligne de code c'est-à-dire on va écouter tous les événements que stripe nous envoie à chaque paiement qui est effectué chaque paiement qui échoue à chaque paiement qui est réussi et nous allons les renvoyer sur le local host 8000/stripe/webhook donc je vais copier cette commande dans mon terminal et je vais faire un stripe Len sur le port 8000 de localhost/ stripe/webhook qui est la nouvelle route que nous avons créée dans notre stripe controller maintenant j'appuie sur Entrer et c'est à ce niveau là qu'ils m'ont donné mon web hook signing secret je vais donc copier précieusement ce secret je vais maintenant dans mes variable d'environnement et je vais ajouter ici le secret qui m'ont donné qui a comme valeur stripe webhook secret je retourne maintenant dans le stripe service et à la place de ce secret codé en dur je vais mettre process.ind.stripe webhook secret et on va mettre que si il n'est pas définé alors on va TR une erreur maintenant je vais tout englober dans un try catch et on va fortement typer cette fonction pour avoir un feedback en C erreur maintenant à chaque fois qu'on reçoit un nouvel événement depuis stripe il sera cons logué dans le default de notre switch à chaque fois que vous ferez des tests qui utilise stripe en local vous aurez besoin de rester connecté d'écouter les notifications que stripe nous envoie on doit donc laisser ce terminal ouvert d'ailleurs il nous affichera tous les événements que stripe nous aura envoyé durant la période maintenant je vais retourner sur postman et je vais créer une nouvelle donation clique sur send et on va retourner dans notre application et on peut voir ici qu'il y a plusieurs événements par exemple événement price created qui signifie que nous avons créé notre prix sauf qu'on a une erreur dans notre terminal effectivement nous avons besoin de la request en RAW sauf qu'avec Express on a renvoyé la request pas en RAW mais par C sous forme d'objet donc on va aller sur Google et on va taper nestjs RAW request body et on va aller sur l'article de la documentation de nestjs qui va nous expliquer comment récupérer le body en rou depuis nest on peut voir ici qu'on a besoin de modifier notre fichier main points de rajouter une configuration dans la méthode Create de la nest factor je retourne donc sur la PI et je vais dans le dossier MAIN.S et ici on peut voir que R body a déjà été configuré on retourne donc sur la documentation de nest et ici en fait on a besoin de récupérer le request.r body donc nous allons hériter de ce type je vais retourner dans mon fichier et je vais mettre que ici on va passer un Rob body request maintenant on retourne notre contrôleur et on va typer cette méthode en disant que c'est un Rob body request sauf que le type request ici est égal au décorateur qui s'appelle également request avec un r majuscule donc on ne peut pas utiliser ce type là effectivement on voit qu'on utilise le décorateur à ce niveau-là nous on a besoin de récupérer le type request on va impemporter depuis Express on peut voir sur la documentation que nous récupérons bien le décorateur sauf qu'on utilise également le décorateur REC que NGS a mis à disposition pour qu'on puisse importer le type d'Express donc on a deux choses à faire soit on va utiliser le décorateur REC et on importe le type request depuis express soit on conserve le décorateur request mais on importe le type de P request en le renomment en par exemple request type et c'est ce que nous allons faire on va donc renommer le type request en request type et je vais le mettre ici comme argument je sauvegarde et nous allons aller sur postman pour récupérer l'url et faire un deuxième don cette fois je vais donner 5 € à Virgile on va mettre notre carte bancaire de test on va payer et maintenant je retourne côté API et là on peut voir qu'on a vraiment un spam avec plein de request qui ont été fait on a donc price created transfer created charge succeeded payment created et cetera si on retourne dans documentation de stripe on peut voir qu'on a un onglet received events qui nous liste tous les événements qui ont été envoyés l'événement qui nous intéresse c'est l'événement qui s'appelle charge. suucceeded parce qu'il possède le montant qui a été payé par l'utilisateur et nous allons le sauvegarder en base de données pour pouvoir l'afficher dans notre application je vais donc retourner dans mon application et je vais rajouter une condition pour l'événement charge.succeeded et on va récupérer notre charge qu'on récupère depuis event.data.object maintenant je me pose une question est-ce que on peut récupérer le product ID et le price ID depuis notre charge effectivement sur Prisma ici on peut voir que notre donation possède un product ID et un price ID on pourrait même aller jusqu'à dire que notre price id est unique qui je vais d'ailleurs le rajouter effectivement pour sauvegarder la valeur de la donation de notre base de données on doit pouvoir récupérer les informations de notre stripe price ID pour pouvoir identifier la donation qui a été faite je viens de demander à chat GPT et apparemment ça reste un peu compliqué de récupérer le price depuis notre charge en effet il nous recommande même de plutôt écouter l'événement payment intent succeeded parce que cet événement là qui se trouve ici payment intent succeeded possède également un montant donc nous allons plutôt écouter cet événement là ensuite à partir de ce payment intent succeeded nous allons utiliser notre filure de stripe qui s'appelle les metadata dans les metadata de ma payment intent je vais rajouter un paramètre et ce paramètre sera ma donation ID que je vais appeler donation ID en effet on voit ici que je créé une nouvelle donation donc je vais récupérer son ID et je vais la renvoyer à stripe ensuite stripe une fois qu'il aura traité le paiement dans l'événement payment intent.succeeded va me renvoyer dans l'objet metadata qu'on peut récupère depuis payment intent succeeded. metadata la donation ID je vais donc la récupérer ici et je pourrais ensuite avec Prisma récupérer la donation et faire un update dessus sur son ID ce sera évidemment un string et je vais mettre à jour le montant qui sera donc l'amount et qui prendra comme valeur l'amount faut savoir que stripe sauvegarde le montant en centimes pour que ça soit vraiment très très précis donc nous allons faire la même chose ici nous allons sauvegarder le montant tel quel ce qu'on va faire maintenant c'est qu'on va rajouter un console log pour s'assurer que la sauvegarde est réellement effectuer je vais donc enregistrer ces paramètres et je retourne sur postman et je vais faire un nouveau don je vais donc lui donner 7 € et je vais renvoyer le code qu'on m envoyer par SMS et je vais payer les 7 € à Virgile je retourne maintenant dans mon terminal et on peut voir ici qu'on a bien reçu le montant qui est égal à 700 soit 700 centimes déjà première nouvelle on reçoit bien les stripe hook et là on peut voir qu'on a reçu la donation ID et qu'on a avec succès réussi à mettre à jour dans notre base de données la valeur de ce don on peut maintenant l'afficher côté front pour vérifier que la sauvegarde est bien fonctionné on va ouvrir Prisma dans une nouvelle fenêtre de terminal et on va regarder toutes les donations qui ont été faites et on peut voir que la dernière possède bien la valeur mise à jour avec le montant de 200 €. donc ce qu'on a fait jusqu'à présent c'est qu'on attend que stripe nous envoie des événements correspondants et ensuite on peut afficher les donations qui ont été faites et je trouve que c'est vraiment très cool maintenant on va implémenter cette logique côté client ce qu'on a besoin de faire c'est donc d'appeler la route donate étant connecté et de passer une ID d'utilisateur si on retourne dans le contrôleur on voit que la route donate va se charger de créer la donation je vais donc copier cette URL et je retourne dans le frontend et je vais coder cette logique dans hos point serveur ici je vais dupliquer la méthode start stripe unboarding et je vais l'appeler create donation qui prendra donc en paramètre le receiving user ID donc l'ID de l'utilisateur qui reçoit l'argent et je vais le passer ici comme argument ça sera donc stripe/donate/re receiving user ID maintenant la logique de cette méthode nous allons la coder dans un nouveau fichier pour que ça soit plus simple je vais donc dupliquer la méthode unboarding et je vais l'appeler donate point et je vais mettre 1 dollar parce que ça va être une route dynamique qui sera exécuté sur le user ID et au lieu d'être un loader ça sera une action donc on va d'abord à la première ligne fa un require user pour récupérer les informations de l'utilisateur connecté et ensuite on va faire un create donation qui va prendre en deuxième paramètre notre receiving user ID et le receiving user ID on le récupère dans les paramètres d'URL parce que c'est la valeur du user ID c'est donc user ID qui est égal à params.useredit on va même s'assurer que ça fonctionne bien en mettant que si le paramètre dynamique n'existe pas alors on envoie une erreur maintenant on peut dire que receiving user ID est égal au user ID qui est le paramètre dynamique sauf qu'on doit aussi modifier ce schéma Zod ici nous allons créer un nouveau schéma Zod une clé erreur qui est un Bouletin ça prendra aussi un message qui est un string et ça prendra une session URL qui est soit string soit égal à nul on va appeler ça stripe donate URL schéma maintenant on va parcer la réponse de notre route et ici on reçoit donc le message d'erreur s'il y en a et l'URL si ça fonctionne bien s'il a donc une URL on va faire une redirection mais si l'erreur est à trou ou on n pas d'URL alors on va TR une erreur pour s'assurer qu'on fasse la redirection seulement s'il n'y a pas d'erreur maintenant on va aller dans notre conversation ID qui est la page de conversation de notre application donc cette page là et ici à côté de l'avatar de Cédric j'ai envie d'afficher le bouton pour lui faire une donation je retourne donc sur VS code et je vais aller dans la chat box ici et on peut voir que j'ai le récipient user qui affiche son image s'il en a une je vais également rajouter un bouton avec comme valeur faire un don et ce bouton sera dans un formulaire parce que nous allons faire un poste et nous allons faire un poste sur la route dynamique/date/ et là je vais mettre le user ID donc le recipient user.id je vais cliquer sur faire un don et on va voir ce qui va se passer là on attend du coup que la requête se fasse côté stripe là on a été redirigé sur stripe je vais faire un don cette fois de 3 € maintenant je vais les payer par carte bancaire le paiement a été effectué et je suis redirigé sur la page d'accueil mais si on retourne sur Prisma studio on peut voir qu'il y a un nouveau don qui est apparu avec la bonne valeur de mes 3 € comme c'est une valeur que nous sauvegardons dans notre base de données on peut afficher côté client et c'est ce qu'on va faire à côté de la conversation j'ai envie de l'afficher donc ici nous allons aller dans chat controller et nous allons récupérer le GET de la conversation ID et dans cette méthode là ici nous allons récupérer les donations qui ont été reçues par cet utilisateur on va donc récupérer le montant et l'ID sauf que voilà nous récupérons là l'utilisateur qui est identifié et qui veut récupérer les données de cette conversation ici je vais mettre qu'on récupère les donations que l'utilisateur a reçu mais seulement cell qu'il a reçu de notre part donc on va mettre un where giving user ID est égal à existing user.id maintenant on va également afficher les donations qu'il a donné et on va récupérer pareil le montant et l'ID mais seulement celle où le receiving user ID c'est mon utilisateur comme ça on s'affiche mutuellement les donations qu'on s'est faites receiving user ID est égal à existing user.id et on va également récupérer la date de création de ces donations maintenant je vais retourner côté front ici dans la méthode GET conversation et nous allons mettre à jour notre schéma Zod donc chaque utilisateur possède des given donations c'est donc un tableau un tableau d'objets avec un montant qui est un number et une created at et une ID qui est un string et nous avons également des received donation qui est le même modèle et nous allons mettre que le montant est un number mais qu'il peut aussi être annul ce qui est le cas pour les premiers montants que nous avons créé effectivement ici le montant il est à nul parce qu'on avait pas encore l'information mais ça ne devrait pas arriver maintenant je vais retourner dans mon composant et je vais retourner dans le chat et ici je vais afficher Je vais boucler sur les donations que l'utilisateur a reçu de ma part on va donc faire un map et on va afficher le montant et la date nous allons parcer évidemment on va afficher le montant en euros donc on va faire un divisé par 100 et on va rajouter euros forcément le montant il peut être égal à nul donc si le montant a été défini alors on va faire cette division par 0 sinon on va y mettre 0 €. on peut donc rajouter notre petit titre don envoyer et on va faire un autre tableau pour les dons reçus et ça sera les received donations maintenant on va aller sur notre application sur notre chat et là on peut voir qu'on a envoyé 0 € 0 € 0 € 2 € et qu'on a reçu 3 € maintenant je vais effacer ce consle log et on va faire un truc assez by je vais aller sur Prisma studio et je vais supprimer toutes les donations pour vérifier que ça fonctionne très bien je vais maintenant sur la page de Cedric je vais faire un don en tant que Virgile à Cedric là il y a un petit délai le temps que stripe reçoive l' formtion je vais lui donner 10 € et je vais lui donner avec mon compte five gamers conceil base Gmail maintenant je vais payer les 10 € et je vais être redirigé vers la page d'accueil maintenant si je vais sur mon historique salut Cédric l'envoi de Don fonctionne très bien et la valeur a bien été enregistrée par stripe c'est-à-dire qu'il nous ont fait un web hook ce qui est plutôt super cool on peut voir maintenant sur l'interface de stripe dans les comptes connectés si je clique par exemple sur ce compte là que les règlements sont effectués automatiquement tous les jours et les paiements ont été activés ça veut dire que ce comptel avec lequel nous avons fourni nos informations de paiement et notre RIB recevra l'intégralité de l'argent donc l'intégralité de ces dons tous les jours il nous reste plein de choses à faire avant de pouvoir mettre cette application en prod effectivement dans nos variables d'environnement nous avons généré notre secret web hook à la voler grâce au terminal de stripe mais quand on mettra en prod on a'ura pas besoin d'avoir un terminal d'ouvert effectivement stripe pourra automatiquement contrôler notre contrôleur parce qu'on le configurera pour le faire on a maintenant terminé de développer ce projet et maintenant nous allons devoir l'éberger on a donc nos deux bases de code en local et on va devoir les mettre sur un serveur et exécuter le code en continu on a donc notre base du code du Front End ici qui est le projet nestgs chat front notre application remix et nous avons aussi notre serveur qui est l'API nest JS et l'approche va être exactement pareil pour mettre en ligne ces deux projets on va faire la même chose et nous allons d'abord le faire pour nest JS puis ensuite nous allons répéter l'opération pour remix pour ce faire nous allons utiliser plusieurs technologies la première ça sera d'utiliser dockur pour créer une image de notre projet à chaque changement de notre code avant de le mettre en ligne nous allons donc créer une image on va donc faire un build avec docker que nous allons envoyer au serveur le serveur va télécharger cette image et il va ensuite l'exécuter et pour l'exécuter automatiquement nous allons utiliser les GitHub actions ici qui est une fonctionnalité entièrement gratuite de GitHub qui va nous permettre justement de construire notre image dockur automatiquement à chaque mise à jour de notre code et ça sera également GitHub qui va se charger d'envoyer cette image de cœur à notre serveur et bien sûr nous parlons de serveur donc on va avoir besoin de commander un serveur qui va tourner en continu et qui va se charger d'exécuter notre code pour mieux comprendre quel serveur vous devez choisir je vous conseille la vidéo qu'on avait créée sur la chaîne qui s'appelle comment héberger tes projets javascript sur un serveur VPS ce qu'on va faire aujourd'hui c'est exactement le même esprit sauf que je vais utiliser un serveur que j'ai déjà commandé sur l'hébergeur hostinger ici on va donc commencer par le début et la première partie c'est de créer une image do cur nestgs on va donc se rendre à la racine de notre projet nest JS ici et nous allons créer un nouveau fichier qu'on va appeler docker file je vais ensuite copier le docker file que j'utilise en entreprise et on va le regarder ensemble comme vous voyez sur le docker file ici on a un lien qui nous redirige vers un site c'est un site que j'ai utiliser pour m'inspirer du docker file pour l'utiliser avec nestugs et on peut voir qu'on peut retrouver le do file ici sauf que j'ai utilisé la version un peu plus compliquée qui est optimisée pour la production en gros ce qu'on est en train de faire c'est qu'on a en train de télécharger une image de node node JS la version 20 et on utilise la version alpine de cette image puis ensuite on configure la variable d'environnement node invv et à partir de là on va créer un dossier qu'on va appeler slash app et dans ce dossier nous allons copier le package. Jon et le package lock.jison on copie toujours ces deux fichiers en premier pour ajouter du CH à notre docor file ensuite après avoir ajouté ces fichiers nous allons ajouter donc tout le contenu de notre projet ici et nous allons exécuter la commande NPM install ce qui va installer toutes les dépendances sauf les dépendances de développement parce que nous sommes en environnement production comme nous souhaitons également télécharger les dépendances de développement parce qu'on en a besoin pour build l'application on rajoute la commande t- include ég dev ensuite après avoir téléchargé toutes les dépendances on va donc rajouter le dossier Prisma qui est ici et nous allons lancer la commande NPX Prisma generate ce qui va générer les déclarations de type et le code source de notre Prisma et ensuite nous pouvons faire un build de notre application donc de notre serveur nest JS sauf que comme on a téléchargé toutes les dépendances y compris les dépendances de l'environnement de développement on a pas envie de conserver tous ces fichiers en production parce que comme sonindiique les dépendances de développement donc toutes celles-ci ne seront pas du tout utilisées enenvironnement de production elles ne seront pas utilisées c'est pour ça qu'on appelle ça des dépendances de l'environnement de développement c'est pourquoi on repart d'e autre base ici et nous copions ensuite tous les fichiers sauf qu'à la fin on fait un prune et on et toutes les dépendances de développement c'est-à-dire que ça va conserver notre fichier not module et on va supprimer chaque fichier qui est en fait une dépendance de développement et enfin après avoir fait ça on repart de nouveau d'une base vierge et nous téléchargeons les librairies nécessaires par exemple les fuseaux hire français cette ligne n'est pas nécessaire mais j'en avais besoin dans mon application et enfin nous créons un utilisateur qui s'appelle donc remix- API si vous voulez on peut le renommer en nestjs et qui va finalement copier le package Jon le fichier l qui est donc le fichier compilé et les nodes modules de production et enfin ça va exécuter la commande start.sh et un fichier source qu'on n pas encore créé nous allons donc le créer tout de suite on va donc ajouter un nouveau fichier qu'on va appeler start.sh et nous allons copier ces trois lignes de code c'est-à-dire en premier on définit bien ce fichier comme utilisant le terminal SH et ensuite on défini les permissions et enfin on fait un Prisma myret deploy ce qui va donc déployer toutes les migrations Prisma et enfin on va lancer le NPM runst ce qui va exécuter notre serveur en environnement de production maintenant qu'on a fait ça on va pouvoir build cette image docker mais d'abord on va rajouter un dernier fichier qui s'appelle le docker ignor comme ceci au final il s'appelle point decore ignor et c'est exactement pareil que le git ignor nous allons ignorer certains fichiers parce que ici on peut voir qu'on a une commande qui va copier tous les fichiers dans notre image docker mais nous on a pas envie par exemple de copier les noes modules ou le dis donc il nous suffit de rajouter dist et not module et en fait tous les fichiers qu'on a pas envie de copier par exemple le dossier test je n'ai pas envie de le copier le dossier docorignor je n'ai pas envie de le copier les points en et les points en point ex on n pas envie de les copier et tout ce qui est configuration SOS lint le git ignor le prti RC le docker file tout ça au final on n a pas besoin pour exécuter notre code on peut même ignorer le redmi et c'est à peu près bon maintenant donc maintenant on va ouvrir un terminal et il faut bien sûr télécharger docker si vous ne l'avez pas déjà fait alors pour télécharger docker vous allez sur Google et vous tapez download docker et on va sur le premier lien docker Desktop et ici vous avez une option pour le télécharger pour votre système d'exploitation donc pour Mac Windows ou Linux je l'utilise sur Mac donc là c'est cette application là ça ressemble à ça c'est exactement le même design sur les autres systèmes d'exploitation et on peut voir ici qu'on a aucune image qui est lancée et aucun conteneur qui est lancé donc maintenant ce qu'on peut faire c'est qu'on peut dans notre terminal lancer la commande docker build- T et là nous allons nommer notre repository dockur qu'on n pas encore créé sur la plateforme et que nous allons appeler comme le nom du projet nest JS t chat- API et nous allons le mettre dans algomax qui est le nom de l'organisation que j'ai créé sur docker on va faire tout ça après là on teste juste la commande et on a envie d'exécuter le build dans le dossier qui est présent ce que le cor va faire c'est qu'il va détecter notre fichier de core file il va détecter le fichier de core ignor et il va exécuter une par une toutes les instructions de notre fichier de corore file comme ceci on va faire un test on peut voir que ça builde bien chaque étape de notre application on est déjà à l'étape 14 et bien sûr ce qu'il faut savoir c'est que comme on rajoute du cash les builds consécutifs ne vont pas répéter les étapes qui ont déjà été faites par exemple le premier build c'est toujours le plus long parce que on télécharge les dépendances le package Jon qui est ici mais si par exemple je vais dans un fichier le MAIN.S et que ici je rajoute un console log et que je refais un build et ben ça va refaire toutes les étapes depuis le début sauf que ça va commencer à partir de l'étape 14 par exemple c'est-à-dire que ça ne va pas réinstaller toutes les dépendances parce que le fichier package jison n'a pas été modifié bien sûr dans le cas où j'installe ou que je désinstalle une librairie dans ce cas-là ça va reprendre plus haut par exemple à l'étape 9 ou à l'étape où on installe toutes les librairies donc là on est très bien il y a pas eu d'erreur et ce qu'on va faire maintenant c'est qu'on va exécuter cette image on va donc lancer la commande docker run-d et on va nommer cette image mais ce que je vais faire c'est que je vais copier la suggestion de mon terminal ici on va prendre l'image que nous avons créée qu'on avait appelé algomax /nestgs chat API et nous allons l'exécuter sur le port 8000 donc on va reverse proxy le port 8000 de l'image do cur à notre port 8000 en local et nous allons appeler ce projet nestjs chat API on va taper la commande suivante et on va exécuter notre image docur et là on peut voir qu'on a une erreur il n'a pas réussi à trouver le fichier start.sh alors qu'est-ce qui se passe ce qu'on peut faire si on a l'application docker c'est qu'on va l'ouvrir ici et on voit qu'on a un containur qui est en train de cracher donc qui n'arrive pas à se lancer et du coup il se relance à chaque fois sauf qu'il y a une erreur javascript mais ce qu'on a envie de faire ici c'est de cliquer sur le container et d'aller sur l'onglet files pour voir ce qui s'est passé sauf que le problème c'est que comme on narrive pas à exécuter l'image et bien l'image ne reste pas suffisamment longtemps exécuté pour qu'on puisse inspecter les fichiers donc effectivement ça crache comme ça crache on peut pas inspecter les Fichi mais c'est pas grave on va continuer avec notre implémentation du docker file parce que il y a un dernier fichier que nous allons avoir besoin de créer effectivement j'ai pas envie d'exécuter deux commandes à chaque fois c'est-à-dire le docor build puis le docor run et taper dans mon terminal les commandes je préfère utiliser une seule commande qui fait les deux calculs et c'est pour ça que nous allons utiliser ce qu'on appelle docker compose on peut chercher sur google ce que c'est dokerur compose ça va nous permettre d'exécuter plusieurs une ou plusieurs images dokerur et elles seront donc exécuté en même temps et elles pourront communiquer entre elles et c'est ce que nous allons utiliser pour se faire il nous suffit de créer un nouveau fichier qu'on va appeler docor-compose.yam sauf que nous on va avoir plusieurs environnements potentiellement on va avoir un environnement de production et on va avoir un environnement de dev donc là je vais rajouter un point dev dans le fichier parce qu'on va écrire le docor compose de l'environnement de développement en premier ensuite pour la production il nous suffira de copier-coller ce fichier et juste de modifier une ligne 2 donc on crée ce fichier de cors compose ici et nous allons copier ce morceau de code donc nous avons une ligne service parce que on peut définir un ou plusieurs services par exemple si tu voulais utiliser une base de données releas ou alors un bucket S3 en local tu pourrais ajouter un service redis qui sera donc ensuite connecté à ton application tu pourrais rajouter un bucket S3 un bucket email pour envoyer les emails et cetera mais dans notre cas on va conserver un seul service et c'est le nestgs chat API en environnement de dev ensuite nous avons une déclaration environnement c'est pour les variables d'environnement par exemple la connexion à la base de données et ce qui nous intéresse ici c'est le build ici parce qu'on définit un contexte on définit notre docker file et on indique à docker que on a envie qu'il fasse un build de notre fichier docker fail et enfin nous avons le reverse proxy des pororts notre application tournait sur le port 8000 mais comme on va l'exécuter dans un docker elle va tourner dans le docker sur le port 8000 et on a envie de pouvoir y accéder sur notre port 8000 à nous donc on fait comme ça si on av envie qu'elle tombe sur le port 8000 dans le dockur et qu'on a en envie d'y accéder sur notre machine sur le port 4000 on mettrait ici port 4000 et le port 4000 de notre ordinateur serait relié au port 8000 du docker bien sûr si dans le docker on le relie sur le port 8000 mais que notre application le lance sur le Port 2000 ça va jamais marché il faut bien que notre application le lance sur le bon port qu'on est en train de définir ici donc maintenant qu'on a créé ce fichier on peut lancer une commande qu'on appelle docker compose t S pour dire qu'on va exécuter un fichier spéci ici et on peut voir que la commande m'est autocomplétée on va donc utiliser la commande de core compose sur le fichier que nous venons de créer et on va faire un UP et un t- build le tr- build il va tout simplement build notre image de cur si ce n'est pas déjà fait on peut voir ici que j'ai fait une petite faute dans le nom du fichier alors les deux formats sont possibles là il y a le format YML et le format yamel mais pour ne pas avoir à retaper la commande dans le terminal je vais utiliser le format yamel et maintenant on peut exécuter cette commande de cor et comme vous voyez ça exécute à peu peu près les mêmes étapes là nous sommes sur l'étape installer l'application et encore une fois l'application va crash parce qu'elle ne détecte pas notre fichier start.sh ou alors elle a pas les permissions pour l'exécuter et ça c'est une erreur que j'ai à chaque fois que je crée un nouveau projet donc je vous conseil déjà de taper la commande schmod + X start.sh dans votre terminal comme ceci et ensuite on va rajouter une ligne dans notre docker file pour être vraiment sûr qu'on possède bien ce fichier ici à la dernière étape dans le Runner ce qu'on va faire c'est qu'on va copier depuis installleur qui est la base qu'on avait définie ici dans lequel on a copié tous les fichiers et donc depuis installleur nous allons copier le fichier start.sh comme ceci et on va l'appeler start.sh avec ces deux changements je pense que le fichier va être détecté on refait un essai on va lancer cette commande et comme vous voyez on reprend les étapes mais on ne les reprend pas depuis le début et on a malheureusement toujours la même erreur donc dans ce genre de cas on peut essayer de débugger l'application en fait je pense que le fichier start.sh n'a pas été copié donc ici ce qu'on peut faire c'est qu'on peut le copier start.sh se retrouve dans start.sh comme ceci et là bien sûr on doit réinstaller l'application tout simplement parce que on a rajouté une ligne de commande qui s'appelle start.sh juste avant l'installation des dépendances ici donc decor a mis en cache toutes les étapes qui étaient exécutées avant mais il ne met pas en cache les étape à partir de celle qu'on vient de rajouter ce qui est logique parce que si on rajoute un fichier ou si on fait un un petit changement on va devoir tout recalculer on va devoir refaire un build là j'arrive vraiment pas à débugger je ne comprends pas quel est le problème donc en fait ce qu'on va faire c'est que je vais retourner sur la dernière étape ici et on va faire du débugage ici on lui donne l'instruction d'exécuter le fichier start.sh il n'y arrive pas donc je vais rajouter une instruction précédente et ça va être une commande de terminal qui ne peut pas échouer on va donc laisser tourner notre terminal avec cette commande qui s'appelle container is running et ce que ça va faire c'est que ça va laisser notre image ça va la laisser active et pendant qu'elle est active on va retourner sur l'application docor desktop ici et on va essayer de débugger on pourra enfin accéder au fichier pour comprendre ce qui ne va pas donc ce bug tombe bien au final parce qu'on va apprendre quelque chose de nouveau là maintenant j'ai commenté cette dernière commande et j'en ai rajouté une autre donc on peut de nouveau exécuter notre docker compose ici et c'est ce qu'on va faire tout de suite et maintenant on peut voir que là on a pas eu d'erreur et on est à la dernière étape container is runing maintenant on peut donc retourner sur l'application ici et on va supprimer la première image et nous allons cliquer sur la deuxième image ici et maintenant on clique ici et nous avons envie d'accéder au fichiers donc on va se rendre dans files et là on peut vraiment voir tous les fichiers qui sont présent sur le disque dur de cette image on a donc le dossier app ici le dossier dis n module package Jon et nous avons notre fichier start.sh alors c'est bizarre parce que l'application nous dit qu'il n'arrive pas à l'exécuter alors ici ce qu'on peut faire c'est qu'on peut open open file Editor ou alors on peut clic droit sur le fichier et faire edit file et on peut voir que cette image est vraiment à jour donc le problème ne vient pas de l'image qui n'a pas été copiée on va donc retourner dans notre terminal ici et on a envie une dernière fois de regarder ce qui était le message d'erreur au final les réponses sur Google ne m'ont pas aidé par contre j'ai eu la bonne idée de taper cette commande donc la commande SH start.sh et j'y vois un peu plus clair avec une erreur beaucoup plus plante ici ça arrive pas à faire un NPX Prisma myrate deploy parce que ça ne trouve pas le fichier schemma point Prisma dans le repository et j'ai déjà eu cette erreur sur un projet sur lequel je bossais il y a quelques jours et pour mieux comprendre d'où cette erreur vient ce que j'aurais dû faire c'est que j'aurais dû exécuter le fichier start.sh moi-même dans l'ordre et on verra que c'est cette commande là qui pose problème et pourquoi elle pose problème elle pose problème parce que prizma n'arrive pas à se connecter à notre base de données et elle n'arve pas s'y connecter parce que cette base de données n'existe plus depuis la dernière fois Planet scale est devenue payant au début de cette vidéo c'était entièrement gratuit et maintenant ça coûte minimum 40 dollars par mois donc on va devoir utiliser une alternative on va se rendre sur nontech et nous allons créer une nouvelle base de données pour ce projet sur nontech on a droit à une base de données gratuite bien sûr ça va utiliser du postgress et pas du MySQL donc on va devoir faire une petite modification on va d'abord pour commencer par supprimer cette base de données là ici bien sûr il y a que moi qui l'ai vous vous devez sûrement ne pas l'avoir et je vais recréer l'application nestjs chat et on va l'appeler nestjs- chat et on va choisir en région l'Europe et nous allons créer le projet à partir de maintenant on va sélectionner Prisma ici et on doit faire deux changements le premier changement c'est changer le provider dans notre fichier de configuration Prisma donc dans le fichier schéma. Prisma ici on avait sélectionné MySQL et cette fois on va sélectionner postgce et on va retirer cette ligne et enfin on va devoir copier le point enve ici avec ce secret on va donc copier ce secret en entier et on va le rajouter dans notre point en je ne vous montre pas les lignes audessus mais on avait déclaré en tout premier une base de données qui s'appelle database URL avec la DB mSQL et je vous demanderai maintenant de supprimer cette ligne sinon ça va la détecter comme étant la base de données par défaut donc maintenant on peut sauvegarder cette variable d'environnement et ce qu'on va faire c'est qu'on va exécuter cette commande là le NPX Prisma myrate deploy et là on peut voir qu'on a plus d'erreur comme on a plus d'erreur on va tout de suite essayer de réexécuter notre docker fail on va donc lancer notre docker compose comme avant et là on peut voir qu'on a toujours la même erreur et en fait c'est encore une erreur d'inattention de ma part c'est parce que on doit rajouter toutes les valeurs de notre fichier pointinanv dans le fichier docur compose ici on avait rajouté la valeur JWT secret et en fait on doit rajouter le database URL les variables d'environnement stripe donc on va le faire tout de suite vous allez copier toutes les clés de votre fichier pointinv ici et on va les coller comme ceci on avait donc une dizaine de variables d'environnement le JWT secret le port l' PII key de resend du frontend d' WS S3 et de stripe comme ceci et ce que ça va faire c'est qu'en exécutant cette commande en locale ça va lire nos variables d'environnement depuis notre fichier.inv maintenant on peut réexécuter une dernière fois la commande de corore compose et ça devrait normalement marcher bien sûr ça ne marche pas on a toujours la même erreur c'est vraiment l'effet vidéo là on peut voir que mettre à jour cette librairie n'a pas non plus fonctionné alors là je suis vraiment bloqué surtout que cette erreur je l'ai déjà eu une fois au boulot et pareil ça m'avait fait perdre une journée de taf et là en fait le problème franchement je m'en veux de pas l'avoir compris plutôt mais en fait on n pas copié le dossier Prisma ici on l'a pas copié à la dernière étape ici depuis installer on n' pas copié le le dossier Prisma et et on aurait dû le copier on aurait dû le copier en faisant Prisma comme ceci et si on l'avait copié peut-être qu'on aurait pas eu tous ces problèmes au moins on le sera pour la prochaine fois maintenant on va repartir sur l'instruction point en tout cas pour configurer le front end ça va être beaucoup plus simple on n pas Prisma c'est vraiment juste une application react donc ça va être plus rapide et voilà cette fois on a donc une autre erreur c'est l'entry point qui ne fonctionne pas donc on a vraiment deux erreurs à chaque fois c'est assez marrant alors est-ce que ça vient de l'entry point ou ça vient encore de Prisma cette fois on va tester normalement on a copié le dossier Prisma donc ça devrait retrouver le schéma et là on peut voir qu'on a cette erreur nest not found et nest en fait c'est la commande de nest JS pour exécuter l'application ici dans notre commande start on lance la commande nest start sauf que nest les amis c'est ici c'est une dépendance de développement et on peut voir tout de suite on a un fichier compilé ici on a donc dist et dedans on a main JS et en fait ce qu'on aurait pu faire au lieu de faire un nest start c'est de faire un node dist/ main comme ceci donc maintenant j'ai modifier le package Eon donc au moment de rebuild l'application docker ça va repasser toutes les étapes y compris l'installation mais au moins on progresse on a résolu l'erreur Prisma ok donc là on a réussi à faire tourner notre application avec cette commande en vrai on peut s'arrêter là c'est pas grave si on utilise pas entry point start SH notre application tourne elle est access sur le port 8000 on va le tester tout de suite on va faire localost 8000 on va accéder à la route/ash users comme ceci et là bien sûr j'avais oublié de changer donc on peut y accéder sur le port 4000 et pas sur le port 8000 ça c'est une erreur qui vient de moi on peut voir qu'on a eu une petite erreur serveur à ce niveau-là et on retrouve l'erreur sur notre terminal ici on narrive pas à se connecter au serveur ça c'est parce qu'on n pas encore exécuté les migration mais une erreur à la fois donc là ce qu'on va faire c'est qu'on va remettre le port 8000 pour le riversers proxy et on va lancer c'est une commande mais en fait ici on est passé à une base de données postgress avant on avait du MySQL et on avait pas besoin de migration sauf que là on a besoin d'immigration donc on va faire un NPX Prisma migret dev t name et on va mettre comme nom de notre première migration init et maintenant ça a créé un fichier migration.sql et un dossier migration qu'on retrouve ici et normalement à partir de maintenant on devrait plus avoir de problème on va donc relancer le docor compose cette fois sur le port 8000 cette fois avec notre dossier Prisma cette fois notre commande start.sh fonctionne et voilà là notre application est lancée et si on se rend sur la route/ash users bien sûr sur le port 8000 comme ceci là on a un tableau vide parce que il y a plus d'utilisateur effectivement on a entièrement changé de base de données on est passé chez néon maintenant et si on clique sur les table ici on retrouve nos chat nos conversations nos donations et nos utilisateurs maintenant que c'est fait là on a terminé on a terminé notre docker file on a terminé notre docker donc ce qu'on a envie de faire maintenant c'est de configurer les GitHub actions pour déployer automatiquement notre application sur un serveur encore une fois je vais m'inspirer de ce que j'utilise déjà sur mes projets personnels donc je vais coller un fichier ici et on retrouve donc un dossier point GitHub qui est une convention de GitHub donc quand on mettra en ligne le code sur GitHub il va détecter ce fichier il va aller dans le dossier workflows et il va exécuter chaque fichier en pointml là on a donc build.ml et le build.ml ce qu'il va le faire c'est qu'il va exécuter un docker build donc il va tout simplement build notre docker file qu'on vient de créer donc ce qu'on faisait en local docker build cette fois cette commande va être exécutée sur les serveurs de GitHub elle sera exécutée qu'on va faire un push sur la branche main et sur la branche nommé dev et pour se faire on va avoir besoin de deux identifiants le docker hub username et le docker hub token et ces identifiant on les récupère en créant un compte sur le site qui s'appelle docker hub c'est le site officiel de docker et vous pouvez récupérer vos identifiants ici le USERNAME c'est tout simplement votre nom de compte donc pour nous ça sera algomax et le token vous pouvez le retrouver ici dans Account Settings et dans l'onglet security ici vous pouvez générer un nouveau token avec les permissions que vous voulez après avoir généré ce token vous allez vous retrouver sur gitthub si vous avez créé un repository pour sauvegarder votre base de code ici je l'avais fait pour nasgs chat API donc je vais me rendre sur ce repository et je vais aller dans settings et je vais aller dans Secret and variables et dans action et à cet endroit-là je vais ajouter des secret qui seront donc protégés c'est une sorte de Volt et on va rajouter les valeurs de nos secret donc on va rajouter le docker hub token le docker hub username qui est donc algomax et finalement toutes les variables d'environnement qu'on a défin à cet endroit dans le docker compose donc un par un vous pouvez les récupérer depuis votre environnement local et on aura bien sûr des valeurs qui seront différentes pour l'environnement de test et l'environnement de production et dans ce cas-là vous pouvez renommer votre secret ici pour l'environnement de développement moi je l'appelle staging par exemple mais dans cette vidéo on va pas créer deux environnements différents on ne va utiliser qu'un seul environnement c'est l'environnement de production pour que ça soit un peu plus simple sauf bien sûr pour stripe parce que pour stripe ils font bien la différence entre l'environnement de test et l'environnement de production alors pour stripe vous pouvez sauvegarder les deux mais de toute manière on va retourner tout à l'heure sur stripe pour générer nos secretes de production voilà là je viens d'ajouter tous les secretes de mon API et ce qu'on peut faire c'est qu'on peut retourner dans le build ici et on peut voir qu'en fait on build donc l'image docker et ensuite on va l'héberger sur la plateforme docker qui s'appelle docker hub et on peut voir qu'on l'héberge avec un tag assez spécial c'est le table qu'on avait déjà utilisé c'est algomax/nestjs-chat-api sauf que ce repository n'existe pas encore donc on va retourner sur docker hub ici et on va créer un repository qui porte le nom qu'on a défini à notre fichier ici donc nestjs-chat-api bien sûr vous c'est votre nom d'utilisateur qui sera avant le slash ici moi j'ai utilisé le namespace algomax et je vais appeler le projet nestjs-chat-api je vais ensuite créer ce repository comme ceci et maintenant à chaque déploiement sur GitHub on environnement de dev et de main ça va build une nouvelle image dogur sauf que cette commande build.yamel est exécutée dans le fichier ci.aml qui est le deuxème fichier et c'est ce fichier en fait qui va exécuter toutes les actions qu'on lui aura donné par exemple si on retourne dans le fichier package.gon on peut voir qu'on avait des commandes comme le lint et le type check et les tests et toutes ces commandes on peut les exécuter au final à chaque mise à jour du code mais dans cette vidéo on va pas le faire on va juste faire un build et mettre en donc on va avoir un seul job le build qui va donc appeler le fichier qu'on a créé le build.iml et qui va donc hériter des secretes qu'on aura défini sur gitom et ensuite après le build on va exécuter l'action deploy et on peut voir que l'action de déploiement a besoin de du build donc avant d'exécuter l'action de déploiement on va d'abord exécuter le build sauf que ce déploiement on va l'exécuter pas sur les serveur de GitHub mais sur nos serveurs notre serveur qu'on aura acheté chez hostinger c'est pourquoi on a a rajouté la commande runs on self- hosted et enfin on a les mêmes conditions ici c'est-à-dire qu'on exécute le déploiement seulement en cas de push sur la branche main ou sur la branche dev et à cet endroit-là on va devoir redéfinir les variables d'environnement de notre projet et ça prendraas bien sûr les valeurs qu'on a définies sur GitHub à cet endroit donc secrets point et le nom qu'on a défini sur GitHub et enfin à ce moment-là c'est là qu'on va faire une différence entre environnement de staging et environnement de de production ici on a si on est en environnement de dev alors dans ce cas-là on va utiliser les variables de l'environnement de dev donc database URL staging et si on est en prod on va utiliser celle de prod et on va exécuter le fichier docor compose.dev en dev et le fichier doc compose. prod en prod sauf que nous on va créer un seul environnement ça sera l'environnement de production donc cette ligne on peut la commenter et ici on va bien utiliser le frontend URL et le database URL qu'on a défini sauf qu'on a pas besoin de définir ici on va le définir plus haut ici bien sûr si vous avez besoin de définir plusieurs environnements alors dans ce cas-là vous devez répéter cette opération autant de fois que nécessa on va faire une dernière chose ici on va retourner donc plus haut à cet endroit-là et on définit les variables d'environnement qui sont communes à tous les environnements sauf que ça ne pose aucun problème pour nous vu qu'on a qu'un seul environnement c'est la prod donc on aura un JWT secret unort et toutes les variables d'environnement qu'on a défin ici voilà on les a toutes ajouté sauf qu'on a pas encore créé les secret et les web hook de notre compte stripe en production c'est pas grave on va le faire tout de suite après d'abord on a juste envie de mettre en ligne ce code en environnement de production même si on n pas encore les secretes et normalement ça devrait être bon ici on peut voir qu'on est sur la branche main et ce qu'on va faire c'est qu'on va faire un petit guit status on peut voir qu'on a tous ces fichiers à versionner et on va le versionner tout de suite on va faire un guit point un git commit on va appeler mise en prod et enfin on va faire un pH origine donc sur notre branche main et maintenant on va se rendre sur GitHub ici sur notre projet et on va cliquer sur action parce qu' on peut voir ici qu' a une nouvelle action qui a été effectuée parce qu'il a détecté tous les fichiers qu'on a rajouté si on clique donc sur action ici on peut voir qu'on a notre action et on va pouvoir voir le build et le déploiement sur notre serveur sauf qu'on a un petit problème l'action de déploiement ne va pas marcher parce qu'on n pas encore défini notre serveur ici effectivement l'action de diployement s'appelle deploy c'est un runzone selfhosted sauf qu'on a pas encore défini notre serveur hostinger qu'on va utiliser par contre c'est pas grave on a déjà envie de voir si le build s'effectue sans problème pour se faire on peut retourner sur docor hub ici on peut rafraîchir la page et là on peut voir qu'on a bien une branche qui est en train d'être push sur le tag qui s'appelle production et ça veut dire que si on retourne ici dans notre fichier Buil à cet endroit-là on peut voir qu'on avait bien défini le tag production ici sur notre action de déploiement en production et ça marche du tonner ça va Buil de notre image là si on retourne sur gitub on peut voir qu'après 1 minute 26 l'image a été build maintenant bien sûr l'action de déploiement ne va jamais fonctionner parce que on n pas encore configuré le serveur mais c'est pas grave on va annuler le workflow si on veut on peut retourner tout de suite après et on peut cliquer sur replay ce qui va réexécuter cette action donc maintenant on a envie de configurer le serveur hostinger on va se rendre sur hostinger et à cet endroit normalement vous cliquez sur Accès SSH et vous vous connectez au mot de passe que vous avez défini pour se connecter on va donc copier l'adresse IP et le nom d'utilisateur on va faire SSH route @as et l'adresse IP dans mon cas j'ai pas besoin de rentrer le mot de passe parce que je l'ai déjà rajouté sur le serveur je me suis déjà connecté une fois j'ai configuré pour ne pas avoir à rentrer le mot de passe et maintenant une des étapes qu'on doit faire c'est d'installer docker sur le serveur mais dans mon cas je l'ai déjà installé alors pour vous vous allez devoir faire docker install ubunto comme ceci et vous allez dev voir Installer docker sur ubunto il suffit de suivre toutes ces indications ici et d'installer entièrement docker bien sûr vous retrouverez toutes ces informations dans la vidéo qu'on a faite qui s'appelle déploie ton projet javascript sur un serveur VPS donc on aura besoin de docker de CAD serveur et sur ce serveur on a déjà tout le configurer donc ce qu'on va faire c'est qu'on a juste besoin de configurer le Runner de GitHub pour qu'il puisse renvoyer en fait notre image de cur sur le serveur et pour se faire on se rend dans settings à cette endroit et on va cliquer sur action runners et on va créer un new selfhosted Runner à cet endroit-là et on va sélectionner Linux x64 et nous allons suivre les instructions donc on va copier ce premier morceau de code mais ce que j'ai envie c'est d'appeler le dossier deployments comme ceci on va faire un CD sur le dossier deployments et on va copier la deuxième commande cl ici ce qui va télécharger l'exécutable qui va nous permettre de configurer le GitHub Runner maintenant que c'est fait on passe à la commande suivante ici et ensuite on termine avec la dernière commande pour télécharger ce Runner maintenant que c'est fait on va retourner dans le fichier et on va passer à la configuration ici on va donc copier cette commande et on a une erreur qui dit must not run with sududo et cette erreur on l'a déjà eu dans la vidéo précédente en gros on peut pas exécuter ce code en tant qu'utilisateur sududo donc je vais me connecter avec l'utilisateur que j'ai créé qui s'appelle Virgile et je vais retourner dans deployments ici et en fait ce qui s'est passé c'est que tout ce que j'ai fait là je l'avais déjà fait une fois pour un autre projet donc comme j'avais déjà créé le dossier deployment ce que je vais faire c'est que je vais faire un MV pour copier le contenu du dossier deployment que j'avais créé initialement ou sinon ce qu'on peut faire on peut faire encore plus simple on va recopier toutes les commandes qu'on a déjà copié on va faire un mkadir njs- chat- API on va faire la même chose après pour l'application remix on va céder dedans et dedans on va retélécharger l'exécutable on va le refaire une deuxième fois on va déziper tout ça et maintenant on peut de nouveau copier cette partie donc configurer l'application avec cette commande cette fois on n pas l'erreur du sudo et je vais appuyer trois fois sur Entrer et une dernière fois pour confirmer les changements maintenant normalement ça a dû créer le Runner donc si on se rend ici déjà on peut copier la dernière étape même si on ne va pas l'utiliser mais si on actualise la page ici en fait si on reclique sur Runner on peut voir qu'on a maintenant notre Runner qui est selfhosted Linux x64 sauf que maintenant on a envie que ce Runner soit connecté H24 à GitHub et que dès que GitHub lui envoie l'information il y a eu un nouveau commit sur la branche main le runur il disent à giitub vas-y envoie-moi l'image dockur je vais la télécharger donc pour se faire on a plusieurs commandes qu'on peut exécuter on peut exécuter le svc.sh install pour installer le gitthub Runner et là on a un autre message qui nous dit on doit exécuter cette commande en tant que pudo on va le faire tout de suite on va l'exécuter en tant que pudo maintenant on vient de le faire donc on vient d'installer et à présent on peut faire un Start et là on a fait un start le statut est active ce que ça signifie c'est que si on retourne maintenant sur GitHub avant vous voyez statut offline si j'actualise la page maintenant on voit le statut Idol avec un point vert ce qui veut dire qu'il est à l'écoute des nouveaux événements donc on peut retourner sur notre action à cet endroit-là sur l'action mise en prod et ce qu'on va faire maintenant c'est qu'on va cliquer sur replay parce que maintenant on a un Runner qui va écouter les événements bien sûr ça ne va pas réexécuter notre action de build comme elle a déjà été terminée et elle a fonctionné ça va seulement exécuter l'action de déploiement et là on peut voir que le runur il a compris ce qui se passait et c'est en train de déployer notre application donc là si on retourne côté serveur et qu'on fait un docor PS juste pour voir on peut voir qu'on a deux projet qui tourne on a le projet nestgs remix monoripo on a le projet jofas r mais on a aucun projet qui tourne sur le port 8000 ça tombe bien parce que notre projet va tourner sur le port 8000 sauf qu'on a une petite erreur en fait on a créé le fichier docorcompose.dev mais on n pas créé le fichier DEC compose point prod et c'est pour une raison assez simple là déjà on va dupliquer ce fichier fichier le fichier de la prod on n pas envie de refaire un build en fait on ne va pas refaire un build on va à la place rajouter l'image qui est hébergé sur docker hub et pour se faire on rajoute la clé image qui prendra comme valeur algomax/nesjs- chat- API double production donc maintenant qu'on a créé ce nouveau fichier de configuration pour la production ce qu'on peut faire c'est qu'on peut de nouveau push sur la branche main donc on va refaire un guit ad point un guit commit Adad docker compose for prod et on va de nouveau push sur la branche main et pendant que c'est en train de mettre à jour notre deuxième action ce qu'on va faire c'est qu'on va se connecter sur stripe et on va récupérer les variables d'environnement pour la prod donc on va faire un sign in sur notre compte et maintenant que c'est fait on va cliquer sur developpers ici et on va cliquer sur APPI Keys et on a donc deux clés on a la clé publique qui peut être partagée de toute manière c'est une clé qui sera accessible côté client et on a la secret key et celle-ci je ne vais pas vous la montrer mais je vais la copier et je vais retourner dans C settings sur GitHub toujours sur mon projet netgs API et ici on peut voir que j'avais déjà créé les variables d'environnement pour le stripe secret key staging et je vais rajouter la variable stripe secret key qui prendra donc comme valeur ma clé API stripe pour la prod et on va faire la même chose pour les web hook ici donc on a les web hook et ce qu'on a envie de faire c'est de rajouter un endpoint et on va le rajouter sur la branche qu'on va appeler api-chat.algomax.fr et je me souviens plus quels sont les événements qu'on avait utilisé donc on va retourner sur notre base de code ici on va aller sur le fichier stripe controller et on va cliquer sur le service pour accéder à la méthode handle web hooks et c'est à cet endroit qu'on va retrouver les web hooks donc on avait payment intent succeeded on peut rajouter cet événement là sélectionner et ça a l'air d'être le seul événement qu'on utilise pour les donations donc on peut le rajouter et on peut créer C end point et bien sûr ça nous donne un signing secret ici et c'est celui-là qu'on va devoir Rév est pour pareil autoriser l'appel venant de stripe donc on va cliquer sur reveal et pareil je ne vais pas vous le montrer mais je vais le copier ici et je vais le rajouter dans les GitHub actions donc ça s'appelle stripe web hook secret et maintenant je les mets en place je l' créé donc ce qu'on peut faire c'est qu'on peut retourner dans l'onglet action et on peut regarder notre action ici on peut voir qu'elle a réussi l'étape de déploiement a durer 12 secondes et on peut retourner sur le serveur sur high term et on peut faire un docker PS à nouveau et on peut voir qu'on a notre application qui est en train de restart normalement si elle restart c'est pas bon signe ça veut dire qu'elle est en train de cracher mais on va voir quand même ce qui se passe en tout cas la base de code a été téléchargée et ce qu'on peut faire c'est qu'on peut inspecter cette image pour voir si on a eu des messages erreur pour se faire on peut faire un docker logs et le nom de notre application on peut voir qu'elle s'appelle netjs- chat ap dev et là on peut voir qu'on a ce message greur en fait c'est notre serveur WebSocket j'avais oublié qu'on avait donc un serveur WebSocket qu'on utilise mais en fait l'erreur ne vient pas des web soockets en fait l'erreur vient du port 8000 parce que par défaut ça utilise le port 8000 comme on le retrouve dans notre fichier main.ts sauf qu'on n pas défini cette variable d'environnement dans le fichier de cor compose.dev ici en fait on l'a défini oui sur notre fichier c. yamel on a également dû le définir à cet endroit-là mais c'est au niveau de gththub ici dans les réglages dans Secret and variables que je ne l'ai pas défini je pensais que ça allait prendre la valeur par défaut qui est donc de 8000 mais apparemment on est obligé de le rajouter maintenant on vient de rajouter une variable d'environnement donc on va pas devoir repush le code pour réexécuter cette action on a tout simplement besoin de réexécuter l'action de déploiement ici prendre 12 secondes donc on va cliquer sur rerun single job et ça devrait mettre à jour notre action de déploiement avec les nouvelles variables d'environnement y compris celle de stripe qu'on vient de configurer voilà donc maintenant c'est terminé on va de nouveau sur le serveur et on va refaire un docker PS et cette fois on peut voir que ça ne crache pas on va faire un docker logs et on peut voir qu'on a aucune erreur à ce niveau-là ça fonctionne très bien l'application n'a pas crash sauf qu'on ne peut pas y accéder parce qu'on a pas encore configuré le nom de domaine pour configurer le nom de domaine du coup on a besoin d'utiliser un service qui nous permet de d'acheter un nom de domaine de le louer donc moi j'utilise OVH ici et il me suffit d'aller dans domain names de cliquer sur algomax.fr et je ne vais pas racheter un nom domaine vu que je paye déjà pour le domaine algomax.fr ce que je vais faire à la place c'est que je vais aller dans DNS zone ici et je vais créer un sous-domaine que je vais appeler ça sera un sous-domaine ça sera un a et je vais l'appeler chat.algomx.fr comme ceci et en target on va mettre l'adresse IP du serveur hostinger qui est donc celle-ci comme ceci et on va faire la même chose pour l'API et ça prendra comme valeur la valeur qu'on a défini dans stripe ici de notre webhook donc c'est celle-ci ap-chat.algomax.fr on peut donc copier API t chat et l'adresse IP sera la même parce qu'on va héberger le front et le backac sur le même serveur maintenant que c'est fait on peut rajouter ça et on a une configuration CAD à rajouter pour que le nom de domaine soit bien relié à notre fichier on peut donc s'inspirer de ce qui a déjà été créé dans notre configuration CAD encore une fois tout ça je vous l'explique en détail dans la vidéo sur comment héberger un projet JavaScript mais en gros ce qu'on va faire c'est qu'on va faire ça donc on va éditer notre fichier etc CAD CAD file et à l'intérieur on va rajouter le nom du projet donc l'URL plutôt qu'on a défini et c'est donc api- algomax.fr et on va faire un reverse proxy sur localhost 8000 qui est le port en local de notre application lesgs et on va également prendre le chat algomax.fr qui sera donc l'URL qu'on va attribuer au front et on va pareil faire un reverse proxy sur localost 3060 par exemple parce que effectivement on a déjà des projets sur le port 3000 donc on va utiliser le port 3060 pour le front maintenant on peut sauvegarder les changements et on a juste à faire un sududo système CTL restart cadi comme ceci ça prend un petit peu de temps et ça va restart la configuration de CAD serverur avec les changements qu'on vient de lui apporter et maintenant on peut déjà faire un essai on va essayer d'accéder à l'URL chat-api.algomax.fr et là on peut voir qu'on a cette petite erreur le site est inaccessible mais ce qu'on peut faire déjà c'est qu'on peut aller sur le site check-host.net et on peut coller le nom l'URL de notre site pour voir si cet URL redirige bien à notre serveur hostinger pour se faire on va le passer en HTTPS et là on peut voir que ça ne le redirige pas sur l'URL de Stinger donc on va retourner sur VH et on va voir ce qui s'est passé on va taper chat- apayer et là on peut voir que rien n'a encore été créé du côté d'OVH alors je comprends pas ce qui s'est passé apparemment ça n'a pas été créé chez OVH donc on va devoir répéter l'opération on créer une nouvelle entrée a on copie l'IP du serveur hostinger ça sera la target et on va appeler le projet chat ti API next on va confirmer l'opération et on va faire la même chose donc on va garder la même ur et le même serveur sauf que cette fois le projet va s'appeler chat ça sera le nom du sous domomaine et le domaine c'est algomax.fr pareil on va sauvegarder et là on peut voir qu'en fait je m'étais un peu pressé en fait les valeurs ont bien été créées alors je comprends pas la bonne URL c'est api- chat donc chat- AP on va pouvoir supprimer cette entrée et on va faire pareil sur la première entrée chat algomax pour éviter les bugs là en fait ça doit prendre un petit peu de temps je sais pas ce qui se passe mais on peut voir que pour le sous-domaine chat.algomax.fr ça a bien détecté notre nouvelle ISP on utilise bien hostinger international mais bizarrement c'est pas le cas pour notre API pour notre chat-api.algomax.fr alors en fait j'ai sûrement dû faire une connerie peut-être qu'on a pas le droit de mettre des tirets sur le site c'est vrai que j'ai jamais vu un site avec des tirés dedans donc en fait on va totalement changer ici on va l'appeler API chat en un mot et c'est cette url qu'on va renommer ici on va modifier ce champ A et on va l'appeler app chat en un seul mot maintenant on peut voir si on retourne sur Check host que ça a bien détecté le changement donc appchat.algomax.fr si on accède à cette URL sur Google comme ceci on a toujours cette erreur par contre on sait que maintenant ça fonctionne et on va devoir aussi modifier notre configuration cadi donc ici on va retourner sur api- chat et on va enlever le tiret et on va de nouveau relancer notre configuration cadi et maintenant si on actualise la page normalement ça devrait F fctionner une technique qu'on peut faire aussi c'est d'ouvrir un onglet en navigation privée et d'accéder à l'URL au cas où il sera mise en cash et là on peut voir que ça marcher je suis sur l'URL appchat.algomax.fr et on a une erreur nestjs et si on va sur/ash users comme ceci on peut voir qu'on a toujours notre tableau vided donc notre application NGS tourne avec succès sur le serveur maintenant qu'on a mis en place le backend on va maintenant s'occuper du frontend si on retourne sur notre compte GitHub le code se mettra en production à chaque fois qu'on FA fera un nouveau push sur la branche main on retourne donc maintenant dans notre projet frontend ici et nous allons recopier toutes les étapes c'est-à-dire installer docker installer les gitob actions et configurer le Runner sur le serveur mais si on se rend dans le fichier point env ici on se rend compte qu'en fait on aura besoin de setup deux variables d'environnement le backend URL et le WebSocket URL qui est défini à cette url cependant le problème c'est qu'on n'a pas ouvert les ports sur notre serveur regardez si on retourne sur notre projet backend ici dans le fichier deccompose.pr on peut voir qu'on expose qu'un seul port le port 8000 sauf que dans notre fichier app gateway.ts ici nous exposons également le port 8001 qui est le port des WebSockets donc ce qu'on a envie de faire au final c'est également de l'exposer et on va l'exposer de cette manière en rajoutant cette ligne dans notre fichier de corps compose bien sûr nous allons également rajouter cette ligne dans l'autre fichier de cor compompose.dev mais ce n'est qu'une partie du travail parce que effectivement on va devoir également ajouter un nom de domaine et on va également le déclarer sur CAD serveur donc on va commencer par retourner sur OVH sur les informations de notre nom de domaine ici on va regarder tous les champs a et on a donc appychat.algomax.fr et nous allons rajouter une entrée un champ a que nous allons appeler appy chat mais on va rajouter WS juste avant le API chat comme ceci et bien sûr comme target on va prendre la même IP donc ça va être wschat.algomax.fr qui redirige à cette IP maintenant on va juste copier ce nom de domaine on va retourner sur le serveur et nous allons modifier à nouveau le fichier etc/cadi/cadifile et c'est à cet endroit qu'on va rajouter une nouvelle entrée c'est-à-dire wshppchat.algomax.fr et on va faire un reverse proxy sur le localost 8001 comme ceci et maintenant on va enregistrer maintenant nous devons à nouveau retourner sur notre app pour mettre à jour nos changements c'est-à-dire ouvrir le port dans le docker compose pour ce faire on va tout simplement faire un guit ad plus et un guide commit avec comme message add WebSocket ports et on va P sur main maintenant que c'est fait on va pouvoir commencer à configurer ces fichier pour notre frontend donc on va commencer par docker on retourne sur notre API et nous allons copier tous ces fichiers c'està-dire le docker file les fichiers docor compose et le fichier docor ignore comme ceci on les copie et maintenant on se rend dans notre frontend et on va tous les coller maintenant que c'est fait on va modifier le fichier docker file on va laisser les 10 premières lignes tel quell c'est ces lignes-là vont rester les mêmes au final la seule chose que nous allons changer c'est retirer les lignes de Prisma vu qu'on ne l'utilise pas côté front et ensuite on va retirer cette ligne là également et notre build génère un fichier qu'on va appeler build et non pas l comme ceci et ça devrait être bon mais on va tester tout de suite avec dokerur d'abord je retourne encore une fois sur le dossier pay et je vais copier le fichier start.sh parce que on va utiliser la même logique on copie donc le fichier start.sh et on retire cette instruction qui fait appel à notre service Prisma et maintenant on va kill notre terminal et nous allons lancer la commande schmod + X start.sh et maintenant on va modifier les deux fichiers DEC compose parce que parce que nous avons défini dedans le nom du service ici ça va être nestgs-chat- frontend/dv et nous avons que deux vari d'environnement nous avons un frontend URL et un web socket URL et nous allons retirer toutes ces variables d'environnement puisqu'on en a plus que deux nous avons un backend URL et un web soocket URL ici comme nom de containur on va mettre exactement le même c'est-à-dire celui-là et nous allons seulement exposer le port 3000 qui est le port par défaut de remix maintenant on va faire la même chose sur le docker compose de prod c'està-dire qu'on va copier les deux variables d'environnement comme ceci et on va nommer le projet frontend production ici aussi frontend production et l'image va s'appeler nestjs-chat- frontend et bien sûr le port ça sera toujours le port 3000 maintenant on va tout de suite vérifier que ça fonctionne bien on va donc taper la commande de cors compose t F decore compose.f.yamel up-- build et maintenant on va regarder si ça marche bien normalement ça devrait fonctionn du premier coup et voilà ça a bien fonctionné nous sommes sur le port 3000 si on clique sur le projet on peut voir qu'on retrouve bien notre projet remix sur le port 3000 sauf qu'on a pas de style c'est un peu bizarre non al on va enquêter ensemble pour voir ce qui se passe si on retourne dans le fichier docer file j'ai l'impression qu'on a oublié d'ajouter le dossier public ici donc nous allons tout de suite l'ajouter ça vient peut-être de là on va rajouter le fichier public c'est la dernière étape donc normalement on va pas attendre longtemps et nous allons relancer le conteneur de cur là je vais d'abord kill le terminal pour arrêter l'instance en cours et je vais la relancer tout de suite et là on peut voir que cellea tout de suite relancé alors on va voir si on a un peu plus de chance on actualise la page et là nous avons le style ok c'est mieux comme ça donc maintenant on peut fermer cette fenêtre et nous pouvons passer à la suite la suite c'est les gitub actions on retourne donc dans le fichier de notre API et nous allons copier le dossier pointgthub ici et maintenant on va le coller dans le projet frontend ça va être à peu près la même chose sauf qu'on va modifier quelques trucs dans le fichier build on va bien sûr modifier le tag de notre projet ça va être nestgs-chat- frontend comme ceci et dans le fichier ci.yaml nous allons modifier les variables d'environnement ici on va donc rajouter deux secretes le backend_url et le websocket URL comme ceci et bien sûr à cet endroit-là nous devons également modifier le nom de l'image de cur c'est-à-dire qu'on va l'appeler frontend et nous allons également l'appeler frontend dans le commentaire on sait jamais maintenant que c'est fait on va retourner sur GitHub et on va retourner tourner sur le repository du frontend personnellement je l'ai appeler nestjs- chat- front comme ceci et ce que je vais faire c'est que je vais aller dans les settings ici et je vais aller dans les secrets and variable et je vais rajouter dans les actions de secret le premier secret sera le backend URL et cette variable c'est tout simplement laapi chat.algomax.fr donc je retourne sur GitHub et je colle HTTPS w.//happychat.algomax.fr on sauvegarde et pour le deuxème secret c'est le websocket_url et ça va être exactement le même lien sauf qu'on ajoute WS au début effectivement on n pas besoin de rajouter WSS on peut utiliser les web soockets en https comme ceci maintenant on rafraîchit la page on sauvegarde cette valeur et on peut maintenant passer à la suite la suite ça va être de reconfigurer le runnerner GitHub pour ce repository pour se faire on se rend dans action et on clique sur Runner et on va répéter l'opération donc new selfhosted run ça sera sur le même serveur donc on va sélectionner Linux et nous allons copier cette marche à suivre sauf que nous on va être un peu plus malin on va se rendre à la racine et on va faire un ls- L et on peut voir qu'on avait créé un dossier qui s'appelle deployments et si on céd dans le dossier deployments et qu'on refait un ls- l on peut voir que c'est à cet endroit qu'on avait téléchargé la base de code de notre premier runur pour la pay donc ce qu'on va faire c'est qu'on va faire un CD double point et nous allons renommer ce fichier deployments en fichier NJS chat- API pourquoi je le renomme tout simplement pour savoir dans quel fichier se trouve la logique de quel repository et maintenant je vais faire mkadir du dossier deployments et dans ce dossier je vais faire un MV du dossier nestjs-chat-api pour le déplacer dans le fichier deployments comme ceci maintenant si on fait un CD dans deployments et qu'on fait un ls- l on retrouve le dossier netjs chat API et c'est dans ce dossier que je vais créer un autre dossier qu'on va appeler nestjs- chat- frontend ou plutôt front comme ceci maintenant qu'on a créé ce nouveau dossier nous allons céder dedans nestjs chat ti front et c'est à l'intérieur que nous allons réinstaller cet exécutable une fois installé on exécute le reste des instructions et on va dziper ce fichier et maintenant on peut passer à la suite on va configurer le Runner GitHub comme ceci on appuie trois fois sur Entrer on attend un peu et on va encore appuyer sur Entrer et maintenant on lance la commande sudo SVC SH install pour installer le Runner qui va ensuite tourner en tâche de fond et après l'install on va faire un sudo/svc.sh Start et maintenant notre Runner est actif en tâche de fond pour vérifier on retourne sur gitub et on retourne sur Runner ici et on peut voir qu'il est au statut idle donc c'est bon la prochaine fois qu'on va poche du code sur notre branche main le code sera détecté donc maintenant on va retourner dans vs code dans notre projet front end ici on va tout clear et nous allons faire notre commit on va donc faire un gitad point un git commit add gthub actions et on va faire un pche sur la branche main sauf que si on retourne sur le serveur et qu'on affiche le contenu de notre fichier cadif file on peut voir ici qu'on fait un reverse proxy sur localast 360 ce qui signifie que notre projet est accessible sur le port 3060 sauf que c'est pas le cas dans le fichier de corp compose pointp ici on peut voir qu'on redirige le port du conttainur 3000 vers notre port 3000 sauf que ici on s'est trompé effectivement sur le serveur ça sera le port 3060 parce que le port 3000 est déjà utilisé par un autre projet donc je modifie cette erreur mais avant de pche le code on va aller dans les actions gthub pour voir si c'est la seule erreur que nous avons ici on peut voir que l'action a échoué et si on se rend dans le docker Buil en fait le problème c'est qu'on a tout simplement oublié de configurer déjà les identifiants docker et ensuite on n pas créé notre repository nesgs chat frontend donc on va le faire tout de suite on va se rendre dans repositories ici nous allons créer un nouveau repository qu'on a appelé du coup nestjs-chat- Frontin on va copier ce nom nesjs chat frontend et on va le créer comme ceci et maintenant on doit retourner sur gitub et rajouter les deux dernières actions qu'on avait déjà ajouté dans laapi mais cette fois on les ajoute dans le front donc on va se rendre dans secrets and variable et nous allons cliquer sur action et nous allons rajouter le docker hub username qui est donc égal à algomax et le docker hub token maintenant que c'est fait on ne devrait plus avoir de problème alors on va se rendre dans notre fontaine et nous allons faire un guit point pour ajouter notre changement sur le port 3060 Chang DEC onose porte et nous allons à nouveau P ce code sur la branche main maintenant que c'est fait il nous suffit de retourner sur GitHub pour voir si l'action se lance bien on clique dessus et là on peut voir qu'elle est en train d'être exécutée notre action est maintenant terminée sur la prod donc on va essayer de connecté on va taper sur Google chat.algomax.fr là on peut voir qu'on est bien connecté maintenant on va s'inscrire pour voir si ça fonctionne bien je vais donc créer un compte Virgile virgile@algomax.fr un mot de passe ABC 1 23 sanscrire et là c'est plutôt bon signe ça m'a redirigé sur la page de connexion sauf que je ne suis pas connecté alors on va essayer de se connecter tout de suite virgile@algomax.fr abc13 on se connecte et là on a une erreur en fait il arrive pas à se connecter au localhost 8000/hos/login alors à quoi est-ce que c'est dû on va voir ça tout de suite on retourne sur le serveur ici et nous allons inspecter les logs des deux projets on va d'abord inspecter les logs de notre API ici et là on peut voir qu'on a en fait une erreur au niveau de l'envoi de l'email on peut seulement envoyer des emails de test aux emails que nous possédons dans ce cas-là Virgile boris@mail.fr donc j'ai l'impression que c'est ça qui a causé notre erreur alors ce qu'on peut faire c'est qu'on peut ouvrir les logs et on peut rajouter l'instruction t F pour les laisser ouverts en Tage de fond comme ça maintenant on va refaire un essai on va s'inscrire à nouveau cette fois en mettant le mail qui est autorisé par resend et on va mettre comme mot de passe ABC 1 2 3 si on clique sur s'inscrire on peut voir que maintenant ça charge bien sauf que on est toujours pas connecté c'est bizarre et ici on peut voir qu'on a de nouveau la même erreur et ici on peut voir qu'on a maintenant par contre une ID qui est console logué dans la console alors qu'est-ce qui s'est passé déjà on va regarder voir si on a reçu le mail on peut voir ici que je viens de recevoir le mail de la part de ren.dev le mail c'est bonjour Virgile et bienvenue sur nestjs Chat nous sommes heureux de vous avoir parmi nous donc l'envoi de mail a bien fonctionné pour cette adresse email donc cette erreur là a été résolu en fait à quoi cette erreur est d et bien au service que nous utilisons pour envoyer les mails c'est-à-dire resend.dev si on se rend donc sur ren.com et qu'on se connecte avec notre compte GitHub ici on peut voir que j'ai sûrement utilisé une API de test alors en vrai je ne comprends pas trop le problème ce token n'a pas l'air d'être limité ici on peut voir qu'on a l'accès pour envoyer depuis tous les domaines sauf que si on clique sur domaine il nous propose de rajouter notre domaine mais je pense que ce qu'ils veulent dire c'est que si on ajoute notre domaine on peut ensuite on peut ensuite envoyer notre email à partir de notre propre nom de domaine par exemple unboarding@algomax.fr mais là c'est même pas ce que je voulais en fait ce que je voulais c'est tout simplement envoyer un email à n'importe qui alors ce qu'on peut faire c'est qu'on peut copier ce message d'erreur pour débugger un peu resend et cette erreur et on va voir à quoi cette erreur est liée alors voilà ici nous disent bien que pour autoriser tout envoie de mail on a besoin d'ajouter un domaine que nous possédons effectivement ils font ça pour ne pas dégrader la note de leur nom de domaine parce que si j'utilisais ce projet et que j'envoyais des mails à 100000 personnes et que je spammais leur boîte mail ça dégraderait la note de leur domaine resen.dev et ça ils veulent l'éviter mais c'est pas grave pour le moment on a une autre erreur qu'on a envie de corriger d'abord on veut pouvoir se connecter sans problème donc cette fois je vais faire une tentative de connexion je clique dessus et là j'ai toujours cette erreur il est impossible pour moi de me connecter alors à quoi c'est dû est-ce qu'on a un message d'erreur dans la console on a pas de message d'erreur côté AP donc on va kill le terminal et nous allons faire la même commande mais pour le frontend et sur la branche production et là on peut voir qu'on a d'autres types d'erreur ici ce qu'on va faire c'est qu'on va de nouveau cliquer plein de fois sur Se connecter et là on peut voir qu'on a C erur là c'est-à-dire des statutes de sang en fait il y a rien qui pose problème dans la console on ne sait pas vraiment à quoi l'erreur est liée parce qu'on a aucune erreur que ça soit au niveau du front end et du back end donc on va essayer d'inspecter la console ici on a une erreur au niveau des WebSockets mais je ne pense pas que le problème vienne de là mais on va quand même essayer de se connecter au WebSocket ça m'intéresse on va accéder à cette URL et là on peut voir en fait que ce site ne propose pas une connexion sécurisée et en fait cette erreur elle vient du fait qu'on n pas relancé cadi donc on va le relancer tout de suite avec un pudo systemme CTL restart de Cali pour déjà corriger le problème des web socket maintenant que c'est fait on actualise la page et on a une erreur différente cette page n'existe pas cependant si on retourne sur le site ici on peut voir que l'erreur du socketo a disparu je crois donc ce qu'on va faire c'est qu'on va refaire une tentative de connexion même si je ne pense pas que ce soit lié à ça ici en fait on a pas vraiment la raison de notre erreur donc ce qu'on a envie de faire c'est de voir si il connaît bien l'URL du backend si on fait un docker inspect nestgs chat frontend production et qu'on fait un grap de backend ici on peut voir que l'URL est la bonne c'est API chat.algomax.fr mais est-ce que c'est le cas au niveau du code si on retourne dans notre projet fronend ici et qu'on copie le lien localhost 8000 et qu'on le colle dans la recherche ici on peut voir qu'effectivement on a oublié de changer cette valeur ici on a fin une erreur de débutant on a codé en dure la valeur de notre bet URL ce qu'on va faire du coup c'est qu'on va remplacer cette valeur par [Musique] invv.backend_url comme ceci en fait c'est un process.inv et on va coller cette valeur partout où elle est utilisée ici aussi on va la rajouter et on n'oublie pas de rajouter les bactix on va également la rajouter dans le fichier forgot password qui l'utilise trois fois une première fois ici une deuxième fois ici on n'oublie pas les bactix et une troisième fois ici pour le reset du password et encore une fois on n'oublie pas les btix forcément avec une erreur pareil ça n'aurait jamais pu marcher donc ce qu'on va faire c'est qu'on va commitre ça on va mettre fixed fixed backend URL hard coded et on va pche cette nouvelle version qui je l'espère est maintenant corrigé et maintenant on retourne sur GitHub pour voir la nouvelle action qui est en train de travailler voilà on est maintenant à l'étape de déploiement dans la fille et on va bientôt avoir la réponse est-ce que le problème a été résolu la c est terminée on va retourner sur la application et on va retaper notre mot de passe et cette fois on a réussi à se connecter ça marche du tonner donc maintenant on va envoyer un message à un utilisateur sauf que maintenant on est en fait le seul utilisateur qui est présent sur cette plateforme c'est bien dommage alors on va tester voir si tout fonctionne on va d'abord choisir un avatar on va utiliser par exemple cette image on clique sur Modifier l'avatar et là on peut voir qu'on la retrouve bien ça a bien marché donc on est bien connecté Amazon S3 cette image est publié je peux copier son lien et je peux la télécharger au format que je veux donc ça c'est déjà cool maintenant on va voir si ça fonctionne bien au niveau de stripe on va cliquer sur je configure mon compte et là on a une erreur serveur au niveau de l'unboarding alors on a un problème alors on a un problème avec stripe qu'est-ce qui s'est passé on va le voir tout de suite en inspectant les logs si on fait un docker logs de notre backend donc c'est api dev ici on peut voir qu'on a cette erreur you must verify identity to use Connect create live connected accounts on doit donc cliquer sur le dashboard stripe et s'identifier pour pouvoir être autoriser à utiliser Connect en prod et pour cela il faut tout simplement ajouter notre carte d'identité sur le compte stripe à cet endroit là si je clique sur le lien on peut voir qu'il me demande donc de vérifier mon identité avec stripe pour cela j'ai besoin de scanner une pièce d'identité ou alors prendre un selfie pour qu'il puisse me reconnaître si je clique sur continuer on peut voir qu'il me demande de scanner un QR code sauf qu'on ne va pas faire cette étape maintenant on va pas tester si les payements stripe fonctionnent bien ça a l'air de marcher en tout cas parce que il a détecté qu'on est sur l'environnement de production et l'erreur ne vient pas d'un stripe non configuré il faut juste rajouter nos documents d'identité donc ce qu'on va faire à la place c'est qu'on va essayer de créer un deuxième compte même si resend nous autorise pas à le faire donc pour se faire on va se déconnecter ici et on va retourner sur néon.tech pour voir si on a bien deux comptes qui ont été créés on va donc dans table ici et nous dans user et on peut voir qu'on a bien deux comptes qui existent on a quand même le compte virgil@algomx.fr au final il existe bien c'est juste que ça ne nous a pas identifié donc ce qu'on va faire c'est qu'on va se connecter avec ce compte là et comme on peut voir ça fonctionne très bien donc on va cliquer sur Historique des conversations ici pour se rendre sur la page d'une conversation qu'il est possible de faire et on va avoir une conversation avec Virgile hello man how are you ici on va inspecter le code pour voir si les web soockets fonctionnent et pour se faire on va ouvrir une deuxième fenêtre en navigation privée et nous allons copier l'URL du site et on va ouvrir cette fenêtre ici on peut voir que j'ai été rediriger sur la page d'accueil parce que je ne suis pas connecté donc je vais me connecter avec Virgile et je vais de nouveau me rendre sur l'URL de cette conversation et je vais tout simplement répondre W new et là on peut voir que le message est apparu automatiquement ici parce que les web sockets ont bien fonctionné ça a très bien marché et on va même ouvrir la console pour voir à quel point ça marche bien test test test et c'est ici qu'on retrouve notre donnée mise à jour du coup si là j'envoie d'autres messages test test test P voir que la connexion reste ouverte et que je reçois des messages à l'infini maintenant bien sûr pour envoyer de l'argent à vos utilisateurs vous devez au préalable vérifier votre compte stripe et fournir votre pièce d'identité et bien sûr pour pouvoir envoyer des emails vous devez d'abord ajouter un nom de domaine et on peut le faire ensemble tout de suite ce qu'on va faire c'est qu'on va d'abord choisir le nombre de domaines qu'on souhaite utiliser par exemple chatalgomax.fr et on peut seulement choisir cette région malheureusement donc on va l'ajouter et ensuite une fois que c'est fait on a besoin de rajouter des champs chez OVH pour l'URL chat.algomax.fr donc pour ce faire on va retourner sur OVH ici et on regarde il nous demande de rajouter le champ MX avec cette valeur donc on retourne sur OVH et on va ajouter une entrée de type MX ici avec comme valeur cette valeur là qu'ils nous ont fourni ici et avec comme nom send.chat ici donc on retourne sur OVH et on va rajouter le nom ici et ils veulent que ça soit en priorité 10 comme ceci on va rajouter la priorité 10 et on appuie sur Next et sur Confirmer maintenant on retourne sur resend et on va rafraîchir cette page pour voir s'il détecte déjà le changement maintenant on va rajouter deux champs txt le premier ça sera cette valeur donc on retourne ici et on va ajouter un champ txt avec cette valeur à send.chat alors pourquoi send point chat déjà c'est send point et notre nom de domaine mais comme nous avons un sous-domaine qui s'appelle chat et bien ça va utiliser send point chat comme ceci maintenant on va appuyer sur Next et on va retourner une dernière fois sur resend et on va copier la dernière clé txt ici donc on rajoute un champ txt comme ceci avec comme valeur celle-ci et on peut maintenant sauvegarder cette valeur et on va retourner sur resend et ce qui est cool bien sûr c'est qu'on peut rajouter avec resend plein d'options comme track les clics par exemple et traquer le taux d'ouverture bien sûr pour ajouter encore plus de sécurité on peut ajouter cette dernière option le démarque en ajoutant cette valeur encore une fois c'est un txt qu'on va devoir ajouter on va se rendre sur OVH on va ajouter un champ txt avec ça comme valeur et on va lui assigner cette valeur là comme ceci maintenant on peut sauvegarder et ça devrait être bon on a plus qu'à attendre que recend vérifie nos informations donc on doit cliquer sur verify DNS record comme ceci et on peut voir que les informations sont en attente et qu'elles viennent d'être vérifiées ça a très bien fonctionné donc je pense que maintenant on doit mettre à jour notre code pour que ça envoie le mail depuis le bon domaine on va retourner à cet endroit-là et je vais regarder si on peut modifier le domaine d'envoi est-ce qu'on peut changer le domaine au niveau de notre code c'est dans le from ici donc on va quand même le faire pour tester on va mettre Virgile et on va mettre virgile@chat.algomax.fr maintenant qu'on a ajouté ce nom de domaine ce qui nous reste à faire c'est de versionner cette nouvelle version de notre API mais juste avant de le faire on va quand même retourner dans le fichier decor compose.pr et ici on va changer cette faute de frappe parce qu'on a oublié de copier-coller ici de rajouter production non pas dev parce que c'est bien la branche production à ce ni voà maintenant que c'est rajouté on peut commit changed recend domain et on peut push origine a maintenant on va se rendre sur GitHub pour voir les avancements de notre action et on peut voir qu'on a peut-être une petite erreur parce qu'on on a renommé le dossier de déploiement pour cette application et donc du coup j'ai l'impression que le Runner GitHub il ne fonctionne plus donc on va tout de suite le reconfigurer on va faire un CD on va retourner dans le dossier deployments et on va aller dans le dossier nestgs chat/ API et on va cette fois faire l'étape enerse c'estàd qu'on va désinstaller ce Runner là on va donc faire un inststall plutôt d'abord un stop mais là en fait j'ai l'impression que j'ai fait une petite erreur si on se rendre dans dans les informations de notre projet giitub dans action et dans Runner ici ici on peut voir que le Runner en fait il est offline c'est-à-dire qu'on l'a clairement carrément tué donc c'est pas grave on va en recréer un nouveau d'abord on va supprimer ce dossier on va faire un rmrf de nestgs- chat- API et on va recréer ce dossier une dernière fois avec le Runner en fait on a fait ça tout simplement pour s'organiser sur le serveur pour qu'on ait un seul dossier avec tous nos déploiements pour que ça soit beaucoup plus simple de les retrouver donc on va faire un MD ngs- chat API on retourne dedans dans ce fichier et on va ajouter un Runner pour la dernière fois en copiant chacune des étapes une par une comme ceci on va copier la deuxième étape et enfin la troisème étape et maintenant on va configurer ce Runner et après l'avoir configuré GitHub recevra le signal ici dans notre action gitub va recevoir le signal et il va terminer cette action donc on appuie sur entrere et là on peut voir qu'il a déjà trouvé un Runner il possède le même nom donc en fait on va appuyer sur Y pour remplacer le runnerner existant comme ceci et après avoir configuré maintenant on va refaire un SVC install comme ceci et un SVC Start et j'ai l'impression que ça fonctionné en fait on a même pas eu besoin de lancer ces commandes parce que le Runner existait déjà là si on fait un sudseudo svc.sh status on peut voir que le Runner il est totalement décédé donc ce qu'on peut faire c'est qu'on peut l'arrêter et même le désinstaller mais en fait j'ai l'impression que ça marche vraiment pas et ça c'est un petit problème si on fait un status ok il n'est pas installé là c'est bon ce qu'on va faire c'est qu'on va le réinstaller et on va le relancer et maintenant ça a l'air d'être mieux en fait on a dû le désinstaller pour le réinstaller c'était un petit peu bizarre là si on rafraîchit la page on peut voir qu'il est maintenant actif en fait il est plus idle il est actif parce que GitHub vient d'exécuter notre action de déploiement donc ce qu'on va faire maintenant c'est qu'on va supprimer chaque onglet qu'on a d'ouvert on attend que le déploiement se termine et là on a même eu une erreur au niveau du déploiement alors là c'est vraiment marrant on a toutes les erreurs c'est parfait et cette erreur là elle est liée en fait à l'image qu'on avait créé qui s'appelait ipi dev et que nous avons renommé donc pour réparer cette erreur ce qu'on va faire c'est qu'on va faire un docker système prune pour tout simplement supprimer les images docker qui ne sont plus utilisé notamment celle de l'environnement de développement et ça nous demande donc de confirmer parce que ça va supprimer toutes les images et il n'y aura plus de notion de cache en tout cas ça va supprimer toutes les images qui ne sont pas actives donc ne vous inquiétez pas notre projet fend est actif donc ça va pas la supprimer et l'API qui est actuellement présente est active donc ça ne va pas la supprimer ce qu'on peut faire qu'on peut appuyer sur oui et comme l'API est actuellement active ça ne la supprime pas on a quand même envie de la supprimer donc on va lancer la commande docker stop et le nom de notre projet nestjs chat api_dev comme ceci et nous sommes maintenant en train d'arrêter une image do cur pour essentiellement la supprimer maintenant on peut retaper la commande d'avant de corore system Prun comme ceci et on va confirmer et on peut voir que ça a supprimé notre image do cur maintenant que c'est fait on peut retourner sur GitHub sur notre action de déploiement et nous allons la réexécuter pour voir si ça résout le problème et là cette fois l'action de déploiement a fonctionné donc on va retourner sur notre terminal et nous allons faire docker logs cette fois de l'image nestjs chat dir api production on rajoute le T F et là on peut voir que ça fonctionne beaucoup mieux donc on va retourner sur notre application et nous allons créer un dernier compte pour voir si on reçoit bien les emails le compte ça va donc être fegamerscceil@gmail.fr bien sûr on met ça dans l'adresse email et on va s'appeler epic tê et le mot de passe sera ABC1 23 maintenant on va s'inscrire et on peut voir que ça m'a bien connecté ça m'a connecté donc le domaine a été confirmé par resend et si on regarde les emails que nous avons reçu ici on peut voir Virgile bienvenue sur la plateforme et ça a été envoyé par virgil@chat. algomax.fr on peut donc le signaler comme non spam bonjour ép tête et bienvenue sur nestgs Chat nous sommes heureux de vous avoir parmi nous et voilà nous avons terminé cette intégration de notre chat avec nest JS et remix n'hésite pas à me dire dans les commentaires ce que tu as pensé de cette vidéo est-ce qu'elle t'a plu est-ce que tu as appris quelque chose et on se retrouve très bientôt pour une prochaine à plus