From a2d85d2e669c23268a47f76becc101ba6be7f423 Mon Sep 17 00:00:00 2001 From: Selma EL BABARTI <selma.el-babarti@etu.univ-nantes.fr> Date: Tue, 16 May 2023 08:45:30 +0200 Subject: [PATCH] test avec ajout des fichiers admin --- dynamique/app/administration.html | 43 +++-- dynamique/app/connexion_admin.html | 12 +- dynamique/app/js/admin.js | 281 ++++++++++++++++++++++++----- dynamique/app/js/coadmin.js | 47 +++++ dynamique/app/js/pays.js | 2 +- 5 files changed, 317 insertions(+), 68 deletions(-) create mode 100644 dynamique/app/js/coadmin.js diff --git a/dynamique/app/administration.html b/dynamique/app/administration.html index a2dd420..a43afd9 100644 --- a/dynamique/app/administration.html +++ b/dynamique/app/administration.html @@ -74,14 +74,17 @@ <label for="image_pays">Image du pays (lien):</label> <textarea id="image_pays" name="image_pays" rows="1" cols="4"></textarea><br> + <label for="drapeau_pays">Drapeau du pays (lien):</label> + <textarea id="drapeau_pays" name="drapeau_pays" rows="1" cols="4"></textarea><br> + <label for="liste_cuisine">Sélectionnez la cuisine de ce pays :</label> - <select class="liste_cuisine" id="liste_cuisine"></select><br> + <select class="liste_cuisine" id="crealicuisine" multiple></select><br> <label for="liste_sport">Sélectionnez le sport de ce pays :</label> - <select class="liste_sport" id="liste_sport"></select><br> + <select class="liste_sport" id="crealisport" multiple></select><br> <label for="liste_nature">Sélectionnez la nature de ce pays :</label> - <select class="liste_nature" id="liste_nature"></select><br> + <select class="liste_nature" id="crealinature" multiple></select><br> <label for="liste_culture">Sélectionnez la culture de ce pays :</label> - <select class="liste_culture" id="liste_culture"></select><br> + <select class="liste_culture" id="crealiculture" multiple></select><br> @@ -93,22 +96,22 @@ <h2>Modifier un pays existant</h2> <form id="form-modifier-pays"> <label for="liste_pays">Sélectionnez un pays :</label> - <select id="liste_pays" name="nom_pays"></select><br> + <select class = "liste_pays" id="liste_pays_modif" name="nom_pays"></select><br> - <label for="description_pays">Description du pays :</label><br> - <textarea id="description_pays" name="description_pays" rows="5" cols="40"></textarea><br> + <label for="modif_description">Description du pays :</label><br> + <textarea id="modif_description" name="modif_description" rows="5" cols="40"></textarea><br> - <label for="image_pays">Image du pays (lien):</label> - <textarea id="image_pays" name="image_pays" rows="1" cols="4"></textarea><br> - - <label for="liste_cuisine">Sélectionnez la cuisine de ce pays :</label> - <select class="liste_cuisine" id="liste_cuisine"></select><br> - <label for="liste_sport">Sélectionnez le sport de ce pays :</label> - <select class="liste_sport" id="liste_sport"></select><br> - <label for="liste_nature">Sélectionnez la nature de ce pays :</label> - <select class="liste_nature" id="liste_nature"></select><br> - <label for="liste_culture">Sélectionnez la culture de ce pays :</label> - <select class="liste_culture" id="liste_culture"></select><br> + <label for="change_image">Image du pays (lien):</label> + <textarea id="change_image" name="change_image" rows="1" cols="4"></textarea><br> + + <label for="liste_cuisine">Sélectionnez la cuisine de ce pays (CTRL pour plusieurs):</label> + <select class="liste_cuisine" id="modificuisine" multiple></select><br> + <label for="liste_sport">Sélectionnez le sport de ce pays (CTRL pour plusieurs) :</label> + <select class="liste_sport" id="modifisport" multiple></select><br> + <label for="liste_nature">Sélectionnez la nature de ce pays (CTRL pour plusieurs):</label> + <select class="liste_nature" id="modifinature" multiple></select><br> + <label for="liste_culture">Sélectionnez la culture de ce pays (CTRL pour plusieurs) :</label> + <select class="liste_culture" id="modificulture" multiple></select><br> <input type="submit" value="Modifier le pays"> </form> @@ -117,8 +120,8 @@ <h2>Supprimer un pays</h2> <form id="form-supprimer-pays"> <label for="liste_pays">Sélectionnez un pays :</label> - <select id="liste_pays" name="nom_pays"></select><br> - <input type="submit" value="Supprimer le pays"> + <select class = "liste_pays" id="liste_pays_supp" name="nom_pays_supp" ></select><br> + <input type="submit_supp" value="Supprimer le pays"> </form> </section> diff --git a/dynamique/app/connexion_admin.html b/dynamique/app/connexion_admin.html index bd401ce..84c8b50 100644 --- a/dynamique/app/connexion_admin.html +++ b/dynamique/app/connexion_admin.html @@ -8,8 +8,8 @@ <script src="https://cdnjs.cloudflare.com/ajax/libs/es6-promise/4.0.5/es6-promise.min.js" defer></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/fetch/2.0.1/fetch.min.js" defer></script> <!-- Notre script principal : --> - <script type="text/javascript" src="./js/data.js" defer></script> - <script type="text/javascript" src="./js/main.js" defer></script> + <script type="text/javascript" src="./js/main.js" defer></script> + <script type="text/javascript" src="./js/coadmin.js" defer></script> </head> @@ -59,12 +59,12 @@ <!-- Connexion --> <section id="connection"> - <form class="form" action="administration.html"> - <label class="label" for="username">Adresse mail:</label> + <form class="form"> + <label class="label" for="username">Adresse mail: (prenom.nom.admin@gmail.com)</label> <input type="text" id="mail" name="mail" required><br><br> - <label for="password">Mot de passe:</label> + <label for="password">Mot de passe: (Admin)</label> <input type="password" id="password" name="password" required><br><br> - <input type="submit" value="Se connecter"> + <input type="submit" id="loginBouton" value="Se connecter"> </form> </section> diff --git a/dynamique/app/js/admin.js b/dynamique/app/js/admin.js index 695ecbe..05c28ca 100644 --- a/dynamique/app/js/admin.js +++ b/dynamique/app/js/admin.js @@ -1,57 +1,256 @@ -// Récupération du formulaire -const form = document.getElementById("form-creer-pays"); +////ON RECUPERE LES DONNEES //// +var pageUrl = window.location.pathname; // renvoie l'URL de la page +var pageID = pageUrl.substring(pageUrl.lastIndexOf('/')+1, pageUrl.lastIndexOf('.')); -// Écouteur d'événement sur la soumission du formulaire -form.addEventListener("submit", function(event) { - // Empêcher le comportement par défaut du formulaire (envoi de données) - event.preventDefault(); +const base_url = 'http://127.0.0.1:8899'; +const auth_token = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6InNlbG1hLmVsYmFiYXJ0aUBnbWFpbC5jb20iLCJmaXJzdG5hbWUiOm51bGwsImxhc3RuYW1lIjpudWxsLCJpZCI6InVzX2g0bTBxM2VnNDM0eGJ4Iiwicm9sZXMiOiJvcmctbGV2ZWwtY3JlYXRvcixzdXBlciIsInRva2VuX3ZlcnNpb24iOiI4YmIwMjBjYjQ5YmVjMjJlOGQzNGY4YjkzOGQ2NDc4OTczYWY4ZTFlZDBiZjIxNzQ0YzFkNzliMGM2MGY2ZjAzMGEwYTI3OWFhY2VlMzk4YSIsImlhdCI6MTY4NDA2MzcyMiwiZXhwIjoxNjg0MDk5NzIyfQ.xO_OQkVzHBgB3FwXdT7BlfM-oalruQzETAQlnBlZuTo'; - // Récupération des valeurs des champs - const nomPays = document.getElementById("nom_pays").value; - const descriptionPays = document.getElementById("description_pays").value; - const imagePays = document.getElementById("image_pays").value; - const cuisinePays = document.getElementById("liste_cuisine").selectedIndex !== -1 ? document.getElementById("liste_cuisine").value : ""; - const sportPays = document.getElementById("liste_sport").selectedIndex !== -1 ? document.getElementById("liste_sport").value : ""; - const naturePays = document.getElementById("liste_nature").selectedIndex !== -1 ? document.getElementById("liste_nature").value : ""; - const culturePays = document.getElementById("liste_culture").selectedIndex !== -1 ? document.getElementById("liste_culture").value : ""; - +async function getFromAPI(url){ + let req = await fetch(url, { + method: 'GET', + headers: { + 'xc-auth': auth_token, + 'Access-Control-Allow-Origin': '*', + 'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS', + 'Access-Control-Allow-Headers': 'Content-Type, Authorization' + } + }); + let data = await req.json(); + return data; +} + +//ON AFFICHE ET COMPLETE LES PAYS DANS LES MENUS DEROULANTS (modifier, supprimer) +async function loadpays() +{ + const select = document.getElementsByClassName('liste_pays'); + const list_pays = await getFromAPI(base_url+'/api/v1/db/data/v1/Latino/Pays/views/Pays'); + for (const pays of list_pays) { + const option = document.createElement('option');//on crée une nouvelle option + option.value = pays.IdPays; + option.textContent = pays.Nom; + select.appendChild(option);//on ajoute cette option au menu déroulant + } +} +loadpays() + +//ON AFFICHE LES OPTIONS CUISINE, NATURE, CULTURE ET SPORT DANS LES MENUS DEROULANTS (créer, modifier) +async function loadOptions() +{ + const selectNature = document.getElementsByClassName('liste_nature'); + const selectCuisine = document.getElementsByClassName('liste_cuisine'); + const selectCulture = document.getElementsByClassName('liste_culture'); + const selectSport = document.getElementsByClassName('liste_sport'); + + const list_cuisine= await getFromAPI(base_url+'/api/v1/db/data/v1/Latino/Cuisine'); + for (const cuisine of list_cuisine) { + const optionCui = document.createElement('option');//on crée une nouvelle option + optionCui.value = cuisine.IdCuisine; + optionCui.textContent = cuisine.Nom; + selectCuisine.appendChild(optionCui);//on ajoute cette option au menu déroulant + } + const list_nature= await getFromAPI(base_url+'/api/v1/db/data/v1/Latino/Nature'); + for (const nature of list_nature) { + const optionNat = document.createElement('option');//on crée une nouvelle option + optionNat.value = nature.IdNature; + optionNat.textContent = nature.Nom; + selectNature.appendChild(optionNat);//on ajoute cette option au menu déroulant + } + const list_culture= await getFromAPI(base_url+'/api/v1/db/data/v1/Latino/Culture'); + for (const culture of list_culture) { + const optionCult = document.createElement('option');//on crée une nouvelle option + optionCult.value = culture.IdCulture; + optionCult.textContent = culture.Nom; + selectCulture.appendChild(optionCult);//on ajoute cette option au menu déroulant + } + const list_sport= await getFromAPI(base_url+'/api/v1/db/data/v1/Latino/Sport'); + for (const sport of list_sport) { + const optionSport = document.createElement('option');//on crée une nouvelle option + optionSport.value = sport.IdSport; + optionSport.textContent = sport.Nom; + selectSport.appendChild(optionSport);//on ajoute cette option au menu déroulant + } +} +loadOptions() + + + + + + + +///LA PARTIE OU L'ADMINISTRATEUR CREE UN NOUVEAU PAYS DANS LA BASE DE DONNEES - // Création de l'objet de données à envoyer au serveur - const data = { - nom_pays: nomPays, - description_pays: descriptionPays, - image_pays: imagePays, - cuisine_pays: cuisinePays, - sport_pays: sportPays, - nature_pays: naturePays, - culture_pays: culturePays - }; - const base_url = 'http://127.0.0.1:8899'; - const auth_token = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6InNlbG1hLmVsYmFiYXJ0aUBnbWFpbC5jb20iLCJmaXJzdG5hbWUiOm51bGwsImxhc3RuYW1lIjpudWxsLCJpZCI6InVzX2g0bTBxM2VnNDM0eGJ4Iiwicm9sZXMiOiJvcmctbGV2ZWwtY3JlYXRvcixzdXBlciIsInRva2VuX3ZlcnNpb24iOiI4YmIwMjBjYjQ5YmVjMjJlOGQzNGY4YjkzOGQ2NDc4OTczYWY4ZTFlZDBiZjIxNzQ0YzFkNzliMGM2MGY2ZjAzMGEwYTI3OWFhY2VlMzk4YSIsImlhdCI6MTY4MzgwMjg3MiwiZXhwIjoxNjgzODM4ODcyfQ.oUB0G-FuicvkX7AyJwJU4qGVUG6-T-MyhD8ni1Z1MZU'; +//On récupère le formulaire de création de pays +const form = document.getElementById('form-creer-pays'); +form.addEventListener('submit', async function(event) { + event.preventDefault();//// Empêche le rechargement de la page - // Envoi des données au serveur (exemple avec fetch) - fetch(base_url+"/api/v1/db/data/v1/Latino/Pays/views/Pays/", { - method: "POST", + // Récupération des valeurs du formulaire + const nom = document.getElementById('nom_pays').value; + const description = document.getElementById('description_pays').value; + const drapeau = document.getElementById('drapeau_pays').value; + const photo = document.getElementById('image_pays').value; + + // Récupération des sélections de la liste déroulante + const cuisines = Array.from(document.querySelectorAll('#crealicuisine option:checked')).map(option => option.value); + const sports = Array.from(document.querySelectorAll('#crealisport option:checked')).map(option => option.value); + const natures = Array.from(document.querySelectorAll('#crealinature option:checked')).map(option => option.value); + const cultures = Array.from(document.querySelectorAll('#crealicultures option:checked')).map(option => option.value); + + // Création d'un nouveau pays avec les valeurs du formulaire + const nouveauPays = { + IdPays: nom.normalize("NFD").replace(/[\u0300-\u036f]/g, "").toLowerCase(), //le nom du pays en minuscule + Nom: nom, + Description: description, + Drapeau: drapeau, + Photo: photo, + PaysCuisine: cuisines.map(c => ({ IdPaysCuisine: '', IdCuisineLien: c })), + PaysSport: sports.map(s => ({ IdPaysSport: '', IdSportLien: s })), + PaysNature: natures.map(n => ({ IdPaysNature: '', IdNatureLien: n })), + PaysCulture: cultures.map(c => ({ IdPaysCulture: '', IdCultureLien: c })), + }; + + // Envoi de la requête à l'API pour ajouter le nouveau pays à la BDD + const ajout = await fetch(base_url + '/api/v1/db/data/v1/Latino/Pays/views/Pays', { + method: 'POST', headers: { - 'Accept': 'application/json', - "Content-Type": "application/json", - 'xc-auth' : auth_token, + 'Content-Type': 'application/json' }, - body: JSON.stringify(data) + body: JSON.stringify(nouveauPays) + }); + if (!ajout.ok) { + console.error('Erreur lors de la création du pays'); + return; + } + console.log('Le pays a été créé avec succès !'); +}); + + + + + + + + + +///LA PARTIE OU L'ADMINISTRATEUR SUPPRIME UN NOUVEAU PAYS DANS LA BASE DE DONNEES + +// Récupérer la séletion du pays à supprimer pour l'administrateur +const paysAsupprimer = document.getElementById('form-supprimer-pays'); + +// Ajouter un écouteur d'événement lorsque la sélection est envoyée +paysAsupprimer.addEventListener('submit', function(event) { + // Empêcher le formulaire de se soumettre normalement + event.preventDefault(); + + // Récupérer l'ID du pays sélectionné + const idPays = document.getElementById('liste_pays_supp').value; + + // Envoyer une requête DELETE pour supprimer le pays de la base de données + fetch(`/api/v1/db/data/bulk/v1/Latino/Pays/${idPays}`, { + method: 'DELETE' }) .then(response => { - // Traitement de la réponse du serveur + // Vérifier que la réponse est bonne (200) if (response.ok) { - alert("Le pays a été créé avec succès !"); - form.reset(); // Réinitialisation du formulaire + // Afficher un message comme quoi la suppression est ok + alert('Le pays a été supprimé.'); + // Recharger la page pour mettre à jour la liste des pays + location.reload(); } else { - alert("Une erreur est survenue lors de la création du pays."); + // Afficher un message d'erreur + alert('La suppression est ratée.'); } - console.log(data) }) .catch(error => { - console.error(error); - alert("Une erreur est survenue lors de la création du pays."); + // Afficher un message d'erreur + alert('Il y a une erreur, regarde la console'); + console.error(error);//affiche l'erreur dans la console }); }); + + + + + + + + + + + + +// LA PARTIE OU L'ADMINISTRATEUR FAIT LES MODIFICATIONS + +// PAYS +//Les champs du pays sélectionné sont affichés : +async function afficheChamps(PaysID){ + // charger les données du pays à partir de l'API + const paysData = await getFromAPI(base_url+`/api/v1/db/data/v1/Latino/Pays/views/Pays/${PaysID}`); + + + // récupérer les éléments associés au pays sélectionné + const descripPays = paysData["Description"]; + const imagePays = paysData["Photo"]; + const cuisineList = paysData["Cuisine List"]; + const cultureList = paysData["Culture List"]; + const natureList = paysData["Nature List"]; + const sportList = paysData["Sport List"]; + + ////ZONES DE TEXTES + ///AFFICHER LES ELEMENTS DU PAYS SELECTIONNE + document.getElementById("modif_description").value = descripPays; + document.getElementById("change_image").value = imagePays; + //A COMPLETER POUR LES LISTES +} + +///L'administrateur sélectionne un pays : +async function selectionPays() { + const select = document.getElementById('liste_pays_modif'); + const selectedIdPays = select.value; + const list_pays = await getFromAPI(base_url+'/api/v1/db/data/v1/Latino/Pays/views/Pays'); + const selectedPays = list_pays.find(pays => pays.IdPays === selectedIdPays); + console.log("Pays sélectionné par l'admin : ", selectedPays.Nom); + afficheChamps(pays.IdPays) + } + +// Ajouter un écouteur d'événements pour le changement de pays au menu déroulant, cela va appeler selectionPays +const selectpays = document.getElementById('liste_pays_modif'); +selectpays.addEventListener('change', selectionPays); + +const formodif = document.getElementById("form-modifier-pays"); + +// Ajouter un écouteur d'événements pour la soumission du formulaire +formodif.addEventListener("submit", async (event, IdPaysamodif) => { + // Empêcher le comportement par défaut du formulaire (rechargement de la page) + event.preventDefault(); + + // Récupérer les données du formulaire + const descriptionMAJ = document.getElementById("modif_description").value; + const imageMAJ = document.getElementById("change_image").value; + + // Créer un objet avec les données à mettre à jour + const dataMAJ = { + Description: descriptionMAJ, + Photo: imageMAJ, + }; + + // Créer la requête API pour mettre à jour le pays dans la base de données + const maj = await fetch(base_url+`/api/v1/db/data/v1/Latino/Pays/${paysId}`, { + method: "PATCH", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify(dataMAJ), + }); + + // Vérifier la réponse de la requête + if (maj.ok) { + // Afficher un message de confirmation + alert("Le pays a été modifié avec succès !"); + } else { + // Afficher un message d'erreur + alert("Une erreur est survenue lors de la modification du pays."); + } +}); diff --git a/dynamique/app/js/coadmin.js b/dynamique/app/js/coadmin.js new file mode 100644 index 0000000..3bffab8 --- /dev/null +++ b/dynamique/app/js/coadmin.js @@ -0,0 +1,47 @@ +//LA PARTIE CONNEXION ADMINISTRATEUR + +// Récupérer les éléments HTML pour l'identification de l'administrateur +const emailInput = document.getElementById('mail'); +const passwordInput = document.getElementById('password'); +const loginButton = document.getElementById('loginBouton'); +const auth_token = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6InNlbG1hLmVsYmFiYXJ0aUBnbWFpbC5jb20iLCJmaXJzdG5hbWUiOm51bGwsImxhc3RuYW1lIjpudWxsLCJpZCI6InVzX2g0bTBxM2VnNDM0eGJ4Iiwicm9sZXMiOiJvcmctbGV2ZWwtY3JlYXRvcixzdXBlciIsInRva2VuX3ZlcnNpb24iOiI4YmIwMjBjYjQ5YmVjMjJlOGQzNGY4YjkzOGQ2NDc4OTczYWY4ZTFlZDBiZjIxNzQ0YzFkNzliMGM2MGY2ZjAzMGEwYTI3OWFhY2VlMzk4YSIsImlhdCI6MTY4NDA2MzcyMiwiZXhwIjoxNjg0MDk5NzIyfQ.xO_OQkVzHBgB3FwXdT7BlfM-oalruQzETAQlnBlZuTo'; + + +// Écouter l'événement click sur le bouton de connexion: c'est cet évènement qui fait le lien avec la BDD +loginButton.addEventListener('click', () => { + // Récupérer les valeurs entrées par l'utilisateur + const Mail = emailInput.value; + const MotDePasse = passwordInput.value; + + // Vérifier si les champs sont remplis pour passer à la vérification en BDD + if (Mail.trim() === '' || MotDePasse.trim() === '') { + alert('Veuillez remplir tous les champs'); + return; + } + else { + console.log("test"); + // Envoyer la requête pour vérifier les identifiants de l'administrateur + fetch('/api/v1/db/data/v1/Latino/Administrateur', { + method: 'POST', + headers: { + 'xc-auth': auth_token, + 'Content-Type': 'application/json' + + }, + body: JSON.stringify({ + Mail, + MotDePasse + })//envoie des données d'identification à l'API sous forme de chaîne JSON + }) + .then(response => response.json()) + .then(data => { + // Si les identifiants sont valides, rediriger vers la page d'administration + if (data.valid) { + window.location.href = '/administration.html'; + } else {//message à l'utilisateur + alert('Identification incorrecte. Réeesayez.'); + } + }) + } + +}); \ No newline at end of file diff --git a/dynamique/app/js/pays.js b/dynamique/app/js/pays.js index 469041a..cbf2f9a 100644 --- a/dynamique/app/js/pays.js +++ b/dynamique/app/js/pays.js @@ -51,7 +51,7 @@ var pageID = pageUrl.substring(pageUrl.lastIndexOf('/')+1, pageUrl.lastIndexOf(' const base_url = 'http://127.0.0.1:8899'; -const auth_token = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6InNlbG1hLmVsYmFiYXJ0aUBnbWFpbC5jb20iLCJmaXJzdG5hbWUiOm51bGwsImxhc3RuYW1lIjpudWxsLCJpZCI6InVzX2g0bTBxM2VnNDM0eGJ4Iiwicm9sZXMiOiJvcmctbGV2ZWwtY3JlYXRvcixzdXBlciIsInRva2VuX3ZlcnNpb24iOiI4YmIwMjBjYjQ5YmVjMjJlOGQzNGY4YjkzOGQ2NDc4OTczYWY4ZTFlZDBiZjIxNzQ0YzFkNzliMGM2MGY2ZjAzMGEwYTI3OWFhY2VlMzk4YSIsImlhdCI6MTY4MzgwMjg3MiwiZXhwIjoxNjgzODM4ODcyfQ.oUB0G-FuicvkX7AyJwJU4qGVUG6-T-MyhD8ni1Z1MZU'; +const auth_token = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6InNlbG1hLmVsYmFiYXJ0aUBnbWFpbC5jb20iLCJmaXJzdG5hbWUiOm51bGwsImxhc3RuYW1lIjpudWxsLCJpZCI6InVzX2g0bTBxM2VnNDM0eGJ4Iiwicm9sZXMiOiJvcmctbGV2ZWwtY3JlYXRvcixzdXBlciIsInRva2VuX3ZlcnNpb24iOiI4YmIwMjBjYjQ5YmVjMjJlOGQzNGY4YjkzOGQ2NDc4OTczYWY4ZTFlZDBiZjIxNzQ0YzFkNzliMGM2MGY2ZjAzMGEwYTI3OWFhY2VlMzk4YSIsImlhdCI6MTY4NDIxOTI3NywiZXhwIjoxNjg0MjU1Mjc3fQ.mUFSHuT02Lva9H4s6CG8aOonQGQVNvW6EA7C4n8g1EA'; async function getFromAPI( url ){ let req = await fetch( url ,{ -- GitLab