e65111a7f4
Permisos (superadmin, viewer, busqueda, tareas recurrentes), bootstrap atomico, revocacion de JWT por version de sesion (028), control optimista de edicion (029), logo sin SVG + CSP, ingesta endurecida, correos escapados, borradores, paginacion de proyectos, accesibilidad de dialogos/controles e i18n. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
68 lines
2.7 KiB
JavaScript
68 lines
2.7 KiB
JavaScript
import { pool } from '../../config/db.js';
|
|
|
|
const RESULT_LIMIT = 20;
|
|
|
|
// Busqueda global (menu Proyectos): proyectos, actividades (con su proyecto) y tareas (con su
|
|
// actividad y proyecto) — para armar la migaja de pan "Proyecto - Actividad - Tarea" en el cliente.
|
|
export async function searchGlobal(term, user) {
|
|
const like = `%${term}%`;
|
|
const fullAccess = ['superadmin', 'admin', 'it_manager'].includes(user.roleCode);
|
|
const scope = fullAccess ? '' : ' AND EXISTS (SELECT 1 FROM project_members pm WHERE pm.project_id = p.id AND pm.user_id = ?)';
|
|
const scopeParams = fullAccess ? [] : [user.id];
|
|
|
|
const [projects] = await pool.query(
|
|
`SELECT p.id, p.code, p.name FROM projects p
|
|
WHERE p.deleted_at IS NULL AND (p.code LIKE ? OR p.name LIKE ?)${scope}
|
|
ORDER BY name LIMIT ?`,
|
|
[like, like, ...scopeParams, RESULT_LIMIT]
|
|
);
|
|
|
|
const [activities] = await pool.query(
|
|
`SELECT a.id, a.code, a.name,
|
|
p.id AS project_id, p.code AS project_code, p.name AS project_name
|
|
FROM activities a
|
|
JOIN projects p ON p.id = a.project_id
|
|
WHERE p.deleted_at IS NULL AND a.deleted_at IS NULL AND (a.code LIKE ? OR a.name LIKE ?)${scope}
|
|
ORDER BY a.name LIMIT ?`,
|
|
[like, like, ...scopeParams, RESULT_LIMIT]
|
|
);
|
|
|
|
const [tasks] = await pool.query(
|
|
`SELECT t.id, t.name,
|
|
a.id AS activity_id, a.code AS activity_code, a.name AS activity_name,
|
|
p.id AS project_id, p.code AS project_code, p.name AS project_name
|
|
FROM tasks t
|
|
JOIN activities a ON a.id = t.activity_id
|
|
JOIN projects p ON p.id = a.project_id
|
|
WHERE p.deleted_at IS NULL AND a.deleted_at IS NULL AND t.deleted_at IS NULL AND t.name LIKE ?${scope}
|
|
ORDER BY t.name LIMIT ?`,
|
|
[like, ...scopeParams, RESULT_LIMIT]
|
|
);
|
|
|
|
return { projects, activities, tasks };
|
|
}
|
|
|
|
// Busqueda dentro de un proyecto (pestaña Actividades): solo actividades y tareas de ESE
|
|
// proyecto — la migaja de pan ahi es "Actividad - Tarea" (el proyecto ya es el contexto visible).
|
|
export async function searchInProject(projectId, term) {
|
|
const like = `%${term}%`;
|
|
|
|
const [activities] = await pool.query(
|
|
`SELECT id, code, name FROM activities
|
|
WHERE project_id = ? AND deleted_at IS NULL AND (code LIKE ? OR name LIKE ?)
|
|
ORDER BY name LIMIT ?`,
|
|
[projectId, like, like, RESULT_LIMIT]
|
|
);
|
|
|
|
const [tasks] = await pool.query(
|
|
`SELECT t.id, t.name, a.id AS activity_id, a.code AS activity_code, a.name AS activity_name
|
|
FROM tasks t
|
|
JOIN activities a ON a.id = t.activity_id
|
|
WHERE a.project_id = ? AND a.deleted_at IS NULL AND t.deleted_at IS NULL AND t.name LIKE ?
|
|
ORDER BY t.name LIMIT ?`,
|
|
[projectId, like, RESULT_LIMIT]
|
|
);
|
|
|
|
return { activities, tasks };
|
|
}
|