Skip to content

Commit 21aecc5

Browse files
committed
merge
2 parents 62dd3cc + 7ee261f commit 21aecc5

11 files changed

Lines changed: 234 additions & 112 deletions

.env.example

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ WORKERS=
55
# Server Configuration
66
PORT=8000
77
NODE_ENV=development
8+
CACHE_REFRESH_HEADER=
9+
CACHE_REFRESH_SECRET=
810

911
# Database Configuration
1012
DATABASE_URL=

package-lock.json

Lines changed: 32 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,17 +29,20 @@
2929
"dependencies": {
3030
"@prisma/client": "^6.16.2",
3131
"dotenv": "^17.2.3",
32+
"escape-html": "^1.0.3",
3233
"express": "^5.1.0",
3334
"express-rate-limit": "^8.1.0",
3435
"firebase-admin": "^13.5.0",
3536
"helmet": "^8.1.0",
3637
"node-cron": "^4.2.1",
38+
"node-cache": "^5.1.2",
3739
"zod": "^4.1.12"
3840
},
3941
"devDependencies": {
4042
"@eslint/js": "^9.36.0",
4143
"@trivago/prettier-plugin-sort-imports": "^5.2.2",
4244
"@types/cookie-parser": "^1.4.9",
45+
"@types/escape-html": "^1.0.4",
4346
"@types/express": "^5.0.3",
4447
"@types/node": "^24.5.2",
4548
"@types/node-cron": "^3.0.11",

src/courses/courseController.ts

Lines changed: 0 additions & 101 deletions
This file was deleted.

src/courses/courses.schema.ts

Lines changed: 0 additions & 9 deletions
This file was deleted.

src/eateries/eateries.schema.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import { z } from 'zod';
2+
3+
export const getAllEateriesSchema = z.object({
4+
query: z.object({
5+
days: z.coerce.number().int().min(0).default(0),
6+
}),
7+
});
8+
9+
// Schema for validating cached eatery data
10+
export const EaterySchema = z.array(z.any()); // This will be validated by the scraper that sends the data

src/eateries/eateryController.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import type { Request, Response } from 'express';
2+
3+
import * as eateryService from './eateryService.js';
4+
5+
export const getAllEateries = async (req: Request, res: Response) => {
6+
const { days } = req.query;
7+
const eateries = await eateryService.getAllEateries(
8+
days as number | undefined,
9+
);
10+
return res.json(eateries);
11+
};
12+
13+
export const getEateryById = async (req: Request, res: Response) => {
14+
const eateryId = parseInt(req.params.eateryId, 10);
15+
const eatery = await eateryService.getEateryById(eateryId);
16+
return res.json(eatery);
17+
};

src/eateries/eateryRouter.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import { Router } from 'express';
2+
3+
import { validateRequest } from '../middleware/validateRequest.js';
4+
import { getAllEateriesSchema } from './eateries.schema.js';
5+
import { getAllEateries, getEateryById } from './eateryController.js';
6+
7+
export const eateryRouter = Router();
8+
9+
eateryRouter.get('/', validateRequest(getAllEateriesSchema), getAllEateries);
10+
eateryRouter.get('/:eateryId', getEateryById);

src/eateries/eateryService.ts

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
import type { Event } from '@prisma/client';
2+
3+
import { prisma } from '../prisma.js';
4+
import { NotFoundError } from '../utils/AppError.js';
5+
import { getAllEateriesData } from '../utils/cache.js';
6+
7+
export const getAllEateries = async (days: number = 0) => {
8+
// Calculate date range for filtering events
9+
// days=0 means today, days=1 means tomorrow, etc.
10+
const now = new Date();
11+
const targetDay = new Date(now);
12+
targetDay.setDate(now.getDate() + days);
13+
14+
const startOfDay = new Date(targetDay);
15+
startOfDay.setHours(0, 0, 0, 0);
16+
17+
const endOfDay = new Date(targetDay);
18+
endOfDay.setHours(23, 59, 59, 999);
19+
20+
// Try to get from cache first
21+
try {
22+
const cachedEateries = getAllEateriesData();
23+
24+
// Filter events to only include those on the specified day
25+
const filteredEateries = cachedEateries.map((eatery) => ({
26+
...eatery,
27+
events: eatery.events.filter((event: Event) => {
28+
const eventStart = new Date(event.startTimestamp);
29+
const eventEnd = new Date(event.endTimestamp);
30+
31+
// Include event if it overlaps with the target day
32+
return eventStart <= endOfDay && eventEnd >= startOfDay;
33+
}),
34+
}));
35+
36+
return filteredEateries;
37+
} catch {
38+
// If cache is cold (should never happen), fall back to database
39+
const eateries = await prisma.eatery.findMany({
40+
include: {
41+
events: {
42+
where: {
43+
startTimestamp: {
44+
lte: endOfDay,
45+
},
46+
endTimestamp: {
47+
gte: startOfDay,
48+
},
49+
},
50+
},
51+
},
52+
});
53+
54+
return eateries;
55+
}
56+
};
57+
58+
export const getEateryById = async (eateryId: number) => {
59+
// Try to get eatery from cache first
60+
try {
61+
const cachedEateries = getAllEateriesData();
62+
const eatery = cachedEateries.find((e) => e.id === eateryId);
63+
64+
if (!eatery) {
65+
throw new NotFoundError('Eatery not found');
66+
}
67+
68+
return eatery;
69+
} catch (error) {
70+
// If cache is cold or eatery not found in cache, fall back to database
71+
if (error instanceof NotFoundError) {
72+
throw error;
73+
}
74+
75+
const eatery = await prisma.eatery.findUnique({
76+
where: { id: eateryId },
77+
include: {
78+
events: {
79+
include: {
80+
menu: {
81+
include: {
82+
items: {
83+
include: {
84+
dietaryPreferences: true,
85+
allergens: true,
86+
},
87+
},
88+
},
89+
},
90+
userEventVotes: true,
91+
},
92+
orderBy: {
93+
startTimestamp: 'asc',
94+
},
95+
},
96+
},
97+
});
98+
99+
if (!eatery) {
100+
throw new NotFoundError('Eatery not found');
101+
}
102+
103+
return eatery;
104+
}
105+
};

src/server.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import express from 'express';
55
import type { Request, Response } from 'express';
66

77
import authRouter from './auth/authRouter.js';
8-
import courseRouter from './courses/courseRouter.js';
98
import { requireAuth } from './middleware/authentication.js';
109
import { globalErrorHandler } from './middleware/errorHandler.js';
1110
import { requestLogger } from './middleware/logger.js';
@@ -51,7 +50,6 @@ router.use('/auth', authRouter);
5150

5251
// Protected routes (require GET authentication)
5352
router.use(requireAuth);
54-
router.use('/courses', courseRouter);
5553

5654
app.use(router);
5755

0 commit comments

Comments
 (0)