Skip to content

Commit

Permalink
Improve documentation of chat-members based on suggestions
Browse files Browse the repository at this point in the history
  • Loading branch information
rayz1065 committed Jan 24, 2025
1 parent e4b74e1 commit 639036a
Showing 1 changed file with 41 additions and 22 deletions.
63 changes: 41 additions & 22 deletions site/docs/plugins/chat-members.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,59 +5,67 @@ 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

```ts [TypeScript]
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"],
});
```
Expand All @@ -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"],
});
```
Expand All @@ -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"],
});
```
Expand Down Expand Up @@ -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:
Expand All @@ -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 },
Expand All @@ -195,7 +214,7 @@ groups.on("chat_member", (ctx, next) => {

// update database data here

return next();
await next();
});

// specific handlers
Expand All @@ -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) => {
Expand Down Expand Up @@ -252,7 +271,7 @@ const bot = new Bot<MyContext>("");
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"],
});
```
Expand All @@ -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"],
});
```
Expand All @@ -294,7 +313,7 @@ const bot = new Bot<MyContext>("");
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"],
});
```
Expand Down

0 comments on commit 639036a

Please sign in to comment.