179}
180
181// API Routes
182
183// Create new event
184app.post("/api/events", async c => {
185 console.log(`๐ฏ [API] New event creation request`);
186
187 try {
189 const { name, password, location, csvContent } = body;
190
191 console.log(`๐ [API] Event details: "${name}", location: "${location || 'N/A'}"`);
192
193 if (!name || !password || !csvContent) {
205 const passwordHash = hashPassword(password);
206 const eventId = Math.floor(Date.now() / 1000); // Unix timestamp in seconds
207 console.log(`๐ [API] Creating event with ID: ${eventId}, name: "${name}", location: "${location || 'N/A'}"`);
208
209 try {
212 [eventId, name, passwordHash, location || null]
213 );
214 console.log(`โ
[API] Event successfully inserted into database with ID: ${eventId}`);
215 } catch (error) {
216 console.error(`๐ฅ [API] Failed to insert event:`, error);
217 throw error;
218 }
221 const verifyEventResult = await sqlite.execute(`SELECT id, name FROM ${TABLES.EVENTS} WHERE id = ?`, [eventId]);
222 const verifyEvent = verifyEventResult.rows || verifyEventResult;
223 console.log(`๐ [API] Event verification: found ${verifyEvent.length} events with ID ${eventId}`);
224 if (verifyEvent.length > 0) {
225 console.log(`๐ [API] Event details: ${JSON.stringify(verifyEvent[0])}`);
226 }
227
228 // Insert attendees
229 console.log(`๐ [API] Starting to insert ${attendees.length} attendees...`);
230 let insertedCount = 0;
231 for (const attendee of attendees) {
236 );
237 insertedCount++;
238 console.log(`๐ค [API] Inserted attendee ${insertedCount}/${attendees.length}: "${attendee.name}" (external_id: ${attendee.external_id || 'N/A'})`);
239 } catch (error) {
240 console.error(`๐ฅ [API] Failed to insert attendee "${attendee.name}":`, error);
241 throw error;
242 }
247 const verifyAttendees = verifyAttendeesResult.rows || verifyAttendeesResult;
248 const actualAttendeeCount = Number(verifyAttendees[0]?.count || 0);
249 console.log(`๐ [API] Attendee verification: expected ${attendees.length}, found ${actualAttendeeCount} in database`);
250
251 console.log(`โ
[API] Successfully added ${insertedCount} attendees to event ${eventId}`);
252
253 return c.json({
259
260 } catch (error) {
261 console.error(`๐ฅ [API] Error creating event:`, error);
262 return c.json({ error: "Internal server error" }, 500);
263 }
265
266// Get basic event info (public, no auth required)
267app.get("/api/:eventId", async c => {
268 const eventId = parseInt(c.req.param("eventId"));
269 console.log(`๐ [API] Fetching basic event details for event ${eventId}`);
270
271 try {
277
278 if (event.length === 0) {
279 console.log(`โ [API] Event ${eventId} not found`);
280 return c.json({ error: "Event not found" }, 404);
281 }
297 const checkedInCount = Number(checkedInCountRows[0]?.count || 0);
298
299 console.log(`๐ [API] Event ${eventId} found: ${attendeeCount} attendees, ${checkedInCount} checked in`);
300
301 return c.json({
311
312 } catch (error) {
313 console.error(`๐ฅ [API] Error fetching event details:`, error);
314 return c.json({ error: "Internal server error" }, 500);
315 }
317
318// Get attendee list for sign-in (names only, no sensitive info)
319app.get("/api/:eventId/attendees", async c => {
320 const eventId = parseInt(c.req.param("eventId"));
321 console.log(`๐ [API] Fetching attendees for event ${eventId}`);
322
323 try {
324 // First check if event exists
325 console.log(`๐ [API] Checking if event ${eventId} exists in table ${TABLES.EVENTS}`);
326 const eventCheckResult = await sqlite.execute(`
327 SELECT id FROM ${TABLES.EVENTS} WHERE id = ?
329
330 const eventCheck = eventCheckResult.rows || eventCheckResult;
331 console.log(`๐ [API] Event check result: found ${eventCheck.length} events with ID ${eventId}`);
332 if (eventCheck.length === 0) {
333 console.log(`โ [API] Event ${eventId} not found`);
334 return c.json({ error: "Event not found" }, 404);
335 }
336
337 // Get attendees with check-in status
338 console.log(`๐ [API] Querying attendees from table ${TABLES.ATTENDEES} for event ${eventId}`);
339 const attendeesResult = await sqlite.execute(`
340 SELECT a.id, a.name,
347
348 const attendees = attendeesResult.rows || attendeesResult;
349 console.log(`๐ [API] Found ${attendees.length} attendees for event ${eventId}`);
350
351 // Log first few attendees for debugging
352 if (attendees.length > 0) {
353 console.log(`๐ [API] First few attendees:`, attendees.slice(0, 3).map(a => ({ id: a.id, name: a.name, checked_in: a.checked_in })));
354 }
355
362 };
363
364 console.log(`๐ [API] Returning ${result.attendees.length} attendees to client`);
365 return c.json(result);
366
367 } catch (error) {
368 console.error(`๐ฅ [API] Error fetching attendees for event ${eventId}:`, error);
369 console.error(`๐ฅ [API] Error stack:`, error.stack);
370 return c.json({ error: "Internal server error" }, 500);
371 }
373
374// Sign in to event
375app.post("/api/:eventId/signin", async c => {
376 const eventId = parseInt(c.req.param("eventId"));
377
403 const existingCheckIn = existingCheckInResult.rows || existingCheckInResult;
404 if (existingCheckIn.length > 0) {
405 console.log(`โ ๏ธ [API] Attendee ${attendee[0].name} already signed in`);
406 // TODO: Consider security implications of multiple sign-in attempts
407 // For now, we'll allow it but flag it
420 );
421
422 console.log(`โ
[API] ${attendee[0].name} signed in to event ${eventId}`);
423
424 return c.json({
429
430 } catch (error) {
431 console.error(`๐ฅ [API] Error during sign-in:`, error);
432 return c.json({ error: "Internal server error" }, 500);
433 }
435
436// Authentication endpoint - login with password and create session
437app.post("/api/:eventId/auth", async c => {
438 const eventId = parseInt(c.req.param("eventId"));
439
471
472 } catch (error) {
473 console.error(`๐ฅ [API] Error during authentication:`, error);
474 return c.json({ error: "Internal server error" }, 500);
475 }
477
478// Logout endpoint
479app.post("/api/:eventId/logout", async c => {
480 clearSessionCookie(c);
481 return c.json({ success: true });
483
484// Get event details (session protected)
485app.get("/api/:eventId/details", authMiddleware, async c => {
486 const eventId = parseInt(c.req.param("eventId"));
487
531
532 } catch (error) {
533 console.error(`๐ฅ [API] Error fetching event details:`, error);
534 return c.json({ error: "Internal server error" }, 500);
535 }
537
538// Get analytics (session protected)
539app.get("/api/:eventId/analytics", authMiddleware, async c => {
540 const eventId = parseInt(c.req.param("eventId"));
541
590
591 } catch (error) {
592 console.error(`๐ฅ [API] Error fetching analytics:`, error);
593 return c.json({ error: "Internal server error" }, 500);
594 }
596
597// Export check-in data as CSV (session protected)
598app.get("/api/:eventId/export", authMiddleware, async c => {
599 const eventId = parseInt(c.req.param("eventId"));
600
649
650 } catch (error) {
651 console.error(`๐ฅ [API] Error exporting data:`, error);
652 return c.json({ error: "Internal server error" }, 500);
653 }