fix: resolver DNS nginx pour éviter cache IP stale après restart backend
This commit is contained in:
@@ -1,172 +0,0 @@
|
||||
import { db } from '../db';
|
||||
import { decrypt } from '../crypto';
|
||||
|
||||
// ─── Types ───────────────────────────────────────────────────
|
||||
|
||||
interface GraphConfig {
|
||||
tenantId: string;
|
||||
clientId: string;
|
||||
clientSecret: string;
|
||||
sharepointSiteId: string;
|
||||
sharepointItemId: string;
|
||||
sharepointSheet: string;
|
||||
}
|
||||
|
||||
export interface SharepointRowData {
|
||||
category: string;
|
||||
companyName: string;
|
||||
comment: string;
|
||||
guests: Array<{ name: string; company?: string | null }>;
|
||||
date: string; // format JJ/MM/AAAA
|
||||
amount: number;
|
||||
userName: string; // 'Greg' ou 'Gaël'
|
||||
}
|
||||
|
||||
// ─── Helpers ─────────────────────────────────────────────────
|
||||
|
||||
async function getGraphConfig(): Promise<GraphConfig> {
|
||||
const result = await db.query(
|
||||
`SELECT key, value FROM app_settings
|
||||
WHERE key IN (
|
||||
'graph_tenant_id', 'graph_client_id', 'graph_client_secret_enc',
|
||||
'sharepoint_site_id', 'sharepoint_item_id', 'sharepoint_sheet_name'
|
||||
)`
|
||||
);
|
||||
const cfg: Record<string, string> = {};
|
||||
for (const row of result.rows) cfg[row.key] = row.value;
|
||||
|
||||
if (!cfg.graph_tenant_id || !cfg.graph_client_id || !cfg.graph_client_secret_enc) {
|
||||
throw new Error('Microsoft Graph non configuré (tenant_id, client_id ou client_secret manquant)');
|
||||
}
|
||||
if (!cfg.sharepoint_site_id || !cfg.sharepoint_item_id) {
|
||||
throw new Error('Fichier Excel SharePoint non configuré (site_id ou item_id manquant dans Paramètres → Microsoft 365)');
|
||||
}
|
||||
|
||||
return {
|
||||
tenantId: cfg.graph_tenant_id,
|
||||
clientId: cfg.graph_client_id,
|
||||
clientSecret: decrypt(cfg.graph_client_secret_enc),
|
||||
sharepointSiteId: cfg.sharepoint_site_id,
|
||||
sharepointItemId: cfg.sharepoint_item_id,
|
||||
sharepointSheet: cfg.sharepoint_sheet_name ?? 'Feuil1',
|
||||
};
|
||||
}
|
||||
|
||||
async function getAccessToken(cfg: GraphConfig): Promise<string> {
|
||||
const response = await fetch(
|
||||
`https://login.microsoftonline.com/${cfg.tenantId}/oauth2/v2.0/token`,
|
||||
{
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
||||
body: new URLSearchParams({
|
||||
grant_type: 'client_credentials',
|
||||
client_id: cfg.clientId,
|
||||
client_secret: cfg.clientSecret,
|
||||
scope: 'https://graph.microsoft.com/.default',
|
||||
}),
|
||||
}
|
||||
);
|
||||
|
||||
if (!response.ok) {
|
||||
const body = await response.text();
|
||||
throw new Error(`Obtention token Graph échouée (${response.status}) : ${body}`);
|
||||
}
|
||||
|
||||
const data = (await response.json()) as { access_token: string };
|
||||
return data.access_token;
|
||||
}
|
||||
|
||||
// ─── Test de connexion (sans écriture) ───────────────────────
|
||||
|
||||
/**
|
||||
* Vérifie que le token Graph s'obtient et que la feuille Excel est accessible.
|
||||
* Utilisé par POST /api/settings/sharepoint/test.
|
||||
*/
|
||||
export async function testSharepointConnection(): Promise<void> {
|
||||
const cfg = await getGraphConfig();
|
||||
const token = await getAccessToken(cfg);
|
||||
|
||||
const baseUrl = `https://graph.microsoft.com/v1.0/sites/${cfg.sharepointSiteId}/drive/items/${cfg.sharepointItemId}/workbook/worksheets/${encodeURIComponent(cfg.sharepointSheet)}`;
|
||||
const resp = await fetch(`${baseUrl}/usedRange?$select=rowCount`, {
|
||||
headers: { Authorization: `Bearer ${token}` },
|
||||
});
|
||||
|
||||
if (!resp.ok) {
|
||||
const body = await resp.text();
|
||||
throw new Error(`Impossible d'accéder à la feuille "${cfg.sharepointSheet}" (${resp.status}) : ${body.slice(0, 200)}`);
|
||||
}
|
||||
}
|
||||
|
||||
// ─── Fonction principale ──────────────────────────────────────
|
||||
|
||||
/**
|
||||
* Ajoute une ligne dans le fichier Excel SharePoint commun selon le mapping :
|
||||
* A : Catégorie
|
||||
* B : Société facturée
|
||||
* C : Commentaire + invités
|
||||
* D : Date (JJ/MM/AAAA)
|
||||
* E : Montant si Greg
|
||||
* F : Montant si Gaël
|
||||
*/
|
||||
export async function addRowToExcel(row: SharepointRowData): Promise<void> {
|
||||
const cfg = await getGraphConfig();
|
||||
const token = await getAccessToken(cfg);
|
||||
|
||||
// Construction de la cellule C (commentaire + invités)
|
||||
let cellComment = row.comment || '';
|
||||
if (row.guests.length > 0) {
|
||||
const guestStr = row.guests
|
||||
.map((g) => (g.company ? `${g.name} — ${g.company}` : g.name))
|
||||
.join(' ; ');
|
||||
cellComment = cellComment
|
||||
? `${cellComment}. Invités : ${guestStr}`
|
||||
: `Invités : ${guestStr}`;
|
||||
}
|
||||
|
||||
// Colonnes E/F selon l'utilisateur
|
||||
const nameLower = row.userName.toLowerCase().normalize('NFD').replace(/[̀-ͯ]/g, '');
|
||||
const isGreg = nameLower === 'greg';
|
||||
const isGael = nameLower === 'gael';
|
||||
|
||||
const values = [[
|
||||
row.category, // A
|
||||
row.companyName, // B
|
||||
cellComment, // C
|
||||
row.date, // D
|
||||
isGreg ? row.amount : null, // E — Greg
|
||||
isGael ? row.amount : null, // F — Gaël
|
||||
]];
|
||||
|
||||
// ── Trouver la première ligne vide ───────────────────────────
|
||||
const baseUrl = `https://graph.microsoft.com/v1.0/sites/${cfg.sharepointSiteId}/drive/items/${cfg.sharepointItemId}/workbook/worksheets/${encodeURIComponent(cfg.sharepointSheet)}`;
|
||||
|
||||
const rangeResp = await fetch(`${baseUrl}/usedRange`, {
|
||||
headers: { Authorization: `Bearer ${token}` },
|
||||
});
|
||||
|
||||
if (!rangeResp.ok) {
|
||||
const body = await rangeResp.text();
|
||||
throw new Error(`Graph usedRange échoué (${rangeResp.status}) : ${body}`);
|
||||
}
|
||||
|
||||
const rangeData = (await rangeResp.json()) as { rowCount: number };
|
||||
const nextRow = rangeData.rowCount + 1;
|
||||
|
||||
// ── Écriture de la nouvelle ligne ────────────────────────────
|
||||
const writeResp = await fetch(
|
||||
`${baseUrl}/range(address='A${nextRow}:F${nextRow}')`,
|
||||
{
|
||||
method: 'PATCH',
|
||||
headers: {
|
||||
Authorization: `Bearer ${token}`,
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({ values }),
|
||||
}
|
||||
);
|
||||
|
||||
if (!writeResp.ok) {
|
||||
const body = await writeResp.text();
|
||||
throw new Error(`Graph écriture ligne échouée (${writeResp.status}) : ${body}`);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user