fix(通知): 微信订阅消息的每条跳过路径都写日志,不再静默
以前 sendWechatSubscribeToUser 的四条提前返回(no-template / disabled-by-user / no-wechat-openid / no-access-token)都不写日志,线上排查「通知没发出去」时 容器日志里一片空白,只能靠猜。现在每条都打一行 [WeChatSubscribe] ... 跳过:原因, 另外 createSongSelectedNotification 在「用户关了通知总开关」时也补了一行。 用途:发布一首新歌后执行 docker logs --timestamps voicehub-app | grep WeChatSubscribe 即可直接看到卡在哪一步(模板没配 / 用户没绑微信 / 拿不到 token / 没有额度 43101 / 字段 47003)。
This commit is contained in:
@@ -163,6 +163,9 @@ export async function createSongSelectedNotification(
|
|||||||
|
|
||||||
// 如果用户关闭了此类通知,则不发送
|
// 如果用户关闭了此类通知,则不发送
|
||||||
if (settings && !settings.enabled) {
|
if (settings && !settings.enabled) {
|
||||||
|
console.warn(
|
||||||
|
`[Notification] SONG_SELECTED → user ${userId} 跳过:该用户关闭了通知总开关,微信/MeoW/邮件都不会发`
|
||||||
|
)
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -350,7 +353,10 @@ export async function createSongPlayedNotification(songId: number, ipAddress?: s
|
|||||||
}
|
}
|
||||||
// 同步发送 微信订阅消息(只有绑了微信、且刚点过授权的用户收得到,见 wechatSubscribeService)
|
// 同步发送 微信订阅消息(只有绑了微信、且刚点过授权的用户收得到,见 wechatSubscribeService)
|
||||||
try {
|
try {
|
||||||
await sendWechatSubscribeToUser(targetUserId, 'SONG_PLAYED', { songTitle: song.title, message: userMessage })
|
await sendWechatSubscribeToUser(targetUserId, 'SONG_PLAYED', {
|
||||||
|
songTitle: song.title,
|
||||||
|
message: userMessage
|
||||||
|
})
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('发送微信订阅消息失败:', error)
|
console.error('发送微信订阅消息失败:', error)
|
||||||
}
|
}
|
||||||
@@ -554,7 +560,11 @@ export async function createSongRejectedNotification(
|
|||||||
}
|
}
|
||||||
// 同步发送 微信订阅消息(只有绑了微信、且刚点过授权的用户收得到,见 wechatSubscribeService)
|
// 同步发送 微信订阅消息(只有绑了微信、且刚点过授权的用户收得到,见 wechatSubscribeService)
|
||||||
try {
|
try {
|
||||||
await sendWechatSubscribeToUser(userId, 'SONG_REJECTED', { songTitle: songInfo.title, reason: reason, message })
|
await sendWechatSubscribeToUser(userId, 'SONG_REJECTED', {
|
||||||
|
songTitle: songInfo.title,
|
||||||
|
reason: reason,
|
||||||
|
message
|
||||||
|
})
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('发送微信订阅消息失败:', error)
|
console.error('发送微信订阅消息失败:', error)
|
||||||
}
|
}
|
||||||
@@ -591,7 +601,9 @@ export async function createSubmissionNoteClearedNotification(
|
|||||||
ipAddress?: string
|
ipAddress?: string
|
||||||
) {
|
) {
|
||||||
try {
|
try {
|
||||||
const uniqueUserIds = [...new Set(userIds.filter((userId) => Number.isInteger(userId) && userId > 0))]
|
const uniqueUserIds = [
|
||||||
|
...new Set(userIds.filter((userId) => Number.isInteger(userId) && userId > 0))
|
||||||
|
]
|
||||||
|
|
||||||
if (uniqueUserIds.length === 0) {
|
if (uniqueUserIds.length === 0) {
|
||||||
return []
|
return []
|
||||||
@@ -651,7 +663,10 @@ export async function createSystemNotification(
|
|||||||
}
|
}
|
||||||
// 同步发送 微信订阅消息(只有绑了微信、且刚点过授权的用户收得到,见 wechatSubscribeService)
|
// 同步发送 微信订阅消息(只有绑了微信、且刚点过授权的用户收得到,见 wechatSubscribeService)
|
||||||
try {
|
try {
|
||||||
await sendWechatSubscribeToUser(userId, 'SYSTEM_NOTICE', { songTitle: title, message: content })
|
await sendWechatSubscribeToUser(userId, 'SYSTEM_NOTICE', {
|
||||||
|
songTitle: title,
|
||||||
|
message: content
|
||||||
|
})
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('发送微信订阅消息失败:', error)
|
console.error('发送微信订阅消息失败:', error)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -234,7 +234,12 @@ export async function sendWechatSubscribeToUser(
|
|||||||
): Promise<SendResult> {
|
): Promise<SendResult> {
|
||||||
try {
|
try {
|
||||||
const conf = getSubscribeTemplates()[kind]
|
const conf = getSubscribeTemplates()[kind]
|
||||||
if (!conf || !conf.id) return { ok: false, skipped: 'no-template' }
|
if (!conf || !conf.id) {
|
||||||
|
// 这四条跳过路径以前是静默 return,线上排查时日志里什么都没有,只能靠猜。
|
||||||
|
// 现在每条都留一行,grep [WeChatSubscribe] 就能看出卡在哪一步。
|
||||||
|
console.error(`[WeChatSubscribe] ${kind} → user ${userId} 跳过:没有配置模板 ID(no-template)`)
|
||||||
|
return { ok: false, skipped: 'no-template' }
|
||||||
|
}
|
||||||
|
|
||||||
// 用户的通知总开关(与 MeoW / 邮件共用同一份设置)
|
// 用户的通知总开关(与 MeoW / 邮件共用同一份设置)
|
||||||
const settings = await db
|
const settings = await db
|
||||||
@@ -243,14 +248,24 @@ export async function sendWechatSubscribeToUser(
|
|||||||
.where(eq(notificationSettings.userId, userId))
|
.where(eq(notificationSettings.userId, userId))
|
||||||
.limit(1)
|
.limit(1)
|
||||||
if (settings[0] && settings[0].enabled === false) {
|
if (settings[0] && settings[0].enabled === false) {
|
||||||
|
console.warn(`[WeChatSubscribe] ${kind} → user ${userId} 跳过:该用户的通知总开关是关的(disabled-by-user)`)
|
||||||
return { ok: false, skipped: 'disabled-by-user' }
|
return { ok: false, skipped: 'disabled-by-user' }
|
||||||
}
|
}
|
||||||
|
|
||||||
const openid = await getWechatOpenid(userId)
|
const openid = await getWechatOpenid(userId)
|
||||||
if (!openid) return { ok: false, skipped: 'no-wechat-openid' }
|
if (!openid) {
|
||||||
|
// 用户没有绑定微信(userIdentities 里没有 provider='wechat-mp' 的行)→ 永远发不出去
|
||||||
|
console.warn(`[WeChatSubscribe] ${kind} → user ${userId} 跳过:该用户没有绑定微信 openid(no-wechat-openid)`)
|
||||||
|
return { ok: false, skipped: 'no-wechat-openid' }
|
||||||
|
}
|
||||||
|
|
||||||
const token = await getMiniAccessToken()
|
const token = await getMiniAccessToken()
|
||||||
if (!token) return { ok: false, skipped: 'no-access-token' }
|
if (!token) {
|
||||||
|
console.error(
|
||||||
|
`[WeChatSubscribe] ${kind} → user ${userId} 跳过:拿不到小程序 access_token(no-access-token,检查 WECHAT_MINI_APPID / WECHAT_MINI_SECRET)`
|
||||||
|
)
|
||||||
|
return { ok: false, skipped: 'no-access-token' }
|
||||||
|
}
|
||||||
|
|
||||||
const data = buildTemplateData(conf, Object.assign({ songTitle: '宝一外校园点歌系统' }, vars))
|
const data = buildTemplateData(conf, Object.assign({ songTitle: '宝一外校园点歌系统' }, vars))
|
||||||
return await postSubscribe(token, openid, conf.id, data, userId, kind)
|
return await postSubscribe(token, openid, conf.id, data, userId, kind)
|
||||||
|
|||||||
Reference in New Issue
Block a user