Beispiel #1
0
def request_language_setup(update: Update, context: CallbackContext) -> None:
    setup_state, _ = get_user_states(str(update.effective_chat.id))
    if setup_state is not SetupState.LANGUAGE_NOT_SET:
        logger.error('request_language_setup being called when state is not LANGUAGE_NOT_SET')
        return None

    if update.callback_query is None or update.callback_query.data not in _callback_query_options:
        reply_markup = InlineKeyboardMarkup(_lang_inline_keyboard_buttons)
        send_markup_msg(update, strings()["language:choose"], reply_markup)
    else:
        query = update.callback_query

        lang = Language(query.data.split("#")[1])
        if lang is Language.ENGLISH:
            set_strings(force_lang=Language.ENGLISH)
        else:
            set_strings(force_lang=Language.PORTUGUESE)

        set_language(chat_id=str(update.callback_query.message.chat.id),
                     lang=lang,
                     next_state=SetupState.TIMEZONE_NOT_SET)

        try:
            set_timezone(str(update.effective_chat.id), int(os.environ.get('TIMEZONE_SECONDS_OFFSET', None)),
                         SetupState.NONE)
            send_markup_msg(update, strings()['setup:complete'], options_kbd(strings()))
        except Exception as e:
            logger.warn(e)
            logger.warn('TIMEZONE_SECONDS_OFFSET not present or in wrong format.\n'
                        'Switching to fallback mode with google maps api.')
            edit_message(update, strings()['language:set'])
            send_message(update, strings()['timezone:request'])

    raise DispatcherHandlerStop
Beispiel #2
0
def request_clock_out_description(update: Update, context: CallbackContext):
    chat_id = update.effective_chat.id
    try:
        user_info = get_user_info(chat_id)
        msg_id = int(user_info['msg_reply_id'])
        clock_out_date = user_info['clock_out_date']
    except KeyError:
        return

    if not update.effective_message.reply_to_message or update.effective_message.reply_to_message.message_id != msg_id:
        try:
            update.effective_message.bot.delete_message(chat_id=chat_id,
                                                        message_id=msg_id)
        except BadRequest:
            logger.warn(
                'The message to be replied has been deleted by the user, but we\'ll try again'
            )
        msg = send_markup_msg(update,
                              strings()['feedback:exit:insist_reply'],
                              ForceReply(), True)
        set_clock_out_msg_reply_id(chat_id, msg.message_id)
        raise DispatcherHandlerStop
    else:
        replied_entry_description(chat_id, update.effective_message.text,
                                  clock_out_date)
        send_markup_msg(update,
                        strings()['feedback:exit:acknowledgment'],
                        options_kbd(strings()))
        remove_msg_reply_id(chat_id)
        raise DispatcherHandlerStop
Beispiel #3
0
def start(update: Update, context: CallbackContext):
    _, chat_state = get_user_states(str(update.effective_message.chat_id))
    if chat_state in _sensitive_states:
        logger.debug(f"Not letting user perform a restart because they're in {chat_state} state")
        send_markup_msg(update, strings()['start:prohibit'], options_kbd(strings()))
    else:
        create_or_reset_user(str(update.message.chat_id))
        request_language_setup(update, context)
    raise DispatcherHandlerStop
def ensure_valid_clocked_in(update: Update, context: CallbackContext):
    # if the chat_state is clocked_in but there are no records today, this means that
    # the user forgot to clock out the other day.
    chat_id = update.effective_chat.id
    if len(today_entries(chat_id)) == 0:
        user_info = get_user_info(chat_id)
        clocked_in_date = datetime.fromisoformat(user_info['clocked_in_date'])

        # we are in an inconsistent state
        # check if there's any msg waiting for a reply
        # if not, create one
        try:
            msg_id = int(user_info['msg_reply_id'])
            if not update.effective_message.reply_to_message \
                    or update.effective_message.reply_to_message.message_id != msg_id:
                try:
                    update.effective_message.bot.delete_message(chat_id=chat_id, message_id=msg_id)
                except BadRequest:
                    logger.warn('The message to be replied has been deleted by the user, but we\'ll try again')
                generate_reply(update, context, clocked_in_date.isoformat())
                raise DispatcherHandlerStop

            else:
                msg = update.effective_message.text
                time = msg.split('\n')[0]
                if len(time) != 5:  # hh:mm
                    raise ValueError('It should be in format hh:mm')

                hour, minute = int(time.split(':')[0]), int(time.split(':')[1])
                clock_out_date = clocked_in_date.replace(hour=hour, minute=minute,
                                                         microsecond=clocked_in_date.microsecond + 1).isoformat()
                description = msg.split('\n')[0].strip()

                if len(description) == 0:
                    raise ValueError('Description should not be empty')

                if clock_out_date < clocked_in_date.isoformat():
                    raise ValueError('Clock out date must be greater than the clock in date')

                create_full_entry(chat_id, clock_out_date, description)
                remove_msg_reply_id(chat_id)
                send_markup_msg(update, strings()['request:acknowledgment'], options_kbd(strings()))
                raise DispatcherHandlerStop
        except DispatcherHandlerStop:
            raise DispatcherHandlerStop
        except Exception as e:
            logger.error(e)
            generate_reply(update, context, clocked_in_date.isoformat())
            raise DispatcherHandlerStop
        finally:
            raise DispatcherHandlerStop
