import { Router, Response } from 'express'; import { PrismaClient } from '@prisma/client'; import { AuthedRequest, requireAuth, requireRole } from '../middleware/auth'; const prisma = new PrismaClient(); /** * Peer-Bewertungssystem für (Zwischen-)Mieter. * * Jeder authentifizierte Nutzer darf einen Mieter bewerten (Sauberkeit, * Zuverlässigkeit, WG-Verträglichkeit). Bewertungen sind bewusst freistehend * (kein Bezug zu einem Contract) und jederzeit erfassbar. Einsehbar sind sie * ausschließlich für Vermieter/Admin — Mitbewohner sehen weder eigene noch * fremde Bewertungen, um WG-interne Konflikte durch offene Kritik zu * vermeiden. */ export const ratingsRouter = Router(); // Für jeden authentifizierten Nutzer sichtbar (Name + Zimmer, keine sensiblen // Daten) — Grundlage für die Auswahl im Bewertungsformular. ratingsRouter.get('/ratings/tenants', requireAuth, async (_req: AuthedRequest, res: Response) => { const tenants = await prisma.user.findMany({ where: { role: 'TENANT' }, select: { id: true, fullName: true, room: { select: { roomNumber: true } } }, orderBy: { fullName: 'asc' }, }); res.status(200).json({ tenants }); }); ratingsRouter.post('/ratings', requireAuth, async (req: AuthedRequest, res: Response) => { const { ratedUserId, score, comment } = req.body || {}; if (!ratedUserId || typeof ratedUserId !== 'string') { return res.status(400).json({ error: 'ratedUserId ist erforderlich' }); } if (ratedUserId === req.user!.id) { return res.status(400).json({ error: 'Du kannst dich nicht selbst bewerten' }); } const numericScore = Number(score); if (!Number.isInteger(numericScore) || numericScore < 1 || numericScore > 5) { return res.status(400).json({ error: 'score muss eine Ganzzahl zwischen 1 und 5 sein' }); } const ratedUser = await prisma.user.findUnique({ where: { id: ratedUserId } }); if (!ratedUser || ratedUser.role !== 'TENANT') { return res.status(400).json({ error: 'ratedUserId muss ein Mieter sein' }); } const rating = await prisma.tenantRating.create({ data: { raterId: req.user!.id, ratedUserId, score: numericScore, comment: typeof comment === 'string' && comment.trim() ? comment.trim() : null, }, }); res.status(201).json({ rating }); }); // Nur Vermieter/Admin dürfen Bewertungen einsehen — optional gefiltert nach // bewertetem Mieter (?userId=...). ratingsRouter.get( '/ratings', requireAuth, requireRole('LANDLORD', 'ADMIN'), async (req: AuthedRequest, res: Response) => { const userId = typeof req.query.userId === 'string' ? req.query.userId : undefined; const ratings = await prisma.tenantRating.findMany({ where: userId ? { ratedUserId: userId } : undefined, orderBy: { createdAt: 'desc' }, select: { id: true, score: true, comment: true, createdAt: true, rater: { select: { id: true, fullName: true, role: true } }, ratedUser: { select: { id: true, fullName: true } }, }, }); const summaryByUser = new Map(); for (const r of ratings) { const entry = summaryByUser.get(r.ratedUser.id) || { userId: r.ratedUser.id, fullName: r.ratedUser.fullName, count: 0, avgScore: 0, }; entry.avgScore = (entry.avgScore * entry.count + r.score) / (entry.count + 1); entry.count += 1; summaryByUser.set(r.ratedUser.id, entry); } res.status(200).json({ ratings, summary: Array.from(summaryByUser.values()) }); }, );