Files
api/src/notifications/central-sms.service.ts
T
MahdiandCursor a6b3457779 Add production-ready SuperAdmin API features for tenants, SMS, servers, and plugins.
Includes mobile auth, get_user/get_version, SMS wallet parity endpoints, appearance backfill, and related Prisma migrations.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-30 18:19:53 +03:30

84 lines
2.5 KiB
TypeScript

import { Injectable, Logger } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import axios from 'axios';
import { normalizeMobile } from '../common/mobile.util';
export type CentralSmsResult = {
success: boolean;
raw?: unknown;
error?: string;
};
@Injectable()
export class CentralSmsService {
private readonly logger = new Logger(CentralSmsService.name);
constructor(private readonly config: ConfigService) {}
async send(phone: string, text: string): Promise<CentralSmsResult> {
const to = normalizeMobile(phone);
const message = text.trim();
if (!to) {
return { success: false, error: 'شماره موبایل نامعتبر است' };
}
if (!message) {
return { success: false, error: 'متن پیامک خالی است' };
}
const url =
this.config.get<string>('CENTRAL_SMS_URL') ||
'http://185.231.112.101/api/createsms';
const secret = this.config.get<string>('CENTRAL_SMS_SECRET')?.trim();
if (!secret) {
this.logger.error('CENTRAL_SMS_SECRET is not configured');
return { success: false, error: 'سرویس پیامک پیکربندی نشده است' };
}
const host =
this.config.get<string>('CENTRAL_SMS_HOST') || 'superadmin';
const platform =
this.config.get<string>('CENTRAL_SMS_PLATFORM') || 'superadmin';
try {
const response = await axios.post(
url,
{
phone: to,
host,
text: message,
platform,
},
{
timeout: 15000,
headers: {
'Content-Type': 'application/json',
secret_key: secret,
},
// Prefer IPv4 like Hamkar curl CURLOPT_IPRESOLVE_V4
family: 4,
validateStatus: () => true,
},
);
const body = response.data;
let success = response.status >= 200 && response.status < 300;
if (body && typeof body === 'object') {
if (body.success === false || body.ok === false) success = false;
const status = String(body.status ?? '').toLowerCase();
if (['error', 'failed', 'fail'].includes(status)) success = false;
}
if (!success) {
this.logger.warn(`Central SMS failed to ${to} (HTTP ${response.status})`);
}
return { success, raw: body };
} catch (error: any) {
const msg = error?.message || 'SMS send error';
this.logger.error(`Central SMS exception to ${to}: ${msg}`);
return { success: false, error: msg };
}
}
}