refactor(channels): add default channel protection in DB, API and UI settings modal

This commit is contained in:
Chneemann 2026-08-31 10:47:00 +02:00
parent 942fce0e63
commit 2325c5725e
No known key found for this signature in database
4 changed files with 30 additions and 9 deletions

View file

@ -49,6 +49,14 @@ export async function PATCH(
return NextResponse.json({ error: "Channel not found" }, { status: 404 }); return NextResponse.json({ error: "Channel not found" }, { status: 404 });
} }
// Protect the default channel from changes
if (existingChannel.isDefault) {
return NextResponse.json(
{ error: "The default channel cannot be edited." },
{ status: 400 },
);
}
// Check if the user is a member of the server // Check if the user is a member of the server
const [member] = await db const [member] = await db
.select() .select()
@ -114,6 +122,14 @@ export async function DELETE(
return NextResponse.json({ error: "Channel not found" }, { status: 404 }); return NextResponse.json({ error: "Channel not found" }, { status: 404 });
} }
// Protect default channel from deletion
if (existingChannel.isDefault) {
return NextResponse.json(
{ error: "The default channel cannot be deleted." },
{ status: 400 },
);
}
// Check if the user is a member of the server // Check if the user is a member of the server
const [member] = await db const [member] = await db
.select() .select()

View file

@ -68,6 +68,7 @@ export async function POST(req: Request) {
.values({ .values({
name: "general", name: "general",
serverId: server.id, serverId: server.id,
isDefault: true,
}) })
.returning(); .returning();

View file

@ -114,15 +114,17 @@ export function ChannelSidebar() {
</div> </div>
{/* Gear Button */} {/* Gear Button */}
<button {!channel.isDefault && (
type="button" <button
onClick={(e) => handleOpenSettings(e, channel)} type="button"
className="opacity-0 group-hover:opacity-100 p-1 text-muted hover:text-white focus:outline-none transition-all cursor-pointer" onClick={(e) => handleOpenSettings(e, channel)}
aria-label="Channel Settings" className="opacity-0 group-hover:opacity-100 p-1 text-muted hover:text-white focus:outline-none transition-all cursor-pointer"
title="Channel Settings" aria-label="Channel Settings"
> title="Channel Settings"
<Settings className="w-3.5 h-3.5" /> >
</button> <Settings className="w-3.5 h-3.5" />
</button>
)}
</Link> </Link>
); );
})} })}

View file

@ -5,6 +5,7 @@
import { relations } from "drizzle-orm"; import { relations } from "drizzle-orm";
import { import {
boolean,
pgEnum, pgEnum,
pgTable, pgTable,
text, text,
@ -88,6 +89,7 @@ export const channels = pgTable("channels", {
serverId: uuid("server_id") serverId: uuid("server_id")
.references(() => servers.id, { onDelete: "cascade" }) .references(() => servers.id, { onDelete: "cascade" })
.notNull(), .notNull(),
isDefault: boolean("is_default").default(false).notNull(),
createdAt: timestamp("created_at").defaultNow().notNull(), createdAt: timestamp("created_at").defaultNow().notNull(),
}); });