Moderating group chats¶
Group chats are an awesome way to communicate with your circle of friends, but you can also use them to discuss with other users in public groups. Unfortunately, there are people who just want to spam their own groups or post inappropriate content and, without some moderators always online, a public group will get messy sooner or later.
Telegram bots are able to moderate groups easily, so you can programmatically ban and unban users of the groups your bot is an administrator of.
New in version 0.3.
Allowing your bot to moderate groups¶
Bots can’t moderate groups by default, but they need to be authorized to do so. How to authorize them is specific to the client you use, but take the following advices:
- If you’re trying to add your bot as administrator to a group, you need to disable the “Everyone is an admin” setting of it, and then explicitly mark your bot as administrator.
- If you’re trying to add your bot as administrator to a supergroup, just add it to the administrators list.
Keep in mind your bot might lose its status of administrator during the conversion from a group to a supergroup, so if you converted a group check if your bot is still an administrator of it.
Banning nasty users¶
Nobody wants users joining a public groups just to spam their own group but, if there isn’t a moderator always online, a spammer can join in the middle of the night, and multiple users might see their message before a moderator gets online to ban him.
As an example, with the aid of ParsedText
you can detect
all the posted URLs, and ban all the user who sends a telegram.me
link,
with botogram.Chat.ban()
. Unfortunately bots can’t delete messages
yet, but they can mention all the administrators of the group, so they can
erase that message later:
@bot.process_message
def ban_telegram_links(chat, message):
# Don't do anything if there is no text message
if message.text is None:
return
# Check all the links in the message
for link in message.parsed_text.filter("link"):
# Match both HTTP and HTTPS links
if "://telegram.me" in link.url:
break
else:
return
# Ban the sender of the message
chat.ban(message.sender)
# Tell all the admins of the chat to delete the message
admins = " ".join("@"+a.username for a in chat.admins if a.username)
if admins:
message.reply("%s! Please delete this message!" % admins)
return
Unbanning users from supergroups¶
If an user is banned from a group chat, he can rejoin the group if he uses a join link or it’s added by another member. Instead, when an user is banned from a supergroup he’s put in a blacklist, and he needs to be explicitly removed from it if he want to join the supergroup again.
The following example is a working tempban code, which stores when the user was
banned in the shared memory, with a timer to unban the user later. The actual unban is executed via the
botogram.Chat.unban()
method:
import time
# This means `/tempban 1` bans the user for 60 seconds
BAN_DURATION_MULTIPLIER = 60
@bot.prepare_memory
def prepare_memory(shared):
shared["bans"] = {}
@bot.command("tempban")
def tempban_command(shared, chat, message, args):
"""Tempban an user from the group"""
# Handle some possible errors
if message.sender not in chat.admins:
message.reply("You're not an admin of this chat!")
return
if not message.reply_to_message:
message.reply("You must reply to a message the user sent!")
return
if message.reply_to_message.sender in chat.admins:
message.reply("You can't ban another admin!")
return
# Get the exact ban duration
try:
length = int(args[0])
except (IndexError, TypeError):
message.reply("You must provide the length of the ban!")
return
# Store the ban in the shared memory
with shared.lock("bans-change"):
bans = shared["bans"]
if chat.id not in bans:
bans[chat.id] = {}
# Calculate the expiry time and store it
expiry = time.time()+length*BAN_DURATION_MULTIPLIER
bans[chat.id][message.reply_to_message.sender.id] = expiry
shared["bans"] = bans
# Let's finally ban this guy!
chat.ban(message.reply_to_message.sender)
@bot.timer(BAN_DURATION_MULTIPLIER)
def unban_timer(bot, shared):
"""Unban the users"""
now = time.time()
# Everything is locked so no there are no races
with shared.lock("bans-change"):
global_bans = shared["bans"]
# Here .copy() is used because we're changing the dicts in-place
for chat_id, bans in global_bans.copy().items():
for user, expires in bans.copy().items():
# Unban the user if his ban expired
if expires <= now:
continue
bot.chat(chat_id).unban(user)
del global_bans[chat_id][user]
# Cleaning up is not such a bad thing...
if not global_bans[chat_id]:
del global_bans[chat_id]
shared["bans"] = global_bans