ki integration
This commit is contained in:
119
scripts/test-mandanten.mjs
Normal file
119
scripts/test-mandanten.mjs
Normal file
@@ -0,0 +1,119 @@
|
||||
/**
|
||||
* E2-Abnahme: Mandantentrennung – geprüft über die API, nicht über das UI.
|
||||
*
|
||||
* Legt zwei echte Konten an und baut für beide Team + brands-Zeile genau so wie
|
||||
* client/src/lib/auth.ts. Danach: sieht Konto B irgendetwas von Konto A?
|
||||
*
|
||||
* Kein SDK, nur fetch mit eigenem Cookie-Speicher – so verhält sich der Aufruf
|
||||
* wie ein Browser, und der Test hängt nicht an SDK-Eigenheiten.
|
||||
*/
|
||||
const ENDPOINT = 'https://appwrite.webklar.com/v1';
|
||||
const PROJECT = '6a5cee34002bb8360c34';
|
||||
const DB = 'brandloop';
|
||||
const KEY = process.env.APPWRITE_API_KEY;
|
||||
if (!KEY) { console.error('APPWRITE_API_KEY fehlt'); process.exit(1); }
|
||||
|
||||
const stamp = Date.now();
|
||||
let fehler = 0;
|
||||
const ok = (m) => console.log(` ok ${m}`);
|
||||
const bad = (m) => { fehler++; console.log(` FEHL ${m}`); };
|
||||
const limit = encodeURIComponent(JSON.stringify({ method: 'limit', values: [100] }));
|
||||
|
||||
/** Ein Konto = ein Cookie-Speicher, so wie ein Browser-Profil. */
|
||||
function neueSitzung() {
|
||||
const jar = new Map();
|
||||
return async function call(method, path, body) {
|
||||
const headers = { 'X-Appwrite-Project': PROJECT, 'Content-Type': 'application/json' };
|
||||
if (jar.size) headers.Cookie = [...jar].map(([k, v]) => `${k}=${v}`).join('; ');
|
||||
const res = await fetch(`${ENDPOINT}${path}`, {
|
||||
method, headers, body: body ? JSON.stringify(body) : undefined, redirect: 'manual',
|
||||
});
|
||||
for (const c of res.headers.getSetCookie?.() ?? []) {
|
||||
const [pair] = c.split(';');
|
||||
const i = pair.indexOf('=');
|
||||
if (i > 0) jar.set(pair.slice(0, i).trim(), pair.slice(i + 1).trim());
|
||||
}
|
||||
const text = await res.text();
|
||||
let json; try { json = JSON.parse(text); } catch { json = { message: text }; }
|
||||
return { status: res.status, json };
|
||||
};
|
||||
}
|
||||
|
||||
const admin = async (method, path, body) => {
|
||||
const res = await fetch(`${ENDPOINT}${path}`, {
|
||||
method,
|
||||
headers: { 'X-Appwrite-Project': PROJECT, 'X-Appwrite-Key': KEY, 'Content-Type': 'application/json' },
|
||||
body: body ? JSON.stringify(body) : undefined,
|
||||
});
|
||||
const text = await res.text();
|
||||
let json; try { json = JSON.parse(text); } catch { json = { message: text }; }
|
||||
return { status: res.status, json };
|
||||
};
|
||||
|
||||
function muss(r, was) {
|
||||
if (r.status >= 200 && r.status < 300) return r.json;
|
||||
throw new Error(`${was}: HTTP ${r.status} – ${r.json?.message}`);
|
||||
}
|
||||
|
||||
/** Spiegelt client/src/lib/auth.ts: Konto → Session → Team → brands-Zeile. */
|
||||
async function kontoAnlegen(kennung) {
|
||||
const call = neueSitzung();
|
||||
const email = `e2-${kennung}-${stamp}@brandloop.test`;
|
||||
const password = `Test-${stamp}-${kennung}!`;
|
||||
const label = `Marke ${kennung.toUpperCase()}`;
|
||||
|
||||
const user = muss(await call('POST', '/account', { userId: 'unique()', email, password, name: label }), 'account');
|
||||
muss(await call('POST', '/account/sessions/email', { email, password }), 'session');
|
||||
|
||||
const team = muss(await call('POST', '/teams', { teamId: 'unique()', name: label }), 'team');
|
||||
const rolle = `team:${team.$id}`;
|
||||
const brand = muss(await call('POST', `/tablesdb/${DB}/tables/brands/rows`, {
|
||||
rowId: 'unique()',
|
||||
data: { team_id: team.$id, label_name: label, status: 'trial', plan: 'trial' },
|
||||
permissions: [`read("${rolle}")`, `update("${rolle}")`, `delete("${rolle}")`],
|
||||
}), 'brands-Zeile');
|
||||
|
||||
return { call, userId: user.$id, teamId: team.$id, brandId: brand.$id, label };
|
||||
}
|
||||
|
||||
console.log('Konten anlegen (wie der Client es tut):');
|
||||
const A = await kontoAnlegen('a');
|
||||
console.log(` A: user=${A.userId} team=${A.teamId} brand=${A.brandId}`);
|
||||
const B = await kontoAnlegen('b');
|
||||
console.log(` B: user=${B.userId} team=${B.teamId} brand=${B.brandId}`);
|
||||
|
||||
console.log('\nMandantentrennung:');
|
||||
|
||||
const liste = await B.call('GET', `/tablesdb/${DB}/tables/brands/rows?queries[]=${limit}`);
|
||||
const ids = (liste.json.rows ?? []).map((r) => r.$id);
|
||||
if (ids.includes(A.brandId)) bad(`B sieht A's Zeile in der Liste`);
|
||||
else ok(`B listet ${ids.length} brands-Zeile(n), A's ist nicht dabei`);
|
||||
if (!ids.includes(B.brandId)) bad('B sieht die EIGENE Zeile nicht – Rechte zu streng');
|
||||
else ok('B sieht die eigene Zeile');
|
||||
|
||||
const direkt = await B.call('GET', `/tablesdb/${DB}/tables/brands/rows/${A.brandId}`);
|
||||
if (direkt.status < 300) bad(`B konnte A's Zeile direkt lesen (HTTP ${direkt.status})`);
|
||||
else ok(`Direktzugriff B→A abgewiesen (HTTP ${direkt.status} ${direkt.json?.type ?? ''})`);
|
||||
|
||||
const schreib = await B.call('PATCH', `/tablesdb/${DB}/tables/brands/rows/${A.brandId}`, { data: { label_name: 'gekapert' } });
|
||||
if (schreib.status < 300) bad(`B konnte A's Zeile ÄNDERN (HTTP ${schreib.status})`);
|
||||
else ok(`Schreibzugriff B→A abgewiesen (HTTP ${schreib.status} ${schreib.json?.type ?? ''})`);
|
||||
|
||||
// Gegenprobe: sieht der Server-Key beide? Sonst wäre der erste Test wertlos,
|
||||
// weil dann vielleicht schlicht nichts in der Tabelle steht.
|
||||
const alle = await admin('GET', `/tablesdb/${DB}/tables/brands/rows?queries[]=${limit}`);
|
||||
const alleIds = (alle.json.rows ?? []).map((r) => r.$id);
|
||||
if (alleIds.includes(A.brandId) && alleIds.includes(B.brandId)) ok(`Server-Key sieht beide Zeilen (${alle.json.total} gesamt) – der erste Test ist damit aussagekräftig`);
|
||||
else bad(`Server-Key sieht nicht beide: ${JSON.stringify(alleIds)}`);
|
||||
|
||||
console.log('\nAufräumen:');
|
||||
for (const k of [A, B]) {
|
||||
await admin('DELETE', `/tablesdb/${DB}/tables/brands/rows/${k.brandId}`);
|
||||
await admin('DELETE', `/teams/${k.teamId}`);
|
||||
await admin('DELETE', `/users/${k.userId}`);
|
||||
}
|
||||
const rest = await admin('GET', `/tablesdb/${DB}/tables/brands/rows?queries[]=${limit}`);
|
||||
console.log(` Testkonten entfernt, brands enthält jetzt ${rest.json.total} Zeile(n).`);
|
||||
|
||||
console.log(fehler ? `\n${fehler} FEHLER – Mandantentrennung nicht dicht.` : '\nMandantentrennung hält.');
|
||||
process.exit(fehler ? 1 : 0);
|
||||
Reference in New Issue
Block a user