fix(events): ensure getEventWithAttendees matches attendees by FK and short username, returns seats_claimed, and updates guest drawer
This commit is contained in:
parent
2bfbdd602b
commit
64f758e7cb
@ -735,12 +735,20 @@ async function openAttendeesDrawer(eventId, eventName) {
|
||||
if (res.ok && data.success) {
|
||||
const attendees = data.attendees || [];
|
||||
|
||||
const claimedElem = document.getElementById("guestDrawerClaimed");
|
||||
if (claimedElem) claimedElem.textContent = attendees.length;
|
||||
|
||||
if (data.event) {
|
||||
const claimedElem = document.getElementById("guestDrawerClaimed");
|
||||
if (claimedElem) {
|
||||
claimedElem.textContent = data.event.seats_claimed !== undefined
|
||||
? data.event.seats_claimed
|
||||
: attendees.length;
|
||||
}
|
||||
|
||||
const maxElem = document.getElementById("guestDrawerMax");
|
||||
if (maxElem) maxElem.textContent = data.event.max_seats;
|
||||
if (maxElem) {
|
||||
maxElem.textContent = Number(data.event.max_seats) > 0
|
||||
? data.event.max_seats
|
||||
: "∞";
|
||||
}
|
||||
|
||||
const expiresAtElem = document.getElementById("guestDrawerExpiresAt");
|
||||
if (expiresAtElem && data.event.expires_at) {
|
||||
|
||||
@ -216,7 +216,11 @@ eventsActionsRoutes.get("/api/events/:id/attendees", async (c) => {
|
||||
success: true,
|
||||
attendees: data.attendees,
|
||||
event: {
|
||||
id: data.event.id,
|
||||
name: data.event.name,
|
||||
slug: data.event.slug,
|
||||
max_seats: data.event.max_seats,
|
||||
seats_claimed: data.event.seats_claimed,
|
||||
expires_at: data.event.expires_at,
|
||||
},
|
||||
});
|
||||
|
||||
@ -237,18 +237,22 @@ export async function getEventWithAttendees(
|
||||
isGlobalAdmin: boolean,
|
||||
) {
|
||||
const event = await sqlWrapper.sql`
|
||||
SELECT id, slug, max_seats, expires_at FROM event_passes
|
||||
SELECT id, name, slug, max_seats, seats_claimed, expires_at FROM event_passes
|
||||
WHERE id = ${eventId}
|
||||
AND (created_by = ${userId} OR ${isGlobalAdmin})
|
||||
`.then((res: any) => res[0]);
|
||||
|
||||
if (!event) return null;
|
||||
|
||||
const shortId = String(event.id).split("-")[0];
|
||||
const shortPattern = `guest_${shortId}_%`;
|
||||
|
||||
const attendees = await sqlWrapper.sql`
|
||||
SELECT s.id, s.label, s.is_paused, s.created_at, s.expires_at, s.last_activity_at, s.last_activity_action, u.username, u.display_name
|
||||
FROM sessions s
|
||||
JOIN users u ON s.user_id = u.id
|
||||
WHERE u.event_pass_id = ${eventId}
|
||||
OR u.username LIKE ${shortPattern}
|
||||
ORDER BY s.created_at DESC
|
||||
`;
|
||||
|
||||
|
||||
@ -10,6 +10,7 @@ import {
|
||||
EventCockpitDeckFragment,
|
||||
WorkshopPassDrawerFragment,
|
||||
} from "../events/fragments.tsx";
|
||||
import { AppLaunchpadPageFragment } from "../dashboard/launchpad_fragments.tsx";
|
||||
|
||||
Deno.test("[Sessions] GET /dashboard unauthenticated redirects to /login", async () => {
|
||||
const req = new Request("http://localhost/dashboard");
|
||||
@ -155,3 +156,42 @@ Deno.test("[Sessions] GET /dashboard/passkeys unauthenticated redirects to /logi
|
||||
assertEquals(res.status, 302);
|
||||
assertEquals(res.headers.get("location"), "/login");
|
||||
});
|
||||
|
||||
Deno.test("[Sessions] AppLaunchpadPageFragment renders authorized workload cards and roles", () => {
|
||||
const mockApps = [
|
||||
{
|
||||
id: "app-1",
|
||||
name: "ed-droid",
|
||||
description: "Autonomous Agent UI",
|
||||
domain: "ed.atyg.org",
|
||||
role: "Guest (Viewer)",
|
||||
},
|
||||
{
|
||||
id: "app-2",
|
||||
name: "grafana",
|
||||
description: "Metrics Dashboard",
|
||||
domain: "grafana.atyg.org",
|
||||
role: "Admin",
|
||||
},
|
||||
];
|
||||
|
||||
const html = <AppLaunchpadPageFragment apps={mockApps} isAdmin={false} />;
|
||||
const str = String(html);
|
||||
assertStringIncludes(str, "Application Launchpad");
|
||||
assertStringIncludes(str, "ed-droid");
|
||||
assertStringIncludes(str, "ed.atyg.org");
|
||||
assertStringIncludes(str, "Guest (Viewer)");
|
||||
assertStringIncludes(str, "https://ed.atyg.org");
|
||||
assertStringIncludes(str, "grafana");
|
||||
assertStringIncludes(str, "badge-success");
|
||||
});
|
||||
|
||||
Deno.test("[Sessions] AppLaunchpadPageFragment renders empty state when no apps authorized", () => {
|
||||
const html = <AppLaunchpadPageFragment apps={[]} isAdmin={false} />;
|
||||
const str = String(html);
|
||||
assertStringIncludes(str, "No Authorized Applications");
|
||||
assertStringIncludes(
|
||||
str,
|
||||
"You do not have active role grants for any workloads.",
|
||||
);
|
||||
});
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user