Files
grow-api/src/sms-settings/sms-settings.service.ts
T
2026-07-11 22:08:41 +03:30

152 lines
4.4 KiB
TypeScript

import {
BadRequestException,
ForbiddenException,
Injectable,
NotFoundException,
} from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { ServicePolicy } from '../authorization/policies/service.policy';
import { AuthUser } from '../auth/interfaces/auth-user.interface';
import { SmsTemplatesService } from '../sms-templates/sms-templates.service';
import {
SMS_SCENARIO_MAP,
SmsScenarioDefinition,
} from './constants/sms-scenarios.constants';
import {
PreviewSmsScenarioDto,
UpdateSmsScenarioSettingDto,
} from './dto/update-sms-scenario-setting.dto';
import { SmsScenarioSetting } from './entities/sms-scenario-setting.entity';
import { SmsScenarioKey } from './enums/sms-scenario-key.enum';
import { SmsDispatchService } from './sms-dispatch.service';
import { isCampaignSmsScenarioKey } from './utils/is-campaign-sms-scenario.util';
export interface SmsScenarioSettingResponse {
key: SmsScenarioKey;
body: string | null;
templateId: string | null;
templateTitle: string | null;
isActive: boolean;
definition: SmsScenarioDefinition;
preview: string;
}
@Injectable()
export class SmsSettingsService {
constructor(
@InjectRepository(SmsScenarioSetting)
private readonly settingsRepository: Repository<SmsScenarioSetting>,
private readonly smsDispatchService: SmsDispatchService,
private readonly smsTemplatesService: SmsTemplatesService,
private readonly servicePolicy: ServicePolicy,
) {}
getScenarioDefinitions(): SmsScenarioDefinition[] {
return this.smsDispatchService
.getScenarioDefinitions()
.filter((definition) => !isCampaignSmsScenarioKey(definition.key));
}
async findAll(user: AuthUser): Promise<SmsScenarioSettingResponse[]> {
this.ensureCanManage(user);
const settings = await this.smsDispatchService.findAllSettings();
return Promise.all(
settings
.filter((setting) => !isCampaignSmsScenarioKey(setting.key))
.map((setting) => this.toResponse(setting)),
);
}
async update(
key: SmsScenarioKey,
updateDto: UpdateSmsScenarioSettingDto,
user: AuthUser,
): Promise<SmsScenarioSettingResponse> {
this.ensureCanManage(user);
if (!SMS_SCENARIO_MAP.has(key)) {
throw new NotFoundException(`SMS scenario "${key}" not found`);
}
const setting = await this.smsDispatchService.findSettingByKey(key);
if (updateDto.templateId) {
await this.smsTemplatesService.findOne(updateDto.templateId);
setting.templateId = updateDto.templateId;
setting.body = null;
} else if (updateDto.templateId === null) {
setting.templateId = null;
}
if (updateDto.body !== undefined) {
setting.body = updateDto.body;
if (updateDto.body) {
setting.templateId = null;
}
}
if (updateDto.isActive !== undefined) {
setting.isActive = updateDto.isActive;
}
if (!setting.templateId && !setting.body) {
throw new BadRequestException(
'Either body text or a template must be configured',
);
}
const saved = await this.settingsRepository.save(setting);
return this.toResponse(saved);
}
async preview(
dto: PreviewSmsScenarioDto,
user: AuthUser,
): Promise<{ preview: string }> {
this.ensureCanManage(user);
const preview = await this.smsDispatchService.previewMessage(dto);
return { preview };
}
private async toResponse(
setting: SmsScenarioSetting,
): Promise<SmsScenarioSettingResponse> {
const definition = SMS_SCENARIO_MAP.get(setting.key);
if (!definition) {
throw new NotFoundException(`SMS scenario "${setting.key}" not found`);
}
let templateTitle: string | null = null;
if (setting.templateId) {
const template = await this.smsTemplatesService.findOne(
setting.templateId,
);
templateTitle = template.title;
}
const preview = await this.smsDispatchService.previewMessage({
key: setting.key,
body: setting.body ?? undefined,
templateId: setting.templateId,
});
return {
key: setting.key,
body: setting.body,
templateId: setting.templateId,
templateTitle,
isActive: setting.isActive,
definition,
preview,
};
}
private ensureCanManage(user: AuthUser): void {
if (!this.servicePolicy.canManage(user)) {
throw new ForbiddenException();
}
}
}