add vikunja integration

This commit is contained in:
Matthias Hochmeister
2026-03-05 18:07:18 +01:00
parent fb5acd3d52
commit e9463c1c66
13 changed files with 683 additions and 0 deletions

View File

@@ -0,0 +1,94 @@
import { Request, Response } from 'express';
import vikunjaService from '../services/vikunja.service';
import notificationService from '../services/notification.service';
import environment from '../config/environment';
import logger from '../utils/logger';
class VikunjaController {
async getMyTasks(_req: Request, res: Response): Promise<void> {
if (!environment.vikunja.url) {
res.status(200).json({ success: true, data: [], configured: false });
return;
}
try {
const tasks = await vikunjaService.getMyTasks();
res.status(200).json({ success: true, data: tasks, configured: true });
} catch (error) {
logger.error('VikunjaController.getMyTasks error', { error });
res.status(500).json({ success: false, message: 'Vikunja konnte nicht abgefragt werden' });
}
}
async getOverdueTasks(req: Request, res: Response): Promise<void> {
if (!environment.vikunja.url) {
res.status(200).json({ success: true, data: [], configured: false });
return;
}
try {
const tasks = await vikunjaService.getOverdueTasks();
// Side-effect: create notifications for each overdue task (dedup via DB constraint)
if (req.user?.id && tasks.length > 0) {
const userId = req.user.id;
for (const task of tasks) {
await notificationService.createNotification({
user_id: userId,
typ: 'vikunja_task',
titel: 'Überfällige Aufgabe',
nachricht: task.title,
schwere: 'warnung',
link: environment.vikunja.url ? `${environment.vikunja.url}/tasks/${task.id}` : undefined,
quell_id: String(task.id),
quell_typ: 'vikunja_task',
});
}
}
res.status(200).json({ success: true, data: tasks, configured: true });
} catch (error) {
logger.error('VikunjaController.getOverdueTasks error', { error });
res.status(500).json({ success: false, message: 'Vikunja konnte nicht abgefragt werden' });
}
}
async getProjects(_req: Request, res: Response): Promise<void> {
if (!environment.vikunja.url) {
res.status(200).json({ success: true, data: [], configured: false });
return;
}
try {
const projects = await vikunjaService.getProjects();
res.status(200).json({ success: true, data: projects, configured: true });
} catch (error) {
logger.error('VikunjaController.getProjects error', { error });
res.status(500).json({ success: false, message: 'Vikunja-Projekte konnten nicht geladen werden' });
}
}
async createTask(req: Request, res: Response): Promise<void> {
if (!environment.vikunja.url) {
res.status(503).json({ success: false, message: 'Vikunja ist nicht eingerichtet' });
return;
}
const { projectId, title, dueDate } = req.body as {
projectId?: number;
title?: string;
dueDate?: string;
};
if (!projectId || !title || title.trim().length === 0) {
res.status(400).json({ success: false, message: 'Projekt und Titel sind erforderlich' });
return;
}
try {
const task = await vikunjaService.createTask(projectId, title.trim(), dueDate);
res.status(201).json({ success: true, data: task });
} catch (error) {
logger.error('VikunjaController.createTask error', { error });
res.status(500).json({ success: false, message: 'Aufgabe konnte nicht erstellt werden' });
}
}
}
export default new VikunjaController();