feat: add application interface controls
This commit is contained in:
@@ -63,7 +63,7 @@ function createPrismaMock() {
|
||||
findUnique: jest.fn().mockResolvedValue({ id: 'tenant-1', status: 'active', certificationStatus: 'approved' }),
|
||||
},
|
||||
smsApplication: {
|
||||
findUnique: jest.fn().mockResolvedValue({ id: 'app-1', tenantId: 'tenant-1', cmppAccount: '100001', status: 'active', customerUnitPrice: 3, queuePriority: 'normal' }),
|
||||
findUnique: jest.fn().mockResolvedValue({ id: 'app-1', tenantId: 'tenant-1', cmppAccount: '100001', status: 'active', interfaceEnabled: true, customerUnitPrice: 3, queuePriority: 'normal' }),
|
||||
findMany: jest.fn().mockResolvedValue([{ id: 'app-1', tenantId: 'tenant-1', name: '应用A' }]),
|
||||
findFirst: jest.fn().mockResolvedValue({
|
||||
id: 'app-1',
|
||||
@@ -71,6 +71,7 @@ function createPrismaMock() {
|
||||
cmppAccount: '100001',
|
||||
secretHash: 'secret-hash',
|
||||
status: 'active',
|
||||
interfaceEnabled: true,
|
||||
queuePriority: 'normal',
|
||||
ipAllowlist: [{ ipCidr: '127.0.0.1/32' }],
|
||||
tenant: { id: 'tenant-1', status: 'active', certificationStatus: 'approved' },
|
||||
@@ -414,6 +415,74 @@ describe('SendChainService', () => {
|
||||
).rejects.toThrow('企业认证未通过,不能发送短信');
|
||||
});
|
||||
|
||||
it('blocks sending when application interface is disabled', async () => {
|
||||
const { service, prisma } = createService();
|
||||
prisma.smsApplication.findUnique.mockResolvedValue({
|
||||
id: 'app-1',
|
||||
tenantId: 'tenant-1',
|
||||
status: 'active',
|
||||
interfaceEnabled: false,
|
||||
customerUnitPrice: 3,
|
||||
queuePriority: 'normal',
|
||||
});
|
||||
|
||||
await expect(
|
||||
service.createBatchTask({
|
||||
tenantId: 'tenant-1',
|
||||
applicationId: 'app-1',
|
||||
templateId: 'tpl-1',
|
||||
content: 'hello',
|
||||
phones: ['13800000001'],
|
||||
}),
|
||||
).rejects.toThrow('短信应用接口未开通,不能发送短信');
|
||||
|
||||
expect(prisma.smsBatchTask.create).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('rejects Gateway authentication when application interface is disabled', async () => {
|
||||
const { service, prisma } = createService();
|
||||
prisma.smsApplication.findFirst.mockResolvedValue({
|
||||
id: 'app-1',
|
||||
tenantId: 'tenant-1',
|
||||
cmppAccount: '100001',
|
||||
secretHash: 'secret-hash',
|
||||
status: 'active',
|
||||
interfaceEnabled: false,
|
||||
ipAllowlist: [{ ipCidr: '127.0.0.1/32' }],
|
||||
tenant: { id: 'tenant-1', status: 'active', certificationStatus: 'approved' },
|
||||
});
|
||||
|
||||
await expect(service.authenticateInboundApplication({
|
||||
account: '100001',
|
||||
password: 'secret-hash',
|
||||
remoteIp: '127.0.0.1',
|
||||
})).rejects.toThrow('CMPP interface is disabled for this application');
|
||||
});
|
||||
|
||||
it('rejects Gateway submit when application interface is disabled', async () => {
|
||||
const { service, prisma } = createService();
|
||||
prisma.smsApplication.findFirst.mockResolvedValue({
|
||||
id: 'app-1',
|
||||
tenantId: 'tenant-1',
|
||||
cmppAccount: '100001',
|
||||
secretHash: 'secret-hash',
|
||||
status: 'active',
|
||||
interfaceEnabled: false,
|
||||
queuePriority: 'normal',
|
||||
ipAllowlist: [{ ipCidr: '127.0.0.1/32' }],
|
||||
tenant: { id: 'tenant-1', status: 'active', certificationStatus: 'approved' },
|
||||
});
|
||||
|
||||
await expect(service.submitInboundMessage({
|
||||
account: '100001',
|
||||
phoneNumber: '13800000001',
|
||||
content: 'hello',
|
||||
remoteIp: '127.0.0.1',
|
||||
})).rejects.toThrow('CMPP interface is disabled for this application');
|
||||
|
||||
expect(prisma.smsBatchTask.create).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('previews imported phone files with duplicate, invalid, blacklist, and variable errors', async () => {
|
||||
const { service, prisma } = createService();
|
||||
prisma.enterpriseBlacklist.findMany.mockResolvedValue([{ phoneNumber: '13800000003' }]);
|
||||
|
||||
Reference in New Issue
Block a user