Beispiel #5
0
def request_timezone_setup(update: Update, context: CallbackContext) -> None:
    state, _ = get_user_states(str(update.effective_chat.id))
    if state is not SetupState.TIMEZONE_NOT_SET:
        logger.error(
            'request_timezone_setup being called when state is not TIMEZONE_NOT_SET'
        )
        return

    if update.message is not None:
        try:
            tz = get_address_and_timezone_by_name(update.message.text)
            is_negative = "-" if tz['offset'] < 0 else ""
            pretty_offset = is_negative + str(
                timedelta(seconds=abs(tz['offset'])))[:-3]
            _inline_keyboard_buttons = [[
                InlineKeyboardButton(
                    strings()['button:yes'],
                    callback_data=f"timezone#yes#{pretty_offset}"),
                InlineKeyboardButton(strings()['button:no'],
                                     callback_data='timezone#no'),
            ]]
            reply_markup = InlineKeyboardMarkup(_inline_keyboard_buttons)
            tz_msg = f"regx*x{tz['timezone_id']}regx*x \nregx*xUTC{pretty_offset}regx*x\n"
            full_msg = strings()["timezone:location:confirm"].format(tz_msg)
            send_markup_msg(update, full_msg, reply_markup, True)
        except LocationNotFoundException:
            send_message(update, strings()['timezone:location:not_found'])
    else:
        query = update.callback_query
        if not any(cb_option in query.data
                   for cb_option in _callback_query_options):
            send_message(update, strings()['timezone:request'])
        else:
            if 'timezone#no' in query.data:
                send_message(update, strings()['timezone:request'])
            else:
                pretty_offset = query.data.split('#')[-1]
                hours, minutes = map(int, pretty_offset.split(':'))
                minutes = minutes if hours >= 0 else minutes * (-1)
                offset = (hours * 60 * 60) + (minutes * 60)
                set_timezone(str(update.effective_chat.id), offset,
                             SetupState.NONE)
                send_markup_msg(update,
                                strings()['setup:complete'],
                                options_kbd(strings()))
    raise DispatcherHandlerStop
Beispiel #6
0
def edit_choice_selector(update: Update, context: CallbackContext):
    kbd = [
        [InlineKeyboardButton(strings()['button:today'], callback_data='edit#today')],
        [InlineKeyboardButton(strings()['button:yesterday'], callback_data='edit#yesterday')],
        [InlineKeyboardButton(strings()['button:other'], callback_data='edit#other')],
    ]
    try:
        edit_message(update,
                     strings()['edit:choose:message'],
                     True,
                     InlineKeyboardMarkup(kbd))
    except BadRequest as e:
        send_markup_msg(
            update,
            strings()['edit:choose:message'],
            InlineKeyboardMarkup(kbd),
            True,
        )
    raise DispatcherHandlerStop
Beispiel #7
0
def clockin(update: Update, context: CallbackContext) -> None:
    chat_id = str(update.message.chat_id)
    _date = clock_in(chat_id)
    entries = today_entries(chat_id)
    if len(entries) % 2 == 0:
        msg = send_markup_msg(update,
                              strings()['feedback:exit'], ForceReply(), True)
        set_unreported_clock_out(chat_id, msg.message_id, _date)
        raise DispatcherHandlerStop
    else:
        send_message(update, strings()['feedback:entrance'])
        raise DispatcherHandlerStop
