def test_cascade_delete_bot_and_message_by_id_with_valid_botid_and_no_msgs( self): bot = MyBot(token='dummy-token', username='******').save() self.assertIsNotNone(bot) response = self.client.delete(url_for( 'botapi.delete_bot_and_message_by_id', botid=bot.bot_id), headers=self.get_api_headers()) self.assertEqual(response.status_code, 200) json_response = json.loads(response.data.decode('utf-8')) self.assertEqual(json_response['status'], 'success') self.assertTrue(bot.username in json_response['message']) self.assertEqual( json_response['message'], 'Bot:{uname} and {msgs} logged messages ' 'removed'.format(uname=bot.username, msgs=0))
class EditBot(FlaskForm): """ Flask form for editing a bot status i.e. enable/disable polling for the bot. """ choose_bot = SelectField( 'Choose Bot', coerce=str, choices=[('#', 'Select')] + list(MyBot.objects().values_list('username', 'username'))) status_field = StringField('Status') toggle = SubmitField() def __init__(self, *args, **kwargs): super(EditBot, self).__init__(*args, **kwargs) read_only(self.status_field)
def test_add_testbot_using_dummy_token_and_test_flag(self): response = self.client.post(url_for('botapi.add_bot', token='dummy-token', test=1), headers=self.get_api_headers()) json_response = json.loads(response.data.decode('utf-8')) self.assertEqual(response.status_code, 201) self.assertEqual(json_response['status'], 'ok') bot = MyBot.objects(token='dummy-token', test_bot=True).first() self.assertIsNotNone(bot) self.assertEqual( json_response['message'], "Bot:{name} successfully added to database but could not start " "polling.".format(name=bot.username))
def test_cascade_delete_bot_and_msgs_by_uname_with_messages(self): bot = MyBot(token='dummy-token', username='******').save() self.assertIsNotNone(bot) Message.generate_fake(10) response = self.client.delete(url_for( 'botapi.delete_bot_and_message_by_uname', username=bot.username), headers=self.get_api_headers()) self.assertEqual(response.status_code, 200) json_response = json.loads(response.data.decode('utf-8')) self.assertEqual(json_response['status'], 'success') self.assertEqual( json_response['message'], 'Bot:{uname} and {msgs} logged messages ' 'removed'.format(uname=bot.username, msgs=10)) self.assertEqual(Message.objects.count(), 0) self.assertEqual(MyBot.objects.count(), 0)
def test_add_livebot_with_valid_token(self): status = procedures.add_bot(token=CONSTANTS.LIVE_BOTS.get(1)) # Get bot information from Telegram API. bot = Bot(token=CONSTANTS.LIVE_BOTS.get(1)).get_me() self.assertIsNotNone(status[0]) self.assertEqual(status[0], bot.username) self.assertTrue(status[1]) mybot = MyBot.objects(username=status[0]).first() self.assertIsNotNone(mybot) self.assertFalse(mybot.test_bot) self.assertEqual(mybot.first_name, bot.first_name) self.assertEqual(mybot.last_name, mybot.last_name) self.assertEqual(mybot.username, bot.username) # Otherwise unittests doesn't end. self.assertEqual(procedures.stop_bot(mybot.bot_id), 1)
def test_add_livebot_with_valid_token(self): response = self.client.post(url_for('botapi.add_bot', token=CONSTANTS.LIVE_BOTS.get(1), test=0), headers=self.get_api_headers()) json_response = json.loads(response.data.decode('utf-8')) self.assertEqual(response.status_code, 201) bot = MyBot.objects(token=CONSTANTS.LIVE_BOTS.get(1)).first() self.assertIsNotNone(bot) # Live bot is polling, stop it from polling. self.assertTrue(bot.state) self.assertEqual(procedures.stop_bot(botid=bot.bot_id), 1) self.assertEqual( json_response['message'], "Bot:{name} successfully added to database and started " "polling.".format(name=bot.username))
def start_all(): """ This function starts all bots in the database. :return started_bots: List of bot IDs for bots which successfully started polling. """ # Get all non-test (i.e. live) bots. bots = MyBot.objects(test_bot=False).all() started_bots = [] # Start all non test bots registered in the database. for bot in bots: try: if start_bot(botid=bot.bot_id) > 0: started_bots.append(bot.bot_id) except (ValueError, Exception): pass # Skip if some bot is not started. proc_logger.info('Successfully started polling for {count} bots out of ' '{total} live bots registered in the database.'.format( count=len(started_bots), total=len(bots))) return started_bots
class FilteringForm(FlaskForm): """ FlaskForm for setting up form for filtering logged messages. :parameter bot_field: Drop-down list containing all bots in the databases. :parameter time_field: Drop-down list for choosing time for filtering. :parameter time_int_field: Input field for getting time (in minutes) for filtering. :parameter text_field: Input field for entering text for filtering. :parameter username_field: Usernames of all users from which messages were recieved. :parameter name_field: (Partial) name for sender's firstname, lastname. """ bot_field = SelectField( 'Choose Bot', coerce=int, choices=[(0, 'Select an option')] + list(MyBot.objects().all().values_list('bot_id', 'username'))) time_field = SelectField('Time', coerce=int, choices=[(0, 'Choose'), (10, '10 minutes'), (30, '30 minutes'), (60, '60 minutes')]) time_int_field = IntegerField( 'Enter time (in Minutes)', validators=[ NumberRange(0, int(time.time()) / 60, message="Please enter valid time or 0.") ]) text_field = StringField('Text (contains)') username_field = SelectField( 'Sender username', coerce=str, choices=[('#', 'Select')] + list( Message.objects(sender_username__nin=['unknown', '']).values_list( 'sender_username', 'sender_username'))) fn_ln_field = StringField('First name/ Last name (contains)') submit = SubmitField('Filter')
def test_get_bot_info(self): base_address = 'http://127.0.0.1:5000/web/index' # Add a special bot and some expected messages. bot = MyBot(bot_id=123456, username='******', token='special-dummy-token', first_name='special', last_name='bot').save() for i in range(5): Message(bot_id=bot.bot_id, text_content='message' + str(i)).save() # navigate to home page self.client.get(base_address) # Navigate to filtering page self.client.find_element_by_link_text('Get-Bot-Info').click() self.assertTrue( re.search('Get Bot Information', self.client.page_source, re.IGNORECASE)) self.client.find_element_by_name('choose_bot').send_keys(bot.username) self.client.find_element_by_name('submit').click() # Redirected to bot information page. Make Assertions. self.assertTrue( re.search(bot.username, self.client.page_source, re.IGNORECASE)) self.assertTrue( re.search( '{fname}\s+{lname}'.format(fname=bot.first_name, lname=bot.last_name), self.client.page_source, re.IGNORECASE)) self.assertTrue( re.search('Token:\s+{token}'.format(token=bot.token), self.client.page_source, re.IGNORECASE)) msgs = Message.objects(bot_id=bot.bot_id).all() for msg in msgs: self.assertTrue(msg.text_content in self.client.page_source)
def test_edit_valid_bot(self): base_address = 'http://127.0.0.1:5000/web/index' # navigate to home page self.client.get(base_address) # Navigate to filering page self.client.find_element_by_link_text('Edit-Bot').click() self.assertTrue( re.search('Toggle\s+\(Enable/\s+Disable\)\s+Bot', self.client.page_source, re.IGNORECASE)) # add a test bot self.assertTrue(procedures.add_bot(token=CONSTANTS.LIVE_BOTS.get(1))) bot = MyBot.objects(token=CONSTANTS.LIVE_BOTS.get(1), test_bot=False).first() self.assertIsNotNone(bot) self.assertTrue(bot.state) # self.client.find_elements_by_name('status_field').send_keys('tomato') self.client.find_element_by_name('choose_bot').send_keys( bot.username.lower()) self.client.find_element_by_name('toggle').click() # check for success self.assertTrue('Bot:{uname} successfully stopped polling'.format( uname=bot.username) in self.client.page_source) self.assertTrue('Disabled' in self.client.page_source) # Enable the bot self.client.find_element_by_name('choose_bot').send_keys(bot.username) self.client.find_element_by_name('toggle').click() # check for success self.assertTrue('Bot:{uname} successfully started polling'.format( uname=bot.username) in self.client.page_source) self.assertTrue('Enabled' in self.client.page_source) # Force disable live bot from polling. self.assertEqual(procedures.stop_bot(botid=bot.bot_id), 1)
def tearDown(self): # Drop all collections MyBot.drop_collection() Message.drop_collection() self.app_context.pop()
def test_stop_bot_never_running_live_bot(self): bot = MyBot(token=CONSTANTS.LIVE_BOTS.get(1)).save() self.assertIsNotNone(bot) self.assertEqual(procedures.stop_bot(botid=bot.bot_id), -2)
def test_stop_bot_for_test_bot(self): bot = MyBot(token='dummy-token', test_bot=True).save() self.assertIsNotNone(bot) self.assertEqual(procedures.stop_bot(botid=bot.bot_id), -2)
def stop_bot(botid=None, username=None): """ This function stops a bot from polling for new message updates. :param botid: ID of the bot for which start polling request is made. :param username: Username of the bot for which start polling request is made. :return Integer: -1 = Bot with requested username/bot ID not found in DB. 1 = successfully stopped the bot for polling. 0 = Unable to stop the bot for polling. Internal Error. -2 = The requested bot never started polling in the first place. """ if username is None and botid is None: raise ValueError('No botid/username provided with stop bot request.') elif botid is not None and type(botid) is not int: raise ValueError('Integer value expected for stop in start bot ' 'request.') elif username is not None and type(username) is not str: raise ValueError('String value expected for username in stop bot ' 'request.') bot = MyBot.objects(bot_id=botid or 0).first() or \ MyBot.objects(username__iexact=username or '').first() if bot is None: proc_logger.error('No bot found with ID:{id} or Username:{uname} for ' 'starting the polling.'.format(id=botid, uname=username)) return -1 if bot.state: try: if bot.bot_id in running_bots.keys(): updater = running_bots.get(bot.bot_id) # Find bot from dict. updater.stop() # Stop bot bot.state = False # Update bot state to STOP. bot.save() proc_logger.info( 'Successfully stopped polling for live bot with id:{id} ' 'or username:{uname}'.format(id=botid, uname=username)) return 1 # Bot stopped successfully. else: updater = Updater(token=bot.token) # Get bot Updater dispatcher = updater.dispatcher start_handler = CommandHandler('start', start) # Add Handlers. dispatcher.add_handler(start_handler) log_handler = MessageHandler([Filters.text], log_message) dispatcher.add_handler(log_handler) updater.stop() # Start polling. running_bots[bot.bot_id] = updater # Add to dictionary. bot.state = False # Update bot state. bot.save() proc_logger.info( 'Successfully added and started polling for live bot ' 'with id:{id} or username:{uname}'.format(id=botid, uname=username)) return 1 except (KeyError, Exception): proc_logger.critical('Unable to start polling for bot registered ' 'with ID:{id} or username:{uname}.' ''.format(id=botid, uname=username)) return 0 # Unable to stop bot. proc_logger.error('Cannot start/stop polling for test-bot with ID:{id} ' 'or username:{uname}'.format(id=botid, uname=username)) return -2 # Bot not polling already.
def start_bot(botid=None, username=None): """ This function starts polling for a newly added bot. It gets an updater object for a valid (i.e. not test) bot and associated dispatcher. It adds handlers for responding to /start command and text messages to the dispatcher. :param botid: ID of the bot for which start polling request is made. :param username: Username of the bot for which start polling request is made. :return integer: -1 = Unable to find bot with given username/ID in the DB. -2 = The requested bot is a testbot, live polling is not available for a test bot. 1 = Successfully started polling for the requested bot. 0 = Internal error, unable to start polling for the requested bot. :except ValueError: If neither Bot ID nor Username is provided. """ if username is None and botid is None: raise ValueError('No botid/username provided with start bot request.') elif botid is not None and type(botid) is not int: raise ValueError('Integer value expected for botid in start bot ' 'request.') elif username is not None and type(username) is not str: raise ValueError('String value expected for username in start bot ' 'request.') # Find the requested Bot in database. bot = MyBot.objects(bot_id=botid or 0).first() or \ MyBot.objects(username__iexact=username or '').first() if bot is None: # Requested bot not found in DB. proc_logger.error('No bot found with ID:{id} or Username:{uname} for ' 'starting the polling.'.format(id=botid, uname=username)) return -1 if bot.test_bot: # Requested bot is testbot. proc_logger.error('Cannot start polling for test-bot with ID:{id} ' 'or username:{uname}'.format(id=botid, uname=username)) return -2 if bot.bot_id in running_bots.keys(): # Bot found and previously ran once. updater = running_bots.get(bot.bot_id) # Retrieve updater from dict. updater.start_polling() bot.state = True bot.save() proc_logger.info('Successfully started polling for live bot with id:' '{id} or username:{uname}'.format(id=botid, uname=username)) return 1 # Started running requested bot. try: updater = Updater(token=bot.token) # Get bot Updater dispatcher = updater.dispatcher start_handler = CommandHandler('start', start) # Add Handlers. dispatcher.add_handler(start_handler) log_handler = MessageHandler([Filters.text], log_message) dispatcher.add_handler(log_handler) updater.start_polling() # Start polling. running_bots[bot.bot_id] = updater # Add to dictionary. bot.state = True # Update bot state. bot.save() proc_logger.info('Successfully added and started polling for live bot ' 'with id:{id} or username:{uname}'.format( id=botid, uname=username)) return 1 except InvalidToken: proc_logger.error('Unable to start polling for bot registered with ID:' '{id} or username:{uname}.'.format(id=botid, uname=username)) raise ValueError('Bot:{uname} registered with bad token can not be ' 'started.'.format(uname=bot.username))
def test_generate_fake_message(self): MyBot.generate_fake(1) # Generate a fake bot to associate messages. Message.generate_fake(10) msgs = Message.objects.all() self.assertEqual(len(msgs), 10)
def test_live_bot_creation(self): MyBot(token=CONSTANTS.LIVE_BOTS.get(1)).save() bot = MyBot.objects(token=CONSTANTS.LIVE_BOTS.get(1)).first() self.assertIsNotNone(bot) self.assertFalse(bot.test_bot) self.assertFalse(bot.state)
def edit_bot(bot_choice=0): """ This function renders the page for Editing the bot. Editing the bot allows to enable/disable polling of the bot. :param bot_choice: Initial choice for selected bot. :return: .../editbot """ form = EditBot(choose_bot=bot_choice, toggle='Toggle (Enable/Disable)') # Populate the initial set of choices for Bot DropDownList. form.choose_bot.choices = [(0, 'Select')] + \ list(MyBot.objects().values_list( 'username', 'username')) if form.validate_on_submit(): # Get list of bots bot = MyBot.objects(username__iexact=form.choose_bot.data).first() if bot is None: # Redirect to same page because no option selected. flash('Please select an option and then press submit.') return render_template('edit_bot.html', form=form) if bot.test_bot: # Redirect to same page because testbot cannot be started. web_logger.info('Attempt to start polling for a test bot bot:' '{uname} via web api.'.format(uname=bot.username)) flash('Testbot Bot:{username} attempt to start polling ' 'failed.'.format(username=bot.username)) form.status_field.data = 'Cannot be enabled.' return render_template('edit_bot.html', form=form) if not bot.state: # Bot is not polling currently, start polling. status = procedures.start_bot(botid=bot.bot_id, username=str(bot.username)) if status == 1: web_logger.info('Bot:{uname} successfully started polling via ' 'web api.'.format(uname=bot.username)) flash('Bot:{username} successfully started polling.'.format( username=bot.username)) form.status_field.data = 'Enabled' elif status == 0: web_logger.info('Bot:{uname} could not start polling via ' 'web api.'.format(uname=bot.username)) flash('Failed to enable Bot:{username} for polling'.format( username=bot.username)) form.status_field.data = 'Failed to enable.' form.toggle = 'Enable' elif bot.state: # Bot is polling currently, stop polling. status = procedures.stop_bot(botid=bot.bot_id, username=str(bot.username)) if status == 1: web_logger.info('Bot:{uname} successfully stopped polling via ' 'web api.'.format(uname=bot.username)) flash('Bot:{username} successfully stopped polling.'.format( username=bot.username)) form.status_field.data = 'Disabled' elif status == 0: web_logger.info('Bot:{uname} could not stop polling via ' 'web api.'.format(uname=bot.username)) flash('Failed to disable Bot:{username} for polling'.format( username=bot.username)) form.status_field.data = 'Failed to disable.' return render_template('edit_bot.html', form=form) # Responding to get Request return render_template('edit_bot.html', form=form)