def intro_handler(bot: Bot, update: Update): #chat_id = update.message.chat_id #p, _ = Profile.objects.get_or_create( # external_id = chat_id, ### } #) intro = update.callback_query.data j = JobQueue() j.set_dispatcher(dispatcher) if intro == CALLBACK_BUTTON1_LEFT: chat_id = update.effective_message.chat_id text = "Прекрасно! Теперь я буду каждый день отправлять тебе упражнения. Береги глаза друг!" j.run_repeating(callback_alarm, 60 * 60 * 24, 60, context=chat_id) j.start() update.effective_message.reply_text( text=text, reply_markup=get_keyboard2(), ) return ConversationHandler.END elif intro == CALLBACK_BUTTON2_RIGHT: text = "Тогда ты можешь просто насладиться статьями, которые будут только улучшаться" update.callback_query.message.reply_text( text=text, reply_markup=get_keyboard2(), ) return ConversationHandler.END
def start_aoc_handlers(queue: JobQueue, bot: Bot): logger.info("registering aoc handlers") update_aoc_data(bot, queue) queue.run_repeating( lambda _: update_aoc_data(bot, queue), AOC_UPDATE_INTERVAL, name=JOB_AOC_UPDATE, )
def set_handlers(queue: JobQueue, bot: Bot): queue.run_daily(lambda _: daily_infection(get_group_chat_id(), bot), DAILY_INFECTION_TIME, name=JOB_QUEUE_DAILY_INFECTION_KEY) queue.run_repeating(lambda _: random_cough(bot, queue), REPEATING_COUGHING_INTERVAL, name=JOB_QUEUE_REPEATING_COUGHING_KEY)
def _run_scheduler(self, job_queue: JobQueue, schedulers: Iterable[SchedulerDTO]) -> None: for scheduler_dto in schedulers: job_queue.run_repeating( callback=scheduler_dto.callback, interval=scheduler_dto.interval, first=1, )
def add_job(job_queue: JobQueue, chat: Chat): for job in job_queue.jobs(): if job.context.id == chat.id: job.enabled = False job.schedule_removal() job_queue.run_repeating(send_issue, int(JIRA_REQUESTS_SECONDS_PERIOD), context=chat)
def main(): mongoengine.connect(db=config.database.db, host=config.database.host, port=config.database.port, username=config.database.user, password=config.database.password) start_handler = CommandHandler('start', commands) dispatcher.add_handler(start_handler) help_handler = CommandHandler('help', commands) dispatcher.add_handler(help_handler) register_handler = CommandHandler('register', register) dispatcher.add_handler(register_handler) info_handler = CommandHandler('info', info) dispatcher.add_handler(info_handler) balance_handler = CommandHandler('balance', balance) dispatcher.add_handler(balance_handler) balance_prefix_handler = PrefixHandler(COMMAND_PREFIX, 'balance', balance) dispatcher.add_handler(balance_prefix_handler) withdraw_handler = CommandHandler('withdraw', withdraw) dispatcher.add_handler(withdraw_handler) transfer_handler = CommandHandler('transfer', transfer) dispatcher.add_handler(transfer_handler) transfer_prefix_handler = PrefixHandler(COMMAND_PREFIX, 'transfer', transfer) dispatcher.add_handler(transfer_prefix_handler) tip_handler = CommandHandler('tip', tip) dispatcher.add_handler(tip_handler) tip_prefix_handler = PrefixHandler(COMMAND_PREFIX, 'tip', tip) dispatcher.add_handler(tip_prefix_handler) outputs_handler = CommandHandler('outputs', outputs) dispatcher.add_handler(outputs_handler) optimize_handler = CommandHandler('optimize', optimize) dispatcher.add_handler(optimize_handler) dispatcher.add_error_handler(handle_errors) jobqueue = JobQueue() jobqueue.set_dispatcher(dispatcher) jobqueue.run_repeating(update_balance_wallets, config.wallet_balance_update_interval) jobqueue.start() updater.start_polling()
def test_job_run(self, _dp, use_context): _dp.use_context = use_context job_queue = JobQueue() job_queue.set_dispatcher(_dp) if use_context: job = job_queue.run_repeating(self.job_context_based_callback, 0.02, context=2) else: job = job_queue.run_repeating(self.job_run_once, 0.02, context=2) assert self.result == 0 job.run(_dp) assert self.result == 1
def main(): updater = Updater(token=FreeOnEpic.bot_token, use_context=True) dp = updater.dispatcher job_queue = JobQueue() job_queue.set_dispatcher(dp) job_queue.run_repeating(callback=FreeOnEpic.get_links, interval=600) logger.info('The bot has started') dp.add_handler(CommandHandler('freegame', FreeOnEpic.free_game)) dp.add_handler(CommandHandler("help", FreeOnEpic.help_command)) job_queue.start() updater.start_polling() updater.idle()
def main(): """Start the bot.""" # Create the Updater and pass it your bot's token. # Make sure to set use_context=True to use the new context based callbacks # Post version 12 this will no longer be necessary updater = Updater(config.bottoken, use_context=True) # Get the dispatcher to register handlers dp = updater.dispatcher # on different commands - answer in Telegram # dp.add_handler(CommandHandler("start", start)) dp.add_handler(CommandHandler("hilfe", help)) dp.add_handler(CommandHandler("status", status)) dp.add_handler(CommandHandler("forceupdate", force_update)) # Add conversation handler with the states ASKFORLK, UNIQUELK, MULTIPLELK conv_handler = ConversationHandler( entry_points=[ CommandHandler('start', start), CommandHandler('neuerlk', newlk), CommandHandler('entfernelk', removelk) ], states={ ASKFORLK: [MessageHandler(Filters.text, ask_for_landkreis)], CHOOSELK: [MessageHandler(Filters.text, choose_landkreis)], REMOVELK: [MessageHandler(Filters.text, remove_landkreis)] }, fallbacks=[CommandHandler('cancel', cancel)]) dp.add_handler(conv_handler) # Error handler dp.add_error_handler(error) # Read the existing data casesdata.load_data() # Start the Bot updater.start_polling() # Check for updates of rki numbers and notify users every hour (3600s). cronjob = JobQueue() cronjob.set_dispatcher(dp) cronjob.run_repeating(process_case_updates, 3600) cronjob.start() # Run the bot until you press Ctrl-C or the process receives SIGINT, # SIGTERM or SIGABRT. This should be used most of the time, since # start_polling() is non-blocking and will stop the bot gracefully. updater.idle()
def scrape_begin_city(bot: Bot, update: Update, job_queue: JobQueue, chat_data, city=None): if not city: city = update.message.text[19:].lower( ) # 19 characters is len('/scrape_begin_city ') if city in URLS.keys(): jobs_for_same_city = [ job for job in job_queue.jobs() if job.context == city ] if jobs_for_same_city: update.message.reply_text( 'wg_ges scraper job was already set! /scrape_stop_city {} to kill it' .format(city)) else: job = job_queue.run_repeating(callback=job_scrape_city, interval=75, first=10, context=city) chat_data[city] = job logging.info('start scraping {}'.format(city)) update.message.reply_text( 'wg_ges scraper job successfully set! /subscribe {} to test, /unsubscribe to stop, /scrape_stop_city ' '{} to stop it.'.format(city, city)) else: update.message.reply_text('valid cities: {}'.format(all_cities_string))
def main(): with open(os.path.join(dir_path, 'config.json')) as config_file: config = json.loads(config_file.read())['main'] logger = logging.getLogger(__name__) logger.setLevel(logging.INFO) fh = logging.FileHandler(os.path.join(dir_path, config["log_filename"])) fh.setFormatter(logging.Formatter('%(asctime)s %(levelname)s:%(message)s')) logger.addHandler(fh) api = OxfordApi(config['api'], logger) bot_words_learner = BotWordsLearner(dir_path, get_bot_token(config["token_path"]), logger, config["bot_words_learner"], api) bot_words_learner.load_from_disk() job_queue = JobQueue(Bot(get_bot_token(config["token_path"]))) job_queue.run_repeating( run_and_log(bot_words_learner.save_to_disk, logger), 60 * 60) job_queue.start() updater = Updater(token=bot_words_learner.token) dispatcher = updater.dispatcher dispatcher.add_handler(CommandHandler('start', bot_words_learner.start)) dispatcher.add_handler(CommandHandler('help', bot_words_learner.help)) dispatcher.add_handler(CommandHandler('stat', bot_words_learner.stat)) dispatcher.add_handler(MessageHandler(Filters.text, bot_words_learner.talk)) dispatcher.add_handler( MessageHandler(Filters.document, bot_words_learner.document_load)) dispatcher.add_handler( CommandHandler('keyboard', bot_words_learner.keyboard)) dispatcher.add_error_handler(bot_words_learner.error) updater.start_polling() updater.idle() logger.critical('Finish session\n') bot_words_learner.save_to_disk() api.cash.save() job_queue.stop()
def __init__(self, logger): self.logger = logger self.settings = default_settings self.token = os.getenv('tbot_api') self.spc_url = os.getenv('spc_url') self.spc_wallet = os.getenv('spc_wallet') self.admin_id = int(os.getenv('spc_admin_id', None)) self._create_tables() self.delays = {} self.latest_dices = {} self.roll_messages = [] self.secret_key, self.public_key = self._get_keys(self.spc_wallet) self.bot = Bot(self.token) self.updater = Updater(self.token, use_context=True) msg_filter = Filters.text \ & (~Filters.forwarded) \ & (~Filters.update.edited_message) dice_filter = Filters.dice \ & (~Filters.forwarded) \ & (~Filters.update.edited_message) \ & Filters.group msg_handler = MessageHandler(filters=msg_filter, callback=self.message_callback) dice_handler = MessageHandler(filters=dice_filter, callback=self.dice_callback) self.updater.dispatcher.add_handler(msg_handler) self.updater.dispatcher.add_handler(dice_handler) jobs = JobQueue() jobs.set_dispatcher(self.updater.dispatcher) jobs.run_repeating(callback=self.job_callback, interval=10) jobs.run_repeating(callback=self.message_job_callback, interval=1) jobs.start() self.updater.start_polling() self.updater.idle()
def subscribe_city_cmd(bot: Bot, update: Update, job_queue: JobQueue, chat_data, city=None): if not city: city = update.message.text[11:].lower() if city in all_cities: chat_id = update.message.chat_id if chat_id in subscribers and subscribers[chat_id].is_subscribed(city): update.message.reply_text( 'Dein Abo für {} lief schon. /unsubscribe für Stille im Postfach.' .format(city)) else: context = {'chat_id': chat_id, 'city': city} job = job_queue.run_repeating(callback=job_notify_subscriber, interval=15, first=1, context=context) try: try: old_jobs = chat_data['jobs'] if old_jobs is None: old_jobs = [] except KeyError: old_jobs = [] old_jobs.append(job) chat_data['jobs'] = old_jobs except Unauthorized: logging.warning('unauthorized in job notify. removing job') job.schedule_removal() return if chat_id not in subscribers: subscribers[chat_id] = Subscriber(chat_id) subscribers[chat_id].subscribe(city) logging.info('{} subbed {}'.format(chat_id, city)) update.message.reply_text( 'Erfolgreich {} abboniert, du liegst jetzt auf der Lauer. Nützliche Filter Beispiele:\n' '"/filter_rent 500" - nur Anzeigen bis 500€\n' '"/filter_sex m" - keine Anzeigen die nur Frauen suchen\n' '"/filter_from 16.03.2018" - keine Anzeigen die erst später frei werden. Datumsformat muss stimmen.\n' '"/filter_to 17.03.2018" - keine Anzeigen die nur kürzer frei sind. Datumsformat muss stimmen.\n' '"/unsubscribe" - Stille'.format(city)) else: if city == '': update.message.reply_text( 'Bitte gib an in welcher Stadt du deine WG suchen möchtest.' 'Verfügbare Städte: {} ' 'Beispiel: /subscribe MUC'.format(city, all_cities_string)) else: update.message.reply_text( 'In {} gibt\'s mich nicht, sorry. Verfügbare Städte: {}'. format(city, all_cities_string))
def main(): """Main methode, starts all jobs""" # Start DX Cluster in background cluster.clustersearch() # Create the EventHandler and pass it your bot's token. updater = Updater(TOKEN) jobquere = JobQueue(Bot(TOKEN)) # Register Cluster job jobquere.run_repeating(realcluster, 15, 0) jobquere.start() # Get the dispatcher to register handlers dp = updater.dispatcher # on different commands - answer in Telegram dp.add_handler(CallbackQueryHandler(button)) dp.add_handler(CommandHandler("start", start)) dp.add_handler(CommandHandler("help", help)) dp.add_handler(CommandHandler("menu", menu)) # Call Commands dp.add_handler(CommandHandler("add", addcall)) dp.add_handler(CommandHandler("rm", deletecall)) dp.add_handler(CommandHandler("list", listcalls)) # DXCC Commands dp.add_handler(CommandHandler("adddx", adddxcc)) dp.add_handler(CommandHandler("listdx", listdxcc)) # log all errors dp.add_error_handler(error) # Start the Bot updater.start_polling() # Run the bot until you press Ctrl-C or the process receives SIGINT, # SIGTERM or SIGABRT. This should be used most of the time, since # start_polling() is non-blocking and will stop the bot gracefully. updater.idle() cluster.clustersearch()
def bot_command(self): """ creating the bot instructions """ updater = Updater(self._token, use_context=True) dp = updater.dispatcher job_queue = JobQueue() job_queue.set_dispatcher(dp) # repeats the command on repeat job_queue.run_repeating(self.bot_audio_repeat, interval=self.interval * 60) # repeated intervals # creates the handle for the command dp.add_handler( CommandHandler(self.command_name, self.bot_audio_on_command)) # command updater.start_polling() job_queue.start() updater.idle()
def handle(self, *args, **options): request = Request(connect_timeout=5, read_timeout=5, con_pool_size=8) bot = Bot(request=request, token=config.bot_token) print(bot.get_me()) job_queue = JobQueue() updater = Updater(bot=bot, use_context=True) job_queue.set_dispatcher(updater.dispatcher) job_queue.run_repeating(upload_hot_video, 30, name="hot") job_queue.run_repeating(setup_schedule, 30, name="schedule_setup") job_queue.start() message_handler = MessageHandler(Filters.text, do_echo) updater.dispatcher.add_handler(CommandHandler("help", help_command)) updater.dispatcher.add_handler(CommandHandler("send", send_post)) updater.dispatcher.add_handler(CommandHandler("set", job_maker)) updater.dispatcher.add_handler(CommandHandler("unset", unset)) updater.dispatcher.add_handler(message_handler) updater.start_polling() updater.idle()
def connect(bot: Bot, update: Updater, user_data: dict, job_queue: JobQueue): """ Tries to open a SSH connection from the bot server to the bridge computer. After that, sends a message to the chat with the result of the connection (successed or failed) and returns to the main menu. Args: bot (:obj:`telegram.bot.Bot`): The telegram bot instance. update (:obj:`telegram.ext.update.Updater`): The Updater associated to the bot. user_data (:obj:`dict`): The dictionary with user variables. """ session = Session.get_from(user_data) # Try to connect to the client session.start_connection() # Send the status message view.connect_output(session).reply(update) if session.connected: # Check if the bridge computer has all the required dependencies initialize_bridge(bot, update, user_data) # Check the status of each computers (which are alive or unreachable) update_computers_status(user_data) job_queue.run_repeating( job_update_computers_status, interval=states.config_file.check_status_interval, context=user_data, ) # Show the main menu again menu.new_main(bot, update, user_data)
def schedule(self, job_queue: JobQueue, callback: Callable) -> Job: """Schedule this event job in the provided job_queue""" upcoming_date = helper.get_upcoming_date(date.today(), self.day_to_schedule) return job_queue.run_repeating( callback, interval=timedelta(weeks=1), first=datetime( upcoming_date.year, upcoming_date.month, upcoming_date.day, 20, 0, 0, ), context=self.chat_id, name=self.job_name, )
def subscribe_city_cmd(bot: Bot, update: Update, job_queue: JobQueue, chat_data, city=None): if not city: city = update.message.text[11:].lower() if city in all_cities: chat_id = update.message.chat_id if chat_id in subscribers and subscribers[chat_id].is_subscribed(city): update.message.reply_text('Das Abo lief schon. /unsubscribe für Stille im Postfach oder um die Stadt zu ' 'wechseln.') else: context = {'chat_id': chat_id, 'city': city} job = job_queue.run_repeating(callback=job_notify_subscriber, interval=15, first=1, context=context) try: chat_data['job'] = job except Unauthorized: logging.warning('unauthorized in job notify. removing job') job.schedule_removal() return if not chat_id in subscribers: subscribers[chat_id] = Subscriber(chat_id) subscriber = subscribers[chat_id] subscriber.subscribe(city) logging.info('{} subbed {}'.format(chat_id, city)) update.message.reply_text( 'Erfolgreich {} abboniert, jetzt heißt es warten auf die neue Bude.\n' 'Zieh die Mietpreisbremse in deinem Kopf und erhalte keine Anzeigen mehr, die du dir eh nicht ' 'leisten kannst mit /filter_rent. Bsp: "/filter_rent 500" für Anzeigen bis 500€.\n' 'Mit /filter_sex kannst du Angebote herausfiltern, die nicht für dein Geschlecht sind. Bsp: ' '"/filter_sex m" oder eben w.\n' 'Beende Benachrichtigungen mit /unsubscribe. Über Feedback oder Fehler an [email protected] würde ich ' 'mich freuen'.format(city) ) else: if city == '': update.message.reply_text('Bitte gib an in welcher Stadt du deine WG suchen möchtest.' 'Verfügbare Städte: {} ' 'Beispiel: /subscribe MUC'.format(city, all_cities_string)) else: update.message.reply_text( 'In {} gibt\'s mich nicht, sorry. Verfügbare Städte: {}'.format(city, all_cities_string))
def set_job(job_queue: JobQueue): return job_queue.run_repeating(RepeatedHelloJob.__every_minute, JOB_INTERVAL, JOB_FIRST, context=CLEANING_GROUP_ID)
InlineKeyboardMarkup, InlineKeyboardButton, InputMediaPhoto) from update_stats import update_pages import logging, os, db with open('secret.token', 'r') as f: TOKEN = f.read().split()[1] logging.basicConfig(filename='log.log', level=logging.INFO) updater = Updater(token=TOKEN, use_context=True) dispatcher = updater.dispatcher jobQ = JobQueue() jobQ.set_dispatcher(dispatcher) jobQ.run_repeating(update_pages, interval=1800, first=1) jobQ.start() dbase = db.DB('db.db') def start(update, context): num_of_images = len(os.listdir('./pages')) keyboard = [[ InlineKeyboardButton('⬅', callback_data="p 0"), InlineKeyboardButton('🔄', callback_data="p 1"), InlineKeyboardButton('➡', callback_data="p 2") ], [ InlineKeyboardButton('⏮', callback_data="p 1"),
def _start(self, jobs: List[telegram.ext.Job], job_queue: JobQueue, chat_id) -> None: new_job = job_queue.run_repeating( self.callback, self.repeat_time, context=chat_id, first=self.first_time) new_job.name = self.job_name jobs.append(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)
def jq_add_festive_stats(jq: JobQueue): jq.run_repeating(stat_unprocessed, interval=STAT_UNPROCESSED_INTERVAL, first=1)
def create_jobs(job_classes: List[BaseJob], jq: JobQueue): for job in job_classes: jq.run_repeating(job.run, interval=job.get_interval(), first=job.get_delay())
if abs(diff_percent) > 0.5: news_params = { "apiKey": NEWS_API_KEY, # https://newsapi.org "qInTitle": COMPANY_NAME, } news_response = requests.get(NEWS_ENDPOINT, params=news_params) articles = news_response.json()["articles"] print(articles) three_articles = articles[:3] print(three_articles) formatted_articles = [ f"{STOCK}: {up_down}{diff_percent}% " \ f"\nHeadline: {article['title']}. \nBrief: {article['description']}" for article in three_articles ] for article in formatted_articles: context.bot.send_message(chat_id=CHAT_ID, text=article) updater = Updater(BOT_TOKEN, persistence=PicklePersistence(filename='bot_data')) job_queue = JobQueue() job_queue.set_dispatcher(updater.dispatcher) job_queue.run_repeating(callback=send_notify, interval=60) updater.start_polling() job_queue.start() updater.idle()
class Bot: def __init__(self, logger, postgres): self._status = {} self._logger = logger self._postgres = postgres # self._updater = Updater(token=BOT_TOKEN, use_context=True) self._bot = TelegramBot(token=BOT_TOKEN) self._job_queue = JobQueue() self._update_queue = Queue() self._dispatcher = Dispatcher(self._bot, self._update_queue, use_context=True) self._translator = Translator(file=TRANSLATION_FILE) self._set_commands() self._load_status() self._set_job_queue() # ------------------------------------------------------------------------------------------ # INIT METHODS # ------------------------------------------------------------------------------------------ def _set_commands(self): self._dispatcher.add_handler(CommandHandler(START, self._start)) self._dispatcher.add_handler(CommandHandler(ADD, self._add)) self._dispatcher.add_handler(CommandHandler(FRIENDS, self._friends)) self._dispatcher.add_handler(CommandHandler(LANGUAGE, self._language)) self._dispatcher.add_handler(CommandHandler(HELP, self._help)) self._dispatcher.add_handler(CallbackQueryHandler(self._callback_query)) self._dispatcher.add_handler(MessageHandler(Filters.all, self._other_messages)) # self._updater.dispatcher.add_handler(CommandHandler(START, self._start)) # self._updater.dispatcher.add_handler(CommandHandler(ADD, self._add)) # self._updater.dispatcher.add_handler(CommandHandler(FRIENDS, self._friends)) # self._updater.dispatcher.add_handler(CommandHandler(LANGUAGE, self._language)) # self._updater.dispatcher.add_handler(CommandHandler(HELP, self._help)) # self._updater.dispatcher.add_handler(CallbackQueryHandler(self._callback_query)) # self._updater.dispatcher.add_handler(MessageHandler(Filters.all, self._other_messages)) def _load_status(self): command = self._postgres.commands().select_account() records = self._postgres.execute(command) if self._correct_postgres_answer(records): for record in records: self._status[record[0]] = json.loads(record[5]) def _set_job_queue(self): self._job_queue.set_dispatcher(self._dispatcher) now = datetime.utcnow() to = now + timedelta(seconds=24 * 60 * 60) to = to.replace(hour=0, minute=0, second=30, microsecond=0) self._job_queue.run_repeating( self._it_is_time_for_birthday, interval=24 * 60 * 60, first=to.timestamp() - now.timestamp() ) self._job_queue.start() # ------------------------------------------------------------------------------------------ # PUBLIC METHODS # ------------------------------------------------------------------------------------------ def start_pooling(self): # self._updater.start_polling() # self._updater.idle() self._bot.setWebhook(HEROKU_APP_URL + BOT_TOKEN) def get_dispatcher(self): # pass return self._dispatcher def get_update_queue(self): # pass return self._update_queue def get_bot(self): # pass return self._bot # ------------------------------------------------------------------------------------------ # COMMANDS # ------------------------------------------------------------------------------------------ def _start(self, update, context): account_id = update.effective_user[ACCOUNT_ID] language = self._status[account_id][LANGUAGE] if self._status.get(account_id, None) else STANDARD_LANGUAGE translate = self._translator.translate if account_id in self._status.keys(): self._status[account_id][STATUS] = NONE context.bot.send_message( chat_id=update.effective_message.chat_id, text=translate("Я рад снова тебя приветствовать здесь!", language) ) else: self._status[account_id] = { LANGUAGE: STANDARD_LANGUAGE, STATUS: NONE, BIRTHDAY: {} } command = self._postgres.commands().insert_account( account_id=account_id, first_name=update.effective_user[FIRST_NAME], last_name=update.effective_user[LAST_NAME], user_name=update.effective_user[USERNAME], language_code=STANDARD_LANGUAGE, status=json.dumps(self._status[account_id]) ) self._postgres.execute(command) context.bot.send_message( chat_id=update.effective_message.chat_id, text=translate("Я рад тебя приветствовать у меня в гостях. У меня уютно и есть печеньки!", language) ) context.bot.send_message( chat_id=update.effective_message.chat_id, text=translate("Чтобы вы лучше понимали что я могу, воспользуйтесь командой /help. Если у вас есть желание сменить язык общения, то команда /language поможет вам это сделать!", language) ) self._update_status(account_id) def _add(self, update, context): account_id = update.effective_user[ACCOUNT_ID] language = self._status[account_id][LANGUAGE] translate = self._translator.translate self._status[account_id][STATUS] = ADD_CONTACT self._status[account_id][BIRTHDAY] = { FIO: { LAST_NAME: NONE, FIRST_NAME: NONE, MIDDLE_NAME: NONE }, DATE: { YEAR: NONE, MONTH: NONE, DAY: NONE }, CONGRATULATION: NONE, DESIRES: NONE, PHONE_NUMBER: NONE, TELEGRAM_USER_ID: NONE } context.bot.send_message( chat_id=update.effective_message.chat_id, text=translate("Давайте начнем заполнение анкеты вашего друга. Сперва пришлите контакт друга", language) ) self._update_status(account_id) def _friends(self, update, context): account_id = update.effective_user[ACCOUNT_ID] language = self._status[account_id][LANGUAGE] translate = self._translator.translate self._status[account_id][STATUS] = NONE birthday_command = self._postgres.commands().select_birthday_for_account(account_id) birthday_records = self._postgres.execute(birthday_command) if self._correct_postgres_answer(birthday_records): text = translate("Вот список добавленных друзей:", language) + "\n\n" for birthday_record in birthday_records: text += "{fio} {birthday}\n".format( fio=str(" ".join([birthday_record[3], birthday_record[1], birthday_record[2]])).strip(), birthday=birthday_record[6].strftime("%Y-%m-%d") ) context.bot.send_message( chat_id=update.message.chat_id, text=text[:-1] ) else: context.bot.send_message( chat_id=update.message.chat_id, text=translate("Вы еще не добавили ни одного друга!", language) ) self._update_status(account_id) def _language(self, update, context): account_id = update.effective_user[ACCOUNT_ID] language = self._status[account_id][LANGUAGE] translate = self._translator.translate self._status[account_id][STATUS] = LANGUAGE languages = [(key, value) for key, value in self._translator.languages().items() if key != language] keyboard = [ [ InlineKeyboardButton(languages[0][1], callback_data=languages[0][0]), InlineKeyboardButton(languages[1][1], callback_data=languages[1][0]) ] ] reply_markup = InlineKeyboardMarkup(keyboard) context.bot.send_message( chat_id=update.effective_message.chat_id, text=translate("Сейчас установленный язык русский. На какой Вы желаете изменить?", language), reply_markup=reply_markup ) self._update_status(account_id) def _help(self, update, context): account_id = update.effective_user[ACCOUNT_ID] language = self._status[account_id][LANGUAGE] translate = self._translator.translate self._status[account_id][STATUS] = NONE context.bot.send_message( chat_id=update.message.chat_id, text=translate("BirthdayBot создан для напоминания о днях рождениях твоих друзей! " "Вдруг у вас много работы или дел по дому, то я всегда дам вам знать, " "что особенный день близко!\\n\\n" "Чтобы я смог напомнить вам о дне рождения, вам необходимо заполнить анкету друга! " "Для заполнения анкеты существует команда /add\\n\\n" "При необходимости сменить язык общения - можно отправить команду /language", language) ) self._update_status(account_id) def _callback_query(self, update, context): account_id = update.effective_user[ACCOUNT_ID] query_data = update.callback_query.data status = self._status[account_id][STATUS] if status == LANGUAGE: self._language_in_callback_query(update, context) elif status == CREATE: context.bot.answer_callback_query(callback_query_id=update.callback_query.id) if query_data == ADD_FIO: self._add_fio_in_callback_query(update, context) elif query_data == ADD_DATE: self._add_date_in_callback_query(update, context) elif query_data == ADD_CONGRATULATION: self._add_congratulation_in_callback_query(update, context) elif query_data == ADD_DESIRES: self._add_desires_in_callback_query(update, context) elif query_data == CREATE: self._create_in_callback_query(update, context) else: self._invalid_in_callback_query(update, context) def _other_messages(self, update, context): account_id = update.effective_user[ACCOUNT_ID] status = self._status[account_id][STATUS] if status == ADD_CONTACT: self._add_contact_in_other_messages(update, context) elif status == ADD_DATE_INTERVAL: self._add_date_interval_in_other_messages(update, context) elif status == ADD_DATE_YEAR: self._add_date_year_in_other_messages(update, context) elif status == ADD_DATE_MONTH: self._add_date_month_in_other_messages(update, context) elif status == ADD_DATE_DAY: self._add_date_day_in_other_messages(update, context) elif status == ADD_FIO_LAST_NAME: self._add_fio_last_name_in_other_messages(update, context) elif status == ADD_FIO_FIRST_NAME: self._add_fio_first_name_in_other_messages(update, context) elif status == ADD_FIO_MIDDLE_NAME: self._add_fio_middle_name_in_other_messages(update, context) elif status == ADD_CONGRATULATION: self._add_congratulation_in_other_messages(update, context) elif status == ADD_DESIRES: self._add_desires_in_other_messages(update, context) else: self._invalid_in_other_messages(update, context) # ------------------------------------------------------------------------------------------ # JOBQUEUE METHODS # ------------------------------------------------------------------------------------------ def _it_is_time_for_birthday(self, dispatcher): self._logger.info("_it_is_time_for_birthday", "i am here") account_command = self._postgres.commands().select_account() account_records = self._postgres.execute(account_command) translate = self._translator.translate if self._correct_postgres_answer(account_records): for account_record in account_records: account_id = account_record[0] language = self._status[account_id][LANGUAGE] birthday_command = self._postgres.commands().select_birthday_for_account(account_record[0]) birthday_records = self._postgres.execute(birthday_command) if self._correct_postgres_answer(birthday_records): for birthday_record in birthday_records: datetime_birthday = datetime.strptime(birthday_record[6].strftime("%Y-%m-%d"), "%Y-%m-%d") birthday = { FIO: { LAST_NAME: birthday_record[1], FIRST_NAME: birthday_record[2], MIDDLE_NAME: birthday_record[3] }, DATE: { YEAR: str(datetime_birthday.year), MONTH: str(datetime_birthday.month), DAY: str(datetime_birthday.day) } } remind7, remind1 = birthday_record[9], birthday_record[10] datetime_birthday = datetime_birthday.replace(year=datetime.utcnow().year) if datetime.utcnow().timestamp() > datetime_birthday.timestamp(): datetime_birthday = datetime_birthday.replace(year=datetime.utcnow().year + 1) if datetime_birthday.timestamp() - datetime.utcnow().timestamp() <= 24 * 60 * 60 and remind1: dispatcher.bot.send_message( chat_id=account_record[0], text=translate("У твоего друга менее чем через сутки день рождения!\\n\\n" "{fio} исполняется {age}!\\n\\n" "Не забудь поздравить именинника и постарайся сделать его день рождения незабываемым! " "Надеюсь, что подарок ты уже приготовил!", language).format( fio=str(" ".join(birthday[FIO].values())).strip(), age=str(datetime.utcnow().year - int(birthday[DATE][YEAR])), ) ) remind7, remind1 = True, True elif datetime_birthday.timestamp() - datetime.utcnow().timestamp() <= 7 * 24 * 60 * 60 and remind7: dispatcher.bot.send_message( chat_id=account_record[0], text=translate( "У твоего друга менее чем через неделю день рождения!\\n\\n" "{fio} исполнится {age}!\\n\\n" "Приготовь хороший подарок, надеюсь ты знаешь что бы он хотел! " "Не забудь поздравить именинника и постарайся " "сделать его день рождения незабываемым!", language).format( fio=str(" ".join(birthday[FIO].values())).strip(), age=str(datetime.utcnow().year - int(birthday[DATE][YEAR])), ) ) remind7, remind1 = False, True command = self._postgres.commands().update_remind(remind7, remind1, birthday_record[0]) self._postgres.execute(command) # ------------------------------------------------------------------------------------------ # PRIVATE METHODS # ------------------------------------------------------------------------------------------ @staticmethod def _correct_postgres_answer(answer): return True if answer and len(answer) > 0 else False def _send_create_message(self, update, context): account_id = update.effective_user[ACCOUNT_ID] language = self._status[account_id][LANGUAGE] translate = self._translator.translate self._status[account_id][STATUS] = CREATE keyboard = [ [ InlineKeyboardButton(translate("ФИО", language), callback_data=ADD_FIO), InlineKeyboardButton(translate("Дата рождения", language), callback_data=ADD_DATE) ], [ InlineKeyboardButton(translate("Поздравление", language), callback_data=ADD_CONGRATULATION), InlineKeyboardButton(translate("Пожелания", language), callback_data=ADD_DESIRES) ], [ InlineKeyboardButton(translate("Создать", language), callback_data=CREATE) ] ] reply_markup = InlineKeyboardMarkup(keyboard) year = self._status[account_id][BIRTHDAY][DATE][YEAR] month = self._status[account_id][BIRTHDAY][DATE][MONTH] day = self._status[account_id][BIRTHDAY][DATE][DAY] context.bot.send_message( chat_id=update.effective_message.chat_id, text=translate("Давай посмотрим что получилось!", language), reply_markup=ReplyKeyboardRemove() ) fio_value = ' '.join(value for value in self._status[account_id][BIRTHDAY][FIO].values() if value) congratulation = self._status[account_id][BIRTHDAY][CONGRATULATION] congratulation_value = congratulation if congratulation else translate("не задано", language) desires = self._status[account_id][BIRTHDAY][DESIRES] desires_value = desires if desires else translate("не задано", language) context.bot.send_message( chat_id=update.effective_message.chat_id, text="{text}:\n\n" "<b>{fio}</b>: {fio_value}\n" "<b>{date}</b>: {date_value}\n" "<b>{congratulation}</b>: {congratulation_value}\n" "<b>{desires}</b>: {desires_value}".format( text=translate("Анкета друга", language), fio=translate("ФИО", language), date=translate("Дата рождения", language), congratulation=translate("Поздравление", language), desires=translate("Пожелания", language), fio_value=fio_value, date_value="{0}-{1}-{2}".format(year, month, day), congratulation_value=congratulation_value, desires_value=desires_value), reply_markup=reply_markup, parse_mode=ParseMode.HTML ) self._update_status(account_id) def _it_is_time_for_birthday_after_create(self, update, context): account_id = update.effective_user[ACCOUNT_ID] language = self._status[account_id][LANGUAGE] translate = self._translator.translate birthday = self._status[account_id][BIRTHDAY] datetime_birthday = datetime( int(birthday[DATE][YEAR]), int(birthday[DATE][MONTH]), int(birthday[DATE][DAY]), 0, 0, 0 ) remind7, remind1 = True, True datetime_birthday = datetime_birthday.replace(year=datetime.utcnow().year) if datetime.utcnow().timestamp() > datetime_birthday.timestamp(): datetime_birthday = datetime_birthday.replace(year=datetime.utcnow().year + 1) if datetime_birthday.timestamp() - datetime.utcnow().timestamp() <= 24 * 60 * 60: context.bot.send_message( chat_id=update.callback_query.message.chat_id, text=translate("У твоего друга менее чем через сутки день рождения!\\n\\n" "{fio} исполняется {age}!\\n\\n" "Не забудь поздравить именинника и постарайся сделать его день рождения незабываемым! " "Надеюсь, что подарок ты уже приготовил!", language).format( fio=str(" ".join(birthday[FIO].values())).strip(), age=str(datetime.utcnow().year - int(birthday[DATE][YEAR])), ) ) elif datetime_birthday.timestamp() - datetime.utcnow().timestamp() <= 7 * 24 * 60 * 60: context.bot.send_message( chat_id=update.callback_query.message.chat_id, text=translate( "У твоего друга менее чем через неделю день рождения!\\n\\n" "{fio} исполнится {age}!\\n\\n" "Приготовь хороший подарок, надеюсь ты знаешь что бы он хотел! " "Не забудь поздравить именинника и постарайся " "сделать его день рождения незабываемым!", language).format( fio=str(" ".join(birthday[FIO].values())).strip(), age=str(datetime.utcnow().year - int(birthday[DATE][YEAR])), ) ) remind7 = False command = self._postgres.commands().select_specific_birthday( account_id=account_id, first_name=birthday[FIO][FIRST_NAME], last_name=birthday[FIO][LAST_NAME], middle_name=birthday[FIO][MIDDLE_NAME] ) specific_birthday = self._postgres.execute(command) if self._correct_postgres_answer(specific_birthday): command = self._postgres.commands().update_remind(remind7, remind1, specific_birthday[0][0]) self._postgres.execute(command) def _update_status(self, account_id): command = self._postgres.commands().update_status(json.dumps(self._status[account_id]), account_id) self._postgres.execute(command) # ------------------------------------------------------------------------------------------ # CALLBACK QUERY METHODS # ------------------------------------------------------------------------------------------ def _language_in_callback_query(self, update, context): query_data = update.callback_query.data account_id = update.effective_user[ACCOUNT_ID] translate = self._translator.translate language = query_data command = self._postgres.commands().update_language( language_code=query_data, account_id=account_id ) self._postgres.execute(command) self._status[account_id][LANGUAGE] = query_data self._status[account_id][STATUS] = NONE context.bot.edit_message_text( chat_id=update.callback_query.message.chat_id, message_id=update.callback_query.message.message_id, text=translate("Вы изменили язык на русский!", language) ) self._update_status(account_id) def _add_fio_in_callback_query(self, update, context): account_id = update.effective_user[ACCOUNT_ID] language = self._status[account_id][LANGUAGE] translate = self._translator.translate self._status[account_id][STATUS] = ADD_FIO_LAST_NAME context.bot.send_message( chat_id=update.callback_query.message.chat_id, text=translate("Введите фамилию друга", language) ) self._update_status(account_id) def _add_date_in_callback_query(self, update, context): account_id = update.effective_user[ACCOUNT_ID] language = self._status[account_id][LANGUAGE] translate = self._translator.translate self._status[account_id][STATUS] = ADD_DATE_INTERVAL start_year = 1930 keyboard = [ [ "{0} - {1}".format( start_year + (2 * i + j) * 12, start_year + (2 * i + j) * 12 + 11 ) for j in range(2) ] for i in range(4) ] context.bot.send_message( chat_id=update.effective_message.chat_id, text=translate("Введите интервал даты рождения", language), reply_markup=ReplyKeyboardMarkup( keyboard=keyboard, resize_keyboard=True ) ) self._update_status(account_id) def _add_congratulation_in_callback_query(self, update, context): account_id = update.effective_user[ACCOUNT_ID] language = self._status[account_id][LANGUAGE] translate = self._translator.translate self._status[account_id][STATUS] = ADD_CONGRATULATION context.bot.send_message( chat_id=update.callback_query.message.chat_id, text=translate("Введите поздравление для друга", language) ) self._update_status(account_id) def _add_desires_in_callback_query(self, update, context): account_id = update.effective_user[ACCOUNT_ID] language = self._status[account_id][LANGUAGE] translate = self._translator.translate self._status[account_id][STATUS] = ADD_DESIRES context.bot.send_message( chat_id=update.callback_query.message.chat_id, message_id=update.callback_query.message.message_id, text=translate("Введите желания друга", language) ) self._update_status(account_id) def _create_in_callback_query(self, update, context): account_id = update.effective_user[ACCOUNT_ID] language = self._status[account_id][LANGUAGE] translate = self._translator.translate context.bot.answer_callback_query(callback_query_id=update.callback_query.id) birthday = self._status[account_id][BIRTHDAY] year = birthday[DATE][YEAR] month = birthday[DATE][MONTH] day = birthday[DATE][DAY] command = self._postgres.commands().insert_birthday( last_name=birthday[FIO][LAST_NAME], first_name=birthday[FIO][FIRST_NAME], middle_name=birthday[FIO][MIDDLE_NAME], phone_number=birthday[PHONE_NUMBER], user_id=birthday[TELEGRAM_USER_ID], date="{0}-{1}-{2}".format(year, month, day), congratulation=birthday[CONGRATULATION], desires=birthday[DESIRES], remind7=True, remind1=True, account_id=account_id ) self._postgres.execute(command) context.bot.edit_message_text( chat_id=update.callback_query.message.chat_id, message_id=update.callback_query.message.message_id, text=translate("Вы успешно добавили информацию о друге!", language) ) self._it_is_time_for_birthday_after_create(update, context) self._status[account_id][STATUS] = NONE self._status[account_id][BIRTHDAY] = {} self._update_status(account_id) def _invalid_in_callback_query(self, update, context): account_id = update.effective_user[ACCOUNT_ID] language = self._status[account_id][LANGUAGE] translate = self._translator.translate context.bot.edit_message_text( chat_id=update.callback_query.message.chat_id, message_id=update.callback_query.message.message_id, text=translate("К сожалению, я не поддерживаю данное сообщение!", language) ) # ------------------------------------------------------------------------------------------ # OTHER METHODS # ------------------------------------------------------------------------------------------ def _add_contact_in_other_messages(self, update, context): account_id = update.effective_user[ACCOUNT_ID] language = self._status[account_id][LANGUAGE] translate = self._translator.translate if update.effective_message[ATTACHMENTS_CONTACT]: birthday = self._status[account_id][BIRTHDAY] first_name = update.effective_message[CONTACT][FIRST_NAME] last_name = update.effective_message[CONTACT][LAST_NAME] phone_number = update.effective_message[CONTACT][PHONE_NUMBER] user_id = update.effective_message[CONTACT][TELEGRAM_USER_ID] birthday[FIO][LAST_NAME] = last_name if last_name and len(last_name) > 0 else NONE birthday[FIO][FIRST_NAME] = first_name if first_name and len(first_name) > 0 else NONE birthday[PHONE_NUMBER] = phone_number if phone_number and len(phone_number) > 0 else NONE birthday[TELEGRAM_USER_ID] = user_id if user_id else 0 self._status[account_id][STATUS] = ADD_DATE_INTERVAL start_year = 1930 keyboard = [ [ "{0} - {1}".format( start_year + (2 * i + j) * 12, start_year + (2 * i + j) * 12 + 11 ) for j in range(2) ] for i in range(4) ] context.bot.send_message( chat_id=update.effective_message.chat_id, text=translate("Введите интервал даты рождения", language), reply_markup=ReplyKeyboardMarkup( keyboard=keyboard, resize_keyboard=True ) ) else: context.bot.send_message( chat_id=update.effective_message.chat_id, text=translate("Будьте так любезны, пришлите мне контакт именинника!", language) ) self._update_status(account_id) def _add_date_interval_in_other_messages(self, update, context): account_id = update.effective_user[ACCOUNT_ID] language = self._status[account_id][LANGUAGE] translate = self._translator.translate self._status[account_id][STATUS] = ADD_DATE_YEAR interval = update.effective_message.text begin = int(interval[0:4]) keyboard = [ [ "{0}".format(begin + 3 * i + j) for j in range(3) ] for i in range(4) ] context.bot.send_message( chat_id=update.effective_message.chat_id, text=translate("Введите год даты рождения", language), reply_markup=ReplyKeyboardMarkup( keyboard=keyboard, resize_keyboard=True ) ) self._update_status(account_id) def _add_date_year_in_other_messages(self, update, context): account_id = update.effective_user[ACCOUNT_ID] language = self._status[account_id][LANGUAGE] translate = self._translator.translate self._status[account_id][BIRTHDAY][DATE] = { YEAR: NONE, MONTH: NONE, DAY: NONE } self._status[account_id][BIRTHDAY][DATE][YEAR] = update.effective_message.text self._status[account_id][STATUS] = ADD_DATE_MONTH keyboard = [ [ translate(MONTH_LIST[3 * i + j], language) for j in range(3) ] for i in range(4) ] context.bot.send_message( chat_id=update.effective_message.chat_id, text=translate("Введите месяц даты рождения", language), reply_markup=ReplyKeyboardMarkup( keyboard=keyboard, resize_keyboard=True ) ) self._update_status(account_id) def _add_date_month_in_other_messages(self, update, context): account_id = update.effective_user[ACCOUNT_ID] language = self._status[account_id][LANGUAGE] translate = self._translator.translate self._status[account_id][STATUS] = ADD_DATE_DAY month_arr = [translate(month, language) for month in MONTH_LIST] self._status[account_id][BIRTHDAY][DATE][MONTH] = str(month_arr.index(update.effective_message.text) + 1) year = int(self._status[account_id][BIRTHDAY][DATE][YEAR]) month = int(self._status[account_id][BIRTHDAY][DATE][MONTH]) days = calendar.monthrange(year, month)[1] keyboard = [ [ str(4 * i + j + 1) for j in range(4) if 4 * i + j + 1 <= days ] for i in range(days // 4 + 1) ] context.bot.send_message( chat_id=update.effective_message.chat_id, text=translate("Введите день даты рождения", language), reply_markup=ReplyKeyboardMarkup( keyboard=keyboard, resize_keyboard=True ) ) self._update_status(account_id) def _add_date_day_in_other_messages(self, update, context): account_id = update.effective_user[ACCOUNT_ID] self._status[account_id][BIRTHDAY][DATE][DAY] = update.effective_message.text self._send_create_message(update, context) self._update_status(account_id) def _add_fio_last_name_in_other_messages(self, update, context): account_id = update.effective_user[ACCOUNT_ID] language = self._status[account_id][LANGUAGE] translate = self._translator.translate if update.effective_message.text: self._status[account_id][STATUS] = ADD_FIO_FIRST_NAME self._status[account_id][BIRTHDAY][FIO][LAST_NAME] = update.effective_message.text context.bot.send_message( chat_id=update.effective_message.chat_id, text=translate("Введите имя друга", language) ) else: context.bot.send_message( chat_id=update.effective_message.chat_id, text=translate("Будьте так любезны, введите фамилию друга", language) ) self._update_status(account_id) def _add_fio_first_name_in_other_messages(self, update, context): account_id = update.effective_user[ACCOUNT_ID] language = self._status[account_id][LANGUAGE] translate = self._translator.translate if update.effective_message.text: self._status[account_id][STATUS] = ADD_FIO_MIDDLE_NAME self._status[account_id][BIRTHDAY][FIO][FIRST_NAME] = update.effective_message.text context.bot.send_message( chat_id=update.effective_message.chat_id, text=translate("Введите отчество друга", language) ) else: context.bot.send_message( chat_id=update.effective_message.chat_id, text=translate("Будьте так любезны, введите имя друга", language) ) self._update_status(account_id) def _add_fio_middle_name_in_other_messages(self, update, context): account_id = update.effective_user[ACCOUNT_ID] language = self._status[account_id][LANGUAGE] translate = self._translator.translate if update.effective_message.text: self._status[account_id][BIRTHDAY][FIO][MIDDLE_NAME] = update.effective_message.text self._send_create_message(update, context) else: context.bot.send_message( chat_id=update.effective_message.chat_id, text=translate("Будьте так любезны, введите отчество друга", language) ) self._update_status(account_id) def _add_congratulation_in_other_messages(self, update, context): account_id = update.effective_user[ACCOUNT_ID] language = self._status[account_id][LANGUAGE] translate = self._translator.translate if update.effective_message.text: self._status[account_id][BIRTHDAY][CONGRATULATION] = update.effective_message.text self._send_create_message(update, context) else: context.bot.send_message( chat_id=update.effective_message.chat_id, text=translate("Будьте так любезны, пришлите мне поздравление для именинника!", language) ) self._update_status(account_id) def _add_desires_in_other_messages(self, update, context): account_id = update.effective_user[ACCOUNT_ID] language = self._status[account_id][LANGUAGE] translate = self._translator.translate if update.effective_message.text: self._status[account_id][BIRTHDAY][DESIRES] = update.effective_message.text self._send_create_message(update, context) else: context.bot.send_message( chat_id=update.effective_message.chat_id, text=translate("Будьте так любезны, пришлите мне пожелания к подарку для именинника!", language) ) self._update_status(account_id) def _invalid_in_other_messages(self, update, context): account_id = update.effective_user[ACCOUNT_ID] self._status[account_id][STATUS] = CREATE if self._status[account_id][STATUS] == CREATE else NONE if update.effective_message[ATTACHMENTS_AUDIO]: self._audio_in_other_messages(update, context) elif update.effective_message[ATTACHMENTS_DOCUMENT]: self._document_in_other_messages(update, context) elif update.effective_message[ATTACHMENTS_PHOTO]: self._photo_in_other_messages(update, context) elif update.effective_message[ATTACHMENTS_STICKER]: self._sticker_in_other_messages(update, context) elif update.effective_message[ATTACHMENTS_VIDEO]: self._video_in_other_messages(update, context) elif update.effective_message[ATTACHMENTS_VOICE]: self._voice_in_other_messages(update, context) elif update.effective_message[ATTACHMENTS_VIDEO_NOTE]: self._video_note_in_other_messages(update, context) elif update.effective_message[ATTACHMENTS_CONTACT]: self._contact_note_in_other_messages(update, context) elif update.effective_message[ATTACHMENTS_LOCATION]: self._location_in_other_messages(update, context) elif update.effective_message[ATTACHMENTS_VENUE]: self._venue_in_other_messages(update, context) elif update.effective_message[ATTACHMENTS_GAME]: self._game_in_other_messages(update, context) elif update.effective_message[ATTACHMENTS_ANIMATION]: self._animation_in_other_messages(update, context) elif update.effective_message[ATTACHMENTS_INVOICE]: self._invoice_in_other_messages(update, context) elif update.effective_message[ATTACHMENTS_SUCCESSFUL_PAYMENT]: self._successful_payment_in_other_messages(update, context) else: self._unprocessed_other_messages(update, context) self._update_status(account_id) # ------------------------------------------------------------------------------------------ # ATTACHMENT METHODS # ------------------------------------------------------------------------------------------ def _audio_in_other_messages(self, update, context): account_id = update.effective_user[ACCOUNT_ID] language = self._status[account_id][LANGUAGE] translate = self._translator.translate context.bot.send_message( chat_id=update.effective_message.chat_id, text=translate("У вас определенно хороший музыкальный вкус!", language) ) def _document_in_other_messages(self, update, context): account_id = update.effective_user[ACCOUNT_ID] language = self._status[account_id][LANGUAGE] translate = self._translator.translate context.bot.send_message( chat_id=update.effective_message.chat_id, text=translate("Я обязательно прочту ваш документ и напишу рецензию!", language) ) def _photo_in_other_messages(self, update, context): account_id = update.effective_user[ACCOUNT_ID] language = self._status[account_id][LANGUAGE] translate = self._translator.translate context.bot.send_message( chat_id=update.effective_message.chat_id, text=translate("Как вы смеете мне присылать такие фото!", language) ) def _sticker_in_other_messages(self, update, context): account_id = update.effective_user[ACCOUNT_ID] language = self._status[account_id][LANGUAGE] translate = self._translator.translate context.bot.send_message( chat_id=update.effective_message.chat_id, text=translate("У меня есть набор стикеров поинтереснее!", language) ) def _video_in_other_messages(self, update, context): account_id = update.effective_user[ACCOUNT_ID] language = self._status[account_id][LANGUAGE] translate = self._translator.translate context.bot.send_message( chat_id=update.effective_message.chat_id, text=translate("Это видео я отправлю в Роскомнадзор, там с вами разберутся!", language) ) def _voice_in_other_messages(self, update, context): account_id = update.effective_user[ACCOUNT_ID] language = self._status[account_id][LANGUAGE] translate = self._translator.translate context.bot.send_message( chat_id=update.effective_message.chat_id, text=translate("Какой милый голосок! Прочитай мне сказку!", language) ) def _video_note_in_other_messages(self, update, context): account_id = update.effective_user[ACCOUNT_ID] language = self._status[account_id][LANGUAGE] translate = self._translator.translate context.bot.send_message( chat_id=update.effective_message.chat_id, text=translate("Если я буду присылать такие видео как проснусь, то я буду выглядеть намного лучше!", language) ) def _contact_note_in_other_messages(self, update, context): account_id = update.effective_user[ACCOUNT_ID] language = self._status[account_id][LANGUAGE] translate = self._translator.translate context.bot.send_message( chat_id=update.effective_message.chat_id, text=translate("ФСБ проверит твой контакт, я уже передал!", language) ) def _location_in_other_messages(self, update, context): account_id = update.effective_user[ACCOUNT_ID] language = self._status[account_id][LANGUAGE] translate = self._translator.translate context.bot.send_message( chat_id=update.effective_message.chat_id, text=translate("Если там собираются красивые девушки, то я уже выезжаю!", language) ) def _venue_in_other_messages(self, update, context): account_id = update.effective_user[ACCOUNT_ID] language = self._status[account_id][LANGUAGE] translate = self._translator.translate context.bot.send_message( chat_id=update.effective_message.chat_id, text=translate("Там определенно продаются самые вкусные пончики в мире!", language) ) def _game_in_other_messages(self, update, context): account_id = update.effective_user[ACCOUNT_ID] language = self._status[account_id][LANGUAGE] translate = self._translator.translate context.bot.send_message( chat_id=update.effective_message.chat_id, text=translate("Я в такие игры не играю! Я еще маленький!", language) ) def _animation_in_other_messages(self, update, context): account_id = update.effective_user[ACCOUNT_ID] language = self._status[account_id][LANGUAGE] translate = self._translator.translate context.bot.send_message( chat_id=update.effective_message.chat_id, text=translate("Рассмашил так рассмешил! Мне понравилось!", language) ) def _invoice_in_other_messages(self, update, context): account_id = update.effective_user[ACCOUNT_ID] language = self._status[account_id][LANGUAGE] translate = self._translator.translate context.bot.send_message( chat_id=update.effective_message.chat_id, text=translate("Я такого не заказывал! Хочу оформить возврат!", language) ) def _successful_payment_in_other_messages(self, update, context): account_id = update.effective_user[ACCOUNT_ID] language = self._status[account_id][LANGUAGE] translate = self._translator.translate context.bot.send_message( chat_id=update.effective_message.chat_id, text=translate("Если вы отдаете мне это бесплатно, то я готов принять подарок!", language) ) def _unprocessed_other_messages(self, update, context): account_id = update.effective_user[ACCOUNT_ID] language = self._status[account_id][LANGUAGE] translate = self._translator.translate context.bot.send_message( chat_id=update.effective_message.chat_id, text=translate("К сожалению, я не поддерживаю данное сообщение!", language) )
def setup(): bot = Bot(token=conf['BOT_TOKEN']) update_queue = Queue() dp = Dispatcher(bot, update_queue) jq = JobQueue(bot) # Commands for admin dp.add_handler(CommandHandler('start', start)) dp.add_handler( CommandHandler('apod', apod, pass_args=True, filters=Filters.user(username=conf['ADMIN']))) dp.add_handler( CommandHandler('epic', epic, pass_args=True, filters=Filters.user(username=conf['ADMIN']))) dp.add_handler( CommandHandler('mars', mars_photos, pass_args=True, filters=Filters.user(username=conf['ADMIN']))) dp.add_handler( CommandHandler('db', test_db_command, filters=Filters.user(username=conf['ADMIN']))) dp.add_error_handler(error) # jq.run_repeating(check_apod_updates, interval=3600, first=0, context=make_apod_context(bot, TESTING)) jq.run_repeating(check_epic_updates, interval=3600, first=15 if TESTING else 500, context=make_epic_context(bot, TESTING)) jq.run_daily(check_mars_photos_updates, time=time(9), context={ 'Curiosity': 2320, 'Opportunity': 5111, 'Spirit': 2208, 'all': ['Curiosity', 'Opportunity', 'Spirit'] }) s = bot.set_webhook( url='https://salty-escarpment-89606.herokuapp.com/hook/' + conf['BOT_TOKEN']) if s: print(s) logger.info('webhook setup ok') else: print(s) logger.info('webhook setup failed') thread = Thread(target=dp.start, name='dispatcher') thread.start() jq.start() return update_queue, bot
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)
def photos_post(job_queue: JobQueue): def job(context: CallbackContext): log.debug('Start photos post job') upload() job_queue.run_repeating(job, interval=30, first=30)
class Bot(object): START_MESSAGE = "Hello, I am a bot, nice to meet you. You may use /help to read what my commands do." ADD_USAGE = "/add <url> <m> <keyword 1> <keyword 2> ..." LIST_USAGE = "/list" REMOVE_USAGE = "/remove <url>" # Help message. HELP_MESSAGE = f"""*KeywordScrapeBot*:\n {ADD_USAGE} Add a job that runs every m minutes (minimum 15), scanning the url for links containing the keywords. Running the command again for the same url will overwrite the job.\n {LIST_USAGE} List your running jobs.\n {REMOVE_USAGE} Remove a job. """ def __init__(self, bot_token: str, database_file: Union[str, Path], minimum_interval: int = 15): """ :param bot_token: The token to run the bot on. :param database_file: The database file. :param minimum_interval: The minimum update interval in minutes. Defaults to 15. """ self._database_file = database_file self._minimum_interval = minimum_interval self._updater = Updater(token=bot_token, use_context=True) self._updater.dispatcher.add_handler( CommandHandler("start", self._add_user)) self._updater.dispatcher.add_handler( CommandHandler("list", self._list_jobs)) self._updater.dispatcher.add_handler( CommandHandler("add", self._add_job)) self._updater.dispatcher.add_handler( CommandHandler("remove", self._remove_job)) self._updater.dispatcher.add_handler( CommandHandler("help", self._send_help)) self._job_queue = JobQueue() self._job_queue.set_dispatcher(self._updater.dispatcher) self._job_queue.start() # Keep map {(user, url) : telegram.ext.Job} to allow canceling jobs. self._job_map = dict() # Load all Jobs in the database. for job in Database(self._database_file).get_jobs(): self._schedule(job) def start(self): self._updater.start_polling() def idle(self): self._updater.idle() def _add_user(self, update: telegram.Update, context: telegram.ext.CallbackContext): """ Callback for the addition of a user. """ user = update.effective_chat.id # Add user to database. Database(self._database_file).add_user(user) # Answer user. context.bot.send_message(chat_id=user, text=self.START_MESSAGE) # Log the info about the new user. logging.info(f"/start command received by user: {user}.") def _add_job(self, update: telegram.Update, context: telegram.ext.CallbackContext): f""" Callback for the update of a job. Message must be: ``` {Bot.ADD_USAGE} ``` """ user = update.effective_chat.id try: # Extract info. url = context.args[0] # Check url validity. if not utils.is_valid_url(url): update.message.reply_text(f"{url} is not a valid url.", disable_web_page_preview=True) logging.warning(f"Invalid url from user {user}.") return # Check minimum time freq = int(context.args[1]) if freq < self._minimum_interval: update.message.reply_text( f"{self._minimum_interval} minutes is the minimum time. I'll just set it for you." ) freq = self._minimum_interval keywords = context.args[2::] if len(context.args) > 2 else list() # Update database. job = Job(user, url, freq, keywords) Database(self._database_file).add_job(job) # Schedule job. self._schedule(job) # Send back a response as a confirmation. response = f"Will start searching {url} for links containing {', '.join(keywords)} every {freq} minutes." update.message.reply_text(response, disable_web_page_preview=True) logging.info(f"/add command received by user: {user}. {response}") except (IndexError, ValueError): update.message.reply_text(f"Usage: {Bot.ADD_USAGE}") logging.warning(f"Inappropriate /add command from user {user}.") def _list_jobs(self, update: telegram.Update, context: telegram.ext.CallbackContext): """ Send a message containing the scheduled jobs for the user. """ user = update.effective_chat.id jobs = Database(self._database_file).get_jobs(user) if jobs: update.message.reply_markdown("\n---\n".join([ f"*JOB {i + 1}*\nurl: {j.url}\nkeywords: {j.keywords}\nEvery {j.freq} hours." for i, j in enumerate(jobs) ]), disable_web_page_preview=True) else: update.message.reply_text(f"No jobs scheduled.") logging.info(f"Sent job list to {user}.") def _remove_job(self, update: telegram.Update, context: telegram.ext.CallbackContext): f""" Callback for the removal of a job. Message must be: ``` {Bot.REMOVE_USAGE} ``` """ user = update.effective_chat.id try: url = context.args[0] db = Database(self._database_file) jobs = db.get_jobs(user) # Job not in database. if url not in [j.url for j in jobs]: update.message.reply_text(f"You have no job for url: {url}", disable_web_page_preview=True) logging.info( f"User {user} asked for removal of non-existing job {url}") return # Job in db, delete and unschedule job. db.delete_job(user, url) self._unschedule(user, url) # Send back a response. update.message.reply_text( f"You will receive no more updates from: {url}", disable_web_page_preview=True) logging.info(f"Removed job {url} for user {user}.") except IndexError: update.message.reply_text(f"Usage: {Bot.REMOVE_USAGE}") logging.warning(f"Inappropriate /remove command from user {user}.") def _send_help(self, update: telegram.Update, context: telegram.ext.CallbackContext): """ Send help message. """ user = update.effective_chat.id # Answer user. context.bot.send_message(chat_id=user, text=self.HELP_MESSAGE, parse_mode="markdown") logging.info(f"Sent help to user: {user}.") def _schedule(self, job: Job): """ Schedule a new job for the bot. Tries to remove any previous job for the same key (user, url) :param job: The new job to schedule. """ # Safely remove any old matching job. self._unschedule(job.user, job.url) # Set job to run every x hours and keep track to cancel it later. self._job_map[(job.user, job.url)] = self._job_queue.run_repeating( make_job_callback(job, self._database_file), 60 * job.freq, 1) logging.info(f"Started job on url {job.url} for user {job.user}.") def _unschedule(self, user: int, url: str): """ Remove the corresponding job from the queue. :param user: The user of the job. :param url: The url of the job. """ old_job = self._job_map.pop((user, url), 0) if old_job != 0: old_job.schedule_removal() logging.info(f"Removed Telegram job on url {url} for user {user}.") def __del__(self): # Stop za bot. self._job_queue.stop() self._updater.stop()