136 lines
3.5 KiB
TypeScript
136 lines
3.5 KiB
TypeScript
import {
|
|||
|
|
BadGatewayException,
|
||
|
|
Injectable,
|
||
|
|
NotFoundException,
|
||
|
|
} from '@nestjs/common';
|
||
|
|
import axios from 'axios';
|
||
|
|
import { Prisma } from '@prisma/client';
|
||
|
|
import { PrismaService } from '../prisma/prisma.service';
|
||
|
|
import { AuditService } from '../audit/audit.service';
|
||
|
|
|
||
|
|
@Injectable()
|
||
|
|
export class SettingsProxyService {
|
||
|
|
constructor(
|
||
|
|
private readonly prisma: PrismaService,
|
||
|
|
private readonly audit: AuditService,
|
||
|
|
) {}
|
||
|
|
|
||
|
|
async getSettings(tenantId: string) {
|
||
|
|
const tenant = await this.requireTenant(tenantId);
|
||
|
|
|
||
|
|
if (!tenant.remoteApiToken) {
|
||
|
|
return {
|
||
|
|
stub: true,
|
||
|
|
message:
|
||
|
|
'remoteApiToken تنظیم نشده. فعلاً stub است تا endpoint سوپر روی Laravel اضافه شود.',
|
||
|
|
tenant: {
|
||
|
|
id: tenant.id,
|
||
|
|
slug: tenant.slug,
|
||
|
|
nodeServer: tenant.nodeServer,
|
||
|
|
},
|
||
|
|
settings: [],
|
||
|
|
};
|
||
|
|
}
|
||
|
|
|
||
|
|
try {
|
||
|
|
const { data } = await axios.get(
|
||
|
|
this.joinUrl(tenant.nodeServer, '/super/settings'),
|
||
|
|
{
|
||
|
|
headers: {
|
||
|
|
Authorization: `Bearer ${tenant.remoteApiToken}`,
|
||
|
|
Accept: 'application/json',
|
||
|
|
},
|
||
|
|
timeout: 15000,
|
||
|
|
},
|
||
|
|
);
|
||
|
|
return { stub: false, settings: data };
|
||
|
|
} catch (error) {
|
||
|
|
throw new BadGatewayException(
|
||
|
|
this.axiosMessage(error, 'خواندن تنظیمات از سرور نسخه ناموفق بود'),
|
||
|
|
);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
async updateSettings(
|
||
|
|
tenantId: string,
|
||
|
|
payload: Record<string, unknown>,
|
||
|
|
userId?: string,
|
||
|
|
) {
|
||
|
|
const tenant = await this.requireTenant(tenantId);
|
||
|
|
|
||
|
|
if (!tenant.remoteApiToken) {
|
||
|
|
await this.audit.log({
|
||
|
|
action: 'settings.proxy.stub_update',
|
||
|
|
entityType: 'tenant_settings',
|
||
|
|
entityId: tenantId,
|
||
|
|
tenantId,
|
||
|
|
userId,
|
||
|
|
after: payload as Prisma.InputJsonValue,
|
||
|
|
meta: { stub: true },
|
||
|
|
});
|
||
|
|
|
||
|
|
return {
|
||
|
|
stub: true,
|
||
|
|
message:
|
||
|
|
'remoteApiToken تنظیم نشده؛ تغییر فقط در audit ثبت شد (stub).',
|
||
|
|
accepted: payload,
|
||
|
|
};
|
||
|
|
}
|
||
|
|
|
||
|
|
try {
|
||
|
|
const { data } = await axios.post(
|
||
|
|
this.joinUrl(tenant.nodeServer, '/super/settings'),
|
||
|
|
payload,
|
||
|
|
{
|
||
|
|
headers: {
|
||
|
|
Authorization: `Bearer ${tenant.remoteApiToken}`,
|
||
|
|
Accept: 'application/json',
|
||
|
|
'Content-Type': 'application/json',
|
||
|
|
},
|
||
|
|
timeout: 20000,
|
||
|
|
},
|
||
|
|
);
|
||
|
|
|
||
|
|
await this.audit.log({
|
||
|
|
action: 'settings.proxy.update',
|
||
|
|
entityType: 'tenant_settings',
|
||
|
|
entityId: tenantId,
|
||
|
|
tenantId,
|
||
|
|
userId,
|
||
|
|
after: payload as Prisma.InputJsonValue,
|
||
|
|
});
|
||
|
|
|
||
|
|
return { stub: false, result: data };
|
||
|
|
} catch (error) {
|
||
|
|
throw new BadGatewayException(
|
||
|
|
this.axiosMessage(error, 'ذخیره تنظیمات روی سرور نسخه ناموفق بود'),
|
||
|
|
);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
private async requireTenant(tenantId: string) {
|
||
|
|
const tenant = await this.prisma.tenant.findUnique({
|
||
|
|
where: { id: tenantId },
|
||
|
|
});
|
||
|
|
if (!tenant) {
|
||
|
|
throw new NotFoundException('نسخه یافت نشد');
|
||
|
|
}
|
||
|
|
return tenant;
|
||
|
|
}
|
||
|
|
|
||
|
|
private joinUrl(base: string, path: string) {
|
||
|
|
return `${base.replace(/\/$/, '')}${path}`;
|
||
|
|
}
|
||
|
|
|
||
|
|
private axiosMessage(error: unknown, fallback: string) {
|
||
|
|
if (axios.isAxiosError(error)) {
|
||
|
|
const status = error.response?.status;
|
||
|
|
const body = error.response?.data;
|
||
|
|
return `${fallback}${status ? ` (HTTP ${status})` : ''}${
|
||
|
|
body ? `: ${JSON.stringify(body)}` : ''
|
||
|
|
}`;
|
||
|
|
}
|
||
|
|
return fallback;
|
||
|
|
}
|
||
|
|
}
|