diff --git a/apps/web/src/lib/ui/data/TaskItem.svelte b/apps/web/src/lib/ui/data/TaskItem.svelte index 1231c42..4a09402 100644 --- a/apps/web/src/lib/ui/data/TaskItem.svelte +++ b/apps/web/src/lib/ui/data/TaskItem.svelte @@ -79,9 +79,10 @@ if (busy || completed) return; busy = true; try { + const hadNoAssignees = assigneesCount === 0; const res = await fetch(`/api/tasks/${id}/complete`, { method: "POST" }); if (res.ok) { - success("Tarea completada"); + success(hadNoAssignees ? "Te has asignado y completado la tarea" : "Tarea completada"); location.reload(); } else { const txt = await res.text(); diff --git a/apps/web/src/routes/api/tasks/[id]/complete/+server.ts b/apps/web/src/routes/api/tasks/[id]/complete/+server.ts index 9947d8e..ead73aa 100644 --- a/apps/web/src/routes/api/tasks/[id]/complete/+server.ts +++ b/apps/web/src/routes/api/tasks/[id]/complete/+server.ts @@ -69,13 +69,29 @@ export const POST: RequestHandler = async (event) => { }); } - db.prepare(` - UPDATE tasks - SET completed = 1, - completed_at = strftime('%Y-%m-%d %H:%M:%f', 'now'), - completed_by = ? - WHERE id = ? - `).run(userId, taskId); + // Transacción: auto-asignar si no hay responsables y completar + const tx = db.transaction(() => { + const cntRow = db + .prepare(`SELECT COUNT(*) AS cnt FROM task_assignments WHERE task_id = ?`) + .get(taskId) as any; + const cnt = Number(cntRow?.cnt || 0); + if (cnt === 0) { + db.prepare(` + INSERT OR IGNORE INTO task_assignments (task_id, user_id, assigned_by) + VALUES (?, ?, ?) + `).run(taskId, userId, userId); + } + db.prepare(` + UPDATE tasks + SET completed = 1, + completed_at = strftime('%Y-%m-%d %H:%M:%f', 'now'), + completed_by = ? + WHERE id = ? + AND COALESCE(completed, 0) = 0 + AND completed_at IS NULL + `).run(userId, taskId); + }); + tx(); const updated = db.prepare(` SELECT id, description, due_date, display_code, COALESCE(completed, 0) AS completed, completed_at @@ -83,8 +99,10 @@ export const POST: RequestHandler = async (event) => { WHERE id = ? `).get(taskId) as any; + const statusStr = Number(updated.completed || 0) === 1 ? 'updated' : 'already'; + const body = { - status: 'updated', + status: statusStr, task: { id: Number(updated.id), description: String(updated.description || ''), diff --git a/docs/operations.md b/docs/operations.md index 5b33b93..4d1ad6e 100644 --- a/docs/operations.md +++ b/docs/operations.md @@ -52,7 +52,7 @@ Endpoints operativos - POST /api/tasks/:id/unassign - Elimina la asignación del usuario actual (idempotente) si existe. Requiere sesión; tarea abierta y gating equivalente. - POST /api/tasks/:id/complete - - Marca como completada (idempotente). Gating: si tiene group_id, cualquier miembro activo del grupo de un grupo allowed; si no tiene group_id, solo un asignado. Devuelve la tarea con completed y completed_at. + - Marca como completada (idempotente). Si es de grupo y no tiene responsables, auto-asigna al usuario que completa antes de marcarla como completada. Gating: si tiene group_id, cualquier miembro activo del grupo de un grupo allowed; si no tiene group_id, solo un asignado. Devuelve la tarea con completed y completed_at. - PATCH /api/tasks/:id - Actualiza { due_date: 'YYYY-MM-DD' | null, description?: string }. Valida due_date y normaliza/sanea description (texto plano, 1–1000 chars, colapsa espacios). Requiere sesión, tarea abierta y gating.