feat: Add password reset endpoints for super-admins
- POST /api/admin/users/:userId/reset-password - POST /api/admin/reset-password-by-email
This commit is contained in:
@@ -412,6 +412,75 @@ adminRouter.post("/organizations/:id/remove-free", requireSuperAdmin, async (ctx
|
|||||||
ctx.response.body = { message: `Freistellung aufgehoben, ${trialDays} Tage Trial gesetzt` };
|
ctx.response.body = { message: `Freistellung aufgehoben, ${trialDays} Tage Trial gesetzt` };
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Reset user password (Super Admin only)
|
||||||
|
adminRouter.post("/users/:userId/reset-password", requireSuperAdmin, async (ctx) => {
|
||||||
|
const userId = ctx.params.userId;
|
||||||
|
const body = await ctx.request.body.json();
|
||||||
|
const { newPassword } = body;
|
||||||
|
|
||||||
|
if (!newPassword || newPassword.length < 8) {
|
||||||
|
throw new AppError("Neues Passwort erforderlich (min. 8 Zeichen)", 400);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if user exists
|
||||||
|
const user = await queryOne<{ id: string; email: string }>(
|
||||||
|
`SELECT id, email FROM users WHERE id = $1`,
|
||||||
|
[userId]
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!user) {
|
||||||
|
throw new AppError("Benutzer nicht gefunden", 404);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hash and update password
|
||||||
|
const { hashPassword } = await import("../utils/auth.ts");
|
||||||
|
const passwordHash = await hashPassword(newPassword);
|
||||||
|
|
||||||
|
await execute(
|
||||||
|
`UPDATE users SET password_hash = $1 WHERE id = $2`,
|
||||||
|
[passwordHash, userId]
|
||||||
|
);
|
||||||
|
|
||||||
|
ctx.response.body = {
|
||||||
|
message: `Passwort für ${user.email} zurückgesetzt`,
|
||||||
|
userId: user.id
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
// Reset password by email (Super Admin only)
|
||||||
|
adminRouter.post("/reset-password-by-email", requireSuperAdmin, async (ctx) => {
|
||||||
|
const body = await ctx.request.body.json();
|
||||||
|
const { email, newPassword } = body;
|
||||||
|
|
||||||
|
if (!email || !newPassword || newPassword.length < 8) {
|
||||||
|
throw new AppError("Email und neues Passwort erforderlich (min. 8 Zeichen)", 400);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if user exists
|
||||||
|
const user = await queryOne<{ id: string; email: string }>(
|
||||||
|
`SELECT id, email FROM users WHERE email = $1`,
|
||||||
|
[email]
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!user) {
|
||||||
|
throw new AppError("Benutzer nicht gefunden", 404);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hash and update password
|
||||||
|
const { hashPassword } = await import("../utils/auth.ts");
|
||||||
|
const passwordHash = await hashPassword(newPassword);
|
||||||
|
|
||||||
|
await execute(
|
||||||
|
`UPDATE users SET password_hash = $1 WHERE id = $2`,
|
||||||
|
[passwordHash, user.id]
|
||||||
|
);
|
||||||
|
|
||||||
|
ctx.response.body = {
|
||||||
|
message: `Passwort für ${user.email} zurückgesetzt`,
|
||||||
|
userId: user.id
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
// List all organizations with subscription info
|
// List all organizations with subscription info
|
||||||
adminRouter.get("/subscriptions", requireSuperAdmin, async (ctx) => {
|
adminRouter.get("/subscriptions", requireSuperAdmin, async (ctx) => {
|
||||||
const filter = ctx.request.url.searchParams.get("filter"); // all, trial, active, paused, expired
|
const filter = ctx.request.url.searchParams.get("filter"); // all, trial, active, paused, expired
|
||||||
|
|||||||
Reference in New Issue
Block a user