diff --git a/site/docs/plugins/chat-members.md b/site/docs/plugins/chat-members.md index 7755b817e..9c8fc148e 100644 --- a/site/docs/plugins/chat-members.md +++ b/site/docs/plugins/chat-members.md @@ -5,26 +5,29 @@ next: false # Chat Members Plugin (`chat-members`) +Telegram doesn't offer a method in the Bot API to retrieve the members of a chat, you have to keep track of them yourself. This plugin makes it easy to work with `ChatMember` objects, by offering a convenient way to listen for changes in the form of custom filters, and by storing and updating the objects. ## Introduction -Working with `ChatMember` objects from the Telegram Bot API can sometimes be cumbersome, there are several different statuses that are often interchangeable in most applications, as well as a restricted status that can represent both members of the group and restricted users that are not in the group. +Working with `ChatMember` objects from the Telegram Bot API can sometimes be cumbersome. +There are several different statuses that are often interchangeable in most applications. +In addition, the restricted status is ambiguous because it can represent both members of the group and restricted users that are not in the group. -This plugin aims to simplify dealing with chat members, by offering fully typed filters for chat member updates. +This plugin simplifies dealing with chat members by offering fully typed filters for chat member updates. ## Usage -### Chat member filters +### Chat Member Filters -You can listen for two kinds of updates regarding chat members using a Telegram bot: `chat_member` and `my_chat_member`, -both of them specify the old and new status of the user. +You can listen for two kinds of updates regarding chat members using a Telegram bot: `chat_member` and `my_chat_member`. +Both of them specify the old and new status of the user. - `my_chat_member` updates are received by your bot by default and they inform you about the status of the bot being updated in any chat, as well as users blocking the bot; -- `chat_member` updates are only received if you specifically include them in the list of allowed updates, they notify about any status changes for users in chats **where your bot is admin**. +- `chat_member` updates are only received if you explicitly include them in the list of allowed updates, they notify about any status changes for users in chats **where your bot is admin**. Instead of manually filtering the old and new status, chat member filters do this automatically for you, allowing you to react to every type of transition you're interested in. -Within the handler, types of `old_chat_member` and `new_chat_member` are updated accordingly. +Within the handler, the types of `old_chat_member` and `new_chat_member` are narrowed down accordingly. ::: code-group @@ -32,32 +35,37 @@ Within the handler, types of `old_chat_member` and `new_chat_member` are updated import { API_CONSTANTS, Bot } from "grammy"; import { chatMemberFilter, myChatMemberFilter } from "@grammyjs/chat-members"; -const bot = new Bot(process.env.BOT_TOKEN!); +const bot = new Bot(""); const groups = bot.chatType(["group", "supergroup"]); +// Listen for updates where the bot is added to a group as a regular user. groups.filter(myChatMemberFilter("out", "regular"), async (ctx) => { await ctx.reply("Hello, thank you for adding me to the group!"); }); +// Listen for updates where the bot is added to a group as an admin. groups.filter(myChatMemberFilter("out", "admin"), async (ctx) => { await ctx.reply("Hello, thank you for adding me to the group as admin!"); }); +// Listen for updates where the bot is promoted to admin. groups.filter(myChatMemberFilter("regular", "admin"), async (ctx) => { await ctx.reply("I was promoted to admin!"); }); +// Listen for updates where the bot is demoted to a regular user. groups.filter(myChatMemberFilter("admin", "regular"), async (ctx) => { await ctx.reply("I am no longer admin"); }); +// Listen for updates where a user joins a group where your bot is admin. groups.filter(chatMemberFilter("out", "in"), async (ctx) => { const user = ctx.chatMember.new_chat_member.user; await ctx.reply(`Welcome ${user.first_name} to the group!`); }); bot.start({ - // Make sure to specify the desired update types + // Make sure to specify the desired update types. allowed_updates: [...API_CONSTANTS.DEFAULT_UPDATE_TYPES, "chat_member"], }); ``` @@ -66,32 +74,37 @@ bot.start({ import { API_CONSTANTS, Bot } from "grammy"; import { chatMemberFilter, myChatMemberFilter } from "@grammyjs/chat-members"; -const bot = new Bot(process.env.BOT_TOKEN); +const bot = new Bot(""); const groups = bot.chatType(["group", "supergroup"]); +// Listen for updates where the bot is added to a group as a regular user. groups.filter(myChatMemberFilter("out", "regular"), async (ctx) => { await ctx.reply("Hello, thank you for adding me to the group!"); }); +// Listen for updates where the bot is added to a group as an admin. groups.filter(myChatMemberFilter("out", "admin"), async (ctx) => { await ctx.reply("Hello, thank you for adding me to the group as admin!"); }); +// Listen for updates where the bot is promoted to admin. groups.filter(myChatMemberFilter("regular", "admin"), async (ctx) => { await ctx.reply("I was promoted to admin!"); }); +// Listen for updates where the bot is demoted to a regular user. groups.filter(myChatMemberFilter("admin", "regular"), async (ctx) => { await ctx.reply("I am no longer admin"); }); +// Listen for updates where a user joins a group where your bot is admin. groups.filter(chatMemberFilter("out", "in"), async (ctx) => { const user = ctx.chatMember.new_chat_member.user; await ctx.reply(`Welcome ${user.first_name} to the group!`); }); bot.start({ - // Make sure to specify the desired update types + // Make sure to specify the desired update types. allowed_updates: [...API_CONSTANTS.DEFAULT_UPDATE_TYPES, "chat_member"], }); ``` @@ -103,32 +116,37 @@ import { myChatMemberFilter, } from "https://deno.land/x/grammy_chat_members/mod.ts"; -const bot = new Bot(Deno.env.get("BOT_TOKEN")!); +const bot = new Bot(""); const groups = bot.chatType(["group", "supergroup"]); +// Listen for updates where the bot is added to a group as a regular user. groups.filter(myChatMemberFilter("out", "regular"), async (ctx) => { await ctx.reply("Hello, thank you for adding me to the group!"); }); +// Listen for updates where the bot is added to a group as an admin. groups.filter(myChatMemberFilter("out", "admin"), async (ctx) => { await ctx.reply("Hello, thank you for adding me to the group as admin!"); }); +// Listen for updates where the bot is promoted to admin. groups.filter(myChatMemberFilter("regular", "admin"), async (ctx) => { await ctx.reply("I was promoted to admin!"); }); +// Listen for updates where the bot is demoted to a regular user. groups.filter(myChatMemberFilter("admin", "regular"), async (ctx) => { await ctx.reply("I am no longer admin"); }); +// Listen for updates where a user joins a group where your bot is admin. groups.filter(chatMemberFilter("out", "in"), async (ctx) => { const user = ctx.chatMember.new_chat_member.user; await ctx.reply(`Welcome ${user.first_name} to the group!`); }); bot.start({ - // Make sure to specify the desired update types + // Make sure to specify the desired update types. allowed_updates: [...API_CONSTANTS.DEFAULT_UPDATE_TYPES, "chat_member"], }); ``` @@ -162,7 +180,7 @@ groups.filter( ); ``` -#### Example usage +#### Example Usage The best way to use the filters is to pick a set of relevant statuses, for example 'out', 'regular' and 'admin', then make a table of the transitions between them: @@ -175,12 +193,13 @@ make a table of the transitions between them: Assign a listener to all the transitions that are relevant to your use-case. -Combine these filters with `bot.chatType` to only listen for transitions for a specific type of chat. Add a middleware to listen to all updates as a way to perform common operations (like updating your database) before handing off control to a specific handler. +Combine these filters with `bot.chatType` to only listen for transitions for a specific type of chat. +Add a middleware to listen to all updates as a way to perform common operations (like updating your database) before handing off control to a specific handler. ```typescript const groups = bot.chatType(["group", "supergroup"]); -groups.on("chat_member", (ctx, next) => { +groups.on("chat_member", async (ctx, next) => { // ran on all updates of type chat_member const { old_chat_member: { status: oldStatus }, @@ -195,7 +214,7 @@ groups.on("chat_member", (ctx, next) => { // update database data here - return next(); + await next(); }); // specific handlers @@ -206,10 +225,10 @@ groups.filter(chatMemberFilter("out", "in"), async (ctx, next) => { }); ``` -### Status checking utility +### Status Checking Utility The `chatMemberIs` utility function can be useful whenever you want to use filtering logic within a handler. -It takes as input any of the regular and custom statuses (or an array of them) and updates the type of the passed variable. +It takes as input any of the regular and custom statuses (or an array of them), and updates the type of the passed variable. ```ts bot.callbackQuery("foo", async (ctx) => { @@ -252,7 +271,7 @@ const bot = new Bot(""); bot.use(chatMembers(adapter)); bot.start({ - // Make sure to specify the desired update types + // Make sure to specify the desired update types. allowed_updates: ["chat_member", "message"], }); ``` @@ -268,7 +287,7 @@ const bot = new Bot(""); bot.use(chatMembers(adapter)); bot.start({ - // Make sure to specify the desired update types + // Make sure to specify the desired update types. allowed_updates: ["chat_member", "message"], }); ``` @@ -294,7 +313,7 @@ const bot = new Bot(""); bot.use(chatMembers(adapter)); bot.start({ - // Make sure to specify the desired update types + // Make sure to specify the desired update types. allowed_updates: ["chat_member", "message"], }); ```