Add custom emoji mapping system for premium emoji support
Some checks failed
continuous-integration/drone/pr Build is failing
Some checks failed
continuous-integration/drone/pr Build is failing
- Create emoji_mappings table to store emoji->emoji_id mappings - Add EmojiMappingService for managing emoji registration and replacement - Add admin emoji handlers (/add_emoji, /my_emojis, /delete_emoji, /all_emojis) - Create emoji message helper for automatic emoji processing - Add Alembic migration for emoji_mappings table - Integrate emoji router into main dispatcher - Add comprehensive documentation (EMOJI_SYSTEM.md) - Fix migration chain issue with merge_migration Features: - Admins can register premium emojis via /add_emoji command - Automatic emoji->emoji_id replacement before sending messages - Per-admin unique constraint on emoji registration - Track last used timestamp for analytics - Bulk operations support
This commit is contained in:
244
docs/EMOJI_SYSTEM.md
Normal file
244
docs/EMOJI_SYSTEM.md
Normal file
@@ -0,0 +1,244 @@
|
||||
# Система управления кастомными эмодзи
|
||||
|
||||
## Обзор
|
||||
|
||||
Система позволяет администраторам регистрировать премиум эмодзи и использовать их в сообщениях бота. Когда админ отправляет эмодзи боту:
|
||||
|
||||
1. Бот получает `emoji_id` от Telegram API
|
||||
2. Сохраняет эмодзи в таблице `emoji_mappings`
|
||||
3. При отправке сообщений в чаты бот автоматически использует `emoji_id` вместо текста эмодзи
|
||||
|
||||
Это обеспечивает, что эмодзи будут выглядеть точно так же, как их отправил админ, даже если это премиум эмодзи.
|
||||
|
||||
## Команды администратора
|
||||
|
||||
### 1. Добавить новый эмодзи
|
||||
|
||||
```
|
||||
/add_emoji
|
||||
```
|
||||
|
||||
Процесс:
|
||||
1. Админ запускает команду `/add_emoji`
|
||||
2. Бот просит отправить эмодзи
|
||||
3. Админ отправляет эмодзи (например, 🎲)
|
||||
4. Бот просит описание (для чего используется)
|
||||
5. Админ отправляет描述 (например, "Для лотереи")
|
||||
6. Бот сохраняет в БД и подтверждает
|
||||
|
||||
### 2. Просмотр своих эмодзи
|
||||
|
||||
```
|
||||
/my_emojis
|
||||
```
|
||||
|
||||
Показывает все эмодзи, добавленные этим админом:
|
||||
- Сам эмодзи
|
||||
- Описание
|
||||
- ID (первые 30 символов)
|
||||
- Дату добавления
|
||||
|
||||
### 3. Просмотр всех эмодзи в системе
|
||||
|
||||
```
|
||||
/all_emojis
|
||||
```
|
||||
|
||||
Показывает все эмодзи всех админов с информацией об администраторе
|
||||
|
||||
### 4. Удалить эмодзи
|
||||
|
||||
```
|
||||
/delete_emoji
|
||||
```
|
||||
|
||||
Админ может удалить только свои эмодзи. Процесс:
|
||||
1. Вызвать команду
|
||||
2. Выбрать эмодзи из список (кнопки)
|
||||
3. Бот удалит из БД
|
||||
|
||||
## Использование в коде
|
||||
|
||||
### Простой способ - прямое использование эмодзи
|
||||
|
||||
```python
|
||||
from aiogram.types import Message
|
||||
|
||||
async def handler(message: Message):
|
||||
await message.answer(
|
||||
text="🎲 Добро пожаловать на лотерею! 🏆",
|
||||
parse_mode="HTML"
|
||||
)
|
||||
```
|
||||
|
||||
### С обработкой эмодзи
|
||||
|
||||
```python
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
from src.core.emoji_message_helper import get_emoji_aware_text
|
||||
from aiogram.types import Message
|
||||
|
||||
async def handler(message: Message, session: AsyncSession):
|
||||
# Текст с эмодзи
|
||||
original_text = "🎲 Выиграли! 🏆"
|
||||
|
||||
# Обработаны текст (эмодзи заменены на ID для корректного отображения)
|
||||
processed_text = await get_emoji_aware_text(session, original_text)
|
||||
|
||||
await message.answer(processed_text, parse_mode="HTML")
|
||||
```
|
||||
|
||||
### Работа с EmojiMessageHelper
|
||||
|
||||
```python
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
from src.core.emoji_message_helper import EmojiMessageHelper
|
||||
|
||||
async def handler(message: Message, session: AsyncSession):
|
||||
helper = EmojiMessageHelper(session)
|
||||
|
||||
# Обработка перед отправкой
|
||||
text = "🎲 Лотерея начинается! 💎"
|
||||
processed = await helper.process_text_before_send(text)
|
||||
|
||||
await message.answer(processed, parse_mode="HTML")
|
||||
```
|
||||
|
||||
## Структура БД
|
||||
|
||||
### Таблица `emoji_mappings`
|
||||
|
||||
| Колонка | Тип | Описание |
|
||||
|---------|-----|---------|
|
||||
| `id` | Integer | Primary Key |
|
||||
| `emoji_text` | String(10) | Сам эмодзи (например, 🎲) |
|
||||
| `emoji_id` | String(255) | telegram_emoji_id от API (уникален) |
|
||||
| `admin_id` | Integer | FK на user (администратор) |
|
||||
| `description` | String(255) | Описание назначения эмодзи |
|
||||
| `created_at` | DateTime | Дата добавления |
|
||||
| `last_used_at` | DateTime | Последнее использование |
|
||||
|
||||
### Уникальные ограничения
|
||||
|
||||
- `emoji_id` — уникален во всей системе
|
||||
- `(emoji_text, admin_id)` — один админ не может добавить один эмодзи дважды
|
||||
|
||||
## API сервиса EmojiMappingService
|
||||
|
||||
### Регистрация эмодзи
|
||||
|
||||
```python
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
from src.core.emoji_mapping_service import EmojiMappingService
|
||||
|
||||
async with async_session_maker() as session:
|
||||
service = EmojiMappingService(session)
|
||||
|
||||
emoji = await service.register_emoji(
|
||||
emoji_text="🎲",
|
||||
emoji_id="telegram_emoji_id_here",
|
||||
admin_id=12345,
|
||||
description="Для лотереи"
|
||||
)
|
||||
```
|
||||
|
||||
### Получение эмодзи
|
||||
|
||||
```python
|
||||
# По тексту
|
||||
emoji = await service.get_emoji_by_text("🎲")
|
||||
|
||||
# По emoji_id
|
||||
emoji = await service.get_emoji_by_id("telegram_emoji_id")
|
||||
|
||||
# Все эмодзи админа
|
||||
emojis = await service.get_all_emoji_by_admin(admin_id=12345)
|
||||
|
||||
# Все эмодзи
|
||||
all_emojis = await service.get_all_emojis()
|
||||
```
|
||||
|
||||
### Замена эмодзи в тексте
|
||||
|
||||
```python
|
||||
# Текст → с заменой эмодзи на ID
|
||||
processed = await service.replace_emojis_in_text(
|
||||
"🎲 Выиграли! 🏆"
|
||||
)
|
||||
|
||||
# Обратно - ID → эмодзи
|
||||
original = await service.restore_emojis_in_text(processed)
|
||||
```
|
||||
|
||||
### Получить словарь маппинга
|
||||
|
||||
```python
|
||||
# {emoji_text: emoji_id}
|
||||
mapping = await service.get_emoji_mapping_dict()
|
||||
# {'🎲': 'telegram_emoji_id_1', '🏆': 'telegram_emoji_id_2', ...}
|
||||
```
|
||||
|
||||
## Примеры использования в разных рутерах
|
||||
|
||||
### В регистрации
|
||||
|
||||
```python
|
||||
async def registration_complete(message: Message, session: AsyncSession):
|
||||
text = "✅ Регистрация завершена! 🎉"
|
||||
text = await get_emoji_aware_text(session, text)
|
||||
await message.answer(text, parse_mode="HTML")
|
||||
```
|
||||
|
||||
### В админ-панели
|
||||
|
||||
```python
|
||||
async def lottery_created(callback: CallbackQuery, session: AsyncSession):
|
||||
text = "🎰 Новый розыгрыш создан! 🏆"
|
||||
text = await get_emoji_aware_text(session, text)
|
||||
await callback.message.edit_text(text, parse_mode="HTML")
|
||||
```
|
||||
|
||||
### В чатовой рассылке
|
||||
|
||||
```python
|
||||
async def broadcast_message(message: Message, session: AsyncSession):
|
||||
text = f"📢 Сообщение от админа: {message.text}\n\n💎 Удачи!"
|
||||
text = await get_emoji_aware_text(session, text)
|
||||
|
||||
for user_id in target_users:
|
||||
await bot.send_message(user_id, text, parse_mode="HTML")
|
||||
```
|
||||
|
||||
## Важные моменты
|
||||
|
||||
1. **Parse Mode**: Всегда используйте `parse_mode="HTML"` при работе с эмодзи
|
||||
2. **Кеширование ID**: Система не кеширует, каждый раз обращается к БД. Для оптимизации можно добавить кеширование
|
||||
3. **Лог использования**: `last_used_at` обновляется автоматически при замене в тексте
|
||||
4. **Удаление**: Удаленный эмодзи больше не будет заменяться в новых сообщениях
|
||||
5. **Конфликты**: Если два админа добавляют один эмодзи - они сохранятся отдельно (разные admin_id)
|
||||
|
||||
## Миграция
|
||||
|
||||
Таблица создана миграцией:
|
||||
```
|
||||
migrations/versions/20260307_0100_add_emoji_mappings.py
|
||||
```
|
||||
|
||||
Применить миграцию:
|
||||
```bash
|
||||
alembic upgrade head
|
||||
```
|
||||
|
||||
## Trouble Shooting
|
||||
|
||||
### Эмодзи не отображается корректно
|
||||
- Проверьте что используете `parse_mode="HTML"`
|
||||
- Убедитесь что эмодзи зарегистрирован с помощью `/my_emojis`
|
||||
|
||||
### Ошибка "Can't parse entities"
|
||||
- Это означает что есть конфликт форматирования
|
||||
- Убедитесь что используете HTML теги (`<b>`, `<i>`, и т.д.), а не Markdown (`**`, `__`)
|
||||
|
||||
### Эмодзи не заменяется
|
||||
- Проверьте что был зарегистрирован с помощью `/add_emoji`
|
||||
- Убедитесь что используете функцию `get_emoji_aware_text()` перед отправкой
|
||||
Reference in New Issue
Block a user