more refactor
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:
@@ -23,7 +23,6 @@ const wrapper = ({ children }: { children: ReactNode }) => <UserDataProvider>{ch
|
|||||||
|
|
||||||
// 4. Mock data for testing
|
// 4. Mock data for testing
|
||||||
const mockUser: UserProfile = createMockUserProfile({
|
const mockUser: UserProfile = createMockUserProfile({
|
||||||
user_id: 'user-123',
|
|
||||||
full_name: 'Test User',
|
full_name: 'Test User',
|
||||||
points: 100,
|
points: 100,
|
||||||
user: { user_id: 'user-123', email: 'test@example.com' },
|
user: { user_id: 'user-123', email: 'test@example.com' },
|
||||||
|
|||||||
@@ -30,7 +30,6 @@ const mockedApiClient = apiClient as Mocked<typeof apiClient>;
|
|||||||
|
|
||||||
// --- Mock Data ---
|
// --- Mock Data ---
|
||||||
const mockProfile: UserProfile = createMockUserProfile({
|
const mockProfile: UserProfile = createMockUserProfile({
|
||||||
user_id: 'user-123',
|
|
||||||
user: createMockUser({ user_id: 'user-123', email: 'test@example.com' }),
|
user: createMockUser({ user_id: 'user-123', email: 'test@example.com' }),
|
||||||
full_name: 'Test User',
|
full_name: 'Test User',
|
||||||
avatar_url: 'http://example.com/avatar.jpg',
|
avatar_url: 'http://example.com/avatar.jpg',
|
||||||
|
|||||||
@@ -237,12 +237,12 @@ router.get('/unmatched-items', async (req, res, next: NextFunction) => {
|
|||||||
* DELETE /api/admin/recipes/:recipeId - Admin endpoint to delete any recipe.
|
* DELETE /api/admin/recipes/:recipeId - Admin endpoint to delete any recipe.
|
||||||
*/
|
*/
|
||||||
router.delete('/recipes/:recipeId', validateRequest(numericIdParamSchema('recipeId')), async (req: Request, res: Response, next: NextFunction) => {
|
router.delete('/recipes/:recipeId', validateRequest(numericIdParamSchema('recipeId')), async (req: Request, res: Response, next: NextFunction) => {
|
||||||
const adminUser = req.user as UserProfile;
|
const userProfile = req.user as UserProfile;
|
||||||
// Infer the type directly from the schema generator function. // This was a duplicate, fixed.
|
// Infer the type directly from the schema generator function. // This was a duplicate, fixed.
|
||||||
const { params } = req as unknown as z.infer<ReturnType<typeof numericIdParamSchema>>;
|
const { params } = req as unknown as z.infer<ReturnType<typeof numericIdParamSchema>>;
|
||||||
try {
|
try {
|
||||||
// The isAdmin flag bypasses the ownership check in the repository method.
|
// The isAdmin flag bypasses the ownership check in the repository method.
|
||||||
await db.recipeRepo.deleteRecipe(params.recipeId, adminUser.user.user_id, true, req.log);
|
await db.recipeRepo.deleteRecipe(params.recipeId, userProfile.user.user_id, true, req.log);
|
||||||
res.status(204).send();
|
res.status(204).send();
|
||||||
} catch (error: unknown) {
|
} catch (error: unknown) {
|
||||||
next(error);
|
next(error);
|
||||||
@@ -323,11 +323,11 @@ router.put('/users/:id', validateRequest(updateUserRoleSchema), async (req: Requ
|
|||||||
});
|
});
|
||||||
|
|
||||||
router.delete('/users/:id', validateRequest(uuidParamSchema('id', 'A valid user ID is required.')), async (req: Request, res: Response, next: NextFunction) => {
|
router.delete('/users/:id', validateRequest(uuidParamSchema('id', 'A valid user ID is required.')), async (req: Request, res: Response, next: NextFunction) => {
|
||||||
const adminUser = req.user as UserProfile;
|
const userProfile = req.user as UserProfile;
|
||||||
// Apply ADR-003 pattern for type safety
|
// Apply ADR-003 pattern for type safety
|
||||||
const { params } = req as unknown as z.infer<ReturnType<typeof uuidParamSchema>>;
|
const { params } = req as unknown as z.infer<ReturnType<typeof uuidParamSchema>>;
|
||||||
try {
|
try {
|
||||||
if (adminUser.user.user_id === params.id) {
|
if (userProfile.user.user_id === params.id) {
|
||||||
throw new ValidationError([], 'Admins cannot delete their own account.');
|
throw new ValidationError([], 'Admins cannot delete their own account.');
|
||||||
}
|
}
|
||||||
await db.userRepo.deleteUserById(params.id, req.log);
|
await db.userRepo.deleteUserById(params.id, req.log);
|
||||||
@@ -342,8 +342,8 @@ router.delete('/users/:id', validateRequest(uuidParamSchema('id', 'A valid user
|
|||||||
* This is useful for testing or forcing an update without waiting for the cron schedule.
|
* This is useful for testing or forcing an update without waiting for the cron schedule.
|
||||||
*/
|
*/
|
||||||
router.post('/trigger/daily-deal-check', async (req: Request, res: Response, next: NextFunction) => {
|
router.post('/trigger/daily-deal-check', async (req: Request, res: Response, next: NextFunction) => {
|
||||||
const adminUser = req.user as UserProfile;
|
const userProfile = req.user as UserProfile;
|
||||||
logger.info(`[Admin] Manual trigger for daily deal check received from user: ${adminUser.user.user_id}`);
|
logger.info(`[Admin] Manual trigger for daily deal check received from user: ${userProfile.user.user_id}`);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// We call the function but don't wait for it to finish (no `await`).
|
// We call the function but don't wait for it to finish (no `await`).
|
||||||
@@ -361,8 +361,8 @@ router.post('/trigger/daily-deal-check', async (req: Request, res: Response, nex
|
|||||||
* This is useful for testing or re-generating a report without waiting for the cron schedule.
|
* This is useful for testing or re-generating a report without waiting for the cron schedule.
|
||||||
*/
|
*/
|
||||||
router.post('/trigger/analytics-report', async (req: Request, res: Response, next: NextFunction) => {
|
router.post('/trigger/analytics-report', async (req: Request, res: Response, next: NextFunction) => {
|
||||||
const adminUser = req.user as UserProfile;
|
const userProfile = req.user as UserProfile;
|
||||||
logger.info(`[Admin] Manual trigger for analytics report generation received from user: ${adminUser.user.user_id}`);
|
logger.info(`[Admin] Manual trigger for analytics report generation received from user: ${userProfile.user.user_id}`);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const reportDate = new Date().toISOString().split('T')[0]; // YYYY-MM-DD
|
const reportDate = new Date().toISOString().split('T')[0]; // YYYY-MM-DD
|
||||||
@@ -383,10 +383,10 @@ router.post('/trigger/analytics-report', async (req: Request, res: Response, nex
|
|||||||
* This is triggered by an admin after they have verified the flyer processing was successful.
|
* This is triggered by an admin after they have verified the flyer processing was successful.
|
||||||
*/
|
*/
|
||||||
router.post('/flyers/:flyerId/cleanup', validateRequest(numericIdParamSchema('flyerId')), async (req: Request, res: Response, next: NextFunction) => {
|
router.post('/flyers/:flyerId/cleanup', validateRequest(numericIdParamSchema('flyerId')), async (req: Request, res: Response, next: NextFunction) => {
|
||||||
const adminUser = req.user as UserProfile;
|
const userProfile = req.user as UserProfile;
|
||||||
// Infer type from the schema generator for type safety, as per ADR-003.
|
// Infer type from the schema generator for type safety, as per ADR-003.
|
||||||
const { params } = req as unknown as z.infer<ReturnType<typeof numericIdParamSchema>>; // This was a duplicate, fixed.
|
const { params } = req as unknown as z.infer<ReturnType<typeof numericIdParamSchema>>; // This was a duplicate, fixed.
|
||||||
logger.info(`[Admin] Manual trigger for flyer file cleanup received from user: ${adminUser.user.user_id} for flyer ID: ${params.flyerId}`);
|
logger.info(`[Admin] Manual trigger for flyer file cleanup received from user: ${userProfile.user.user_id} for flyer ID: ${params.flyerId}`);
|
||||||
|
|
||||||
// Enqueue the cleanup job. The worker will handle the file deletion.
|
// Enqueue the cleanup job. The worker will handle the file deletion.
|
||||||
try {
|
try {
|
||||||
@@ -402,8 +402,8 @@ router.post('/flyers/:flyerId/cleanup', validateRequest(numericIdParamSchema('fl
|
|||||||
* This is for testing the retry mechanism and Bull Board UI.
|
* This is for testing the retry mechanism and Bull Board UI.
|
||||||
*/
|
*/
|
||||||
router.post('/trigger/failing-job', async (req: Request, res: Response, next: NextFunction) => {
|
router.post('/trigger/failing-job', async (req: Request, res: Response, next: NextFunction) => {
|
||||||
const adminUser = req.user as UserProfile;
|
const userProfile = req.user as UserProfile;
|
||||||
logger.info(`[Admin] Manual trigger for a failing job received from user: ${adminUser.user.user_id}`);
|
logger.info(`[Admin] Manual trigger for a failing job received from user: ${userProfile.user.user_id}`);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Add a job with a special 'forceFail' flag that the worker will recognize.
|
// Add a job with a special 'forceFail' flag that the worker will recognize.
|
||||||
@@ -419,8 +419,8 @@ router.post('/trigger/failing-job', async (req: Request, res: Response, next: Ne
|
|||||||
* Requires admin privileges.
|
* Requires admin privileges.
|
||||||
*/
|
*/
|
||||||
router.post('/system/clear-geocode-cache', async (req: Request, res: Response, next: NextFunction) => {
|
router.post('/system/clear-geocode-cache', async (req: Request, res: Response, next: NextFunction) => {
|
||||||
const adminUser = req.user as UserProfile;
|
const userProfile = req.user as UserProfile;
|
||||||
logger.info(`[Admin] Manual trigger for geocode cache clear received from user: ${adminUser.user.user_id}`);
|
logger.info(`[Admin] Manual trigger for geocode cache clear received from user: ${userProfile.user.user_id}`);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const keysDeleted = await geocodingService.clearGeocodeCache(req.log);
|
const keysDeleted = await geocodingService.clearGeocodeCache(req.log);
|
||||||
@@ -476,7 +476,7 @@ router.get('/queues/status', async (req: Request, res: Response, next: NextFunct
|
|||||||
* POST /api/admin/jobs/:queueName/:jobId/retry - Retries a specific failed job.
|
* POST /api/admin/jobs/:queueName/:jobId/retry - Retries a specific failed job.
|
||||||
*/
|
*/
|
||||||
router.post('/jobs/:queueName/:jobId/retry', validateRequest(jobRetrySchema), async (req: Request, res: Response, next: NextFunction) => {
|
router.post('/jobs/:queueName/:jobId/retry', validateRequest(jobRetrySchema), async (req: Request, res: Response, next: NextFunction) => {
|
||||||
const adminUser = req.user as UserProfile;
|
const userProfile = req.user as UserProfile;
|
||||||
const { params: { queueName, jobId } } = req as unknown as z.infer<typeof jobRetrySchema>;
|
const { params: { queueName, jobId } } = req as unknown as z.infer<typeof jobRetrySchema>;
|
||||||
|
|
||||||
const queueMap: { [key: string]: Queue } = {
|
const queueMap: { [key: string]: Queue } = {
|
||||||
@@ -501,7 +501,7 @@ router.post('/jobs/:queueName/:jobId/retry', validateRequest(jobRetrySchema), as
|
|||||||
if (jobState !== 'failed') throw new ValidationError([], `Job is not in a 'failed' state. Current state: ${jobState}.`); // This was a duplicate, fixed.
|
if (jobState !== 'failed') throw new ValidationError([], `Job is not in a 'failed' state. Current state: ${jobState}.`); // This was a duplicate, fixed.
|
||||||
|
|
||||||
await job.retry();
|
await job.retry();
|
||||||
logger.info(`[Admin] User ${adminUser.user.user_id} manually retried job ${jobId} in queue ${queueName}.`);
|
logger.info(`[Admin] User ${userProfile.user.user_id} manually retried job ${jobId} in queue ${queueName}.`);
|
||||||
res.status(200).json({ message: `Job ${jobId} has been successfully marked for retry.` });
|
res.status(200).json({ message: `Job ${jobId} has been successfully marked for retry.` });
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
next(error);
|
next(error);
|
||||||
@@ -512,8 +512,8 @@ router.post('/jobs/:queueName/:jobId/retry', validateRequest(jobRetrySchema), as
|
|||||||
* POST /api/admin/trigger/weekly-analytics - Manually trigger the weekly analytics report job.
|
* POST /api/admin/trigger/weekly-analytics - Manually trigger the weekly analytics report job.
|
||||||
*/
|
*/
|
||||||
router.post('/trigger/weekly-analytics', async (req: Request, res: Response, next: NextFunction) => {
|
router.post('/trigger/weekly-analytics', async (req: Request, res: Response, next: NextFunction) => {
|
||||||
const adminUser = req.user as UserProfile; // This was a duplicate, fixed.
|
const userProfile = req.user as UserProfile; // This was a duplicate, fixed.
|
||||||
logger.info(`[Admin] Manual trigger for weekly analytics report received from user: ${adminUser.user.user_id}`);
|
logger.info(`[Admin] Manual trigger for weekly analytics report received from user: ${userProfile.user.user_id}`);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const { year: reportYear, week: reportWeek } = getSimpleWeekAndYear();
|
const { year: reportYear, week: reportWeek } = getSimpleWeekAndYear();
|
||||||
|
|||||||
@@ -79,7 +79,7 @@ describe('Admin Stats Routes (/api/admin/stats)', () => {
|
|||||||
|
|
||||||
describe('GET /stats', () => {
|
describe('GET /stats', () => {
|
||||||
it('should return application stats on success', async () => {
|
it('should return application stats on success', async () => {
|
||||||
const mockStats = { flyerCount: 150, userCount: 42, flyerItemCount: 10000, storeCount: 12, pendingCorrectionCount: 5 };
|
const mockStats = { flyerCount: 150, userCount: 42, flyerItemCount: 10000, storeCount: 12, pendingCorrectionCount: 5, recipeCount: 50 };
|
||||||
vi.mocked(adminRepo.getApplicationStats).mockResolvedValue(mockStats);
|
vi.mocked(adminRepo.getApplicationStats).mockResolvedValue(mockStats);
|
||||||
const response = await supertest(app).get('/api/admin/stats');
|
const response = await supertest(app).get('/api/admin/stats');
|
||||||
expect(response.status).toBe(200);
|
expect(response.status).toBe(200);
|
||||||
|
|||||||
@@ -48,12 +48,12 @@ router.use(passport.authenticate('jwt', { session: false }));
|
|||||||
* GET /api/budgets - Get all budgets for the authenticated user.
|
* GET /api/budgets - Get all budgets for the authenticated user.
|
||||||
*/
|
*/
|
||||||
router.get('/', async (req: Request, res: Response, next: NextFunction) => {
|
router.get('/', async (req: Request, res: Response, next: NextFunction) => {
|
||||||
const user = req.user as UserProfile;
|
const userProfile = req.user as UserProfile;
|
||||||
try {
|
try {
|
||||||
const budgets = await budgetRepo.getBudgetsForUser(user.user_id, req.log);
|
const budgets = await budgetRepo.getBudgetsForUser(userProfile.user.user_id, req.log);
|
||||||
res.json(budgets);
|
res.json(budgets);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
req.log.error({ error, userId: user.user_id }, 'Error fetching budgets');
|
req.log.error({ error, userId: userProfile.user.user_id }, 'Error fetching budgets');
|
||||||
next(error);
|
next(error);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -62,14 +62,14 @@ router.get('/', async (req: Request, res: Response, next: NextFunction) => {
|
|||||||
* POST /api/budgets - Create a new budget for the authenticated user.
|
* POST /api/budgets - Create a new budget for the authenticated user.
|
||||||
*/
|
*/
|
||||||
router.post('/', validateRequest(createBudgetSchema), async (req: Request, res: Response, next: NextFunction) => {
|
router.post('/', validateRequest(createBudgetSchema), async (req: Request, res: Response, next: NextFunction) => {
|
||||||
const user = req.user as UserProfile;
|
const userProfile = req.user as UserProfile;
|
||||||
type CreateBudgetRequest = z.infer<typeof createBudgetSchema>;
|
type CreateBudgetRequest = z.infer<typeof createBudgetSchema>;
|
||||||
const { body } = req as unknown as CreateBudgetRequest;
|
const { body } = req as unknown as CreateBudgetRequest;
|
||||||
try {
|
try {
|
||||||
const newBudget = await budgetRepo.createBudget(user.user_id, body, req.log);
|
const newBudget = await budgetRepo.createBudget(userProfile.user.user_id, body, req.log);
|
||||||
res.status(201).json(newBudget);
|
res.status(201).json(newBudget);
|
||||||
} catch (error: unknown) {
|
} catch (error: unknown) {
|
||||||
req.log.error({ error, userId: user.user_id, body }, 'Error creating budget');
|
req.log.error({ error, userId: userProfile.user.user_id, body }, 'Error creating budget');
|
||||||
next(error);
|
next(error);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -78,14 +78,14 @@ router.post('/', validateRequest(createBudgetSchema), async (req: Request, res:
|
|||||||
* PUT /api/budgets/:id - Update an existing budget.
|
* PUT /api/budgets/:id - Update an existing budget.
|
||||||
*/
|
*/
|
||||||
router.put('/:id', validateRequest(updateBudgetSchema), async (req: Request, res: Response, next: NextFunction) => {
|
router.put('/:id', validateRequest(updateBudgetSchema), async (req: Request, res: Response, next: NextFunction) => {
|
||||||
const user = req.user as UserProfile;
|
const userProfile = req.user as UserProfile;
|
||||||
type UpdateBudgetRequest = z.infer<typeof updateBudgetSchema>;
|
type UpdateBudgetRequest = z.infer<typeof updateBudgetSchema>;
|
||||||
const { params, body } = req as unknown as UpdateBudgetRequest;
|
const { params, body } = req as unknown as UpdateBudgetRequest;
|
||||||
try {
|
try {
|
||||||
const updatedBudget = await budgetRepo.updateBudget(params.id, user.user_id, body, req.log);
|
const updatedBudget = await budgetRepo.updateBudget(params.id, userProfile.user.user_id, body, req.log);
|
||||||
res.json(updatedBudget);
|
res.json(updatedBudget);
|
||||||
} catch (error: unknown) {
|
} catch (error: unknown) {
|
||||||
req.log.error({ error, userId: user.user_id, budgetId: params.id }, 'Error updating budget');
|
req.log.error({ error, userId: userProfile.user.user_id, budgetId: params.id }, 'Error updating budget');
|
||||||
next(error);
|
next(error);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -94,14 +94,14 @@ router.put('/:id', validateRequest(updateBudgetSchema), async (req: Request, res
|
|||||||
* DELETE /api/budgets/:id - Delete a budget.
|
* DELETE /api/budgets/:id - Delete a budget.
|
||||||
*/
|
*/
|
||||||
router.delete('/:id', validateRequest(budgetIdParamSchema), async (req: Request, res: Response, next: NextFunction) => {
|
router.delete('/:id', validateRequest(budgetIdParamSchema), async (req: Request, res: Response, next: NextFunction) => {
|
||||||
const user = req.user as UserProfile;
|
const userProfile = req.user as UserProfile;
|
||||||
type DeleteBudgetRequest = z.infer<typeof budgetIdParamSchema>;
|
type DeleteBudgetRequest = z.infer<typeof budgetIdParamSchema>;
|
||||||
const { params } = req as unknown as DeleteBudgetRequest;
|
const { params } = req as unknown as DeleteBudgetRequest;
|
||||||
try {
|
try {
|
||||||
await budgetRepo.deleteBudget(params.id, user.user_id, req.log);
|
await budgetRepo.deleteBudget(params.id, userProfile.user.user_id, req.log);
|
||||||
res.status(204).send(); // No Content
|
res.status(204).send(); // No Content
|
||||||
} catch (error: unknown) {
|
} catch (error: unknown) {
|
||||||
req.log.error({ error, userId: user.user_id, budgetId: params.id }, 'Error deleting budget');
|
req.log.error({ error, userId: userProfile.user.user_id, budgetId: params.id }, 'Error deleting budget');
|
||||||
next(error);
|
next(error);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -111,15 +111,15 @@ router.delete('/:id', validateRequest(budgetIdParamSchema), async (req: Request,
|
|||||||
* Query params: startDate (YYYY-MM-DD), endDate (YYYY-MM-DD)
|
* Query params: startDate (YYYY-MM-DD), endDate (YYYY-MM-DD)
|
||||||
*/
|
*/
|
||||||
router.get('/spending-analysis', validateRequest(spendingAnalysisSchema), async (req: Request, res: Response, next: NextFunction) => {
|
router.get('/spending-analysis', validateRequest(spendingAnalysisSchema), async (req: Request, res: Response, next: NextFunction) => {
|
||||||
const user = req.user as UserProfile;
|
const userProfile = req.user as UserProfile;
|
||||||
type SpendingAnalysisRequest = z.infer<typeof spendingAnalysisSchema>;
|
type SpendingAnalysisRequest = z.infer<typeof spendingAnalysisSchema>;
|
||||||
const { query: { startDate, endDate } } = req as unknown as SpendingAnalysisRequest;
|
const { query: { startDate, endDate } } = req as unknown as SpendingAnalysisRequest;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const spendingData = await budgetRepo.getSpendingByCategory(user.user_id, startDate, endDate, req.log);
|
const spendingData = await budgetRepo.getSpendingByCategory(userProfile.user.user_id, startDate, endDate, req.log);
|
||||||
res.json(spendingData);
|
res.json(spendingData);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
req.log.error({ error, userId: user.user_id, startDate, endDate }, 'Error fetching spending analysis');
|
req.log.error({ error, userId: userProfile.user.user_id, startDate, endDate }, 'Error fetching spending analysis');
|
||||||
next(error);
|
next(error);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -26,11 +26,11 @@ router.use(passport.authenticate('jwt', { session: false }));
|
|||||||
* @access Private
|
* @access Private
|
||||||
*/
|
*/
|
||||||
router.get('/best-watched-prices', validateRequest(bestWatchedPricesSchema), async (req: Request, res: Response, next: NextFunction) => {
|
router.get('/best-watched-prices', validateRequest(bestWatchedPricesSchema), async (req: Request, res: Response, next: NextFunction) => {
|
||||||
const user = req.user as UserProfile;
|
const userProfile = req.user as UserProfile;
|
||||||
try {
|
try {
|
||||||
// The controller logic is simple enough to be handled directly in the route,
|
// The controller logic is simple enough to be handled directly in the route,
|
||||||
// consistent with other simple GET routes in the project.
|
// consistent with other simple GET routes in the project.
|
||||||
const deals = await dealsRepo.findBestPricesForWatchedItems(user.user_id, req.log);
|
const deals = await dealsRepo.findBestPricesForWatchedItems(userProfile.user.user_id, req.log);
|
||||||
req.log.info({ dealCount: deals.length }, 'Successfully fetched best watched item deals.');
|
req.log.info({ dealCount: deals.length }, 'Successfully fetched best watched item deals.');
|
||||||
res.status(200).json(deals);
|
res.status(200).json(deals);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|||||||
@@ -75,12 +75,12 @@ router.get(
|
|||||||
'/me',
|
'/me',
|
||||||
passport.authenticate('jwt', { session: false }),
|
passport.authenticate('jwt', { session: false }),
|
||||||
async (req, res, next: NextFunction): Promise<void> => {
|
async (req, res, next: NextFunction): Promise<void> => {
|
||||||
const user = req.user as UserProfile;
|
const userProfile = req.user as UserProfile;
|
||||||
try {
|
try {
|
||||||
const userAchievements = await gamificationRepo.getUserAchievements(user.user_id, req.log);
|
const userAchievements = await gamificationRepo.getUserAchievements(userProfile.user.user_id, req.log);
|
||||||
res.json(userAchievements);
|
res.json(userAchievements);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.error({ error, userId: user.user_id }, 'Error fetching user achievements:');
|
logger.error({ error, userId: userProfile.user.user_id }, 'Error fetching user achievements:');
|
||||||
next(error);
|
next(error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -484,7 +484,7 @@ describe('Admin DB Service', () => {
|
|||||||
|
|
||||||
describe('updateUserRole', () => {
|
describe('updateUserRole', () => {
|
||||||
it('should update the user role and return the updated user', async () => {
|
it('should update the user role and return the updated user', async () => {
|
||||||
const mockProfile: Profile = createMockProfile({ user_id: '1', role: 'admin' });
|
const mockProfile: Profile = createMockProfile({ role: 'admin' });
|
||||||
mockPoolInstance.query.mockResolvedValue({ rows: [mockProfile], rowCount: 1 });
|
mockPoolInstance.query.mockResolvedValue({ rows: [mockProfile], rowCount: 1 });
|
||||||
const result = await adminRepo.updateUserRole('1', 'admin', mockLogger);
|
const result = await adminRepo.updateUserRole('1', 'admin', mockLogger);
|
||||||
expect(mockPoolInstance.query).toHaveBeenCalledWith('UPDATE public.profiles SET role = $1 WHERE user_id = $2 RETURNING *', ['admin', '1']);
|
expect(mockPoolInstance.query).toHaveBeenCalledWith('UPDATE public.profiles SET role = $1 WHERE user_id = $2 RETURNING *', ['admin', '1']);
|
||||||
|
|||||||
Reference in New Issue
Block a user