import fs from 'fs'; import path from 'path'; /** * Check if the current user has write access to a table. * Reads .acai file from ACAI_PROJECT_DIR. * Returns { allowed: true } or { allowed: false, error: "..." } * * NOTA: Esta funcion NO depende del campo `mode`. En modo produccion los * registros de tablas (contenido CMS) se siguen pudiendo editar — son los * datos reales del usuario, no codigo. El bloqueo de produccion solo aplica * a escritura de archivos de codigo (gestionado por is_project_admin en el * server Python al recibir POST /api/files/*). * * Si existe ACAI_MODE_OVERRIDE en el entorno (cronjob con override), se usa * en lugar del .acai para determinar el modo. */ export function canAccessTable(tableName) { const projectDir = process.env.ACAI_PROJECT_DIR || ""; if (!projectDir) return { allowed: true }; // no project dir, don't block const acaiFile = path.join(projectDir, ".acai"); try { if (!fs.existsSync(acaiFile)) return { allowed: true }; const data = JSON.parse(fs.readFileSync(acaiFile, "utf-8")); // Override de modo (cronjobs lo inyectan via env var) if (process.env.ACAI_MODE_OVERRIDE) { data.mode = process.env.ACAI_MODE_OVERRIDE; } const user = data.user || {}; // Admin has full access if (user.isAdmin === "1" || user.isAdmin === 1) return { allowed: true }; const accessList = user.accessList || {}; if (!accessList || Object.keys(accessList).length === 0) return { allowed: true }; // all.accessLevel >= 9 means full access const allAccess = parseInt(accessList.all?.accessLevel || "0"); if (allAccess >= 9) return { allowed: true }; // Check specific table (without cms_ prefix) const bare = tableName.replace(/^cms_/, ""); const entry = accessList[bare]; if (entry && parseInt(entry.accessLevel || "0") > 0) return { allowed: true }; return { allowed: false, error: `No tienes acceso a la tabla '${bare}'` }; } catch (e) { return { allowed: true }; // On error, don't block } }