Beispiel #8
0
def choose_report(update: Update, context: CallbackContext) -> None:
    class InlineKeyboardOptions(Enum):
        TODAY = strings()['button:today']
        YESTERDAY = strings()['button:yesterday']
        WEEK = strings()['button:report:week']
        MONTH = strings()['button:report:month']
        LAST_WEEK = strings()['button:report:last_week']
        LAST_MONTH = strings()['button:report:last_month']

    inline_keyboard_buttons = [
        [
            InlineKeyboardButton(InlineKeyboardOptions.TODAY.value,
                                 callback_data="report#today")
        ],
        [
            InlineKeyboardButton(InlineKeyboardOptions.YESTERDAY.value,
                                 callback_data="report#yesterday")
        ],
        [
            InlineKeyboardButton(InlineKeyboardOptions.WEEK.value,
                                 callback_data="report#week")
        ],
        [
            InlineKeyboardButton(InlineKeyboardOptions.MONTH.value,
                                 callback_data="report#month")
        ],
        [
            InlineKeyboardButton(InlineKeyboardOptions.LAST_WEEK.value,
                                 callback_data="report#last_week")
        ],
        [
            InlineKeyboardButton(InlineKeyboardOptions.LAST_MONTH.value,
                                 callback_data="report#last_month")
        ],
    ]

    reply_markup = InlineKeyboardMarkup(inline_keyboard_buttons)
    send_markup_msg(update, strings()["report:period:choose"], reply_markup)
    raise DispatcherHandlerStop
def generate_reply(update: Update, context: CallbackContext, clocked_in_date: str) -> None:
    chat_id = update.effective_chat.id
    that_day_entries = _that_day_entries(chat_id, clocked_in_date)

    compiled_entries = [
        strings()['request:warning'],
        datetime.fromisoformat(clocked_in_date).strftime('%d/%m/%Y') + '\n',
        compile_entries(that_day_entries) + '\n',
        strings()['request:missing_entry']
    ]

    msg = send_markup_msg(update, "\n".join(compiled_entries), ForceReply(), True)
    set_msg_reply_id(chat_id, msg.message_id)
def delete(update: Update, context: CallbackContext):
    _del_inline_keyboard_buttons = [
        [
            InlineKeyboardButton(strings()['button:yes'],
                                 callback_data='delete#yes')
        ],
        [
            InlineKeyboardButton(strings()['button:no'],
                                 callback_data='delete#no')
        ],
    ]

    _callback_query_options = ['delete#yes', 'delete#no']

    chat_id = update.effective_chat.id
    if update.callback_query is None or update.callback_query.data not in _callback_query_options:
        reply_markup = InlineKeyboardMarkup(_del_inline_keyboard_buttons)
        send_markup_msg(update,
                        strings()["delete:confirm"], reply_markup, True)
        raise DispatcherHandlerStop
    else:
        if update.callback_query.data == 'delete#yes':
            deleted_user_entries = db.delete_user_entries(chat_id)
            deleted_user_info = db.delete_user_info(chat_id)
            if not deleted_user_entries and not deleted_user_info:
                update.effective_message.delete()
                send_markup_msg(
                    update,
                    strings()['delete:nothing'],
                    ReplyKeyboardMarkup([['/start']],
                                        resize_keyboard=True,
                                        one_time_keyboard=True))
            else:
                update.effective_message.delete()
                send_markup_msg(
                    update,
                    strings()['delete:success'],
                    ReplyKeyboardMarkup([['/start']],
                                        resize_keyboard=True,
                                        one_time_keyboard=True))
            raise DispatcherHandlerStop
        else:
            edit_message(update, strings()['delete:cancelled'])
            raise DispatcherHandlerStop
Beispiel #11
0
def default(update: Update, context: CallbackContext):
    send_markup_msg(update, strings()['default'], options_kbd(strings()))
    raise DispatcherHandlerStop
Beispiel #12
0
def help_message(update: Update, context: CallbackContext):
    send_markup_msg(update, strings()['help'], help_inline_kdb(), True)
    raise DispatcherHandlerStop
Beispiel #13
0
def options(update: Update, context: CallbackContext):
    send_markup_msg(update, strings()['options:choose'], options_inline_kdb())
    raise DispatcherHandlerStop