feat: Enhance logging and type safety across various components and services
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
This commit is contained in:
@@ -4,21 +4,19 @@ import passport from './passport.routes';
|
||||
import { isAdmin } from './passport.routes'; // Correctly imported
|
||||
import multer from 'multer';// --- Zod Schemas for Admin Routes (as per ADR-003) ---
|
||||
import { z } from 'zod';
|
||||
import crypto from 'crypto';
|
||||
|
||||
import * as db from '../services/db/index.db';
|
||||
import { logger } from '../services/logger.server';
|
||||
import { UserProfile } from '../types';
|
||||
import { clearGeocodeCache } from '../services/geocodingService.server';
|
||||
import { geocodingService } from '../services/geocodingService.server';
|
||||
import { requireFileUpload } from '../middleware/fileUpload.middleware'; // This was a duplicate, fixed.
|
||||
import { ForeignKeyConstraintError, NotFoundError, ValidationError } from '../services/db/errors.db';
|
||||
import { NotFoundError, ValidationError } from '../services/db/errors.db';
|
||||
import { validateRequest } from '../middleware/validation.middleware';
|
||||
|
||||
// --- Bull Board (Job Queue UI) Imports ---
|
||||
import { createBullBoard } from '@bull-board/api';
|
||||
import { BullMQAdapter } from '@bull-board/api/bullMQAdapter';
|
||||
import { ExpressAdapter } from '@bull-board/express';
|
||||
import { render, screen } from '@testing-library/react';
|
||||
|
||||
import type { Queue } from 'bullmq';
|
||||
import { backgroundJobService } from '../services/backgroundJobService';
|
||||
@@ -108,7 +106,7 @@ router.use(passport.authenticate('jwt', { session: false }), isAdmin);
|
||||
|
||||
router.get('/corrections', async (req, res, next: NextFunction) => {
|
||||
try {
|
||||
const corrections = await db.adminRepo.getSuggestedCorrections();
|
||||
const corrections = await db.adminRepo.getSuggestedCorrections(req.log);
|
||||
res.json(corrections);
|
||||
} catch (error) {
|
||||
next(error);
|
||||
@@ -117,7 +115,7 @@ router.get('/corrections', async (req, res, next: NextFunction) => {
|
||||
|
||||
router.get('/brands', async (req, res, next: NextFunction) => {
|
||||
try {
|
||||
const brands = await db.flyerRepo.getAllBrands();
|
||||
const brands = await db.flyerRepo.getAllBrands(req.log);
|
||||
res.json(brands);
|
||||
} catch (error) {
|
||||
next(error);
|
||||
@@ -126,7 +124,7 @@ router.get('/brands', async (req, res, next: NextFunction) => {
|
||||
|
||||
router.get('/stats', async (req, res, next: NextFunction) => {
|
||||
try {
|
||||
const stats = await db.adminRepo.getApplicationStats();
|
||||
const stats = await db.adminRepo.getApplicationStats(req.log);
|
||||
res.json(stats);
|
||||
} catch (error) {
|
||||
next(error);
|
||||
@@ -135,7 +133,7 @@ router.get('/stats', async (req, res, next: NextFunction) => {
|
||||
|
||||
router.get('/stats/daily', async (req, res, next: NextFunction) => {
|
||||
try {
|
||||
const dailyStats = await db.adminRepo.getDailyStatsForLast30Days();
|
||||
const dailyStats = await db.adminRepo.getDailyStatsForLast30Days(req.log);
|
||||
res.json(dailyStats);
|
||||
} catch (error) {
|
||||
next(error);
|
||||
@@ -145,7 +143,7 @@ router.get('/stats/daily', async (req, res, next: NextFunction) => {
|
||||
router.post('/corrections/:id/approve', validateRequest(numericIdParamSchema('id')), async (req, res, next: NextFunction) => {
|
||||
try {
|
||||
const correctionId = req.params.id as unknown as number;
|
||||
await db.adminRepo.approveCorrection(correctionId);
|
||||
await db.adminRepo.approveCorrection(correctionId, req.log);
|
||||
res.status(200).json({ message: 'Correction approved successfully.' });
|
||||
} catch (error) {
|
||||
next(error);
|
||||
@@ -155,7 +153,7 @@ router.post('/corrections/:id/approve', validateRequest(numericIdParamSchema('id
|
||||
router.post('/corrections/:id/reject', validateRequest(numericIdParamSchema('id')), async (req, res, next: NextFunction) => {
|
||||
try {
|
||||
const correctionId = req.params.id as unknown as number;
|
||||
await db.adminRepo.rejectCorrection(correctionId);
|
||||
await db.adminRepo.rejectCorrection(correctionId, req.log);
|
||||
res.status(200).json({ message: 'Correction rejected successfully.' });
|
||||
} catch (error) {
|
||||
next(error);
|
||||
@@ -166,7 +164,7 @@ router.put('/corrections/:id', validateRequest(updateCorrectionSchema), async (r
|
||||
const correctionId = req.params.id as unknown as number;
|
||||
const { suggested_value } = req.body;
|
||||
try {
|
||||
const updatedCorrection = await db.adminRepo.updateSuggestedCorrection(correctionId, suggested_value);
|
||||
const updatedCorrection = await db.adminRepo.updateSuggestedCorrection(correctionId, suggested_value, req.log);
|
||||
res.status(200).json(updatedCorrection);
|
||||
} catch (error) {
|
||||
next(error);
|
||||
@@ -177,7 +175,7 @@ router.put('/recipes/:id/status', validateRequest(updateRecipeStatusSchema), asy
|
||||
const recipeId = req.params.id as unknown as number;
|
||||
const { status } = req.body;
|
||||
try {
|
||||
const updatedRecipe = await db.adminRepo.updateRecipeStatus(recipeId, status); // This is still a standalone function in admin.db.ts
|
||||
const updatedRecipe = await db.adminRepo.updateRecipeStatus(recipeId, status, req.log); // This is still a standalone function in admin.db.ts
|
||||
res.status(200).json(updatedRecipe);
|
||||
} catch (error) {
|
||||
next(error); // Pass all errors to the central error handler
|
||||
@@ -193,9 +191,9 @@ router.post('/brands/:id/logo', validateRequest(numericIdParamSchema('id')), upl
|
||||
throw new ValidationError([], 'Logo image file is missing.');
|
||||
}
|
||||
const logoUrl = `/assets/${req.file.filename}`;
|
||||
await db.adminRepo.updateBrandLogo(brandId, logoUrl);
|
||||
await db.adminRepo.updateBrandLogo(brandId, logoUrl, req.log);
|
||||
|
||||
logger.info(`Brand logo updated for brand ID: ${brandId}`, { brandId, logoUrl });
|
||||
logger.info({ brandId, logoUrl }, `Brand logo updated for brand ID: ${brandId}`);
|
||||
res.status(200).json({ message: 'Brand logo updated successfully.', logoUrl });
|
||||
} catch (error) {
|
||||
next(error);
|
||||
@@ -204,7 +202,7 @@ router.post('/brands/:id/logo', validateRequest(numericIdParamSchema('id')), upl
|
||||
|
||||
router.get('/unmatched-items', async (req, res, next: NextFunction) => {
|
||||
try {
|
||||
const items = await db.adminRepo.getUnmatchedFlyerItems();
|
||||
const items = await db.adminRepo.getUnmatchedFlyerItems(req.log);
|
||||
res.json(items);
|
||||
} catch (error) {
|
||||
next(error);
|
||||
@@ -220,7 +218,7 @@ router.delete('/recipes/:recipeId', validateRequest(numericIdParamSchema('recipe
|
||||
|
||||
try {
|
||||
// The isAdmin flag bypasses the ownership check in the repository method.
|
||||
await db.recipeRepo.deleteRecipe(recipeId, adminUser.user_id, true);
|
||||
await db.recipeRepo.deleteRecipe(recipeId, adminUser.user_id, true, req.log);
|
||||
res.status(204).send();
|
||||
} catch (error: unknown) {
|
||||
next(error);
|
||||
@@ -233,7 +231,7 @@ router.delete('/recipes/:recipeId', validateRequest(numericIdParamSchema('recipe
|
||||
router.delete('/flyers/:flyerId', validateRequest(numericIdParamSchema('flyerId')), async (req, res, next: NextFunction) => {
|
||||
const flyerId = req.params.flyerId as unknown as number;
|
||||
try {
|
||||
await db.flyerRepo.deleteFlyer(flyerId);
|
||||
await db.flyerRepo.deleteFlyer(flyerId, req.log);
|
||||
res.status(204).send();
|
||||
} catch (error: unknown) {
|
||||
next(error);
|
||||
@@ -244,7 +242,7 @@ router.put('/comments/:id/status', validateRequest(updateCommentStatusSchema), a
|
||||
const commentId = req.params.id as unknown as number;
|
||||
const { status } = req.body;
|
||||
try {
|
||||
const updatedComment = await db.adminRepo.updateRecipeCommentStatus(commentId, status); // This is still a standalone function in admin.db.ts
|
||||
const updatedComment = await db.adminRepo.updateRecipeCommentStatus(commentId, status, req.log); // This is still a standalone function in admin.db.ts
|
||||
res.status(200).json(updatedComment);
|
||||
} catch (error: unknown) {
|
||||
next(error);
|
||||
@@ -253,7 +251,7 @@ router.put('/comments/:id/status', validateRequest(updateCommentStatusSchema), a
|
||||
|
||||
router.get('/users', async (req, res, next: NextFunction) => {
|
||||
try {
|
||||
const users = await db.adminRepo.getAllUsers();
|
||||
const users = await db.adminRepo.getAllUsers(req.log);
|
||||
res.json(users);
|
||||
} catch (error) {
|
||||
next(error);
|
||||
@@ -263,7 +261,7 @@ router.get('/users', async (req, res, next: NextFunction) => {
|
||||
router.get('/activity-log', validateRequest(activityLogSchema), async (req, res, next: NextFunction) => {
|
||||
const { limit, offset } = req.query as unknown as { limit: number; offset: number };
|
||||
try {
|
||||
const logs = await db.adminRepo.getActivityLog(limit, offset);
|
||||
const logs = await db.adminRepo.getActivityLog(limit, offset, req.log);
|
||||
res.json(logs);
|
||||
} catch (error) {
|
||||
next(error);
|
||||
@@ -272,7 +270,7 @@ router.get('/activity-log', validateRequest(activityLogSchema), async (req, res,
|
||||
|
||||
router.get('/users/:id', validateRequest(z.object({ params: z.object({ id: z.string().uuid() }) })), async (req, res, next: NextFunction) => {
|
||||
try {
|
||||
const user = await db.userRepo.findUserProfileById(req.params.id);
|
||||
const user = await db.userRepo.findUserProfileById(req.params.id, req.log);
|
||||
res.json(user);
|
||||
} catch (error) {
|
||||
next(error);
|
||||
@@ -283,10 +281,10 @@ router.put('/users/:id', validateRequest(updateUserRoleSchema), async (req, res,
|
||||
const { role } = req.body;
|
||||
|
||||
try {
|
||||
const updatedUser = await db.adminRepo.updateUserRole(req.params.id, role);
|
||||
const updatedUser = await db.adminRepo.updateUserRole(req.params.id, role, req.log);
|
||||
res.json(updatedUser);
|
||||
} catch (error) {
|
||||
logger.error(`Error updating user ${req.params.id}:`, { error });
|
||||
logger.error({ error }, `Error updating user ${req.params.id}:`);
|
||||
next(error);
|
||||
}
|
||||
});
|
||||
@@ -297,7 +295,7 @@ router.delete('/users/:id', validateRequest(z.object({ params: z.object({ id: z.
|
||||
if (adminUser.user.user_id === req.params.id) {
|
||||
throw new ValidationError([], 'Admins cannot delete their own account.');
|
||||
}
|
||||
await db.userRepo.deleteUserById(req.params.id);
|
||||
await db.userRepo.deleteUserById(req.params.id, req.log);
|
||||
res.status(204).send();
|
||||
} catch (error) {
|
||||
next(error);
|
||||
@@ -318,7 +316,7 @@ router.post('/trigger/daily-deal-check', async (req, res, next: NextFunction) =>
|
||||
backgroundJobService.runDailyDealCheck();
|
||||
res.status(202).json({ message: 'Daily deal check job has been triggered successfully. It will run in the background.' });
|
||||
} catch (error) {
|
||||
logger.error('[Admin] Failed to trigger daily deal check job.', { error });
|
||||
logger.error({ error }, '[Admin] Failed to trigger daily deal check job.');
|
||||
next(error);
|
||||
}
|
||||
});
|
||||
@@ -340,7 +338,7 @@ router.post('/trigger/analytics-report', async (req, res, next: NextFunction) =>
|
||||
|
||||
res.status(202).json({ message: `Analytics report generation job has been enqueued successfully. Job ID: ${job.id}` });
|
||||
} catch (error) {
|
||||
logger.error('[Admin] Failed to enqueue analytics report job.', { error });
|
||||
logger.error({ error }, '[Admin] Failed to enqueue analytics report job.');
|
||||
next(error);
|
||||
}
|
||||
});
|
||||
@@ -390,10 +388,10 @@ router.post('/system/clear-geocode-cache', async (req, res, next: NextFunction)
|
||||
logger.info(`[Admin] Manual trigger for geocode cache clear received from user: ${adminUser.user_id}`);
|
||||
|
||||
try {
|
||||
const keysDeleted = await clearGeocodeCache();
|
||||
const keysDeleted = await geocodingService.clearGeocodeCache(req.log);
|
||||
res.status(200).json({ message: `Successfully cleared the geocode cache. ${keysDeleted} keys were removed.` });
|
||||
} catch (error) {
|
||||
logger.error('[Admin] Failed to clear geocode cache.', { error });
|
||||
logger.error({ error }, '[Admin] Failed to clear geocode cache.');
|
||||
next(error);
|
||||
}
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user