From 5ceae7c364055fb8701f5347e01b17822362cbf5 Mon Sep 17 00:00:00 2001 From: Matthias Hochmeister Date: Wed, 25 Mar 2026 07:54:40 +0100 Subject: [PATCH] fix permissions --- backend/src/controllers/issue.controller.ts | 63 --------- backend/src/routes/issue.routes.ts | 28 ---- backend/src/services/issue.service.ts | 77 ----------- frontend/src/pages/Issues.tsx | 140 +------------------- frontend/src/services/issues.ts | 18 +-- frontend/src/types/issue.types.ts | 11 -- 6 files changed, 3 insertions(+), 334 deletions(-) diff --git a/backend/src/controllers/issue.controller.ts b/backend/src/controllers/issue.controller.ts index 82d97f5..a4bb239 100644 --- a/backend/src/controllers/issue.controller.ts +++ b/backend/src/controllers/issue.controller.ts @@ -464,69 +464,6 @@ class IssueController { res.status(500).json({ success: false, message: 'Priorität konnte nicht deaktiviert werden' }); } } - - async getStatusmeldungen(_req: Request, res: Response): Promise { - try { - const items = await issueService.getStatusmeldungen(); - res.status(200).json({ success: true, data: items }); - } catch (error) { - logger.error('IssueController.getStatusmeldungen error', { error }); - res.status(500).json({ success: false, message: 'Statusmeldungen konnten nicht geladen werden' }); - } - } - - async createStatusmeldung(req: Request, res: Response): Promise { - const { titel } = req.body; - if (!titel || typeof titel !== 'string' || titel.trim().length === 0) { - res.status(400).json({ success: false, message: 'Titel ist erforderlich' }); - return; - } - try { - const item = await issueService.createStatusmeldung(req.body, req.user!.id); - res.status(201).json({ success: true, data: item }); - } catch (error) { - logger.error('IssueController.createStatusmeldung error', { error }); - res.status(500).json({ success: false, message: 'Statusmeldung konnte nicht erstellt werden' }); - } - } - - async updateStatusmeldung(req: Request, res: Response): Promise { - const id = parseInt(param(req, 'id'), 10); - if (isNaN(id)) { - res.status(400).json({ success: false, message: 'Ungültige ID' }); - return; - } - try { - const item = await issueService.updateStatusmeldung(id, req.body); - if (!item) { - res.status(404).json({ success: false, message: 'Statusmeldung nicht gefunden' }); - return; - } - res.status(200).json({ success: true, data: item }); - } catch (error) { - logger.error('IssueController.updateStatusmeldung error', { error }); - res.status(500).json({ success: false, message: 'Statusmeldung konnte nicht aktualisiert werden' }); - } - } - - async deleteStatusmeldung(req: Request, res: Response): Promise { - const id = parseInt(param(req, 'id'), 10); - if (isNaN(id)) { - res.status(400).json({ success: false, message: 'Ungültige ID' }); - return; - } - try { - const deleted = await issueService.deleteStatusmeldung(id); - if (!deleted) { - res.status(404).json({ success: false, message: 'Statusmeldung nicht gefunden' }); - return; - } - res.status(200).json({ success: true, message: 'Statusmeldung gelöscht' }); - } catch (error) { - logger.error('IssueController.deleteStatusmeldung error', { error }); - res.status(500).json({ success: false, message: 'Statusmeldung konnte nicht gelöscht werden' }); - } - } } export default new IssueController(); diff --git a/backend/src/routes/issue.routes.ts b/backend/src/routes/issue.routes.ts index 9186635..fe7e25d 100644 --- a/backend/src/routes/issue.routes.ts +++ b/backend/src/routes/issue.routes.ts @@ -5,34 +5,6 @@ import { requirePermission } from '../middleware/rbac.middleware'; const router = Router(); -// --- Statusmeldungen routes (BEFORE /:id) --- -router.get( - '/statusmeldungen', - authenticate, - issueController.getStatusmeldungen.bind(issueController) -); - -router.post( - '/statusmeldungen', - authenticate, - requirePermission('issues:edit_settings'), - issueController.createStatusmeldung.bind(issueController) -); - -router.patch( - '/statusmeldungen/:id', - authenticate, - requirePermission('issues:edit_settings'), - issueController.updateStatusmeldung.bind(issueController) -); - -router.delete( - '/statusmeldungen/:id', - authenticate, - requirePermission('issues:edit_settings'), - issueController.deleteStatusmeldung.bind(issueController) -); - // --- Widget summary route (BEFORE /:id) --- router.get( '/widget-summary', diff --git a/backend/src/services/issue.service.ts b/backend/src/services/issue.service.ts index ef75008..8b2dcca 100644 --- a/backend/src/services/issue.service.ts +++ b/backend/src/services/issue.service.ts @@ -559,79 +559,6 @@ async function deleteIssuePriority(id: number) { } } -async function getStatusmeldungen() { - try { - const result = await pool.query( - `SELECT * FROM issue_statusmeldungen WHERE aktiv = true ORDER BY created_at DESC` - ); - return result.rows; - } catch (error) { - logger.error('IssueService.getStatusmeldungen failed', { error }); - throw new Error('Statusmeldungen konnten nicht geladen werden'); - } -} - -async function createStatusmeldung( - data: { titel: string; inhalt?: string; schwere?: string }, - userId: string -) { - try { - const result = await pool.query( - `INSERT INTO issue_statusmeldungen (titel, inhalt, schwere, erstellt_von) - VALUES ($1, $2, $3, $4) - RETURNING *`, - [data.titel, data.inhalt ?? null, data.schwere ?? 'info', userId] - ); - return result.rows[0]; - } catch (error) { - logger.error('IssueService.createStatusmeldung failed', { error }); - throw new Error('Statusmeldung konnte nicht erstellt werden'); - } -} - -async function updateStatusmeldung( - id: number, - data: { titel?: string; inhalt?: string; schwere?: string; aktiv?: boolean } -) { - try { - const setClauses: string[] = []; - const values: any[] = []; - let idx = 1; - - if (data.titel !== undefined) { setClauses.push(`titel = $${idx}`); values.push(data.titel); idx++; } - if ('inhalt' in data) { setClauses.push(`inhalt = $${idx}`); values.push(data.inhalt ?? null); idx++; } - if (data.schwere !== undefined) { setClauses.push(`schwere = $${idx}`); values.push(data.schwere); idx++; } - if (data.aktiv !== undefined) { setClauses.push(`aktiv = $${idx}`); values.push(data.aktiv); idx++; } - - if (setClauses.length === 0) { - const r = await pool.query(`SELECT * FROM issue_statusmeldungen WHERE id = $1`, [id]); - return r.rows[0] || null; - } - - values.push(id); - const result = await pool.query( - `UPDATE issue_statusmeldungen SET ${setClauses.join(', ')} WHERE id = $${idx} RETURNING *`, - values - ); - return result.rows[0] || null; - } catch (error) { - logger.error('IssueService.updateStatusmeldung failed', { error, id }); - throw new Error('Statusmeldung konnte nicht aktualisiert werden'); - } -} - -async function deleteStatusmeldung(id: number) { - try { - const result = await pool.query( - `DELETE FROM issue_statusmeldungen WHERE id = $1 RETURNING id`, - [id] - ); - return result.rows.length > 0; - } catch (error) { - logger.error('IssueService.deleteStatusmeldung failed', { error, id }); - throw new Error('Statusmeldung konnte nicht gelöscht werden'); - } -} export default { getIssues, @@ -655,9 +582,5 @@ export default { createIssuePriority, updateIssuePriority, deleteIssuePriority, - getStatusmeldungen, - createStatusmeldung, - updateStatusmeldung, - deleteStatusmeldung, UNASSIGN, }; diff --git a/frontend/src/pages/Issues.tsx b/frontend/src/pages/Issues.tsx index 5bf11ef..364c12b 100644 --- a/frontend/src/pages/Issues.tsx +++ b/frontend/src/pages/Issues.tsx @@ -20,7 +20,7 @@ import { useNotification } from '../contexts/NotificationContext'; import { usePermissionContext } from '../contexts/PermissionContext'; import { useAuth } from '../contexts/AuthContext'; import { issuesApi } from '../services/issues'; -import type { Issue, IssueComment, IssueTyp, CreateIssuePayload, UpdateIssuePayload, IssueFilters, AssignableMember, IssueStatusmeldung, IssueStatusDef, IssuePriorityDef } from '../types/issue.types'; +import type { Issue, IssueComment, IssueTyp, CreateIssuePayload, UpdateIssuePayload, IssueFilters, AssignableMember, IssueStatusDef, IssuePriorityDef } from '../types/issue.types'; // ── Helpers ── @@ -755,12 +755,6 @@ function IssueSettings() { const queryClient = useQueryClient(); const { showSuccess, showError } = useNotification(); - // ── Statusmeldungen state ── - const [createOpen, setCreateOpen] = useState(false); - const [createData, setCreateData] = useState<{ titel: string; inhalt: string; schwere: 'info' | 'warnung' | 'fehler' }>({ titel: '', inhalt: '', schwere: 'info' }); - const [editId, setEditId] = useState(null); - const [editData, setEditData] = useState>({}); - // ── Status state ── const [statusCreateOpen, setStatusCreateOpen] = useState(false); const [statusCreateData, setStatusCreateData] = useState>({ schluessel: '', bezeichnung: '', farbe: 'default', ist_abschluss: false, ist_initial: false, benoetigt_typ_freigabe: false, sort_order: 0 }); @@ -773,11 +767,6 @@ function IssueSettings() { const [prioEditId, setPrioEditId] = useState(null); const [prioEditData, setPrioEditData] = useState>({}); - const { data: statusmeldungen = [], isLoading: smLoading } = useQuery({ - queryKey: ['issue-statusmeldungen'], - queryFn: issuesApi.getStatusmeldungen, - }); - const { data: issueStatuses = [], isLoading: statusLoading } = useQuery({ queryKey: ['issue-statuses'], queryFn: issuesApi.getStatuses, @@ -788,40 +777,6 @@ function IssueSettings() { queryFn: issuesApi.getPriorities, }); - // Statusmeldungen mutations - const createSmMut = useMutation({ - mutationFn: (data: { titel: string; inhalt?: string; schwere?: string }) => issuesApi.createStatusmeldung(data), - onSuccess: () => { - queryClient.invalidateQueries({ queryKey: ['issue-statusmeldungen'] }); - showSuccess('Statusmeldung erstellt'); - setCreateOpen(false); - setCreateData({ titel: '', inhalt: '', schwere: 'info' }); - }, - onError: () => showError('Fehler beim Erstellen'), - }); - - const updateSmMut = useMutation({ - mutationFn: ({ id, data }: { id: number; data: Partial }) => issuesApi.updateStatusmeldung(id, data), - onSuccess: () => { - queryClient.invalidateQueries({ queryKey: ['issue-statusmeldungen'] }); - showSuccess('Statusmeldung aktualisiert'); - setEditId(null); - }, - onError: () => showError('Fehler beim Aktualisieren'), - }); - - const deleteSmMut = useMutation({ - mutationFn: (id: number) => issuesApi.deleteStatusmeldung(id), - onSuccess: () => { - queryClient.invalidateQueries({ queryKey: ['issue-statusmeldungen'] }); - showSuccess('Statusmeldung gelöscht'); - }, - onError: () => showError('Fehler beim Löschen'), - }); - - const schwereColors: Record = { info: 'info', warnung: 'warning', fehler: 'error' }; - const schwereLabels: Record = { info: 'Info', warnung: 'Warnung', fehler: 'Fehler' }; - // Status mutations const createStatusMut = useMutation({ mutationFn: (data: Partial) => issuesApi.createStatus(data), @@ -988,76 +943,7 @@ function IssueSettings() { )} - {/* Section 3: Statusmeldungen */} - - - Statusmeldungen - - - {smLoading ? : ( - - - - - Titel - Schwere - Aktiv - Aktionen - - - - {statusmeldungen.length === 0 ? ( - - - Keine Statusmeldungen - - - ) : statusmeldungen.map((sm) => ( - - {editId === sm.id ? ( - <> - - setEditData({ ...editData, titel: e.target.value })} /> - - - - - - setEditData({ ...editData, aktiv: e.target.checked })} size="small" /> - - - updateSmMut.mutate({ id: sm.id, data: editData })}> - setEditId(null)}> - - - ) : ( - <> - {sm.titel} - - - updateSmMut.mutate({ id: sm.id, data: { aktiv: e.target.checked } })} size="small" /> - - - { setEditId(sm.id); setEditData({ titel: sm.titel, schwere: sm.schwere, aktiv: sm.aktiv, inhalt: sm.inhalt ?? '' }); }}> - deleteSmMut.mutate(sm.id)}> - - - )} - - ))} - -
-
- )} -
- - {/* Section 4: Kategorien */} + {/* Section 3: Kategorien */} @@ -1100,28 +986,6 @@ function IssueSettings() { - {/* Create Statusmeldung Dialog */} - setCreateOpen(false)} maxWidth="sm" fullWidth> - Neue Statusmeldung - - setCreateData({ ...createData, titel: e.target.value })} autoFocus /> - setCreateData({ ...createData, inhalt: e.target.value })} /> - - Schwere - - - - - - - - ); } diff --git a/frontend/src/services/issues.ts b/frontend/src/services/issues.ts index 2641763..f951248 100644 --- a/frontend/src/services/issues.ts +++ b/frontend/src/services/issues.ts @@ -1,5 +1,5 @@ import { api } from './api'; -import type { Issue, IssueComment, CreateIssuePayload, UpdateIssuePayload, IssueTyp, IssueFilters, AssignableMember, IssueStatusmeldung, IssueStatusDef, IssuePriorityDef, IssueWidgetSummary } from '../types/issue.types'; +import type { Issue, IssueComment, CreateIssuePayload, UpdateIssuePayload, IssueTyp, IssueFilters, AssignableMember, IssueStatusDef, IssuePriorityDef, IssueWidgetSummary } from '../types/issue.types'; export const issuesApi = { getIssues: async (filters?: IssueFilters): Promise => { @@ -57,22 +57,6 @@ export const issuesApi = { const r = await api.get('/api/issues/members'); return r.data.data; }, - // Statusmeldungen CRUD - getStatusmeldungen: async (): Promise => { - const r = await api.get('/api/issues/statusmeldungen'); - return r.data.data; - }, - createStatusmeldung: async (data: { titel: string; inhalt?: string; schwere?: string }): Promise => { - const r = await api.post('/api/issues/statusmeldungen', data); - return r.data.data; - }, - updateStatusmeldung: async (id: number, data: Partial): Promise => { - const r = await api.patch(`/api/issues/statusmeldungen/${id}`, data); - return r.data.data; - }, - deleteStatusmeldung: async (id: number): Promise => { - await api.delete(`/api/issues/statusmeldungen/${id}`); - }, // Widget summary getWidgetSummary: async (): Promise => { const r = await api.get('/api/issues/widget-summary'); diff --git a/frontend/src/types/issue.types.ts b/frontend/src/types/issue.types.ts index fb1c466..4841316 100644 --- a/frontend/src/types/issue.types.ts +++ b/frontend/src/types/issue.types.ts @@ -68,17 +68,6 @@ export interface AssignableMember { name: string; } -export interface IssueStatusmeldung { - id: number; - titel: string; - inhalt: string | null; - schwere: 'info' | 'warnung' | 'fehler'; - aktiv: boolean; - erstellt_von: string | null; - created_at: string; - updated_at: string; -} - export interface IssueStatusDef { id: number; schluessel: string;