import "dotenv/config";
import { spfi } from "@pnp/sp";
import { SPDefault } from "@pnp/nodejs";
import * as fs from "fs";
import * as path from "path";
import * as XLSX from "xlsx";
import "@pnp/sp/webs";
import "@pnp/sp/lists";
import "@pnp/sp/items";
// ─── Configuration ─────────────────────────────────────────────────
const TENANT_ID = process.env.TENANT_ID!;
const CLIENT_ID = process.env.CLIENT_ID!;
const THUMBPRINT = process.env.THUMBPRINT!;
const KEY_PATH = process.env.KEY_PATH!;
const SITE_URL = process.env.SITE_URL!;
const SP_ROOT_URL = process.env.SP_ROOT_URL!;
const LIST_NAME = "NomDeLaListe"; // ← à adapter
const EXCEL_PATH = path.resolve(__dirname, "../fichier.xlsx"); // ← à adapter
// ──────────────────────────────────────────────────────────────────
async function importData(): Promise<void> {
// Lecture du fichier Excel
const workbook = XLSX.readFile(EXCEL_PATH);
const sheet = workbook.Sheets[workbook.SheetNames[0]];
const rows: Record<string, any>[] = XLSX.utils.sheet_to_json(sheet);
console.log(`${rows.length} ligne(s) trouvée(s).`);
// Connexion SharePoint
const privateKey = fs.readFileSync(KEY_PATH, "utf-8").trim();
const sp = spfi(SITE_URL).using(
SPDefault({
baseUrl: SITE_URL,
msal: {
config: {
auth: {
clientId: CLIENT_ID,
authority: `https://login.microsoftonline.com/${TENANT_ID}`,
clientCertificate: {
thumbprint: THUMBPRINT,
privateKey: privateKey
}
}
},
scopes: [`${SP_ROOT_URL}/.default`]
}
})
);
const list = sp.web.lists.getByTitle(LIST_NAME);
// Import ligne par ligne
for (const [index, row] of rows.entries()) {
try {
// Construire l'objet à envoyer — adapter les champs selon la liste
// ?? "" : envoyer une chaîne vide si la cellule est vide (colonnes texte)
// ?? null : envoyer null si la cellule est vide (colonnes date)
// Number() : convertir en nombre (colonnes numériques)
// Conversion de date JJ/MM/AAAA → AAAA-MM-JJ (format attendu par SharePoint)
// Exemple : "30/03/2026" → "2026-03-30"
const toIsoDate = (val: string | undefined): string | null => {
if (!val) return null;
const parts = val.split("/");
if (parts.length !== 3) return val; // déjà au bon format ou valeur inattendue
return `${parts[2]}-${parts[1]}-${parts[0]}`;
};
const item = {
Title: row["Title"] ?? "", // texte → chaîne vide par défaut
CodeFormation: row["CodeFormation"] ?? "", // texte → chaîne vide par défaut
DateSession: toIsoDate(row["DateSession"]), // JJ/MM/AAAA → AAAA-MM-JJ
NbConfirmes: Number(row["NbConfirmes"]) || 0, // nombre → 0 si vide ou NaN
NbOption: Number(row["NbOption"]) || 0, // nombre → 0 si vide ou NaN
// ↑ Ajouter ici tous les autres champs de la liste en suivant le même modèle
};
await list.items.add(item);
console.log(` [${index + 1}/${rows.length}] Importé : ${row["Title"] ?? row[Object.keys(row)[0]]}`);
} catch (err: any) {
console.error(` [${index + 1}] Erreur : ${err.message}`);
}
}
console.log("Import terminé.");
}
importData()
.then(() => process.exit(0))
.catch((err) => {
console.error("Erreur fatale :", err.message ?? err);
process.exit(1);
});