async def handler_call(message: types.Message): await check_access(message, grant=Grant.READ_ACCESS) match = constraints.REGEX_CMD_GROUP_MESSAGE.search(message.text) if not match: return await message.reply(md.text(md_style.bold("Пример вызова:"), md_style.code("/call group"), " ", md_style.bold("Ограничения:"), md.text( "group:", constraints.MESSAGE_FOR_GROUP), sep='\n'), parse_mode=ParseMode.MARKDOWN) group_name = match.group("group") with db.get_connection() as conn: group = db.select_group_by_alias_name(conn, chat_id=message.chat.id, alias_name=group_name) if not group: return await message.reply(md.text('Группа', md_style.code(group_name), 'не найдена!'), parse_mode=ParseMode.MARKDOWN) logging.info(f"group: {group}") members = db.select_members(conn, group_id=group.group_id) if len(members) == 0: return await message.reply('Группа пользователей пуста!') mentions = convert_members_to_mentions(members) await message.reply(" ".join(mentions), parse_mode=ParseMode.MARKDOWN)
async def handler_help(message: types.Message): await check_access(message, grant=Grant.READ_ACCESS) def prepare_commands(commands: Dict[str, str]) -> List[str]: return [ md.text(md.escape_md(f"/{x[0]}"), "—", x[1]) for x in commands.items() ] await message.reply(text=md.text( f"Привет, {message.from_user.get_mention()}! 👋", "", md_style.bold("Пример работы с ботом:"), md_style.code("/add_group group1"), md_style.code("/add_members group1 @user1 @user2 @user3"), md_style.code("/call group1"), "", md.text("Команда", md_style.italic("call"), "вызовет ранее добавленных пользователей из группы", md_style.italic("group1"), "вот в таком виде:"), md_style.code("@user1 @user2 @user3"), "", md_style.bold("Общие команды:"), *prepare_commands(COMMON_COMMANDS), "", md_style.bold("Административные команды:"), *prepare_commands(ADMIN_COMMANDS), sep='\n'), parse_mode=ParseMode.MARKDOWN)
async def handler_remove_group_alias(message: types.Message): await check_access(message, Grant.WRITE_ACCESS) match = constraints.REGEX_CMD_GROUP_ALIAS.search(message.text) if not match: return await message.reply(md.text( md_style.bold("Пример вызова:"), md_style.code("/remove_alias group alias"), " ", md_style.bold("Ограничения:"), md.text("group:", constraints.MESSAGE_FOR_GROUP), md.text("alias:", constraints.MESSAGE_FOR_GROUP), sep='\n'), parse_mode=ParseMode.MARKDOWN) group_name = match.group('group') alias_name = match.group('alias') with db.get_connection() as conn: db.select_chat_for_update(conn, chat_id=message.chat.id) group = db.select_group_by_alias_name(conn, chat_id=message.chat.id, alias_name=group_name) if not group: return await message.reply(md.text('Группа', md_style.code(group_name), 'не найдена!'), parse_mode=ParseMode.MARKDOWN) logging.info(f"group: {group}") group_aliases: Dict[str, GroupAlias] = { x.alias_name: x for x in db.select_group_aliases_by_group_id( conn, group_id=group.group_id) } if alias_name not in group_aliases: return await message.reply(md.text('Алиас', md_style.code(alias_name), 'не найден для группы', md_style.code(group_name)), parse_mode=ParseMode.MARKDOWN) group_alias = group_aliases[alias_name] if len(group_aliases) == 1: return await message.reply( md.text("Нельзя удалить единственное название группы!"), parse_mode=ParseMode.MARKDOWN) db.delete_group_alias(conn, alias_id=group_alias.alias_id) await message.reply(md.text("Алиас", md_style.code(alias_name), "удалён из группы", md_style.code(group_name)), parse_mode=ParseMode.MARKDOWN)
async def handler_remove_members(message: types.Message): await check_access(message, Grant.WRITE_ACCESS) match = constraints.REGEX_CMD_GROUP_MEMBERS.search(message.text) if not match: return await message.reply(md.text( md_style.bold("Пример вызова:"), md_style.code("/remove_members group username1 username2"), " ", md_style.bold("Ограничения:"), md.text("group:", constraints.MESSAGE_FOR_GROUP), md.text("username:"******"group: {group}") mentions = [ x.get_text(message.text) for x in message.entities if x.type == MessageEntityType.MENTION ] text_mentions = [ f"[{x.user.full_name}]({x.user.url})" for x in message.entities if x.type == MessageEntityType.TEXT_MENTION ] all_members = mentions + text_mentions logging.info(f"members: {all_members}") if len(all_members) < 1: return await message.reply( 'Нужно указать хотя бы одного пользователя!') for member in all_members: db.delete_member(conn, group_id=group.group_id, member_name=member) await message.reply(md.text(md.text("Пользователи удалённые из группы", md_style.code(group_name)), md_style.code("\n".join( [f"- {x}" for x in all_members])), sep='\n'), parse_mode=ParseMode.MARKDOWN)
async def handler_add_group_alias(message: types.Message): await check_access(message, Grant.WRITE_ACCESS) match = constraints.REGEX_CMD_GROUP_ALIAS.search(message.text) if not match: return await message.reply(md.text( md_style.bold("Пример вызова:"), md_style.code("/add_alias group alias"), " ", md_style.bold("Ограничения:"), md.text("group:", constraints.MESSAGE_FOR_GROUP), md.text("alias:", constraints.MESSAGE_FOR_GROUP), sep='\n'), parse_mode=ParseMode.MARKDOWN) group_name = match.group('group') group_alias = match.group('alias') if len(group_alias) > constraints.MAX_GROUP_NAME_LENGTH: return await message.reply('Слишком длинное название группы!') with db.get_connection() as conn: db.select_chat_for_update(conn, chat_id=message.chat.id) group = db.select_group_by_alias_name(conn, chat_id=message.chat.id, alias_name=group_name) if not group: return await message.reply(md.text('Группа', md_style.code(group_name), 'не найдена!'), parse_mode=ParseMode.MARKDOWN) logging.info(f"group: {group}") aliases: List[GroupAlias] = db.select_group_aliases_by_chat_id( conn, chat_id=message.chat.id) if group_alias in set(x.alias_name for x in aliases): return await message.reply("Такой алиас уже используется!") if len([x for x in aliases if x.group_id == group.group_id ]) >= constraints.MAX_ALIASES_PER_GROUP: return await message.reply( f"Нельзя добавить так много алиасов!" f" Текущее ограничение для одной группы: {constraints.MAX_ALIASES_PER_GROUP}" ) db.insert_group_alias(conn, chat_id=message.chat.id, group_id=group.group_id, alias_name=group_alias) await message.reply(md.text("Для группы", md_style.code(group_name), "добавлен алиас", md_style.code(group_alias)), parse_mode=ParseMode.MARKDOWN)
async def handler_list_groups(message: types.Message): await check_access(message, grant=Grant.READ_ACCESS) with db.get_connection() as conn: aliases: List[GroupAlias] = db.select_group_aliases_by_chat_id( conn, chat_id=message.chat.id) if len(aliases) == 0: return await message.reply("Нет ни одной группы.", parse_mode=ParseMode.MARKDOWN) aliases_lookup: Dict[int, List[GroupAlias]] = {} for a in aliases: aliases_lookup.setdefault(a.group_id, []).append(a) groups_for_print = [] for group_id in sorted({x.group_id for x in aliases}): group_aliases = sorted(aliases_lookup.get(group_id, []), key=lambda x: x.alias_id) group_aliases = [x.alias_name for x in group_aliases] head, *tail = group_aliases tail = f" (синонимы: {', '.join(tail)})" if len(tail) > 0 else "" groups_for_print.append(f"- {head}{tail}") await message.reply(md.text(md_style.bold("Вот такие группы существуют:"), md_style.code("\n".join(groups_for_print)), sep='\n'), parse_mode=ParseMode.MARKDOWN)
async def handler_add_group(message: types.Message): await check_access(message, Grant.WRITE_ACCESS) match = constraints.REGEX_CMD_GROUP.search(message.text) if not match: return await message.reply(md.text(md_style.bold("Пример вызова:"), md_style.code("/add_group group"), " ", md_style.bold("Ограничения:"), md.text( "group:", constraints.MESSAGE_FOR_GROUP), sep='\n'), parse_mode=ParseMode.MARKDOWN) group_name = match.group("group") if len(group_name) > constraints.MAX_GROUP_NAME_LENGTH: return await message.reply('Слишком длинное название группы!') with db.get_connection() as conn: db.insert_chat(conn, chat_id=message.chat.id, chat_title=message.chat.title, chat_username=message.chat.username) db.select_chat_for_update(conn, chat_id=message.chat.id) existing_groups: List[GroupAlias] = db.select_group_aliases_by_chat_id( conn, chat_id=message.chat.id) if group_name in {x.alias_name for x in existing_groups}: return await message.reply('Такая группа уже существует!') if len({x.group_id for x in existing_groups}) >= constraints.MAX_GROUPS_PER_CHAT: return await message.reply( f'Слишком много групп уже создано!' f' Текущее ограничение для чата: {constraints.MAX_GROUPS_PER_CHAT}' ) group_id = db.insert_group(conn, chat_id=message.chat.id) db.insert_group_alias(conn, chat_id=message.chat.id, group_id=group_id, alias_name=group_name) await message.reply(md.text("Группа", md_style.code(group_name), "добавлена!"), parse_mode=ParseMode.MARKDOWN)
async def handler_list_members(message: types.Message): await check_access(message, grant=Grant.READ_ACCESS) match = constraints.REGEX_CMD_GROUP.search(message.text) if not match: return await message.reply(md.text(md_style.bold("Пример вызова:"), md_style.code("/members group"), " ", md_style.bold("Ограничения:"), md.text( "group:", constraints.MESSAGE_FOR_GROUP), sep='\n'), parse_mode=ParseMode.MARKDOWN) group_name = match.group("group") with db.get_connection() as conn: group = db.select_group_by_alias_name(conn, chat_id=message.chat.id, alias_name=group_name) if not group: return await message.reply(md.text('Группа', md_style.code(group_name), 'не найдена!'), parse_mode=ParseMode.MARKDOWN) members = db.select_members(conn, group_id=group.group_id) members = sorted(convert_members_to_names(members)) logging.info(f"members: {members}") if len(members) == 0: text = md.text( "В группе", md_style.code(group_name), "нет ни одного пользователя!", ) else: text = md.text(md.text(md_style.bold("Участники группы"), md_style.code(group_name)), md_style.code("\n".join([f"- {x}" for x in members])), sep='\n') await message.reply(text, parse_mode=ParseMode.MARKDOWN)
async def handler_remove_group(message: types.Message): await check_access(message, Grant.WRITE_ACCESS) match = constraints.REGEX_CMD_GROUP.search(message.text) if not match: return await message.reply(md.text( md_style.bold("Пример вызова:"), md_style.code("/remove_group group"), " ", md_style.bold("Ограничения:"), md.text("group:", constraints.MESSAGE_FOR_GROUP), sep='\n'), parse_mode=ParseMode.MARKDOWN) group_name = match.group("group") with db.get_connection() as conn: db.select_chat_for_update(conn, chat_id=message.chat.id) group = db.select_group_by_alias_name(conn, chat_id=message.chat.id, alias_name=group_name) if not group: return await message.reply(md.text('Группа', md_style.code(group_name), 'не найдена!'), parse_mode=ParseMode.MARKDOWN) logging.info(f"group: {group}") members = db.select_members(conn, group.group_id) if len(members) != 0: logging.info(f"members: {members}") return await message.reply( 'Группу нельзя удалить, в ней есть пользователи!') group_aliases = db.select_group_aliases_by_group_id( conn, group_id=group.group_id) for a in group_aliases: db.delete_group_alias(conn, alias_id=a.alias_id) db.delete_group(conn, group_id=group.group_id) await message.reply(md.text("Группа", md_style.bold(group_name), "удалена!"), parse_mode=ParseMode.MARKDOWN)
async def handler_xcall(message: types.Message): await check_access(message, grant=Grant.READ_ACCESS) with db.get_connection() as conn: aliases: List[GroupAlias] = db.select_group_aliases_by_chat_id( conn, chat_id=message.chat.id) if len(aliases) == 0: return await message.reply("Нет ни одной группы.", parse_mode=ParseMode.MARKDOWN) aliases_lookup: Dict[int, List[GroupAlias]] = {} for a in aliases: aliases_lookup.setdefault(a.group_id, []).append(a) inline_keyboard = InlineKeyboardMarkup() inline_keyboard.add( InlineKeyboardButton(text="✖ Отмена ✖", callback_data=CallbackData( type=CallbackType.CANCEL, user_id=message.from_user.id).serialize())) groups_for_print = [] for group_id in sorted({x.group_id for x in aliases}): group_aliases = sorted(aliases_lookup.get(group_id, []), key=lambda x: x.alias_id) group_aliases = [x.alias_name for x in group_aliases] head, *tail = group_aliases tail = f" (синонимы: {', '.join(tail)})" if len(tail) > 0 else "" groups_for_print.append(f"{head}{tail}") inline_keyboard.add( InlineKeyboardButton(text=f"{head}{tail}", callback_data=CallbackData( type=CallbackType.SELECT_GROUP, user_id=message.from_user.id, group_id=group_id).serialize())) await message.reply(md_style.bold("Выберите группу"), parse_mode=ParseMode.MARKDOWN, reply_markup=inline_keyboard)
async def handler_add_members(message: types.Message): await check_access(message, Grant.WRITE_ACCESS) match = constraints.REGEX_CMD_GROUP_MEMBERS.search(message.text) if not match: return await message.reply(md.text( md_style.bold("Пример вызова:"), md_style.code("/add_members group username1 username2"), " ", md_style.bold("Ограничения:"), md.text("group:", constraints.MESSAGE_FOR_GROUP), md.text("username:"******"members: {all_members}") if len(all_members) < 1: return await message.reply('Нужно указать хотя бы одного пользователя!' ) with db.get_connection() as conn: db.select_chat_for_update(conn, chat_id=message.chat.id) group = db.select_group_by_alias_name(conn, chat_id=message.chat.id, alias_name=group_name) if not group: return await message.reply(md.text('Группа', md_style.code(group_name), 'не найдена!'), parse_mode=ParseMode.MARKDOWN) logging.info(f"group: {group}") existing_members: List[Member] = db.select_members( conn, group_id=group.group_id) if len(existing_members) + len( all_members) > constraints.MAX_MEMBERS_PER_GROUP: return await message.reply( f'Слишком много пользователей уже добавлено в группу!' f' Текущее ограничение для одной группы: {constraints.MAX_MEMBERS_PER_GROUP}' ) for member in all_members: db.insert_member(conn, group_id=group.group_id, member=member) await message.reply(md.text( md.text( "Пользователи добавленные в группу", md_style.code(group_name), ), md_style.code("\n".join( [f"- {x}" for x in convert_members_to_names(all_members)])), sep='\n'), parse_mode=ParseMode.MARKDOWN)