335 lines
11 KiB
TypeScript
335 lines
11 KiB
TypeScript
|
|
import { Router, Request, Response } from 'express';
|
||
|
|
import { SaasTenantService } from '../../services/tenant/SaasTenantService';
|
||
|
|
import { TenantDomainMiddleware } from '../../middleware/TenantDomainMiddleware';
|
||
|
|
import { logger } from '../../utils/logger';
|
||
|
|
|
||
|
|
const router = Router();
|
||
|
|
|
||
|
|
router.use(TenantDomainMiddleware.resolveTenant);
|
||
|
|
|
||
|
|
router.get('/tenants', async (req: Request, res: Response) => {
|
||
|
|
try {
|
||
|
|
const filters: any = {};
|
||
|
|
|
||
|
|
if (req.query.status) {
|
||
|
|
filters.status = req.query.status as string;
|
||
|
|
}
|
||
|
|
if (req.query.plan) {
|
||
|
|
filters.plan = req.query.plan as string;
|
||
|
|
}
|
||
|
|
if (req.query.type) {
|
||
|
|
filters.type = req.query.type as string;
|
||
|
|
}
|
||
|
|
|
||
|
|
const tenants = await SaasTenantService.listTenants(filters);
|
||
|
|
|
||
|
|
res.json({ success: true, data: tenants });
|
||
|
|
} catch (error: any) {
|
||
|
|
logger.error('[SaasTenantAPI] Error listing tenants:', error);
|
||
|
|
res.status(500).json({ error: error.message });
|
||
|
|
}
|
||
|
|
});
|
||
|
|
|
||
|
|
router.get('/tenants/:tenantId', async (req: Request, res: Response) => {
|
||
|
|
try {
|
||
|
|
const tenant = await SaasTenantService.getTenant(req.params.tenantId as string);
|
||
|
|
|
||
|
|
if (!tenant) {
|
||
|
|
return res.status(404).json({ error: 'Tenant not found' });
|
||
|
|
}
|
||
|
|
|
||
|
|
res.json({ success: true, data: tenant });
|
||
|
|
} catch (error: any) {
|
||
|
|
logger.error('[SaasTenantAPI] Error getting tenant:', error);
|
||
|
|
res.status(500).json({ error: error.message });
|
||
|
|
}
|
||
|
|
});
|
||
|
|
|
||
|
|
router.post('/tenants', async (req: Request, res: Response) => {
|
||
|
|
try {
|
||
|
|
const tenant = await SaasTenantService.createTenant(req.body);
|
||
|
|
|
||
|
|
res.status(201).json({ success: true, data: tenant });
|
||
|
|
} catch (error: any) {
|
||
|
|
logger.error('[SaasTenantAPI] Error creating tenant:', error);
|
||
|
|
res.status(500).json({ error: error.message });
|
||
|
|
}
|
||
|
|
});
|
||
|
|
|
||
|
|
router.get('/tenants/:tenantId/domains', async (req: Request, res: Response) => {
|
||
|
|
try {
|
||
|
|
const domains = await SaasTenantService.getTenantDomains(req.params.tenantId as string);
|
||
|
|
|
||
|
|
res.json({ success: true, data: domains });
|
||
|
|
} catch (error: any) {
|
||
|
|
logger.error('[SaasTenantAPI] Error getting tenant domains:', error);
|
||
|
|
res.status(500).json({ error: error.message });
|
||
|
|
}
|
||
|
|
});
|
||
|
|
|
||
|
|
router.post('/tenants/:tenantId/domains', async (req: Request, res: Response) => {
|
||
|
|
try {
|
||
|
|
const { domain, type } = req.body;
|
||
|
|
|
||
|
|
if (!domain) {
|
||
|
|
return res.status(400).json({ error: 'Domain is required' });
|
||
|
|
}
|
||
|
|
|
||
|
|
const tenantDomain = await SaasTenantService.addDomain(
|
||
|
|
req.params.tenantId as string,
|
||
|
|
domain,
|
||
|
|
type || 'SUBDOMAIN'
|
||
|
|
);
|
||
|
|
|
||
|
|
res.status(201).json({ success: true, data: tenantDomain });
|
||
|
|
} catch (error: any) {
|
||
|
|
logger.error('[SaasTenantAPI] Error adding domain:', error);
|
||
|
|
res.status(500).json({ error: error.message });
|
||
|
|
}
|
||
|
|
});
|
||
|
|
|
||
|
|
router.post('/domains/:domainId/verify', async (req: Request, res: Response) => {
|
||
|
|
try {
|
||
|
|
const domain = await SaasTenantService.verifyDomain(req.params.domainId as string);
|
||
|
|
|
||
|
|
res.json({ success: true, data: domain });
|
||
|
|
} catch (error: any) {
|
||
|
|
logger.error('[SaasTenantAPI] Error verifying domain:', error);
|
||
|
|
res.status(500).json({ error: error.message });
|
||
|
|
}
|
||
|
|
});
|
||
|
|
|
||
|
|
router.post('/domains/:domainId/primary', async (req: Request, res: Response) => {
|
||
|
|
try {
|
||
|
|
await SaasTenantService.setPrimaryDomain(req.params.domainId as string);
|
||
|
|
|
||
|
|
res.json({ success: true, message: 'Primary domain set successfully' });
|
||
|
|
} catch (error: any) {
|
||
|
|
logger.error('[SaasTenantAPI] Error setting primary domain:', error);
|
||
|
|
res.status(500).json({ error: error.message });
|
||
|
|
}
|
||
|
|
});
|
||
|
|
|
||
|
|
router.get('/tenants/:tenantId/users', async (req: Request, res: Response) => {
|
||
|
|
try {
|
||
|
|
const users = await SaasTenantService.getTenantUsers(req.params.tenantId as string);
|
||
|
|
|
||
|
|
res.json({ success: true, data: users });
|
||
|
|
} catch (error: any) {
|
||
|
|
logger.error('[SaasTenantAPI] Error getting tenant users:', error);
|
||
|
|
res.status(500).json({ error: error.message });
|
||
|
|
}
|
||
|
|
});
|
||
|
|
|
||
|
|
router.post('/tenants/:tenantId/users', async (req: Request, res: Response) => {
|
||
|
|
try {
|
||
|
|
const { userId, role, permissions } = req.body;
|
||
|
|
|
||
|
|
if (!userId) {
|
||
|
|
return res.status(400).json({ error: 'User ID is required' });
|
||
|
|
}
|
||
|
|
|
||
|
|
const tenantUser = await SaasTenantService.addUser(
|
||
|
|
req.params.tenantId as string,
|
||
|
|
userId,
|
||
|
|
role || 'OPERATOR',
|
||
|
|
permissions || []
|
||
|
|
);
|
||
|
|
|
||
|
|
res.status(201).json({ success: true, data: tenantUser });
|
||
|
|
} catch (error: any) {
|
||
|
|
logger.error('[SaasTenantAPI] Error adding user:', error);
|
||
|
|
res.status(500).json({ error: error.message });
|
||
|
|
}
|
||
|
|
});
|
||
|
|
|
||
|
|
router.put('/tenants/:tenantId/users/:userId', async (req: Request, res: Response) => {
|
||
|
|
try {
|
||
|
|
const { role, permissions } = req.body;
|
||
|
|
|
||
|
|
if (!role) {
|
||
|
|
return res.status(400).json({ error: 'Role is required' });
|
||
|
|
}
|
||
|
|
|
||
|
|
const tenantUser = await SaasTenantService.updateUserRole(
|
||
|
|
req.params.tenantId as string,
|
||
|
|
req.params.userId as string,
|
||
|
|
role,
|
||
|
|
permissions || []
|
||
|
|
);
|
||
|
|
|
||
|
|
res.json({ success: true, data: tenantUser });
|
||
|
|
} catch (error: any) {
|
||
|
|
logger.error('[SaasTenantAPI] Error updating user role:', error);
|
||
|
|
res.status(500).json({ error: error.message });
|
||
|
|
}
|
||
|
|
});
|
||
|
|
|
||
|
|
router.get('/users/:userId/tenants', async (req: Request, res: Response) => {
|
||
|
|
try {
|
||
|
|
const tenants = await SaasTenantService.getUserTenants(req.params.userId as string);
|
||
|
|
|
||
|
|
res.json({ success: true, data: tenants });
|
||
|
|
} catch (error: any) {
|
||
|
|
logger.error('[SaasTenantAPI] Error getting user tenants:', error);
|
||
|
|
res.status(500).json({ error: error.message });
|
||
|
|
}
|
||
|
|
});
|
||
|
|
|
||
|
|
router.get('/tenants/:tenantId/settings', async (req: Request, res: Response) => {
|
||
|
|
try {
|
||
|
|
const category = req.query.category as string;
|
||
|
|
const settings = await SaasTenantService.getSettings(req.params.tenantId as string, category);
|
||
|
|
|
||
|
|
res.json({ success: true, data: settings });
|
||
|
|
} catch (error: any) {
|
||
|
|
logger.error('[SaasTenantAPI] Error getting tenant settings:', error);
|
||
|
|
res.status(500).json({ error: error.message });
|
||
|
|
}
|
||
|
|
});
|
||
|
|
|
||
|
|
router.get('/tenants/:tenantId/settings/:key', async (req: Request, res: Response) => {
|
||
|
|
try {
|
||
|
|
const tenantId = Array.isArray(req.params.tenantId) ? req.params.tenantId[0] : req.params.tenantId;
|
||
|
|
const key = Array.isArray(req.params.key) ? req.params.key[0] : req.params.key;
|
||
|
|
const value = await SaasTenantService.getSetting(tenantId, key);
|
||
|
|
|
||
|
|
if (value === null) {
|
||
|
|
return res.status(404).json({ error: 'Setting not found' });
|
||
|
|
}
|
||
|
|
|
||
|
|
res.json({ success: true, data: { key, value } });
|
||
|
|
} catch (error: any) {
|
||
|
|
logger.error('[SaasTenantAPI] Error getting tenant setting:', error);
|
||
|
|
res.status(500).json({ error: error.message });
|
||
|
|
}
|
||
|
|
});
|
||
|
|
|
||
|
|
router.put('/tenants/:tenantId/settings/:key', async (req: Request, res: Response) => {
|
||
|
|
try {
|
||
|
|
const { value, category } = req.body;
|
||
|
|
|
||
|
|
if (value === undefined) {
|
||
|
|
return res.status(400).json({ error: 'Value is required' });
|
||
|
|
}
|
||
|
|
|
||
|
|
const tenantId = Array.isArray(req.params.tenantId) ? req.params.tenantId[0] : req.params.tenantId;
|
||
|
|
const key = Array.isArray(req.params.key) ? req.params.key[0] : req.params.key;
|
||
|
|
|
||
|
|
await SaasTenantService.setSetting(
|
||
|
|
tenantId,
|
||
|
|
key,
|
||
|
|
value,
|
||
|
|
category || 'general'
|
||
|
|
);
|
||
|
|
|
||
|
|
res.json({ success: true, message: 'Setting updated successfully' });
|
||
|
|
} catch (error: any) {
|
||
|
|
logger.error('[SaasTenantAPI] Error setting tenant setting:', error);
|
||
|
|
res.status(500).json({ error: error.message });
|
||
|
|
}
|
||
|
|
});
|
||
|
|
|
||
|
|
router.get('/current-tenant', (req: Request, res: Response) => {
|
||
|
|
if (!req.tenant) {
|
||
|
|
return res.status(404).json({ error: 'No tenant found for current request' });
|
||
|
|
}
|
||
|
|
|
||
|
|
res.json({ success: true, data: req.tenant });
|
||
|
|
});
|
||
|
|
|
||
|
|
router.put('/tenants/:tenantId', async (req: Request, res: Response) => {
|
||
|
|
try {
|
||
|
|
const tenant = await SaasTenantService.updateTenant(req.params.tenantId as string, req.body);
|
||
|
|
|
||
|
|
res.json({ success: true, data: tenant });
|
||
|
|
} catch (error: any) {
|
||
|
|
logger.error('[SaasTenantAPI] Error updating tenant:', error);
|
||
|
|
res.status(500).json({ error: error.message });
|
||
|
|
}
|
||
|
|
});
|
||
|
|
|
||
|
|
router.delete('/tenants/:tenantId', async (req: Request, res: Response) => {
|
||
|
|
try {
|
||
|
|
await SaasTenantService.deleteTenant(req.params.tenantId as string);
|
||
|
|
|
||
|
|
res.json({ success: true, message: 'Tenant deleted successfully' });
|
||
|
|
} catch (error: any) {
|
||
|
|
logger.error('[SaasTenantAPI] Error deleting tenant:', error);
|
||
|
|
res.status(500).json({ error: error.message });
|
||
|
|
}
|
||
|
|
});
|
||
|
|
|
||
|
|
router.put('/tenants/:tenantId/status', async (req: Request, res: Response) => {
|
||
|
|
try {
|
||
|
|
const { status } = req.body;
|
||
|
|
|
||
|
|
if (!status) {
|
||
|
|
return res.status(400).json({ error: 'Status is required' });
|
||
|
|
}
|
||
|
|
|
||
|
|
const tenant = await SaasTenantService.updateTenantStatus(req.params.tenantId as string, status);
|
||
|
|
|
||
|
|
res.json({ success: true, data: tenant });
|
||
|
|
} catch (error: any) {
|
||
|
|
logger.error('[SaasTenantAPI] Error updating tenant status:', error);
|
||
|
|
res.status(500).json({ error: error.message });
|
||
|
|
}
|
||
|
|
});
|
||
|
|
|
||
|
|
router.delete('/domains/:domainId', async (req: Request, res: Response) => {
|
||
|
|
try {
|
||
|
|
await SaasTenantService.deleteDomain(req.params.domainId as string);
|
||
|
|
|
||
|
|
res.json({ success: true, message: 'Domain deleted successfully' });
|
||
|
|
} catch (error: any) {
|
||
|
|
logger.error('[SaasTenantAPI] Error deleting domain:', error);
|
||
|
|
res.status(500).json({ error: error.message });
|
||
|
|
}
|
||
|
|
});
|
||
|
|
|
||
|
|
router.delete('/tenants/:tenantId/users/:userId', async (req: Request, res: Response) => {
|
||
|
|
try {
|
||
|
|
await SaasTenantService.removeUser(req.params.tenantId as string, req.params.userId as string);
|
||
|
|
|
||
|
|
res.json({ success: true, message: 'User removed successfully' });
|
||
|
|
} catch (error: any) {
|
||
|
|
logger.error('[SaasTenantAPI] Error removing user:', error);
|
||
|
|
res.status(500).json({ error: error.message });
|
||
|
|
}
|
||
|
|
});
|
||
|
|
|
||
|
|
router.get('/stats', async (req: Request, res: Response) => {
|
||
|
|
try {
|
||
|
|
const stats = await SaasTenantService.getStats();
|
||
|
|
|
||
|
|
res.json({ success: true, data: stats });
|
||
|
|
} catch (error: any) {
|
||
|
|
logger.error('[SaasTenantAPI] Error getting stats:', error);
|
||
|
|
res.status(500).json({ error: error.message });
|
||
|
|
}
|
||
|
|
});
|
||
|
|
|
||
|
|
router.get('/tenants/:tenantId/usage', async (req: Request, res: Response) => {
|
||
|
|
try {
|
||
|
|
const usage = await SaasTenantService.getUsage(req.params.tenantId as string);
|
||
|
|
|
||
|
|
res.json({ success: true, data: usage });
|
||
|
|
} catch (error: any) {
|
||
|
|
logger.error('[SaasTenantAPI] Error getting tenant usage:', error);
|
||
|
|
res.status(500).json({ error: error.message });
|
||
|
|
}
|
||
|
|
});
|
||
|
|
|
||
|
|
router.get('/tenants/:tenantId/logs', async (req: Request, res: Response) => {
|
||
|
|
try {
|
||
|
|
const logs = await SaasTenantService.getOperationLogs(req.params.tenantId as string);
|
||
|
|
|
||
|
|
res.json({ success: true, data: logs });
|
||
|
|
} catch (error: any) {
|
||
|
|
logger.error('[SaasTenantAPI] Error getting operation logs:', error);
|
||
|
|
res.status(500).json({ error: error.message });
|
||
|
|
}
|
||
|
|
});
|
||
|
|
|
||
|
|
export default router;
|