feat: Implement deals repository and routes for fetching best watched item prices
Some checks failed
Deploy to Test Environment / deploy-to-test (push) Has been cancelled
Some checks failed
Deploy to Test Environment / deploy-to-test (push) Has been cancelled
- Added a new DealsRepository class to interact with the database for fetching the best sale prices of watched items. - Created a new route `/api/users/deals/best-watched-prices` to handle requests for the best prices of items the authenticated user is watching. - Enhanced logging in the FlyerDataTransformer and FlyerProcessingService for better traceability. - Updated tests to ensure proper logging and functionality in the FlyerProcessingService. - Refactored logger client to support structured logging for better consistency across the application.
This commit is contained in:
@@ -4,8 +4,7 @@ import { z } from 'zod';
|
||||
import passport from './passport.routes';
|
||||
import { budgetRepo } from '../services/db/index.db';
|
||||
import { logger } from '../services/logger.server';
|
||||
import { UserProfile } from '../types';
|
||||
import { ForeignKeyConstraintError } from '../services/db/errors.db';
|
||||
import type { UserProfile } from '../types';
|
||||
import { validateRequest } from '../middleware/validation.middleware';
|
||||
|
||||
const router = express.Router();
|
||||
@@ -49,10 +48,10 @@ router.use(passport.authenticate('jwt', { session: false }));
|
||||
router.get('/', async (req, res, next: NextFunction) => {
|
||||
const user = req.user as UserProfile;
|
||||
try {
|
||||
const budgets = await budgetRepo.getBudgetsForUser(user.user_id);
|
||||
const budgets = await budgetRepo.getBudgetsForUser(user.user_id, req.log);
|
||||
res.json(budgets);
|
||||
} catch (error) {
|
||||
logger.error('Error fetching budgets:', { error, userId: user.user_id });
|
||||
req.log.error({ err: error, userId: user.user_id }, 'Error fetching budgets');
|
||||
next(error);
|
||||
}
|
||||
});
|
||||
@@ -63,10 +62,10 @@ router.get('/', async (req, res, next: NextFunction) => {
|
||||
router.post('/', validateRequest(createBudgetSchema), async (req, res, next: NextFunction) => {
|
||||
const user = req.user as UserProfile;
|
||||
try {
|
||||
const newBudget = await budgetRepo.createBudget(user.user_id, req.body);
|
||||
const newBudget = await budgetRepo.createBudget(user.user_id, req.body, req.log);
|
||||
res.status(201).json(newBudget);
|
||||
} catch (error: unknown) {
|
||||
logger.error('Error creating budget:', { error, userId: user.user_id, body: req.body });
|
||||
req.log.error({ err: error, userId: user.user_id, body: req.body }, 'Error creating budget');
|
||||
next(error);
|
||||
}
|
||||
});
|
||||
@@ -78,10 +77,10 @@ router.put('/:id', validateRequest(updateBudgetSchema), async (req, res, next: N
|
||||
const user = req.user as UserProfile;
|
||||
const budgetId = req.params.id as unknown as number;
|
||||
try {
|
||||
const updatedBudget = await budgetRepo.updateBudget(budgetId, user.user_id, req.body);
|
||||
const updatedBudget = await budgetRepo.updateBudget(budgetId, user.user_id, req.body, req.log);
|
||||
res.json(updatedBudget);
|
||||
} catch (error: unknown) {
|
||||
logger.error('Error updating budget:', { error, userId: user.user_id, budgetId });
|
||||
req.log.error({ err: error, userId: user.user_id, budgetId }, 'Error updating budget');
|
||||
next(error);
|
||||
}
|
||||
});
|
||||
@@ -93,10 +92,10 @@ router.delete('/:id', validateRequest(budgetIdParamSchema), async (req, res, nex
|
||||
const user = req.user as UserProfile;
|
||||
const budgetId = req.params.id as unknown as number;
|
||||
try {
|
||||
await budgetRepo.deleteBudget(budgetId, user.user_id);
|
||||
await budgetRepo.deleteBudget(budgetId, user.user_id, req.log);
|
||||
res.status(204).send(); // No Content
|
||||
} catch (error: unknown) {
|
||||
logger.error('Error deleting budget:', { error, userId: user.user_id, budgetId });
|
||||
req.log.error({ err: error, userId: user.user_id, budgetId }, 'Error deleting budget');
|
||||
next(error);
|
||||
}
|
||||
});
|
||||
@@ -110,10 +109,10 @@ router.get('/spending-analysis', validateRequest(spendingAnalysisSchema), async
|
||||
const { startDate, endDate } = req.query;
|
||||
|
||||
try {
|
||||
const spendingData = await budgetRepo.getSpendingByCategory(user.user_id, startDate as string, endDate as string);
|
||||
const spendingData = await budgetRepo.getSpendingByCategory(user.user_id, startDate as string, endDate as string, req.log);
|
||||
res.json(spendingData);
|
||||
} catch (error) {
|
||||
logger.error('Error fetching spending analysis:', { error, userId: user.user_id, startDate, endDate });
|
||||
req.log.error({ err: error, userId: user.user_id, startDate, endDate }, 'Error fetching spending analysis');
|
||||
next(error);
|
||||
}
|
||||
});
|
||||
|
||||
34
src/routes/deals.routes.ts
Normal file
34
src/routes/deals.routes.ts
Normal file
@@ -0,0 +1,34 @@
|
||||
// src/routes/deals.routes.ts
|
||||
import express, { type Request, type Response, type NextFunction } from 'express';
|
||||
import passport from './passport.routes';
|
||||
import { dealsRepo } from '../services/db/deals.db';
|
||||
import type { UserProfile } from '../types';
|
||||
|
||||
const router = express.Router();
|
||||
|
||||
// --- Middleware for all deal routes ---
|
||||
|
||||
// Per ADR-002, all routes in this file require an authenticated user.
|
||||
// We apply the standard passport JWT middleware at the router level.
|
||||
router.use(passport.authenticate('jwt', { session: false }));
|
||||
|
||||
/**
|
||||
* @route GET /api/users/deals/best-watched-prices
|
||||
* @description Fetches the best current sale price for each of the authenticated user's watched items.
|
||||
* @access Private
|
||||
*/
|
||||
router.get('/best-watched-prices', async (req: Request, res: Response, next: NextFunction) => {
|
||||
const user = req.user as UserProfile;
|
||||
try {
|
||||
// The controller logic is simple enough to be handled directly in the route,
|
||||
// consistent with other simple GET routes in the project.
|
||||
const deals = await dealsRepo.findBestPricesForWatchedItems(user.user_id);
|
||||
req.log.info({ dealCount: deals.length, userId: user.user_id }, 'Successfully fetched best watched item deals.');
|
||||
res.status(200).json(deals);
|
||||
} catch (error) {
|
||||
req.log.error({ err: error, userId: user.user_id }, 'Error fetching best watched item deals.');
|
||||
next(error); // Pass errors to the global error handler
|
||||
}
|
||||
});
|
||||
|
||||
export default router;
|
||||
Reference in New Issue
Block a user