def validate_edited_registries(update: Update, context: CallbackContext): try: chat_id = update.effective_chat.id user_info = get_user_info(chat_id) editing_day = datetime.fromisoformat(user_info['editing_day']) offset = user_info['utc_delta_seconds'] _now = datetime.utcnow() + timedelta(seconds=int(offset)) split_message = (update.effective_message.text + '\n').split('\n') i = (list(g) for _, g in groupby(split_message, key=''.__ne__)) chunks = [a + b for a, b in zip(i, i)] last_clock_out = editing_day - timedelta(microseconds=1) entries = [] for chunk in chunks: _e, last_clock_out = parse_and_validate_chunk(chunk, last_clock_out, editing_day, chat_id) entries = [*entries, *_e] # delete before inserting new ones of that day delete_that_day_entries(chat_id, editing_day) list(map(lambda _e: create_full_entry(**_e), entries)) send_markdown_msg(update, strings()['edit:done']) _cancel_edit(chat_id) raise DispatcherHandlerStop except DispatcherHandlerStop: raise except Exception as e: logger.error(f"User sent data in wrong format {e}") msg = "\n".join([ strings()['edit:request:entry:wrong_format'], strings()['edit:request:model'], strings()['edit:suggest:cancel'], ]) send_markdown_msg(update, msg) finally: raise DispatcherHandlerStop
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
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
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
def validate_picked_day(update: Update, context: CallbackContext): try: chat_id = update.effective_chat.id day, month, year = map(int, update.effective_message.text.split('/')) _date = datetime.combine(date(year=year, month=month, day=day), time()) entries = that_day_entries(chat_id, _date.isoformat()) set_edit_day(chat_id, _date.isoformat()) edit_entry_request(update, context, entries) except DispatcherHandlerStop: raise except Exception as e: logger.error(e) msg = "\n".join([ strings()['edit:request:date:wrong_format'], strings()['edit:request:date_model'], strings()['edit:suggest:cancel'], ]) send_markdown_msg(update, msg) finally: raise DispatcherHandlerStop
def error_handler(update: object, context: CallbackContext): logger.error(context.error) pprint(update) raise context.error