kaneo (minimalist kanban) fork to experiment adding a tangled integration github.com/usekaneo/kaneo
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

at main 122 lines 3.3 kB view raw
1import { and, eq } from "drizzle-orm"; 2import { HTTPException } from "hono/http-exception"; 3import db from "../../database"; 4import { columnTable, projectTable, taskTable } from "../../database/schema"; 5import { publishEvent } from "../../events"; 6import { 7 coercePriority, 8 coerceStatus, 9 getValidTaskStatuses, 10} from "../validate-task-fields"; 11import getNextTaskNumber from "./get-next-task-number"; 12 13type ImportTask = { 14 title: string; 15 description?: string; 16 status: string; 17 priority?: string; 18 startDate?: string; 19 dueDate?: string; 20 userId?: string | null; 21}; 22 23async function importTasks(projectId: string, tasksToImport: ImportTask[]) { 24 const project = await db.query.projectTable.findFirst({ 25 where: eq(projectTable.id, projectId), 26 }); 27 28 if (!project) { 29 throw new HTTPException(404, { 30 message: "Project not found", 31 }); 32 } 33 34 const nextTaskNumber = await getNextTaskNumber(projectId); 35 let taskNumber = nextTaskNumber; 36 const validStatuses = await getValidTaskStatuses(projectId); 37 38 const results = []; 39 40 for (const taskData of tasksToImport) { 41 try { 42 const { status, warning: statusWarning } = coerceStatus( 43 taskData.status, 44 validStatuses, 45 ); 46 const { priority, warning: priorityWarning } = coercePriority( 47 taskData.priority || "low", 48 ); 49 const warnings = [statusWarning, priorityWarning].filter(Boolean); 50 51 const column = await db.query.columnTable.findFirst({ 52 where: and( 53 eq(columnTable.projectId, projectId), 54 eq(columnTable.slug, status), 55 ), 56 }); 57 58 const [createdTask] = await db 59 .insert(taskTable) 60 .values({ 61 projectId, 62 userId: taskData.userId || null, 63 title: taskData.title, 64 status, 65 columnId: column?.id ?? null, 66 startDate: taskData.startDate ? new Date(taskData.startDate) : null, 67 dueDate: taskData.dueDate ? new Date(taskData.dueDate) : null, 68 description: taskData.description || "", 69 priority, 70 number: ++taskNumber, 71 }) 72 .returning(); 73 74 if (createdTask) { 75 await publishEvent("task.created", { 76 taskId: createdTask.id, 77 userId: createdTask.userId ?? "", 78 type: "create", 79 content: "imported the task", 80 }); 81 82 results.push({ 83 success: true, 84 task: createdTask, 85 ...(warnings.length > 0 && { warnings }), 86 }); 87 } else { 88 results.push({ 89 success: false, 90 error: "Failed to create task", 91 task: taskData, 92 }); 93 } 94 } catch (error) { 95 if (error instanceof HTTPException) { 96 throw error; 97 } 98 results.push({ 99 success: false, 100 error: error instanceof Error ? error.message : "Unknown error", 101 task: taskData, 102 }); 103 } 104 } 105 106 return { 107 importedAt: new Date().toISOString(), 108 project: { 109 id: project.id, 110 name: project.name, 111 slug: project.slug, 112 }, 113 results: { 114 total: tasksToImport.length, 115 successful: results.filter((r) => r.success).length, 116 failed: results.filter((r) => !r.success).length, 117 tasks: results, 118 }, 119 }; 120} 121 122export default importTasks;