complete project using prettier!
This commit is contained in:
@@ -12,7 +12,8 @@ const router = express.Router();
|
||||
const adminGamificationRouter = express.Router(); // Create a new router for admin-only routes.
|
||||
|
||||
// Helper for consistent required string validation (handles missing/null/empty)
|
||||
const requiredString = (message: string) => z.preprocess((val) => val ?? '', z.string().min(1, message));
|
||||
const requiredString = (message: string) =>
|
||||
z.preprocess((val) => val ?? '', z.string().min(1, message));
|
||||
|
||||
// --- Zod Schemas for Gamification Routes (as per ADR-003) ---
|
||||
|
||||
@@ -49,21 +50,25 @@ router.get('/', async (req, res, next: NextFunction) => {
|
||||
* GET /api/achievements/leaderboard - Get the top users by points.
|
||||
* This is a public endpoint.
|
||||
*/
|
||||
router.get('/leaderboard', validateRequest(leaderboardSchema), async (req, res, next: NextFunction): Promise<void> => {
|
||||
// Apply ADR-003 pattern for type safety.
|
||||
// Explicitly coerce query params to ensure numbers are passed to the repo,
|
||||
// as validateRequest might not replace req.query in all test environments.
|
||||
const query = req.query as unknown as { limit?: string };
|
||||
const limit = query.limit ? Number(query.limit) : 10;
|
||||
router.get(
|
||||
'/leaderboard',
|
||||
validateRequest(leaderboardSchema),
|
||||
async (req, res, next: NextFunction): Promise<void> => {
|
||||
// Apply ADR-003 pattern for type safety.
|
||||
// Explicitly coerce query params to ensure numbers are passed to the repo,
|
||||
// as validateRequest might not replace req.query in all test environments.
|
||||
const query = req.query as unknown as { limit?: string };
|
||||
const limit = query.limit ? Number(query.limit) : 10;
|
||||
|
||||
try {
|
||||
const leaderboard = await gamificationRepo.getLeaderboard(limit, req.log);
|
||||
res.json(leaderboard);
|
||||
} catch (error) {
|
||||
logger.error({ error }, 'Error fetching leaderboard:');
|
||||
next(error);
|
||||
}
|
||||
});
|
||||
try {
|
||||
const leaderboard = await gamificationRepo.getLeaderboard(limit, req.log);
|
||||
res.json(leaderboard);
|
||||
} catch (error) {
|
||||
logger.error({ error }, 'Error fetching leaderboard:');
|
||||
next(error);
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
// --- Authenticated User Routes ---
|
||||
|
||||
@@ -77,13 +82,19 @@ router.get(
|
||||
async (req, res, next: NextFunction): Promise<void> => {
|
||||
const userProfile = req.user as UserProfile;
|
||||
try {
|
||||
const userAchievements = await gamificationRepo.getUserAchievements(userProfile.user.user_id, req.log);
|
||||
const userAchievements = await gamificationRepo.getUserAchievements(
|
||||
userProfile.user.user_id,
|
||||
req.log,
|
||||
);
|
||||
res.json(userAchievements);
|
||||
} catch (error) {
|
||||
logger.error({ error, userId: userProfile.user.user_id }, 'Error fetching user achievements:');
|
||||
logger.error(
|
||||
{ error, userId: userProfile.user.user_id },
|
||||
'Error fetching user achievements:',
|
||||
);
|
||||
next(error);
|
||||
}
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
// --- Admin-Only Routes ---
|
||||
@@ -96,26 +107,34 @@ adminGamificationRouter.use(passport.authenticate('jwt', { session: false }), is
|
||||
* This is an admin-only endpoint.
|
||||
*/
|
||||
adminGamificationRouter.post(
|
||||
'/award', validateRequest(awardAchievementSchema),
|
||||
'/award',
|
||||
validateRequest(awardAchievementSchema),
|
||||
async (req, res, next: NextFunction): Promise<void> => {
|
||||
// Infer type and cast request object as per ADR-003
|
||||
type AwardAchievementRequest = z.infer<typeof awardAchievementSchema>;
|
||||
const { body } = req as unknown as AwardAchievementRequest;
|
||||
try {
|
||||
await gamificationRepo.awardAchievement(body.userId, body.achievementName, req.log);
|
||||
res.status(200).json({ message: `Successfully awarded '${body.achievementName}' to user ${body.userId}.` });
|
||||
res
|
||||
.status(200)
|
||||
.json({
|
||||
message: `Successfully awarded '${body.achievementName}' to user ${body.userId}.`,
|
||||
});
|
||||
} catch (error) {
|
||||
if (error instanceof ForeignKeyConstraintError) {
|
||||
res.status(400).json({ message: error.message });
|
||||
return;
|
||||
}
|
||||
logger.error({ error, userId: body.userId, achievementName: body.achievementName }, 'Error awarding achievement via admin endpoint:');
|
||||
logger.error(
|
||||
{ error, userId: body.userId, achievementName: body.achievementName },
|
||||
'Error awarding achievement via admin endpoint:',
|
||||
);
|
||||
next(error);
|
||||
}
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
// Mount the admin sub-router onto the main gamification router.
|
||||
router.use(adminGamificationRouter);
|
||||
|
||||
export default router;
|
||||
export default router;
|
||||
|
||||
Reference in New Issue
Block a user