mirror of
https://github.com/miloszowi/everyone-mention-telegram-bot.git
synced 2025-10-10 17:16:03 +00:00
0.1.0 Version : changed in to join and out to leave, folder structure and naming changes
This commit is contained in:
@@ -5,9 +5,9 @@ from telegram.ext.dispatcher import Dispatcher
|
||||
|
||||
from logger import Logger
|
||||
from config.credentials import BOT_TOKEN, PORT, WEBHOOK_URL
|
||||
from handler import (groupsHandler, inHandler, mentionHandler, outHandler,
|
||||
from bot.handler import (groupsHandler, joinHandler, mentionHandler, leaveHandler,
|
||||
silentMentionHandler, startHandler)
|
||||
from handler.abstractHandler import AbstractHandler
|
||||
from bot.handler.abstractHandler import AbstractHandler
|
||||
|
||||
|
||||
class App:
|
||||
|
@@ -1,11 +1,11 @@
|
||||
from abc import abstractmethod
|
||||
|
||||
from bot.message.messageData import MessageData
|
||||
from logger import Logger
|
||||
from telegram.ext.callbackcontext import CallbackContext
|
||||
from telegram.ext.handler import Handler
|
||||
from telegram.update import Update
|
||||
|
||||
from handler.vo.updateData import UpdateData
|
||||
from telegram.utils.helpers import mention_markdown
|
||||
|
||||
|
||||
class AbstractHandler:
|
||||
@@ -16,10 +16,13 @@ class AbstractHandler:
|
||||
def handle(self, update: Update, context: CallbackContext) -> None: raise Exception('handle method is not implemented')
|
||||
|
||||
@abstractmethod
|
||||
def log_action(self, update_data: UpdateData) -> None: raise Exception('log_action method is not implemented')
|
||||
def log_action(self, message_data: MessageData) -> None: raise Exception('log_action method is not implemented')
|
||||
|
||||
def get_update_data(self, update: Update, context: CallbackContext) -> UpdateData:
|
||||
return UpdateData.create_from_arguments(update, context)
|
||||
def interpolate_reply(self, reply: str, message_data: MessageData):
|
||||
return reply.format(
|
||||
mention_markdown(message_data.user_id, message_data.username),
|
||||
message_data.group_name
|
||||
)
|
||||
|
||||
def reply_markdown(self, update: Update, message: str) -> None:
|
||||
try:
|
@@ -1,17 +1,16 @@
|
||||
from typing import Iterable
|
||||
|
||||
import prettytable as pt
|
||||
from bot.handler.abstractHandler import AbstractHandler
|
||||
from bot.message.messageData import MessageData
|
||||
from config.contents import no_groups
|
||||
from entity.group import Group
|
||||
from handler.vo.updateData import UpdateData
|
||||
from logger import Logger
|
||||
from repository.groupRepository import GroupRepository
|
||||
from telegram.ext.callbackcontext import CallbackContext
|
||||
from telegram.ext.commandhandler import CommandHandler
|
||||
from telegram.update import Update
|
||||
|
||||
from handler.abstractHandler import AbstractHandler
|
||||
|
||||
|
||||
class GroupsHandler(AbstractHandler):
|
||||
bot_handler: CommandHandler
|
||||
@@ -22,21 +21,21 @@ class GroupsHandler(AbstractHandler):
|
||||
self.group_repository = GroupRepository()
|
||||
|
||||
def handle(self, update: Update, context: CallbackContext) -> None:
|
||||
update_data = UpdateData.create_from_arguments(update, context, False)
|
||||
message_data = MessageData.create_from_arguments(update, context, False)
|
||||
|
||||
groups = self.group_repository.get_by_chat_id(update_data.chat_id)
|
||||
groups = self.group_repository.get_by_chat_id(message_data.chat_id)
|
||||
|
||||
if groups:
|
||||
self.reply_html(update, self.build_groups_message(groups))
|
||||
return self.log_action(update_data)
|
||||
return self.log_action(message_data)
|
||||
|
||||
self.reply_markdown(update, no_groups)
|
||||
|
||||
def get_bot_handler(self) -> CommandHandler:
|
||||
return self.bot_handler
|
||||
|
||||
def log_action(self, update_data: UpdateData) -> None:
|
||||
Logger.info(f'User {update_data.username} called /groups for {update_data.chat_id}')
|
||||
def log_action(self, message_data: MessageData) -> None:
|
||||
Logger.info(f'User {message_data.username} called /groups for {message_data.chat_id}')
|
||||
|
||||
def build_groups_message(self, groups: Iterable[Group]) -> str:
|
||||
resultTable = pt.PrettyTable(['Name', 'Members'])
|
46
src/bot/handler/joinHandler.py
Executable file
46
src/bot/handler/joinHandler.py
Executable file
@@ -0,0 +1,46 @@
|
||||
from telegram.utils.helpers import mention_markdown
|
||||
from bot.handler.abstractHandler import AbstractHandler
|
||||
from bot.message.messageData import MessageData
|
||||
from config.contents import joined, not_joined
|
||||
from exception.invalidArgumentException import InvalidArgumentException
|
||||
from exception.notFoundException import NotFoundException
|
||||
from logger import Logger
|
||||
from repository.userRepository import UserRepository
|
||||
from telegram.ext.callbackcontext import CallbackContext
|
||||
from telegram.ext.commandhandler import CommandHandler
|
||||
from telegram.update import Update
|
||||
|
||||
|
||||
class JoinHandler(AbstractHandler):
|
||||
bot_handler: CommandHandler
|
||||
user_repository: UserRepository
|
||||
|
||||
def __init__(self) -> None:
|
||||
self.bot_handler = CommandHandler('join', self.handle)
|
||||
self.user_repository = UserRepository()
|
||||
|
||||
def handle(self, update: Update, context: CallbackContext) -> None:
|
||||
try:
|
||||
message_data = MessageData.create_from_arguments(update, context)
|
||||
except InvalidArgumentException as e:
|
||||
return self.reply_markdown(update, str(e))
|
||||
|
||||
try:
|
||||
user = self.user_repository.get_by_id(message_data.user_id)
|
||||
|
||||
if user.is_in_chat(message_data.chat_id):
|
||||
return self.reply_markdown(update, self.interpolate_reply(not_joined, message_data))
|
||||
|
||||
user.add_to_chat(message_data.chat_id)
|
||||
self.user_repository.save(user)
|
||||
except NotFoundException:
|
||||
self.user_repository.save_by_message_data(message_data)
|
||||
|
||||
self.reply_markdown(update, self.interpolate_reply(joined, message_data))
|
||||
self.log_action(message_data)
|
||||
|
||||
def get_bot_handler(self) -> CommandHandler:
|
||||
return self.bot_handler
|
||||
|
||||
def log_action(self, message_data: MessageData) -> None:
|
||||
Logger.info(f'User {message_data.username} joined {message_data.chat_id}')
|
@@ -1,46 +1,45 @@
|
||||
from config.contents import opted_off, opted_off_failed
|
||||
from bot.handler.abstractHandler import AbstractHandler
|
||||
from bot.message.messageData import MessageData
|
||||
from config.contents import left, not_left
|
||||
from exception.invalidArgumentException import InvalidArgumentException
|
||||
from exception.notFoundException import NotFoundException
|
||||
from handler.vo.updateData import UpdateData
|
||||
from logger import Logger
|
||||
from repository.userRepository import UserRepository
|
||||
from telegram.ext.callbackcontext import CallbackContext
|
||||
from telegram.ext.commandhandler import CommandHandler
|
||||
from telegram.update import Update
|
||||
|
||||
from handler.abstractHandler import AbstractHandler
|
||||
|
||||
|
||||
class OutHandler(AbstractHandler):
|
||||
class LeaveHandler(AbstractHandler):
|
||||
bot_handler: CommandHandler
|
||||
user_repository: UserRepository
|
||||
|
||||
def __init__(self) -> None:
|
||||
self.bot_handler = CommandHandler('out', self.handle)
|
||||
self.bot_handler = CommandHandler('leave', self.handle)
|
||||
self.user_repository = UserRepository()
|
||||
|
||||
def handle(self, update: Update, context: CallbackContext) -> None:
|
||||
try:
|
||||
update_data = self.get_update_data(update, context)
|
||||
message_data = MessageData.create_from_arguments(update, context)
|
||||
except InvalidArgumentException as e:
|
||||
return self.reply_markdown(update, str(e))
|
||||
|
||||
try:
|
||||
user = self.user_repository.get_by_id(update_data.user_id)
|
||||
user = self.user_repository.get_by_id(message_data.user_id)
|
||||
|
||||
if not user.is_in_chat(update_data.chat_id):
|
||||
if not user.is_in_chat(message_data.chat_id):
|
||||
raise NotFoundException()
|
||||
except NotFoundException:
|
||||
return self.reply_markdown(update, opted_off_failed)
|
||||
return self.reply_markdown(update, self.interpolate_reply(not_left, message_data))
|
||||
|
||||
user.remove_from_chat(update_data.chat_id)
|
||||
user.remove_from_chat(message_data.chat_id)
|
||||
self.user_repository.save(user)
|
||||
|
||||
self.reply_markdown(update, opted_off)
|
||||
self.log_action(update_data)
|
||||
self.reply_markdown(update, self.interpolate_reply(left, message_data))
|
||||
self.log_action(message_data)
|
||||
|
||||
def get_bot_handler(self) -> CommandHandler:
|
||||
return self.bot_handler
|
||||
|
||||
def log_action(self, update_data: UpdateData) -> None:
|
||||
Logger.info(f'User {update_data.username} left {update_data.chat_id}')
|
||||
def log_action(self, message_data: MessageData) -> None:
|
||||
Logger.info(f'User {message_data.username} left {message_data.chat_id}')
|
@@ -1,17 +1,18 @@
|
||||
from typing import Iterable
|
||||
|
||||
from telegram.utils.helpers import mention_markdown
|
||||
|
||||
from bot.handler.abstractHandler import AbstractHandler
|
||||
from bot.message.messageData import MessageData
|
||||
from config.contents import mention_failed
|
||||
from entity.user import User
|
||||
from exception.invalidArgumentException import InvalidArgumentException
|
||||
from handler.vo.updateData import UpdateData
|
||||
from logger import Logger
|
||||
from repository.userRepository import UserRepository
|
||||
from telegram.ext.callbackcontext import CallbackContext
|
||||
from telegram.ext.commandhandler import CommandHandler
|
||||
from telegram.update import Update
|
||||
|
||||
from handler.abstractHandler import AbstractHandler
|
||||
|
||||
|
||||
class MentionHandler(AbstractHandler):
|
||||
bot_handler: CommandHandler
|
||||
@@ -23,28 +24,24 @@ class MentionHandler(AbstractHandler):
|
||||
|
||||
def handle(self, update: Update, context: CallbackContext) -> None:
|
||||
try:
|
||||
update_data = self.get_update_data(update, context)
|
||||
message_data = MessageData.create_from_arguments(update, context)
|
||||
except InvalidArgumentException as e:
|
||||
return self.reply_markdown(update, str(e))
|
||||
|
||||
users = self.user_repository.get_all_for_chat(update_data.chat_id)
|
||||
users = self.user_repository.get_all_for_chat(message_data.chat_id)
|
||||
|
||||
if users:
|
||||
self.reply_markdown(update, self.build_mention_message(users))
|
||||
return self.log_action(update_data)
|
||||
return self.log_action(message_data)
|
||||
|
||||
self.reply_markdown(update, mention_failed)
|
||||
|
||||
def get_bot_handler(self) -> CommandHandler:
|
||||
return self.bot_handler
|
||||
|
||||
def log_action(self, update_data: UpdateData) -> None:
|
||||
Logger.info(f'User {update_data.username} called /everyone for {update_data.chat_id}')
|
||||
def log_action(self, message_data: MessageData) -> None:
|
||||
Logger.info(f'User {message_data.username} called /everyone for {message_data.chat_id}')
|
||||
|
||||
def build_mention_message(self, users: Iterable[User]) -> str:
|
||||
result = ''
|
||||
return ' '.join([mention_markdown(user.user_id, user.username) for user in users])
|
||||
|
||||
for user in users:
|
||||
result += f'*[{user.username}](tg://user?id={user.user_id})* '
|
||||
|
||||
return result
|
21
src/bot/handler/silentMentionHandler.py
Normal file
21
src/bot/handler/silentMentionHandler.py
Normal file
@@ -0,0 +1,21 @@
|
||||
from typing import Iterable
|
||||
|
||||
from entity.user import User
|
||||
from logger import Logger
|
||||
from telegram.ext.commandhandler import CommandHandler
|
||||
|
||||
from bot.handler.abstractHandler import AbstractHandler
|
||||
from bot.handler.mentionHandler import MentionHandler
|
||||
from bot.message.messageData import MessageData
|
||||
|
||||
|
||||
class MentionHandler(MentionHandler, AbstractHandler):
|
||||
def __init__(self) -> None:
|
||||
super().__init__()
|
||||
self.bot_handler = CommandHandler('silent', self.handle)
|
||||
|
||||
def build_mention_message(self, users: Iterable[User]) -> str:
|
||||
return ' '.join([user.username for user in users])
|
||||
|
||||
def log_action(self, message_data: MessageData) -> None:
|
||||
Logger.info(f'User {message_data.username} called /silent for {message_data.chat_id}')
|
@@ -4,8 +4,8 @@ from telegram.ext.callbackcontext import CallbackContext
|
||||
from telegram.ext.commandhandler import CommandHandler
|
||||
from telegram.update import Update
|
||||
|
||||
from handler.abstractHandler import AbstractHandler
|
||||
from handler.vo.updateData import UpdateData
|
||||
from bot.handler.abstractHandler import AbstractHandler
|
||||
from bot.message.messageData import MessageData
|
||||
|
||||
|
||||
class StartHandler(AbstractHandler):
|
||||
@@ -16,10 +16,10 @@ class StartHandler(AbstractHandler):
|
||||
|
||||
def handle(self, update: Update, context: CallbackContext) -> None:
|
||||
self.reply_markdown(update, start_text)
|
||||
self.log_action(UpdateData.create_from_arguments(update, context))
|
||||
self.log_action(MessageData.create_from_arguments(update, context))
|
||||
|
||||
def get_bot_handler(self) -> CommandHandler:
|
||||
return self.bot_handler
|
||||
|
||||
def log_action(self, update_data: UpdateData) -> None:
|
||||
Logger.info(f'User {update_data.username} called /start for {update_data.chat_id}')
|
||||
def log_action(self, message_data: MessageData) -> None:
|
||||
Logger.info(f'User {message_data.username} called /start for {message_data.chat_id}')
|
@@ -1,26 +1,27 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from dataclasses import dataclass
|
||||
import re
|
||||
from dataclasses import dataclass
|
||||
|
||||
import names
|
||||
from entity.group import Group
|
||||
from exception.invalidArgumentException import InvalidArgumentException
|
||||
from telegram.ext.callbackcontext import CallbackContext
|
||||
from telegram.update import Update
|
||||
from entity.group import Group
|
||||
|
||||
from exception.invalidArgumentException import InvalidArgumentException
|
||||
|
||||
|
||||
@dataclass
|
||||
class UpdateData():
|
||||
class MessageData():
|
||||
user_id: str
|
||||
chat_id: str
|
||||
group_name: str
|
||||
username: str
|
||||
|
||||
@staticmethod
|
||||
def create_from_arguments(update: Update, context: CallbackContext, include_group: bool = True) -> UpdateData:
|
||||
def create_from_arguments(update: Update, context: CallbackContext, include_group: bool = True) -> MessageData:
|
||||
chat_id = str(update.effective_chat.id)
|
||||
|
||||
group_name = Group.default_name
|
||||
|
||||
if context.args and context.args[0] and include_group:
|
||||
group_name = str(context.args[0]).lower()
|
||||
if not re.match(r"^[A-Za-z]+$", group_name):
|
||||
@@ -41,4 +42,4 @@ class UpdateData():
|
||||
if not username:
|
||||
username = names.get_first_name()
|
||||
|
||||
return UpdateData(user_id, chat_id, username)
|
||||
return MessageData(user_id, chat_id, group_name, username)
|
@@ -1,28 +1,25 @@
|
||||
import re
|
||||
|
||||
# These are MarkdownV2 python-telegram-bot specific
|
||||
opted_in = re.escape('You have opted-in for everyone-mentions.')
|
||||
opted_in_failed = re.escape('You already opted-in for everyone-mentions.')
|
||||
opted_off = re.escape('You have opted-off for everyone-mentions.')
|
||||
opted_off_failed = re.escape('You need to opt-in first before processing this command.')
|
||||
mention_failed = re.escape('There are no users to mention.')
|
||||
no_groups = re.escape('There are no groups for this chat.')
|
||||
joined = '{} joined group `{}`'
|
||||
not_joined = '{} is already in group `{}`'
|
||||
left = '{} left group `{}`'
|
||||
not_left = '{} did not join group `{}` before'
|
||||
mention_failed = 'There are no users to mention'
|
||||
no_groups = 'There are no groups for this chat'
|
||||
|
||||
|
||||
start_text = re.escape("""
|
||||
Hello there.
|
||||
I am `@everyone_mention_bot`.
|
||||
I am here to help you with mass notifies.
|
||||
start_text = """
|
||||
Hello there
|
||||
I am @everyone\_mention\_bot
|
||||
I am here to help you with mass notifies
|
||||
|
||||
Please take a look at available commands.
|
||||
Parameter `<group-name>` is not required, if not given, I will assign you to `default` group.
|
||||
Please take a look at available commands
|
||||
`<group-name>` is not required, if not given, it is set to `default`
|
||||
|
||||
To opt-in for everyone-mentions use:
|
||||
`/in <group-name>`
|
||||
for example: `/in gaming`
|
||||
To join group:
|
||||
`/join <group-name>`
|
||||
for example: `/join games`
|
||||
|
||||
To opt-off for everyone mentions use:
|
||||
`/out <group-name>`
|
||||
To leave group:
|
||||
`/leave <group-name>`
|
||||
|
||||
To gather everyone attention use:
|
||||
`/everyone <group-name>`
|
||||
@@ -30,8 +27,6 @@ To gather everyone attention use:
|
||||
To see all available groups use:
|
||||
`/groups`
|
||||
|
||||
To display all users that opted-in for everyone-mentions use:
|
||||
To display all members in a group:
|
||||
`/silent <group-name>`
|
||||
|
||||
In case questions regarding my usage please reach out to @miloszowi
|
||||
""")
|
||||
"""
|
@@ -1,46 +0,0 @@
|
||||
from handler.vo.updateData import UpdateData
|
||||
from logger import Logger
|
||||
from config.contents import opted_in, opted_in_failed
|
||||
from exception.invalidArgumentException import InvalidArgumentException
|
||||
from exception.notFoundException import NotFoundException
|
||||
from repository.userRepository import UserRepository
|
||||
from telegram.ext.callbackcontext import CallbackContext
|
||||
from telegram.ext.commandhandler import CommandHandler
|
||||
from telegram.update import Update
|
||||
|
||||
from handler.abstractHandler import AbstractHandler
|
||||
|
||||
|
||||
class InHandler(AbstractHandler):
|
||||
bot_handler: CommandHandler
|
||||
user_repository: UserRepository
|
||||
|
||||
def __init__(self) -> None:
|
||||
self.bot_handler = CommandHandler('in', self.handle)
|
||||
self.user_repository = UserRepository()
|
||||
|
||||
def handle(self, update: Update, context: CallbackContext) -> None:
|
||||
try:
|
||||
update_data = self.get_update_data(update, context)
|
||||
except InvalidArgumentException as e:
|
||||
return self.reply_markdown(update, str(e))
|
||||
|
||||
try:
|
||||
user = self.user_repository.get_by_id(update_data.user_id)
|
||||
|
||||
if user.is_in_chat(update_data.chat_id):
|
||||
return self.reply_markdown(update, opted_in_failed)
|
||||
|
||||
user.add_to_chat(update_data.chat_id)
|
||||
self.user_repository.save(user)
|
||||
except NotFoundException:
|
||||
self.user_repository.save_by_update_data(update_data)
|
||||
|
||||
self.reply_markdown(update, opted_in)
|
||||
self.log_action(update_data)
|
||||
|
||||
def get_bot_handler(self) -> CommandHandler:
|
||||
return self.bot_handler
|
||||
|
||||
def log_action(self, update_data: UpdateData) -> None:
|
||||
Logger.info(f'User {update_data.username} joined {update_data.chat_id}')
|
@@ -1,26 +0,0 @@
|
||||
from typing import Iterable
|
||||
|
||||
from entity.user import User
|
||||
from logger import Logger
|
||||
from telegram.ext.commandhandler import CommandHandler
|
||||
|
||||
from handler.abstractHandler import AbstractHandler
|
||||
from handler.mentionHandler import MentionHandler
|
||||
from handler.vo.updateData import UpdateData
|
||||
|
||||
|
||||
class MentionHandler(MentionHandler, AbstractHandler):
|
||||
def __init__(self) -> None:
|
||||
super().__init__()
|
||||
self.bot_handler = CommandHandler('silent', self.handle)
|
||||
|
||||
def build_mention_message(self, users: Iterable[User]) -> str:
|
||||
result = ''
|
||||
|
||||
for user in users:
|
||||
result += f'*{user.username}\({user.user_id}\)*\n'
|
||||
|
||||
return result
|
||||
|
||||
def log_action(self, update_data: UpdateData) -> None:
|
||||
Logger.info(f'User {update_data.username} called /silent for {update_data.chat_id}')
|
@@ -1,9 +1,9 @@
|
||||
from typing import Iterable, Optional
|
||||
|
||||
from bot.message.messageData import MessageData
|
||||
from database.client import Client
|
||||
from entity.user import User
|
||||
from exception.notFoundException import NotFoundException
|
||||
from handler.vo.updateData import UpdateData
|
||||
|
||||
|
||||
class UserRepository():
|
||||
@@ -36,7 +36,7 @@ class UserRepository():
|
||||
user.to_mongo_document()
|
||||
)
|
||||
|
||||
def save_by_update_data(self, data: UpdateData) -> None:
|
||||
def save_by_message_data(self, data: MessageData) -> None:
|
||||
self.client.insert_one(
|
||||
User.collection,
|
||||
{
|
||||
|
Reference in New Issue
Block a user