def init(*, bot: Bot, job_queue: JobQueue, callback: callable): _load_all() _configure_logging(bot) for chat in auto_spins: job = Job(callback, 86400.0, context=auto_spins[chat]) job_queue.put(job, next_t=time_diff(auto_spins[chat])) auto_spin_jobs.update({chat: job})
def initialize_participants(job_queue: JobQueue): user_map = DataSet() try: # Todo: auto-initalize function db = sqlite3.connect('survey/participants.db') cursor = db.cursor() cursor.execute("SELECT * FROM participants ORDER BY (ID)") participants = cursor.fetchall() # print(participants) for row in participants: user = Participant(row[1], init=False) user.conditions_ = pickle.loads(row[2]) user.data_set_ = pickle.loads(row[0]) user.timezone_ = row[3] user.country_ = row[4] user.gender_ = row[5] user.language_ = row[6] user.question_ = row[7] user.age_ = row[8] user.day_ = row[9] user.q_idle_ = row[10] user.active_ = row[11] user.block_ = row[12] user.pointer_ = row[13] user_map.participants[row[1]] = user if user.language_ != '': q_set = user_map.return_question_set_by_language( user.language_) user.q_set_ = q_set if user.country_ != '' and user.timezone_ != '' and user.gender_ != '': user.set_next_block() next_day = user.set_next_block() if next_day is None and user.active_ and user.pointer_ > -1: finished(user, job_queue) continue element = user.next_block[2] day_offset = next_day - user.day_ time_t = calc_block_time(element["time"]) due = calc_delta_t(time_t, day_offset, user.timezone_) debug('QUEUE', 'next block in ' + str(due) + ' seconds. User: ' + str(user.chat_id_), log=True) new_job = Job(queue_next, due, repeat=False, context=[user, job_queue]) job_queue.put(new_job) except sqlite3.Error as error: print(error) return user_map
def initialize_participants(job_queue: JobQueue): user_map = DataSet() try: # Todo: auto-initalize function db = sqlite3.connect('survey/participants.db') cursor = db.cursor() cursor.execute("SELECT * FROM participants ORDER BY (ID)") participants = cursor.fetchall() # print(participants) for row in participants: user = Participant(row[1], init=False) user.conditions_ = pickle.loads(row[2]) user.data_set_ = pickle.loads(row[0]) user.timezone_ = row[3] user.country_ = row[4] user.gender_ = row[5] user.language_ = row[6] user.question_ = row[7] user.age_ = row[8] user.day_ = row[9] user.q_idle_ = row[10] user.active_ = row[11] user.block_ = row[12] user.pointer_ = row[13] user_map.participants[row[1]] = user if user.language_ != '': q_set = user_map.return_question_set_by_language(user.language_) user.q_set_ = q_set if user.country_ != '' and user.timezone_ != '' and user.gender_ != '': user.set_next_block() next_day = user.set_next_block() if next_day is None and user.active_ and user.pointer_ > -1: finished(user, job_queue) continue element = user.next_block[2] day_offset = next_day - user.day_ time_t = calc_block_time(element["time"]) due = calc_delta_t(time_t, day_offset, user.timezone_) debug('QUEUE', 'next block in ' + str(due) + ' seconds. User: ' + str(user.chat_id_), log=True) new_job = Job(queue_next, due, repeat=False, context=[user, job_queue]) job_queue.put(new_job) except sqlite3.Error as error: print(error) return user_map
def do_login(bot: Bot, chat_id: str, sender: str, token: str, job_queue: JobQueue): from bot_app.model import Conversation global data try: # Notify this is going to take some time # In groups if data.change_account_queries[sender] != sender: bot.sendChatAction(chat_id=chat_id, action=ChatAction.TYPING) # In private chat bot.sendChatAction(chat_id=chat_id, action=ChatAction.TYPING) # Create Tinder session session = Session(token) if session.do_connect(): message = "Switching to %s's account." % session.get_profile_name() messages.send_custom_message( bot=bot, message=message, chat_id=data.change_account_queries[sender]) if sender != data.change_account_queries[sender]: # group_name = bot.getChat(chat_id=data.change_account_queries[sender]).title bot.sendMessage(chat_id=sender, text=message, reply_markup=keyboards.switch_group_keyboard()) # Create conversation conversation = Conversation(data.change_account_queries[sender], session, sender) data.conversations[ data.change_account_queries[sender]] = conversation del data.change_account_queries[sender] # Launch get matches background job cache_time = int( conversation.settings.get_setting("matches_cache_time")) job = Job(job_refresh_matches, cache_time + 1, repeat=True, context=conversation) job_queue.put(job, next_t=0.0) else: messages.send_error(bot=bot, chat_id=chat_id, name="auth_failed") except BaseException: messages.send_error(bot=bot, chat_id=chat_id, name="auth_failed")
def auto_spin_config(bot: Bot, update: Update, args: list, job_queue: JobQueue): msg = core.get_message(update) if len(args) == 0: return is_moder = core.can_change_spin_name(msg.chat_id, msg.from_user.id, bot) cmd = args.pop(0) if cmd == "set" and is_moder: try: time = args[0].split(':') time = "{:0>2}:{:0>2}".format(time[0], time[1]) job = Job(auto_spin, 86400.0, context=msg.chat_id) job_queue.put(job, next_t=core.time_diff(time)) if msg.chat_id in core.auto_spins: core.auto_spin_jobs[msg.chat_id].schedule_removal() except (ValueError, IndexError): msg.reply_text( f"Ошибка! Проверьте время на правильность и отредактируйте сообщение" ) return core.auto_spins.update({msg.chat_id: time}) core.auto_spin_jobs.update({msg.chat_id: job}) msg.reply_text( f"Автоматический розыгрыш установлен на {time} GMT+0\n\n" f"ВНИМАНИЕ! Если розыгрыш уже был проведён до того, как запустится автоматический розыгрыш, то" f" бот не напишет ничего в чат по наступлению времени розыгрыша") elif cmd == 'del' and is_moder: if msg.chat_id in core.auto_spins: core.auto_spin_jobs.pop(msg.chat_id).schedule_removal() core.auto_spins.pop(msg.chat_id) msg.reply_text( "Теперь автоматический розыгрыш отключен в этом чате") else: msg.reply_text( "Автоматический розыгрыш ещё не был включен в этом чате") elif cmd == 'status': if msg.chat_id in core.auto_spins: msg.reply_text(f"Автоматический розыгрыш установлен в этом чате" f" на {core.auto_spins.get(msg.chat_id)} GMT+0") else: msg.reply_text("Автоматический розыгрыш отключен в этом чате")
class JobQueueTest(BaseTest, unittest.TestCase): """ This object represents Tests for Updater, Dispatcher, WebhookServer and WebhookHandler """ def setUp(self): self.jq = JobQueue(MockBot('jobqueue_test')) self.jq.start() self.result = 0 def tearDown(self): if self.jq is not None: self.jq.stop() def job1(self, bot, job): self.result += 1 def job2(self, bot, job): raise Exception("Test Error") def job3(self, bot, job): self.result += 1 job.schedule_removal() def job4(self, bot, job): self.result += job.context def test_basic(self): self.jq.put(Job(self.job1, 0.1)) sleep(1.5) self.assertGreaterEqual(self.result, 10) def test_job_with_context(self): self.jq.put(Job(self.job4, 0.1, context=5)) sleep(1.5) self.assertGreaterEqual(self.result, 50) def test_noRepeat(self): self.jq.put(Job(self.job1, 0.1, repeat=False)) sleep(0.5) self.assertEqual(1, self.result) def test_nextT(self): self.jq.put(Job(self.job1, 0.1), next_t=0.5) sleep(0.45) self.assertEqual(0, self.result) sleep(0.1) self.assertEqual(1, self.result) def test_multiple(self): self.jq.put(Job(self.job1, 0.1, repeat=False)) self.jq.put(Job(self.job1, 0.2, repeat=False)) self.jq.put(Job(self.job1, 0.4)) sleep(1) self.assertEqual(4, self.result) def test_disabled(self): j0 = Job(self.job1, 0.1) j1 = Job(self.job1, 0.2) self.jq.put(j0) self.jq.put(Job(self.job1, 0.4)) self.jq.put(j1) j0.enabled = False j1.enabled = False sleep(1) self.assertEqual(2, self.result) def test_schedule_removal(self): j0 = Job(self.job1, 0.1) j1 = Job(self.job1, 0.2) self.jq.put(j0) self.jq.put(Job(self.job1, 0.4)) self.jq.put(j1) j0.schedule_removal() j1.schedule_removal() sleep(1) self.assertEqual(2, self.result) def test_schedule_removal_from_within(self): self.jq.put(Job(self.job1, 0.4)) self.jq.put(Job(self.job3, 0.2)) sleep(1) self.assertEqual(3, self.result) def test_longer_first(self): self.jq.put(Job(self.job1, 0.2, repeat=False)) self.jq.put(Job(self.job1, 0.1, repeat=False)) sleep(0.15) self.assertEqual(1, self.result) def test_error(self): self.jq.put(Job(self.job2, 0.1)) self.jq.put(Job(self.job1, 0.2)) sleep(0.5) self.assertEqual(2, self.result) def test_jobs_tuple(self): self.jq.stop() jobs = tuple(Job(self.job1, t) for t in range(5, 25)) for job in jobs: self.jq.put(job) self.assertTupleEqual(jobs, self.jq.jobs()) def test_inUpdater(self): u = Updater(bot="MockBot") u.job_queue.start() try: u.job_queue.put(Job(self.job1, 0.5)) sleep(0.75) self.assertEqual(1, self.result) u.stop() sleep(2) self.assertEqual(1, self.result) finally: u.stop()
class JobQueueTest(BaseTest, unittest.TestCase): """ This object represents Tests for Updater, Dispatcher, WebhookServer and WebhookHandler """ def setUp(self): self.jq = JobQueue(MockBot('jobqueue_test')) self.jq.start() self.result = 0 self.job_time = 0 def tearDown(self): if self.jq is not None: self.jq.stop() def getSeconds(self): return int(ceil(time.time())) def job1(self, bot, job): self.result += 1 def job2(self, bot, job): raise Exception("Test Error") def job3(self, bot, job): self.result += 1 job.schedule_removal() def job4(self, bot, job): self.result += job.context def job5(self, bot, job): self.job_time = self.getSeconds() def test_basic(self): self.jq.put(Job(self.job1, 0.1)) sleep(1.5) self.assertGreaterEqual(self.result, 10) def test_job_with_context(self): self.jq.put(Job(self.job4, 0.1, context=5)) sleep(1.5) self.assertGreaterEqual(self.result, 50) def test_noRepeat(self): self.jq.put(Job(self.job1, 0.1, repeat=False)) sleep(0.5) self.assertEqual(1, self.result) def test_nextT(self): self.jq.put(Job(self.job1, 0.1), next_t=0.5) sleep(0.45) self.assertEqual(0, self.result) sleep(0.1) self.assertEqual(1, self.result) def test_multiple(self): self.jq.put(Job(self.job1, 0.1, repeat=False)) self.jq.put(Job(self.job1, 0.2, repeat=False)) self.jq.put(Job(self.job1, 0.4)) sleep(1) self.assertEqual(4, self.result) def test_disabled(self): j0 = Job(self.job1, 0.1) j1 = Job(self.job1, 0.2) self.jq.put(j0) self.jq.put(Job(self.job1, 0.4)) self.jq.put(j1) j0.enabled = False j1.enabled = False sleep(1) self.assertEqual(2, self.result) def test_schedule_removal(self): j0 = Job(self.job1, 0.1) j1 = Job(self.job1, 0.2) self.jq.put(j0) self.jq.put(Job(self.job1, 0.4)) self.jq.put(j1) j0.schedule_removal() j1.schedule_removal() sleep(1) self.assertEqual(2, self.result) def test_schedule_removal_from_within(self): self.jq.put(Job(self.job1, 0.4)) self.jq.put(Job(self.job3, 0.2)) sleep(1) self.assertEqual(3, self.result) def test_longer_first(self): self.jq.put(Job(self.job1, 0.2, repeat=False)) self.jq.put(Job(self.job1, 0.1, repeat=False)) sleep(0.15) self.assertEqual(1, self.result) def test_error(self): self.jq.put(Job(self.job2, 0.1)) self.jq.put(Job(self.job1, 0.2)) sleep(0.5) self.assertEqual(2, self.result) def test_jobs_tuple(self): self.jq.stop() jobs = tuple(Job(self.job1, t) for t in range(5, 25)) for job in jobs: self.jq.put(job) self.assertTupleEqual(jobs, self.jq.jobs()) def test_inUpdater(self): u = Updater(bot="MockBot") u.job_queue.start() try: u.job_queue.put(Job(self.job1, 0.5)) sleep(0.75) self.assertEqual(1, self.result) u.stop() sleep(2) self.assertEqual(1, self.result) finally: u.stop() def test_time_unit_int(self): # Testing seconds in int seconds_interval = 5 expected_time = self.getSeconds() + seconds_interval self.jq.put(Job(self.job5, seconds_interval, repeat=False)) sleep(6) self.assertEqual(self.job_time, expected_time) def test_time_unit_dt_time(self): # Testing seconds, minutes and hours as datetime.timedelta object # This is sufficient to test that it actually works. interval = datetime.timedelta(seconds=5) expected_time = self.getSeconds() + interval.total_seconds() self.jq.put(Job(self.job5, interval, repeat=False)) sleep(6) self.assertEqual(self.job_time, expected_time)
class JobQueueTest(BaseTest, unittest.TestCase): """ This object represents Tests for Updater, Dispatcher, WebhookServer and WebhookHandler """ def setUp(self): self.jq = JobQueue("Bot", tick_interval=0.005) self.result = 0 def tearDown(self): if self.jq is not None: self.jq.stop() def job1(self, bot): self.result += 1 def job2(self, bot): raise Exception("Test Error") def test_basic(self): self.jq.put(self.job1, 0.1) sleep(1.5) self.assertGreaterEqual(self.result, 10) def test_noRepeat(self): self.jq.put(self.job1, 0.1, repeat=False) sleep(0.5) self.assertEqual(1, self.result) def test_nextT(self): self.jq.put(self.job1, 0.1, next_t=0.5) sleep(0.45) self.assertEqual(0, self.result) sleep(0.1) self.assertEqual(1, self.result) def test_multiple(self): self.jq.put(self.job1, 0.1, repeat=False) self.jq.put(self.job1, 0.2, repeat=False) self.jq.put(self.job1, 0.4) sleep(1) self.assertEqual(4, self.result) def test_error(self): self.jq.put(self.job2, 0.1) self.jq.put(self.job1, 0.2) self.jq.start() sleep(0.4) self.assertEqual(1, self.result) def test_inUpdater(self): u = Updater(bot="MockBot", job_queue_tick_interval=0.005) u.job_queue.put(self.job1, 0.5) sleep(0.75) self.assertEqual(1, self.result) u.stop() sleep(2) self.assertEqual(1, self.result)
def question_handler(bot: Bot, update: Update, user_map: DataSet, job_queue: JobQueue): try: # Get the user from the dict and its question_set (by language) user = user_map.participants[update.message.chat_id] # type: Participant # Case for very first question. if user.question_ == -1: user.set_active(True) user.set_language(update.message.text) user.set_block(0) q_set = user_map.return_question_set_by_language(user.language_) user.q_set_ = q_set current_day = q_set[0]["day"] user.set_day(current_day) user.set_block(0) elif user.q_idle_: q_set = user.q_set_ # Get the matching question for the users answer. pointer = user.pointer_ d_prev = q_set[pointer] b_prev = d_prev["blocks"][user.block_] q_prev = b_prev["questions"][user.question_] if not valid_answer(q_prev, update.message.text, user): user.set_q_idle(True) return # Storing the answer and moving on the next question store_answer(user, update.message.text, q_prev, job_queue) user.set_q_idle(False) else: # User has send something without being asked a question. return except KeyError as error: print(error) return if not user.active_: return message, question = find_next_question(user) if question is not None: message = question["text"] q_keyboard = get_keyboard(question["choice"], user) try: bot.send_message(chat_id=user.chat_id_, text=message, reply_markup=q_keyboard) debug(flag="MSG", text=str(user.chat_id_) + ": " + message + "\n") except TelegramError as error: if error.message == 'Unauthorized': user.pause() user.set_q_idle(True) elif user.auto_queue_ is False: user.block_complete_ = True next_day = user.set_next_block() if next_day is None: finished(user, job_queue) return element = user.next_block[2] day_offset = next_day - user.day_ time_t = calc_block_time(element["time"]) due = calc_delta_t(time_t, day_offset, user.timezone_) debug('QUEUE', 'next block in ' + str(due) + ' seconds. User: ' + str(user.chat_id_), log=True) new_job = Job(queue_next, due, repeat=False, context=[user, job_queue]) user.job_ = new_job job_queue.put(new_job)
class JobQueueTest(BaseTest, unittest.TestCase): """ This object represents Tests for Updater, Dispatcher, WebhookServer and WebhookHandler """ def setUp(self): self.jq = JobQueue(MockBot('jobqueue_test')) self.jq.start() self.result = 0 self.job_time = 0 def tearDown(self): if self.jq is not None: self.jq.stop() def job1(self, bot, job): self.result += 1 def job2(self, bot, job): raise Exception("Test Error") def job3(self, bot, job): self.result += 1 job.schedule_removal() def job4(self, bot, job): self.result += job.context def job5(self, bot, job): self.job_time = time.time() def test_basic(self): self.jq.put(Job(self.job1, 0.1)) sleep(1.5) self.assertGreaterEqual(self.result, 10) def test_job_with_context(self): self.jq.put(Job(self.job4, 0.1, context=5)) sleep(1.5) self.assertGreaterEqual(self.result, 50) def test_noRepeat(self): self.jq.put(Job(self.job1, 0.1, repeat=False)) sleep(0.5) self.assertEqual(1, self.result) def test_nextT(self): self.jq.put(Job(self.job1, 0.1), next_t=0.5) sleep(0.45) self.assertEqual(0, self.result) sleep(0.1) self.assertEqual(1, self.result) def test_multiple(self): self.jq.put(Job(self.job1, 0.1, repeat=False)) self.jq.put(Job(self.job1, 0.2, repeat=False)) self.jq.put(Job(self.job1, 0.4)) sleep(1) self.assertEqual(4, self.result) def test_disabled(self): j0 = Job(self.job1, 0.1) j1 = Job(self.job1, 0.2) self.jq.put(j0) self.jq.put(Job(self.job1, 0.4)) self.jq.put(j1) j0.enabled = False j1.enabled = False sleep(1) self.assertEqual(2, self.result) def test_schedule_removal(self): j0 = Job(self.job1, 0.1) j1 = Job(self.job1, 0.2) self.jq.put(j0) self.jq.put(Job(self.job1, 0.4)) self.jq.put(j1) j0.schedule_removal() j1.schedule_removal() sleep(1) self.assertEqual(2, self.result) def test_schedule_removal_from_within(self): self.jq.put(Job(self.job1, 0.4)) self.jq.put(Job(self.job3, 0.2)) sleep(1) self.assertEqual(3, self.result) def test_longer_first(self): self.jq.put(Job(self.job1, 0.2, repeat=False)) self.jq.put(Job(self.job1, 0.1, repeat=False)) sleep(0.15) self.assertEqual(1, self.result) def test_error(self): self.jq.put(Job(self.job2, 0.1)) self.jq.put(Job(self.job1, 0.2)) sleep(0.5) self.assertEqual(2, self.result) def test_jobs_tuple(self): self.jq.stop() jobs = tuple(Job(self.job1, t) for t in range(5, 25)) for job in jobs: self.jq.put(job) self.assertTupleEqual(jobs, self.jq.jobs()) def test_inUpdater(self): u = Updater(bot="MockBot") u.job_queue.start() try: u.job_queue.put(Job(self.job1, 0.5)) sleep(0.75) self.assertEqual(1, self.result) u.stop() sleep(2) self.assertEqual(1, self.result) finally: u.stop() def test_time_unit_int(self): # Testing seconds in int delta = 2 expected_time = time.time() + delta self.jq.put(Job(self.job5, delta, repeat=False)) sleep(2.5) self.assertAlmostEqual(self.job_time, expected_time, delta=0.1) def test_time_unit_dt_timedelta(self): # Testing seconds, minutes and hours as datetime.timedelta object # This is sufficient to test that it actually works. interval = datetime.timedelta(seconds=2) expected_time = time.time() + interval.total_seconds() self.jq.put(Job(self.job5, interval, repeat=False)) sleep(2.5) self.assertAlmostEqual(self.job_time, expected_time, delta=0.1) def test_time_unit_dt_datetime(self): # Testing running at a specific datetime delta = datetime.timedelta(seconds=2) next_t = datetime.datetime.now() + delta expected_time = time.time() + delta.total_seconds() self.jq.put(Job(self.job5, repeat=False), next_t=next_t) sleep(2.5) self.assertAlmostEqual(self.job_time, expected_time, delta=0.1) def test_time_unit_dt_time_today(self): # Testing running at a specific time today delta = 2 next_t = (datetime.datetime.now() + datetime.timedelta(seconds=delta)).time() expected_time = time.time() + delta self.jq.put(Job(self.job5, repeat=False), next_t=next_t) sleep(2.5) self.assertAlmostEqual(self.job_time, expected_time, delta=0.1) def test_time_unit_dt_time_tomorrow(self): # Testing running at a specific time that has passed today. Since we can't wait a day, we # test if the jobs next_t has been calculated correctly delta = -2 next_t = (datetime.datetime.now() + datetime.timedelta(seconds=delta)).time() expected_time = time.time() + delta + 60 * 60 * 24 self.jq.put(Job(self.job5, repeat=False), next_t=next_t) self.assertAlmostEqual(self.jq.queue.get(False)[0], expected_time, delta=0.1) def test_run_once(self): delta = 2 expected_time = time.time() + delta self.jq.run_once(self.job5, delta) sleep(2.5) self.assertAlmostEqual(self.job_time, expected_time, delta=0.1) def test_run_repeating(self): interval = 0.1 first = 1.5 self.jq.run_repeating(self.job1, interval, first=first) sleep(2.505) self.assertAlmostEqual(self.result, 10, delta=1) def test_run_daily(self): delta = 1 time_of_day = (datetime.datetime.now() + datetime.timedelta(seconds=delta)).time() expected_time = time.time() + 60 * 60 * 24 + delta self.jq.run_daily(self.job1, time_of_day) sleep(2 * delta) self.assertEqual(self.result, 1) self.assertAlmostEqual(self.jq.queue.get(False)[0], expected_time, delta=0.1)
class JobQueueTest(BaseTest, unittest.TestCase): """ This object represents Tests for Updater, Dispatcher, WebhookServer and WebhookHandler """ def setUp(self): self.jq = JobQueue("Bot", tick_interval=0.005) self.result = 0 def tearDown(self): if self.jq is not None: self.jq.stop() def job1(self, bot): self.result += 1 def job2(self, bot): raise Exception("Test Error") def test_basic(self): self.jq.put(self.job1, 0.1) sleep(1.5) self.assertGreaterEqual(self.result, 10) def test_noRepeat(self): self.jq.put(self.job1, 0.1, repeat=False) sleep(0.5) self.assertEqual(1, self.result) def test_nextT(self): self.jq.put(self.job1, 0.1, next_t=0.5) sleep(0.45) self.assertEqual(0, self.result) sleep(0.1) self.assertEqual(1, self.result) def test_multiple(self): self.jq.put(self.job1, 0.1, repeat=False) self.jq.put(self.job1, 0.2, repeat=False) self.jq.put(self.job1, 0.4) sleep(1) self.assertEqual(4, self.result) def test_error(self): self.jq.put(self.job2, 0.1) self.jq.put(self.job1, 0.2) self.jq.start() sleep(0.4) self.assertEqual(1, self.result) def test_inUpdater(self): u = Updater(bot="MockBot", job_queue_tick_interval=0.005) u.job_queue.put(self.job1, 0.5) sleep(0.75) self.assertEqual(1, self.result) u.stop() sleep(2) self.assertEqual(1, self.result)
class JobQueueTest(BaseTest, unittest.TestCase): """ This object represents Tests for Updater, Dispatcher, WebhookServer and WebhookHandler """ def setUp(self): self.jq = JobQueue("Bot") self.result = 0 def tearDown(self): if self.jq is not None: self.jq.stop() stop_con_pool() def job1(self, bot, job): self.result += 1 def job2(self, bot, job): raise Exception("Test Error") def job3(self, bot, job): self.result += 1 job.schedule_removal() def job4(self, bot, job): self.result += job.context def test_basic(self): self.jq.put(Job(self.job1, 0.1)) sleep(1.5) self.assertGreaterEqual(self.result, 10) def test_job_with_context(self): self.jq.put(Job(self.job4, 0.1, context=5)) sleep(1.5) self.assertGreaterEqual(self.result, 50) def test_noRepeat(self): self.jq.put(Job(self.job1, 0.1, repeat=False)) sleep(0.5) self.assertEqual(1, self.result) def test_nextT(self): self.jq.put(Job(self.job1, 0.1), next_t=0.5) sleep(0.45) self.assertEqual(0, self.result) sleep(0.1) self.assertEqual(1, self.result) def test_multiple(self): self.jq.put(Job(self.job1, 0.1, repeat=False)) self.jq.put(Job(self.job1, 0.2, repeat=False)) self.jq.put(Job(self.job1, 0.4)) sleep(1) self.assertEqual(4, self.result) def test_disabled(self): j0 = Job(self.job1, 0.1) j1 = Job(self.job1, 0.2) self.jq.put(j0) self.jq.put(Job(self.job1, 0.4)) self.jq.put(j1) j0.enabled = False j1.enabled = False sleep(1) self.assertEqual(2, self.result) def test_schedule_removal(self): j0 = Job(self.job1, 0.1) j1 = Job(self.job1, 0.2) self.jq.put(j0) self.jq.put(Job(self.job1, 0.4)) self.jq.put(j1) j0.schedule_removal() j1.schedule_removal() sleep(1) self.assertEqual(2, self.result) def test_schedule_removal_from_within(self): self.jq.put(Job(self.job1, 0.4)) self.jq.put(Job(self.job3, 0.2)) sleep(1) self.assertEqual(3, self.result) def test_longer_first(self): self.jq.put(Job(self.job1, 0.2, repeat=False)) self.jq.put(Job(self.job1, 0.1, repeat=False)) sleep(0.15) self.assertEqual(1, self.result) def test_error(self): self.jq.put(Job(self.job2, 0.1)) self.jq.put(Job(self.job1, 0.2)) self.jq.start() sleep(0.5) self.assertEqual(2, self.result) def test_jobs_tuple(self): self.jq.stop() jobs = tuple(Job(self.job1, t) for t in range(5, 25)) for job in jobs: self.jq.put(job) self.assertTupleEqual(jobs, self.jq.jobs()) def test_inUpdater(self): u = Updater(bot="MockBot") u.job_queue.put(Job(self.job1, 0.5)) sleep(0.75) self.assertEqual(1, self.result) u.stop() sleep(2) self.assertEqual(1, self.result)
class UserCommandHandler(PicBotRoutines): """docstring for UserCommandHandler""" def _command_method(func): """Decorator for functions that are invoked on commands. Ensures that the user is initialized.""" # @functools.wraps(func) def wrapper(self, bot, update, *args, **kwargs): # print("command method", func.__name__, ) # debug # print("self",self)# debug # print("command method", self, bot, update, args, kwargs, sep="||") # debug chat_id = update.message.chat_id log.info("Command method called!", func.__name__, "Chat_id: ", chat_id) # Initialize user, if not present in DB self.database_handler.initializeUser(chat_id=chat_id) log.debug("User initialized") lS = LanguageSupport(self.database_handler.getLang(chat_id)).languageSupport # noinspection PyCallingNonCallable func(self, bot, update, lS) log.debug("Function completed") return wrapper def __init__(self, bot, dispatcher, database_handler, token): self.dispatcher = dispatcher # queue for async jobs self.job_queue = JobQueue(bot) # Where to get pictures from: local filesystem(local) or Dropbox storage (DB) self.pic_source = sr["pic_source"] self.database_handler = database_handler super(UserCommandHandler, self).__init__(token, self.database_handler) self._addHandlers() if self.pic_source == "DB": self.DB_file_updater_thread = None # a thread that updates files self.dropbox_handler = DropboxHandler(self.database_handler) self._updateDBFiles() elif self.pic_source == "local": self.local_cleaner_job = None self._startLocalCleanerJob() self._initializeSubscriptionJobs() def _initializeSubscriptionJobs(self): for chat_id in self.database_handler.getAllSubscribedUserIDs(): log.debug("_initializeSubscriptionJobs chat_id", chat_id) self.createPeriodicSenderTask(chat_id) def _updateDBFiles(self, bot=None, job=None): if not self.DB_file_updater_thread or not self.DB_file_updater_thread.is_alive(): self.DB_file_updater_thread = self.dropbox_handler.updateFiles() job = Job(self._updateDBFiles, interval=sr['file_update_period'], repeat=False) else: log.warning("The Dropbox updater thread hasn't finished yet. Consider increasing FILE_UPDATE_PERIOD in settings!") job = Job(self._updateDBFiles, interval=10, repeat=False) # create periodic job self.job_queue.put(job) def _startLocalCleanerJob(self): """ Creates a delayed async job that cleans database every now and then if local files get deeleted :return: """ log.debug("_startLocalCleanerJob") self.local_cleaner_job = job = Job(self._localCleanerThread, interval=LOCAL_CLEANER_PERIOD, repeat=True) self.job_queue.put(job) def _localCleanerThread(self, bot, job): log.debug("_localCleanerThread") local_files = self.getLocalFiles() bd_files = set(self.database_handler.getFileList()) to_delete = bd_files.difference(local_files) log.debug("to_delete", to_delete) if to_delete: self.database_handler.batchDeleteFiles(to_delete) def _addHandlers(self): self.dispatcher.add_handler(CommandHandler('start', self.command_start)) self.dispatcher.add_handler(CommandHandler('help', self.command_help)) self.dispatcher.add_handler(CommandHandler('about', self.command_about)) self.dispatcher.add_handler(CommandHandler('otherbots', self.command_otherbots)) self.dispatcher.add_handler(CommandHandler('gimmepic', self.command_gimmepic)) self.dispatcher.add_handler(CommandHandler('subscribe', self.command_subscribe)) self.dispatcher.add_handler(CommandHandler('unsubscribe', self.command_unsubscribe)) self.dispatcher.add_handler(CommandHandler('spamuncached', self.command_spamuncached)) # non-command message self.dispatcher.add_handler(MessageHandler([Filters.text], self.messageMethod)) # unknown commands self.dispatcher.add_handler(MessageHandler([Filters.command], self.unknown_command)) self.dispatcher.add_error_handler(self.error_handler) log.info("Commands set!") def setPeriod(self, bot, update, lS=None): message = update.message.text chat_id = update.message.chat_id try: new_period = int(message) if not self.database_handler.getSubscribed(chat_id): self.sendMessageCommandMethod(bot, update, "You're not subscribed yet! /subscribe first!") else: # If a period is too small if new_period < MIN_PICTURE_SEND_PERIOD: self.database_handler.setPeriod(chat_id, MIN_PICTURE_SEND_PERIOD) self.sendMessageCommandMethod(bot, update, "The minimum possible period is {0}.\nSetting period to {0}.".format( str(MIN_PICTURE_SEND_PERIOD))) # If a period is too big elif new_period > MAX_PICTURE_SEND_PERIOD: self.database_handler.setPeriod(chat_id, MAX_PICTURE_SEND_PERIOD) self.sendMessageCommandMethod(bot, update, "The maximum possible period is {0}.\nSetting period to {0}.".format( str(MAX_PICTURE_SEND_PERIOD))) # If a period length is fine - accept else: self.database_handler.setPeriod(chat_id, new_period) self.sendMessageCommandMethod(bot, update, "Setting period to {0}.".format(new_period) ) # Reset timer self.database_handler.resetTimer(chat_id) self.restartPeriodicTask(chat_id) return True # user has sent a bullsh*t command except ValueError: return False def doGimmepic(self, chat_id): if self.pic_source == "local": self.sendLocalRandomPic(chat_id) elif self.pic_source == "DB": self.sendDropboxRandomPic(chat_id) def _periodicSender(self, bot, job): chat_id = job.context self.doGimmepic(chat_id) self.database_handler.resetTimer(chat_id) self.restartPeriodicTask(chat_id) def restartPeriodicTask(self, chat_id): self.removePeriodicSenderTask(chat_id) self.createPeriodicSenderTask(chat_id) def createPeriodicSenderTask(self, chat_id): time_left = self.database_handler.getSendTime(chat_id) - time() log.debug("Time left:", time_left) job = Job(self._periodicSender, time_left, context=chat_id) subscriptions_tasks[chat_id] = job self.job_queue.put(job) def removePeriodicSenderTask(self, chat_id): subscriptions_tasks[chat_id].schedule_removal() # remove task from job queue del subscriptions_tasks[chat_id] ########## # COMMAND METHODS ########## # GENERIC COMMANDS # noinspection PyArgumentList @_command_method def command_start(self, bot, update, lS=None): self.sendMessageCommandMethod(bot, update, lS(START_MESSAGE)) # noinspection PyArgumentList @_command_method def command_help(self, bot, update, lS=None): msg = lS(HELP_MESSAGE).format(sr['picture_send_period'],MIN_PICTURE_SEND_PERIOD, MAX_PICTURE_SEND_PERIOD) self.sendMessageCommandMethod(bot, update, msg) # noinspection PyArgumentList @_command_method def command_about(self, bot, update, lS=None): msg = lS(ABOUT_MESSAGE).format(".".join([str(i) for i in VERSION_NUMBER])) self.sendMessageCommandMethod(bot, update, msg, disable_web_page_preview=False) # noinspection PyArgumentList # @_command_method def command_otherbots(self, bot, update, lS=None): # a = 2/0 self.sendMessageCommandMethod(bot, update, OTHER_BOTS_MESSAGE) # noinspection PyArgumentList @_command_method def messageMethod(self, bot, update, lS=None): chat_id = update.message.chat_id message = update.message.text log.info("messageMethod. Chat_id:", chat_id, "Message:", message) if message in LanguageSupport.allVariants(HELP_BUTTON): self.command_help(bot, update, lS) elif message in LanguageSupport.allVariants(ABOUT_BUTTON): self.command_about(bot, update, lS) elif message in LanguageSupport.allVariants(OTHER_BOTS_BUTTON): self.command_otherbots(bot, update, lS) # elif message == EN_LANG_BUTTON: # self.command_set_lang_en(bot, update, lS) # elif message == RU_LANG_BUTTON: # self.command_set_lang_ru(bot, update, lS) elif message in LanguageSupport.allVariants(GIMMEPIC_BUTTON): self.command_gimmepic(bot, update, lS) elif message in LanguageSupport.allVariants(SUBSCRIBE_BUTTON): self.command_subscribe(bot, update, lS) elif message in LanguageSupport.allVariants(UNSUBSCRIBE_BUTTON): self.command_unsubscribe(bot, update, lS) elif message in LanguageSupport.allVariants(SHOW_PERIOD_BUTTON): self.command_show_period(bot, update, lS) else: if not self.setPeriod(bot, update, lS): self.unknown_command(bot, update, lS) # noinspection PyArgumentList @_command_method def unknown_command(self, bot, update, lS=None): self.sendMessageCommandMethod(bot, update, UNKNOWN_COMMAND_MESSAGE) def error_handler(self, bot, update, error): print(error) # PICBOT COMMANDS # noinspection PyArgumentList @_command_method def command_gimmepic(self, bot, update, lS=None): chat_id = update.message.chat_id self.doGimmepic(chat_id) # noinspection PyArgumentList @_command_method def command_subscribe(self, bot, update, lS=None): chat_id = update.message.chat_id period = self.database_handler.getPeriod(chat_id) if self.database_handler.getSubscribed(chat_id): self.sendMessageCommandMethod(bot, update, lS(ALREADY_SUBSCRIBED_MESSAGE).format(period)) else: self.database_handler.subscribeUser(chat_id) self.database_handler.resetTimer(chat_id) self.createPeriodicSenderTask(chat_id) self.sendMessageCommandMethod(bot, update, lS(SUBSCRIBED_MESSAGE).format(period)) # noinspection PyArgumentList @_command_method def command_unsubscribe(self, bot, update, lS=None): chat_id = update.message.chat_id if not self.database_handler.getSubscribed(chat_id): self.sendMessageCommandMethod(bot, update, lS(NOT_SUBSCRIBED_YET_MESSAGE)) else: self.database_handler.unsubscribeUser(chat_id) self.removePeriodicSenderTask(chat_id) self.sendMessageCommandMethod(bot, update, lS(UNSUBSCRIBED_MESSAGE)) # noinspection PyArgumentList @_command_method def command_show_period(self, bot, update, lS=None): chat_id = update.message.chat_id period = self.database_handler.getPeriod(chat_id) self.sendMessageCommandMethod(bot, update, """An image is sent to you every {0} seconds.""".format(period)) # noinspection PyArgumentList @_command_method def command_spamuncached(self, bot, update, lS=None): chat_id = update.message.chat_id self.sendUncachedImages(chat_id, self.pic_source)
class JobQueueTest(BaseTest, unittest.TestCase): """ This object represents Tests for Updater, Dispatcher, WebhookServer and WebhookHandler """ def setUp(self): self.jq = JobQueue(MockBot('jobqueue_test')) self.jq.start() self.result = 0 self.job_time = 0 def tearDown(self): if self.jq is not None: self.jq.stop() def job1(self, bot, job): self.result += 1 def job2(self, bot, job): raise Exception("Test Error") def job3(self, bot, job): self.result += 1 job.schedule_removal() def job4(self, bot, job): self.result += job.context def job5(self, bot, job): self.job_time = time.time() def test_basic(self): self.jq.put(Job(self.job1, 0.1)) sleep(1.5) self.assertGreaterEqual(self.result, 10) def test_job_with_context(self): self.jq.put(Job(self.job4, 0.1, context=5)) sleep(1.5) self.assertGreaterEqual(self.result, 50) def test_noRepeat(self): self.jq.put(Job(self.job1, 0.1, repeat=False)) sleep(0.5) self.assertEqual(1, self.result) def test_nextT(self): self.jq.put(Job(self.job1, 0.1), next_t=0.5) sleep(0.45) self.assertEqual(0, self.result) sleep(0.1) self.assertEqual(1, self.result) def test_multiple(self): self.jq.put(Job(self.job1, 0.1, repeat=False)) self.jq.put(Job(self.job1, 0.2, repeat=False)) self.jq.put(Job(self.job1, 0.4)) sleep(1) self.assertEqual(4, self.result) def test_disabled(self): j0 = Job(self.job1, 0.1) j1 = Job(self.job1, 0.2) self.jq.put(j0) self.jq.put(Job(self.job1, 0.4)) self.jq.put(j1) j0.enabled = False j1.enabled = False sleep(1) self.assertEqual(2, self.result) def test_schedule_removal(self): j0 = Job(self.job1, 0.1) j1 = Job(self.job1, 0.2) self.jq.put(j0) self.jq.put(Job(self.job1, 0.4)) self.jq.put(j1) j0.schedule_removal() j1.schedule_removal() sleep(1) self.assertEqual(2, self.result) def test_schedule_removal_from_within(self): self.jq.put(Job(self.job1, 0.4)) self.jq.put(Job(self.job3, 0.2)) sleep(1) self.assertEqual(3, self.result) def test_longer_first(self): self.jq.put(Job(self.job1, 0.2, repeat=False)) self.jq.put(Job(self.job1, 0.1, repeat=False)) sleep(0.15) self.assertEqual(1, self.result) def test_error(self): self.jq.put(Job(self.job2, 0.1)) self.jq.put(Job(self.job1, 0.2)) sleep(0.5) self.assertEqual(2, self.result) def test_jobs_tuple(self): self.jq.stop() jobs = tuple(Job(self.job1, t) for t in range(5, 25)) for job in jobs: self.jq.put(job) self.assertTupleEqual(jobs, self.jq.jobs()) def test_inUpdater(self): u = Updater(bot="MockBot") u.job_queue.start() try: u.job_queue.put(Job(self.job1, 0.5)) sleep(0.75) self.assertEqual(1, self.result) u.stop() sleep(2) self.assertEqual(1, self.result) finally: u.stop() def test_time_unit_int(self): # Testing seconds in int delta = 2 expected_time = time.time() + delta self.jq.put(Job(self.job5, delta, repeat=False)) sleep(2.5) self.assertAlmostEqual(self.job_time, expected_time, delta=0.1) def test_time_unit_dt_timedelta(self): # Testing seconds, minutes and hours as datetime.timedelta object # This is sufficient to test that it actually works. interval = datetime.timedelta(seconds=2) expected_time = time.time() + interval.total_seconds() self.jq.put(Job(self.job5, interval, repeat=False)) sleep(2.5) self.assertAlmostEqual(self.job_time, expected_time, delta=0.1) def test_time_unit_dt_datetime(self): # Testing running at a specific datetime delta = datetime.timedelta(seconds=2) next_t = datetime.datetime.now() + delta expected_time = time.time() + delta.total_seconds() self.jq.put(Job(self.job5, repeat=False), next_t=next_t) sleep(2.5) self.assertAlmostEqual(self.job_time, expected_time, delta=0.1) def test_time_unit_dt_time_today(self): # Testing running at a specific time today delta = 2 next_t = (datetime.datetime.now() + datetime.timedelta(seconds=delta)).time() expected_time = time.time() + delta self.jq.put(Job(self.job5, repeat=False), next_t=next_t) sleep(2.5) self.assertAlmostEqual(self.job_time, expected_time, delta=0.1) def test_time_unit_dt_time_tomorrow(self): # Testing running at a specific time that has passed today. Since we can't wait a day, we # test if the jobs next_t has been calculated correctly delta = -2 next_t = (datetime.datetime.now() + datetime.timedelta(seconds=delta)).time() expected_time = time.time() + delta + 60 * 60 * 24 self.jq.put(Job(self.job5, repeat=False), next_t=next_t) self.assertAlmostEqual(self.jq.queue.get(False)[0], expected_time, delta=0.1) def test_run_once(self): delta = 2 expected_time = time.time() + delta self.jq.run_once(self.job5, delta) sleep(2.5) self.assertAlmostEqual(self.job_time, expected_time, delta=0.1) def test_run_repeating(self): interval = 0.1 first = 1.5 self.jq.run_repeating(self.job1, interval, first=first) sleep(2.505) self.assertAlmostEqual(self.result, 10, delta=1) def test_run_daily(self): delta = 1 time_of_day = (datetime.datetime.now() + datetime.timedelta(seconds=delta)).time() expected_time = time.time() + 60 * 60 * 24 + delta self.jq.run_daily(self.job1, time_of_day) sleep(2 * delta) self.assertEqual(self.result, 1) self.assertAlmostEqual(self.jq.queue.get(False)[0], expected_time, delta=0.1)
class JobQueueTest(BaseTest, unittest.TestCase): """ This object represents Tests for Updater, Dispatcher, WebhookServer and WebhookHandler """ def setUp(self): self.jq = JobQueue(MockBot('jobqueue_test')) self.jq.start() self.result = 0 self.job_time = 0 def tearDown(self): if self.jq is not None: self.jq.stop() def getSeconds(self): return int(ceil(time.time())) def job1(self, bot, job): self.result += 1 def job2(self, bot, job): raise Exception("Test Error") def job3(self, bot, job): self.result += 1 job.schedule_removal() def job4(self, bot, job): self.result += job.context def job5(self, bot, job): self.job_time = self.getSeconds() def test_basic(self): self.jq.put(Job(self.job1, 0.1)) sleep(1.5) self.assertGreaterEqual(self.result, 10) def test_job_with_context(self): self.jq.put(Job(self.job4, 0.1, context=5)) sleep(1.5) self.assertGreaterEqual(self.result, 50) def test_noRepeat(self): self.jq.put(Job(self.job1, 0.1, repeat=False)) sleep(0.5) self.assertEqual(1, self.result) def test_nextT(self): self.jq.put(Job(self.job1, 0.1), next_t=0.5) sleep(0.45) self.assertEqual(0, self.result) sleep(0.1) self.assertEqual(1, self.result) def test_multiple(self): self.jq.put(Job(self.job1, 0.1, repeat=False)) self.jq.put(Job(self.job1, 0.2, repeat=False)) self.jq.put(Job(self.job1, 0.4)) sleep(1) self.assertEqual(4, self.result) def test_disabled(self): j0 = Job(self.job1, 0.1) j1 = Job(self.job1, 0.2) self.jq.put(j0) self.jq.put(Job(self.job1, 0.4)) self.jq.put(j1) j0.enabled = False j1.enabled = False sleep(1) self.assertEqual(2, self.result) def test_schedule_removal(self): j0 = Job(self.job1, 0.1) j1 = Job(self.job1, 0.2) self.jq.put(j0) self.jq.put(Job(self.job1, 0.4)) self.jq.put(j1) j0.schedule_removal() j1.schedule_removal() sleep(1) self.assertEqual(2, self.result) def test_schedule_removal_from_within(self): self.jq.put(Job(self.job1, 0.4)) self.jq.put(Job(self.job3, 0.2)) sleep(1) self.assertEqual(3, self.result) def test_longer_first(self): self.jq.put(Job(self.job1, 0.2, repeat=False)) self.jq.put(Job(self.job1, 0.1, repeat=False)) sleep(0.15) self.assertEqual(1, self.result) def test_error(self): self.jq.put(Job(self.job2, 0.1)) self.jq.put(Job(self.job1, 0.2)) sleep(0.5) self.assertEqual(2, self.result) def test_jobs_tuple(self): self.jq.stop() jobs = tuple(Job(self.job1, t) for t in range(5, 25)) for job in jobs: self.jq.put(job) self.assertTupleEqual(jobs, self.jq.jobs()) def test_inUpdater(self): u = Updater(bot="MockBot") u.job_queue.start() try: u.job_queue.put(Job(self.job1, 0.5)) sleep(0.75) self.assertEqual(1, self.result) u.stop() sleep(2) self.assertEqual(1, self.result) finally: u.stop() def test_time_unit_int(self): # Testing seconds in int seconds_interval = 5 expected_time = self.getSeconds() + seconds_interval self.jq.put(Job(self.job5, seconds_interval, repeat=False)) sleep(6) self.assertEqual(self.job_time, expected_time) def test_time_unit_dt_time(self): # Testing seconds, minutes and hours as datetime.timedelta object # This is sufficient to test that it actually works. interval = datetime.timedelta(seconds=5) expected_time = self.getSeconds() + interval.total_seconds() self.jq.put(Job(self.job5, interval, repeat=False)) sleep(6) self.assertEqual(self.job_time, expected_time)
def question_handler(bot: Bot, update: Update, user_map: DataSet, job_queue: JobQueue): try: # Get the user from the dict and its question_set (by language) user = user_map.participants[ update.message.chat_id] # type: Participant # Case for very first question. if user.question_ == -1: user.set_active(True) user.set_language(update.message.text) user.set_block(0) q_set = user_map.return_question_set_by_language(user.language_) user.q_set_ = q_set current_day = q_set[0]["day"] user.set_day(current_day) user.set_block(0) elif user.q_idle_: q_set = user.q_set_ # Get the matching question for the users answer. pointer = user.pointer_ d_prev = q_set[pointer] b_prev = d_prev["blocks"][user.block_] q_prev = b_prev["questions"][user.question_] if not valid_answer(q_prev, update.message.text, user): user.set_q_idle(True) return # Storing the answer and moving on the next question store_answer(user, update.message.text, q_prev, job_queue) user.set_q_idle(False) else: # User has send something without being asked a question. return except KeyError as error: print(error) return if not user.active_: return message, question = find_next_question(user) if question is not None: message = question["text"] q_keyboard = get_keyboard(question["choice"], user) try: bot.send_message(chat_id=user.chat_id_, text=message, reply_markup=q_keyboard) debug(flag="MSG", text=str(user.chat_id_) + ": " + message + "\n") except TelegramError as error: if error.message == 'Unauthorized': user.pause() user.set_q_idle(True) elif user.auto_queue_ is False: user.block_complete_ = True next_day = user.set_next_block() if next_day is None: finished(user, job_queue) return element = user.next_block[2] day_offset = next_day - user.day_ time_t = calc_block_time(element["time"]) due = calc_delta_t(time_t, day_offset, user.timezone_) debug('QUEUE', 'next block in ' + str(due) + ' seconds. User: ' + str(user.chat_id_), log=True) new_job = Job(queue_next, due, repeat=False, context=[user, job_queue]) user.job_ = new_job job_queue.put(new_job)