Интеграция с sms.ru
This commit is contained in:
parent
053bd699f3
commit
1461d16983
|
|
@ -1,4 +1,5 @@
|
|||
import { Module } from '@nestjs/common';
|
||||
import { ConfigModule } from '@nestjs/config';
|
||||
import { AppController } from './app.controller';
|
||||
import { AppService } from './app.service';
|
||||
import { YachtsModule } from './yachts/yachts.module';
|
||||
|
|
@ -10,7 +11,16 @@ import { ReviewsModule } from './reviews/reviews.module';
|
|||
import { ReservationsModule } from './reservations/reservations.module';
|
||||
|
||||
@Module({
|
||||
imports: [YachtsModule, CatalogModule, AuthModule, UsersModule, FilesModule, ReviewsModule, ReservationsModule],
|
||||
imports: [
|
||||
ConfigModule.forRoot({ isGlobal: true }),
|
||||
YachtsModule,
|
||||
CatalogModule,
|
||||
AuthModule,
|
||||
UsersModule,
|
||||
FilesModule,
|
||||
ReviewsModule,
|
||||
ReservationsModule,
|
||||
],
|
||||
controllers: [AppController],
|
||||
providers: [AppService],
|
||||
})
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import { Module } from '@nestjs/common';
|
||||
import { ConfigModule } from '@nestjs/config';
|
||||
import { AuthService } from './auth.service';
|
||||
import { AuthController } from './auth.controller';
|
||||
import { UsersModule } from '../users/users.module';
|
||||
|
|
@ -10,6 +11,7 @@ import { RefreshTokenStoreService } from './refresh-token-store.service';
|
|||
|
||||
@Module({
|
||||
imports: [
|
||||
ConfigModule,
|
||||
UsersModule,
|
||||
JwtModule.register({
|
||||
secret: jwtConstants.secret,
|
||||
|
|
|
|||
|
|
@ -1,7 +1,26 @@
|
|||
import { Injectable, Logger } from '@nestjs/common';
|
||||
import { ConfigService } from '@nestjs/config';
|
||||
|
||||
export const SMS_SERVICE = 'SmsService';
|
||||
|
||||
const SMS_RU_SEND_URL = 'https://sms.ru/sms/send';
|
||||
|
||||
/** Ответ API sms.ru (фрагмент для одного номера). */
|
||||
interface SmsRuSmsItem {
|
||||
status: string;
|
||||
status_code: number;
|
||||
sms_id?: string;
|
||||
status_text?: string;
|
||||
}
|
||||
|
||||
/** Ответ API sms.ru при json=1. */
|
||||
interface SmsRuResponse {
|
||||
status: string;
|
||||
status_code: number;
|
||||
sms?: Record<string, SmsRuSmsItem>;
|
||||
balance?: number;
|
||||
}
|
||||
|
||||
/** Интерфейс для отправки SMS. В проде подставьте реализацию (SMS.ru, Twilio и т.д.). */
|
||||
export interface ISmsSender {
|
||||
sendVerificationCode(phone: string, code: string): Promise<void>;
|
||||
|
|
@ -10,10 +29,67 @@ export interface ISmsSender {
|
|||
@Injectable()
|
||||
export class SmsService implements ISmsSender {
|
||||
private readonly logger = new Logger(SmsService.name);
|
||||
private readonly apiId: string | undefined;
|
||||
private readonly isDev: boolean;
|
||||
|
||||
constructor(private readonly configService: ConfigService) {
|
||||
this.apiId = this.configService.get<string>('SMS_RU_API_ID');
|
||||
this.isDev = this.configService.get<string>('NODE_ENV') === 'development';
|
||||
if (!this.apiId && !this.isDev) {
|
||||
this.logger.warn(
|
||||
'SMS_RU_API_ID не задан — SMS не отправляются, код верификации только логируется',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
async sendVerificationCode(phone: string, code: string): Promise<void> {
|
||||
// Заглушка: в разработке только логируем. Подключите реальный провайдер SMS.
|
||||
this.logger.log(`[SMS] Код для ${phone}: ${code}`);
|
||||
// await this.smsProvider.send(phone, `Ваш код: ${code}`);
|
||||
if (this.isDev) {
|
||||
this.logger.log(`[dev] Код верификации для ${phone}: ${code}`);
|
||||
return;
|
||||
}
|
||||
|
||||
const msg = `Ваш код: ${code}`;
|
||||
const to = this.toSmsRuPhone(phone);
|
||||
|
||||
if (!this.apiId) {
|
||||
this.logger.log(`[SMS stub] Код для ${phone}: ${code}`);
|
||||
return;
|
||||
}
|
||||
|
||||
const url = new URL(SMS_RU_SEND_URL);
|
||||
url.searchParams.set('api_id', this.apiId);
|
||||
url.searchParams.set('to', to);
|
||||
url.searchParams.set('msg', msg);
|
||||
url.searchParams.set('json', '1');
|
||||
|
||||
try {
|
||||
const res = await fetch(url.toString());
|
||||
const data = (await res.json()) as SmsRuResponse;
|
||||
|
||||
if (data.status !== 'OK' || data.status_code !== 100) {
|
||||
this.logger.error(`SMS.ru: ошибка запроса status=${data.status} status_code=${data.status_code}`);
|
||||
throw new Error(`SMS.ru: ${data.status_code}`);
|
||||
}
|
||||
|
||||
const item = data.sms?.[to];
|
||||
if (item?.status !== 'OK') {
|
||||
const text = item?.status_text ?? 'неизвестная ошибка';
|
||||
this.logger.error(`SMS.ru: не удалось отправить на ${to}: ${text}`);
|
||||
throw new Error(`SMS.ru: ${text}`);
|
||||
}
|
||||
|
||||
this.logger.log(`SMS отправлен на ${phone}, код=${code}, sms_id=${item.sms_id ?? '—'}`);
|
||||
} catch (err) {
|
||||
this.logger.error(`Ошибка отправки SMS на ${phone}:`, err);
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
/** Номер в формате sms.ru: только цифры, например 79255070602. */
|
||||
private toSmsRuPhone(phone: string): string {
|
||||
const digits = phone.replace(/\D/g, '');
|
||||
if (digits.length === 10 && digits.startsWith('9')) return '7' + digits;
|
||||
if (digits.length === 11 && digits.startsWith('7')) return digits;
|
||||
return digits;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue