Spaces:
Paused
Paused
Download apps/api/src/modules/tasks.js from nenbuj/we-superapp: direct link, hf CLI and curl.
- Browser
- Download file 4.02 kB
-
https://huggingface.co/spaces/nenbuj/we-superapp/resolve/main/apps/api/src/modules/tasks.js
- Command line
-
hf download hf://spaces/nenbuj/we-superapp/apps/api/src/modules/tasks.js
-
curl -L -o tasks.js https://huggingface.co/spaces/nenbuj/we-superapp/resolve/main/apps/api/src/modules/tasks.js
4.02 kB
| import crypto from 'node:crypto'; | |
| import { db } from '../core/db.js'; | |
| import { bus } from '../core/bus.js'; | |
| import { requireMember } from '../core/guards.js'; | |
| function sendError(reply, status, code, message) { | |
| return reply.code(status).send({ error: { code, message } }); | |
| } | |
| function hasField(obj, key) { | |
| return Object.prototype.hasOwnProperty.call(obj, key); | |
| } | |
| function isMember(spaceId, userId) { | |
| if (userId === null || userId === undefined) return true; | |
| return Boolean( | |
| db | |
| .prepare('SELECT id FROM space_members WHERE space_id = ? AND user_id = ?') | |
| .get(spaceId, userId) | |
| ); | |
| } | |
| function validateNullableTimestamp(value, name) { | |
| if (value === null || value === undefined) return null; | |
| if (!Number.isInteger(value)) return `${name} должен быть unix ms или null`; | |
| return null; | |
| } | |
| export default async function tasksRoutes(fastify) { | |
| fastify.get('/spaces/:id/tasks', async (request) => { | |
| await requireMember(request, request.params.id); | |
| const tasks = db | |
| .prepare('SELECT * FROM tasks WHERE space_id = ? ORDER BY created_at DESC') | |
| .all(request.params.id); | |
| return { tasks }; | |
| }); | |
| fastify.post('/spaces/:id/tasks', async (request, reply) => { | |
| await requireMember(request, request.params.id); | |
| const spaceId = request.params.id; | |
| const { title, assignee_id = null, due_at = null } = request.body || {}; | |
| if (!title || typeof title !== 'string') { | |
| return sendError(reply, 400, 'VALIDATION', 'title обязателен'); | |
| } | |
| if (!isMember(spaceId, assignee_id)) { | |
| return sendError(reply, 400, 'VALIDATION', 'assignee_id должен быть участником пространства или null'); | |
| } | |
| const dueError = validateNullableTimestamp(due_at, 'due_at'); | |
| if (dueError) { | |
| return sendError(reply, 400, 'VALIDATION', dueError); | |
| } | |
| const task = { | |
| id: crypto.randomUUID(), | |
| space_id: spaceId, | |
| title, | |
| assignee_id, | |
| done: 0, | |
| due_at, | |
| created_at: Date.now(), | |
| }; | |
| db.prepare( | |
| `INSERT INTO tasks (id, space_id, title, assignee_id, done, due_at, created_at) | |
| VALUES (?,?,?,?,?,?,?)` | |
| ).run(task.id, task.space_id, task.title, task.assignee_id, task.done, task.due_at, task.created_at); | |
| bus.emit(spaceId, { type: 'task.created', space_id: spaceId, payload: task }); | |
| return reply.code(201).send({ task }); | |
| }); | |
| fastify.patch('/spaces/:id/tasks/:taskId', async (request, reply) => { | |
| await requireMember(request, request.params.id); | |
| const spaceId = request.params.id; | |
| const taskId = request.params.taskId; | |
| const body = request.body || {}; | |
| const existing = db.prepare('SELECT * FROM tasks WHERE id = ? AND space_id = ?').get(taskId, spaceId); | |
| if (!existing) { | |
| return sendError(reply, 404, 'NOT_FOUND', 'Задача не найдена'); | |
| } | |
| const task = { ...existing }; | |
| if (hasField(body, 'title')) { | |
| if (!body.title || typeof body.title !== 'string') { | |
| return sendError(reply, 400, 'VALIDATION', 'title должен быть непустой строкой'); | |
| } | |
| task.title = body.title; | |
| } | |
| if (hasField(body, 'assignee_id')) { | |
| if (!isMember(spaceId, body.assignee_id)) { | |
| return sendError(reply, 400, 'VALIDATION', 'assignee_id должен быть участником пространства или null'); | |
| } | |
| task.assignee_id = body.assignee_id; | |
| } | |
| if (hasField(body, 'done')) { | |
| if (typeof body.done !== 'boolean' && body.done !== 0 && body.done !== 1) { | |
| return sendError(reply, 400, 'VALIDATION', 'done должен быть boolean или 0|1'); | |
| } | |
| task.done = body.done ? 1 : 0; | |
| } | |
| db.prepare('UPDATE tasks SET title = ?, assignee_id = ?, done = ? WHERE id = ? AND space_id = ?') | |
| .run(task.title, task.assignee_id, task.done, task.id, task.space_id); | |
| bus.emit(spaceId, { type: 'task.updated', space_id: spaceId, payload: task }); | |
| return { task }; | |
| }); | |
| } | |