720 lines
35 KiB
JavaScript
720 lines
35 KiB
JavaScript
"use strict";
|
|
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
if (k2 === undefined) k2 = k;
|
|
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
}
|
|
Object.defineProperty(o, k2, desc);
|
|
}) : (function(o, m, k, k2) {
|
|
if (k2 === undefined) k2 = k;
|
|
o[k2] = m[k];
|
|
}));
|
|
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
}) : function(o, v) {
|
|
o["default"] = v;
|
|
});
|
|
var __importStar = (this && this.__importStar) || (function () {
|
|
var ownKeys = function(o) {
|
|
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
var ar = [];
|
|
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
return ar;
|
|
};
|
|
return ownKeys(o);
|
|
};
|
|
return function (mod) {
|
|
if (mod && mod.__esModule) return mod;
|
|
var result = {};
|
|
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
__setModuleDefault(result, mod);
|
|
return result;
|
|
};
|
|
})();
|
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
const express_1 = require("express");
|
|
const requireAdminAuth_1 = require("../../middleware/requireAdminAuth");
|
|
const validate_1 = require("../../http/validate");
|
|
const respond_1 = require("../../http/respond");
|
|
const sessionCookies_1 = require("../../security/sessionCookies");
|
|
const service = __importStar(require("./admin.service"));
|
|
const subService = __importStar(require("../subscriptions/subscription.service"));
|
|
const menuService = __importStar(require("../menu/menu.service"));
|
|
const admin_presenter_1 = require("./admin.presenter");
|
|
const admin_schemas_1 = require("./admin.schemas");
|
|
const zod_1 = require("zod");
|
|
const adminSubOverrideSchema = zod_1.z.object({
|
|
reason: zod_1.z.string().min(1).max(500),
|
|
});
|
|
const adminExtendTrialSchema = zod_1.z.object({
|
|
extraDays: zod_1.z.number().int().positive(),
|
|
reason: zod_1.z.string().min(1).max(500),
|
|
});
|
|
const adminImpersonationSchema = zod_1.z.object({
|
|
reason: zod_1.z.string().min(5).max(500),
|
|
durationMinutes: zod_1.z.number().int().min(1).max(30).default(15),
|
|
});
|
|
const subIdParamSchema = zod_1.z.object({ subscriptionId: zod_1.z.string() });
|
|
const router = (0, express_1.Router)();
|
|
// ─── Auth (public) ─────────────────────────────────────────────
|
|
router.post('/auth/login', async (req, res, next) => {
|
|
try {
|
|
const { email, password, totpCode, recoveryCode } = (0, validate_1.parseBody)(admin_schemas_1.loginSchema, req);
|
|
const result = await service.login(email, password, totpCode, recoveryCode);
|
|
if (!result)
|
|
return res.status(401).json({ error: 'invalid_credentials', message: 'Invalid email or password', statusCode: 401 });
|
|
if ('totpRequired' in result)
|
|
return res.status(401).json({ error: 'totp_required', message: '2FA code required', statusCode: 401 });
|
|
if ('invalidTotp' in result)
|
|
return res.status(401).json({ error: 'invalid_totp', message: 'Invalid 2FA code', statusCode: 401 });
|
|
(0, sessionCookies_1.setSessionCookie)(res, 'admin', result.token, 8 * 60 * 60 * 1000);
|
|
(0, respond_1.ok)(res, result);
|
|
}
|
|
catch (err) {
|
|
next(err);
|
|
}
|
|
});
|
|
router.post('/auth/logout', (_req, res) => {
|
|
(0, sessionCookies_1.clearSessionCookie)(res, 'admin');
|
|
(0, respond_1.ok)(res, { success: true });
|
|
});
|
|
router.post('/auth/forgot-password', async (req, res, next) => {
|
|
try {
|
|
const { email } = (0, validate_1.parseBody)(admin_schemas_1.forgotPasswordSchema, req);
|
|
await service.forgotPassword(email);
|
|
(0, respond_1.ok)(res, { message: 'If that email is registered, a reset link has been sent.' });
|
|
}
|
|
catch (err) {
|
|
next(err);
|
|
}
|
|
});
|
|
router.post('/auth/reset-password', async (req, res, next) => {
|
|
try {
|
|
const { token, password } = (0, validate_1.parseBody)(admin_schemas_1.resetPasswordSchema, req);
|
|
const ok2 = await service.resetPassword(token, password);
|
|
if (!ok2)
|
|
return res.status(400).json({ error: 'invalid_token', message: 'Reset link is invalid or has expired.', statusCode: 400 });
|
|
(0, respond_1.ok)(res, { message: 'Password updated successfully. You can now sign in.' });
|
|
}
|
|
catch (err) {
|
|
next(err);
|
|
}
|
|
});
|
|
// ─── Auth (protected) ──────────────────────────────────────────
|
|
router.get('/auth/me', requireAdminAuth_1.requireAdminAuth, (req, res) => {
|
|
(0, respond_1.ok)(res, (0, admin_presenter_1.presentAdminUser)(req.admin));
|
|
});
|
|
router.post('/auth/2fa/setup', requireAdminAuth_1.requireAdminAuth, async (req, res, next) => {
|
|
try {
|
|
(0, respond_1.ok)(res, await service.setupTotp(req.admin.id, req.admin.email));
|
|
}
|
|
catch (err) {
|
|
next(err);
|
|
}
|
|
});
|
|
router.post('/auth/2fa/verify', requireAdminAuth_1.requireAdminAuth, async (req, res, next) => {
|
|
try {
|
|
const { code } = (0, validate_1.parseBody)(admin_schemas_1.totpVerifySchema, req);
|
|
const result = await service.verifyTotp(req.admin.id, code);
|
|
if (!result)
|
|
return res.status(400).json({ error: 'invalid_code', message: 'Invalid 2FA code', statusCode: 400 });
|
|
(0, sessionCookies_1.setSessionCookie)(res, 'admin', result.token, 8 * 60 * 60 * 1000);
|
|
(0, respond_1.ok)(res, { success: true, admin: result.admin, recoveryCodes: result.recoveryCodes });
|
|
}
|
|
catch (err) {
|
|
next(err);
|
|
}
|
|
});
|
|
router.post('/auth/2fa/recovery-codes/regenerate', requireAdminAuth_1.requireAdminAuth, requireAdminAuth_1.requireFreshAdmin2FA, async (req, res, next) => {
|
|
try {
|
|
(0, respond_1.ok)(res, await service.regenerateRecoveryCodes(req.admin.id));
|
|
}
|
|
catch (err) {
|
|
next(err);
|
|
}
|
|
});
|
|
// ─── Companies ─────────────────────────────────────────────────
|
|
router.get('/companies', requireAdminAuth_1.requireAdminAuth, async (req, res, next) => {
|
|
try {
|
|
(0, respond_1.ok)(res, await service.listCompanies((0, validate_1.parseQuery)(admin_schemas_1.companiesQuerySchema, req)));
|
|
}
|
|
catch (err) {
|
|
next(err);
|
|
}
|
|
});
|
|
router.get('/companies/:id', requireAdminAuth_1.requireAdminAuth, async (req, res, next) => {
|
|
try {
|
|
const { id } = (0, validate_1.parseParams)(admin_schemas_1.idParamSchema, req);
|
|
(0, respond_1.ok)(res, await service.getCompany(id));
|
|
}
|
|
catch (err) {
|
|
next(err);
|
|
}
|
|
});
|
|
router.patch('/companies/:id', requireAdminAuth_1.requireAdminAuth, (0, requireAdminAuth_1.requireAdminRole)('SUPPORT'), async (req, res, next) => {
|
|
try {
|
|
const { id } = (0, validate_1.parseParams)(admin_schemas_1.idParamSchema, req);
|
|
const body = (0, validate_1.parseBody)(admin_schemas_1.adminCompanyUpdateSchema, req);
|
|
(0, respond_1.ok)(res, await service.updateCompany(id, body, req.admin.id, req.ip));
|
|
}
|
|
catch (err) {
|
|
next(err);
|
|
}
|
|
});
|
|
router.patch('/companies/:id/status', requireAdminAuth_1.requireAdminAuth, (0, requireAdminAuth_1.requireAdminRole)('SUPPORT'), async (req, res, next) => {
|
|
try {
|
|
const { id } = (0, validate_1.parseParams)(admin_schemas_1.idParamSchema, req);
|
|
const { status, reason } = (0, validate_1.parseBody)(admin_schemas_1.companyStatusSchema, req);
|
|
(0, respond_1.ok)(res, await service.setCompanyStatus(id, status, reason, req.admin.id, req.ip));
|
|
}
|
|
catch (err) {
|
|
next(err);
|
|
}
|
|
});
|
|
router.delete('/companies/:id', requireAdminAuth_1.requireAdminAuth, (0, requireAdminAuth_1.requireAdminRole)('ADMIN'), requireAdminAuth_1.requireFreshAdmin2FA, async (req, res, next) => {
|
|
try {
|
|
const { id } = (0, validate_1.parseParams)(admin_schemas_1.idParamSchema, req);
|
|
await service.deleteCompany(id, req.admin.id, req.ip);
|
|
(0, respond_1.ok)(res, { success: true });
|
|
}
|
|
catch (err) {
|
|
next(err);
|
|
}
|
|
});
|
|
router.post('/companies/:id/impersonate', requireAdminAuth_1.requireAdminAuth, (0, requireAdminAuth_1.requireAdminRole)('SUPER_ADMIN'), requireAdminAuth_1.requireFreshAdmin2FA, async (req, res, next) => {
|
|
try {
|
|
const { id } = (0, validate_1.parseParams)(admin_schemas_1.idParamSchema, req);
|
|
const { reason, durationMinutes } = (0, validate_1.parseBody)(adminImpersonationSchema, req);
|
|
(0, respond_1.ok)(res, await service.impersonateCompany(id, req.admin.id, req.ip, reason, durationMinutes));
|
|
}
|
|
catch (err) {
|
|
next(err);
|
|
}
|
|
});
|
|
// ─── Menu management ──────────────────────────────────────────
|
|
router.get('/menu-items', requireAdminAuth_1.requireAdminAuth, (0, requireAdminAuth_1.requireAdminRole)('SUPPORT'), async (_req, res, next) => {
|
|
try {
|
|
(0, respond_1.ok)(res, await menuService.listMenuItems());
|
|
}
|
|
catch (err) {
|
|
next(err);
|
|
}
|
|
});
|
|
router.post('/menu-items', requireAdminAuth_1.requireAdminAuth, (0, requireAdminAuth_1.requireAdminRole)('ADMIN'), async (req, res, next) => {
|
|
try {
|
|
(0, respond_1.created)(res, { data: await menuService.createMenuItem((0, validate_1.parseBody)(admin_schemas_1.menuItemSchema, req), req.admin) });
|
|
}
|
|
catch (err) {
|
|
next(err);
|
|
}
|
|
});
|
|
router.get('/menu-items/:id', requireAdminAuth_1.requireAdminAuth, (0, requireAdminAuth_1.requireAdminRole)('SUPPORT'), async (req, res, next) => {
|
|
try {
|
|
const { id } = (0, validate_1.parseParams)(admin_schemas_1.idParamSchema, req);
|
|
(0, respond_1.ok)(res, await menuService.getMenuItem(id));
|
|
}
|
|
catch (err) {
|
|
next(err);
|
|
}
|
|
});
|
|
router.put('/menu-items/:id', requireAdminAuth_1.requireAdminAuth, (0, requireAdminAuth_1.requireAdminRole)('ADMIN'), async (req, res, next) => {
|
|
try {
|
|
const { id } = (0, validate_1.parseParams)(admin_schemas_1.idParamSchema, req);
|
|
(0, respond_1.ok)(res, await menuService.updateMenuItem(id, (0, validate_1.parseBody)(admin_schemas_1.menuItemSchema, req), req.admin));
|
|
}
|
|
catch (err) {
|
|
next(err);
|
|
}
|
|
});
|
|
router.patch('/menu-items/:id/status', requireAdminAuth_1.requireAdminAuth, (0, requireAdminAuth_1.requireAdminRole)('ADMIN'), async (req, res, next) => {
|
|
try {
|
|
const { id } = (0, validate_1.parseParams)(admin_schemas_1.idParamSchema, req);
|
|
const { isActive } = (0, validate_1.parseBody)(admin_schemas_1.menuItemStatusSchema, req);
|
|
(0, respond_1.ok)(res, await menuService.setMenuItemStatus(id, isActive, req.admin));
|
|
}
|
|
catch (err) {
|
|
next(err);
|
|
}
|
|
});
|
|
router.delete('/menu-items/:id', requireAdminAuth_1.requireAdminAuth, (0, requireAdminAuth_1.requireAdminRole)('ADMIN'), async (req, res, next) => {
|
|
try {
|
|
const { id } = (0, validate_1.parseParams)(admin_schemas_1.idParamSchema, req);
|
|
await menuService.deleteMenuItem(id, req.admin);
|
|
(0, respond_1.ok)(res, { success: true });
|
|
}
|
|
catch (err) {
|
|
next(err);
|
|
}
|
|
});
|
|
router.post('/menu-items/:id/subscriptions', requireAdminAuth_1.requireAdminAuth, (0, requireAdminAuth_1.requireAdminRole)('ADMIN'), async (req, res, next) => {
|
|
try {
|
|
const { id } = (0, validate_1.parseParams)(admin_schemas_1.idParamSchema, req);
|
|
const { assignments } = (0, validate_1.parseBody)(admin_schemas_1.menuPlanAssignmentsSchema, req);
|
|
(0, respond_1.ok)(res, await menuService.assignMenuItemToPlans(id, assignments, req.admin));
|
|
}
|
|
catch (err) {
|
|
next(err);
|
|
}
|
|
});
|
|
router.delete('/menu-items/:id/subscriptions/:plan', requireAdminAuth_1.requireAdminAuth, (0, requireAdminAuth_1.requireAdminRole)('ADMIN'), async (req, res, next) => {
|
|
try {
|
|
const { id, plan } = (0, validate_1.parseParams)(admin_schemas_1.menuPlanParamSchema, req);
|
|
(0, respond_1.ok)(res, await menuService.removeMenuItemFromPlan(id, plan, req.admin));
|
|
}
|
|
catch (err) {
|
|
next(err);
|
|
}
|
|
});
|
|
router.post('/menu-items/:id/companies', requireAdminAuth_1.requireAdminAuth, (0, requireAdminAuth_1.requireAdminRole)('ADMIN'), async (req, res, next) => {
|
|
try {
|
|
const { id } = (0, validate_1.parseParams)(admin_schemas_1.idParamSchema, req);
|
|
const { assignments } = (0, validate_1.parseBody)(admin_schemas_1.menuCompanyAssignmentsSchema, req);
|
|
(0, respond_1.ok)(res, await menuService.assignMenuItemToCompanies(id, assignments, req.admin));
|
|
}
|
|
catch (err) {
|
|
next(err);
|
|
}
|
|
});
|
|
router.delete('/menu-items/:id/companies/:companyId', requireAdminAuth_1.requireAdminAuth, (0, requireAdminAuth_1.requireAdminRole)('ADMIN'), async (req, res, next) => {
|
|
try {
|
|
const { id, companyId } = (0, validate_1.parseParams)(admin_schemas_1.menuCompanyParamSchema, req);
|
|
(0, respond_1.ok)(res, await menuService.removeMenuItemFromCompany(id, companyId, req.admin));
|
|
}
|
|
catch (err) {
|
|
next(err);
|
|
}
|
|
});
|
|
router.post('/menu-preview', requireAdminAuth_1.requireAdminAuth, (0, requireAdminAuth_1.requireAdminRole)('SUPPORT'), async (req, res, next) => {
|
|
try {
|
|
(0, respond_1.ok)(res, await menuService.previewCompanyMenu((0, validate_1.parseBody)(admin_schemas_1.menuPreviewSchema, req)));
|
|
}
|
|
catch (err) {
|
|
next(err);
|
|
}
|
|
});
|
|
router.get('/menu-audit-logs', requireAdminAuth_1.requireAdminAuth, (0, requireAdminAuth_1.requireAdminRole)('SUPPORT'), async (req, res, next) => {
|
|
try {
|
|
(0, respond_1.ok)(res, await menuService.listMenuAuditLogs((0, validate_1.parseQuery)(admin_schemas_1.menuAuditLogQuerySchema, req)));
|
|
}
|
|
catch (err) {
|
|
next(err);
|
|
}
|
|
});
|
|
// ─── Renters ───────────────────────────────────────────────────
|
|
router.get('/renters', requireAdminAuth_1.requireAdminAuth, async (req, res, next) => {
|
|
try {
|
|
(0, respond_1.ok)(res, await service.listRenters((0, validate_1.parseQuery)(admin_schemas_1.rentersQuerySchema, req)));
|
|
}
|
|
catch (err) {
|
|
next(err);
|
|
}
|
|
});
|
|
router.post('/renters/:id/block', requireAdminAuth_1.requireAdminAuth, (0, requireAdminAuth_1.requireAdminRole)('SUPPORT'), async (req, res, next) => {
|
|
try {
|
|
const { id } = (0, validate_1.parseParams)(admin_schemas_1.idParamSchema, req);
|
|
await service.setRenterActive(id, false);
|
|
(0, respond_1.ok)(res, { success: true });
|
|
}
|
|
catch (err) {
|
|
next(err);
|
|
}
|
|
});
|
|
router.post('/renters/:id/unblock', requireAdminAuth_1.requireAdminAuth, (0, requireAdminAuth_1.requireAdminRole)('SUPPORT'), async (req, res, next) => {
|
|
try {
|
|
const { id } = (0, validate_1.parseParams)(admin_schemas_1.idParamSchema, req);
|
|
await service.setRenterActive(id, true);
|
|
(0, respond_1.ok)(res, { success: true });
|
|
}
|
|
catch (err) {
|
|
next(err);
|
|
}
|
|
});
|
|
// ─── Metrics ───────────────────────────────────────────────────
|
|
router.get('/metrics', requireAdminAuth_1.requireAdminAuth, (0, requireAdminAuth_1.requireAdminRole)('FINANCE'), async (req, res, next) => {
|
|
try {
|
|
(0, respond_1.ok)(res, await service.getPlatformMetrics());
|
|
}
|
|
catch (err) {
|
|
next(err);
|
|
}
|
|
});
|
|
// ─── Notifications ─────────────────────────────────────────────
|
|
router.get('/notifications', requireAdminAuth_1.requireAdminAuth, (0, requireAdminAuth_1.requireAdminRole)('SUPPORT'), async (req, res, next) => {
|
|
try {
|
|
(0, respond_1.ok)(res, await service.listNotifications((0, validate_1.parseQuery)(admin_schemas_1.notificationsQuerySchema, req)));
|
|
}
|
|
catch (err) {
|
|
next(err);
|
|
}
|
|
});
|
|
// ─── Audit logs ────────────────────────────────────────────────
|
|
router.get('/audit-logs', requireAdminAuth_1.requireAdminAuth, (0, requireAdminAuth_1.requireAdminRole)('ADMIN'), async (req, res, next) => {
|
|
try {
|
|
(0, respond_1.ok)(res, await service.getAuditLogs((0, validate_1.parseQuery)(admin_schemas_1.auditLogQuerySchema, req)));
|
|
}
|
|
catch (err) {
|
|
next(err);
|
|
}
|
|
});
|
|
// ─── Admin users ───────────────────────────────────────────────
|
|
router.get('/admins', requireAdminAuth_1.requireAdminAuth, (0, requireAdminAuth_1.requireAdminRole)('SUPER_ADMIN'), async (req, res, next) => {
|
|
try {
|
|
(0, respond_1.ok)(res, await service.listAdmins());
|
|
}
|
|
catch (err) {
|
|
next(err);
|
|
}
|
|
});
|
|
router.post('/admins', requireAdminAuth_1.requireAdminAuth, (0, requireAdminAuth_1.requireAdminRole)('SUPER_ADMIN'), requireAdminAuth_1.requireFreshAdmin2FA, async (req, res, next) => {
|
|
try {
|
|
(0, respond_1.created)(res, { data: await service.createAdmin((0, validate_1.parseBody)(admin_schemas_1.createAdminSchema, req)) });
|
|
}
|
|
catch (err) {
|
|
next(err);
|
|
}
|
|
});
|
|
router.patch('/admins/:id', requireAdminAuth_1.requireAdminAuth, (0, requireAdminAuth_1.requireAdminRole)('SUPER_ADMIN'), requireAdminAuth_1.requireFreshAdmin2FA, async (req, res, next) => {
|
|
try {
|
|
const { id } = (0, validate_1.parseParams)(admin_schemas_1.idParamSchema, req);
|
|
(0, respond_1.ok)(res, await service.updateAdmin(id, (0, validate_1.parseBody)(admin_schemas_1.updateAdminSchema, req)));
|
|
}
|
|
catch (err) {
|
|
next(err);
|
|
}
|
|
});
|
|
router.patch('/admins/:id/role', requireAdminAuth_1.requireAdminAuth, (0, requireAdminAuth_1.requireAdminRole)('SUPER_ADMIN'), requireAdminAuth_1.requireFreshAdmin2FA, async (req, res, next) => {
|
|
try {
|
|
const { id } = (0, validate_1.parseParams)(admin_schemas_1.idParamSchema, req);
|
|
const { role } = (0, validate_1.parseBody)(admin_schemas_1.adminRoleSchema, req);
|
|
await service.updateAdminRole(id, role);
|
|
(0, respond_1.ok)(res, { success: true });
|
|
}
|
|
catch (err) {
|
|
next(err);
|
|
}
|
|
});
|
|
router.patch('/admins/:id/permissions', requireAdminAuth_1.requireAdminAuth, (0, requireAdminAuth_1.requireAdminRole)('SUPER_ADMIN'), requireAdminAuth_1.requireFreshAdmin2FA, async (req, res, next) => {
|
|
try {
|
|
const { id } = (0, validate_1.parseParams)(admin_schemas_1.idParamSchema, req);
|
|
const { permissions } = (0, validate_1.parseBody)(admin_schemas_1.adminPermissionsSchema, req);
|
|
(0, respond_1.ok)(res, await service.updateAdminPermissions(id, permissions));
|
|
}
|
|
catch (err) {
|
|
next(err);
|
|
}
|
|
});
|
|
// ─── Billing ───────────────────────────────────────────────────
|
|
router.get('/billing', requireAdminAuth_1.requireAdminAuth, (0, requireAdminAuth_1.requireAdminRole)('FINANCE'), async (req, res, next) => {
|
|
try {
|
|
(0, respond_1.ok)(res, await service.getBilling((0, validate_1.parseQuery)(admin_schemas_1.billingQuerySchema, req)));
|
|
}
|
|
catch (err) {
|
|
next(err);
|
|
}
|
|
});
|
|
router.get('/billing/invoices/:invoiceId/pdf', requireAdminAuth_1.requireAdminAuth, (0, requireAdminAuth_1.requireAdminRole)('FINANCE'), async (req, res, next) => {
|
|
try {
|
|
const { invoiceId } = (0, validate_1.parseParams)(admin_schemas_1.invoiceIdParamSchema, req);
|
|
const { pdfBuffer, invoiceNumber } = await service.getInvoicePdf(invoiceId);
|
|
res.setHeader('Content-Type', 'application/pdf');
|
|
res.setHeader('Content-Disposition', `attachment; filename="${invoiceNumber}.pdf"`);
|
|
res.setHeader('Content-Length', pdfBuffer.length);
|
|
res.end(pdfBuffer);
|
|
}
|
|
catch (err) {
|
|
next(err);
|
|
}
|
|
});
|
|
router.get('/billing/:companyId', requireAdminAuth_1.requireAdminAuth, (0, requireAdminAuth_1.requireAdminRole)('FINANCE'), async (req, res, next) => {
|
|
try {
|
|
const { companyId } = (0, validate_1.parseParams)(admin_schemas_1.companyIdParamSchema, req);
|
|
(0, respond_1.ok)(res, await service.getBillingAccountDetail(companyId));
|
|
}
|
|
catch (err) {
|
|
next(err);
|
|
}
|
|
});
|
|
router.get('/billing/:companyId/invoices', requireAdminAuth_1.requireAdminAuth, (0, requireAdminAuth_1.requireAdminRole)('FINANCE'), async (req, res, next) => {
|
|
try {
|
|
const { companyId } = (0, validate_1.parseParams)(admin_schemas_1.companyIdParamSchema, req);
|
|
(0, respond_1.ok)(res, await service.getCompanyInvoices(companyId, (0, validate_1.parseQuery)(admin_schemas_1.invoicesQuerySchema, req)));
|
|
}
|
|
catch (err) {
|
|
next(err);
|
|
}
|
|
});
|
|
router.patch('/billing/accounts/:billingAccountId', requireAdminAuth_1.requireAdminAuth, (0, requireAdminAuth_1.requireAdminRole)('FINANCE'), async (req, res, next) => {
|
|
try {
|
|
const { billingAccountId } = (0, validate_1.parseParams)(admin_schemas_1.billingAccountIdParamSchema, req);
|
|
(0, respond_1.ok)(res, await service.updateBillingAccount(billingAccountId, (0, validate_1.parseBody)(admin_schemas_1.billingAccountUpdateSchema, req), req.admin.id, req.ip));
|
|
}
|
|
catch (err) {
|
|
next(err);
|
|
}
|
|
});
|
|
router.post('/billing/accounts/:billingAccountId/pause-dunning', requireAdminAuth_1.requireAdminAuth, (0, requireAdminAuth_1.requireAdminRole)('FINANCE'), async (req, res, next) => {
|
|
try {
|
|
const { billingAccountId } = (0, validate_1.parseParams)(admin_schemas_1.billingAccountIdParamSchema, req);
|
|
(0, respond_1.ok)(res, await service.setDunningPaused(billingAccountId, true, req.admin.id, req.ip));
|
|
}
|
|
catch (err) {
|
|
next(err);
|
|
}
|
|
});
|
|
router.post('/billing/accounts/:billingAccountId/resume-dunning', requireAdminAuth_1.requireAdminAuth, (0, requireAdminAuth_1.requireAdminRole)('FINANCE'), async (req, res, next) => {
|
|
try {
|
|
const { billingAccountId } = (0, validate_1.parseParams)(admin_schemas_1.billingAccountIdParamSchema, req);
|
|
(0, respond_1.ok)(res, await service.setDunningPaused(billingAccountId, false, req.admin.id, req.ip));
|
|
}
|
|
catch (err) {
|
|
next(err);
|
|
}
|
|
});
|
|
router.post('/billing/accounts/:billingAccountId/invoices', requireAdminAuth_1.requireAdminAuth, (0, requireAdminAuth_1.requireAdminRole)('FINANCE'), async (req, res, next) => {
|
|
try {
|
|
const { billingAccountId } = (0, validate_1.parseParams)(admin_schemas_1.billingAccountIdParamSchema, req);
|
|
(0, respond_1.created)(res, await service.createBillingInvoice(billingAccountId, (0, validate_1.parseBody)(admin_schemas_1.createBillingInvoiceSchema, req), req.admin.id, req.ip));
|
|
}
|
|
catch (err) {
|
|
next(err);
|
|
}
|
|
});
|
|
router.post('/billing/invoices/:invoiceId/finalize', requireAdminAuth_1.requireAdminAuth, (0, requireAdminAuth_1.requireAdminRole)('FINANCE'), async (req, res, next) => {
|
|
try {
|
|
const { invoiceId } = (0, validate_1.parseParams)(admin_schemas_1.invoiceIdParamSchema, req);
|
|
(0, respond_1.ok)(res, await service.finalizeBillingInvoice(invoiceId, req.admin.id, req.ip));
|
|
}
|
|
catch (err) {
|
|
next(err);
|
|
}
|
|
});
|
|
router.post('/billing/invoices/:invoiceId/pay', requireAdminAuth_1.requireAdminAuth, (0, requireAdminAuth_1.requireAdminRole)('FINANCE'), requireAdminAuth_1.requireFreshAdmin2FA, async (req, res, next) => {
|
|
try {
|
|
const { invoiceId } = (0, validate_1.parseParams)(admin_schemas_1.invoiceIdParamSchema, req);
|
|
(0, respond_1.ok)(res, await service.payBillingInvoice(invoiceId, (0, validate_1.parseBody)(admin_schemas_1.payBillingInvoiceSchema, req), req.admin.id, req.ip));
|
|
}
|
|
catch (err) {
|
|
next(err);
|
|
}
|
|
});
|
|
router.post('/billing/invoices/:invoiceId/retry-payment', requireAdminAuth_1.requireAdminAuth, (0, requireAdminAuth_1.requireAdminRole)('FINANCE'), async (req, res, next) => {
|
|
try {
|
|
const { invoiceId } = (0, validate_1.parseParams)(admin_schemas_1.invoiceIdParamSchema, req);
|
|
(0, respond_1.ok)(res, await service.retryBillingInvoicePayment(invoiceId, (0, validate_1.parseBody)(admin_schemas_1.retryBillingInvoiceSchema, req), req.admin.id, req.ip));
|
|
}
|
|
catch (err) {
|
|
next(err);
|
|
}
|
|
});
|
|
router.post('/billing/invoices/:invoiceId/void', requireAdminAuth_1.requireAdminAuth, (0, requireAdminAuth_1.requireAdminRole)('FINANCE'), async (req, res, next) => {
|
|
try {
|
|
const { invoiceId } = (0, validate_1.parseParams)(admin_schemas_1.invoiceIdParamSchema, req);
|
|
const { reason } = (0, validate_1.parseBody)(admin_schemas_1.billingReasonSchema, req);
|
|
(0, respond_1.ok)(res, await service.voidBillingInvoice(invoiceId, reason, req.admin.id, req.ip));
|
|
}
|
|
catch (err) {
|
|
next(err);
|
|
}
|
|
});
|
|
router.post('/billing/invoices/:invoiceId/uncollectible', requireAdminAuth_1.requireAdminAuth, (0, requireAdminAuth_1.requireAdminRole)('FINANCE'), async (req, res, next) => {
|
|
try {
|
|
const { invoiceId } = (0, validate_1.parseParams)(admin_schemas_1.invoiceIdParamSchema, req);
|
|
const { reason } = (0, validate_1.parseBody)(admin_schemas_1.billingReasonSchema, req);
|
|
(0, respond_1.ok)(res, await service.markBillingInvoiceUncollectible(invoiceId, reason, req.admin.id, req.ip));
|
|
}
|
|
catch (err) {
|
|
next(err);
|
|
}
|
|
});
|
|
router.post('/billing/invoices/:invoiceId/credit-notes', requireAdminAuth_1.requireAdminAuth, (0, requireAdminAuth_1.requireAdminRole)('FINANCE'), async (req, res, next) => {
|
|
try {
|
|
const { invoiceId } = (0, validate_1.parseParams)(admin_schemas_1.invoiceIdParamSchema, req);
|
|
(0, respond_1.ok)(res, await service.issueBillingCreditNote(invoiceId, (0, validate_1.parseBody)(admin_schemas_1.billingCreditNoteSchema, req), req.admin.id, req.ip));
|
|
}
|
|
catch (err) {
|
|
next(err);
|
|
}
|
|
});
|
|
router.post('/billing/invoices/:invoiceId/refunds', requireAdminAuth_1.requireAdminAuth, (0, requireAdminAuth_1.requireAdminRole)('FINANCE'), requireAdminAuth_1.requireFreshAdmin2FA, async (req, res, next) => {
|
|
try {
|
|
const { invoiceId } = (0, validate_1.parseParams)(admin_schemas_1.invoiceIdParamSchema, req);
|
|
(0, respond_1.ok)(res, await service.issueBillingRefund(invoiceId, (0, validate_1.parseBody)(admin_schemas_1.billingRefundSchema, req), req.admin.id, req.ip));
|
|
}
|
|
catch (err) {
|
|
next(err);
|
|
}
|
|
});
|
|
// ─── Pricing config ────────────────────────────────────────────
|
|
router.get('/pricing', requireAdminAuth_1.requireAdminAuth, (0, requireAdminAuth_1.requireAdminRole)('FINANCE'), async (req, res, next) => {
|
|
try {
|
|
(0, respond_1.ok)(res, await service.getPricingConfigs());
|
|
}
|
|
catch (err) {
|
|
next(err);
|
|
}
|
|
});
|
|
router.patch('/pricing', requireAdminAuth_1.requireAdminAuth, (0, requireAdminAuth_1.requireAdminRole)('FINANCE'), requireAdminAuth_1.requireFreshAdmin2FA, async (req, res, next) => {
|
|
try {
|
|
const { entries } = (0, validate_1.parseBody)(admin_schemas_1.pricingUpdateSchema, req);
|
|
(0, respond_1.ok)(res, await service.updatePricingConfigs(entries, req.admin.id, req.ip));
|
|
}
|
|
catch (err) {
|
|
next(err);
|
|
}
|
|
});
|
|
router.get('/pricing/features', requireAdminAuth_1.requireAdminAuth, (0, requireAdminAuth_1.requireAdminRole)('FINANCE'), async (_req, res, next) => {
|
|
try {
|
|
(0, respond_1.ok)(res, await service.listPlanFeatures());
|
|
}
|
|
catch (err) {
|
|
next(err);
|
|
}
|
|
});
|
|
router.post('/pricing/features', requireAdminAuth_1.requireAdminAuth, (0, requireAdminAuth_1.requireAdminRole)('FINANCE'), requireAdminAuth_1.requireFreshAdmin2FA, async (req, res, next) => {
|
|
try {
|
|
const data = (0, validate_1.parseBody)(admin_schemas_1.planFeatureCreateSchema, req);
|
|
(0, respond_1.created)(res, await service.createPlanFeature(data, req.admin.id, req.ip));
|
|
}
|
|
catch (err) {
|
|
next(err);
|
|
}
|
|
});
|
|
router.patch('/pricing/features/:featureId', requireAdminAuth_1.requireAdminAuth, (0, requireAdminAuth_1.requireAdminRole)('FINANCE'), requireAdminAuth_1.requireFreshAdmin2FA, async (req, res, next) => {
|
|
try {
|
|
const { featureId } = (0, validate_1.parseParams)(admin_schemas_1.planFeatureIdParamSchema, req);
|
|
const data = (0, validate_1.parseBody)(admin_schemas_1.planFeatureUpdateSchema, req);
|
|
(0, respond_1.ok)(res, await service.updatePlanFeature(featureId, data, req.admin.id, req.ip));
|
|
}
|
|
catch (err) {
|
|
next(err);
|
|
}
|
|
});
|
|
router.delete('/pricing/features/:featureId', requireAdminAuth_1.requireAdminAuth, (0, requireAdminAuth_1.requireAdminRole)('FINANCE'), requireAdminAuth_1.requireFreshAdmin2FA, async (req, res, next) => {
|
|
try {
|
|
const { featureId } = (0, validate_1.parseParams)(admin_schemas_1.planFeatureIdParamSchema, req);
|
|
await service.deletePlanFeature(featureId, req.admin.id, req.ip);
|
|
(0, respond_1.ok)(res, { success: true });
|
|
}
|
|
catch (err) {
|
|
next(err);
|
|
}
|
|
});
|
|
// ─── Promotions ────────────────────────────────────────────────────────────
|
|
router.get('/pricing/promotions', requireAdminAuth_1.requireAdminAuth, (0, requireAdminAuth_1.requireAdminRole)('FINANCE'), async (req, res, next) => {
|
|
try {
|
|
(0, respond_1.ok)(res, await service.listPromotions());
|
|
}
|
|
catch (err) {
|
|
next(err);
|
|
}
|
|
});
|
|
router.post('/pricing/promotions', requireAdminAuth_1.requireAdminAuth, (0, requireAdminAuth_1.requireAdminRole)('FINANCE'), requireAdminAuth_1.requireFreshAdmin2FA, async (req, res, next) => {
|
|
try {
|
|
const data = (0, validate_1.parseBody)(admin_schemas_1.promotionCreateSchema, req);
|
|
(0, respond_1.created)(res, await service.createPromotion(data, req.admin.id, req.ip));
|
|
}
|
|
catch (err) {
|
|
next(err);
|
|
}
|
|
});
|
|
router.patch('/pricing/promotions/:promotionId', requireAdminAuth_1.requireAdminAuth, (0, requireAdminAuth_1.requireAdminRole)('FINANCE'), requireAdminAuth_1.requireFreshAdmin2FA, async (req, res, next) => {
|
|
try {
|
|
const { promotionId } = (0, validate_1.parseParams)(admin_schemas_1.promotionIdParamSchema, req);
|
|
const data = (0, validate_1.parseBody)(admin_schemas_1.promotionUpdateSchema, req);
|
|
(0, respond_1.ok)(res, await service.updatePromotion(promotionId, data, req.admin.id, req.ip));
|
|
}
|
|
catch (err) {
|
|
next(err);
|
|
}
|
|
});
|
|
router.delete('/pricing/promotions/:promotionId', requireAdminAuth_1.requireAdminAuth, (0, requireAdminAuth_1.requireAdminRole)('FINANCE'), requireAdminAuth_1.requireFreshAdmin2FA, async (req, res, next) => {
|
|
try {
|
|
const { promotionId } = (0, validate_1.parseParams)(admin_schemas_1.promotionIdParamSchema, req);
|
|
await service.deletePromotion(promotionId, req.admin.id, req.ip);
|
|
(0, respond_1.ok)(res, { success: true });
|
|
}
|
|
catch (err) {
|
|
next(err);
|
|
}
|
|
});
|
|
// ─── Subscription admin overrides ─────────────────────────────
|
|
router.get('/subscriptions/:subscriptionId/events', requireAdminAuth_1.requireAdminAuth, (0, requireAdminAuth_1.requireAdminRole)('SUPPORT'), async (req, res, next) => {
|
|
try {
|
|
const { subscriptionId } = (0, validate_1.parseParams)(subIdParamSchema, req);
|
|
(0, respond_1.ok)(res, await subService.getEventsBySubscriptionId(subscriptionId));
|
|
}
|
|
catch (err) {
|
|
next(err);
|
|
}
|
|
});
|
|
router.post('/subscriptions/:subscriptionId/extend-trial', requireAdminAuth_1.requireAdminAuth, (0, requireAdminAuth_1.requireAdminRole)('SUPPORT'), requireAdminAuth_1.requireFreshAdmin2FA, async (req, res, next) => {
|
|
try {
|
|
const { subscriptionId } = (0, validate_1.parseParams)(subIdParamSchema, req);
|
|
const { extraDays, reason } = (0, validate_1.parseBody)(adminExtendTrialSchema, req);
|
|
(0, respond_1.ok)(res, await subService.adminExtendTrial(subscriptionId, extraDays, req.admin.id, reason));
|
|
}
|
|
catch (err) {
|
|
next(err);
|
|
}
|
|
});
|
|
router.post('/subscriptions/:subscriptionId/extend-grace-period', requireAdminAuth_1.requireAdminAuth, (0, requireAdminAuth_1.requireAdminRole)('SUPPORT'), requireAdminAuth_1.requireFreshAdmin2FA, async (req, res, next) => {
|
|
try {
|
|
const { subscriptionId } = (0, validate_1.parseParams)(subIdParamSchema, req);
|
|
const { reason } = (0, validate_1.parseBody)(adminSubOverrideSchema, req);
|
|
(0, respond_1.ok)(res, await subService.adminExtendGracePeriod(subscriptionId, 7, req.admin.id, reason));
|
|
}
|
|
catch (err) {
|
|
next(err);
|
|
}
|
|
});
|
|
router.post('/subscriptions/:subscriptionId/suspend', requireAdminAuth_1.requireAdminAuth, (0, requireAdminAuth_1.requireAdminRole)('SUPPORT'), requireAdminAuth_1.requireFreshAdmin2FA, async (req, res, next) => {
|
|
try {
|
|
const { subscriptionId } = (0, validate_1.parseParams)(subIdParamSchema, req);
|
|
const { reason } = (0, validate_1.parseBody)(adminSubOverrideSchema, req);
|
|
(0, respond_1.ok)(res, await subService.adminSuspendSubscription(subscriptionId, req.admin.id, reason));
|
|
}
|
|
catch (err) {
|
|
next(err);
|
|
}
|
|
});
|
|
router.post('/subscriptions/:subscriptionId/reactivate', requireAdminAuth_1.requireAdminAuth, (0, requireAdminAuth_1.requireAdminRole)('SUPPORT'), requireAdminAuth_1.requireFreshAdmin2FA, async (req, res, next) => {
|
|
try {
|
|
const { subscriptionId } = (0, validate_1.parseParams)(subIdParamSchema, req);
|
|
const { reason } = (0, validate_1.parseBody)(adminSubOverrideSchema, req);
|
|
(0, respond_1.ok)(res, await subService.adminReactivateSubscription(subscriptionId, req.admin.id, reason));
|
|
}
|
|
catch (err) {
|
|
next(err);
|
|
}
|
|
});
|
|
router.post('/subscriptions/:subscriptionId/cancel', requireAdminAuth_1.requireAdminAuth, (0, requireAdminAuth_1.requireAdminRole)('SUPPORT'), requireAdminAuth_1.requireFreshAdmin2FA, async (req, res, next) => {
|
|
try {
|
|
const { subscriptionId } = (0, validate_1.parseParams)(subIdParamSchema, req);
|
|
const { reason } = (0, validate_1.parseBody)(adminSubOverrideSchema, req);
|
|
(0, respond_1.ok)(res, await subService.adminCancelSubscription(subscriptionId, req.admin.id, reason));
|
|
}
|
|
catch (err) {
|
|
next(err);
|
|
}
|
|
});
|
|
// ─── Site config ───────────────────────────────────────────────
|
|
router.get('/site-config/marketplace-homepage', requireAdminAuth_1.requireAdminAuth, async (req, res, next) => {
|
|
try {
|
|
(0, respond_1.ok)(res, await service.getMarketplaceHomepage());
|
|
}
|
|
catch (err) {
|
|
next(err);
|
|
}
|
|
});
|
|
router.patch('/site-config/marketplace-homepage', requireAdminAuth_1.requireAdminAuth, (0, requireAdminAuth_1.requireAdminRole)('SUPPORT'), async (req, res, next) => {
|
|
try {
|
|
const { homepage } = (0, validate_1.parseBody)(admin_schemas_1.homepageUpdateSchema, req);
|
|
(0, respond_1.ok)(res, await service.updateMarketplaceHomepage(homepage, req.admin.id, req.ip));
|
|
}
|
|
catch (err) {
|
|
next(err);
|
|
}
|
|
});
|
|
exports.default = router;
|
|
//# sourceMappingURL=admin.routes.js.map
|