Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
4fdfcc7
feat(mcp): פתקים דביקים — צפייה, יצירה ועריכה דרך ה-MCP
claude Jul 20, 2026
fd6b706
feat(webapp): קיצור דרך לעריכת תיאור מתפריט ⋮ בעמוד הקובץ
claude Jul 20, 2026
e97bee5
Merge branch 'main' into claude/mcp-codekeeper-webapp-ldnzsg
amirbiron Jul 20, 2026
9218b77
fix(webapp): תבנית חדשה מגיעה מיד אחרי deploy (ETag כולל גרסת deploy)
claude Jul 20, 2026
e745b7e
Merge branch 'main' into claude/mcp-codekeeper-webapp-ldnzsg
amirbiron Jul 20, 2026
71e3264
feat(webapp): אייקון תיאור על קבצים באוסף + מודאל תצוגה
claude Jul 20, 2026
7ea470a
feat(webapp): הזזת אייקון תיאור בכרטיס אוסף + ארכיון לאוספים
claude Jul 20, 2026
26b25b6
Merge origin/main: יישור הענף מול main + פתרון קונפליקט collections.css
claude Jul 20, 2026
991b1ad
fix(webapp): המרת צבעים קשיחים לטוקני ערכה במודאל התיאור ובכפתור הארכיון
claude Jul 20, 2026
afa7b6d
Merge origin/main: יישור מול main אחרי squash של #3192 + פתרון קונפלי…
claude Jul 20, 2026
c7c49a3
fix(bot): תיקון מספר קבצים בהודעות ZIP + שלב בחירת שם ל-ZIP
claude Jul 24, 2026
bab0701
Merge branch 'main' into claude/mcp-codekeeper-webapp-ldnzsg
amirbiron Jul 24, 2026
fd88aa0
fix(bot): הקשחת יצירת ZIP — ניקוי שמות (Zip-Slip), מגבלות איסוף, to_t…
claude Jul 24, 2026
85bcfa9
fix(bot): הקשחת ZIP סבב 2 — מגבלות לפני הורדה, מניעת שמות כפולים, תיק…
claude Jul 24, 2026
2f84c9f
fix(webapp): Config Inspector — הפרדת שירותים, סטטוס Set, וביטול מיסו…
claude Jul 26, 2026
552bcf4
Merge branch 'main' into claude/mcp-codekeeper-webapp-ldnzsg
amirbiron Jul 26, 2026
78c0a04
fix(webapp): Config Inspector v2 — webserver כשירות נפרד, משתנים משות…
claude Jul 26, 2026
606a1c1
feat(bot): סוג קובץ חדש "סקיל" — אחסון נפרד מגיבויים
claude Jul 26, 2026
b4f4844
fix(bot,webapp): סבב review לסקילים — כשלי CI, אבטחה וביצועים
claude Jul 26, 2026
352247a
fix(bot): שמירת סקילים נכשלה — pymongo Database לא תומך ב-bool()
claude Jul 26, 2026
ace434f
Merge origin/main: יישור מול main אחרי squash של #3197 ו-#3198 (פתרון…
claude Jul 26, 2026
49ca0a2
fix(webapp): Config Inspector — שחזור רווחים, סינון בעמוד 2, ודיוק שי…
claude Jul 26, 2026
0ed5fd9
fix(bot): סבב review לסקילים — PII בלוגים, ניקוי pending, מכסות, ושאי…
claude Jul 26, 2026
fe906d5
feat(bot): נוסח חדש להודעת קליטת ZIP, "קבצי גיבוי" במקום "קבצי ZIP", …
claude Jul 26, 2026
9ef85c2
Merge origin/main: יישור אחרי squash של #3199 (main זהה לגרסת טרום-fe…
claude Jul 26, 2026
81cc87d
style(bot): איחוד אייקון הסקיל ל-🧩 בכל המופעים
claude Jul 26, 2026
4909cb3
fix(bot): סבב review על PR #3200 — wrapper לעריכות שגיאה ו-fallback מ…
claude Jul 26, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions GUIDES/BOT_USER_GUIDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -748,7 +748,7 @@ class DataHandler:
2. בחר מקור:
- **✍️ הדבק קוד** - הדבק קוד ישירות
- **🗂 לפי ריפו** - בחר מקבצים לפי ריפו
- **📦 קבצי ZIP** - בחר מקבצי ZIP שמורים
- **📦 קבצי גיבוי** - בחר מקבצי ZIP שמורים
- **📂 קבצים גדולים** - בחר מקבצים גדולים (500+ שורות)
- **📁 שאר הקבצים** - בחר מכל הקבצים האחרים
3. בחר קובץ להעלאה
Expand Down Expand Up @@ -1071,7 +1071,7 @@ git checkout -b restore-from-checkpoint

