def try_message(context, chat_id, text, reply_markup=None, remove_job_when_blocked=True): """ Send a message to a user. """ try: context.bot.send_message(chat_id, text, parse_mode='markdown', reply_markup=reply_markup, disable_web_page_preview=True) except TelegramError as e: if 'bot was blocked by the user' in e.message: logger.info("Telegram user " + str(chat_id) + " blocked me; removing him from the user list") del context.dispatcher.user_data[chat_id] del context.dispatcher.chat_data[chat_id] del context.dispatcher.persistence.user_data[chat_id] del context.dispatcher.persistence.chat_data[chat_id] # Somehow session.data does not get updated if all users block the bot. # That makes problems on bot restart. That's why we delete the file ourselves. if len(context.dispatcher.persistence.user_data ) == 0 and os.path.exists("./storage/session.data"): os.remove("./storage/session.data") if remove_job_when_blocked: context.job.schedule_removal() else: logger.error(e, exc_info=True) logger.info("Telegram user " + str(chat_id))
def on_show_active_proposals_clicked(update, context): query = update.callback_query _ = query.data.split("-") try: active_proposals = get_active_proposals() except Exception as e: logger.error(e, exc_info=True) try_message(context=context, chat_id=query['message']['chat']['id'], text=NETWORK_ERROR_MSG) return title = '🗳 ✅ *Active proposals*🗳 ✅ \n' \ 'Click on any of the proposals to see details and vote options.\n\n' def button_builder(proposal_title: str, proposal_id: str) -> InlineKeyboardButton: return InlineKeyboardButton(proposal_title, callback_data=f'proposal-{proposal_id}-1' ) # 1 - open read and vote view _display_proposals(proposals=active_proposals, query=query, title=title, button_builder=button_builder)
def on_proposal_clicked(update, context): query = update.callback_query _, proposal_id, votable = query.data.split("-") votable = int(votable) previous_view = 'proposals_show_active' if votable else 'proposals_show_all' try: proposal = get_proposal(int(proposal_id)) context.user_data.setdefault('proposals_cache', {})[proposal_id] = { 'title': proposal['content']['value']['title'] } except Exception as e: logger.error(e) query.edit_message_text(NETWORK_ERROR_MSG) return keyboard = [[ InlineKeyboardButton(BACK_BUTTON_MSG, callback_data=previous_view) ]] my_wallet = context.user_data['proposals_cache'].get('wallet', None) my_vote = None if my_wallet: my_vote = get_vote(wallet_addr=my_wallet, proposal_id=proposal_id) message = '' if my_wallet and my_vote: message += f'🎉 You voted *{my_vote}* 🎉' else: if votable: keyboard = [ [ InlineKeyboardButton( '✅ Yes', callback_data=f'vote-{proposal_id}-{MsgVote.YES}'), InlineKeyboardButton( '❌ No', callback_data=f'vote-{proposal_id}-{MsgVote.NO}'), ], [ InlineKeyboardButton( '❌❌ No with veto', callback_data= f'vote-{proposal_id}-{MsgVote.NO_WITH_VETO}'), InlineKeyboardButton( '🤷 Abstain', callback_data=f'vote-{proposal_id}-{MsgVote.ABSTAIN}'), ], [ InlineKeyboardButton(BACK_BUTTON_MSG, callback_data='proposals_show_active') ] ] message += f"\n\n\n{proposal_to_text(proposal)}" query.edit_message_text(message, parse_mode='markdown', reply_markup=InlineKeyboardMarkup(keyboard))
def send_slack_message(text): if SLACK_WEBHOOK: try: requests.post(SLACK_WEBHOOK, data=json.dumps({'text': text}), headers={'Content-Type': 'application/json'}) except RequestException as e: logger.error(f"Slack Webhook post request failed with:\n{e}")
def check_governance_proposals(context): """ Monitoring related to governance proposals """ try: governance_proposals = get_governance_proposals() except ConnectionError as e: logger.error(e) return check_new_goverance_proposal(context, governance_proposals) check_results_of_proposals(context, governance_proposals)
def check_sentry_node_status(node_ip, sentry_nodes_data) -> [None, str]: try: is_currently_syncing = is_syncing(node_ip) except Exception as e: logger.error(e) return None was_syncing = sentry_nodes_data.setdefault(node_ip, {}).setdefault('syncing', False) if was_syncing != is_currently_syncing: sentry_nodes_data[node_ip]['syncing'] = is_currently_syncing if is_currently_syncing: text = NODE_STARTED_SYNCING_MSG.format(node_ip) else: text = NODE_FINISHED_SYNCING_MSG.format(node_ip) return text else: return None
def setup_existing_user(dispatcher): """ Tasks to ensure smooth user experience for existing users upon Bot restart """ chat_ids = dispatcher.user_data.keys() delete_chat_ids = [] for chat_id in chat_ids: try: dispatcher.bot.send_message(chat_id, BOT_RESTARTED_MSG) dispatcher.job_queue.run_repeating( node_checks, interval=JOB_INTERVAL_IN_SECONDS, context={ 'chat_id': chat_id, 'user_data': dispatcher.user_data[chat_id] }) except TelegramError as e: if 'bot was blocked by the user' in e.message: delete_chat_ids.append(chat_id) continue else: logger.error("Got Error\n" + str(e) + "\nwith telegram user " + str(chat_id)) for chat_id in delete_chat_ids: logger.info("Telegram user " + str(chat_id) + " blocked me; removing him from the user list") del dispatcher.user_data[chat_id] del dispatcher.chat_data[chat_id] del dispatcher.persistence.user_data[chat_id] del dispatcher.persistence.chat_data[chat_id] # Somehow session.data does not get updated if all users block the bot. # That's why we delete the file ourselves. if len(dispatcher.persistence.user_data) == 0 and os.path.exists( session_data_path): os.remove(session_data_path)