Skip to content

Commit f2f4ebe

Browse files
idoshamunclaude
andauthored
feat: add userId query param to log route (#3400)
Co-authored-by: Claude <noreply@anthropic.com>
1 parent 7152da4 commit f2f4ebe

3 files changed

Lines changed: 48 additions & 24 deletions

File tree

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,4 @@ debezium/conf/key.json
1111
debezium/data
1212
coverage
1313
.DS_Store
14+
node-compile-cache/

src/config.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ export const submissionAccessThreshold = parseInt(
3232
export const RESUME_BUCKET_NAME = process.env.RESUME_BUCKET_NAME;
3333
export const EMPLOYMENT_AGREEMENT_BUCKET_NAME =
3434
process.env.EMPLOYMENT_AGREEMENT_BUCKET_NAME;
35+
export const YEAR_IN_REVIEW_BUCKET_NAME = 'daily-dev-year-in-review';
3536

3637
export enum StorageTopic {
3738
Boot = 'boot',

src/routes/log.ts

Lines changed: 46 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,15 @@
11
import { FastifyInstance, FastifyReply } from 'fastify';
2+
import { Storage } from '@google-cloud/storage';
23
import { retryFetch } from '../integrations/retry';
3-
import { WEBAPP_MAGIC_IMAGE_PREFIX } from '../config';
4+
import {
5+
WEBAPP_MAGIC_IMAGE_PREFIX,
6+
YEAR_IN_REVIEW_BUCKET_NAME,
7+
} from '../config';
48
import createOrGetConnection from '../db';
59
import { User } from '../entity';
610

11+
const storage = new Storage();
12+
713
// Record types matching the webapp's RecordType enum
814
const RecordType = {
915
YEAR_ACTIVE: 'yearActive',
@@ -127,6 +133,29 @@ const MOCK_LOG_DATA = {
127133
shareCount: 24853,
128134
};
129135

136+
/**
137+
* Fetch user's year-in-review log data from GCS bucket.
138+
* Returns null if the file doesn't exist.
139+
*/
140+
async function fetchLogDataFromGCS(
141+
userId: string,
142+
): Promise<typeof MOCK_LOG_DATA | null> {
143+
try {
144+
const bucket = storage.bucket(YEAR_IN_REVIEW_BUCKET_NAME);
145+
const file = bucket.file(`2025/first_30/${userId}.json`);
146+
147+
const [exists] = await file.exists();
148+
if (!exists) {
149+
return null;
150+
}
151+
152+
const [content] = await file.download();
153+
return JSON.parse(content.toString());
154+
} catch (error) {
155+
return null;
156+
}
157+
}
158+
130159
// Valid card types for log share images (welcome is not shareable)
131160
const VALID_CARD_TYPES = [
132161
'total-impact',
@@ -228,22 +257,24 @@ export default async function (fastify: FastifyInstance): Promise<void> {
228257
/**
229258
* GET /log
230259
* Returns the user's log data for the year.
260+
* Accepts optional userId query param to fetch specific user's data from GCS.
231261
* Returns 404 if user doesn't have enough data (no JSON file exists).
232262
*/
233-
fastify.get('/', async (req, res) => {
234-
if (!req.userId) {
235-
return res.status(401).send({ error: 'Unauthorized' });
236-
}
237-
238-
// TODO: Replace with actual JSON file lookup based on req.userId
239-
// In production, this will check if the user's JSON file exists
240-
const userDataExists = true;
241-
242-
if (!userDataExists) {
243-
return res.status(404).send({ error: 'No log data available' });
263+
fastify.get<{
264+
Querystring: { userId?: string };
265+
}>('/', async (req, res) => {
266+
const { userId } = req.query;
267+
268+
// If userId query param is provided, fetch from GCS
269+
if (userId) {
270+
const logData = await fetchLogDataFromGCS(userId);
271+
if (!logData) {
272+
return res.status(404).send({ error: 'No log data available' });
273+
}
274+
return res.send(logData);
244275
}
245276

246-
// TODO: Replace mock data with actual user data from JSON file
277+
// Fall back to mock data when no userId provided
247278
return res.send(MOCK_LOG_DATA);
248279
});
249280

@@ -288,17 +319,8 @@ export default async function (fastify: FastifyInstance): Promise<void> {
288319
return res.status(404).send({ error: 'User not found' });
289320
}
290321

291-
// TODO: Replace with actual JSON file lookup based on req.userId
292-
// In production, this will check if the user's JSON file exists
293-
const userDataExists = true;
294-
295-
if (!userDataExists) {
296-
return res.status(404).send({ error: 'No log data available' });
297-
}
298-
299-
// Fetch user's log data
300-
// TODO: Replace with actual data fetching from JSON file
301-
const logData = MOCK_LOG_DATA;
322+
// Fetch user's log data from GCS, fall back to mock data
323+
const logData = (await fetchLogDataFromGCS(req.userId)) ?? MOCK_LOG_DATA;
302324

303325
// Extract only the data needed for this card type
304326
const cardData = extractCardData(card as CardType, logData);

0 commit comments

Comments
 (0)