193 lines
5.3 KiB
TypeScript
193 lines
5.3 KiB
TypeScript
import { sqlWrapper } from "../../core/db.ts";
|
|
|
|
export async function rotateEventPin(
|
|
eventId: string,
|
|
userId: string,
|
|
isGlobalAdmin: boolean,
|
|
): Promise<string | null> {
|
|
const randPin = Math.floor(100000 + Math.random() * 900000).toString();
|
|
const formattedPin = `${randPin.slice(0, 3)}-${randPin.slice(3)}`;
|
|
|
|
const result = await sqlWrapper.sql`
|
|
UPDATE event_passes
|
|
SET pin_code = ${formattedPin}
|
|
WHERE id = ${eventId}
|
|
AND (created_by = ${userId} OR ${isGlobalAdmin})
|
|
AND is_active = TRUE
|
|
RETURNING pin_code
|
|
`;
|
|
|
|
if (!result || result.length === 0) return null;
|
|
return result[0].pin_code;
|
|
}
|
|
|
|
export async function getEventAttendees(
|
|
eventId: string,
|
|
userId: string,
|
|
isGlobalAdmin: boolean,
|
|
) {
|
|
const event = await sqlWrapper.sql`
|
|
SELECT slug FROM event_passes
|
|
WHERE id = ${eventId}
|
|
AND (created_by = ${userId} OR ${isGlobalAdmin})
|
|
`;
|
|
|
|
if (!event || event.length === 0) return null;
|
|
|
|
const slug = event[0].slug;
|
|
const guestPattern = `guest_${slug}_%`;
|
|
|
|
const users = await sqlWrapper.sql`
|
|
SELECT id, username, display_name, created_at
|
|
FROM users
|
|
WHERE username LIKE ${guestPattern}
|
|
ORDER BY created_at DESC
|
|
`;
|
|
|
|
return users;
|
|
}
|
|
|
|
export async function getEventBySlugOrPin(code: string) {
|
|
const rawNormalized = code.trim().toLowerCase();
|
|
const pinNormalized = code.trim().replace(/[-\s]/g, "");
|
|
|
|
const eventLookup = await sqlWrapper.sql`
|
|
SELECT * FROM event_passes
|
|
WHERE (LOWER(slug) = ${rawNormalized} OR REPLACE(pin_code, '-', '') = ${pinNormalized})
|
|
AND is_active = TRUE
|
|
AND (expires_at IS NULL OR expires_at > NOW())
|
|
`;
|
|
|
|
if (!eventLookup || eventLookup.length === 0) return null;
|
|
return eventLookup[0];
|
|
}
|
|
|
|
export async function incrementEventSeats(eventId: string) {
|
|
const updateResult = await sqlWrapper.sql`
|
|
UPDATE event_passes
|
|
SET seats_claimed = seats_claimed + 1
|
|
WHERE id = ${eventId}
|
|
AND (max_seats = 0 OR seats_claimed < max_seats)
|
|
RETURNING *
|
|
`;
|
|
if (!updateResult || updateResult.length === 0) return null;
|
|
return updateResult[0];
|
|
}
|
|
|
|
export async function createGuestUser(
|
|
guestUuid: string,
|
|
username: string,
|
|
displayName: string,
|
|
eventId: string,
|
|
) {
|
|
await sqlWrapper.sql`
|
|
INSERT INTO users (id, username, display_name, account_status, event_pass_id)
|
|
VALUES (${guestUuid}, ${username}, ${displayName}, 'guest', ${eventId})
|
|
ON CONFLICT DO NOTHING
|
|
`;
|
|
}
|
|
|
|
export async function getAppById(appId: string) {
|
|
const apps = await sqlWrapper
|
|
.sql`SELECT name, domain FROM apps WHERE id = ${appId}`;
|
|
if (apps.length > 0) return apps[0];
|
|
return null;
|
|
}
|
|
|
|
export async function endEvent(
|
|
eventId: string,
|
|
userId: string,
|
|
isGlobalAdmin: boolean,
|
|
) {
|
|
const result = await sqlWrapper.sql`
|
|
UPDATE event_passes
|
|
SET is_active = FALSE
|
|
WHERE id = ${eventId}
|
|
AND (created_by = ${userId} OR ${isGlobalAdmin})
|
|
RETURNING slug
|
|
`;
|
|
if (!result || result.length === 0) return null;
|
|
return result[0].slug;
|
|
}
|
|
|
|
export async function createEventSession(
|
|
sessionId: string,
|
|
userId: string,
|
|
label: string,
|
|
customScopes: string[],
|
|
expiresAt: Date,
|
|
) {
|
|
await sqlWrapper.sql`
|
|
INSERT INTO sessions (id, user_id, label, is_agent, custom_scopes, expires_at)
|
|
VALUES (${sessionId}, ${userId}, ${label}, false, ${customScopes}, ${expiresAt})
|
|
`;
|
|
}
|
|
|
|
export async function expandEventSeats(
|
|
eventId: string,
|
|
addSeats: number,
|
|
userId: string,
|
|
isGlobalAdmin: boolean,
|
|
) {
|
|
const eventResult = await sqlWrapper.sql`
|
|
UPDATE event_passes
|
|
SET max_seats = max_seats + ${addSeats}
|
|
WHERE id = ${eventId}
|
|
AND (created_by = ${userId} OR ${isGlobalAdmin})
|
|
AND is_active = TRUE
|
|
RETURNING max_seats
|
|
`;
|
|
if (!eventResult || eventResult.length === 0) return null;
|
|
return eventResult[0].max_seats;
|
|
}
|
|
|
|
export async function createEventPass(
|
|
name: string,
|
|
slug: string,
|
|
pinCode: string,
|
|
appId: string | null,
|
|
role: string,
|
|
maxSeats: number,
|
|
lifespanHours: number,
|
|
userId: string,
|
|
expiresAt: Date,
|
|
) {
|
|
const result = await sqlWrapper.sql`
|
|
INSERT INTO event_passes (name, slug, pin_code, app_id, role, max_seats, lifespan_hours, created_by, expires_at)
|
|
VALUES (${name}, ${slug}, ${pinCode}, ${appId || null}, ${role}, ${
|
|
Number(maxSeats)
|
|
}, ${Number(lifespanHours)}, ${userId}, ${expiresAt.toISOString()})
|
|
RETURNING *
|
|
`;
|
|
if (!result || result.length === 0) return null;
|
|
return result[0];
|
|
}
|
|
|
|
export async function getEventById(eventId: string) {
|
|
const result = await sqlWrapper.sql`
|
|
SELECT * FROM event_passes WHERE id = ${eventId}
|
|
`;
|
|
if (!result || result.length === 0) return null;
|
|
return result[0];
|
|
}
|
|
|
|
export async function getEventBySlug(slug: string) {
|
|
const result = await sqlWrapper.sql`
|
|
SELECT * FROM event_passes WHERE slug = ${slug} AND is_active = TRUE
|
|
`;
|
|
if (!result || result.length === 0) return null;
|
|
return result[0];
|
|
}
|
|
|
|
export async function getUserEventPasses(userId: string) {
|
|
const result = await sqlWrapper.sql`
|
|
SELECT ep.*, a.name as app_name, a.domain as app_domain
|
|
FROM event_passes ep
|
|
LEFT JOIN apps a ON ep.app_id = a.id
|
|
WHERE ep.created_by = ${userId}
|
|
AND ep.is_active = TRUE
|
|
ORDER BY ep.created_at DESC
|
|
`;
|
|
return result;
|
|
}
|