feat: harden sessions and track downstream acknowledgements

This commit is contained in:
hectorzhao
2026-07-14 14:18:43 +08:00
parent 3d37adcc9f
commit 8c03663f24
43 changed files with 1733 additions and 150 deletions
@@ -1,5 +1,6 @@
import { Body, Controller, Get, Param, Post, Put, Query } from '@nestjs/common';
import { ApiTags } from '@nestjs/swagger';
import { RequireRecentAuthentication } from '../auth/require-recent-authentication.decorator';
import { CreateSmsApplicationDto, CreateSmsDrainageInfoDto, CreateSmsSignatureDto, CreateSmsTemplateDto, ReplaceApplicationRouteRulesDto, ReviewDto, SmsConfigService, StatusChangeDto, UpdateSmsApplicationDto, UpdateSmsDrainageInfoDto, UpdateSmsSignatureDto, UpdateSmsTemplateDto } from './sms-config.service';
@ApiTags('admin-sms-config')
@@ -23,16 +24,19 @@ export class AdminSmsConfigController {
}
@Post('enterprise-applications')
@RequireRecentAuthentication()
createApplication(@Body() body: CreateSmsApplicationDto) {
return this.smsConfig.createApplication(body);
}
@Put('enterprise-applications/:id')
@RequireRecentAuthentication()
updateApplication(@Param('id') applicationId: string, @Body() body: UpdateSmsApplicationDto) {
return this.smsConfig.updateApplication(applicationId, body);
}
@Put('enterprise-applications/:id/route-rules')
@RequireRecentAuthentication()
replaceApplicationRouteRules(@Param('id') applicationId: string, @Body() body: ReplaceApplicationRouteRulesDto) {
return this.smsConfig.replaceApplicationRouteRules(applicationId, body);
}
@@ -78,16 +82,19 @@ export class AdminSmsConfigController {
}
@Post('drainage-infos/:id/approve')
@RequireRecentAuthentication()
approveDrainageInfo(@Param('id') itemId: string, @Body() body: ReviewDto) {
return this.smsConfig.approveDrainageInfo(itemId, body);
}
@Post('drainage-infos/:id/reject')
@RequireRecentAuthentication()
rejectDrainageInfo(@Param('id') itemId: string, @Body() body: ReviewDto) {
return this.smsConfig.rejectDrainageInfo(itemId, body);
}
@Post('drainage-infos/:id/status')
@RequireRecentAuthentication()
changeDrainageInfoStatus(@Param('id') itemId: string, @Body() body: StatusChangeDto) {
return this.smsConfig.changeDrainageInfoStatus(itemId, body);
}
@@ -113,36 +120,43 @@ export class AdminSmsConfigController {
}
@Post('signatures/:id/approve')
@RequireRecentAuthentication()
approveSignature(@Param('id') signatureId: string, @Body() body: ReviewDto) {
return this.smsConfig.approveSignature(signatureId, body);
}
@Post('signatures/:id/reject')
@RequireRecentAuthentication()
rejectSignature(@Param('id') signatureId: string, @Body() body: ReviewDto) {
return this.smsConfig.rejectSignature(signatureId, body);
}
@Post('templates/:id/approve')
@RequireRecentAuthentication()
approveTemplate(@Param('id') templateId: string, @Body() body: ReviewDto) {
return this.smsConfig.approveTemplate(templateId, body);
}
@Post('templates/:id/reject')
@RequireRecentAuthentication()
rejectTemplate(@Param('id') templateId: string, @Body() body: ReviewDto) {
return this.smsConfig.rejectTemplate(templateId, body);
}
@Post('enterprise-applications/:id/status')
@RequireRecentAuthentication()
changeApplicationStatus(@Param('id') applicationId: string, @Body() body: StatusChangeDto) {
return this.smsConfig.changeApplicationStatus(applicationId, body);
}
@Post('enterprise-signatures/:id/status')
@RequireRecentAuthentication()
changeSignatureStatus(@Param('id') signatureId: string, @Body() body: StatusChangeDto) {
return this.smsConfig.changeSignatureStatus(signatureId, body);
}
@Post('enterprise-templates/:id/status')
@RequireRecentAuthentication()
changeTemplateStatus(@Param('id') templateId: string, @Body() body: StatusChangeDto) {
return this.smsConfig.changeTemplateStatus(templateId, body);
}
@@ -1,6 +1,7 @@
import { Body, Controller, Get, Param, Post, Put } from '@nestjs/common';
import { ApiTags } from '@nestjs/swagger';
import { TenantId } from '../common/tenant-id.decorator';
import { RequireRecentAuthentication } from '../auth/require-recent-authentication.decorator';
import {
CreateSignatureMaterialDto,
CreateSmsApplicationDto,
@@ -39,11 +40,13 @@ export class ClientSmsConfigController {
}
@Post('applications/:id/secret/reset')
@RequireRecentAuthentication()
resetApplicationSecret(@Param('id') applicationId: string, @Body() body: StatusChangeDto) {
return this.smsConfig.resetApplicationSecret(applicationId, body);
}
@Post('applications/:id/status')
@RequireRecentAuthentication()
changeApplicationStatus(@Param('id') applicationId: string, @Body() body: StatusChangeDto) {
return this.smsConfig.changeApplicationStatus(applicationId, body);
}
@@ -271,6 +271,8 @@ describe('SmsConfigService', () => {
interfaceEnabled: false,
interfaceType: 'cmpp20',
queuePriority: 'priority',
downstreamReceiptRetryEnabled: true,
downstreamUplinkRetryEnabled: true,
ipAllowlist: { create: [{ ipCidr: '10.0.0.1/32' }] },
}),
}));
+6
View File
@@ -20,6 +20,8 @@ export interface CreateSmsApplicationDto {
queuePriority?: string;
maxPhonesPerTask?: number;
templateMismatchMode?: string;
downstreamReceiptRetryEnabled?: boolean;
downstreamUplinkRetryEnabled?: boolean;
ipAllowlist?: string[];
}
@@ -314,6 +316,8 @@ export class SmsConfigService {
queuePriority,
maxPhonesPerTask: data.maxPhonesPerTask ?? 1000000,
templateMismatchMode: data.templateMismatchMode ?? 'reject',
downstreamReceiptRetryEnabled: data.downstreamReceiptRetryEnabled ?? true,
downstreamUplinkRetryEnabled: data.downstreamUplinkRetryEnabled ?? true,
ipAllowlist: {
create: (data.ipAllowlist ?? []).map((ipCidr) => ({ ipCidr })),
},
@@ -365,6 +369,8 @@ export class SmsConfigService {
queuePriority,
maxPhonesPerTask: data.maxPhonesPerTask,
templateMismatchMode: data.templateMismatchMode,
downstreamReceiptRetryEnabled: data.downstreamReceiptRetryEnabled,
downstreamUplinkRetryEnabled: data.downstreamUplinkRetryEnabled,
status: data.status,
ipAllowlist: data.ipAllowlist ? {
create: data.ipAllowlist.map((ipCidr) => ({ ipCidr })),