mirror of
https://github.com/mudabbir-ahmad/peworkshop.git
synced 2026-10-07 19:50:20 +00:00
fixed the map, made it so the map is scrollable and synced the timing between the admin page and map page. They now share the same elapsed time. need to fix map css for altering the svg.
Grey = cant click Red = current Green = complete blue = skipped? Need to add Clue page Need to fix Leaderboard.
This commit is contained in:
1 parent
e7ad53643c
commit
16319f1333
14 files changed
+791
-472
No files matched your search
@@ -1,70 +1,97 @@
|
||||
import { queryOne, run } from "@/lib/db";
|
||||
import { cookies } from "next/headers";
|
||||
import { verifyToken } from "@/app/api/auth/[...nextauth]/route";
|
||||
import { queryOne } from "@/lib/db";
|
||||
import { getToken } from "next-auth/jwt";
|
||||
|
||||
export const dynamic = "force-dynamic"; // Disable caching
|
||||
|
||||
// GET endpoint to retrieve a specific clue
|
||||
export async function GET(request, { params }) {
|
||||
const { clueId } = params;
|
||||
|
||||
export async function GET(request, context) {
|
||||
try {
|
||||
// Check if the hunt is active first
|
||||
const huntActiveSetting = await queryOne(
|
||||
"SELECT value FROM settings WHERE key = 'hunt_active'"
|
||||
);
|
||||
const huntActive = huntActiveSetting && huntActiveSetting.value === "true";
|
||||
const token = await getToken({
|
||||
req: request,
|
||||
secret:
|
||||
process.env.NEXTAUTH_SECRET ||
|
||||
"your-fallback-secret-should-be-at-least-32-chars",
|
||||
});
|
||||
|
||||
// Only verify authentication when hunt is not active
|
||||
if (!huntActive) {
|
||||
const cookieStore = await cookies();
|
||||
const sessionToken =
|
||||
cookieStore.get("next-auth.session-token")?.value ||
|
||||
cookieStore.get("__Secure-next-auth.session-token")?.value;
|
||||
|
||||
if (!sessionToken) {
|
||||
return Response.json(
|
||||
{ error: "Unauthorized", clue: null },
|
||||
{ status: 401, headers: { "Content-Type": "application/json" } }
|
||||
);
|
||||
}
|
||||
|
||||
const userData = verifyToken(sessionToken);
|
||||
if (!userData) {
|
||||
return Response.json(
|
||||
{ error: "Invalid session", clue: null },
|
||||
{ status: 401, headers: { "Content-Type": "application/json" } }
|
||||
);
|
||||
}
|
||||
|
||||
// Admin can see clues even if hunt is not active
|
||||
if (userData.role !== "admin") {
|
||||
return Response.json(
|
||||
{ error: "Hunt is not active", clue: null },
|
||||
{ headers: { "Content-Type": "application/json" } }
|
||||
);
|
||||
}
|
||||
if (!token) {
|
||||
return Response.json({ error: "Unauthorized" }, { status: 401 });
|
||||
}
|
||||
|
||||
// Fetch the specific clue
|
||||
const clue = await queryOne("SELECT * FROM clues WHERE id = ?", [clueId]);
|
||||
|
||||
if (!clue) {
|
||||
// Check if user has a team
|
||||
if (!token.teamId) {
|
||||
return Response.json(
|
||||
{ error: "Clue not found", clue: null },
|
||||
{ status: 404, headers: { "Content-Type": "application/json" } }
|
||||
{ error: "You must be part of a team to view clues" },
|
||||
{ status: 403 }
|
||||
);
|
||||
}
|
||||
|
||||
const { clueId } = context.params;
|
||||
|
||||
// Validate clueId is a number
|
||||
if (isNaN(parseInt(clueId))) {
|
||||
return Response.json({ error: "Invalid clue ID" }, { status: 400 });
|
||||
}
|
||||
|
||||
// Get the specific clue
|
||||
const clue = await queryOne(
|
||||
"SELECT id, title, description, location, x_coord, y_coord FROM clues WHERE id = ?",
|
||||
[clueId]
|
||||
);
|
||||
|
||||
if (!clue) {
|
||||
return Response.json({ error: "Clue not found" }, { status: 404 });
|
||||
}
|
||||
|
||||
// Check if this team has found this clue before
|
||||
const found = await queryOne(
|
||||
"SELECT * FROM team_clues WHERE team_id = ? AND clue_id = ?",
|
||||
[token.teamId, clueId]
|
||||
);
|
||||
|
||||
// If not found yet, mark it as found now
|
||||
if (!found) {
|
||||
try {
|
||||
// First ensure the team_clues table exists
|
||||
await queryOne(`
|
||||
CREATE TABLE IF NOT EXISTS team_clues (
|
||||
team_id INTEGER NOT NULL,
|
||||
clue_id INTEGER NOT NULL,
|
||||
found_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (team_id, clue_id),
|
||||
FOREIGN KEY (team_id) REFERENCES teams(id),
|
||||
FOREIGN KEY (clue_id) REFERENCES clues(id)
|
||||
)
|
||||
`);
|
||||
|
||||
// Record that the team found this clue
|
||||
await queryOne(
|
||||
"INSERT INTO team_clues (team_id, clue_id) VALUES (?, ?)",
|
||||
[token.teamId, clueId]
|
||||
);
|
||||
} catch (err) {
|
||||
console.error("Error marking clue as found:", err);
|
||||
// Continue even if there's an error recording the find
|
||||
}
|
||||
}
|
||||
|
||||
return Response.json(
|
||||
{ clue },
|
||||
{ headers: { "Content-Type": "application/json" } }
|
||||
{
|
||||
...clue,
|
||||
found: !!found,
|
||||
foundNow: !found,
|
||||
},
|
||||
{
|
||||
headers: {
|
||||
"Cache-Control": "no-store, no-cache, must-revalidate",
|
||||
Pragma: "no-cache",
|
||||
Expires: "0",
|
||||
},
|
||||
}
|
||||
);
|
||||
} catch (error) {
|
||||
console.error("Error fetching clue details:", error);
|
||||
console.error("Error fetching clue:", error);
|
||||
return Response.json(
|
||||
{ error: "Failed to fetch clue details: " + error.message, clue: null },
|
||||
{ status: 500, headers: { "Content-Type": "application/json" } }
|
||||
{ error: "Failed to fetch clue: " + error.message },
|
||||
{ status: 500 }
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user