def send_daily_report(hours_of_day: list): audience = get_all_humans_for_telegram_notifications( hours_of_day=hours_of_day) # create bot bot = get_telegram_bot_instance() # send to audience notify_admin = True count = 0 for member in audience: try: human = Human(human_id=member[HumanProperties.ID.value]) # get most recent coordinates most_recent_location = human.get_most_recent_location() if most_recent_location is None: return "NOTHING TO SHOW. SHARE YOUR LOCATION FIRST." lat, lng = most_recent_location human.send_proximity_alert(lat=lat, lng=lng) count += 1 except Exception as e: if notify_admin: bot.send_message( chat_id=int( CONFIG.get('telegram-credentials-telegram-admin-id')), text="[ADMIN] `send_daily_report` exception : {}".format( e)) notify_admin = False # alert admin bot.send_message( chat_id=int(CONFIG.get('telegram-credentials-telegram-admin-id')), text="[ADMIN] Sent proximity report to {}/{} humans.".format( count, len(audience)))
def fulfill_log_symptom(human: Human, symptom_name: str) -> bool: bot = get_telegram_bot_instance() try: human.log_symptom(symptom_name=symptom_name) log_sent_message(bot.send_message( chat_id=human.telegram_human_id, text="Noted!" ), human_id=human.id) except Exception as e: logger.error(e) return False return True
def send_feedback_request(hours_of_day: list): audience = get_all_humans_for_telegram_notifications( hours_of_day=hours_of_day) # create bot bot = get_telegram_bot_instance() # send to audience notify_admin = True count = 0 for member in audience: try: bot.send_message( chat_id=member[HumanProperties.TELEGRAM_HUMAN_ID.value], text= "*[🤙 Feedback Request]* Please share your feedback on the product by clicking here: @OpendemicTeam", parse_mode='markdown', reply_markup=get_telegram_menu()) except Exception as e: if notify_admin: bot.send_message( chat_id=int( CONFIG.get('telegram-credentials-telegram-admin-id')), text="[ADMIN] `send_feedback_request` exception : {}". format(e)) notify_admin = False # try to unsubscribe try: human = Human(human_id=member[HumanProperties.ID.value]) human.unsubscribe() except Exception as unsb_e: pass else: count += 1 # alert admin bot.send_message( chat_id=int(CONFIG.get('telegram-credentials-telegram-admin-id')), text="[ADMIN] Sent feedback request to {}/{} humans.".format( count, len(audience)))
def send_reminders(hours_of_day: list): audience = get_all_humans_for_telegram_notifications( hours_of_day=hours_of_day) # create bot bot = get_telegram_bot_instance() # send to audience notify_admin = True count = 0 for member in audience: try: bot.send_message( chat_id=member[HumanProperties.TELEGRAM_HUMAN_ID.value], text= "👇 Remember to report your location (always) and symptoms (if any) 👇", reply_markup=get_telegram_menu()) except Exception as e: if notify_admin: bot.send_message( chat_id=int( CONFIG.get('telegram-credentials-telegram-admin-id')), text="[ADMIN] `send_reminders` exception : {}".format(e)) notify_admin = False # try to unsubscribe try: human = Human(human_id=member[HumanProperties.ID.value]) human.unsubscribe() except Exception as unsb_e: pass else: count += 1 # alert admin bot.send_message(chat_id=int( CONFIG.get('telegram-credentials-telegram-admin-id')), text="[ADMIN] Sent reminder to {}/{} humans.".format( count, len(audience)))
def local_map(human_id): try: human = Human(human_id=human_id) except Exception as e: logger.error(e) abort(403) # get most recent coordinates most_recent_location = human.get_most_recent_location() if most_recent_location is None: return "Nothing to show. Share your location first.", 200 else: lat, lng = most_recent_location self_lat_lng = [lng, lat] self_geojson_feature = { 'type': "Point", 'coordinates': self_lat_lng } risky_humans_geojson = get_risky_humans_geojson( lat=lat, lng=lng, days_window=int(CONFIG.get('days_window')), km_radius=int(CONFIG.get('km_radius')) ) return render_template( MAP_TEMPLATE, self_geojson_feature=self_geojson_feature, self_lat_lng=self_lat_lng, risky_humans_geojson=risky_humans_geojson, km_radius=int(CONFIG.get('km_radius')), include_legend=True, zoom_level=9 )
def fulfill_intent(intent: str, human_id: str) -> bool: if human_id is None: return False human = Human(human_id=human_id) if "Report fever" in intent: return fulfill_log_symptom(human=human, symptom_name=Symptoms.FEVER.value) elif "Report cough" in intent: return fulfill_log_symptom(human=human, symptom_name=Symptoms.COUGH.value) elif "Report shortness of breath" in intent: return fulfill_log_symptom(human=human, symptom_name=Symptoms.SHORTNESS_OF_BREATH.value) elif "My Map" in intent: return fulfill_my_map_request(human=human) elif "Help" in intent: return fulfill_help_request(human=human) return True
def fulfill_telegram_command(telegram_command: TelegramCommand, human_id: str): if not isinstance(telegram_command, TelegramCommand): logger.error( TypeError("Expected `telegram_command` to be of type TelegramCommand. Got {}".format( type(telegram_command) )) ) if human_id is None: return False human = Human(human_id=human_id) if not TelegramBotCommand.has_value(telegram_command.command): return fulfill_invalid_telegram_command(human=human) elif telegram_command.command == TelegramBotCommand.START.value: return fulfill_start_telegram_command(human=human) elif telegram_command.command == TelegramBotCommand.HELP.value: return fulfill_help_request(human=human) elif telegram_command.command == TelegramBotCommand.REPORT.value: return fulfill_report_telegram_command(human=human) elif telegram_command.command == TelegramBotCommand.MY_MAP.value: return fulfill_my_map_request(human=human) return True
def process_telegram_update(update: Update): bot = get_telegram_bot_instance() # get payload attributes if update.callback_query is not None: telegram_human_id = int(update.callback_query.from_user.id) telegram_message_timestamp = datetime.datetime.fromtimestamp(update.callback_query.message.date) telegram_message_id = int(update.callback_query.message.message_id) try: bot.delete_message(chat_id=telegram_human_id, message_id=telegram_message_id) except Exception as e: pass elif update.message is not None: telegram_human_id = int(update.message.from_user.id) telegram_message_timestamp = datetime.datetime.fromtimestamp(update.message.date) telegram_message_id = int(update.message.message_id) else: return '', 204 # typing animation try: bot.send_chat_action( chat_id=telegram_human_id, action='typing' ) except Exception as e: return '', 204 else: time.sleep(0.1) # detect action type is_message = False is_callback = False callback_data = None message_content_type = None message_is_command = False message_text = None telegram_command = None is_reply = False reply_to_message_id = None if update.callback_query is not None: # fetch callback data callback_data = update.callback_query.data is_callback = True if update.message is not None: # set flag is_message = True is_reply = update.message.reply_to_message is not None if is_reply: reply_to_message_id = update.message.reply_to_message.message_id # fetch message content type message_content_type = update.message.content_type # case message is text if message_content_type == 'text': message_text = update.message.text # case message is Telegram command if TelegramCommand.is_telegram_command(data=message_text): telegram_command = TelegramCommand(data=message_text) message_is_command = True logger.debug("[TELEGRAM WEBHOOK REQUEST] human : {}".format(telegram_human_id)) logger.debug("[TELEGRAM WEBHOOK REQUEST] timestamp : {}".format(telegram_message_timestamp)) logger.debug("[TELEGRAM WEBHOOK REQUEST] message : {}".format(telegram_message_id)) # authenticate human human_exists, human_id = verify_telegram_id_exists(telegram_human_id=telegram_human_id) # log message if is_callback: action_type = CONFIG.get('INTENT-ACTION') action_value = callback_data elif is_message: if message_is_command: action_type = CONFIG.get('TELEGRAM-COMMAND') action_value = telegram_command.command else: action_type = message_content_type action_value = message_text log_action( human_id=human_id, telegram_human_id=telegram_human_id, from_human=True, action_type=action_type, action_value=action_value, local_timestamp=telegram_message_timestamp, message_id=telegram_message_id ) # redirect to landing unless if human_exists: # fetch human human = Human(human_id=human_id) else: try: log_sent_message(bot.send_message( chat_id=telegram_human_id, text="Welcome to Opendemic!", reply_markup=get_telegram_menu() ), human_id=human_id) except Exception as e: return '', 204 else: human, err = create_human(telegram_human_id=telegram_human_id) if err is not None: logger.error(err) return '', 204 log_sent_message(bot.send_message( chat_id=telegram_human_id, text=""" *Opendemic* is an non-profit anonymous COVID-19 proximity alert system. Here is how it works ⬇️: 1. Anonymously share your location and symptoms as much as you can (we'll send you reminders to prompt you) 2. You'll get an alert if you've been in close proximity to a potential COVID-19 case 3. *Opendemic* will only share anonymous data with public health authorities """, parse_mode='markdown', reply_markup=get_telegram_menu() ), human_id=human_id) return '', 204 # case callback if is_callback: # process callback fulfill_intent( intent=callback_data, human_id=human_id ) elif is_message: # case text if message_content_type == 'text': # case command if message_is_command: # process command fulfill_telegram_command( telegram_command=telegram_command, human_id=human_id ) # case free-form message else: if is_reply: log_action( human_id=human_id, telegram_human_id=telegram_human_id, from_human=True, action_type="REPLY_TO[{}]".format(reply_to_message_id), action_value=message_text, local_timestamp=telegram_message_timestamp, message_id=telegram_message_id, tag=CONFIG.get('REFER-REPLY-ACTION') ) else: valid_intent = fulfill_intent( intent=message_text, human_id=human_id ) if not valid_intent: try: log_sent_message(bot.send_message( chat_id=telegram_human_id, text="Please use '/' commands to communicate with *Opendemic*.", parse_mode="Markdown" ), human_id=human_id) except Exception as e: return '', 204 # case location elif message_content_type == 'location': try: log_sent_message(bot.reply_to( message=update.message, text=random.choice([ "Thanks for sharing your location 🙏", "Great, got it!", "Thanks! We'll keep that secure." ]) ), human_id=human_id) except Exception as e: return '', 204 else: human.log_location( latitude=update.message.location.latitude, longitude=update.message.location.longitude ) # case photo elif message_content_type == 'photo': try: log_sent_message(bot.reply_to( message=update.message, text=random.choice([ "Thanks for the pic! But we can't process it just yet.", "Cannot process photos just yet, though we are sure that's a great pic!" ]) ), human_id=human_id) log_sent_message(bot.send_message( chat_id=telegram_human_id, text="Please use '/' commands to communicate with *Opendemic*.", parse_mode="Markdown" ), human_id=human_id) except Exception: return '', 204 # case documents elif message_content_type == 'document': try: log_sent_message(bot.reply_to( message=update.message, text=random.choice([ "Thanks for the document! But we can't process it just yet.", "Cannot process photos just yet, though we are sure that's a great document!" ]) ), human_id=human_id) log_sent_message(bot.send_message( chat_id=telegram_human_id, text="Please use '/' commands to communicate with *Opendemic*.", parse_mode="Markdown" ), human_id=human_id) except Exception as e: return '', 204 # case sticker elif message_content_type == 'sticker': try: log_sent_message(bot.reply_to( message=update.message, text=random.choice([ "Thanks for the sticker! But we can't process it just yet.", "Cannot process stickers just yet, though that looks like a great sticker!" ]) ), human_id=human_id) log_sent_message(bot.send_message( chat_id=telegram_human_id, text="Please use '/' commands to communicate with *Opendemic*.", parse_mode="Markdown" ), human_id=human_id) except Exception: return '', 204 return '', 204