mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-09 20:44:32 +00:00
refactor: simplify telegram event authorization flow
This commit is contained in:
@@ -17,6 +17,7 @@ import { resolveChannelConfigWrites } from "../channels/plugins/config-writes.js
|
|||||||
import { loadConfig } from "../config/config.js";
|
import { loadConfig } from "../config/config.js";
|
||||||
import { writeConfigFile } from "../config/io.js";
|
import { writeConfigFile } from "../config/io.js";
|
||||||
import { loadSessionStore, resolveStorePath } from "../config/sessions.js";
|
import { loadSessionStore, resolveStorePath } from "../config/sessions.js";
|
||||||
|
import type { DmPolicy } from "../config/types.base.js";
|
||||||
import type { TelegramGroupConfig, TelegramTopicConfig } from "../config/types.js";
|
import type { TelegramGroupConfig, TelegramTopicConfig } from "../config/types.js";
|
||||||
import { danger, logVerbose, warn } from "../globals.js";
|
import { danger, logVerbose, warn } from "../globals.js";
|
||||||
import { enqueueSystemEvent } from "../infra/system-events.js";
|
import { enqueueSystemEvent } from "../infra/system-events.js";
|
||||||
@@ -507,54 +508,87 @@ export const registerTelegramHandlers = ({
|
|||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
|
|
||||||
const isTelegramEventSenderAuthorized = async (params: {
|
type TelegramGroupAllowContext = Awaited<ReturnType<typeof resolveTelegramGroupAllowFromContext>>;
|
||||||
|
type TelegramEventAuthorizationMode = "reaction" | "callback-scope" | "callback-allowlist";
|
||||||
|
type TelegramEventAuthorizationResult = { allowed: true } | { allowed: false; reason: string };
|
||||||
|
type TelegramEventAuthorizationContext = TelegramGroupAllowContext & { dmPolicy: DmPolicy };
|
||||||
|
|
||||||
|
const TELEGRAM_EVENT_AUTH_RULES: Record<
|
||||||
|
TelegramEventAuthorizationMode,
|
||||||
|
{
|
||||||
|
enforceDirectAuthorization: boolean;
|
||||||
|
enforceGroupAllowlistAuthorization: boolean;
|
||||||
|
deniedDmReason: string;
|
||||||
|
deniedGroupReason: string;
|
||||||
|
}
|
||||||
|
> = {
|
||||||
|
reaction: {
|
||||||
|
enforceDirectAuthorization: true,
|
||||||
|
enforceGroupAllowlistAuthorization: false,
|
||||||
|
deniedDmReason: "reaction unauthorized by dm policy/allowlist",
|
||||||
|
deniedGroupReason: "reaction unauthorized by group allowlist",
|
||||||
|
},
|
||||||
|
"callback-scope": {
|
||||||
|
enforceDirectAuthorization: false,
|
||||||
|
enforceGroupAllowlistAuthorization: false,
|
||||||
|
deniedDmReason: "callback unauthorized by inlineButtonsScope",
|
||||||
|
deniedGroupReason: "callback unauthorized by inlineButtonsScope",
|
||||||
|
},
|
||||||
|
"callback-allowlist": {
|
||||||
|
enforceDirectAuthorization: true,
|
||||||
|
enforceGroupAllowlistAuthorization: true,
|
||||||
|
deniedDmReason: "callback unauthorized by inlineButtonsScope allowlist",
|
||||||
|
deniedGroupReason: "callback unauthorized by inlineButtonsScope allowlist",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const resolveTelegramEventAuthorizationContext = async (params: {
|
||||||
chatId: number;
|
chatId: number;
|
||||||
chatTitle?: string;
|
|
||||||
isGroup: boolean;
|
|
||||||
isForum: boolean;
|
isForum: boolean;
|
||||||
messageThreadId?: number;
|
messageThreadId?: number;
|
||||||
senderId: string;
|
groupAllowContext?: TelegramGroupAllowContext;
|
||||||
senderUsername: string;
|
}): Promise<TelegramEventAuthorizationContext> => {
|
||||||
enforceDirectAuthorization: boolean;
|
|
||||||
enforceGroupAllowlistAuthorization: boolean;
|
|
||||||
deniedDmReason: string;
|
|
||||||
deniedGroupReason: string;
|
|
||||||
groupAllowContext?: Awaited<ReturnType<typeof resolveTelegramGroupAllowFromContext>>;
|
|
||||||
}) => {
|
|
||||||
const {
|
|
||||||
chatId,
|
|
||||||
chatTitle,
|
|
||||||
isGroup,
|
|
||||||
isForum,
|
|
||||||
messageThreadId,
|
|
||||||
senderId,
|
|
||||||
senderUsername,
|
|
||||||
enforceDirectAuthorization,
|
|
||||||
enforceGroupAllowlistAuthorization,
|
|
||||||
deniedDmReason,
|
|
||||||
deniedGroupReason,
|
|
||||||
groupAllowContext: preResolvedGroupAllowContext,
|
|
||||||
} = params;
|
|
||||||
const dmPolicy = telegramCfg.dmPolicy ?? "pairing";
|
const dmPolicy = telegramCfg.dmPolicy ?? "pairing";
|
||||||
const groupAllowContext =
|
const groupAllowContext =
|
||||||
preResolvedGroupAllowContext ??
|
params.groupAllowContext ??
|
||||||
(await resolveTelegramGroupAllowFromContext({
|
(await resolveTelegramGroupAllowFromContext({
|
||||||
chatId,
|
chatId: params.chatId,
|
||||||
accountId,
|
accountId,
|
||||||
dmPolicy,
|
dmPolicy,
|
||||||
isForum,
|
isForum: params.isForum,
|
||||||
messageThreadId,
|
messageThreadId: params.messageThreadId,
|
||||||
groupAllowFrom,
|
groupAllowFrom,
|
||||||
resolveTelegramGroupConfig,
|
resolveTelegramGroupConfig,
|
||||||
}));
|
}));
|
||||||
|
return { dmPolicy, ...groupAllowContext };
|
||||||
|
};
|
||||||
|
|
||||||
|
const authorizeTelegramEventSender = (params: {
|
||||||
|
chatId: number;
|
||||||
|
chatTitle?: string;
|
||||||
|
isGroup: boolean;
|
||||||
|
senderId: string;
|
||||||
|
senderUsername: string;
|
||||||
|
mode: TelegramEventAuthorizationMode;
|
||||||
|
context: TelegramEventAuthorizationContext;
|
||||||
|
}): TelegramEventAuthorizationResult => {
|
||||||
|
const { chatId, chatTitle, isGroup, senderId, senderUsername, mode, context } = params;
|
||||||
const {
|
const {
|
||||||
|
dmPolicy,
|
||||||
resolvedThreadId,
|
resolvedThreadId,
|
||||||
storeAllowFrom,
|
storeAllowFrom,
|
||||||
groupConfig,
|
groupConfig,
|
||||||
topicConfig,
|
topicConfig,
|
||||||
effectiveGroupAllow,
|
effectiveGroupAllow,
|
||||||
hasGroupAllowOverride,
|
hasGroupAllowOverride,
|
||||||
} = groupAllowContext;
|
} = context;
|
||||||
|
const authRules = TELEGRAM_EVENT_AUTH_RULES[mode];
|
||||||
|
const {
|
||||||
|
enforceDirectAuthorization,
|
||||||
|
enforceGroupAllowlistAuthorization,
|
||||||
|
deniedDmReason,
|
||||||
|
deniedGroupReason,
|
||||||
|
} = authRules;
|
||||||
if (
|
if (
|
||||||
shouldSkipGroupMessage({
|
shouldSkipGroupMessage({
|
||||||
isGroup,
|
isGroup,
|
||||||
@@ -569,7 +603,7 @@ export const registerTelegramHandlers = ({
|
|||||||
topicConfig,
|
topicConfig,
|
||||||
})
|
})
|
||||||
) {
|
) {
|
||||||
return false;
|
return { allowed: false, reason: "group-policy" };
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isGroup && enforceDirectAuthorization) {
|
if (!isGroup && enforceDirectAuthorization) {
|
||||||
@@ -577,7 +611,7 @@ export const registerTelegramHandlers = ({
|
|||||||
logVerbose(
|
logVerbose(
|
||||||
`Blocked telegram direct event from ${senderId || "unknown"} (${deniedDmReason})`,
|
`Blocked telegram direct event from ${senderId || "unknown"} (${deniedDmReason})`,
|
||||||
);
|
);
|
||||||
return false;
|
return { allowed: false, reason: "direct-disabled" };
|
||||||
}
|
}
|
||||||
if (dmPolicy !== "open") {
|
if (dmPolicy !== "open") {
|
||||||
const effectiveDmAllow = normalizeAllowFromWithStore({
|
const effectiveDmAllow = normalizeAllowFromWithStore({
|
||||||
@@ -587,17 +621,17 @@ export const registerTelegramHandlers = ({
|
|||||||
});
|
});
|
||||||
if (!isAllowlistAuthorized(effectiveDmAllow, senderId, senderUsername)) {
|
if (!isAllowlistAuthorized(effectiveDmAllow, senderId, senderUsername)) {
|
||||||
logVerbose(`Blocked telegram direct sender ${senderId || "unknown"} (${deniedDmReason})`);
|
logVerbose(`Blocked telegram direct sender ${senderId || "unknown"} (${deniedDmReason})`);
|
||||||
return false;
|
return { allowed: false, reason: "direct-unauthorized" };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (isGroup && enforceGroupAllowlistAuthorization) {
|
if (isGroup && enforceGroupAllowlistAuthorization) {
|
||||||
if (!isAllowlistAuthorized(effectiveGroupAllow, senderId, senderUsername)) {
|
if (!isAllowlistAuthorized(effectiveGroupAllow, senderId, senderUsername)) {
|
||||||
logVerbose(`Blocked telegram group sender ${senderId || "unknown"} (${deniedGroupReason})`);
|
logVerbose(`Blocked telegram group sender ${senderId || "unknown"} (${deniedGroupReason})`);
|
||||||
return false;
|
return { allowed: false, reason: "group-unauthorized" };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return { allowed: true };
|
||||||
};
|
};
|
||||||
|
|
||||||
// Handle emoji reactions to messages.
|
// Handle emoji reactions to messages.
|
||||||
@@ -630,19 +664,20 @@ export const registerTelegramHandlers = ({
|
|||||||
if (reactionMode === "own" && !wasSentByBot(chatId, messageId)) {
|
if (reactionMode === "own" && !wasSentByBot(chatId, messageId)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const senderAuthorized = await isTelegramEventSenderAuthorized({
|
const eventAuthContext = await resolveTelegramEventAuthorizationContext({
|
||||||
|
chatId,
|
||||||
|
isForum,
|
||||||
|
});
|
||||||
|
const senderAuthorization = authorizeTelegramEventSender({
|
||||||
chatId,
|
chatId,
|
||||||
chatTitle: reaction.chat.title,
|
chatTitle: reaction.chat.title,
|
||||||
isGroup,
|
isGroup,
|
||||||
isForum,
|
|
||||||
senderId,
|
senderId,
|
||||||
senderUsername,
|
senderUsername,
|
||||||
enforceDirectAuthorization: true,
|
mode: "reaction",
|
||||||
enforceGroupAllowlistAuthorization: false,
|
context: eventAuthContext,
|
||||||
deniedDmReason: "reaction unauthorized by dm policy/allowlist",
|
|
||||||
deniedGroupReason: "reaction unauthorized by group allowlist",
|
|
||||||
});
|
});
|
||||||
if (!senderAuthorized) {
|
if (!senderAuthorization.allowed) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -965,33 +1000,26 @@ export const registerTelegramHandlers = ({
|
|||||||
|
|
||||||
const messageThreadId = callbackMessage.message_thread_id;
|
const messageThreadId = callbackMessage.message_thread_id;
|
||||||
const isForum = callbackMessage.chat.is_forum === true;
|
const isForum = callbackMessage.chat.is_forum === true;
|
||||||
const groupAllowContext = await resolveTelegramGroupAllowFromContext({
|
const eventAuthContext = await resolveTelegramEventAuthorizationContext({
|
||||||
chatId,
|
chatId,
|
||||||
accountId,
|
|
||||||
dmPolicy: telegramCfg.dmPolicy ?? "pairing",
|
|
||||||
isForum,
|
isForum,
|
||||||
messageThreadId,
|
messageThreadId,
|
||||||
groupAllowFrom,
|
|
||||||
resolveTelegramGroupConfig,
|
|
||||||
});
|
});
|
||||||
const { resolvedThreadId, storeAllowFrom } = groupAllowContext;
|
const { resolvedThreadId, storeAllowFrom } = eventAuthContext;
|
||||||
const senderId = callback.from?.id ? String(callback.from.id) : "";
|
const senderId = callback.from?.id ? String(callback.from.id) : "";
|
||||||
const senderUsername = callback.from?.username ?? "";
|
const senderUsername = callback.from?.username ?? "";
|
||||||
const senderAuthorized = await isTelegramEventSenderAuthorized({
|
const authorizationMode: TelegramEventAuthorizationMode =
|
||||||
|
inlineButtonsScope === "allowlist" ? "callback-allowlist" : "callback-scope";
|
||||||
|
const senderAuthorization = authorizeTelegramEventSender({
|
||||||
chatId,
|
chatId,
|
||||||
chatTitle: callbackMessage.chat.title,
|
chatTitle: callbackMessage.chat.title,
|
||||||
isGroup,
|
isGroup,
|
||||||
isForum,
|
|
||||||
messageThreadId,
|
|
||||||
senderId,
|
senderId,
|
||||||
senderUsername,
|
senderUsername,
|
||||||
enforceDirectAuthorization: inlineButtonsScope === "allowlist",
|
mode: authorizationMode,
|
||||||
enforceGroupAllowlistAuthorization: inlineButtonsScope === "allowlist",
|
context: eventAuthContext,
|
||||||
deniedDmReason: "callback unauthorized by inlineButtonsScope allowlist",
|
|
||||||
deniedGroupReason: "callback unauthorized by inlineButtonsScope allowlist",
|
|
||||||
groupAllowContext,
|
|
||||||
});
|
});
|
||||||
if (!senderAuthorized) {
|
if (!senderAuthorization.allowed) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1230,25 +1258,20 @@ export const registerTelegramHandlers = ({
|
|||||||
if (shouldSkipUpdate(event.ctxForDedupe)) {
|
if (shouldSkipUpdate(event.ctxForDedupe)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const dmPolicy = telegramCfg.dmPolicy ?? "pairing";
|
const eventAuthContext = await resolveTelegramEventAuthorizationContext({
|
||||||
|
|
||||||
const groupAllowContext = await resolveTelegramGroupAllowFromContext({
|
|
||||||
chatId: event.chatId,
|
chatId: event.chatId,
|
||||||
accountId,
|
|
||||||
dmPolicy,
|
|
||||||
isForum: event.isForum,
|
isForum: event.isForum,
|
||||||
messageThreadId: event.messageThreadId,
|
messageThreadId: event.messageThreadId,
|
||||||
groupAllowFrom,
|
|
||||||
resolveTelegramGroupConfig,
|
|
||||||
});
|
});
|
||||||
const {
|
const {
|
||||||
|
dmPolicy,
|
||||||
resolvedThreadId,
|
resolvedThreadId,
|
||||||
storeAllowFrom,
|
storeAllowFrom,
|
||||||
groupConfig,
|
groupConfig,
|
||||||
topicConfig,
|
topicConfig,
|
||||||
effectiveGroupAllow,
|
effectiveGroupAllow,
|
||||||
hasGroupAllowOverride,
|
hasGroupAllowOverride,
|
||||||
} = groupAllowContext;
|
} = eventAuthContext;
|
||||||
const effectiveDmAllow = normalizeAllowFromWithStore({
|
const effectiveDmAllow = normalizeAllowFromWithStore({
|
||||||
allowFrom,
|
allowFrom,
|
||||||
storeAllowFrom,
|
storeAllowFrom,
|
||||||
|
|||||||
@@ -832,24 +832,12 @@ describe("createTelegramBot", () => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("blocks reaction when dmPolicy is disabled", async () => {
|
it.each([
|
||||||
onSpy.mockClear();
|
{
|
||||||
enqueueSystemEventSpy.mockClear();
|
name: "blocks reaction when dmPolicy is disabled",
|
||||||
|
updateId: 510,
|
||||||
loadConfig.mockReturnValue({
|
channelConfig: { dmPolicy: "disabled", reactionNotifications: "all" },
|
||||||
channels: {
|
reaction: {
|
||||||
telegram: { dmPolicy: "disabled", reactionNotifications: "all" },
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
createTelegramBot({ token: "tok" });
|
|
||||||
const handler = getOnHandler("message_reaction") as (
|
|
||||||
ctx: Record<string, unknown>,
|
|
||||||
) => Promise<void>;
|
|
||||||
|
|
||||||
await handler({
|
|
||||||
update: { update_id: 510 },
|
|
||||||
messageReaction: {
|
|
||||||
chat: { id: 1234, type: "private" },
|
chat: { id: 1234, type: "private" },
|
||||||
message_id: 42,
|
message_id: 42,
|
||||||
user: { id: 9, first_name: "Ada" },
|
user: { id: 9, first_name: "Ada" },
|
||||||
@@ -857,29 +845,17 @@ describe("createTelegramBot", () => {
|
|||||||
old_reaction: [],
|
old_reaction: [],
|
||||||
new_reaction: [{ type: "emoji", emoji: "👍" }],
|
new_reaction: [{ type: "emoji", emoji: "👍" }],
|
||||||
},
|
},
|
||||||
});
|
expectedEnqueueCalls: 0,
|
||||||
|
},
|
||||||
expect(enqueueSystemEventSpy).not.toHaveBeenCalled();
|
{
|
||||||
});
|
name: "blocks reaction in allowlist mode for unauthorized direct sender",
|
||||||
|
updateId: 511,
|
||||||
it("blocks reaction in allowlist mode for unauthorized direct sender", async () => {
|
channelConfig: {
|
||||||
onSpy.mockClear();
|
dmPolicy: "allowlist",
|
||||||
enqueueSystemEventSpy.mockClear();
|
allowFrom: ["12345"],
|
||||||
|
reactionNotifications: "all",
|
||||||
loadConfig.mockReturnValue({
|
|
||||||
channels: {
|
|
||||||
telegram: { dmPolicy: "allowlist", allowFrom: ["12345"], reactionNotifications: "all" },
|
|
||||||
},
|
},
|
||||||
});
|
reaction: {
|
||||||
|
|
||||||
createTelegramBot({ token: "tok" });
|
|
||||||
const handler = getOnHandler("message_reaction") as (
|
|
||||||
ctx: Record<string, unknown>,
|
|
||||||
) => Promise<void>;
|
|
||||||
|
|
||||||
await handler({
|
|
||||||
update: { update_id: 511 },
|
|
||||||
messageReaction: {
|
|
||||||
chat: { id: 1234, type: "private" },
|
chat: { id: 1234, type: "private" },
|
||||||
message_id: 42,
|
message_id: 42,
|
||||||
user: { id: 9, first_name: "Ada" },
|
user: { id: 9, first_name: "Ada" },
|
||||||
@@ -887,29 +863,13 @@ describe("createTelegramBot", () => {
|
|||||||
old_reaction: [],
|
old_reaction: [],
|
||||||
new_reaction: [{ type: "emoji", emoji: "👍" }],
|
new_reaction: [{ type: "emoji", emoji: "👍" }],
|
||||||
},
|
},
|
||||||
});
|
expectedEnqueueCalls: 0,
|
||||||
|
},
|
||||||
expect(enqueueSystemEventSpy).not.toHaveBeenCalled();
|
{
|
||||||
});
|
name: "allows reaction in allowlist mode for authorized direct sender",
|
||||||
|
updateId: 512,
|
||||||
it("allows reaction in allowlist mode for authorized direct sender", async () => {
|
channelConfig: { dmPolicy: "allowlist", allowFrom: ["9"], reactionNotifications: "all" },
|
||||||
onSpy.mockClear();
|
reaction: {
|
||||||
enqueueSystemEventSpy.mockClear();
|
|
||||||
|
|
||||||
loadConfig.mockReturnValue({
|
|
||||||
channels: {
|
|
||||||
telegram: { dmPolicy: "allowlist", allowFrom: ["9"], reactionNotifications: "all" },
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
createTelegramBot({ token: "tok" });
|
|
||||||
const handler = getOnHandler("message_reaction") as (
|
|
||||||
ctx: Record<string, unknown>,
|
|
||||||
) => Promise<void>;
|
|
||||||
|
|
||||||
await handler({
|
|
||||||
update: { update_id: 512 },
|
|
||||||
messageReaction: {
|
|
||||||
chat: { id: 1234, type: "private" },
|
chat: { id: 1234, type: "private" },
|
||||||
message_id: 42,
|
message_id: 42,
|
||||||
user: { id: 9, first_name: "Ada" },
|
user: { id: 9, first_name: "Ada" },
|
||||||
@@ -917,34 +877,18 @@ describe("createTelegramBot", () => {
|
|||||||
old_reaction: [],
|
old_reaction: [],
|
||||||
new_reaction: [{ type: "emoji", emoji: "👍" }],
|
new_reaction: [{ type: "emoji", emoji: "👍" }],
|
||||||
},
|
},
|
||||||
});
|
expectedEnqueueCalls: 1,
|
||||||
|
},
|
||||||
expect(enqueueSystemEventSpy).toHaveBeenCalledTimes(1);
|
{
|
||||||
});
|
name: "blocks reaction in group allowlist mode for unauthorized sender",
|
||||||
|
updateId: 513,
|
||||||
it("blocks reaction in group allowlist mode for unauthorized sender", async () => {
|
channelConfig: {
|
||||||
onSpy.mockClear();
|
dmPolicy: "open",
|
||||||
enqueueSystemEventSpy.mockClear();
|
groupPolicy: "allowlist",
|
||||||
|
groupAllowFrom: ["12345"],
|
||||||
loadConfig.mockReturnValue({
|
reactionNotifications: "all",
|
||||||
channels: {
|
|
||||||
telegram: {
|
|
||||||
dmPolicy: "open",
|
|
||||||
groupPolicy: "allowlist",
|
|
||||||
groupAllowFrom: ["12345"],
|
|
||||||
reactionNotifications: "all",
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
});
|
reaction: {
|
||||||
|
|
||||||
createTelegramBot({ token: "tok" });
|
|
||||||
const handler = getOnHandler("message_reaction") as (
|
|
||||||
ctx: Record<string, unknown>,
|
|
||||||
) => Promise<void>;
|
|
||||||
|
|
||||||
await handler({
|
|
||||||
update: { update_id: 513 },
|
|
||||||
messageReaction: {
|
|
||||||
chat: { id: 9999, type: "supergroup" },
|
chat: { id: 9999, type: "supergroup" },
|
||||||
message_id: 77,
|
message_id: 77,
|
||||||
user: { id: 9, first_name: "Ada" },
|
user: { id: 9, first_name: "Ada" },
|
||||||
@@ -952,9 +896,29 @@ describe("createTelegramBot", () => {
|
|||||||
old_reaction: [],
|
old_reaction: [],
|
||||||
new_reaction: [{ type: "emoji", emoji: "🔥" }],
|
new_reaction: [{ type: "emoji", emoji: "🔥" }],
|
||||||
},
|
},
|
||||||
|
expectedEnqueueCalls: 0,
|
||||||
|
},
|
||||||
|
])("$name", async ({ updateId, channelConfig, reaction, expectedEnqueueCalls }) => {
|
||||||
|
onSpy.mockClear();
|
||||||
|
enqueueSystemEventSpy.mockClear();
|
||||||
|
|
||||||
|
loadConfig.mockReturnValue({
|
||||||
|
channels: {
|
||||||
|
telegram: channelConfig,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(enqueueSystemEventSpy).not.toHaveBeenCalled();
|
createTelegramBot({ token: "tok" });
|
||||||
|
const handler = getOnHandler("message_reaction") as (
|
||||||
|
ctx: Record<string, unknown>,
|
||||||
|
) => Promise<void>;
|
||||||
|
|
||||||
|
await handler({
|
||||||
|
update: { update_id: updateId },
|
||||||
|
messageReaction: reaction,
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(enqueueSystemEventSpy).toHaveBeenCalledTimes(expectedEnqueueCalls);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("skips reaction when reactionNotifications is off", async () => {
|
it("skips reaction when reactionNotifications is off", async () => {
|
||||||
|
|||||||
Reference in New Issue
Block a user