omnichannel-backend/src/modules/whatsapp/whatsapp-config.service.ts

86 lines
3.1 KiB
TypeScript
Raw Normal View History

import { Injectable } from '@nestjs/common';
import { WhatsappConfigRepository } from './repositories/whatsapp-config.repository';
interface WhatsappConfig {
access_token: string | null;
phone_number_id: string | null;
api_version: string;
webhook_token: string | null;
}
@Injectable()
export class WhatsappConfigService {
private _cache: { config: WhatsappConfig; expiresAt: number } | null = null;
private readonly CACHE_TTL_MS = 60_000;
constructor(private readonly repo: WhatsappConfigRepository) {}
async getConfig(): Promise<WhatsappConfig> {
if (this._cache && Date.now() < this._cache.expiresAt) {
return this._cache.config;
}
const row = await this.repo.find();
const config: WhatsappConfig = {
access_token: row?.access_token || process.env.META_ACCESS_TOKEN || null,
phone_number_id: row?.phone_number_id || process.env.META_PHONE_NUMBER_ID || null,
api_version: row?.api_version || process.env.META_API_VERSION || 'v25.0',
webhook_token: row?.webhook_token || process.env.META_WEBHOOK_TOKEN || null,
};
this._cache = { config, expiresAt: Date.now() + this.CACHE_TTL_MS };
return config;
}
async getPublicConfig() {
const row = await this.repo.find();
const effectiveToken = row?.access_token || process.env.META_ACCESS_TOKEN;
const effectivePhoneId = row?.phone_number_id || process.env.META_PHONE_NUMBER_ID;
return {
phone_number_id: effectivePhoneId || null,
api_version: row?.api_version || process.env.META_API_VERSION || 'v25.0',
webhook_token: row?.webhook_token || process.env.META_WEBHOOK_TOKEN || null,
is_configured: !!(effectiveToken && effectivePhoneId),
has_token: !!effectiveToken,
token_source: row?.access_token ? 'database' : effectiveToken ? 'env' : null,
updated_at: row?.updated_at || null,
};
}
async saveConfig(
dto: { access_token?: string; phone_number_id?: string; api_version?: string; webhook_token?: string },
userId?: number,
) {
this._cache = null;
await this.repo.update({
access_token: dto.access_token || null,
phone_number_id: dto.phone_number_id || null,
api_version: dto.api_version || null,
webhook_token: dto.webhook_token || null,
updated_by: userId,
});
return this.getPublicConfig();
}
async validateCredentials(token: string, phoneNumberId: string, apiVersion = 'v25.0') {
const url = `https://graph.facebook.com/${apiVersion}/${phoneNumberId}?access_token=${token}&fields=display_phone_number,verified_name,quality_rating`;
try {
const response = await fetch(url);
const data = (await response.json()) as any;
if (!response.ok) {
return {
valid: false,
error: data?.error?.message || 'Credenciais inválidas',
code: data?.error?.code,
};
}
return {
valid: true,
phone_number: data.display_phone_number,
verified_name: data.verified_name,
quality_rating: data.quality_rating,
};
} catch {
return { valid: false, error: 'Erro de conexão com a Meta API' };
}
}
}