זרימת שמירת קוד (Save Flow)

סקירה כללית

זרימת השמירה מאפשרת למשתמשים לשמור קטעי קוד בבוט דרך מספר מסלולים: - הדבקת קוד ישירה - העלאת קובץ (עד 20MB) - מצב איסוף ארוך (מספר הודעות עם /done)

מצבי שמירה

מצבי שמירה

מצב

טריגר

תיאור

GET_CODE

הוסף קוד חדש

מצב המתנה לקוד

GET_FILENAME

לאחר קבלת קוד

מצב המתנה לשם קובץ

GET_NOTE

לאחר קבלת שם

מצב המתנה להערה (אופציונלי)

LONG_COLLECT

/long או קוד >300KB

מצב איסוף מספר הודעות

WAIT_ADD_CODE_MODE

במצב איסוף ארוך

מצב המתנה להוספת קוד נוסף

זרימת עבודה בסיסית

        sequenceDiagram
    participant U as User
    participant B as Bot
    participant H as SaveFlow Handler
    participant CS as CodeService
    participant DB as MongoDB

    U->>B: ➕ הוסף קוד חדש
    B->>H: start_save_flow()
    H->>H: בדיקת מצב (GET_CODE)
    H->>U: "שלח את הקוד שלך"

    U->>H: קוד (הודעה/קובץ)
    H->>H: בדיקת גודל
    alt קוד > 300KB
      H->>H: מעבר ל-LONG_COLLECT
      H->>H: _schedule_long_collect_timeout()
      H->>U: "מצב איסוף ארוך. שלח עוד קוד או /done"
    else קוד רגיל
      H->>H: נרמול קוד (normalize_code)
      H->>H: זיהוי secrets (_detect_secrets)
      alt נמצאו secrets
        H->>U: "אזהרה: נמצאו סודות בקוד"
      end
      H->>H: מעבר ל-GET_FILENAME
      H->>U: "מה שם הקובץ?"
    end

    U->>H: שם קובץ
    H->>H: בדיקת כפילויות
    alt קובץ קיים
      H->>U: תפריט: החלף/שנה שם/ביטול
    else קובץ חדש
      H->>H: מעבר ל-GET_NOTE
      H->>U: "הוסף הערה (אופציונלי) או /skip"
    end

    U->>H: הערה או /skip
    H->>CS: process_code(code, filename, language)
    CS->>CS: זיהוי שפה (detect_language)
    CS->>CS: ניתוח קוד (analyze_code)
    CS->>DB: save_snippet()
    DB-->>CS: file_id
    CS-->>H: success
    H->>U: "נשמר בהצלחה: {filename}"
    

מצב איסוף ארוך (LONG_COLLECT)

מצב זה מאפשר איסוף קוד במספר הודעות:

# הגדרות
LONG_COLLECT_MAX_BYTES = 300 * 1024  # 300KB
LONG_COLLECT_TIMEOUT_SECONDS = 15 * 60  # 15 דקות

זרימה:

  1. משתמש שולח /long או קוד >300KB

  2. הבוט עובר למצב LONG_COLLECT

  3. כל הודעה נוספת מצטרפת ל-context.user_data['code_parts']

  4. טיימאאוט של 15 דקות ללא פעילות מבטל את המצב

  5. /done מסיים את האיסוף ומעביר ל-GET_FILENAME

טיפול בטיימאאוט:

def _schedule_long_collect_timeout(update, context):
    jid = f"long_collect_timeout:{update.effective_user.id}"
    job = context.job_queue.run_once(
        long_collect_timeout_job,
        when=LONG_COLLECT_TIMEOUT_SECONDS,
        data={'chat_id': ..., 'user_id': ...},
        name=jid,
        job_kwargs={'id': jid, 'replace_existing': True}
    )
    context.user_data['long_collect_job'] = job

זיהוי סודות (Secrets Detection)

המערכת מזהה סודות בקוד לפני שמירה:

patterns = [
    r"ghp_[A-Za-z0-9]{36,}",  # GitHub Personal Access Token
    r"github_pat_[A-Za-z0-9_]{30,}",  # GitHub Fine-grained Token
    r"AIza[0-9A-Za-z\-_]{35}",  # Google API Key
    r"sk_(live|test)_[0-9A-Za-z]{20,}",  # Stripe Key
    r"xox[abprs]-[0-9A-Za-z\-]{10,}",  # Slack Token
    r"AWS_ACCESS_KEY_ID\s*=\s*[A-Z0-9]{16,20}",
    r"AWS_SECRET_ACCESS_KEY\s*=\s*[A-Za-z0-9/+=]{30,}",
    r"-----BEGIN (RSA |EC |)PRIVATE KEY-----",
    r"(?i)(api|secret|token|key)[\s:=\"]{1,20}[A-Za-z0-9_\-]{16,}"
]

התנהגות: - אם נמצאו סודות, המשתמש מקבל אזהרה - השמירה ממשיכה (לא נחסמת) - המשתמש יכול לבחור לבטל

טיפול בכפילויות

כאשר קובץ עם אותו שם כבר קיים:

# בדיקת קיום
existing = await db.get_file_by_name(user_id, filename)

if existing:
    # תפריט החלפה
    keyboard = [
        [InlineKeyboardButton("🔄 החלף", callback_data=f"replace:{file_id}")],
        [InlineKeyboardButton("📝 שנה שם", callback_data="rename")],
        [InlineKeyboardButton("❌ ביטול", callback_data="cancel")]
    ]

נרמול קוד

כל קוד עובר נרמול לפני שמירה:

from utils import normalize_code

normalized = normalize_code(code)
# הסרת תווים נסתרים
# נרמול שורות ריקות
# טיפול בקידודים שונים

הערות לסוכנים:

  • הנורמלייזר מסיר רווחים ריקים בסוף כל שורה, ואז מוריד גם \n עודפים בסוף הטקסט. כלומר אם המשתמש לא שלח שורה ריקה אחרונה – לא נוסיף אחת באופן מלאכותי.

  • אם מבחני יחידה או תסריטים חיצוניים מצפים לשורת סיום מסוימת, צריך להוסיף אותה במפורש בקוד לפני הקריאה ל-normalize_code או להתאים את האסרט.

Edge Cases

קוד ריק: - נדחה עם הודעת שגיאה

קובץ גדול מאוד (>20MB): - נדחה עם הודעת שגיאה - מוצע להשתמש ב-GitHub או Google Drive

טיימאאוט במצב LONG_COLLECT: - המצב מתבטל אוטומטית - המשתמש מקבל הודעה - כל הקוד שנאסף נמחק

שגיאת שמירה ב-DB: - המשתמש מקבל הודעת שגיאה - האירוע נרשם ב-Observability - מונה שגיאות Prometheus מתעדכן

קישורים