import { db } from '../../config/database.js'; import { companyUsers, projectUsers, todoUsers } from '../../db/schema.js'; import { eq, and } from 'drizzle-orm'; /** * Univerzálny middleware pre kontrolu prístupu k resources * Admin má prístup vždy, member len ak je priradený k resource * * Použitie: * checkResourceAccess('company', 'companyId') // pre /companies/:companyId * checkResourceAccess('project', 'projectId') // pre /projects/:projectId * checkResourceAccess('todo', 'todoId') // pre /todos/:todoId */ // Mapovanie resource typu na junction tabuľku a stĺpce const resourceConfig = { company: { table: companyUsers, resourceIdColumn: 'companyId', }, project: { table: projectUsers, resourceIdColumn: 'projectId', }, todo: { table: todoUsers, resourceIdColumn: 'todoId', }, }; /** * Skontroluje či user má prístup k danému resource * @param {string} resourceType - Typ resource ('company', 'project', atď.) * @param {string} userId - ID používateľa * @param {string} resourceId - ID resource * @returns {Promise} */ export const hasAccessToResource = async (resourceType, userId, resourceId) => { const config = resourceConfig[resourceType]; if (!config) { throw new Error(`Unknown resource type: ${resourceType}`); } const { table, resourceIdColumn } = config; const [assignment] = await db .select() .from(table) .where(and( eq(table[resourceIdColumn], resourceId), eq(table.userId, userId) )) .limit(1); return !!assignment; }; /** * Middleware factory pre kontrolu prístupu k resource * @param {string} resourceType - Typ resource ('company', 'project') * @param {string} paramName - Názov parametra v URL (napr. 'companyId', 'projectId') */ export const checkResourceAccess = (resourceType, paramName) => { return async (req, res, next) => { // Skontroluj či je user autentifikovaný if (!req.user) { return res.status(401).json({ success: false, error: { message: 'Musíte byť prihlásený', statusCode: 401, }, }); } // Admin má prístup vždy if (req.user.role === 'admin') { return next(); } const resourceId = req.params[paramName]; if (!resourceId) { return res.status(400).json({ success: false, error: { message: `Chýba parameter ${paramName}`, statusCode: 400, }, }); } try { const hasAccess = await hasAccessToResource(resourceType, req.user.id, resourceId); if (!hasAccess) { return res.status(403).json({ success: false, error: { message: 'Nemáte prístup k tomuto zdroju', statusCode: 403, }, }); } next(); } catch (error) { console.error('Resource access check error:', error); return res.status(500).json({ success: false, error: { message: 'Chyba pri overovaní prístupu', statusCode: 500, }, }); } }; }; /** * Helper funkcie pre bežné prípady */ export const checkCompanyAccess = checkResourceAccess('company', 'companyId'); export const checkProjectAccess = checkResourceAccess('project', 'projectId'); export const checkTodoAccess = checkResourceAccess('todo', 'todoId'); /** * Získa zoznam resource IDs ku ktorým má user prístup * Užitočné pre filtrovanie v service vrstvách * @param {string} resourceType - Typ resource ('company', 'project') * @param {string} userId - ID používateľa * @returns {Promise} - Zoznam resource IDs */ export const getAccessibleResourceIds = async (resourceType, userId) => { const config = resourceConfig[resourceType]; if (!config) { throw new Error(`Unknown resource type: ${resourceType}`); } const { table, resourceIdColumn } = config; const assignments = await db .select({ resourceId: table[resourceIdColumn] }) .from(table) .where(eq(table.userId, userId)); return assignments.map(a => a.resourceId); }; /** * Skontroluje prístup a vráti boolean (pre použitie v services) * @param {string} resourceType * @param {string} userId * @param {string} resourceId * @param {string} userRole * @returns {Promise} */ export const canAccessResource = async (resourceType, userId, resourceId, userRole) => { if (userRole === 'admin') return true; return hasAccessToResource(resourceType, userId, resourceId); };