From 20593b71733b88a7312973340fba0087a99831cc Mon Sep 17 00:00:00 2001 From: smueller Date: Fri, 24 Jul 2026 11:59:16 +0200 Subject: [PATCH] Enhance dashboard guild access with owner bypass functionality - Introduced `resolveDashboardGuild` to handle guild resolution for both managed and owner-panel bypass scenarios. - Updated `GuildLayout` and `WelcomePage` components to utilize the new guild resolution logic, improving access handling. - Enhanced `DashboardShell` to display an informational banner for users accessing guilds via the owner-panel bypass. - Added localization support for owner bypass messages in English and German. - Updated authentication logic to allow owner-panel users to access guilds without Discord Manage Guild permission. --- .../src/app/dashboard/[guildId]/layout.tsx | 15 ++++--- .../app/dashboard/[guildId]/welcome/page.tsx | 10 ++--- .../src/components/layout/dashboard-shell.tsx | 19 +++++++- .../src/components/owner/owner-forms.tsx | 4 ++ apps/webui/src/lib/auth.ts | 30 +++++++++---- apps/webui/src/lib/guilds.ts | 43 ++++++++++++++++++- apps/webui/src/lib/owner-auth.ts | 8 ++++ apps/webui/src/messages/de.json | 6 +++ apps/webui/src/messages/en.json | 6 +++ docs/PHASE-TRACKING.md | 14 ++++++ 10 files changed, 133 insertions(+), 22 deletions(-) diff --git a/apps/webui/src/app/dashboard/[guildId]/layout.tsx b/apps/webui/src/app/dashboard/[guildId]/layout.tsx index ade1c86..9cb93fe 100644 --- a/apps/webui/src/app/dashboard/[guildId]/layout.tsx +++ b/apps/webui/src/app/dashboard/[guildId]/layout.tsx @@ -2,7 +2,7 @@ import { notFound } from 'next/navigation'; import type { ReactNode } from 'react'; import { DashboardShell } from '@/components/layout/dashboard-shell'; import { requireGuildAccessOrRedirect } from '@/lib/auth'; -import { getManageableGuilds } from '@/lib/guilds'; +import { getManageableGuilds, resolveDashboardGuild } from '@/lib/guilds'; import { isOwnerUser } from '@/lib/owner-auth'; interface GuildLayoutProps { @@ -13,23 +13,26 @@ interface GuildLayoutProps { export default async function GuildLayout({ children, params }: GuildLayoutProps) { const { guildId } = await params; const session = await requireGuildAccessOrRedirect(guildId); - const guilds = await getManageableGuilds(session); - const currentGuild = guilds.find((guild) => guild.id === guildId); + const [resolved, guilds, showOwnerLink] = await Promise.all([ + resolveDashboardGuild(session, guildId), + getManageableGuilds(session), + isOwnerUser(session.user.id) + ]); - if (!currentGuild) { + if (!resolved) { notFound(); } const otherGuilds = guilds.filter((guild) => guild.id !== guildId); - const showOwnerLink = await isOwnerUser(session.user.id); return ( {children} diff --git a/apps/webui/src/app/dashboard/[guildId]/welcome/page.tsx b/apps/webui/src/app/dashboard/[guildId]/welcome/page.tsx index 4c7adc7..f0a4d1e 100644 --- a/apps/webui/src/app/dashboard/[guildId]/welcome/page.tsx +++ b/apps/webui/src/app/dashboard/[guildId]/welcome/page.tsx @@ -1,7 +1,7 @@ import { notFound } from 'next/navigation'; import { WelcomeForm } from '@/components/modules/welcome-form'; import { requireGuildAccessOrRedirect } from '@/lib/auth'; -import { getManageableGuild } from '@/lib/guilds'; +import { resolveDashboardGuild } from '@/lib/guilds'; import { getLocale, t } from '@/lib/i18n'; import { getWelcomeDashboard } from '@/lib/module-configs/welcome'; import { buildWelcomePreviewVars } from '@/lib/welcome-preview-vars'; @@ -13,13 +13,13 @@ interface WelcomePageProps { export default async function WelcomePage({ params }: WelcomePageProps) { const { guildId } = await params; const session = await requireGuildAccessOrRedirect(guildId); - const [locale, config, guild] = await Promise.all([ + const [locale, config, resolved] = await Promise.all([ getLocale(), getWelcomeDashboard(guildId), - getManageableGuild(session, guildId) + resolveDashboardGuild(session, guildId) ]); - if (!guild) { + if (!resolved) { notFound(); } @@ -32,7 +32,7 @@ export default async function WelcomePage({ params }: WelcomePageProps) { ); diff --git a/apps/webui/src/components/layout/dashboard-shell.tsx b/apps/webui/src/components/layout/dashboard-shell.tsx index 904d83c..031b6db 100644 --- a/apps/webui/src/components/layout/dashboard-shell.tsx +++ b/apps/webui/src/components/layout/dashboard-shell.tsx @@ -18,6 +18,8 @@ interface DashboardShellProps { otherGuilds: DashboardGuild[]; user: SessionUser; showOwnerLink?: boolean; + /** True when an Owner-panel user opened a guild they do not manage on Discord. */ + ownerBypass?: boolean; children: ReactNode; } @@ -27,6 +29,7 @@ export function DashboardShell({ otherGuilds, user, showOwnerLink = false, + ownerBypass = false, children }: DashboardShellProps) { const t = useTranslations(); @@ -59,7 +62,21 @@ export function DashboardShell({
-
{children}
+
+ {ownerBypass ? ( +
+

{t('dashboard.ownerBypass.title')}

+

{t('dashboard.ownerBypass.description')}

+ + {t('dashboard.ownerBypass.backToOwner')} + +
+ ) : null} + {children} +
diff --git a/apps/webui/src/components/owner/owner-forms.tsx b/apps/webui/src/components/owner/owner-forms.tsx index 97bb51d..058613d 100644 --- a/apps/webui/src/components/owner/owner-forms.tsx +++ b/apps/webui/src/components/owner/owner-forms.tsx @@ -1,5 +1,6 @@ 'use client'; +import Link from 'next/link'; import { useRouter } from 'next/navigation'; import { useMemo, useState, useTransition } from 'react'; import { toast } from 'sonner'; @@ -165,6 +166,9 @@ export function GuildsManager({
+