Liste des API
API dans l'ordre d'importance
1) Liste des établissements - Données locales https://portail.ac-reunion.fr/swami/public/api/etablissements/
Importation du fichier vierge avec les têtes de colonne dans GRIST : Annuaire-ETAB-ACA-ALL.csv
Ce code permet d'ajouter, de corriger les établissements mis à jour.
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="utf-8">
<title>Import Lycées La Réunion</title>
<script src="https://docs.getgrist.com/grist-plugin-api.js"></script>
<style>
#importEtabBtn {
margin: 10px;
padding: 10px 20px;
background-color: #4CAF50;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
font-family: sans-serif;
font-size: 14px;
transition: background-color 0.3s;
}
#importEtabBtn:hover:not(:disabled) {
background-color: #45a049;
}
#importEtabBtn:disabled {
background-color: #cccccc;
cursor: not-allowed;
}
</style>
</head>
<body>
<div style="font-family: sans-serif; padding: 1em;">
<h2>Import des établissements</h2>
<p>Cliquez sur le bouton ci-dessous pour mettre à jour la table **"Annuaire_ETAB_ACA_ALL"**.</p>
<button id="importEtabBtn">Mettre à jour l'annuaire</button>
<p id="status" style="margin-top: 10px; color: #666;"></p>
</div>
<script>
// Demande un accès complet pour lire et écrire
grist.ready({ requiredAccess: 'full' });
// Liste des noms de colonnes pour la cohérence
const COLUMN_NAMES = [
"uaj", "nom", "denominationOfficielle", "uajDenominationOfficielle",
"type", "rue", "bassin", "code_postal", "ville", "tel", "fax", "mail", "lat", "lon"
];
/**
* Récupère les données d'établissements via l'API externe.
*/
async function fetchEtab() {
const apiUrl = "https://portail.ac-reunion.fr/swami/public/api/etablissements/";
try {
document.getElementById("status").textContent = "Récupération des données en cours...";
const response = await fetch(apiUrl);
if (!response.ok) {
throw new Error(`HTTP ${response.status}`);
}
const data = await response.json();
const results = data.data?.values || [];
document.getElementById("status").textContent = `${results.length} établissements trouvés.`;
return results;
} catch (error) {
document.getElementById("status").textContent = `Erreur : ${error.message}`;
console.error("Erreur API :", error);
return [];
}
}
/**
* Met à jour (UpdateRecord) ou insère (AddRecord) les enregistrements.
*/
async function upsertIntoGristOptimized(etabs) {
document.getElementById("status").textContent = "Préparation des mises à jour en cours...";
const tableId = "Annuaire_ETAB_ACA_ALL";
const uajColumn = "uaj";
// 1. LECTURE : Récupération des enregistrements existants (docApi.fetchTable est fiable)
const allRecords = await grist.docApi.fetchTable(tableId, ['id', uajColumn]);
// Création de la Map de recherche rapide
const uajToIdMap = new Map();
if (allRecords[uajColumn]) {
allRecords[uajColumn].forEach((uaj, index) => {
uajToIdMap.set(uaj, allRecords.id[index]);
});
}
const actions = []; // Liste des actions à envoyer
let createdCount = 0;
let updatedCount = 0;
for (const etab of etabs) {
const recordId = uajToIdMap.get(etab.uaj);
// Construction de l'objet d'enregistrement (format clé-valeur)
const recordObject = {};
COLUMN_NAMES.forEach(col => {
const value = etab[col];
// Assurer que les valeurs manquantes sont correctement traitées
if (value !== undefined && value !== null) {
recordObject[col] = value;
} else if (["rue", "bassin", "fax", "mail"].includes(col)) {
recordObject[col] = ""; // Les champs texte optionnels doivent être des chaînes vides
} else {
recordObject[col] = null; // Autres champs (nombre/lien) sont null
}
});
if (recordId) {
// MISE À JOUR (Action Ligne par Ligne)
// Format: ['UpdateRecord', TableID, RowID, RecordObject]
actions.push(
['UpdateRecord', tableId, recordId, recordObject]
);
updatedCount++;
} else {
// CRÉATION (Action Ligne par Ligne)
// Format: ['AddRecord', TableID, RowID (null), RecordObject]
actions.push(
['AddRecord', tableId, null, recordObject]
);
createdCount++;
}
}
// 2. ENVOI DES ACTIONS
if (actions.length > 0) {
document.getElementById("status").textContent = `Envoi de ${actions.length} opérations à Grist... (peut prendre du temps)`;
// Envoi de toutes les actions (créations + mises à jour ligne par ligne)
await grist.docApi.applyUserActions(actions);
}
return { created: createdCount, updated: updatedCount };
}
/**
* Fonction principale déclenchée par le bouton.
*/
async function importEtab() {
const btn = document.getElementById("importEtabBtn");
btn.disabled = true;
btn.textContent = "Importation en cours...";
try {
const etabs = await fetchEtab();
if (etabs.length > 0) {
document.getElementById("status").textContent = "Mise à jour de la base en cours...";
const result = await upsertIntoGristOptimized(etabs);
document.getElementById("status").textContent =
`✅ **${result.created}** établissements ajoutés, **${result.updated}** établissements mis à jour.`;
} else {
document.getElementById("status").textContent = "Aucun établissement trouvé à traiter.";
}
} catch (error) {
document.getElementById("status").textContent = "❌ Une erreur critique est survenue. Vérifiez la console (F12) et l'accès.";
console.error("Erreur critique d'importation :", error);
} finally {
btn.disabled = false;
btn.textContent = "Mettre à jour l'annuaire";
}
}
document.getElementById("importEtabBtn").addEventListener("click", importEtab);
</script>
</body>
</html>