W1-W3 实现企业微信个人应用消息通知
这个提交包含在:
@@ -31,7 +31,7 @@ const DELIVERY_QUERY_SCHEMA = z.object({
|
||||
const CHANNEL_ID_SCHEMA = z.string().uuid();
|
||||
const ROLE_CODE_VALUES = Object.freeze(Object.keys(ROLE_PERMISSIONS));
|
||||
const CHANNEL_TYPE_VALUES = Object.freeze(['wecom', 'wechat_work']);
|
||||
const CHANNEL_MODE_VALUES = Object.freeze(['mock', 'wecom_webhook']);
|
||||
const CHANNEL_MODE_VALUES = Object.freeze(['mock', 'wecom_webhook', 'wecom_app_message']);
|
||||
const DOMAIN_SCOPE_VALUES = Object.freeze(Object.values(NOTIFICATION_DOMAIN_SCOPES));
|
||||
const DEFAULT_TEMPLATE_JSON = Object.freeze({
|
||||
title: '{{title}}',
|
||||
@@ -195,15 +195,22 @@ function normalizeRouting(routing) {
|
||||
}
|
||||
|
||||
function normalizeConfigJson(input = {}, options = {}) {
|
||||
const mode = input.mode ?? 'mock';
|
||||
const webhookUrl = mode === 'wecom_webhook' ? String(input.webhookUrl ?? '').trim() || null : null;
|
||||
const secretFields =
|
||||
mode === 'wecom_webhook'
|
||||
? buildStoredSecretFields({
|
||||
config: options.config,
|
||||
existingConfig: options.existingConfig,
|
||||
inputSecret: input.secret,
|
||||
clearSecret: Boolean(input.clearSecret),
|
||||
})
|
||||
: {};
|
||||
|
||||
return {
|
||||
mode: input.mode ?? 'mock',
|
||||
webhookUrl: String(input.webhookUrl ?? '').trim() || null,
|
||||
...buildStoredSecretFields({
|
||||
config: options.config,
|
||||
existingConfig: options.existingConfig,
|
||||
inputSecret: input.secret,
|
||||
clearSecret: Boolean(input.clearSecret),
|
||||
}),
|
||||
mode,
|
||||
webhookUrl,
|
||||
...secretFields,
|
||||
timeoutMs: Math.max(100, Number(input.timeoutMs ?? 5000)),
|
||||
routing: normalizeRouting(input.routing),
|
||||
};
|
||||
@@ -221,11 +228,17 @@ function normalizeTemplateJson(input = {}) {
|
||||
|
||||
function mapChannelConfigForRead(configJson, options = {}) {
|
||||
const rawConfig = configJson && typeof configJson === 'object' ? configJson : {};
|
||||
const secretModel = getChannelSecretReadModel({
|
||||
config: options.config,
|
||||
configJson: rawConfig,
|
||||
logger: options.logger,
|
||||
});
|
||||
const secretModel =
|
||||
rawConfig.mode === 'wecom_webhook'
|
||||
? getChannelSecretReadModel({
|
||||
config: options.config,
|
||||
configJson: rawConfig,
|
||||
logger: options.logger,
|
||||
})
|
||||
: {
|
||||
secretConfigured: false,
|
||||
secretMasked: null,
|
||||
};
|
||||
|
||||
return {
|
||||
mode: rawConfig.mode ?? 'mock',
|
||||
@@ -693,7 +706,9 @@ async function notificationsRoutes(fastify) {
|
||||
body: `测试人:${request.employee.name}(${request.employee.id})`,
|
||||
targetType: 'notification_channel',
|
||||
targetId: channel.id,
|
||||
recipientEmployeeIds: [request.employee.id],
|
||||
},
|
||||
prisma: fastify.prisma,
|
||||
});
|
||||
|
||||
await fastify.prisma.auditLog.create({
|
||||
@@ -773,7 +788,9 @@ async function notificationsRoutes(fastify) {
|
||||
body: `测试人:${request.employee.id}`,
|
||||
targetType: 'notification_channel',
|
||||
targetId: channel.id,
|
||||
recipientEmployeeIds: [request.employee.id],
|
||||
},
|
||||
prisma: fastify.prisma,
|
||||
});
|
||||
|
||||
await fastify.prisma.auditLog.create({
|
||||
|
||||
在新工单中引用
屏蔽一个用户