mirror of
https://github.com/miloszowi/everyone-mention-telegram-bot.git
synced 2025-05-20 09:14:07 +00:00
commit
a6b441b197
@ -1,6 +1,14 @@
|
||||
# Change Log
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
## [0.3.0] - 12.11.2021
|
||||
### Added
|
||||
- Dynamic mentioning by `@` character
|
||||
### Changed
|
||||
- `start` text
|
||||
- Group name validation - those are forbidden now - `all`, `channel`, `chat`, `everyone`, `group`, `here`
|
||||
### Deleted
|
||||
- mentioning user that performed `/everyone` or dynamic mention in bot response
|
||||
## [0.2.0] - 26.10.2021
|
||||
### Added
|
||||
- Inline Mode for `join`, `leave` & `everyone`
|
||||
|
36
README.md
36
README.md
@ -5,6 +5,8 @@
|
||||
# Contents
|
||||
|
||||
* [Description](#description)
|
||||
* [Usage](#usage)
|
||||
* [Dynamic Mentioning](#dynamic-mentioning)
|
||||
* [Commands](#commands)
|
||||
* [`/join`](#join)
|
||||
* [`/leave`](#leave)
|
||||
@ -12,8 +14,7 @@
|
||||
* [`/groups`](#groups)
|
||||
* [`/start`](#start)
|
||||
* [Example command flow](#example-command-flow)
|
||||
* [Inline Mode](#inline-mode)
|
||||
* [Usage](#usage)
|
||||
* [Inline Mode Usage](#inline-mode-usage)
|
||||
* [Getting started.](#getting-started)
|
||||
* [Requirements](#requirements)
|
||||
* [Installation](#installation)
|
||||
@ -24,6 +25,32 @@ Everyone Mention Bot is simple, but useful telegram bot to gather group members
|
||||
|
||||
You can create groups per chat to mention every user that joined the group by calling one command instead of mentioning them one by one.
|
||||
|
||||
## Usage
|
||||
First, users need to join the group to let mentioning them, to do that, they simply need to join specific group.
|
||||
It can be done in 2 ways:
|
||||
- Command [`/join`](#join)
|
||||
- [Inline Mode](#inline-mode-usage)
|
||||
|
||||
Users that have joined the group can be mentioned in 3 ways:
|
||||
- [Dynaminc Mentioning](#dynamic-mentioning) by `@`, for example `@everyone`
|
||||
- Command [`/everyone`](#everyone)
|
||||
- [Inline Mode](#inline-mode-usage)
|
||||
|
||||
To leave the group use one of the two ways:
|
||||
- Command [`/leave`](#leave)
|
||||
- [Inline Mode](#inline-mode-usage)
|
||||
|
||||
To display available groups:
|
||||
- Command [`/groups`](#groups)
|
||||
|
||||
## Dynamic mentioning
|
||||
You can use `@` character (as you would mention a user) to mention specific group.
|
||||
|
||||
All the below will mention users from `default` group.
|
||||
|
||||
`@all`, `@channel`, `@chat`, `@everyone`, `@group`, `@here`.
|
||||
|
||||
If you did create a group named `gaming`, you can simply use `@gaming` in your text to mention them all.
|
||||
## Commands
|
||||
*Important*: `{group-name}` is not required, if not given, it will be set to `default`.
|
||||
### `/join`
|
||||
@ -85,10 +112,7 @@ Start & Help message
|
||||
### Example command flow
|
||||

|
||||
|
||||
## Inline Mode
|
||||
Using Inline Mode is recommended because policy of bots with privacy mode enabled (https://core.telegram.org/bots/faq#what-messages-will-my-bot-get) says that command trigger is sent (without mentioning the bot) only to the last mentioned bot. So if you do have multiple bots in current chat, I might not receive your command!
|
||||
|
||||
### Usage
|
||||
### Inline Mode Usage
|
||||
To use inline mode, type `@everyone_mention_bot` in telegram message input or click on the `Inline Mode` button from `/start` command.
|
||||
|
||||

|
||||
|
@ -1,5 +1,5 @@
|
||||
__all__ = [
|
||||
'abstractHandler', 'everyoneHandler', 'groupsHandler',
|
||||
'inlineQueryHandler', 'joinHandler', 'leaveHandler',
|
||||
'startHandler'
|
||||
'startHandler', 'dynamicMentionHandler'
|
||||
]
|
||||
|
@ -9,6 +9,7 @@ from bot.message.replier import Replier
|
||||
from exception.actionNotAllowedException import ActionNotAllowedException
|
||||
from exception.invalidActionException import InvalidActionException
|
||||
from exception.invalidArgumentException import InvalidArgumentException
|
||||
from exception.notFoundException import NotFoundException
|
||||
from logger import Logger
|
||||
|
||||
|
||||
@ -30,6 +31,8 @@ class AbstractHandler:
|
||||
Logger.action(self.inbound, self.action)
|
||||
except (InvalidActionException, InvalidArgumentException, ActionNotAllowedException) as e:
|
||||
Replier.markdown(update, str(e))
|
||||
except NotFoundException:
|
||||
pass # probably just mentioning user
|
||||
except Exception as e:
|
||||
Logger.exception(e)
|
||||
|
||||
|
28
src/bot/handler/dynamicMentionHandler.py
Normal file
28
src/bot/handler/dynamicMentionHandler.py
Normal file
@ -0,0 +1,28 @@
|
||||
import re
|
||||
|
||||
from telegram.ext import Filters, MessageHandler
|
||||
from telegram.ext.callbackcontext import CallbackContext
|
||||
from telegram.update import Update
|
||||
|
||||
from bot.handler.abstractHandler import AbstractHandler
|
||||
from bot.message.replier import Replier
|
||||
from repository.chatRepository import ChatRepository
|
||||
from utils.messageBuilder import MessageBuilder
|
||||
|
||||
|
||||
class DynamicMentionHandler(AbstractHandler):
|
||||
bot_handler: MessageHandler
|
||||
chat_repository: ChatRepository
|
||||
action: str = 'dynamic-mention'
|
||||
|
||||
def __init__(self) -> None:
|
||||
self.bot_handler = MessageHandler(
|
||||
Filters.regex(re.compile(r'@[^ ]')),
|
||||
self.wrap
|
||||
)
|
||||
self.chat_repository = ChatRepository()
|
||||
|
||||
def handle(self, update: Update, context: CallbackContext) -> None:
|
||||
users = self.chat_repository.get_users_for_group(self.inbound)
|
||||
|
||||
Replier.markdown(update, MessageBuilder.mention_message(users))
|
@ -8,24 +8,21 @@ from config.contents import mention_failed
|
||||
from exception.invalidActionException import InvalidActionException
|
||||
from exception.notFoundException import NotFoundException
|
||||
from repository.chatRepository import ChatRepository
|
||||
from repository.userRepository import UserRepository
|
||||
from utils.messageBuilder import MessageBuilder
|
||||
|
||||
|
||||
class EveryoneHandler(AbstractHandler):
|
||||
bot_handler: CommandHandler
|
||||
chat_repository: ChatRepository
|
||||
user_repository: UserRepository
|
||||
action: str = 'everyone'
|
||||
|
||||
def __init__(self) -> None:
|
||||
self.bot_handler = CommandHandler(self.action, self.wrap)
|
||||
self.chat_repository = ChatRepository()
|
||||
self.user_repository = UserRepository()
|
||||
|
||||
def handle(self, update: Update, context: CallbackContext) -> None:
|
||||
try:
|
||||
users = self.chat_repository.get_users_for_group(self.inbound.chat_id, self.inbound.group_name)
|
||||
users = self.chat_repository.get_users_for_group(self.inbound)
|
||||
|
||||
Replier.markdown(update, MessageBuilder.mention_message(users))
|
||||
except NotFoundException as e:
|
||||
|
@ -3,9 +3,11 @@ from __future__ import annotations
|
||||
from dataclasses import dataclass
|
||||
|
||||
import names
|
||||
import re
|
||||
from telegram.ext.callbackcontext import CallbackContext
|
||||
from telegram.update import Update
|
||||
|
||||
from exception.invalidActionException import InvalidActionException
|
||||
from validator.accessValidator import AccessValidator
|
||||
from validator.groupNameValidator import GroupNameValidator
|
||||
|
||||
@ -24,14 +26,25 @@ class InboundMessage:
|
||||
user_id = str(update.effective_user.id)
|
||||
AccessValidator.validate(user_id)
|
||||
|
||||
message_content = update.edited_message.text if update.edited_message else update.message.text
|
||||
message_content = message_content.replace("\n", " ")
|
||||
chat_id = str(update.effective_chat.id)
|
||||
group_name = InboundMessage.default_group
|
||||
|
||||
# done upon resolving a command action
|
||||
if context.args and context.args[0] and group_specific:
|
||||
group_name = str(context.args[0]).lower()
|
||||
|
||||
GroupNameValidator.validate(group_name)
|
||||
|
||||
# done upon resolving a message handler action
|
||||
if '@' in message_content:
|
||||
searched_message_part = [part for part in message_content.split(' ') if '@' in part][0]
|
||||
group_name = re.sub(r'\W+', '', searched_message_part).lower()
|
||||
|
||||
if group_name in GroupNameValidator.FORBIDDEN_GROUP_NAMES:
|
||||
group_name = InboundMessage.default_group
|
||||
|
||||
username = update.effective_user.username or update.effective_user.first_name
|
||||
|
||||
if not username:
|
||||
|
@ -10,13 +10,16 @@ no_groups = 'There are no groups for this chat'
|
||||
start_text = """
|
||||
Hello!
|
||||
@everyone_mention_bot here.
|
||||
|
||||
<b>Description</b>:
|
||||
I <b>do not</b> have access to your messages!
|
||||
I am here to help you with multiple user mentions.
|
||||
|
||||
<b>Usage</b>:
|
||||
Users that joined the group by <code>/join</code> command, can be mentioned after calling <code>/everyone</code> command.
|
||||
Users that joined the group by <code>/join</code> command,
|
||||
can be mentioned after typing one of those in your message:
|
||||
<code>@all</code>, <code>@channel</code>, <code>@chat</code>, <code>@everyone</code>, <code>@group</code> or <code>@here</code>.
|
||||
|
||||
If you did create a group named <code>gaming</code>, simply use <code>@gaming</code> to call users from that group.
|
||||
|
||||
You can also use <code>/everyone</code> command.
|
||||
|
||||
<b>Commands</b>:
|
||||
<pre>/join {group-name}</pre>
|
||||
@ -36,6 +39,4 @@ Show start & help text
|
||||
|
||||
<b>Please note</b>
|
||||
<code>{group-name}</code> is not required, <code>default</code> if not given.
|
||||
|
||||
If your chat does have multiple bots <b>I might not receive your command</b> according to <a href="https://core.telegram.org/bots/faq#what-messages-will-my-bot-get">policy of bots with privacy mode enabled</a> - use <code>Inline Mode</code> to avoid this.
|
||||
"""
|
||||
|
@ -39,12 +39,17 @@ class ChatRepository(AbstractRepository):
|
||||
|
||||
return Chat.from_mongo_document(chat)
|
||||
|
||||
def get_users_for_group(self, chat_id: str, group: str) -> Iterable[User]:
|
||||
chat = self.get(chat_id)
|
||||
if not chat.groups.get(group):
|
||||
def get_users_for_group(self, inbound: InboundMessage) -> Iterable[User]:
|
||||
chat = self.get(inbound.chat_id)
|
||||
if not chat.groups.get(inbound.group_name):
|
||||
raise NotFoundException
|
||||
|
||||
return [self.user_repository.get(user_id) for user_id in chat.groups.get(group)]
|
||||
users = [self.user_repository.get(user_id) for user_id in chat.groups.get(inbound.group_name) if user_id != inbound.user_id]
|
||||
|
||||
if not users:
|
||||
raise NotFoundException
|
||||
|
||||
return users
|
||||
|
||||
def save(self, chat: Chat) -> None:
|
||||
self.database_client.save(
|
||||
|
@ -5,6 +5,7 @@ from exception.invalidArgumentException import InvalidArgumentException
|
||||
|
||||
class GroupNameValidator:
|
||||
MAX_GROUP_NAME_LENGTH: int = 40
|
||||
FORBIDDEN_GROUP_NAMES = ['all', 'channel', 'chat', 'everyone', 'group', 'here']
|
||||
|
||||
@staticmethod
|
||||
def validate(group: str) -> None:
|
||||
@ -15,3 +16,6 @@ class GroupNameValidator:
|
||||
|
||||
if len(group) > GroupNameValidator.MAX_GROUP_NAME_LENGTH:
|
||||
raise InvalidArgumentException(re.escape(f'Group name length can not be greater than {GroupNameValidator.MAX_GROUP_NAME_LENGTH}.'))
|
||||
|
||||
if group in GroupNameValidator.FORBIDDEN_GROUP_NAMES:
|
||||
raise InvalidArgumentException(re.escape(f'This group name is forbidden, please try with other name.'))
|
||||
|
Loading…
x
Reference in New Issue
Block a user