fix permissions
This commit is contained in:
@@ -352,6 +352,79 @@ class IssueController {
|
||||
res.status(500).json({ success: false, message: 'Mitglieder konnten nicht geladen werden' });
|
||||
}
|
||||
}
|
||||
|
||||
async getWidgetSummary(_req: Request, res: Response): Promise<void> {
|
||||
try {
|
||||
const counts = await issueService.getIssueCounts();
|
||||
res.status(200).json({ success: true, data: counts });
|
||||
} catch (error) {
|
||||
logger.error('IssueController.getWidgetSummary error', { error });
|
||||
res.status(500).json({ success: false, message: 'Issue-Counts konnten nicht geladen werden' });
|
||||
}
|
||||
}
|
||||
|
||||
async getStatusmeldungen(_req: Request, res: Response): Promise<void> {
|
||||
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<void> {
|
||||
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<void> {
|
||||
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<void> {
|
||||
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();
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
-- Migration 057: issue_statusmeldungen table
|
||||
|
||||
CREATE TABLE IF NOT EXISTS issue_statusmeldungen (
|
||||
id SERIAL PRIMARY KEY,
|
||||
titel VARCHAR(255) NOT NULL,
|
||||
inhalt TEXT,
|
||||
schwere VARCHAR(20) NOT NULL DEFAULT 'info',
|
||||
aktiv BOOLEAN NOT NULL DEFAULT true,
|
||||
erstellt_von VARCHAR(255) REFERENCES users(id),
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
||||
);
|
||||
|
||||
CREATE OR REPLACE FUNCTION update_issue_statusmeldungen_updated_at()
|
||||
RETURNS TRIGGER AS $$
|
||||
BEGIN
|
||||
NEW.updated_at = NOW();
|
||||
RETURN NEW;
|
||||
END;
|
||||
$$ LANGUAGE plpgsql;
|
||||
|
||||
CREATE TRIGGER trg_issue_statusmeldungen_updated_at
|
||||
BEFORE UPDATE ON issue_statusmeldungen
|
||||
FOR EACH ROW EXECUTE FUNCTION update_issue_statusmeldungen_updated_at();
|
||||
@@ -5,6 +5,42 @@ 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',
|
||||
authenticate,
|
||||
requirePermission('issues:view_all'),
|
||||
issueController.getWidgetSummary.bind(issueController)
|
||||
);
|
||||
|
||||
// --- Type management routes (BEFORE /:id to avoid conflict) ---
|
||||
router.get(
|
||||
'/typen',
|
||||
|
||||
@@ -361,6 +361,96 @@ async function getAssignableMembers() {
|
||||
}
|
||||
}
|
||||
|
||||
async function getIssueCounts() {
|
||||
try {
|
||||
const result = await pool.query(
|
||||
`SELECT status, COUNT(*)::int AS count FROM issues GROUP BY status`
|
||||
);
|
||||
const counts: Record<string, number> = { offen: 0, in_bearbeitung: 0, erledigt: 0, abgelehnt: 0 };
|
||||
for (const row of result.rows) {
|
||||
counts[row.status] = row.count;
|
||||
}
|
||||
return counts;
|
||||
} catch (error) {
|
||||
logger.error('IssueService.getIssueCounts failed', { error });
|
||||
throw new Error('Issue-Counts konnten nicht geladen werden');
|
||||
}
|
||||
}
|
||||
|
||||
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,
|
||||
getIssueById,
|
||||
@@ -374,5 +464,10 @@ export default {
|
||||
updateType,
|
||||
deactivateType,
|
||||
getAssignableMembers,
|
||||
getIssueCounts,
|
||||
getStatusmeldungen,
|
||||
createStatusmeldung,
|
||||
updateStatusmeldung,
|
||||
deleteStatusmeldung,
|
||||
UNASSIGN,
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user