Esempio n. 1
0
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
Esempio n. 3
0
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)))
Esempio n. 4
0
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