implemented strategy design pattern for buttons in messages.

added handler for button callback

Next: implement business logic
pull/231/head
Yariv Menachem 2024-12-29 18:22:52 +02:00
parent 8996c59492
commit 8195c2c884
9 changed files with 143 additions and 28 deletions

View File

@ -6,7 +6,7 @@ from telegram.ext import Application, CommandHandler, CallbackQueryHandler
from src.jobspy import Site
from src.jobspy.scrapers.utils import create_logger
from src.telegram_handler import TelegramIndeedHandler, TelegramDefaultHandler
from src.telegram_handler.telegram_callback_handler import TelegramCallHandler
from src.telegram_handler.button_callback.telegram_callback_handler import TelegramCallHandler
logger = create_logger("Main")
title_filters: list[str] = ["test", "qa", "Lead", "Full-Stack", "Full Stack", "Fullstack", "Frontend", "Front-end",

View File

@ -44,7 +44,6 @@ class TelegramBot:
logger.error(f"Failed to send job to Telegram: {job.id}")
logger.error(f"Error: {e}")
async def send_test_message(self):
"""
Send Test Message to Telegram chat.
@ -65,15 +64,14 @@ class TelegramBot:
logger.error("Failed o send test message to Telegram")
logger.error(f"Error: {e}")
async def set_message_reaction(self, message_id: int, emoji_reaction: str):
async def set_message_reaction(self, message_id: int, emoji_reaction: ReactionEmoji):
"""
Send Test Message to Telegram chat.
"""
try:
await self.bot.set_message_reaction(chat_id=self.chatId, message_id=message_id,
reaction=ReactionEmoji[emoji_reaction])
logger.info("Sent test message to Telegram")
reaction=emoji_reaction)
logger.info(f"Reaction set to message: {message_id}")
except Exception as e:
logger.error("Failed to send test message to Telegram")
logger.error(f"Failed to set Reaction to message: {message_id}")
logger.error(f"Error: {e}")

View File

@ -0,0 +1,45 @@
from __future__ import annotations
from src.telegram_bot import TelegramBot
from src.telegram_handler.button_callback.button_strategy import ButtonStrategy
class ButtonCallBackContext():
"""
The Context defines the interface
"""
def __init__(self, strategy: ButtonStrategy = None) -> None:
self.telegram_bot = TelegramBot()
self._strategy = strategy
@property
def strategy(self) -> ButtonStrategy:
"""
The Context maintains a reference to one of the Strategy objects. The
Context does not know the concrete class of a strategy. It should work
with all strategies via the Strategy interface.
"""
return self._strategy
@strategy.setter
def strategy(self, strategy: ButtonStrategy) -> None:
"""
Usually, the Context allows replacing a Strategy object at runtime.
"""
self._strategy = strategy
async def run(self) -> None:
# extract job id from message
# find the position in DB
# set applied to True
# save
# set reaction to message
print("Context: Starting")
await self._strategy.execute()
print("Context: Finished")
# ...

View File

@ -0,0 +1,24 @@
from telegram import MaybeInaccessibleMessage
from telegram.constants import ReactionEmoji
from src.telegram_bot import TelegramBot
from src.telegram_handler.button_callback.button_strategy import ButtonStrategy
class FireStrategy(ButtonStrategy):
def __init__(self, data: MaybeInaccessibleMessage) -> None:
"""
Usually, the Context accepts a strategy through the constructor, but
also provides a setter to change it at runtime.
"""
self.data = data
self._emoji = ReactionEmoji.FIRE
async def execute(self):
telegram_bot = TelegramBot()
await telegram_bot.set_message_reaction(self.data.message_id, self._emoji)
# find the position in DB
# set applied to True
# save
# set reaction to message
pass

View File

@ -0,0 +1,17 @@
from telegram import MaybeInaccessibleMessage
from telegram.constants import ReactionEmoji
from src.telegram_handler.button_callback.button_strategy import ButtonStrategy
class PooStrategy(ButtonStrategy):
def __init__(self, data: MaybeInaccessibleMessage) -> None:
"""
Usually, the Context accepts a strategy through the constructor, but
also provides a setter to change it at runtime.
"""
self.data = data
self._emoji = ReactionEmoji.PILE_OF_POO
async def execute(self):
pass

View File

@ -0,0 +1,15 @@
from abc import ABC, abstractmethod
class ButtonStrategy(ABC):
"""
The Strategy interface declares operations common to all supported versions
of some algorithm.
The Context uses this interface to call the algorithm defined by Concrete
Strategies.
"""
@abstractmethod
async def execute(self):
pass

View File

@ -0,0 +1,37 @@
from telegram import Update
from telegram.constants import ReactionEmoji
from telegram.ext import (
ContextTypes,
)
from src.telegram_bot import TelegramBot
from src.telegram_handler.button_callback.button_callback_context import ButtonCallBackContext
from src.telegram_handler.button_callback.button_fire_strategy import FireStrategy
from src.telegram_handler.button_callback.button_poo_strategy import PooStrategy
class TelegramCallHandler:
def __init__(self):
self.telegram_bot = TelegramBot()
async def button_callback(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
"""Parses the CallbackQuery and updates the message text."""
query = update.callback_query
# CallbackQueries need to be answered, even if no notification to the user is needed
# Some clients may have trouble otherwise. See https://core.telegram.org/bots/api#callbackquery
await query.answer()
button_context = ButtonCallBackContext()
if ReactionEmoji.FIRE.name == query.data:
strategy = FireStrategy(query.message)
# elif ReactionEmoji.PILE_OF_POO.name == query.data:
# strategy = PooStrategy(query.message)
else:
raise ValueError("Invalid enum value")
if not strategy:
return
button_context.strategy = strategy
await button_context.run()

View File

@ -1,21 +0,0 @@
from telegram import Update
from telegram.ext import (
ContextTypes,
)
from src.telegram_bot import TelegramBot
class TelegramCallHandler:
def __init__(self):
self.telegram_bot = TelegramBot()
async def button_callback(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
"""Parses the CallbackQuery and updates the message text."""
query = update.callback_query
# CallbackQueries need to be answered, even if no notification to the user is needed
# Some clients may have trouble otherwise. See https://core.telegram.org/bots/api#callbackquery
await query.answer()
await self.telegram_bot.set_message_reaction(query.message.message_id, query.data)