132 lines
5.2 KiB
JavaScript
132 lines
5.2 KiB
JavaScript
import dotenv from 'dotenv';
|
||
import { fileURLToPath } from 'url';
|
||
import { dirname, resolve } from 'path';
|
||
|
||
const __dirname = dirname(fileURLToPath(import.meta.url));
|
||
dotenv.config({ path: resolve(__dirname, '..', '.env') });
|
||
|
||
import express from 'express';
|
||
import cors from 'cors';
|
||
import { Client, Users, Teams, Databases, ID, Query } from 'node-appwrite';
|
||
|
||
const ENDPOINT = process.env.APPWRITE_ENDPOINT;
|
||
const PROJECT_ID = process.env.VITE_APPWRITE_PROJECT_ID;
|
||
const API_KEY = process.env.APPWRITE_API_KEY;
|
||
const DATABASE_ID = process.env.VITE_APPWRITE_DATABASE_ID || 'defekttrack_db';
|
||
const ADMIN_SECRET = process.env.ADMIN_SECRET;
|
||
|
||
const TEAM_ROLES = ['admin', 'firmenleiter', 'filialleiter', 'service', 'lager'];
|
||
|
||
// #region agent log
|
||
function debugLog(location, message, data, hypothesisId) {
|
||
const payload = { sessionId: '405dbc', location, message, data: data || {}, timestamp: Date.now(), hypothesisId };
|
||
fetch('http://127.0.0.1:7886/ingest/990166f5-529c-4789-bcc2-9ebbe976f059', { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-Debug-Session-Id': '405dbc' }, body: JSON.stringify(payload) }).catch(() => {});
|
||
}
|
||
// #endregion
|
||
|
||
const app = express();
|
||
app.use(cors({ origin: true, credentials: true }));
|
||
app.use(express.json());
|
||
|
||
function requireAdminSecret(req, res, next) {
|
||
const secret = req.headers['x-admin-secret'];
|
||
if (!ADMIN_SECRET || secret !== ADMIN_SECRET) {
|
||
// #region agent log
|
||
debugLog('server/index.js:middleware', '403 admin secret mismatch', { hasServerSecret: !!ADMIN_SECRET, hasHeader: !!secret, headerLength: typeof secret === 'string' ? secret.length : 0 }, 'C');
|
||
// #endregion
|
||
return res.status(403).json({ error: 'Forbidden – ADMIN_SECRET und VITE_ADMIN_SECRET in .env müssen identisch sein. Beide Dev-Server (Vite + npm run dev:api) nach .env-Änderung neu starten.' });
|
||
}
|
||
next();
|
||
}
|
||
|
||
app.post('/api/admin/create-user', requireAdminSecret, async (req, res) => {
|
||
// #region agent log
|
||
debugLog('server/index.js:route', 'create-user route hit', { bodyKeys: Object.keys(req.body || {}) }, 'A');
|
||
// #endregion
|
||
try {
|
||
const { email, password, name, locationId, role, mustChangePassword } = req.body || {};
|
||
if (!email || !password || !name || !locationId || !role) {
|
||
return res.status(400).json({
|
||
error: 'Fehlende Felder',
|
||
required: ['email', 'password', 'name', 'locationId', 'role'],
|
||
});
|
||
}
|
||
if (!TEAM_ROLES.includes(role)) {
|
||
return res.status(400).json({
|
||
error: 'Ungültige Rolle',
|
||
allowed: TEAM_ROLES,
|
||
});
|
||
}
|
||
if (!ENDPOINT || !PROJECT_ID || !API_KEY) {
|
||
// #region agent log
|
||
debugLog('server/index.js:env', 'env missing', { hasEndpoint: !!ENDPOINT, hasProjectId: !!PROJECT_ID, hasApiKey: !!API_KEY }, 'B');
|
||
// #endregion
|
||
return res.status(500).json({ error: 'Server-Konfiguration unvollständig (APPWRITE_ENDPOINT, VITE_APPWRITE_PROJECT_ID, APPWRITE_API_KEY in .env prüfen)' });
|
||
}
|
||
// #region agent log
|
||
debugLog('server/index.js:env', 'env check passed', { hasEndpoint: true, hasProjectId: true, hasApiKey: true }, 'B');
|
||
// #endregion
|
||
|
||
const client = new Client().setEndpoint(ENDPOINT).setProject(PROJECT_ID).setKey(API_KEY);
|
||
const users = new Users(client);
|
||
const teams = new Teams(client);
|
||
const databases = new Databases(client);
|
||
|
||
let userId;
|
||
// #region agent log
|
||
debugLog('server/index.js:users', 'before users.create', { email: !!email, role }, 'D');
|
||
// #endregion
|
||
try {
|
||
const user = await users.create(ID.unique(), email, undefined, password, name);
|
||
userId = user.$id;
|
||
} catch (err) {
|
||
// #region agent log
|
||
debugLog('server/index.js:users', 'users.create failed', { code: err.code, message: err.message }, 'D');
|
||
// #endregion
|
||
if (err.code === 409) {
|
||
const list = await users.list([Query.equal('email', [email])]);
|
||
if (list.users.length > 0) userId = list.users[0].$id;
|
||
}
|
||
if (!userId) {
|
||
return res.status(400).json({ error: err.message || 'User anlegen fehlgeschlagen' });
|
||
}
|
||
}
|
||
|
||
try {
|
||
await teams.createMembership(role, [], email, userId, undefined, `${ENDPOINT}/auth/confirm`);
|
||
} catch (err) {
|
||
if (err.code !== 409) {
|
||
console.warn('Team-Membership:', err.message);
|
||
}
|
||
}
|
||
|
||
try {
|
||
await databases.createDocument(DATABASE_ID, 'users_meta', ID.unique(), {
|
||
userId,
|
||
locationId: locationId || '',
|
||
userName: name,
|
||
role,
|
||
mustChangePassword: mustChangePassword !== false,
|
||
});
|
||
} catch (err) {
|
||
if (err.code !== 409) {
|
||
console.warn('users_meta:', err.message);
|
||
}
|
||
}
|
||
|
||
return res.status(201).json({ userId, email, name, role, locationId });
|
||
} catch (err) {
|
||
// #region agent log
|
||
debugLog('server/index.js:outer', 'outer catch 500', { message: err.message, code: err?.code, name: err?.name }, 'E');
|
||
// #endregion
|
||
console.error('create-user error:', err);
|
||
const message = err.message || err.toString?.() || 'Interner Serverfehler';
|
||
return res.status(500).json({ error: message });
|
||
}
|
||
});
|
||
|
||
const PORT = process.env.API_PORT || 3001;
|
||
app.listen(PORT, () => {
|
||
console.log(`API server http://localhost:${PORT}`);
|
||
});
|