def test_guess_member(self, monkeypatch): monkeypatch.setattr(Photon, 'geocode', get_address_from_cache) Member.set_akadressen_credentials('http://all', 'http://active', '', '') with open(check_file_path('tests/data/akadressen.pdf'), 'rb') as akadressen: responses.add( responses.GET, 'http://all', body=akadressen.read(), stream=True, status=200, adding_headers={'Transfer-Encoding': 'chunked'}, ) with open(check_file_path('tests/data/akadressen-active.pdf'), 'rb') as akadressen_active: responses.add( responses.GET, 'http://active', body=akadressen_active.read(), stream=True, status=200, adding_headers={'Transfer-Encoding': 'chunked'}, ) assert Member._AKADRESSEN_CACHE_TIME is None assert Member._AKADRESSEN is None user_1 = User(1, is_bot=False, first_name='John', last_name='Doe') members = Member.guess_member(user_1) assert Member._AKADRESSEN_CACHE_TIME == dt.date.today() assert isinstance(Member._AKADRESSEN, pd.DataFrame) assert len(members) == 1 member = members[0] assert member.user_id == 1 assert member.last_name == 'Doe' assert member.first_name == 'John' assert member.nickname == 'Jonny' assert member.date_of_birth == dt.date(2000, 1, 1) assert member.instruments == [instruments.Trumpet()] assert member.address == 'Münzstraße 5, 38100 Braunschweig' assert member.joined == 2004 Member._AKADRESSEN = None user_2 = User(2, is_bot=False, first_name='Marcel', last_name='Marcel') members = Member.guess_member(user_2) assert Member._AKADRESSEN_CACHE_TIME == dt.date.today() assert isinstance(Member._AKADRESSEN, pd.DataFrame) assert len(members) == 1 member = members[0] assert member.user_id == 2 assert member.last_name == 'Marcel' assert member.first_name == 'Marcel' assert member.nickname is None assert member.date_of_birth == dt.date(2000, 5, 1) assert member.instruments == [] assert member.address == 'Universitätsplatz 2, 38106 Braunschweig' assert member.joined == 2005 test_flag = False def _get_akadressen(*args, **kwargs): nonlocal test_flag test_flag = True monkeypatch.setattr(Member, '_get_akadressen', _get_akadressen) user_3 = User(3, is_bot=False, first_name='Test', username='******') members = Member.guess_member(user_3) assert Member._AKADRESSEN_CACHE_TIME == dt.date.today() assert isinstance(Member._AKADRESSEN, pd.DataFrame) assert not test_flag assert len(members) == 1 member = members[0] assert member.user_id == 3 assert member.last_name == 'Zufall' assert member.first_name == 'Rainer' assert member.nickname == 'Das Brot' assert member.date_of_birth == dt.date(2007, 7, 5) assert member.instruments == [instruments.Flute()] assert member.address == 'Bültenweg 74-75, 38106 Braunschweig' assert member.joined is None user_4 = User(1, is_bot=False, first_name=None) assert Member.guess_member(user_4) is None
def setup( # pylint: disable=R0913,R0914,R0915 dispatcher: Dispatcher, admin: Union[int, str], oc_url: str, oc_username: str, oc_password: str, oc_path: str, ad_url: str, ad_url_active: str, ad_username: str, ad_password: str, yourls_url: str, yourls_signature: str, ) -> None: """ * Adds handlers. Convenience method to avoid doing that all in the main script. * Sets the bot commands and makes sure ``dispatcher.bot_data`` is set up correctly. * Registers a :class:`telegram.ext.TypeHandler` that makes sure that conversations are not interrupted * Sets up statistics Args: dispatcher: The :class:`telegram.ext.Dispatcher`. admin: The admins chat id. oc_url: URL of the OwnCloud Instance. oc_username: Username for the OwnCloud Instance. oc_password: Password of the OwnCloud Instance. oc_path: Remote path on the OwnCloud Instance. ad_url: URL of the AkaDressen file. ad_url_active: URL of the AkaDressen file containing only the active members. ad_username: Username for the AkaDressen. ad_password: Password for the AkaDressen. yourls_url: URL of the YOURLS instance. yourls_signature: Signature for the YOURLS instance. """ def check_conversation_status(update: Update, context: CallbackContext) -> None: """ Checks if the user is currently in a conversation. If they are and the corresponding conversation does *not* handle the incoming update, the user will get a corresponding message and the update will be discarded. Args: update: The update. context: The context as provided by the :class:`telegram.ext.Dispatcher`. """ if not update.effective_user: return conversation = context.user_data.get(CONVERSATION_KEY, None) if not conversation: return conversation_check = not bool( conversations[conversation].check_update(update)) # Make sure that the callback queries for vcard requests are not processed if update.callback_query: contact_request_check = bool( re.match(inline.REQUEST_CONTACT_PATTERN, update.callback_query.data)) highscore_check = 'highscore' in update.callback_query.data else: contact_request_check = False highscore_check = False if conversation_check or contact_request_check or highscore_check: text = interrupt_replies[conversation] if update.callback_query: update.callback_query.answer(text=text, show_alert=True) elif update.effective_message: update.effective_message.reply_text(text) raise DispatcherHandlerStop() def clear_conversation_status(update: Update, context: CallbackContext) -> None: """ Clears the conversation status of a user in case of an error. Just to be sure. Args: update: The update. context: The context as provided by the :class:`telegram.ext.Dispatcher`. """ if update.effective_user: context.user_data.pop(CONVERSATION_KEY) # ------------------------------------------------------------------------------------------- # # Set up statistics set_dispatcher(dispatcher) # Count total number of updates register_stats(SimpleStats('stats', lambda u: bool(u.effective_user)), admin_id=int(admin)) # Count number of started games register_stats( SimpleStats( 'game_stats', lambda u: bool(u.message) and Filters.text('/spiel_starten')(u)), admin_id=int(admin), ) # Count number of requested contacts register_stats( admin_id=int(admin), stats=SimpleStats( 'contact_stats', lambda u: bool(u.callback_query and 'contact_request' in u. callback_query.data), ), ) # Handlers # Prepare conversations game_handler = game.GAME_HANDLER editing_conversation = editing.build_editing_handler(int(admin)) canceling_conversation = cancel_membership.CANCEL_MEMBERSHIP_HANDLER banning_conversation = ban.build_banning_handler(int(admin)) conversations: Dict[str, ConversationHandler] = { game.CONVERSATION_VALUE: game_handler, editing.CONVERSATION_VALUE: editing_conversation, cancel_membership.CONVERSATION_VALUE: canceling_conversation, ban.CONVERSATION_VALUE: banning_conversation, } interrupt_replies: Dict[str, str] = { game.CONVERSATION_VALUE: game.CONVERSATION_INTERRUPT_TEXT, editing.CONVERSATION_VALUE: editing.CONVERSATION_INTERRUPT_TEXT, cancel_membership.CONVERSATION_VALUE: cancel_membership.CONVERSATION_INTERRUPT_TEXT, ban.CONVERSATION_VALUE: ban.CONVERSATION_INTERRUPT_TEXT, } # Registration status dispatcher.add_handler(TypeHandler(Update, registration.check_registration_status), group=-2) # Conversation Interruption behaviour dispatcher.add_handler(TypeHandler(Update, check_conversation_status), group=-1) # Game Conversation # Must be first so that the fallback can catch unrelated messages dispatcher.add_handler(game_handler) # Registration process # We need the filter here in order to not catch /start with deep linking parameter used for # inline help dispatcher.add_handler( CommandHandler('start', registration.start, filters=Filters.text('/start'))) dispatcher.add_handler( CallbackQueryHandler(registration.request_registration, pattern=REGISTRATION_PATTERN, run_async=True)) dispatcher.add_handler(registration.ACCEPT_REGISTRATION_HANDLER) dispatcher.add_handler(registration.DENY_REGISTRATION_HANDLER) # Edit user data dispatcher.add_handler(editing_conversation) # Cancel membership dispatcher.add_handler(canceling_conversation) # Banning members dispatcher.add_handler(banning_conversation) # Simple commands dispatcher.add_handler( CommandHandler(['hilfe', 'help'], commands.help_message)) dispatcher.add_handler(CommandHandler('daten_anzeigen', commands.show_data)) dispatcher.add_handler( CommandHandler('kontakt_abrufen', commands.start_inline)) dispatcher.add_handler( CommandHandler('start', commands.start_inline, filters=Filters.text(f'/start {INLINE_HELP}'))) # Inline Mode dispatcher.add_handler(InlineQueryHandler(inline.search_users)) dispatcher.add_handler(inline.SEND_VCARD_HANDLER) # Highscores dispatcher.add_handler( CommandHandler('highscore', highscore.show_highscore)) dispatcher.add_handler(highscore.HIGHSCORE_HANDLER) # Set commands dispatcher.bot.set_my_commands(BOT_COMMANDS) # Admin stuff dispatcher.add_handler( CommandHandler('rebuild', bot.admin.rebuild_orchestra, filters=Filters.user(int(admin)))) # Error Handler dispatcher.add_error_handler(error.handle_error) dispatcher.add_error_handler(clear_conversation_status) # Schedule jobs check_user_status.schedule_daily_job(dispatcher) backup.PATH = oc_path backup.URL = oc_url backup.USERNAME = oc_username backup.PASSWORD = oc_password backup.schedule_daily_job(dispatcher) # Set up AkaDressen credentials Member.set_akadressen_credentials(ad_url, ad_url_active, ad_username, ad_password) # Set up bot_data bot_data = dispatcher.bot_data if not bot_data.get(ORCHESTRA_KEY): bot_data[ORCHESTRA_KEY] = Orchestra() else: # We rebuild the orchestra on start up to make sure code changes are applied old_orchestra = bot_data.pop(ORCHESTRA_KEY) new_orchestra = old_orchestra.copy() bot_data[ORCHESTRA_KEY] = new_orchestra if not bot_data.get(PENDING_REGISTRATIONS_KEY): bot_data[PENDING_REGISTRATIONS_KEY] = dict() if not bot_data.get(DENIED_USERS_KEY): bot_data[DENIED_USERS_KEY] = list() bot_data[ADMIN_KEY] = int(admin) yourls_client = YOURLSClient(yourls_url, signature=yourls_signature, nonce_life=True) bot_data[YOURLS_KEY] = yourls_client # Clear conversation key user_data = dispatcher.user_data for user_id in user_data: user_data[user_id].pop(CONVERSATION_KEY, None)