**תפריט גיבוי ל-Drive:**
```
📦 קבצי ZIP - גיבוי של כל קבצי ה-ZIP השמורים בבוט
📦 קבצי גיבוי - גיבוי של כל קבצי ה-ZIP השמורים בבוט
🧰 הכל - גיבוי של כל הקבצים בבוט
📂 בחר תיקיית יעד - בחירת תיקייה ב-Drive להעלאה
⏰ קבע תזמון - תזמון אוטומטי לגיבויים
Expand All @@ -1084,7 +1084,7 @@ git checkout -b restore-from-checkpoint
### איך לגבות ל-Drive?

1. **בחר סוג גיבוי:**
- **📦 קבצי ZIP** - רק קבצי ZIP שיצרת או הורדת
- **📦 קבצי גיבוי** - רק קבצי ZIP שיצרת או הורדת
- **🧰 הכל** - כל הקבצים השמורים בבוט

2. **בחר תיקיית יעד (אופציונלי):**
Expand Down
3 changes: 2 additions & 1 deletion backup_menu_handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

from services import backup_service as backup_manager
from handlers.pagination import build_pagination_row
from i18n.strings_he import BTN_BACKUP_ZIPS

logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -627,7 +628,7 @@ def _key(v: Any) -> float:
id_to_version[getattr(b, 'backup_id', '')] = idx
except Exception:
id_to_version = {}
lines = [f"📦 קבצי ZIP שמורים — סה\"כ: {total}\n📄 עמוד {page} מתוך {total_pages}\n"]
lines = [f"{BTN_BACKUP_ZIPS} שמורים — סה\"כ: {total}\n📄 עמוד {page} מתוך {total_pages}\n"]
keyboard = []
delete_mode = bool(context.user_data.get("backup_delete_mode"))
selected = set(context.user_data.get("backup_delete_selected", set()))
Expand Down
5 changes: 5 additions & 0 deletions config.py
Original file line number Diff line number Diff line change
Expand Up @@ -333,6 +333,11 @@ class BotConfig(BaseSettings):
default="https://amirbiron.github.io/CodeBot/", description="Docs URL"
)
BOT_LABEL: str = Field(default="CodeBot", description="Bot label for UI")
# אימוג'י מותאם (טלגרם פרימיום) לאייקון ZIP בהודעות הבוט; ריק/None => אימוג'י רגיל.
# ה-ID הוא משאב חיצוני (חבילת צד ג') ולכן חי רק ב-ENV — לא מוטבע בקוד.
CUSTOM_EMOJI_ZIP_ID: Optional[str] = Field(
default=None, description="Custom emoji ID for ZIP icon (Telegram premium)"
)
DRIVE_ADD_HASH: bool = Field(
default=False, description="Append hash to filenames to avoid collisions"
)
Expand Down
23 changes: 12 additions & 11 deletions conversation_handlers.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ def set_activity_reporter(new_reporter):
from utils import TelegramUtils, TextUtils, ValidationUtils
from services import code_service
from i18n.strings_he import MAIN_MENU as MAIN_KEYBOARD
from i18n.strings_he import BTN_BACKUP_ZIPS
from handlers.pagination import build_pagination_row
from config import config
from urllib.parse import quote_plus
Expand Down Expand Up @@ -688,7 +689,7 @@ async def submit_flows_cancel(update: Update, context: ContextTypes.DEFAULT_TYPE
"🗂 <b>לפי ריפו</b> — קבצים מאורגנים לפי פרויקט\n"
"📂 <b>קבצים גדולים</b> — תצוגה מדורגת לקבצים ארוכים\n"
"📁 <b>שאר הקבצים</b> — כל השאר\n"
"📦 <b>קבצי ZIP</b> — גיבויים/ארכיונים\n\n"
"📦 <b>קבצי גיבוי</b> — ארכיוני ZIP (גיבויים וריפואים מגיטהאב)\n\n"
"<b>לכל קובץ יש תפריט עם:</b>\n"
"👁️ הצג | ✏️ ערוך | 📝 שנה שם\n"
"📚 היסטוריה | 📥 הורד | 🗑️ העבר לסל\n\n"
Expand Down Expand Up @@ -894,7 +895,7 @@ def _count_and_save_skill(raw: bytes, user_id: int, original_name: str):


async def _handle_zip_route(update: Update, context: ContextTypes.DEFAULT_TYPE, data: str) -> None:
"""מטפל בבחירת יעד ל-ZIP שהועלה: '📝 סקיל' (אחסון קבוע as-is) או '📦 גיבוי' (רשימת הגיבויים).
"""מטפל בבחירת יעד ל-ZIP שהועלה: '🧩 סקיל' (אחסון קבוע as-is) או '📦 גיבוי' (רשימת הגיבויים).

ה-bytes נטענים מהקובץ הזמני שנשמר ב-_maybe_store_zip_copy; השמירה הכבדה רצה ב-thread נפרד
כדי לא לחסום את לולאת האירועים.
Expand Down Expand Up @@ -932,7 +933,7 @@ async def _handle_zip_route(update: Update, context: ContextTypes.DEFAULT_TYPE,
await TelegramUtils.safe_edit_message_text(
query,
f"✅ נשמר כסקיל: <code>{html_escape(original_name)}</code>\n"
"🔎 ניתן למצוא אותו תחת: '📚' ← '📝 סקילים'.",
"🔎 ניתן למצוא אותו תחת: '📚' ← '🧩 סקילים'.",
parse_mode=ParseMode.HTML,
)
else:
Expand All @@ -959,7 +960,7 @@ async def _handle_zip_route(update: Update, context: ContextTypes.DEFAULT_TYPE,
await TelegramUtils.safe_edit_message_text(
query,
"✅ קובץ ZIP נשמר בהצלחה לרשימת ה‑ZIP השמורים.\n"
"📦 ניתן למצוא אותו תחת: '📚' ← '📦 קבצי ZIP' או ב‑Batch/GitHub."
f"📦 ניתן למצוא אותו תחת: '📚' ← '{BTN_BACKUP_ZIPS}' או ב‑Batch/GitHub."
)
else:
await TelegramUtils.safe_edit_message_text(
Expand Down Expand Up @@ -1076,8 +1077,8 @@ async def show_all_files(update: Update, context: ContextTypes.DEFAULT_TYPE) ->
keyboard = [
[InlineKeyboardButton("🔎 חפש קובץ", callback_data="search_files")],
[InlineKeyboardButton("🗂 לפי ריפו", callback_data="by_repo_menu")],
[InlineKeyboardButton("📦 קבצי ZIP", callback_data="backup_list")],
[InlineKeyboardButton("📝 סקילים", callback_data="skill_list")],
[InlineKeyboardButton(BTN_BACKUP_ZIPS, callback_data="backup_list")],
[InlineKeyboardButton("🧩 סקילים", callback_data="skill_list")],
[InlineKeyboardButton("📂 קבצים גדולים", callback_data="show_large_files")],
[InlineKeyboardButton("📁 שאר הקבצים", callback_data="show_regular_files")],
[InlineKeyboardButton("⭐ מועדפים", callback_data="show_favorites")],
Expand Down Expand Up @@ -1147,8 +1148,8 @@ async def show_all_files_callback(update: Update, context: ContextTypes.DEFAULT_
pass
keyboard = [
[InlineKeyboardButton("🗂 לפי ריפו", callback_data="by_repo_menu")],
[InlineKeyboardButton("📦 קבצי ZIP", callback_data="backup_list")],
[InlineKeyboardButton("📝 סקילים", callback_data="skill_list")],
[InlineKeyboardButton(BTN_BACKUP_ZIPS, callback_data="backup_list")],
[InlineKeyboardButton("🧩 סקילים", callback_data="skill_list")],
[InlineKeyboardButton("📂 קבצים גדולים", callback_data="show_large_files")],
[InlineKeyboardButton("📁 שאר הקבצים", callback_data="show_regular_files")],
[InlineKeyboardButton("⭐ מועדפים", callback_data="show_favorites")],
Expand Down Expand Up @@ -4766,7 +4767,7 @@ async def show_batch_menu(update: Update, context: ContextTypes.DEFAULT_TYPE) ->
send = update.message.reply_text
keyboard = [
[InlineKeyboardButton("🗂 לפי ריפו", callback_data="batch_cat:repos")],
[InlineKeyboardButton("📦 קבצי ZIP", callback_data="batch_cat:zips")],
[InlineKeyboardButton(BTN_BACKUP_ZIPS, callback_data="batch_cat:zips")],
[InlineKeyboardButton("📂 קבצים גדולים", callback_data="batch_cat:large")],
[InlineKeyboardButton("📁 שאר הקבצים", callback_data="batch_cat:other")],
[InlineKeyboardButton("📋 סטטוס עבודות", callback_data="show_jobs")],
Expand Down Expand Up @@ -4894,7 +4895,7 @@ async def show_batch_zips_menu(update: Update, context: ContextTypes.DEFAULT_TYP
if not backups:
keyboard = [[InlineKeyboardButton("🔙 חזור", callback_data="batch_menu")]]
await query.edit_message_text(
"ℹ️ לא נמצאו קבצי ZIP שמורים.",
"ℹ️ לא נמצאו קבצי גיבוי שמורים.",
reply_markup=InlineKeyboardMarkup(keyboard)
)
return ConversationHandler.END
Expand All @@ -4910,7 +4911,7 @@ async def show_batch_zips_menu(update: Update, context: ContextTypes.DEFAULT_TYP
end = min(start + PAGE_SIZE, total)
items = backups[start:end]

lines = [f'📦 קבצי ZIP שמורים — סה"כ: {total}\n📄 עמוד {page} מתוך {total_pages}\n']
lines = [f'{BTN_BACKUP_ZIPS} שמורים — סה"כ: {total}\n📄 עמוד {page} מתוך {total_pages}\n']
keyboard = []
# חישוב גרסאות vN לפי ריפו
repo_to_sorted: Dict[str, list] = {}
Expand Down
6 changes: 6 additions & 0 deletions docs/environment-variables.rst
Original file line number Diff line number Diff line change
Expand Up @@ -832,6 +832,12 @@
- ``CodeBot``
- ``CKB``
- Bot/WebApp
* - ``CUSTOM_EMOJI_ZIP_ID``
- Custom emoji ID לאייקון ZIP בהודעות הבוט (טלגרם פרימיום, לבעל בוט עם מנוי); ריק = אימוג'י רגיל 📁.
- לא
- (ללא)
- ``5069094945915142952``
- Bot
* - ``DRIVE_ADD_HASH``
- הוספת hash לקבצים משותפים
- לא
Expand Down
4 changes: 2 additions & 2 deletions docs/handlers/drive_menu.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,15 @@ Drive Menu V2

סקירה
-----
תפריט הגיבוי ל‑Google Drive (גרסת V2) כולל בחירה מהירה (קבצי ZIP/הכל/מתקדם), בחירת תיקיית יעד (אוטומטי/ברירת מחדל/מותאם), תזמון גיבוי, וטיפול שגיאות ברור.
תפריט הגיבוי ל‑Google Drive (גרסת V2) כולל בחירה מהירה (קבצי גיבוי/הכל/מתקדם), בחירת תיקיית יעד (אוטומטי/ברירת מחדל/מותאם), תזמון גיבוי, וטיפול שגיאות ברור.

דגל פיצ'ר
----------
- DRIVE_MENU_V2 (ברירת מחדל: true). כיבוי מהיר במשתני סביבה.

זרימות עיקריות
---------------
- קבצי ZIP: העלאת ZIPים שמורים בבוט, כולל הצעה ליצור ZIP אם אין.
- קבצי גיבוי: העלאת ZIPים שמורים בבוט, כולל הצעה ליצור ZIP אם אין.
- הכל: יצירת ZIP מלא והעלאה.
- מתקדם: לפי ריפו / קבצים גדולים / שאר; בחירה מרובה.
- תיקיית יעד: אוטומטי (סידור לפי קטגוריה/תאריך), ברירת מחדל, או נתיב מותאם.
Expand Down
10 changes: 6 additions & 4 deletions github_menu_handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
import errno
from urllib.parse import urlparse

from i18n.strings_he import BTN_BACKUP_ZIPS

# Shim: expose a 'requests' object for tests and route GETs through it.
# This allows monkeypatching gh.requests.get in tests while still using
# our pooled http client under the hood.
Expand Down Expand Up @@ -1497,7 +1499,7 @@ async def handle_menu_callback(self, update: Update, context: ContextTypes.DEFAU
keyboard = [
[InlineKeyboardButton("✍️ הדבק קוד", callback_data="upload_paste_code")],
[InlineKeyboardButton("🗂 לפי ריפו", callback_data="gh_upload_cat:repos")],
[InlineKeyboardButton("📦 קבצי ZIP", callback_data="gh_upload_cat:zips")],
[InlineKeyboardButton(BTN_BACKUP_ZIPS, callback_data="gh_upload_cat:zips")],
[InlineKeyboardButton("📂 קבצים גדולים", callback_data="gh_upload_cat:large")],
[InlineKeyboardButton("📁 שאר הקבצים", callback_data="gh_upload_cat:other")],
[InlineKeyboardButton("🔙 חזור", callback_data="github_menu")],
Expand Down Expand Up @@ -1528,7 +1530,7 @@ async def handle_menu_callback(self, update: Update, context: ContextTypes.DEFAU
keyboard = [
[InlineKeyboardButton("✍️ הדבק קוד", callback_data="upload_paste_code")],
[InlineKeyboardButton("🗂 לפי ריפו", callback_data="gh_upload_cat:repos")],
[InlineKeyboardButton("📦 קבצי ZIP", callback_data="gh_upload_cat:zips")],
[InlineKeyboardButton(BTN_BACKUP_ZIPS, callback_data="gh_upload_cat:zips")],
[InlineKeyboardButton("📂 קבצים גדולים", callback_data="gh_upload_cat:large")],
[InlineKeyboardButton("📁 שאר הקבצים", callback_data="gh_upload_cat:other")],
[InlineKeyboardButton("🔙 חזור", callback_data="github_menu")],
Expand Down Expand Up @@ -1579,12 +1581,12 @@ async def handle_menu_callback(self, update: Update, context: ContextTypes.DEFAU
backup_handler = BackupMenuHandler()
context.bot_data['backup_handler'] = backup_handler
except Exception as e:
await query.edit_message_text(f"❌ רכיב גיבוי לא זמין: {e}")
await TelegramUtils.safe_edit_message_text(query, f"❌ רכיב גיבוי לא זמין: {e}")
return
try:
await backup_handler._show_backups_list(update, context, page=1)
except Exception as e:
await query.edit_message_text(f"❌ שגיאה בטעינת קבצי ZIP: {e}")
await TelegramUtils.safe_edit_message_text(query, f"❌ שגיאה בטעינת קבצי גיבוי: {e}")
elif query.data.startswith("gh_upload_zip_browse:"):
# עיון בקובץ ZIP שמור ובחירת קובץ מתוכו להעלאה לריפו
backup_id = query.data.split(":", 1)[1]
Expand Down
51 changes: 42 additions & 9 deletions handlers/documents.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

from telegram import InlineKeyboardButton, InlineKeyboardMarkup, Update
from telegram.constants import ParseMode
from telegram.error import BadRequest
from telegram.ext import ContextTypes

# שימוש ב-FilesFacade דרך Composition Root כדי להימנע מתלות ישירה ב-DB
Expand All @@ -27,6 +28,9 @@

logger = logging.getLogger(__name__)

# לוג חד-פעמי לתהליך כשטלגרם דוחה את האימוג'י המותאם (תנאי פרימיום/ID לא תקף)
_custom_emoji_warned = False

# מגבלות ייבוא ZIP — הגנה מפני "פצצת ZIP" (דקומפרסיה מתפוצצת) בעת בניית ריפו מקובץ.
# הבדיקות נעשות מול הגודל הלא-דחוס (ZipInfo.file_size) לפני קריאת התוכן לזיכרון.
MAX_IMPORT_ZIP_MEMBERS = 2000 # מספר קבצים מקסימלי בארכיון לייבוא
Expand Down Expand Up @@ -1003,8 +1007,10 @@ async def _maybe_store_zip_copy(
stash_pending_zip_bytes,
cleanup_pending_zip,
cleanup_stale_pending_zips,
tg_emoji,
PENDING_ZIP_TTL_SECONDS,
)
from config import config
import uuid as _uuid

original_name = document.file_name or "upload.zip"
Expand Down Expand Up @@ -1049,21 +1055,48 @@ async def _maybe_store_zip_copy(
"ts": int(datetime.now(timezone.utc).timestamp()),
}

# כפתורים: אימוג'י רגיל בלבד — inline keyboard לא תומך ב-custom emoji entities
keyboard = InlineKeyboardMarkup([
[
InlineKeyboardButton("📝 סקיל", callback_data=f"zip_route_skill:{token}"),
InlineKeyboardButton("🧩 סקיל", callback_data=f"zip_route_skill:{token}"),
InlineKeyboardButton("📦 גיבוי", callback_data=f"zip_route_backup:{token}"),
]
])
try:
await update.message.reply_text(
f"📦 קיבלתי קובץ ZIP: <code>{html_escape(original_name)}</code>\n"
"איך לשמור אותו?\n\n"
"📝 <b>סקיל</b> — אחסון קבוע, בדיוק כמו שהוא (byte-for-byte), בלי מחיקה אוטומטית.\n"
"📦 <b>גיבוי</b> — נשמר לרשימת הגיבויים (כפוף למדיניות ניקוי).",
reply_markup=keyboard,
parse_mode=ParseMode.HTML,

def _zip_prompt_text(icon: str) -> str:
return (
f"{icon} קיבלתי קובץ ZIP: <code>{html_escape(original_name)}</code>\n"
"איפה לשמור אותו?\n\n"
"🧩 <b>בקטגוריית סקילים</b> — קטגוריה מיוחדת לשמירת סקילים בפורמט ZIP\n"
"📦 <b>בקטגוריית גיבויים</b> — קטגוריה לשמירת Repo's מגיטהאב בפורמט ZIP "
"(אפשר אחר כך לשחזר מהזיפ את כל הריפו בגיטהאב דרך הבוט - בלחיצה)"
)

try:
# אייקון ZIP מותאם (טלגרם פרימיום) — ה-ID מגיע מ-ENV בלבד; בלי ID נופלים ל-📁
custom_icon = tg_emoji(getattr(config, "CUSTOM_EMOJI_ZIP_ID", None), "📁")
try:
await update.message.reply_text(
_zip_prompt_text(custom_icon),
reply_markup=keyboard,
parse_mode=ParseMode.HTML,
)
except BadRequest:
# טלגרם דחתה את ההודעה — אם זה בגלל האימוג'י המותאם (תנאי פרימיום/ID
# שנמחק), שולחים שוב עם האימוג'י הרגיל: המשתמש חייב לקבל את ההודעה.
if custom_icon == "📁":
raise # אין אימוג'י מותאם בהודעה — הכשל ממקור אחר, אין טעם בניסיון זהה
await update.message.reply_text(
_zip_prompt_text("📁"),
reply_markup=keyboard,
parse_mode=ParseMode.HTML,
)
Comment thread
amirbiron marked this conversation as resolved.
# מסמנים ומלוגגים רק אחרי שה-fallback עבר — זו ההוכחה שהבעיה הייתה
# האימוג'י (BadRequest ממקור אחר היה מפיל גם את השליחה הזו ומתגלגל הלאה)
global _custom_emoji_warned
if not _custom_emoji_warned:
_custom_emoji_warned = True
logger.warning("האימוג'י המותאם (CUSTOM_EMOJI_ZIP_ID) נדחה ע\"י טלגרם — נופלים לאימוג'י רגיל")
except Exception:
# בלי כפתורים אין דרך לממש את הבחירה — מנקים את הרשומה והקובץ שנוצרו עבור ה-ZIP הזה
cleanup_pending_zip(path)
Expand Down
Loading
Loading