fix: polish channel groups and add production deployment

This commit is contained in:
hectorzhao
2026-07-07 11:16:08 +08:00
parent b5132d7f4e
commit 72f2c010ce
44 changed files with 1265 additions and 489 deletions
+26 -12
View File
@@ -33,6 +33,7 @@ export interface CreateChannelGroupDto {
status?: string;
retryEnabled?: boolean;
retryTimeLimitHours?: number;
retryTimeLimitMinutes?: number;
}
export interface CreateChannelGroupItemDto {
@@ -54,6 +55,7 @@ export interface UpdateChannelGroupDto {
status?: string;
retryEnabled?: boolean;
retryTimeLimitHours?: number;
retryTimeLimitMinutes?: number;
items?: Array<Omit<CreateChannelGroupItemDto, 'groupId'>>;
}
@@ -175,7 +177,11 @@ export class ChannelsService implements OnModuleInit, OnModuleDestroy {
}
listChannels() {
return this.prisma.smsChannel.findMany({ orderBy: { createdAt: 'desc' }, take: 100 });
return this.prisma.smsChannel.findMany({
include: { connectionStates: true },
orderBy: { createdAt: 'desc' },
take: 100,
});
}
async createChannel(data: CreateChannelDto) {
@@ -574,17 +580,14 @@ export class ChannelsService implements OnModuleInit, OnModuleDestroy {
listGroups() {
return this.prisma.smsChannelGroup.findMany({
include: { items: { include: { channel: true }, orderBy: [{ province: 'asc' }, { priority: 'asc' }] } },
include: { items: { include: { channel: { include: { connectionStates: true } } }, orderBy: [{ province: 'asc' }, { priority: 'asc' }] } },
orderBy: { createdAt: 'desc' },
take: 100,
});
}
createGroup(data: CreateChannelGroupDto) {
const retryTimeLimitHours = data.retryTimeLimitHours ?? 72;
if (!Number.isInteger(retryTimeLimitHours) || retryTimeLimitHours <= 0 || retryTimeLimitHours > 72) {
throw new BadRequestException('retryTimeLimitHours must be an integer between 1 and 72');
}
const retryTimeLimitMinutes = normalizeRetryTimeLimitMinutes(data.retryTimeLimitMinutes, data.retryTimeLimitHours, 720);
const carrier = normalizeBusinessCarrier(data.carrier);
return this.prisma.smsChannelGroup.create({
data: {
@@ -594,7 +597,8 @@ export class ChannelsService implements OnModuleInit, OnModuleDestroy {
description: data.description,
status: data.status ?? 'active',
retryEnabled: data.retryEnabled ?? true,
retryTimeLimitHours,
retryTimeLimitHours: Math.ceil(retryTimeLimitMinutes / 60),
retryTimeLimitMinutes,
},
});
}
@@ -659,10 +663,11 @@ export class ChannelsService implements OnModuleInit, OnModuleDestroy {
if (!current) {
throw new NotFoundException('Channel group not found');
}
const retryTimeLimitHours = data.retryTimeLimitHours ?? current.retryTimeLimitHours;
if (!Number.isInteger(retryTimeLimitHours) || retryTimeLimitHours <= 0 || retryTimeLimitHours > 72) {
throw new BadRequestException('retryTimeLimitHours must be an integer between 1 and 72');
}
const retryTimeLimitMinutes = normalizeRetryTimeLimitMinutes(
data.retryTimeLimitMinutes,
data.retryTimeLimitHours,
current.retryTimeLimitMinutes ?? current.retryTimeLimitHours * 60,
);
const carrier = data.carrier ? normalizeBusinessCarrier(data.carrier) : normalizeBusinessCarrier(current.carrier);
const items = data.items ?? [];
const channelIds = [...new Set(items.map((item) => item.channelId))];
@@ -681,7 +686,8 @@ export class ChannelsService implements OnModuleInit, OnModuleDestroy {
description: data.description,
status: data.status ?? current.status,
retryEnabled: data.retryEnabled ?? current.retryEnabled,
retryTimeLimitHours,
retryTimeLimitHours: Math.ceil(retryTimeLimitMinutes / 60),
retryTimeLimitMinutes,
},
});
if (items.length > 0) {
@@ -1220,6 +1226,14 @@ function deriveReceiptStatus(rowCount: number, successCount: number, failedCount
return 'completed';
}
function normalizeRetryTimeLimitMinutes(minutes: number | undefined, hours: number | undefined, fallbackMinutes: number) {
const value = minutes ?? (hours === undefined ? fallbackMinutes : hours * 60);
if (!Number.isInteger(value) || value <= 0 || value > 72 * 60) {
throw new BadRequestException('retryTimeLimitMinutes must be an integer between 1 and 4320');
}
return value;
}
function normalizeBusinessCarrier(carrier?: string | null) {
const normalized = normalizeChannelCarrier(carrier);
if (!['mobile', 'unicom', 'telecom'].includes(normalized)) {