Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Updated Hustle for MongoDB, added last updated #160

Merged
merged 2 commits into from
Jan 4, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 0 additions & 18 deletions .github/workflows/schedule-leaderboard-update.yml

This file was deleted.

52 changes: 27 additions & 25 deletions app/(default)/api/hustle/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,8 @@ import axios from "axios";
// import { JSDOM } from "jsdom";
import puppeteer from "puppeteer";

import {
getFirestore,
doc,
setDoc,
getDoc,
} from "firebase/firestore";
import { app } from "@/Firebase";
import connectMongoDB from "@/lib/dbConnect";
import PbhustleModel from "@/models/PbHustel";
import { LatestModel, LeaderboardModel } from "@/models/PbHustel";

interface ContestRanking {
rank: number;
Expand All @@ -35,7 +28,7 @@ interface LeaderboardData {
export async function POST() {
try {
console.log("Initializing mongodb connection.");
await connectMongoDB()
await connectMongoDB();

const API_URL =
process.env.VJUDGE_CONTEST_API ||
Expand All @@ -51,9 +44,8 @@ export async function POST() {
const url = `https://vjudge.net/contest/${ccode}#rank`;
console.log(`Contest URL: ${url}`);


console.log("Fetching existing leaderboard data from Firestore.");
const leaderboardDoc = await PbhustleModel.findOne({name:"leaderboard"})
const leaderboardDoc = await LeaderboardModel.findOne({ name: "leaderboard" });

const existingData = leaderboardDoc as LeaderboardData | undefined;
console.log("Existing leaderboard data:", existingData);
Expand Down Expand Up @@ -95,11 +87,16 @@ export async function POST() {
await browser.close();

console.log("Updating latest contest results in Firestore.");
await PbhustleModel.findOneAndUpdate({
name:"latest",
results: latest,
updateTime: new Date(),
});
await LatestModel.findOneAndUpdate(
{ name: "latest" },
{
$set: {
results: latest,
updateTime: new Date(),
},
},
{ upsert: true }
);

let rankings: LeaderboardUser[] = existingData?.rankings || [];
console.log("Existing rankings:", rankings);
Expand Down Expand Up @@ -131,12 +128,17 @@ export async function POST() {

console.log("Final rankings:", rankings);
console.log("Updating leaderboard in Firestore.");
await PbhustleModel.findOneAndUpdate({
name:"leaderboard",
rankings,
updatedAt: new Date(),
lastContestCode: ccode,
});
await LeaderboardModel.findOneAndUpdate(
{ name: "leaderboard" },
{
$set: {
rankings,
updatedAt: new Date(),
lastContestCode: ccode,
},
},
{ upsert: true }
);

return NextResponse.json({
message: "Leaderboard updated successfully",
Expand All @@ -150,11 +152,11 @@ export async function POST() {

export async function GET() {
try {
await connectMongoDB()
await connectMongoDB();
console.log("Fetching latest contest results from Firestore.");
const latestDoc = await PbhustleModel.findOne({name:"latest"})
const latestDoc = await LatestModel.findOne({ name: "latest" });
console.log("Fetching leaderboard data from Firestore.");
const leaderboardDoc = await PbhustleModel.findOne({name:"leaderboard"})
const leaderboardDoc = await LeaderboardModel.findOne({ name: "leaderboard" });

console.log("Fetched data successfully:", {
latest: latestDoc,
Expand Down
35 changes: 15 additions & 20 deletions app/(default)/hustle/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,20 +20,23 @@ export default function ResultsTable() {
const [rankings, setRankings] = useState<Result[]>([]);
const [loading, setLoading] = useState(true);
const [isAdminLoggedIn, setIsAdminLoggedIn] = useState(false);
const [lastUpdated, setLastUpdated] = useState<Date | null>(null);

useEffect(() => {
const fetchData = async () => {
try {
const response = await fetch("/api/hustle");
const data = await response.json();
console.log(data)
console.log(data);
if (response.ok && data?.data) {
const allDocs = data.data;
const latestData: Result[] = allDocs.latest.results || [];
const rankingsData: Result[] = allDocs.leaderboard.rankings || [];
const updatedAt: Date = new Date(allDocs.leaderboard.updatedAt);

setLatestResults(latestData);
setRankings(rankingsData);
setLastUpdated(updatedAt);
} else {
console.error("Error in response:", data.error);
}
Expand Down Expand Up @@ -96,20 +99,6 @@ export default function ResultsTable() {
}
};

// const renderConsistency = (consistency?: number[]) => {
// if (!consistency) return "N/A";

// return consistency.map((value, index) => (
// <span
// key={index}
// className="mx-1"
// style={{ color: value === 1 ? "#00C853" : "red" }}
// >
// {value === 1 ? "✓" : "✗"}
// </span>
// ));
// };

const renderTable = (data: Result[], showConsistency: boolean) => (
<div className="overflow-x-auto shadow-xl rounded-xl border border-gray-700">
<table className="w-full text-sm text-left text-gray-300">
Expand Down Expand Up @@ -154,7 +143,6 @@ export default function ResultsTable() {
</p>
</motion.header>


<div className="flex justify-center space-x-6 mb-8">
{(["latest", "rankings"] as const).map((tabName) => (
<button
Expand Down Expand Up @@ -198,10 +186,17 @@ export default function ResultsTable() {
<div className="animate-spin rounded-full h-16 w-16 border-t-4 border-[#00FF66]"></div>
</div>
) : (
renderTable(
tab === "latest" ? latestResults : rankings,
tab === "rankings"
)
<>
{lastUpdated && (
<div className="text-center mb-4 text-white">
Last updated: {lastUpdated.toLocaleString()}
</div>
)}
{renderTable(
tab === "latest" ? latestResults : rankings,
tab === "rankings"
)}
</>
)}
</div>
</div>
Expand Down
95 changes: 82 additions & 13 deletions models/PbHustel.ts
Original file line number Diff line number Diff line change
@@ -1,25 +1,76 @@
import mongoose, { Document, Schema, Model } from "mongoose";

// Define the Pbhustle interface extending Document for Mongoose
export interface Pbhustle extends Document {
updatedAt?: Date;
lastContestCode?: string;
rankings?: {
/**
* Interface for the "latest" document
*/
export interface Latest extends Document {
name: string; // Always "latest"
results: {
rank: number;
name: string;
score: number;
consistency: number;
}[];
updateTime: Date;
}

// Define the schema for Pbhustle
const pbhustleSchema = new Schema<Pbhustle>(
/**
* Schema for the "latest" document
*/
const latestSchema = new Schema<Latest>(
{
updatedAt: {
name: {
type: String,
required: true,
default: "latest",
},
results: [
{
rank: {
type: Number,
required: true,
},
name: {
type: String,
required: true,
},
score: {
type: Number,
required: true,
},
},
],
updateTime: {
type: Date,
required: true,
},
lastContestCode: {
},
{ versionKey: false }
);

/**
* Interface for the "leaderboard" document
*/
export interface Leaderboard extends Document {
name: string; // Always "leaderboard"
rankings: {
rank: number;
name: string;
score: number;
consistency: number;
}[];
lastContestCode: string;
updatedAt: Date;
}

/**
* Schema for the "leaderboard" document
*/
const leaderboardSchema = new Schema<Leaderboard>(
{
name: {
type: String,
required: true,
default: "leaderboard",
},
rankings: [
{
Expand All @@ -35,12 +86,30 @@ const pbhustleSchema = new Schema<Pbhustle>(
type: Number,
required: true,
},
consistency: {
type: Number,
required: true,
},
},
],
lastContestCode: {
type: String,
required: true,
},
updatedAt: {
type: Date,
required: true,
},
},
{ versionKey: false }
);

// Create or retrieve the Pbhustle model
const PbhustleModel: Model<Pbhustle> = mongoose.models.hustles || mongoose.model<Pbhustle>("hustles", pbhustleSchema);
/**
* Models for "latest" and "leaderboard"
*/
export const LatestModel: Model<Latest> =
mongoose.models.latests || mongoose.model<Latest>("latests", latestSchema);

export default PbhustleModel;
export const LeaderboardModel: Model<Leaderboard> =
mongoose.models.leaderboards ||
mongoose.model<Leaderboard>("leaderboards", leaderboardSchema);
Loading