bot_v4 / database /migrations.py
qqqsfasdf's picture
Upload 70 files
036b534 verified
# ============================================
# database/migrations.py โ€” ุฅู†ุดุงุก ุงู„ุฌุฏุงูˆู„ ูˆุงู„ุชุฑู‚ูŠุฉ
# ============================================
# ู„ู…ุงุฐุง migrations ูˆู„ูŠุณ init ูู‚ุทุŸ
# ู„ุฃู† ุงู„ู…ุดุฑูˆุน ุณูŠุชูˆุณุน ูˆุณุชูุถุงู ุฃุนู…ุฏุฉ ุฌุฏูŠุฏุฉ ู„ุงุญู‚ุงู‹.
# ุงู„ู†ู…ุท ู‡ู†ุง: ูƒู„ ุฌุฏูˆู„ ูŠูู†ุดุฃ ุจู€ IF NOT EXISTS ูˆูƒู„ ุนู…ูˆุฏ
# ุฌุฏูŠุฏ ูŠูุถุงู ุจู€ ADD COLUMN IF NOT EXISTS โ€” ุขู…ู† ุนู„ู‰
# ู‚ูˆุงุนุฏ ุงู„ุจูŠุงู†ุงุช ุงู„ู…ูˆุฌูˆุฏุฉ (ู„ุง ุชู…ุณุญ ุงู„ุจูŠุงู†ุงุช).
# ============================================
import logging
from database.connection import get_connection
logger = logging.getLogger(__name__)
def init_database() -> None:
"""
ุฅู†ุดุงุก ุฃูˆ ุชุฑู‚ูŠุฉ ูƒู„ ุงู„ุฌุฏุงูˆู„ ูˆุงู„ูู‡ุงุฑุณ.
ุขู…ู† ู„ู„ุงุณุชุฏุนุงุก ุนู†ุฏ ูƒู„ ุฅู‚ู„ุงุน โ€” ู„ู† ูŠู…ุณุญ ุจูŠุงู†ุงุช ู…ูˆุฌูˆุฏุฉ.
"""
conn = get_connection()
c = conn.cursor()
try:
# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
# ุฌุฏูˆู„ ุงู„ุฑุณุงุฆู„ ุงู„ู…ูู‡ุฑุณุฉ (ุงู„ุฃุณุงุณูŠ)
# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
c.execute("""
CREATE TABLE IF NOT EXISTS messages (
id INTEGER PRIMARY KEY AUTOINCREMENT,
message_id INTEGER NOT NULL,
channel_id INTEGER NOT NULL,
channel_name TEXT DEFAULT '',
channel_username TEXT DEFAULT '',
message_text TEXT DEFAULT '',
text_normalized TEXT DEFAULT '',
message_date TEXT NOT NULL,
hashtags TEXT DEFAULT '',
platform TEXT DEFAULT '',
has_media INTEGER DEFAULT 0,
media_type TEXT DEFAULT '',
indexed_at TEXT DEFAULT (datetime('now','localtime')),
UNIQUE(message_id, channel_id)
)
""")
# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
# ูู‡ุฑุณ ุงู„ุจุญุซ ุงู„ูƒุงู…ู„ FTS5
# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
c.execute("""
CREATE VIRTUAL TABLE IF NOT EXISTS messages_fts
USING fts5(
message_text,
text_normalized,
channel_name,
hashtags,
platform,
content='messages',
content_rowid='id',
tokenize='unicode61'
)
""")
# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
# Triggers ู„ู„ู…ุฒุงู…ู†ุฉ ุงู„ุชู„ู‚ุงุฆูŠุฉ ู…ุน FTS
# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
c.executescript("""
CREATE TRIGGER IF NOT EXISTS fts_insert
AFTER INSERT ON messages BEGIN
INSERT INTO messages_fts(
rowid, message_text, text_normalized,
channel_name, hashtags, platform
)
VALUES (
new.id, new.message_text, new.text_normalized,
new.channel_name, new.hashtags, new.platform
);
END;
CREATE TRIGGER IF NOT EXISTS fts_delete
AFTER DELETE ON messages BEGIN
INSERT INTO messages_fts(
messages_fts, rowid, message_text, text_normalized,
channel_name, hashtags, platform
)
VALUES (
'delete', old.id, old.message_text, old.text_normalized,
old.channel_name, old.hashtags, old.platform
);
END;
CREATE TRIGGER IF NOT EXISTS fts_update
AFTER UPDATE ON messages BEGIN
INSERT INTO messages_fts(
messages_fts, rowid, message_text, text_normalized,
channel_name, hashtags, platform
)
VALUES (
'delete', old.id, old.message_text, old.text_normalized,
old.channel_name, old.hashtags, old.platform
);
INSERT INTO messages_fts(
rowid, message_text, text_normalized,
channel_name, hashtags, platform
)
VALUES (
new.id, new.message_text, new.text_normalized,
new.channel_name, new.hashtags, new.platform
);
END;
""")
# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
# ุฌุฏูˆู„ ุงู„ุฅุนุฏุงุฏุงุช
# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
c.execute("""
CREATE TABLE IF NOT EXISTS settings (
key TEXT PRIMARY KEY,
value TEXT NOT NULL
)
""")
# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
# ุฌุฏูˆู„ ุงู„ู…ุณุชุฎุฏู…ูŠู† (ุฌุฏูŠุฏ)
# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
c.execute("""
CREATE TABLE IF NOT EXISTS users (
user_id INTEGER PRIMARY KEY,
username TEXT DEFAULT '',
first_name TEXT DEFAULT '',
joined_at TEXT DEFAULT (datetime('now','localtime')),
is_banned INTEGER DEFAULT 0
)
""")
# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
# ุฌุฏูˆู„ ุงู„ู…ุดุชุฑูƒูŠู† ููŠ ุงู„ุชู†ุจูŠู‡ุงุช (ุฌุฏูŠุฏ)
# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
c.execute("""
CREATE TABLE IF NOT EXISTS notification_subscribers (
user_id INTEGER PRIMARY KEY,
platform TEXT DEFAULT 'all',
subscribed_at TEXT DEFAULT (datetime('now','localtime')),
FOREIGN KEY (user_id) REFERENCES users(user_id) ON DELETE CASCADE
)
""")
# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
# ุฌุฏูˆู„ ุณุฌู„ ุงู„ุฅุฐุงุนุงุช (ุฌุฏูŠุฏ)
# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
c.execute("""
CREATE TABLE IF NOT EXISTS broadcasts (
id INTEGER PRIMARY KEY AUTOINCREMENT,
admin_id INTEGER NOT NULL,
message_text TEXT NOT NULL,
broadcast_type TEXT DEFAULT 'manual',
game_title TEXT DEFAULT '',
game_link TEXT DEFAULT '',
sent_count INTEGER DEFAULT 0,
failed_count INTEGER DEFAULT 0,
blocked_count INTEGER DEFAULT 0,
sent_at TEXT DEFAULT (datetime('now','localtime'))
)
""")
# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
# ุญูุธ ุงู„ุฅุนุฏุงุฏุงุช ุงู„ุงูุชุฑุงุถูŠุฉ
# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
from config import DEFAULT_CHANNEL_TEXT
c.execute(
"INSERT OR IGNORE INTO settings (key, value) VALUES (?, ?)",
("channel_text", DEFAULT_CHANNEL_TEXT)
)
conn.commit()
logger.info("โœ… ู‚ุงุนุฏุฉ ุงู„ุจูŠุงู†ุงุช ุฌุงู‡ุฒุฉ (ูƒู„ ุงู„ุฌุฏุงูˆู„ ู…ูˆุฌูˆุฏุฉ ุฃูˆ ุชู… ุฅู†ุดุงุคู‡ุง)")
except Exception as e:
conn.rollback()
logger.critical(f"โŒ ูุดู„ ุชู‡ูŠุฆุฉ ู‚ุงุนุฏุฉ ุงู„ุจูŠุงู†ุงุช: {e}", exc_info=True)
raise
finally:
conn.close()
def rebuild_fts_index() -> bool:
"""ุฅุนุงุฏุฉ ุจู†ุงุก ูู‡ุฑุณ ุงู„ุจุญุซ ุงู„ูƒุงู…ู„ โ€” ู…ููŠุฏ ุจุนุฏ ุนู…ู„ูŠุงุช ุญุฐู ุฌู…ุงุนูŠุฉ"""
conn = get_connection()
try:
conn.execute("INSERT INTO messages_fts(messages_fts) VALUES('rebuild')")
conn.commit()
logger.info("โœ… ุชู… ุฅุนุงุฏุฉ ุจู†ุงุก ูู‡ุฑุณ FTS")
return True
except Exception as e:
logger.error(f"โŒ ูุดู„ ุฅุนุงุฏุฉ ุจู†ุงุก ูู‡ุฑุณ FTS: {e}", exc_info=True)
return False
finally:
conn.close()