fix quality code
This commit is contained in:
@@ -3,6 +3,7 @@
|
||||
Скрипт миграции для добавления колонки ban_author в таблицу blacklist.
|
||||
Колонка хранит user_id администратора, инициировавшего бан.
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import asyncio
|
||||
import os
|
||||
@@ -65,4 +66,3 @@ if __name__ == "__main__":
|
||||
)
|
||||
args = parser.parse_args()
|
||||
asyncio.run(main(args.db))
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
Скрипт миграции для добавления колонки is_anonymous в таблицу post_from_telegram_suggest.
|
||||
Для существующих записей определяет is_anonymous на основе текста или устанавливает NULL.
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import asyncio
|
||||
import os
|
||||
@@ -13,6 +14,7 @@ project_root = Path(__file__).resolve().parent.parent
|
||||
sys.path.insert(0, str(project_root))
|
||||
|
||||
import aiosqlite
|
||||
|
||||
from helper_bot.utils.helper_func import determine_anonymity
|
||||
from logs.custom_logger import logger
|
||||
|
||||
@@ -38,9 +40,7 @@ async def main(db_path: str) -> None:
|
||||
await conn.execute("PRAGMA foreign_keys = ON")
|
||||
|
||||
# Проверяем наличие колонки is_anonymous
|
||||
cursor = await conn.execute(
|
||||
"PRAGMA table_info(post_from_telegram_suggest)"
|
||||
)
|
||||
cursor = await conn.execute("PRAGMA table_info(post_from_telegram_suggest)")
|
||||
rows = await cursor.fetchall()
|
||||
await cursor.close()
|
||||
|
||||
@@ -74,26 +74,28 @@ async def main(db_path: str) -> None:
|
||||
is_anonymous = None
|
||||
else:
|
||||
is_anonymous = determine_anonymity(text)
|
||||
|
||||
|
||||
# Преобразуем bool в int для SQLite (True -> 1, False -> 0, None -> None)
|
||||
is_anonymous_int = None if is_anonymous is None else (1 if is_anonymous else 0)
|
||||
|
||||
is_anonymous_int = (
|
||||
None if is_anonymous is None else (1 if is_anonymous else 0)
|
||||
)
|
||||
|
||||
await conn.execute(
|
||||
"UPDATE post_from_telegram_suggest SET is_anonymous = ? WHERE message_id = ?",
|
||||
(is_anonymous_int, message_id)
|
||||
(is_anonymous_int, message_id),
|
||||
)
|
||||
|
||||
|
||||
if is_anonymous is not None:
|
||||
updated_count += 1
|
||||
else:
|
||||
null_count += 1
|
||||
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Ошибка при обработке поста message_id={message_id}: {e}")
|
||||
# В случае ошибки устанавливаем NULL
|
||||
await conn.execute(
|
||||
"UPDATE post_from_telegram_suggest SET is_anonymous = NULL WHERE message_id = ?",
|
||||
(message_id,)
|
||||
(message_id,),
|
||||
)
|
||||
null_count += 1
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
2. Создает таблицу published_post_content для хранения медиафайлов опубликованных постов
|
||||
3. Создает индексы для производительности
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import asyncio
|
||||
import os
|
||||
@@ -15,6 +16,7 @@ project_root = Path(__file__).resolve().parent.parent
|
||||
sys.path.insert(0, str(project_root))
|
||||
|
||||
import aiosqlite
|
||||
|
||||
from logs.custom_logger import logger
|
||||
|
||||
DEFAULT_DB_PATH = "database/tg-bot-database.db"
|
||||
@@ -29,8 +31,6 @@ def _column_exists(rows: list, name: str) -> bool:
|
||||
return False
|
||||
|
||||
|
||||
|
||||
|
||||
async def main(db_path: str, dry_run: bool = False) -> None:
|
||||
"""Выполняет миграцию БД для поддержки опубликованных постов."""
|
||||
db_path = os.path.abspath(db_path)
|
||||
@@ -41,39 +41,45 @@ async def main(db_path: str, dry_run: bool = False) -> None:
|
||||
|
||||
async with aiosqlite.connect(db_path) as conn:
|
||||
await conn.execute("PRAGMA foreign_keys = ON")
|
||||
|
||||
|
||||
changes_made = []
|
||||
|
||||
|
||||
# 1. Проверяем и добавляем колонку published_message_id
|
||||
cursor = await conn.execute(
|
||||
"PRAGMA table_info(post_from_telegram_suggest)"
|
||||
)
|
||||
cursor = await conn.execute("PRAGMA table_info(post_from_telegram_suggest)")
|
||||
rows = await cursor.fetchall()
|
||||
await cursor.close()
|
||||
|
||||
|
||||
if not _column_exists(rows, "published_message_id"):
|
||||
if dry_run:
|
||||
print("DRY RUN: Будет добавлена колонка published_message_id в post_from_telegram_suggest")
|
||||
print(
|
||||
"DRY RUN: Будет добавлена колонка published_message_id в post_from_telegram_suggest"
|
||||
)
|
||||
changes_made.append("Добавление колонки published_message_id")
|
||||
else:
|
||||
logger.info("Добавление колонки published_message_id в post_from_telegram_suggest")
|
||||
logger.info(
|
||||
"Добавление колонки published_message_id в post_from_telegram_suggest"
|
||||
)
|
||||
await conn.execute(
|
||||
"ALTER TABLE post_from_telegram_suggest "
|
||||
"ADD COLUMN published_message_id INTEGER"
|
||||
)
|
||||
await conn.commit()
|
||||
print("✓ Колонка published_message_id добавлена в post_from_telegram_suggest")
|
||||
print(
|
||||
"✓ Колонка published_message_id добавлена в post_from_telegram_suggest"
|
||||
)
|
||||
changes_made.append("Добавлена колонка published_message_id")
|
||||
else:
|
||||
print("✓ Колонка published_message_id уже существует в post_from_telegram_suggest")
|
||||
|
||||
print(
|
||||
"✓ Колонка published_message_id уже существует в post_from_telegram_suggest"
|
||||
)
|
||||
|
||||
# 2. Проверяем и создаем таблицу published_post_content
|
||||
cursor = await conn.execute(
|
||||
"SELECT name FROM sqlite_master WHERE type='table' AND name='published_post_content'"
|
||||
)
|
||||
table_exists = await cursor.fetchone()
|
||||
await cursor.close()
|
||||
|
||||
|
||||
if not table_exists:
|
||||
if dry_run:
|
||||
print("DRY RUN: Будет создана таблица published_post_content")
|
||||
@@ -94,25 +100,29 @@ async def main(db_path: str, dry_run: bool = False) -> None:
|
||||
changes_made.append("Создана таблица published_post_content")
|
||||
else:
|
||||
print("✓ Таблица published_post_content уже существует")
|
||||
|
||||
|
||||
# 3. Проверяем и создаем индексы
|
||||
indexes = [
|
||||
("idx_published_post_content_message_id",
|
||||
"CREATE INDEX IF NOT EXISTS idx_published_post_content_message_id "
|
||||
"ON published_post_content(published_message_id)"),
|
||||
("idx_post_from_telegram_suggest_published",
|
||||
"CREATE INDEX IF NOT EXISTS idx_post_from_telegram_suggest_published "
|
||||
"ON post_from_telegram_suggest(published_message_id)")
|
||||
(
|
||||
"idx_published_post_content_message_id",
|
||||
"CREATE INDEX IF NOT EXISTS idx_published_post_content_message_id "
|
||||
"ON published_post_content(published_message_id)",
|
||||
),
|
||||
(
|
||||
"idx_post_from_telegram_suggest_published",
|
||||
"CREATE INDEX IF NOT EXISTS idx_post_from_telegram_suggest_published "
|
||||
"ON post_from_telegram_suggest(published_message_id)",
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
for index_name, index_sql in indexes:
|
||||
cursor = await conn.execute(
|
||||
"SELECT name FROM sqlite_master WHERE type='index' AND name=?",
|
||||
(index_name,)
|
||||
(index_name,),
|
||||
)
|
||||
index_exists = await cursor.fetchone()
|
||||
await cursor.close()
|
||||
|
||||
|
||||
if not index_exists:
|
||||
if dry_run:
|
||||
print(f"DRY RUN: Будет создан индекс {index_name}")
|
||||
@@ -125,26 +135,32 @@ async def main(db_path: str, dry_run: bool = False) -> None:
|
||||
changes_made.append(f"Создан индекс {index_name}")
|
||||
else:
|
||||
print(f"✓ Индекс {index_name} уже существует")
|
||||
|
||||
|
||||
# Финальная статистика
|
||||
if dry_run:
|
||||
if changes_made:
|
||||
print("\n" + "="*60)
|
||||
print("\n" + "=" * 60)
|
||||
print("DRY RUN: Следующие изменения будут выполнены:")
|
||||
for change in changes_made:
|
||||
print(f" - {change}")
|
||||
print("="*60)
|
||||
print("=" * 60)
|
||||
else:
|
||||
print("\n✓ Все необходимые изменения уже применены. Ничего делать не нужно.")
|
||||
print(
|
||||
"\n✓ Все необходимые изменения уже применены. Ничего делать не нужно."
|
||||
)
|
||||
else:
|
||||
if changes_made:
|
||||
logger.info(f"Миграция завершена. Выполнено изменений: {len(changes_made)}")
|
||||
logger.info(
|
||||
f"Миграция завершена. Выполнено изменений: {len(changes_made)}"
|
||||
)
|
||||
print(f"\n✓ Миграция завершена успешно!")
|
||||
print(f"Выполнено изменений: {len(changes_made)}")
|
||||
for change in changes_made:
|
||||
print(f" - {change}")
|
||||
else:
|
||||
print("\n✓ Все необходимые изменения уже применены. Ничего делать не нужно.")
|
||||
print(
|
||||
"\n✓ Все необходимые изменения уже применены. Ничего делать не нужно."
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
Скрипт для проставления status='legacy' всем существующим записям в post_from_telegram_suggest.
|
||||
Добавляет колонку status, если её нет, затем обновляет все строки.
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import asyncio
|
||||
import os
|
||||
@@ -13,6 +14,7 @@ project_root = Path(__file__).resolve().parent.parent
|
||||
sys.path.insert(0, str(project_root))
|
||||
|
||||
import aiosqlite
|
||||
|
||||
from logs.custom_logger import logger
|
||||
|
||||
DEFAULT_DB_PATH = "database/tg-bot-database.db"
|
||||
@@ -37,9 +39,7 @@ async def main(db_path: str) -> None:
|
||||
await conn.execute("PRAGMA foreign_keys = ON")
|
||||
|
||||
# Проверяем наличие колонки status
|
||||
cursor = await conn.execute(
|
||||
"PRAGMA table_info(post_from_telegram_suggest)"
|
||||
)
|
||||
cursor = await conn.execute("PRAGMA table_info(post_from_telegram_suggest)")
|
||||
rows = await cursor.fetchall()
|
||||
await cursor.close()
|
||||
|
||||
@@ -55,9 +55,7 @@ async def main(db_path: str) -> None:
|
||||
print("Колонка status уже существует.")
|
||||
|
||||
# Обновляем все существующие записи на legacy
|
||||
await conn.execute(
|
||||
"UPDATE post_from_telegram_suggest SET status = 'legacy'"
|
||||
)
|
||||
await conn.execute("UPDATE post_from_telegram_suggest SET status = 'legacy'")
|
||||
await conn.commit()
|
||||
cursor = await conn.execute("SELECT changes()")
|
||||
row = await cursor.fetchone()
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
Скрипт для приведения текста постов к "сырому" виду.
|
||||
Удаляет форматирование, добавленное функцией get_text_message(), оставляя только исходный текст.
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import asyncio
|
||||
import html
|
||||
@@ -15,6 +16,7 @@ project_root = Path(__file__).resolve().parent.parent
|
||||
sys.path.insert(0, str(project_root))
|
||||
|
||||
import aiosqlite
|
||||
|
||||
from logs.custom_logger import logger
|
||||
|
||||
DEFAULT_DB_PATH = "database/tg-bot-database.db"
|
||||
@@ -28,37 +30,37 @@ AUTHOR_SUFFIX_PATTERN = re.compile(r"\n\nАвтор поста: .+$")
|
||||
def extract_raw_text(formatted_text: str) -> str:
|
||||
"""
|
||||
Извлекает сырой текст из форматированного текста поста.
|
||||
|
||||
|
||||
Args:
|
||||
formatted_text: Форматированный текст поста
|
||||
|
||||
|
||||
Returns:
|
||||
str: Сырой текст или исходный текст, если форматирование не обнаружено
|
||||
"""
|
||||
if not formatted_text:
|
||||
return ""
|
||||
|
||||
|
||||
# Проверяем, начинается ли текст с префикса
|
||||
if not formatted_text.startswith(PREFIX):
|
||||
# Текст уже в сыром виде или имеет другой формат
|
||||
return formatted_text
|
||||
|
||||
|
||||
# Извлекаем текст после префикса
|
||||
text_after_prefix = formatted_text[len(PREFIX):]
|
||||
|
||||
text_after_prefix = formatted_text[len(PREFIX) :]
|
||||
|
||||
# Проверяем, заканчивается ли текст на "Пост опубликован анонимно"
|
||||
if text_after_prefix.endswith(ANONYMOUS_SUFFIX):
|
||||
raw_text = text_after_prefix[:-len(ANONYMOUS_SUFFIX)]
|
||||
raw_text = text_after_prefix[: -len(ANONYMOUS_SUFFIX)]
|
||||
# Проверяем, заканчивается ли текст на "Автор поста: ..."
|
||||
elif AUTHOR_SUFFIX_PATTERN.search(text_after_prefix):
|
||||
raw_text = AUTHOR_SUFFIX_PATTERN.sub("", text_after_prefix)
|
||||
else:
|
||||
# Не удалось определить формат, возвращаем текст без префикса
|
||||
raw_text = text_after_prefix
|
||||
|
||||
|
||||
# Декодируем HTML-экранирование
|
||||
raw_text = html.unescape(raw_text)
|
||||
|
||||
|
||||
return raw_text
|
||||
|
||||
|
||||
@@ -92,12 +94,12 @@ async def main(db_path: str, dry_run: bool = False) -> None:
|
||||
try:
|
||||
# Извлекаем сырой текст
|
||||
raw_text = extract_raw_text(formatted_text)
|
||||
|
||||
|
||||
# Проверяем, изменился ли текст
|
||||
if raw_text == formatted_text:
|
||||
skipped_count += 1
|
||||
continue
|
||||
|
||||
|
||||
if dry_run:
|
||||
print(f"\n[DRY-RUN] message_id={message_id}:")
|
||||
print(f" Было: {formatted_text[:100]}...")
|
||||
@@ -106,10 +108,10 @@ async def main(db_path: str, dry_run: bool = False) -> None:
|
||||
# Обновляем запись
|
||||
await conn.execute(
|
||||
"UPDATE post_from_telegram_suggest SET text = ? WHERE message_id = ?",
|
||||
(raw_text, message_id)
|
||||
(raw_text, message_id),
|
||||
)
|
||||
updated_count += 1
|
||||
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Ошибка при обработке поста message_id={message_id}: {e}")
|
||||
error_count += 1
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
Скрипт миграции для создания таблицы blacklist_history.
|
||||
Таблица хранит историю всех операций бана/разбана пользователей.
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import asyncio
|
||||
import os
|
||||
@@ -13,6 +14,7 @@ project_root = Path(__file__).resolve().parent.parent
|
||||
sys.path.insert(0, str(project_root))
|
||||
|
||||
import aiosqlite
|
||||
|
||||
from logs.custom_logger import logger
|
||||
|
||||
DEFAULT_DB_PATH = "database/tg-bot-database.db"
|
||||
@@ -45,7 +47,7 @@ async def main(db_path: str) -> None:
|
||||
|
||||
if not rows:
|
||||
logger.info("Создание таблицы blacklist_history")
|
||||
|
||||
|
||||
# Создаем таблицу
|
||||
await conn.execute("""
|
||||
CREATE TABLE IF NOT EXISTS blacklist_history (
|
||||
@@ -61,7 +63,7 @@ async def main(db_path: str) -> None:
|
||||
FOREIGN KEY (ban_author) REFERENCES our_users(user_id) ON DELETE SET NULL
|
||||
)
|
||||
""")
|
||||
|
||||
|
||||
# Создаем индексы
|
||||
await conn.execute(
|
||||
"CREATE INDEX IF NOT EXISTS idx_blacklist_history_user_id ON blacklist_history(user_id)"
|
||||
@@ -72,7 +74,7 @@ async def main(db_path: str) -> None:
|
||||
await conn.execute(
|
||||
"CREATE INDEX IF NOT EXISTS idx_blacklist_history_date_unban ON blacklist_history(date_unban)"
|
||||
)
|
||||
|
||||
|
||||
await conn.commit()
|
||||
logger.info("Таблица blacklist_history и индексы успешно созданы")
|
||||
print("Таблица blacklist_history и индексы успешно созданы.")
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
Скрипт миграции для переноса записей из blacklist в blacklist_history.
|
||||
Переносит все существующие записи из таблицы blacklist в таблицу blacklist_history.
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import asyncio
|
||||
import os
|
||||
@@ -14,6 +15,7 @@ project_root = Path(__file__).resolve().parent.parent
|
||||
sys.path.insert(0, str(project_root))
|
||||
|
||||
import aiosqlite
|
||||
|
||||
from logs.custom_logger import logger
|
||||
|
||||
DEFAULT_DB_PATH = "database/tg-bot-database.db"
|
||||
@@ -37,8 +39,12 @@ async def main(db_path: str) -> None:
|
||||
await cursor.close()
|
||||
|
||||
if not rows:
|
||||
logger.error("Таблица blacklist_history не найдена. Сначала запустите create_blacklist_history_table.py")
|
||||
print("Ошибка: таблица blacklist_history не найдена. Сначала запустите create_blacklist_history_table.py")
|
||||
logger.error(
|
||||
"Таблица blacklist_history не найдена. Сначала запустите create_blacklist_history_table.py"
|
||||
)
|
||||
print(
|
||||
"Ошибка: таблица blacklist_history не найдена. Сначала запустите create_blacklist_history_table.py"
|
||||
)
|
||||
return
|
||||
|
||||
# Получаем все записи из blacklist
|
||||
@@ -53,7 +59,9 @@ async def main(db_path: str) -> None:
|
||||
logger.info("В таблице blacklist нет записей для переноса")
|
||||
return
|
||||
|
||||
logger.info("Найдено записей в blacklist для переноса: %d", len(blacklist_records))
|
||||
logger.info(
|
||||
"Найдено записей в blacklist для переноса: %d", len(blacklist_records)
|
||||
)
|
||||
print(f"Найдено записей в blacklist для переноса: {len(blacklist_records)}")
|
||||
|
||||
# Получаем текущее время в Unix timestamp
|
||||
@@ -69,16 +77,20 @@ async def main(db_path: str) -> None:
|
||||
# Проверяем, нет ли уже записи для этого user_id с таким же date_ban
|
||||
# (чтобы избежать дубликатов при повторном запуске)
|
||||
date_ban = created_at if created_at is not None else current_time
|
||||
|
||||
|
||||
check_cursor = await conn.execute(
|
||||
"SELECT id FROM blacklist_history WHERE user_id = ? AND date_ban = ?",
|
||||
(user_id, date_ban)
|
||||
(user_id, date_ban),
|
||||
)
|
||||
existing = await check_cursor.fetchone()
|
||||
await check_cursor.close()
|
||||
|
||||
if existing:
|
||||
logger.debug("Запись для user_id=%d с date_ban=%d уже существует, пропускаем", user_id, date_ban)
|
||||
logger.debug(
|
||||
"Запись для user_id=%d с date_ban=%d уже существует, пропускаем",
|
||||
user_id,
|
||||
date_ban,
|
||||
)
|
||||
skipped_count += 1
|
||||
continue
|
||||
|
||||
@@ -96,8 +108,8 @@ async def main(db_path: str) -> None:
|
||||
date_to_unban,
|
||||
ban_author,
|
||||
created_at if created_at is not None else current_time,
|
||||
current_time
|
||||
)
|
||||
current_time,
|
||||
),
|
||||
)
|
||||
migrated_count += 1
|
||||
|
||||
@@ -106,9 +118,11 @@ async def main(db_path: str) -> None:
|
||||
logger.info(
|
||||
"Миграция завершена. Перенесено записей: %d, пропущено (дубликаты): %d",
|
||||
migrated_count,
|
||||
skipped_count
|
||||
skipped_count,
|
||||
)
|
||||
print(
|
||||
f"Миграция завершена. Перенесено записей: {migrated_count}, пропущено (дубликаты): {skipped_count}"
|
||||
)
|
||||
print(f"Миграция завершена. Перенесено записей: {migrated_count}, пропущено (дубликаты): {skipped_count}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
Скрипт для проверки подключения к S3 хранилищу.
|
||||
Читает настройки из .env файла или переменных окружения.
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
import os
|
||||
import sys
|
||||
@@ -14,7 +15,7 @@ sys.path.insert(0, str(project_root))
|
||||
# Загружаем .env файл
|
||||
from dotenv import load_dotenv
|
||||
|
||||
env_path = os.path.join(project_root, '.env')
|
||||
env_path = os.path.join(project_root, ".env")
|
||||
if os.path.exists(env_path):
|
||||
load_dotenv(env_path)
|
||||
|
||||
@@ -26,11 +27,12 @@ except ImportError:
|
||||
sys.exit(1)
|
||||
|
||||
# Данные для подключения из .env или переменных окружения
|
||||
S3_ACCESS_KEY = os.getenv('S3_ACCESS_KEY', 'j3tears100@gmail.com')
|
||||
S3_SECRET_KEY = os.getenv('S3_SECRET_KEY', 'wQ1-6sZEPs92sbZTSf96')
|
||||
S3_ENDPOINT_URL = os.getenv('S3_ENDPOINT_URL', 'https://api.s3.miran.ru:443')
|
||||
S3_BUCKET_NAME = os.getenv('S3_BUCKET_NAME', 'telegram-helper-bot')
|
||||
S3_REGION = os.getenv('S3_REGION', 'us-east-1')
|
||||
S3_ACCESS_KEY = os.getenv("S3_ACCESS_KEY", "j3tears100@gmail.com")
|
||||
S3_SECRET_KEY = os.getenv("S3_SECRET_KEY", "wQ1-6sZEPs92sbZTSf96")
|
||||
S3_ENDPOINT_URL = os.getenv("S3_ENDPOINT_URL", "https://api.s3.miran.ru:443")
|
||||
S3_BUCKET_NAME = os.getenv("S3_BUCKET_NAME", "telegram-helper-bot")
|
||||
S3_REGION = os.getenv("S3_REGION", "us-east-1")
|
||||
|
||||
|
||||
async def test_s3_connection():
|
||||
"""Тестирует подключение к S3 хранилищу."""
|
||||
@@ -40,50 +42,54 @@ async def test_s3_connection():
|
||||
print(f"Region: {S3_REGION}")
|
||||
print(f"Access Key: {S3_ACCESS_KEY}")
|
||||
print()
|
||||
|
||||
|
||||
session = aioboto3.Session()
|
||||
|
||||
|
||||
try:
|
||||
async with session.client(
|
||||
's3',
|
||||
"s3",
|
||||
endpoint_url=S3_ENDPOINT_URL,
|
||||
aws_access_key_id=S3_ACCESS_KEY,
|
||||
aws_secret_access_key=S3_SECRET_KEY,
|
||||
region_name=S3_REGION
|
||||
region_name=S3_REGION,
|
||||
) as s3:
|
||||
# Пытаемся получить список бакетов (может не иметь прав, пропускаем если ошибка)
|
||||
print("📦 Получение списка бакетов...")
|
||||
try:
|
||||
response = await s3.list_buckets()
|
||||
buckets = response.get('Buckets', [])
|
||||
buckets = response.get("Buckets", [])
|
||||
print(f"✅ Подключение успешно! Найдено бакетов: {len(buckets)}")
|
||||
|
||||
|
||||
if buckets:
|
||||
print("\n📋 Список бакетов:")
|
||||
for bucket in buckets:
|
||||
print(f" - {bucket['Name']} (создан: {bucket.get('CreationDate', 'неизвестно')})")
|
||||
print(
|
||||
f" - {bucket['Name']} (создан: {bucket.get('CreationDate', 'неизвестно')})"
|
||||
)
|
||||
else:
|
||||
print("\n⚠️ Бакеты не найдены.")
|
||||
except Exception as list_error:
|
||||
print(f"⚠️ Не удалось получить список бакетов: {list_error}")
|
||||
print(" Это нормально, если нет прав на list_buckets")
|
||||
print(" Продолжаем тестирование с указанным бакетом...")
|
||||
|
||||
|
||||
# Пытаемся создать тестовый файл в указанном бакете
|
||||
print("\n🧪 Тестирование записи файла...")
|
||||
# Используем первый найденный бакет, если указанный не найден
|
||||
test_bucket = S3_BUCKET_NAME
|
||||
if buckets:
|
||||
# Проверяем, есть ли указанный бакет в списке
|
||||
bucket_names = [b['Name'] for b in buckets]
|
||||
bucket_names = [b["Name"] for b in buckets]
|
||||
if test_bucket not in bucket_names:
|
||||
print(f"⚠️ Бакет '{test_bucket}' не найден в списке.")
|
||||
print(f" Используем первый найденный бакет: '{buckets[0]['Name']}'")
|
||||
test_bucket = buckets[0]['Name']
|
||||
|
||||
test_key = 'test-connection.txt'
|
||||
test_content = b'Test connection to S3 storage'
|
||||
|
||||
print(
|
||||
f" Используем первый найденный бакет: '{buckets[0]['Name']}'"
|
||||
)
|
||||
test_bucket = buckets[0]["Name"]
|
||||
|
||||
test_key = "test-connection.txt"
|
||||
test_content = b"Test connection to S3 storage"
|
||||
|
||||
try:
|
||||
# Проверяем существование бакета
|
||||
try:
|
||||
@@ -93,33 +99,32 @@ async def test_s3_connection():
|
||||
print(f"❌ Бакет '{test_bucket}' недоступен: {head_error}")
|
||||
print(" Проверьте права доступа к бакету")
|
||||
return False
|
||||
|
||||
await s3.put_object(
|
||||
Bucket=test_bucket,
|
||||
Key=test_key,
|
||||
Body=test_content
|
||||
|
||||
await s3.put_object(Bucket=test_bucket, Key=test_key, Body=test_content)
|
||||
print(
|
||||
f"✅ Файл успешно записан в бакет '{test_bucket}' с ключом '{test_key}'"
|
||||
)
|
||||
print(f"✅ Файл успешно записан в бакет '{test_bucket}' с ключом '{test_key}'")
|
||||
|
||||
|
||||
# Пытаемся прочитать файл
|
||||
print("🧪 Тестирование чтения файла...")
|
||||
response = await s3.get_object(Bucket=test_bucket, Key=test_key)
|
||||
content = await response['Body'].read()
|
||||
|
||||
content = await response["Body"].read()
|
||||
|
||||
if content == test_content:
|
||||
print("✅ Файл успешно прочитан, содержимое совпадает")
|
||||
else:
|
||||
print("⚠️ Файл прочитан, но содержимое не совпадает")
|
||||
|
||||
|
||||
# Удаляем тестовый файл
|
||||
print("🧹 Удаление тестового файла...")
|
||||
await s3.delete_object(Bucket=test_bucket, Key=test_key)
|
||||
print("✅ Тестовый файл удален")
|
||||
|
||||
|
||||
except Exception as e:
|
||||
print(f"❌ Ошибка при тестировании записи/чтения: {e}")
|
||||
print(f" Тип ошибки: {type(e).__name__}")
|
||||
import traceback
|
||||
|
||||
print(f" Полный traceback:")
|
||||
traceback.print_exc()
|
||||
print("\nВозможные причины:")
|
||||
@@ -127,9 +132,9 @@ async def test_s3_connection():
|
||||
print(" 2. Нет прав на запись в бакет")
|
||||
print(" 3. Неверный endpoint URL или регион")
|
||||
print(" 4. Проблемы с форматом endpoint (попробуйте без :443)")
|
||||
|
||||
|
||||
return True
|
||||
|
||||
|
||||
except Exception as e:
|
||||
print(f"❌ Ошибка подключения к S3: {e}")
|
||||
print("\nВозможные причины:")
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"""
|
||||
Скрипт для диагностики и очистки проблем с голосовыми файлами
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
import os
|
||||
import sys
|
||||
@@ -24,15 +25,15 @@ async def main():
|
||||
if not os.path.exists(db_path):
|
||||
logger.error(f"База данных не найдена: {db_path}")
|
||||
return
|
||||
|
||||
|
||||
bot_db = AsyncBotDB(db_path)
|
||||
cleanup_utils = VoiceFileCleanupUtils(bot_db)
|
||||
|
||||
|
||||
print("=== Диагностика голосовых файлов ===")
|
||||
|
||||
|
||||
# Запускаем полную диагностику
|
||||
diagnostic_result = await cleanup_utils.run_full_diagnostic()
|
||||
|
||||
|
||||
print(f"\n📊 Статистика диска:")
|
||||
if "error" in diagnostic_result["disk_stats"]:
|
||||
print(f" ❌ Ошибка: {diagnostic_result['disk_stats']['error']}")
|
||||
@@ -41,59 +42,65 @@ async def main():
|
||||
print(f" 📁 Директория: {stats['directory']}")
|
||||
print(f" 📄 Всего файлов: {stats['total_files']}")
|
||||
print(f" 💾 Размер: {stats['total_size_mb']} MB")
|
||||
|
||||
|
||||
print(f"\n🗄️ База данных:")
|
||||
print(f" 📝 Записей в БД: {diagnostic_result['db_records_count']}")
|
||||
print(f" 🔍 Записей без файлов: {diagnostic_result['orphaned_db_records_count']}")
|
||||
print(
|
||||
f" 🔍 Записей без файлов: {diagnostic_result['orphaned_db_records_count']}"
|
||||
)
|
||||
print(f" 📁 Файлов без записей: {diagnostic_result['orphaned_files_count']}")
|
||||
|
||||
|
||||
print(f"\n📋 Статус: {diagnostic_result['status']}")
|
||||
|
||||
if diagnostic_result['status'] == 'issues_found':
|
||||
|
||||
if diagnostic_result["status"] == "issues_found":
|
||||
print("\n⚠️ Найдены проблемы!")
|
||||
|
||||
if diagnostic_result['orphaned_db_records_count'] > 0:
|
||||
|
||||
if diagnostic_result["orphaned_db_records_count"] > 0:
|
||||
print(f"\n🗑️ Записи в БД без файлов (первые 10):")
|
||||
for file_name, user_id in diagnostic_result['orphaned_db_records']:
|
||||
for file_name, user_id in diagnostic_result["orphaned_db_records"]:
|
||||
print(f" - {file_name} (user_id: {user_id})")
|
||||
|
||||
if diagnostic_result['orphaned_files_count'] > 0:
|
||||
|
||||
if diagnostic_result["orphaned_files_count"] > 0:
|
||||
print(f"\n📁 Файлы без записей в БД (первые 10):")
|
||||
for file_path in diagnostic_result['orphaned_files']:
|
||||
for file_path in diagnostic_result["orphaned_files"]:
|
||||
print(f" - {file_path}")
|
||||
|
||||
|
||||
# Предлагаем очистку
|
||||
print("\n🧹 Хотите выполнить очистку?")
|
||||
print("1. Удалить записи в БД без файлов")
|
||||
print("2. Удалить файлы без записей в БД")
|
||||
print("3. Выполнить полную очистку")
|
||||
print("4. Выход")
|
||||
|
||||
|
||||
choice = input("\nВыберите действие (1-4): ").strip()
|
||||
|
||||
|
||||
if choice == "1":
|
||||
print("\n🗑️ Удаление записей в БД без файлов...")
|
||||
deleted = await cleanup_utils.cleanup_orphaned_db_records(dry_run=False)
|
||||
print(f"✅ Удалено {deleted} записей")
|
||||
|
||||
|
||||
elif choice == "2":
|
||||
print("\n📁 Удаление файлов без записей в БД...")
|
||||
deleted = await cleanup_utils.cleanup_orphaned_files(dry_run=False)
|
||||
print(f"✅ Удалено {deleted} файлов")
|
||||
|
||||
|
||||
elif choice == "3":
|
||||
print("\n🧹 Полная очистка...")
|
||||
db_deleted = await cleanup_utils.cleanup_orphaned_db_records(dry_run=False)
|
||||
files_deleted = await cleanup_utils.cleanup_orphaned_files(dry_run=False)
|
||||
db_deleted = await cleanup_utils.cleanup_orphaned_db_records(
|
||||
dry_run=False
|
||||
)
|
||||
files_deleted = await cleanup_utils.cleanup_orphaned_files(
|
||||
dry_run=False
|
||||
)
|
||||
print(f"✅ Удалено {db_deleted} записей в БД и {files_deleted} файлов")
|
||||
|
||||
|
||||
elif choice == "4":
|
||||
print("👋 Выход...")
|
||||
else:
|
||||
print("❌ Неверный выбор")
|
||||
else:
|
||||
print("\n✅ Проблем не найдено!")
|
||||
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Ошибка в скрипте: {e}")
|
||||
print(f"❌ Ошибка: {e}")
|
||||
|
||||
Reference in New Issue
Block a user