mirror of https://github.com/Bunsly/JobSpy
implemented strategy design pattern for buttons in messages.
added handler for button callback Next: implement business logicpull/231/head
parent
8996c59492
commit
8195c2c884
|
@ -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",
|
||||
|
|
|
@ -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}")
|
||||
|
|
|
@ -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")
|
||||
|
||||
# ...
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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()
|
||||
|
|
@ -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)
|
||||
|
Loading…
Reference in New Issue