From 694eadd7f06f65b925d2c06a3492bd7d9153d016 Mon Sep 17 00:00:00 2001 From: Dmitrii Morozov Date: Sun, 5 Jan 2025 22:33:28 +0100 Subject: Add query to accept or decline new friends --- formatter/__init__.py | 19 +++++++++-- fortnite_client/__init__.py | 38 +++++++++------------- fortnite_client/fortnite_events.py | 64 ++++++++++++++++++++++++++++++++++++-- telegram_bot/__init__.py | 3 +- telegram_bot/commands.py | 5 +-- 5 files changed, 97 insertions(+), 32 deletions(-) diff --git a/formatter/__init__.py b/formatter/__init__.py index 0642a40..460312a 100644 --- a/formatter/__init__.py +++ b/formatter/__init__.py @@ -149,8 +149,23 @@ def format_new_friend(display_name: str): def format_friend_disabled_public_stats(display_name: str): return formatting.format_text( - 'New friend ', + 'New friend', formatting.mbold('{}'.format(display_name)), 'has disabled public statistics in Fortnite profile, no statistics will be visible', - separator='' + separator=' ' + ) + +def format_new_friend_request(display_name: str): + return formatting.format_text( + 'New friend request from', + formatting.mbold('{}'.format(display_name)), + separator=' ' + ) + +def format_friend_declined(display_name: str): + return formatting.format_text( + 'Friend request from', + formatting.mbold('{}'.format(display_name)), + 'declined', + separator=' ' ) \ No newline at end of file diff --git a/fortnite_client/__init__.py b/fortnite_client/__init__.py index d44fee4..113f3d6 100644 --- a/fortnite_client/__init__.py +++ b/fortnite_client/__init__.py @@ -22,9 +22,10 @@ class ClientInitObserver: pass class NewFriendObserver: - async def on_event(self, friend: User) -> None: + async def on_new_friend_request(self, request_id: str, display_name: str, fortnite_client: any) -> None: + pass + async def on_friend_added(self, friend: User) -> None: pass - async def on_unavailable_public_stats(self, display_name) -> None: pass @@ -121,28 +122,17 @@ class FriendPresenceEvent: class IncomingFriendRequestEvent: async def on_event(request: typing.Union[fortnitepy.friend.IncomingPendingFriend, fortnitepy.friend.OutgoingPendingFriend], new_friend_observer: NewFriendObserver): - print('Do nothing on incoming friend request..') - #if isinstance(request, fortnitepy.friend.IncomingPendingFriend): - #incoming_request = typing.cast(fortnitepy.friend.IncomingPendingFriend, request) - #await incoming_request.accept() - #accepted_friend = incoming_request.client.get_friend(request._id) - - #if isinstance(request, fortnitepy.friend.OutgoingPendingFriend): - #outgoing_request = typing.cast(fortnitepy.friend.OutgoingPendingFriend, request) - #accepted_friend = outgoing_request.client.get_friend(request._id) + if isinstance(request, fortnitepy.friend.IncomingPendingFriend): + incoming_request = typing.cast(fortnitepy.friend.IncomingPendingFriend, request) + await IncomingFriendRequestEvent.__handle_friend_request(incoming_request, new_friend_observer) - #await IncomingFriendRequestEvent.__handle_new_friend(accepted_friend, new_friend_observer) + if isinstance(request, fortnitepy.friend.OutgoingPendingFriend): + outgoing_request = typing.cast(fortnitepy.friend.OutgoingPendingFriend, request) + accepted_friend = outgoing_request.client.get_friend(request._id) + await IncomingFriendRequestEvent.__handle_new_friend(accepted_friend, new_friend_observer) - async def __handle_new_friend(accepted_friend: fortnitepy.friend.Friend, new_friend_observer: NewFriendObserver): - # Try fetch stats - try: - await IncomingFriendRequestEvent.__try_get_stats(accepted_friend) - except: - print(traceback.format_exc()) - await new_friend_observer.on_unavailable_public_stats(accepted_friend.display_name) - - # Register new fried, fetch stats - await new_friend_observer.on_event(User.from_fortnite_friend(accepted_friend)) + async def __handle_friend_request(request: fortnitepy.friend.IncomingPendingFriend, new_friend_observer: NewFriendObserver): + await new_friend_observer.on_new_friend_request(request._id, request.display_name, request.client) - async def __try_get_stats(friend: fortnitepy.Friend): - await friend.fetch_br_stats() \ No newline at end of file + async def __handle_new_friend(accepted_friend: fortnitepy.friend.Friend, new_friend_observer: NewFriendObserver): + await new_friend_observer.on_friend_added(accepted_friend) \ No newline at end of file diff --git a/fortnite_client/fortnite_events.py b/fortnite_client/fortnite_events.py index 918b1e1..1efbc4e 100644 --- a/fortnite_client/fortnite_events.py +++ b/fortnite_client/fortnite_events.py @@ -7,6 +7,9 @@ from telegram_bot import * from persistence import * from formatter import * +__accept_keyword__ = "accept" +__decline_keyword__ = "decline" + class ClientInitObserverImpl(ClientInitObserver): async def on_event(self, fortnite_client: FortniteClient) -> None: print('----------------') @@ -43,10 +46,65 @@ class NewFriendObserverImpl(NewFriendObserver): def __init__(self, telegram_bot: TelegramBot, stats_repository: StatsRepository): self.__telegram_bot = telegram_bot self.__stats_repository = stats_repository + + async def on_new_friend_request(self, request_id: str, display_name: str, fortnite_client: FortniteClient) -> None: + __new_friend_reply_markup = telebot.types.InlineKeyboardMarkup() + __new_friend_reply_markup.add(telebot.types.InlineKeyboardButton('Accept', callback_data="{}:{}:{}".format(__accept_keyword__, request_id, display_name))) + __new_friend_reply_markup.add(telebot.types.InlineKeyboardButton('Decline', callback_data="{}:{}:{}".format(__decline_keyword__, request_id, display_name))) + + self.__telegram_bot.register_callback_query( + NewFriendCallbackQueryHandler(self.__telegram_bot, fortnite_client, self), + lambda call: call.data.startswith(__accept_keyword__) or call.data.startswith(__decline_keyword__)) + + await self.__telegram_bot.send_message_to_all(format_new_friend_request(display_name), reply_markup=__new_friend_reply_markup) - async def on_event(self, friend: User) -> None: + async def on_friend_added(self, fornite_friend: fortnitepy.friend.Friend) -> None: + # Try fetch stats + try: + await self.__try_get_stats(fornite_friend) + except: + print(traceback.format_exc()) + await self.__on_unavailable_public_stats(fornite_friend.display_name) + + friend = User.from_fortnite_friend(fornite_friend) await self.__stats_repository.put_stats(friend, datetime.datetime.now()) await self.__telegram_bot.send_message_to_all(format_new_friend(friend.display_name)) - async def on_unavailable_public_stats(self, display_name) -> None: - await self.__telegram_bot.send_message_to_all(format_friend_disabled_public_stats(display_name)) \ No newline at end of file + async def __try_get_stats(self, friend: fortnitepy.friend.Friend): + await friend.fetch_br_stats() + + async def __on_unavailable_public_stats(self, display_name) -> None: + await self.__telegram_bot.send_message_to_all(format_friend_disabled_public_stats(display_name)) + +class NewFriendCallbackQueryHandler(CallbackQueryHandler): + __telegram_bot: TelegramBot + __fortnite_client: FortniteClient + __new_friend_observer: NewFriendObserver + + def __init__(self, telegram_bot: TelegramBot, fortnite_client: FortniteClient, new_friend_observer: NewFriendObserver): + self.__telegram_bot = telegram_bot + self.__fortnite_client = fortnite_client + self.__new_friend_observer = new_friend_observer + + async def handle(self, call: telebot.types.CallbackQuery): + if self.__fortnite_client.is_initialized(): + answered: bool = False + if call.data.startswith(__accept_keyword__) or call.data.startswith(__decline_keyword__): + splitted = call.data.split(":") + await self.__handle_request(splitted[0], splitted[1], splitted[2]) + + await self.__telegram_bot.answer_callback_query(callback_query_id=call.id) + + async def __handle_request(self, action: str, request_id: str, display_name: str): + pending_friends = self.__fortnite_client.pending_friends + for pending_friend in pending_friends: + if isinstance(pending_friend, fortnitepy.friend.IncomingPendingFriend): + incoming_request = typing.cast(fortnitepy.friend.IncomingPendingFriend, pending_friend) + if incoming_request._id == request_id: + if action == __accept_keyword__: + await incoming_request.accept() + accepted_friend = incoming_request.client.get_friend(incoming_request._id) + await self.__new_friend_observer.on_friend_added(accepted_friend) + elif action == __decline_keyword__: + await incoming_request.decline() + await self.__telegram_bot.send_message_to_all(format_friend_declined(display_name)) \ No newline at end of file diff --git a/telegram_bot/__init__.py b/telegram_bot/__init__.py index c25af95..a50c71b 100644 --- a/telegram_bot/__init__.py +++ b/telegram_bot/__init__.py @@ -47,12 +47,13 @@ class TelegramBot: async def answer_callback_query(self, callback_query_id): await self.__bot.answer_callback_query(callback_query_id=callback_query_id) - async def send_message_to_all(self, message_text: str): + async def send_message_to_all(self, message_text: str, reply_markup = None): for user in self.__user_repository.get_all_users(): try: await self.__bot.send_message( user[0], message_text, + reply_markup=reply_markup, parse_mode='MarkdownV2' ) except Exception as error: diff --git a/telegram_bot/commands.py b/telegram_bot/commands.py index 697d1e3..9c12d97 100644 --- a/telegram_bot/commands.py +++ b/telegram_bot/commands.py @@ -80,7 +80,8 @@ class GetStatsCallbackQueryHandler(CallbackQueryHandler): await self.reply_with_stats_days_difference(call.message, __duration_week__) elif call.data == __stats_month__: await self.reply_with_stats_days_difference(call.message, __duration_month__) - await self.__telegram_bot.answer_callback_query(callback_query_id=call.id) + + await self.__telegram_bot.answer_callback_query(callback_query_id=call.id) async def reply_with_today_stats(self, message): friends = await self.__fortnite_client.get_friends() @@ -117,7 +118,7 @@ class GetStatsCommand(CommandHandler): self.__telegram_bot.register_callback_query( GetStatsCallbackQueryHandler(self.__telegram_bot, self.__fortnite_client, self.__stats_repository), - lambda call: True) + lambda call: call.data == __stats_now__ or call.data == __stats_day__ or call.data == __stats_week__ or call.data == __stats_month__) async def handle(self, message: telebot.types.Message): await self.__telegram_bot.reply(message, 'Which statistics would you like to see?', reply_markup=self.__reply_markup) -- cgit v1.2.3