From b73d057cb97664fb9884424334e988e97a9207f7 Mon Sep 17 00:00:00 2001 From: Harshil <37377066+harshil21@users.noreply.github.com> Date: Sun, 14 Nov 2021 05:06:35 +0530 Subject: [PATCH 01/16] add type hints. See #2778 --- Extensions-–-Your-first-Bot.md | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/Extensions-–-Your-first-Bot.md b/Extensions-–-Your-first-Bot.md index 2b33850..031424e 100644 --- a/Extensions-–-Your-first-Bot.md +++ b/Extensions-–-Your-first-Bot.md @@ -44,10 +44,13 @@ logging.basicConfig(format='%(asctime)s - %(name)s - %(levelname)s - %(message)s Now, you can define a function that should process a specific type of update: ```python -def start(update, context): +from telegram import Update +from telegram.ext import CallbackContext + +def start(update: Update, context: CallbackContext): context.bot.send_message(chat_id=update.effective_chat.id, text="I'm a bot, please talk to me!") ``` -**Related docs:** [`send_message`](https://core.telegram.org/bots/api#sendmessage), [`telegram.ext.CallbackContext` (the type of the context argument)](https://python-telegram-bot.readthedocs.io/en/latest/telegram.ext.callbackcontext.html) +**Related docs:** [`send_message`](https://core.telegram.org/bots/api#sendmessage), [`telegram.ext.CallbackContext` (the type of the context argument)](https://python-telegram-bot.readthedocs.io/en/latest/telegram.ext.callbackcontext.html), [`telegram.Update` (the type of update argument)](https://python-telegram-bot.readthedocs.io/en/latest/telegram.update.html) The goal is to have this function called every time the Bot receives a Telegram message that contains the `/start` command. To accomplish that, you can use a `CommandHandler` (one of the provided `Handler` subclasses) and register it in the dispatcher: @@ -70,10 +73,11 @@ Give it a try! Start a chat with your bot and issue the `/start` command - if al But our Bot can now only answer to the `/start` command. Let's add another handler that listens for regular messages. Use the `MessageHandler`, another `Handler` subclass, to echo all text messages: ```python -def echo(update, context): +from telegram.ext import MessageHandler, Filters + +def echo(update: Update, context: CallbackContext): context.bot.send_message(chat_id=update.effective_chat.id, text=update.message.text) -from telegram.ext import MessageHandler, Filters echo_handler = MessageHandler(Filters.text & (~Filters.command), echo) dispatcher.add_handler(echo_handler) ``` @@ -88,7 +92,7 @@ From now on, your bot should echo all non-command messages it receives. Let's add some actual functionality to your bot. We want to implement a `/caps` command that will take some text as an argument and reply to it in CAPS. To make things easy, you can receive the arguments (as a `list`, split on spaces) that were passed to a command in the callback function: ```python -def caps(update, context): +def caps(update: Update, context: CallbackContext): text_caps = ' '.join(context.args).upper() context.bot.send_message(chat_id=update.effective_chat.id, text=text_caps) @@ -104,11 +108,11 @@ As your bot is obviously a very loud one, let's continue with this theme for inl ```python from telegram import InlineQueryResultArticle, InputTextMessageContent -def inline_caps(update, context): +def inline_caps(update: Update, context: CallbackContext): query = update.inline_query.query if not query: return - results = list() + results = [] results.append( InlineQueryResultArticle( id=query.upper(), @@ -129,7 +133,7 @@ Not bad! Your Bot can now yell on command (ha!) and via inline mode. Some confused users might try to send commands to the bot that it doesn't understand, so you can use a `MessageHandler` with a `command` filter to reply to all commands that were not recognized by the previous handlers. ```python -def unknown(update, context): +def unknown(update: Update, context: CallbackContext): context.bot.send_message(chat_id=update.effective_chat.id, text="Sorry, I didn't understand that command.") unknown_handler = MessageHandler(Filters.command, unknown) From 089e7ffb58ce5665e3431dd4ef84545719243b0d Mon Sep 17 00:00:00 2001 From: Gareth Dwyer Date: Mon, 15 Nov 2021 10:27:24 +0100 Subject: [PATCH 02/16] Add code capsules --- Where-to-host-Telegram-Bots.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Where-to-host-Telegram-Bots.md b/Where-to-host-Telegram-Bots.md index fed6b12..a724d4b 100644 --- a/Where-to-host-Telegram-Bots.md +++ b/Where-to-host-Telegram-Bots.md @@ -14,6 +14,8 @@ Look at [[Hosting your bot|Hosting-your-bot]] if you've decided to get a server. * **[Heroku getting started with Python](https://devcenter.heroku.com/articles/getting-started-with-python#introduction)** * **[[Webhooks on Heroku|Webhooks#heroku]]** * **[Skeleton repository](https://github.com/Bibo-Joshi/ptb-heroku-skeleton)** +* [Code Capsules](https://codecapsules.io) + * **[Host a Telegram Bot on Code Capsules](https://codecapsules.io/docs/tutorials/create-and-host-telegram-bot/)** * [OpenShift](https://www.openshift.com/) * **[How to run a Bot on Openshift v2](https://github.com/lufte/python-telegram-bot-openshift)** * **[How to run a Bot on Openshift v3](https://github.com/Gotham13121997/python-telegram-bot-openshift3)** From cad9694682931f9957703740f7ded6fbd4da595d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=80=81=E6=88=BF=E4=B8=9C?= Date: Sat, 27 Nov 2021 09:20:19 -0500 Subject: [PATCH 03/16] Updated Home (markdown) From 8301da0e2688504bd629c845343a1e184691b6e7 Mon Sep 17 00:00:00 2001 From: Kishore <93278161+jk6521@users.noreply.github.com> Date: Tue, 30 Nov 2021 19:19:43 +0530 Subject: [PATCH 04/16] fix typo and grmmar. --- Home.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Home.md b/Home.md index cabedbb..310ac1f 100644 --- a/Home.md +++ b/Home.md @@ -9,7 +9,7 @@ If you stumble upon a part of the wiki that is unclear or missing important poin ## Structure of this Wiki -In the sidebar to the right you find all important pages of this wiki. They are roughly organized by the following logic: +In the sidebar to the right, you can find all important pages of this wiki. They are roughly organized by the following logic: ### Must read @@ -34,7 +34,7 @@ Articles about advanced networking questions. ### Other resources -More interesting & helpful stuff that didn't fint in any of the above sections. +More interesting & helpful stuff that can't be found in any of the above sections. ### Transition Guides From 0033e7fc78937076d226d61f51ed2128d378e1ed Mon Sep 17 00:00:00 2001 From: Sergey Smirnov Date: Tue, 14 Dec 2021 12:48:44 +0600 Subject: [PATCH 05/16] Added related project --- Related-Projects.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Related-Projects.md b/Related-Projects.md index c10fdf0..819f0f5 100644 --- a/Related-Projects.md +++ b/Related-Projects.md @@ -19,4 +19,6 @@ Please try to keep this page up-to-date. | [telegram.bot](https://github.com/ebeneditos/telegram.bot) | Develop a Telegram Bot with R | >=6.0.0 | Stable | | [flexget](https://github.com/Flexget/Flexget)| Use telegram as a notifier | 3.4 | Stable | [ptb-django-cookiecutter](https://github.com/lugodev/ptb-django-cookiecutter)| A simple cookiecutter to create Python Telegram bots, wrapped with Django. | 0.1.0 | Beta | +| [ptb-menu-pagination](https://github.com/SergSm/ptb-menu-pagination| +Makes a google style pagination line for a list of items. | 0.2.2 | Alpha | [Video Tutorial](https://youtu.be/fQo_327-AZA) | How to create a simple Telegram bot using PTB and then hosting it on Heroku|13.7|-| \ No newline at end of file From 9266445440e37ac73dd444a481f3dac98fe82418 Mon Sep 17 00:00:00 2001 From: Bibo-Joshi <22366557+Bibo-Joshi@users.noreply.github.com> Date: Tue, 14 Dec 2021 07:49:53 +0100 Subject: [PATCH 06/16] Updated Related Projects (markdown) --- Related-Projects.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Related-Projects.md b/Related-Projects.md index 819f0f5..6e74e72 100644 --- a/Related-Projects.md +++ b/Related-Projects.md @@ -19,6 +19,5 @@ Please try to keep this page up-to-date. | [telegram.bot](https://github.com/ebeneditos/telegram.bot) | Develop a Telegram Bot with R | >=6.0.0 | Stable | | [flexget](https://github.com/Flexget/Flexget)| Use telegram as a notifier | 3.4 | Stable | [ptb-django-cookiecutter](https://github.com/lugodev/ptb-django-cookiecutter)| A simple cookiecutter to create Python Telegram bots, wrapped with Django. | 0.1.0 | Beta | -| [ptb-menu-pagination](https://github.com/SergSm/ptb-menu-pagination| -Makes a google style pagination line for a list of items. | 0.2.2 | Alpha | +| [ptb-menu-pagination](https://github.com/SergSm/ptb-menu-pagination) | Makes a google style pagination line for a list of items. | 0.2.2 | Alpha | [Video Tutorial](https://youtu.be/fQo_327-AZA) | How to create a simple Telegram bot using PTB and then hosting it on Heroku|13.7|-| \ No newline at end of file From 44002d9ad85d3622472a553678ab44d7190eba12 Mon Sep 17 00:00:00 2001 From: Sergey Smirnov Date: Tue, 14 Dec 2021 12:54:07 +0600 Subject: [PATCH 07/16] Updated Related Projects (markdown) --- Related-Projects.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Related-Projects.md b/Related-Projects.md index 6e74e72..1f2109a 100644 --- a/Related-Projects.md +++ b/Related-Projects.md @@ -19,5 +19,5 @@ Please try to keep this page up-to-date. | [telegram.bot](https://github.com/ebeneditos/telegram.bot) | Develop a Telegram Bot with R | >=6.0.0 | Stable | | [flexget](https://github.com/Flexget/Flexget)| Use telegram as a notifier | 3.4 | Stable | [ptb-django-cookiecutter](https://github.com/lugodev/ptb-django-cookiecutter)| A simple cookiecutter to create Python Telegram bots, wrapped with Django. | 0.1.0 | Beta | -| [ptb-menu-pagination](https://github.com/SergSm/ptb-menu-pagination) | Makes a google style pagination line for a list of items. | 0.2.2 | Alpha | +| [ptb-menu-pagination](https://github.com/SergSm/ptb-menu-pagination) | Makes a google style pagination line for a list of items. | >=13.8.1 | Alpha | [Video Tutorial](https://youtu.be/fQo_327-AZA) | How to create a simple Telegram bot using PTB and then hosting it on Heroku|13.7|-| \ No newline at end of file From d7d4383a6e58b2426d6fb92583056e26159d0ecb Mon Sep 17 00:00:00 2001 From: TheyCallMeCheng <80591403+TheyCallMeCheng@users.noreply.github.com> Date: Tue, 14 Dec 2021 12:00:43 +0100 Subject: [PATCH 08/16] im sorry im just upset that this guide is confusing and not helpful at all --- Extensions-–-Your-first-Bot.md | 1 + 1 file changed, 1 insertion(+) diff --git a/Extensions-–-Your-first-Bot.md b/Extensions-–-Your-first-Bot.md index 031424e..37f9ae2 100644 --- a/Extensions-–-Your-first-Bot.md +++ b/Extensions-–-Your-first-Bot.md @@ -1,4 +1,5 @@ ## Introduction +## this guide is terribad The `telegram.ext` submodule is built on top of the pure API implementation. It provides an easy-to-use interface and takes some work off the programmer, so you [don't have to repeat yourself](https://en.wikipedia.org/wiki/Don%27t_repeat_yourself). It consists of several classes, but the two most important ones are [`telegram.ext.Updater`](https://python-telegram-bot.readthedocs.io/en/latest/telegram.ext.updater.html#telegram.ext.Updater) and [`telegram.ext.Dispatcher`](https://python-telegram-bot.readthedocs.io/en/latest/telegram.ext.dispatcher.html#telegram.ext.Dispatcher). From 622161bed800280c504518d8aef21da0272f57da Mon Sep 17 00:00:00 2001 From: TheyCallMeCheng <80591403+TheyCallMeCheng@users.noreply.github.com> Date: Tue, 14 Dec 2021 12:01:19 +0100 Subject: [PATCH 09/16] a --- Extensions-–-Your-first-Bot.md | 1 - 1 file changed, 1 deletion(-) diff --git a/Extensions-–-Your-first-Bot.md b/Extensions-–-Your-first-Bot.md index 37f9ae2..031424e 100644 --- a/Extensions-–-Your-first-Bot.md +++ b/Extensions-–-Your-first-Bot.md @@ -1,5 +1,4 @@ ## Introduction -## this guide is terribad The `telegram.ext` submodule is built on top of the pure API implementation. It provides an easy-to-use interface and takes some work off the programmer, so you [don't have to repeat yourself](https://en.wikipedia.org/wiki/Don%27t_repeat_yourself). It consists of several classes, but the two most important ones are [`telegram.ext.Updater`](https://python-telegram-bot.readthedocs.io/en/latest/telegram.ext.updater.html#telegram.ext.Updater) and [`telegram.ext.Dispatcher`](https://python-telegram-bot.readthedocs.io/en/latest/telegram.ext.dispatcher.html#telegram.ext.Dispatcher). From 164bebf2d72e253bb9a8cf41011a8b974de61d58 Mon Sep 17 00:00:00 2001 From: Harshil <37377066+harshil21@users.noreply.github.com> Date: Tue, 14 Dec 2021 17:13:18 +0530 Subject: [PATCH 10/16] update the way to exclude forwarded channel messages --- Code-snippets.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Code-snippets.md b/Code-snippets.md index ade2ae2..c8cdd33 100644 --- a/Code-snippets.md +++ b/Code-snippets.md @@ -517,9 +517,9 @@ dispatcher.add_handler(add_group_handle) --- #### Exclude forwarded channel posts in discussion groups from MessageHandlers -If you're using `MessageHandlers` and do not want them to respond to the channel posts automatically forwarded to the discussion group linked to your channel, you can use this filter in your `MessageHandler`: +If you're using `MessageHandlers` and do not want them to respond to the channel posts automatically forwarded to the discussion group linked to your channel, you can use this filter in your `MessageHandler` (requires PTB v13.9+): ```python -~ Filters.sender_chat.channel +~ Filters.is_automatic_forward ``` --- From 122fb78198f76816fbfb9d17b8b1c6b9f996c527 Mon Sep 17 00:00:00 2001 From: Harshil <37377066+harshil21@users.noreply.github.com> Date: Thu, 23 Dec 2021 16:18:15 +0530 Subject: [PATCH 11/16] update new members message to include chatmemberbot.py --- Code-snippets.md | 1 + 1 file changed, 1 insertion(+) diff --git a/Code-snippets.md b/Code-snippets.md index c8cdd33..3d7c5e8 100644 --- a/Code-snippets.md +++ b/Code-snippets.md @@ -514,6 +514,7 @@ def add_group(update: Update, context: CallbackContext): add_group_handle = MessageHandler(Filters.status_update.new_chat_members, add_group) dispatcher.add_handler(add_group_handle) ``` +Note that service messages about non-bot users joining the chat are removed from large groups. You can get the new members message by following the [chatmemberbot.py example](https://github.com/python-telegram-bot/python-telegram-bot/tree/master/examples#chatmemberbotpy). --- #### Exclude forwarded channel posts in discussion groups from MessageHandlers From a184a6c7a1d6f28525d1a4a52e343f7e5ef7f5ce Mon Sep 17 00:00:00 2001 From: Poolitzer Date: Wed, 29 Dec 2021 13:11:55 +0100 Subject: [PATCH 12/16] new FAQ style site --- Frequently-requested-design-patterns.md | 175 ++++++++++++++++++++++++ 1 file changed, 175 insertions(+) create mode 100644 Frequently-requested-design-patterns.md diff --git a/Frequently-requested-design-patterns.md b/Frequently-requested-design-patterns.md new file mode 100644 index 0000000..dc601d4 --- /dev/null +++ b/Frequently-requested-design-patterns.md @@ -0,0 +1,175 @@ +This page is a collection of sorts, dedicated to showcase design patterns we get asked about often in our support group. + +- [Requirements](#requirements) +- [How to handle updates in several handlers](#how-to-handle-updates-in-several-handlers) + - [Type Handler and Low Group](#type-handler-and-low-group) + - [Boilerplate Code](#boilerplate-code) + - [But I do not want a handler to stop other handlers](#but-i-do-not-want-a-handler-to-stop-other-handlers) + - [How do I limit who can use my bot?](#how-do-i-limit-who-can-use-my-bot-) + - [How do control flooding of my bot?](#how-do-control-flooding-of-my-bot-) + - [How do I do process a update in several handlers?](#how-do-i-process-an-update-in-several-handlers-) + - [Conclusion](#conclusion) +- [How do I enforce users joining a specific channel before using my bot?](#how-do-i-enforce-users-joining-a-specific-channel-before-using-my-bot) +- [How do I send a message to all users of the bot?](#how-do-i-send-a-message-to-all-users-of-the-bot) + +## Requirements + +Knowing how to make bots with PTB is enough. That means you should be familiar with Python and with PTB. +If you haven't worked on anything with PTB, then please check [Introduction to the API](https://github.com/python-telegram-bot/python-telegram-bot/wiki/Introduction-to-the-API). + +## How to handle updates in several handlers + +At some point developing ones bots, most of us face the following question + +> How do I handle an update _before_ other handlers? + + + +The following sections will give you an idea how to tackle this problem, based on frequent scenarios where this problem arises. + +### Type Handler and Groups + +PTB comes with a powerful handler known as [TypeHandler](https://python-telegram-bot.readthedocs.io/en/stable/telegram.ext.typehandler.html). +You can understand it as a generic handler. You can use it to handle any class put through the Updater. +For example, Type Handlers are used in bots to handle "updates" from Github or other external services. + +To add any handler, we use [Dispatcher.add_handler](https://python-telegram-bot.readthedocs.io/en/stable/telegram.ext.dispatcher.html#telegram.ext.Dispatcher.add_handler). Apart from the handler itself, it takes an optional argument called `group`. We can understand groups as numbers which indicate the priority of handlers. A lower group means a higher priority. An update can be processed by (at most) one handler in each group. + +Stopping handlers in higher groups from processing an update is achieved using [DispatcherHandlerStop](https://python-telegram-bot.readthedocs.io/en/stable/telegram.ext.dispatcherhandlerstop.html#telegram.ext.DispatcherHandlerStop). When raising this exception, the Dispatcher is asked to stop sending the updates to handlers in higher groups. Depending on your use case, you may not need to raise it. But it is useful if you want to enable flood handling or limit who can use the bot. + +That's it. With these three knowledge nuggets, we can solve the question given in the introduction. + +### Boilerplate Code + +Before working on the problems, we will provide you with a template of code that you can use. All you need to do to follow this guide is change the internals of your `callback` and `group` as required by the problem you face. + +```python +from telegram import Update +from telegram.ext import CallbackContext, DispatcherHandlerStop, TypeHandler, Updater + + +def callback(update: Update, context: CallbackContext): + """Handle the update""" + do_something_with_this_update(update, context) + raise DispatcherHandlerStop # Only if you DON'T want other handlers to handle this update + + +updater = Updater(TOKEN) +dispatcher = updater.dispatcher +handler = TypeHandler(Update, callback) # Making a handler for the type Update +dispatcher.add_handler(handler, -1) # Default is 0, so we are giving it a number below 0 +# Add other handlers and start your bot. +``` + +The code above should be self-explanatory, provided you read the previous section along with the respective documentation. We made a handler for `telegram.Update` and added it to a lower group. + +#### But I do not want a handler to stop other handlers + +In case you don't want to stop other handlers from processing the update, then you should modify your `callback` to not raise the exception. +This is a generic use case often used for analytics purpose. For example, if you need to add every user who uses your bot to a database, you can use this method. Simply put, this sort of approach is used to keep track of every update. + +```python +def callback(update: Update, context: CallbackContext): + add_message_to_my_analytics(update.effective_message) + add_user_to_my_database(update.effective_user) +``` + +Note the difference in this example compared to the previous ones. Here we don't raise `DispatcherHandlerStop`. This type of handlers is known as _shallow handler_ or _silent handler_. These type of handlers handle the update and also allow it to be handled by other common handlers like `CommandHandler` or `MessageHandler`. In other words, they don't block the other handlers. + +Now let us solve the specific use cases. All you need to do is modify your `callback` as required. 😉 + +### How do I limit who can use my bot? + +To restrict your bot to a set of users or if you don't want it to be available for a specific group of people, you can use a `callback` similar to the following. Remember, the process is same if you want to enable/disable the bot for groups or channels. + +```python +SPECIAL_USERS = [127376448, 172380183, 1827979793] # Allows users + +def callback(update: Update, context: CallbackContext): + if update.effective_user.user_id in SPECIAL_USERS: + pass + else: + update.effective_message.reply_text("Hey! You are not allowed to use me!") + raise DispatcherHandlerStop +``` + +Here, it should be noted that this approach blocks your bot entirely for a set of users. If all you need is to block a specific functionality, like a special command or privilege, then it will be wise to use [Filters.chat](https://python-telegram-bot.readthedocs.io/en/stable/telegram.ext.filters.html#telegram.ext.filters.Filters.chat), [Filters.user](https://python-telegram-bot.readthedocs.io/en/stable/telegram.ext.filters.html#telegram.ext.filters.Filters.user). +Don't forget that you can also use [decorators](https://github.com/python-telegram-bot/python-telegram-bot/wiki/Code-snippets#restrict-access-to-a-handler-decorator) or a simple `if-else` check. +If you want a more streamlined style of managing permissions (like superuser, admin, users) then [ptbcontrib/roles](https://github.com/python-telegram-bot/ptbcontrib/tree/main/ptbcontrib/roles) is worth checking out. + +### How do rate limit users of my bot? + +The exact definition of _rate limit_ depends on your point of view. You typically should keep record of previous usage of the user and warn them when they cross a limit. Here, for demonstration, we use a method that restricts the usage of the bot for 5 minutes. + +```python +from time import time + +MAX_USAGE = 5 + + +def callback(update: Update, context: CallbackContext): + count = context.user_data.get("usageCount", 0) + restrict_since = context.user_data.get("restrictSince", 0) + + if restrict_since: + if (time() - restrict_since) >= 60 * 5: # 5 minutes + del context.user_data["restrictSince"] + del context.user_data["usageCount"] + update.effective_message.reply_text("I have unrestricted you. Please behave well.") + else: + update.effective_message.reply_text("Back off! Wait for your restriction to expire...") + raise DispatcherHandlerStop + else: + if count == MAX_USAGE: + context.user_data["restrictSince"] = time() + update.effective_message.reply_text("Stop flooding! Don't bother me for 5 minutes...") + raise DispatcherHandlerStop + else: + context.user_data["usageCount"] = count + 1 +``` + +The approach we used is dead lazy. We keep a count of updates from the user and when it reaches maximum limit, we note the time. We proceed to stop handling the updates of that user for 5 minutes. Your effective flood limit strategy and punishment may vary. But the logic remains same. + +### Conclusion + +We have seen how `TypeHandler` can be used to give a fluent experience without messing up our code-base. Now you would be able to solve complex use cases from the given examples. But please note that `TypeHandler` **is not** the only option. +If you feel like this approach is too much of trouble, you can use Python's inbuilt [decorators](https://github.com/python-telegram-bot/python-telegram-bot/wiki/Code-snippets#restrict-access-to-a-handler-decorator). + +## How do I enforce users joining a specific channel before using my bot? + +After sending an (invite) link to the channel to the user, you can use [`Bot.get_chat_member`](https://python-telegram-bot.readthedocs.io/en/stable/telegram.bot.html#telegram.Bot.get_chat_member) to check if the user is an that channel. +Note that: + +- the bot needs to be admin in that channel +- the user must have started the bot for this approach to work. If you try to run `get_chat_member` for a user that has not started the bot, the bot can not find the user in a chat, even if it is a member of it. + +Otherwise depending on whether the user in the channel, has joined and left again, has been banned, ... (there are multiple situations possible), the method may + +- raise an exception and in this case the error message will probably be helpful +- return a [`ChatMember`](https://python-telegram-bot.readthedocs.io/en/stable/telegram.chatmember.html#telegram.ChatMember) instance. In that case make sure to check the [`ChatMember.status`](https://python-telegram-bot.readthedocs.io/en/stable/telegram.chatmember.html#telegram.ChatMember.status) attribute + +Since API 5.1 (PTB v13.4+) you can alternatively use the [`ChatMember`](https://python-telegram-bot.readthedocs.io/en/stable/telegram.chatmemberupdated.html) updates to keep track of users in channels. See [`chatmemberbot.py`](https://github.com/python-telegram-bot/python-telegram-bot/tree/master/examples#chatmemberbotpy) for an example. + +If the user has not yet joined the channel, you can ignore incoming updates from that user or reply to them with a corresponding warning. A convenient way to do that is by using [TypeHandler](https://python-telegram-bot.readthedocs.io/en/stable/telegram.ext.typehandler.html). Read this [section](#how-do-i-limit-who-can-use-my-bot-) to learn how to do it. + +## How do I send a message to all users of the bot? + +Let's first point out an easy alternative solution: Instead of sending the messages directly through your bot, you can instead set up a channel to publish the announcements. You can link your users to the channel in a welcome message. + +If that doesn't work for you, here we go: + +To send a message to all users, you of course need the IDs of all the users. You'll have to keep track of those yourself. The most reliable way for that are the [`my_chat_member`](https://python-telegram-bot.readthedocs.io/en/stable/telegram.chatmemberupdated.html) updates. See [`chatmemberbot.py`](https://github.com/python-telegram-bot/python-telegram-bot/tree/master/examples#chatmemberbotpy) for an example on how to use them. + +If you didn't keep track of your users from the beginning, you may have a chance to get the IDs anyway, if you're using persistence. Please have a look at [this issue](https://github.com/python-telegram-bot/python-telegram-bot/issues/1836) in that case. + +Even if you have all the IDs, you can't know if a user has blocked your bot in the meantime. Therefore, you should make sure to wrap your send request in a `try-except` clause checking for [`telegram.error.Unauthorized`](https://python-telegram-bot.readthedocs.io/en/stable/telegram.error.html#telegram.error.Unauthorized) errors. + +Finally, note that Telegram imposes some limits that restrict you to send ~30 Messages per second. If you have a huge user base and try to notify them all at once, you will get flooding errors. To prevent that, try spreading the messages over a long time range. A simple way to achieve that is to leverage the [`JobQueue`](Extensions-–-JobQueue). From 53cc994a7565db14798c11db344041b0ed67218b Mon Sep 17 00:00:00 2001 From: Poolitzer Date: Wed, 29 Dec 2021 13:13:23 +0100 Subject: [PATCH 13/16] adding the frequent design patterns --- _Sidebar.md | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/_Sidebar.md b/_Sidebar.md index cc3fdb9..1ee022a 100644 --- a/_Sidebar.md +++ b/_Sidebar.md @@ -17,12 +17,13 @@ 9. [[Avoiding flood limits|Avoiding-flood-limits]] ## Code Resources -1. [[Code snippets|Code-snippets]] -2. [[Performance Optimizations|Performance-Optimizations]] -3. [[Webhooks|Webhooks]] -4. [[Telegram Passport|Telegram-Passport]] -5. [[Bots built with PTB|Bots-built-with-PTB]] -6. [[Automated Bot Tests|Writing-Tests]] +1. [[Frequently requested design patterns|Frequently-requested-design-patterns]] +2. [[Code snippets|Code-snippets]] +3. [[Performance Optimizations|Performance-Optimizations]] +4. [[Webhooks|Webhooks]] +5. [[Telegram Passport|Telegram-Passport]] +6. [[Bots built with PTB|Bots-built-with-PTB]] +7. [[Automated Bot Tests|Writing-Tests]] ## Examples explained 1. [[InlineKeyboard Example|InlineKeyboard-Example]] From ff69ff44aaee433ec3172bb2dce0045750e7a6c3 Mon Sep 17 00:00:00 2001 From: Poolitzer Date: Wed, 29 Dec 2021 13:21:49 +0100 Subject: [PATCH 14/16] fixing toc --- Frequently-requested-design-patterns.md | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/Frequently-requested-design-patterns.md b/Frequently-requested-design-patterns.md index dc601d4..bf73557 100644 --- a/Frequently-requested-design-patterns.md +++ b/Frequently-requested-design-patterns.md @@ -2,12 +2,11 @@ This page is a collection of sorts, dedicated to showcase design patterns we get - [Requirements](#requirements) - [How to handle updates in several handlers](#how-to-handle-updates-in-several-handlers) - - [Type Handler and Low Group](#type-handler-and-low-group) + - [Type Handler and Groups](#type-handler-and-groups) - [Boilerplate Code](#boilerplate-code) - [But I do not want a handler to stop other handlers](#but-i-do-not-want-a-handler-to-stop-other-handlers) - - [How do I limit who can use my bot?](#how-do-i-limit-who-can-use-my-bot-) - - [How do control flooding of my bot?](#how-do-control-flooding-of-my-bot-) - - [How do I do process a update in several handlers?](#how-do-i-process-an-update-in-several-handlers-) + - [How do I limit who can use my bot?](#how-do-i-limit-who-can-use-my-bot) + - [How do I rate limit users of my bot?](#how-do-i-rate-limit-users-of-my-bot) - [Conclusion](#conclusion) - [How do I enforce users joining a specific channel before using my bot?](#how-do-i-enforce-users-joining-a-specific-channel-before-using-my-bot) - [How do I send a message to all users of the bot?](#how-do-i-send-a-message-to-all-users-of-the-bot) @@ -105,7 +104,7 @@ Here, it should be noted that this approach blocks your bot entirely for a set o Don't forget that you can also use [decorators](https://github.com/python-telegram-bot/python-telegram-bot/wiki/Code-snippets#restrict-access-to-a-handler-decorator) or a simple `if-else` check. If you want a more streamlined style of managing permissions (like superuser, admin, users) then [ptbcontrib/roles](https://github.com/python-telegram-bot/ptbcontrib/tree/main/ptbcontrib/roles) is worth checking out. -### How do rate limit users of my bot? +### How do I rate limit users of my bot? The exact definition of _rate limit_ depends on your point of view. You typically should keep record of previous usage of the user and warn them when they cross a limit. Here, for demonstration, we use a method that restricts the usage of the bot for 5 minutes. From 6954ac38640eddab266696bc1714bbeb219003fa Mon Sep 17 00:00:00 2001 From: Bibo-Joshi <22366557+Bibo-Joshi@users.noreply.github.com> Date: Wed, 29 Dec 2021 21:06:55 +0100 Subject: [PATCH 15/16] Updated Frequently Asked Questions (markdown) --- Frequently-Asked-Questions.md | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/Frequently-Asked-Questions.md b/Frequently-Asked-Questions.md index 6eea357..26286fd 100644 --- a/Frequently-Asked-Questions.md +++ b/Frequently-Asked-Questions.md @@ -17,7 +17,6 @@ - [Can I check, if a `ConversationHandler` is currently active for a user?](#can-i-check-if-a-conversationhandler-is-currently-active-for-a-user) - [How can I list all messages of a particular chat or search through them based on a search query?](#how-can-i-list-all-messages-of-a-particular-chat-or-search-through-them-based-on-a-search-query) - [How can I disable logging for the `APScheduler` module?](#how-can-i-disable-logging-for-the-apscheduler-module) -- [How do I enforce users joining a specific channel before using my bot?](#how-do-i-enforce-users-joining-a-specific-channel-before-using-my-bot) - [Why am I getting an error `The following arguments have not been supplied`?](#why-am-i-getting-an-error-the-following-arguments-have-not-been-supplied) - [How can I check the version of PTB I am using?](#how-can-i-check-the-version-of-ptb-i-am-using) - [Is there a limit on the number of buttons in an inline keyboard?](#is-there-a-limit-on-the-number-of-buttons-in-an-inline-keyboard) @@ -156,21 +155,6 @@ aps_logger = logging.getLogger('apscheduler') aps_logger.setLevel(logging.WARNING) ``` -### How do I enforce users joining a specific channel before using my bot? - -After sending an (invite) link to the channel to the user, you can use [`Bot.get_chat_member`](https://python-telegram-bot.readthedocs.io/en/stable/telegram.bot.html#telegram.Bot.get_chat_member) to check if the user is an that channel. -Note that: -* the bot needs to be admin in that channel -* the user must have started the bot for this approach to work. If you try to run `get_chat_member` for a user that has not started the bot, the bot can not find the user in a chat, even if it is a member of it. - -Otherwise depending on whether the user in the channel, has joined and left again, has been banned, ... (there are multiple situations possible), the method may -* raise an exception and in this case the error message will probably be helpful -* return a `ChatMember` instance. In that case make sure to check the [`ChatMember.status`](https://python-telegram-bot.readthedocs.io/en/stable/telegram.chatmember.html#telegram.ChatMember.status) attribute - -Since API 5.1 (PTB v13.4+) you can alternatively use the `ChatMember` updates to keep track of users in channels. See [`chatmemberbot.py`](https://github.com/python-telegram-bot/python-telegram-bot/tree/master/examples#chatmemberbotpy) for an example. - -If the user has not yet joined the channel, you can ignore incoming updates from that user or reply to them with a corresponding warning. A convenient way to do that is to add at [`TypeHandler(telegram.Update, callback)`](https://python-telegram-bot.readthedocs.io/en/stable/telegram.ext.typehandler.html) to a low group and have the `callback` raise [`DispatcherHandlerStop`](https://python-telegram-bot.readthedocs.io/en/stable/telegram.ext.dispatcherhandlerstop.html) if the user did not join yet. See the docs of [`Dispatcher.add_handler`](https://python-telegram-bot.readthedocs.io/en/stable/telegram.ext.dispatcherhandlerstop.html) for more info on handler groups and `DispatcherHandlerStop`. - ### Why am I getting an error `The following arguments have not been supplied`? The `callback` method you pass to `JobQueue.run_*` takes exactly *one* argument, which is of type `CallbackContext`. This is, because jobs are triggered by a schedule and not by an update from Telegram. If you want to access data in the callback that changes at runtime (e.g. because you schedule jobs on demand), you can either access `context.bot_data` or pass the data to `run_*` as `run_*(…, context=additional_data)`. It can then be accessed within the `callback` as `context.job.context`. Note that `context.{user, chat}_data` will be `None`, as those can only be present, when the `context` object is related to an update, which is not the case for jobs. From 575efc112953cb70a1b35131519b7ebbab355ee7 Mon Sep 17 00:00:00 2001 From: Bibo-Joshi <22366557+Bibo-Joshi@users.noreply.github.com> Date: Wed, 29 Dec 2021 21:07:48 +0100 Subject: [PATCH 16/16] Updated Frequently Asked Questions (markdown) --- Frequently-Asked-Questions.md | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/Frequently-Asked-Questions.md b/Frequently-Asked-Questions.md index 26286fd..a86ca7e 100644 --- a/Frequently-Asked-Questions.md +++ b/Frequently-Asked-Questions.md @@ -21,7 +21,6 @@ - [How can I check the version of PTB I am using?](#how-can-i-check-the-version-of-ptb-i-am-using) - [Is there a limit on the number of buttons in an inline keyboard?](#is-there-a-limit-on-the-number-of-buttons-in-an-inline-keyboard) - [How do I access info about the message my bot sent?](#how-do-I-access-info-about-the-message-my-bot-sent) -- [How do I send a message to all users of the bot?](#how-do-i-send-a-message-to-all-users-of-the-bot) ### What messages can my Bot see? @@ -181,17 +180,3 @@ message_id = message.message_id ``` Please check the docs for details about the return value of each bot method. - -### How do I send a message to all users of the bot? - -Let's first point out an easy alternative solution: Instead of sending the messages directly through your bot, you can instead set up a channel to publish the announcements. You can link your users to the channel in a welcome message. - -If that doesn't work for you, here we go: - -To send a message to all users, you of course need the IDs of all the users. You'll have to keep track of those yourself. The most reliable way for that are the `my_chat_member` updates. See [`chatmemberbot.py`](https://github.com/python-telegram-bot/python-telegram-bot/tree/master/examples#chatmemberbotpy) for an example on how to use them. - -If you didn't keep track of your users from the beginning, you may have a chance to get the IDs anyway, if you're using persistence. Please have a look at [this issue](https://github.com/python-telegram-bot/python-telegram-bot/issues/1836) in that case. - -Even if you have all the IDs, you can't know if a user has blocked your bot in the meantime. Therefore, you should make sure to wrap your send request in a `try-except` clause checking for `telegram.error.Unauthorized` errors. - -Finally, note that Telegram imposes some limits that restrict you to send ~30 Messages per second. If you have a huge user base and try to notify them all at once, you will get flooding errors. To prevent that, try spreading the messages over a long time range. A simple way to achieve that is to leverage the [[`JobQueue`|Extensions-–-JobQueue]].