feat: rediseño de TaskItem, añade completar y lista 24h
Co-authored-by: aider (openrouter/openai/gpt-5) <aider@aider.chat>webui
parent
2446427b5f
commit
06c4a0619d
@ -0,0 +1,102 @@
|
|||||||
|
import type { RequestHandler } from './$types';
|
||||||
|
import { getDb } from '$lib/server/db';
|
||||||
|
|
||||||
|
export const POST: RequestHandler = async (event) => {
|
||||||
|
const userId = event.locals.userId ?? null;
|
||||||
|
if (!userId) {
|
||||||
|
return new Response('Unauthorized', { status: 401 });
|
||||||
|
}
|
||||||
|
|
||||||
|
const idStr = event.params.id || '';
|
||||||
|
const taskId = parseInt(idStr, 10);
|
||||||
|
if (!Number.isFinite(taskId) || taskId <= 0) {
|
||||||
|
return new Response('Bad Request', { status: 400 });
|
||||||
|
}
|
||||||
|
|
||||||
|
const db = await getDb();
|
||||||
|
|
||||||
|
const task = db.prepare(`
|
||||||
|
SELECT id, description, due_date, group_id, COALESCE(completed, 0) AS completed, completed_at, display_code
|
||||||
|
FROM tasks
|
||||||
|
WHERE id = ?
|
||||||
|
`).get(taskId) as any;
|
||||||
|
|
||||||
|
if (!task) {
|
||||||
|
return new Response(JSON.stringify({ status: 'not_found' }), {
|
||||||
|
status: 404,
|
||||||
|
headers: { 'content-type': 'application/json; charset=utf-8', 'cache-control': 'no-store' }
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Gating:
|
||||||
|
// - Si tiene group_id: grupo allowed y miembro activo
|
||||||
|
// - Si NO tiene group_id: debe estar asignada al usuario
|
||||||
|
const groupId: string | null = task.group_id ? String(task.group_id) : null;
|
||||||
|
if (groupId) {
|
||||||
|
const allowed = db
|
||||||
|
.prepare(`SELECT 1 FROM allowed_groups WHERE group_id = ? AND status = 'allowed' LIMIT 1`)
|
||||||
|
.get(groupId);
|
||||||
|
const active = db
|
||||||
|
.prepare(`SELECT 1 FROM group_members WHERE group_id = ? AND user_id = ? AND is_active = 1 LIMIT 1`)
|
||||||
|
.get(groupId, userId);
|
||||||
|
if (!allowed || !active) {
|
||||||
|
return new Response('Forbidden', { status: 403 });
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const isAssigned = db
|
||||||
|
.prepare(`SELECT 1 FROM task_assignments WHERE task_id = ? AND user_id = ? LIMIT 1`)
|
||||||
|
.get(taskId, userId);
|
||||||
|
if (!isAssigned) {
|
||||||
|
return new Response('Forbidden', { status: 403 });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Number(task.completed) !== 0 || task.completed_at) {
|
||||||
|
const body = {
|
||||||
|
status: 'already',
|
||||||
|
task: {
|
||||||
|
id: Number(task.id),
|
||||||
|
description: String(task.description || ''),
|
||||||
|
due_date: task.due_date ? String(task.due_date) : null,
|
||||||
|
display_code: task.display_code != null ? Number(task.display_code) : null,
|
||||||
|
completed: 1,
|
||||||
|
completed_at: task.completed_at ? String(task.completed_at) : null
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return new Response(JSON.stringify(body), {
|
||||||
|
status: 200,
|
||||||
|
headers: { 'content-type': 'application/json; charset=utf-8', 'cache-control': 'no-store' }
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
db.prepare(`
|
||||||
|
UPDATE tasks
|
||||||
|
SET completed = 1,
|
||||||
|
completed_at = strftime('%Y-%m-%d %H:%M:%f', 'now'),
|
||||||
|
completed_by = ?
|
||||||
|
WHERE id = ?
|
||||||
|
`).run(userId, taskId);
|
||||||
|
|
||||||
|
const updated = db.prepare(`
|
||||||
|
SELECT id, description, due_date, display_code, COALESCE(completed, 0) AS completed, completed_at
|
||||||
|
FROM tasks
|
||||||
|
WHERE id = ?
|
||||||
|
`).get(taskId) as any;
|
||||||
|
|
||||||
|
const body = {
|
||||||
|
status: 'updated',
|
||||||
|
task: {
|
||||||
|
id: Number(updated.id),
|
||||||
|
description: String(updated.description || ''),
|
||||||
|
due_date: updated.due_date ? String(updated.due_date) : null,
|
||||||
|
display_code: updated.display_code != null ? Number(updated.display_code) : null,
|
||||||
|
completed: Number(updated.completed || 0),
|
||||||
|
completed_at: updated.completed_at ? String(updated.completed_at) : null
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return new Response(JSON.stringify(body), {
|
||||||
|
status: 200,
|
||||||
|
headers: { 'content-type': 'application/json; charset=utf-8', 'cache-control': 'no-store' }
|
||||||
|
});
|
||||||
|
};
|
||||||
Loading…
Reference in New Issue