Добавление модуля загрузки категорий для API ВОЛК и соответствующей кнопки на фронте
ci/woodpecker/push/woodpecker Pipeline was successful
ci/woodpecker/push/woodpecker Pipeline was successful
This commit is contained in:
+160
@@ -0,0 +1,160 @@
|
||||
import os
|
||||
import json
|
||||
import time
|
||||
from datetime import datetime
|
||||
from urllib.request import urlopen
|
||||
from dotenv import load_dotenv
|
||||
import mysql.connector
|
||||
from mysql.connector import Error
|
||||
from ensure_db import ensure_database_structure
|
||||
|
||||
# Загрузка переменных окружения
|
||||
load_dotenv()
|
||||
|
||||
VOLK_CATEGORY_LIST = os.getenv('VOLK_CATEGORY_LIST')
|
||||
VOLK_API_VERSION = os.getenv('VOLK_API_VERSION')
|
||||
MDB_HOST = os.getenv('MDB_HOST')
|
||||
MDB_USER = os.getenv('MDB_USER')
|
||||
MDB_PW = os.getenv('MDB_PW')
|
||||
MDBASE = os.getenv('MDBASE')
|
||||
LOG_FILE = os.getenv('LOG_FILE')
|
||||
|
||||
def log_message(message, category="VOLK_loader"):
|
||||
"""Функция для записи в лог-файл с повторными попытками при блокировке"""
|
||||
timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
||||
log_entry = f"[{timestamp}] [{category}] {message}\n"
|
||||
|
||||
# До 5 попыток записи с увеличением задержки
|
||||
for attempt in range(5):
|
||||
try:
|
||||
with open(LOG_FILE, 'a', encoding='utf-8') as f:
|
||||
f.write(log_entry)
|
||||
return True
|
||||
except (IOError, OSError) as e:
|
||||
if attempt < 4: # Не последняя попытка
|
||||
time.sleep(0.4) # Задержка 400ms между попытками
|
||||
else:
|
||||
# После 5 неудачных попыток выводим в stdout
|
||||
print(f"Не удалось записать в лог после 5 попыток: {log_entry.strip()}")
|
||||
return False
|
||||
return False
|
||||
|
||||
def load_categories():
|
||||
"""Экспортируемая функция для загрузки категорий из JSON в базу данных"""
|
||||
inserted_count = 0
|
||||
updated_count = 0
|
||||
|
||||
try:
|
||||
log_message("Начало работы")
|
||||
|
||||
# Проверка наличия URL
|
||||
if not VOLK_CATEGORY_LIST:
|
||||
error_msg = "Переменная окружения VOLK_CATEGORY_LIST не установлена"
|
||||
log_message(error_msg, "ERROR")
|
||||
print(error_msg)
|
||||
return
|
||||
|
||||
# Чтение JSON из URL
|
||||
log_message(f"Чтение данных из {VOLK_CATEGORY_LIST}")
|
||||
with urlopen(VOLK_CATEGORY_LIST) as response:
|
||||
data = json.loads(response.read().decode())
|
||||
|
||||
# Проверка версии API
|
||||
api_version = data.get('api_version')
|
||||
if api_version != VOLK_API_VERSION:
|
||||
error_msg = f"Несовпадение версии API: получена версия '{api_version}', ожидается '{VOLK_API_VERSION}'. Обработка остановлена."
|
||||
log_message(error_msg, "ERROR")
|
||||
print(error_msg)
|
||||
return
|
||||
|
||||
log_message(f"Версия API соответствует: {api_version}")
|
||||
|
||||
# Проверка наличия блока data
|
||||
if 'data' not in data:
|
||||
error_msg = "В JSON отсутствует блок 'data'"
|
||||
log_message(error_msg, "ERROR")
|
||||
print(error_msg)
|
||||
return
|
||||
|
||||
categories_data = data['data']
|
||||
log_message(f"Получено {len(categories_data)} записей для обработки")
|
||||
|
||||
# Подключение к базе данных
|
||||
connection = mysql.connector.connect(
|
||||
host=MDB_HOST,
|
||||
user=MDB_USER,
|
||||
password=MDB_PW,
|
||||
database=MDBASE
|
||||
)
|
||||
|
||||
# Установка временной зоны соединения в UTC
|
||||
cursor_temp = connection.cursor()
|
||||
cursor_temp.execute("SET time_zone = '+00:00'")
|
||||
cursor_temp.close()
|
||||
|
||||
cursor = connection.cursor(dictionary=True)
|
||||
|
||||
# Проверка структуры БД
|
||||
log_message("Проверка структуры базы данных")
|
||||
ensure_database_structure()
|
||||
|
||||
for item in categories_data:
|
||||
# Проверка обязательного поля ID
|
||||
if 'id' not in item or not item['id']:
|
||||
log_message(f"Пропущена запись без id или с пустым id: {item}", "WARNING")
|
||||
continue
|
||||
|
||||
# Подготовка значений
|
||||
category_id = item['id']
|
||||
# TITLE может отсутствовать или быть пустым - в этом случае используем пустую строку
|
||||
title = item.get('title', '') or ''
|
||||
|
||||
# Проверка существующей записи
|
||||
cursor.execute(
|
||||
"SELECT AUTO_ID, ID, TITLE FROM categories WHERE ID = %s",
|
||||
(category_id,)
|
||||
)
|
||||
existing = cursor.fetchone()
|
||||
|
||||
if not existing:
|
||||
# Вставка новой записи
|
||||
cursor.execute(
|
||||
"INSERT INTO categories (ID, TITLE) VALUES (%s, %s)",
|
||||
(category_id, title)
|
||||
)
|
||||
inserted_count += 1
|
||||
log_message(f"Добавление: Категория {category_id}, Название: {title if title else '(пусто)'}")
|
||||
else:
|
||||
# Обновление существующей записи (всегда обновляем TITLE, даже если оно пустое)
|
||||
if existing['TITLE'] != title:
|
||||
cursor.execute(
|
||||
"UPDATE categories SET TITLE = %s WHERE ID = %s",
|
||||
(title, category_id)
|
||||
)
|
||||
updated_count += 1
|
||||
log_message(f"Обновление: Категория {category_id}, Новое название: {title if title else '(пусто)'}")
|
||||
else:
|
||||
log_message(f"Категория {category_id} без изменений")
|
||||
|
||||
connection.commit()
|
||||
|
||||
log_message(f"Завершение работы. Добавлено записей: {inserted_count}. Обновлено записей: {updated_count}.")
|
||||
|
||||
except Error as e:
|
||||
error_msg = f"Ошибка базы данных: {e}"
|
||||
log_message(error_msg, "ERROR")
|
||||
print(error_msg)
|
||||
if 'connection' in locals() and connection.is_connected():
|
||||
connection.rollback()
|
||||
except Exception as e:
|
||||
error_msg = f"Общая ошибка: {e}"
|
||||
log_message(error_msg, "ERROR")
|
||||
print(error_msg)
|
||||
finally:
|
||||
if 'connection' in locals() and connection.is_connected():
|
||||
cursor.close()
|
||||
connection.close()
|
||||
|
||||
if __name__ == "__main__":
|
||||
load_categories()
|
||||
|
||||
Reference in New Issue
Block a user