138 lines
4.4 KiB
TypeScript
138 lines
4.4 KiB
TypeScript
import {
|
||
getMember,
|
||
updateRoom,
|
||
getPendingRequests,
|
||
approveRequest,
|
||
rejectRequest,
|
||
banMember,
|
||
setMemberRole,
|
||
createRoomMessage,
|
||
} from "../../../../db/chat-rooms";
|
||
import { getUsersMeta } from "../../../../utils/getUsersMeta";
|
||
|
||
/** PATCH /api/chat/rooms/[roomId] – Room editieren + Anfragen verwalten */
|
||
export default defineEventHandler(async (event) => {
|
||
const user = await requireUser(event);
|
||
const roomId = getRouterParam(event, "roomId");
|
||
if (!roomId) throw createError({ statusCode: 400, message: "roomId fehlt" });
|
||
|
||
const member = await getMember(roomId, user.id);
|
||
if (!member || (member.role !== "owner" && member.role !== "admin")) {
|
||
throw createError({
|
||
statusCode: 403,
|
||
message: "Nur Admins können den Raum bearbeiten",
|
||
});
|
||
}
|
||
|
||
const body = await readBody(event);
|
||
|
||
// Handle join request approval/rejection
|
||
if (body?.action === "approve" && body?.targetUserId) {
|
||
await approveRequest(roomId, body.targetUserId);
|
||
return { ok: true, action: "approved" };
|
||
}
|
||
if (body?.action === "reject" && body?.targetUserId) {
|
||
await rejectRequest(roomId, body.targetUserId);
|
||
return { ok: true, action: "rejected" };
|
||
}
|
||
|
||
// Handle pending requests list
|
||
if (body?.action === "list_requests") {
|
||
const requests = await getPendingRequests(roomId);
|
||
const userIds = requests.map((r) => r.userId);
|
||
const meta = userIds.length > 0 ? await getUsersMeta(userIds) : {};
|
||
return requests.map((r) => ({
|
||
userId: r.userId,
|
||
nickname: meta[r.userId]?.nickname ?? "Anonym",
|
||
avatar: meta[r.userId]?.avatar ?? null,
|
||
requestedAt: r.joinedAt,
|
||
}));
|
||
}
|
||
|
||
// Ban member – owner OR admin can ban regular members (not other admins unless owner)
|
||
if (body?.action === "ban" && body?.targetUserId) {
|
||
const target = await getMember(roomId, body.targetUserId);
|
||
if (!target)
|
||
throw createError({
|
||
statusCode: 404,
|
||
message: "Mitglied nicht gefunden",
|
||
});
|
||
if (target.role === "owner")
|
||
throw createError({
|
||
statusCode: 403,
|
||
message: "Owner kann nicht gebannt werden",
|
||
});
|
||
// Admins dürfen keine anderen Admins bannen – nur Owner darf das
|
||
if (target.role === "admin" && member.role !== "owner") {
|
||
throw createError({
|
||
statusCode: 403,
|
||
message: "Nur der Owner kann Admins bannen",
|
||
});
|
||
}
|
||
const bannedMeta = await getUsersMeta([body.targetUserId]);
|
||
const bannedName =
|
||
bannedMeta[body.targetUserId]?.nickname ?? "Ein Mitglied";
|
||
await banMember(roomId, body.targetUserId);
|
||
// Systemnachricht in Gruppe
|
||
const SYSTEM_ID = "00000000-0000-0000-0000-000000000000";
|
||
await createRoomMessage({
|
||
userId: SYSTEM_ID,
|
||
roomId,
|
||
content: `🚫 ${bannedName} wurde aus der Gruppe entfernt.`,
|
||
}).catch(() => {});
|
||
return { ok: true, action: "banned" };
|
||
}
|
||
|
||
// Promote member to admin – only Owner can do this (not sub-admins)
|
||
if (body?.action === "promote_admin" && body?.targetUserId) {
|
||
if (member.role !== "owner") {
|
||
throw createError({
|
||
statusCode: 403,
|
||
message: "Nur der Owner kann Admins ernennen",
|
||
});
|
||
}
|
||
const target = await getMember(roomId, body.targetUserId);
|
||
if (!target || target.status !== "active") {
|
||
throw createError({
|
||
statusCode: 404,
|
||
message: "Mitglied nicht gefunden",
|
||
});
|
||
}
|
||
await setMemberRole(roomId, body.targetUserId, "admin");
|
||
return { ok: true, action: "promoted" };
|
||
}
|
||
|
||
// Demote admin back to member – only Owner can do this
|
||
if (body?.action === "demote_admin" && body?.targetUserId) {
|
||
if (member.role !== "owner") {
|
||
throw createError({
|
||
statusCode: 403,
|
||
message: "Nur der Owner kann Admins zurückstufen",
|
||
});
|
||
}
|
||
await setMemberRole(roomId, body.targetUserId, "member");
|
||
return { ok: true, action: "demoted" };
|
||
}
|
||
|
||
// Update room settings
|
||
const update: Record<string, any> = {};
|
||
if (body?.name) update.name = String(body.name).trim().slice(0, 60);
|
||
if (body?.description !== undefined)
|
||
update.description = String(body.description).trim().slice(0, 200) || null;
|
||
if (
|
||
body?.joinMode &&
|
||
["open", "approval", "invite_only"].includes(body.joinMode)
|
||
) {
|
||
update.joinMode = body.joinMode;
|
||
}
|
||
if (body?.avatarUrl !== undefined) {
|
||
update.avatarUrl = body.avatarUrl ? String(body.avatarUrl).trim() : null;
|
||
}
|
||
|
||
if (Object.keys(update).length > 0) {
|
||
await updateRoom(roomId, update);
|
||
}
|
||
|
||
return { ok: true };
|
||
});
|