fix: format tenant API response to match frontend DTO
Map flat quota fields to nested quota object and add userCount field to match the frontend's expected Tenant interface. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
3816d6841d
commit
8f89b8121c
|
|
@ -28,13 +28,34 @@ export class TenantController {
|
|||
private readonly tenantProvisioningService: TenantProvisioningService,
|
||||
) {}
|
||||
|
||||
private toDto(t: Tenant) {
|
||||
return {
|
||||
id: t.id,
|
||||
name: t.name,
|
||||
slug: t.slug,
|
||||
plan: t.plan,
|
||||
status: t.status,
|
||||
adminEmail: t.adminEmail,
|
||||
userCount: 0,
|
||||
quota: {
|
||||
maxServers: t.maxServers,
|
||||
maxUsers: t.maxUsers,
|
||||
maxStandingOrders: t.maxStandingOrders,
|
||||
maxAgentTokensPerMonth: t.maxAgentTokensPerMonth,
|
||||
},
|
||||
createdAt: t.createdAt,
|
||||
updatedAt: t.updatedAt,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* GET /api/v1/admin/tenants
|
||||
* Returns all tenants from the public schema's tenants table.
|
||||
*/
|
||||
@Get()
|
||||
async listTenants() {
|
||||
return this.tenantRepository.find({ order: { createdAt: 'DESC' } });
|
||||
const tenants = await this.tenantRepository.find({ order: { createdAt: 'DESC' } });
|
||||
return tenants.map((t) => this.toDto(t));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -47,7 +68,7 @@ export class TenantController {
|
|||
if (!tenant) {
|
||||
throw new NotFoundException(`Tenant with id "${id}" not found`);
|
||||
}
|
||||
return tenant;
|
||||
return this.toDto(tenant);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -95,7 +116,7 @@ export class TenantController {
|
|||
// The tenant record is already saved; schema provisioning can be retried
|
||||
}
|
||||
|
||||
return savedTenant;
|
||||
return this.toDto(savedTenant);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -103,30 +124,32 @@ export class TenantController {
|
|||
* Updates tenant metadata.
|
||||
*/
|
||||
@Patch(':id')
|
||||
async updateTenant(@Param('id') id: string, @Body() body: Partial<Tenant>) {
|
||||
async updateTenant(@Param('id') id: string, @Body() body: any) {
|
||||
const tenant = await this.tenantRepository.findOne({ where: { id } });
|
||||
if (!tenant) {
|
||||
throw new NotFoundException(`Tenant with id "${id}" not found`);
|
||||
}
|
||||
|
||||
// Only allow updating specific fields
|
||||
const allowedFields: (keyof Tenant)[] = [
|
||||
'name',
|
||||
'plan',
|
||||
'status',
|
||||
'adminEmail',
|
||||
'maxServers',
|
||||
'maxUsers',
|
||||
'maxStandingOrders',
|
||||
'maxAgentTokensPerMonth',
|
||||
];
|
||||
if (body.name !== undefined) tenant.name = body.name;
|
||||
if (body.plan !== undefined) tenant.plan = body.plan;
|
||||
if (body.status !== undefined) tenant.status = body.status;
|
||||
if (body.adminEmail !== undefined) tenant.adminEmail = body.adminEmail;
|
||||
|
||||
for (const field of allowedFields) {
|
||||
if (body[field] !== undefined) {
|
||||
(tenant as any)[field] = body[field];
|
||||
}
|
||||
// Support nested quota object from frontend
|
||||
if (body.quota) {
|
||||
if (body.quota.maxServers !== undefined) tenant.maxServers = body.quota.maxServers;
|
||||
if (body.quota.maxUsers !== undefined) tenant.maxUsers = body.quota.maxUsers;
|
||||
if (body.quota.maxStandingOrders !== undefined) tenant.maxStandingOrders = body.quota.maxStandingOrders;
|
||||
if (body.quota.maxAgentTokensPerMonth !== undefined) tenant.maxAgentTokensPerMonth = body.quota.maxAgentTokensPerMonth;
|
||||
}
|
||||
|
||||
return this.tenantRepository.save(tenant);
|
||||
// Also support flat fields
|
||||
if (body.maxServers !== undefined) tenant.maxServers = body.maxServers;
|
||||
if (body.maxUsers !== undefined) tenant.maxUsers = body.maxUsers;
|
||||
if (body.maxStandingOrders !== undefined) tenant.maxStandingOrders = body.maxStandingOrders;
|
||||
if (body.maxAgentTokensPerMonth !== undefined) tenant.maxAgentTokensPerMonth = body.maxAgentTokensPerMonth;
|
||||
|
||||
const saved = await this.tenantRepository.save(tenant);
|
||||
return this.toDto(saved);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue