feat: mover una actividad (con sus tareas) a otro proyecto

Menu de tres puntos en el listado de Actividades -> elegir proyecto destino -> confirmar
("Se movera la actividad... (junto con sus tareas)... Aceptar/Cancelar) antes de ejecutar.

Tareas, comentarios y adjuntos se mueven solos (referencian la actividad, no el proyecto). Las
dependencias existentes se eliminan al mover -- solo tienen sentido dentro del mismo proyecto
(addDependency ya lo exigia). Nuevo PUT /api/activities/:id/move, exige permiso de escritura en
ambos proyectos (origen y destino).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Milton Gonzalez
2026-09-16 14:47:57 -05:00
parent 397fed5eb1
commit 53570bd4f8
12 changed files with 122 additions and 6 deletions
+26
View File
@@ -118,6 +118,32 @@ export async function removeActivity(id, currentUser) {
await recalcProjectProgress(activity.project_id);
}
// Mueve la actividad (y sus tareas/comentarios/adjuntos, que van solos por referenciar activity_id
// en vez de project_id) a otro proyecto. Exige permiso de escritura en AMBOS proyectos.
export async function moveActivity(id, targetProjectId, currentUser) {
const activity = await repo.findById(id);
if (!activity) throw new HttpError(404, 'Actividad no encontrada');
const sourceProject = await getProjectOr404(activity.project_id);
if (!(await canWriteActivity(currentUser, sourceProject, activity))) {
throw new HttpError(403, 'No tienes permisos sobre esta actividad');
}
if (Number(targetProjectId) === activity.project_id) {
throw new HttpError(400, 'La actividad ya pertenece a este proyecto');
}
const targetProject = await getProjectOr404(targetProjectId);
if (!(await canWriteProject(currentUser, targetProject))) {
throw new HttpError(403, 'No tienes permisos sobre el proyecto de destino');
}
const moved = await repo.moveToProject(id, targetProjectId);
await logAudit({
userId: currentUser.id, action: 'move', entityType: 'activity', entityId: id,
detail: { fromProjectId: activity.project_id, toProjectId: Number(targetProjectId) },
});
await recalcProjectProgress(activity.project_id);
await recalcProjectProgress(targetProjectId);
return moved;
}
// Nuevo orden manual (arrastrar con el mouse): mismo permiso que crear actividades en el proyecto.
export async function reorderActivities(projectId, ids, currentUser) {
const project = await getProjectOr404(projectId);