def search_release(update: Update, status_to_return_on_invalid_query=ConversationHandler.END): if len(update.message.text) < 3: update.message.reply_text(Strings.RELEASE_TOO_SHORT) logger.debug('returning status: %d', status_to_return_on_invalid_query) return status_to_return_on_invalid_query releases = db.search(update.message.text)[:64] if not releases: update.message.reply_text(Strings.RELEASES_EMPTY, reply_markup=Keyboard.HIDE, quote=True) logger.debug('returning status: %d', status_to_return_on_invalid_query) return status_to_return_on_invalid_query else: markup = Keyboard.from_list([ '{id}. {titolo} • {dimensione_no_decimal} [{descrizione}]'.format( **release) for release in releases ]) update.message.reply_text(Strings.SELECT_RELEASE, reply_markup=markup) logger.debug('returning status: %d', WAITING_RELEASE_SELECTION_FROM_KB) return WAITING_RELEASE_SELECTION_FROM_KB
def on_pack_name(update: Update, context: CallbackContext): logger.info('user selected the pack name from the keyboard') logger.debug('user_data: %s', context.user_data) if re.search(r'^GO BACK$', update.message.text, re.I): with session_scope() as session: pack_titles = [t.title for t in session.query(Pack.title).filter_by(user_id=update.effective_user.id).all()] markup = Keyboard.from_list(pack_titles) update.message.reply_text(Strings.ADD_STICKER_SELECT_PACK, reply_markup=markup) return Status.WAITING_TITLE # the buttons list has the name without "_by_botusername" selected_name = '{}_by_{}'.format(update.message.text, context.bot.username) with session_scope() as session: pack = session.query(Pack).filter_by(name=selected_name, user_id=update.effective_user.id).first().name pack_name = pack.name pack_animated = pack.is_animated if not pack_name: logger.error('user %d does not have any pack with name %s', update.effective_user.id, selected_name) update.message.reply_text(Strings.ADD_STICKER_SELECTED_NAME_DOESNT_EXIST) # do not reset the user status return Status.WAITING_NAME logger.info('selected pack is animated: %s', pack_animated) context.user_data['pack'] = dict(name=pack_name, animated=pack_animated) pack_link = utils.name2link(pack_name) base_string = Strings.ADD_STICKER_PACK_SELECTED_STATIC if not pack_animated else Strings.ADD_STICKER_PACK_SELECTED_ANIMATED update.message.reply_html(base_string.format(pack_link), reply_markup=Keyboard.HIDE) return Status.WAITING_STATIC_STICKERS
def on_add_command(update: Update, _): logger.info('/add') with session_scope() as session: pack_titles = [t.title for t in session.query(Pack.title).filter_by(user_id=update.effective_user.id).all()] if not pack_titles: update.message.reply_text(Strings.ADD_STICKER_NO_PACKS) return ConversationHandler.END else: markup = Keyboard.from_list(pack_titles) update.message.reply_text(Strings.ADD_STICKER_SELECT_PACK, reply_markup=markup) return Status.WAITING_TITLE
def search_release(update: Update, status_to_return_on_invalid_query=ConversationHandler.END): if len(update.message.text) < 3: update.message.reply_text(Strings.RELEASE_TOO_SHORT) return status_to_return_on_invalid_query releases = db.search(update.message.text, as_dict=True)[:64] if not releases: update.message.reply_text(Strings.RELEASES_EMPTY, reply_markup=Keyboard.HIDE, quote=True) return status_to_return_on_invalid_query else: markup = Keyboard.from_list(['{id}. {titolo}'.format(**release) for release in releases]) update.message.reply_text(Strings.SELECT_RELEASE, reply_markup=markup) return WAITING_RELEASE
def on_pack_title(update: Update, context: CallbackContext): logger.info('user selected the pack title from the keyboard') selected_title = update.message.text user_id = update.effective_user.id with session_scope() as session: packs_by_title = session.query(Pack).filter_by(title=selected_title, user_id=user_id).order_by(Pack.name).all() # for some reason, accessing a Pack attribute outside of a session # raises an error: https://docs.sqlalchemy.org/en/13/errors.html#object-relational-mapping # so we preload the list here in case we're going to need it later, to avoid a more complex handling # of the session by_bot_part = '_by_' + context.bot.username pack_names = [pack.name.replace(by_bot_part, '', 1) for pack in packs_by_title] # strip the '_by_bot' part pack_animated = packs_by_title[0].is_animated # we need this in case there's only one pack and we need to know whether it is animated or not if not packs_by_title: logger.error('cannot find any pack with this title: %s', selected_title) update.message.reply_text(Strings.ADD_STICKER_SELECTED_TITLE_DOESNT_EXIST.format(selected_title[:150])) # do not change the user status return Status.ADD_WAITING_TITLE if len(packs_by_title) > 1: logger.info('user has multiple packs with this title: %s', selected_title) markup = Keyboard.from_list(pack_names, add_back_button=True) # list with the links to the involved packs pack_links = ['<a href="{}">{}</a>'.format(utils.name2link(pack_name, bot_username=context.bot.username), pack_name) for pack_name in pack_names] text = Strings.ADD_STICKER_SELECTED_TITLE_MULTIPLE.format(selected_title, '\n• '.join(pack_links)) update.message.reply_html(text, reply_markup=markup) return Status.ADD_WAITING_NAME # we now have to wait for the user to tap on a pack name logger.info('there is only one pack with the selected title (animated: %s), proceeding...', pack_animated) pack_name = '{}_by_{}'.format(pack_names[0], context.bot.username) context.user_data['pack'] = dict(name=pack_name, animated=pack_animated) pack_link = utils.name2link(pack_name) base_string = Strings.ADD_STICKER_PACK_SELECTED_STATIC if not pack_animated else Strings.ADD_STICKER_PACK_SELECTED_ANIMATED update.message.reply_html(base_string.format(pack_link), reply_markup=Keyboard.HIDE) if pack_animated: return Status.WAITING_ANIMATED_STICKERS else: return Status.WAITING_STATIC_STICKERS
def add_sticker_to_set(update: Update, context: CallbackContext, animated_pack): name = context.user_data['pack'].get('name', None) if not name: logger.error('pack name missing (%s)', name) update.message.reply_text(Strings.ADD_STICKER_PACK_DATA_MISSING) context.user_data.pop('pack', None) # remove temp info return ConversationHandler.END user_emojis = context.user_data['pack'].pop('emojis', None) # we also remove them sticker = StickerFile(bot=context.bot, message=update.message, emojis=user_emojis) sticker.download(prepare_png=True) pack_link = utils.name2link(name) # we edit this flag so the 'finally' statement can end the conversation if needed by an 'except' end_conversation = False try: logger.debug('executing request...') sticker.add_to_set(name) except error.PackFull: max_pack_size = MAX_PACK_SIZE_ANIMATED if animated_pack else MAX_PACK_SIZE_STATIC update.message.reply_html(Strings.ADD_STICKER_PACK_FULL.format( pack_link, max_pack_size), quote=True) end_conversation = True # end the conversation when a pack is full except error.FileDimensionInvalid: logger.error('resized sticker has the wrong size: %s', str(sticker)) update.message.reply_html( Strings.ADD_STICKER_SIZE_ERROR.format(*sticker.size), quote=True) except error.InvalidAnimatedSticker: update.message.reply_html(Strings.ADD_STICKER_INVALID_ANIMATED, quote=True, disable_web_page_preview=True) except error.PackInvalid: # pack name invalid or that pack has been deleted: delete it from the db with session_scope() as session: deleted_rows = session.query(Pack).filter( Pack.user_id == update.effective_user.id, Pack.name == name).delete('fetch') logger.debug('rows deleted: %d', deleted_rows or 0) # get the remaining packs' titles pack_titles = [ t.title for t in session.query(Pack.title).filter_by( user_id=update.effective_user.id).all() ] if not pack_titles: # user doesn't have any other pack to chose from, reset his status update.message.reply_html( Strings.ADD_STICKER_PACK_NOT_VALID_NO_PACKS.format(pack_link)) logger.debug('calling sticker.delete()...') sticker.close() return ConversationHandler.END else: # make the user select another pack from the keyboard markup = Keyboard.from_list(pack_titles) update.message.reply_html( Strings.ADD_STICKER_PACK_NOT_VALID.format(pack_link), reply_markup=markup) context.user_data['pack'].pop('name', None) # remove temporary data logger.debug('calling sticker.delete()...') sticker.close() return Status.ADD_WAITING_TITLE except error.UnknwonError as e: update.message.reply_html(Strings.ADD_STICKER_GENERIC_ERROR.format( pack_link, e.message), quote=True) except Exception as e: logger.error('non-telegram exception while adding a sticker to a set', exc_info=True) raise e # this is not raised else: if not user_emojis: text = Strings.ADD_STICKER_SUCCESS.format(pack_link) else: text = Strings.ADD_STICKER_SUCCESS_USER_EMOJIS.format( pack_link, ''.join(user_emojis)) update.message.reply_html(text, quote=True) finally: # this is entered even when we enter the 'else' or we return in an 'except' # https://stackoverflow.com/a/19805746 logger.debug('calling sticker.close()...') sticker.close() if end_conversation: return ConversationHandler.END if animated_pack: return Status.WAITING_ANIMATED_STICKERS else: return Status.WAITING_STATIC_STICKERS