feat: admin/superadmin — fix response shape, ban/unban, stats tab, role restriction
All checks were successful
CI/CD — Build & Deploy / Build & Deploy (push) Successful in 24s
All checks were successful
CI/CD — Build & Deploy / Build & Deploy (push) Successful in 24s
This commit is contained in:
@@ -99,7 +99,7 @@ router.get("/videos", async (req: Request, res: Response): Promise<void> => {
|
||||
skip: (rawPage - 1) * rawLimit,
|
||||
take: rawLimit,
|
||||
});
|
||||
res.json({ success: true, data: videos, total, page: rawPage, limit: rawLimit });
|
||||
res.json({ success: true, data: { videos }, total, page: rawPage, limit: rawLimit });
|
||||
} catch (err) {
|
||||
logger.error("GET /admin/videos — failed to list videos", { err });
|
||||
res.status(500).json({ success: false, error: "INTERNAL_ERROR" });
|
||||
@@ -262,13 +262,43 @@ router.get("/users", async (req: Request, res: Response): Promise<void> => {
|
||||
})(),
|
||||
}));
|
||||
|
||||
res.json({ success: true, data, total, page: rawPage, limit: rawLimit });
|
||||
res.json({ success: true, data: { users: data }, total, page: rawPage, limit: rawLimit });
|
||||
} catch (err) {
|
||||
logger.error("GET /admin/users — failed to list users", { err });
|
||||
res.status(500).json({ success: false, error: "INTERNAL_ERROR" });
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* PATCH /api/admin/users/:id
|
||||
* Met à jour isActive (ban / unban) d'un utilisateur.
|
||||
*/
|
||||
router.patch("/users/:id", async (req: Request, res: Response): Promise<void> => {
|
||||
const { isActive } = req.body as { isActive?: boolean };
|
||||
|
||||
if (typeof isActive !== "boolean") {
|
||||
res.status(400).json({ success: false, error: "INVALID_BODY" });
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const repo = AppDataSource.getRepository(User);
|
||||
const user = await repo.findOne({ where: { id: req.params.id } });
|
||||
|
||||
if (!user) {
|
||||
res.status(404).json({ success: false, error: "NOT_FOUND" });
|
||||
return;
|
||||
}
|
||||
|
||||
user.isActive = isActive;
|
||||
await repo.save(user);
|
||||
res.json({ success: true, data: { userId: user.id, isActive: user.isActive } });
|
||||
} catch (err) {
|
||||
logger.error("PATCH /admin/users/:id — failed to update user", { err, id: req.params.id });
|
||||
res.status(500).json({ success: false, error: "INTERNAL_ERROR" });
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* PATCH /api/admin/users/:id/roles
|
||||
* Assigne des rôles à un utilisateur (remplace les rôles existants).
|
||||
@@ -332,6 +362,28 @@ router.patch("/users/:id/roles", async (req: Request, res: Response): Promise<vo
|
||||
}
|
||||
});
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// STATS (super_admin)
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* GET /api/admin/stats
|
||||
* Métriques globales de la plateforme.
|
||||
*/
|
||||
router.get("/stats", async (_req: Request, res: Response): Promise<void> => {
|
||||
try {
|
||||
const [totalUsers, totalVideos, activeSubscriptions] = await Promise.all([
|
||||
AppDataSource.getRepository(User).count(),
|
||||
AppDataSource.getRepository(Video).count({ where: { isPublished: true } }),
|
||||
AppDataSource.getRepository(UserSubscription).count({ where: { status: "active" } }),
|
||||
]);
|
||||
res.json({ success: true, data: { totalUsers, totalVideos, activeSubscriptions } });
|
||||
} catch (err) {
|
||||
logger.error("GET /admin/stats — failed", { err });
|
||||
res.status(500).json({ success: false, error: "INTERNAL_ERROR" });
|
||||
}
|
||||
});
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// SUBSCRIPTION PLANS
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
Reference in New Issue
Block a user