Добавление модуля загрузки категорий для API ВОЛК и соответствующей кнопки на фронте
ci/woodpecker/push/woodpecker Pipeline was successful
ci/woodpecker/push/woodpecker Pipeline was successful
This commit is contained in:
+21
@@ -24,6 +24,7 @@ from tg_publish import publish_to_tg_all, publish_to_tg
|
||||
from db_update_shortname import ai_shortname_all, generate_ai_shortname
|
||||
from evtg_publish import tg_post_event_by_id, tg_post_all_events
|
||||
from zk_load import load_json_all
|
||||
from volk_load import load_categories
|
||||
|
||||
# Загружаем настройки из .env
|
||||
load_dotenv()
|
||||
@@ -1064,6 +1065,26 @@ def api_publish_all_events():
|
||||
log_event(error_msg)
|
||||
return jsonify({'success': False, 'error': error_msg}), 500
|
||||
|
||||
@bp.route('/api/load_categories', methods=['POST'])
|
||||
@login_required
|
||||
def api_load_categories():
|
||||
try:
|
||||
# Проверка режима работы
|
||||
workmode = os.getenv('WORKMODE', 'ZILANT')
|
||||
if workmode != 'VOLK':
|
||||
error_msg = "Загрузка категорий доступна только в режиме VOLK"
|
||||
log_event(error_msg)
|
||||
return jsonify({'success': False, 'error': error_msg}), 403
|
||||
|
||||
log_event("Запуск загрузки категорий...")
|
||||
load_categories()
|
||||
log_event("Загрузка категорий выполнена успешно")
|
||||
return jsonify({'success': True})
|
||||
except Exception as e:
|
||||
error_msg = f"Ошибка при загрузке категорий: {str(e)}"
|
||||
log_event(error_msg)
|
||||
return jsonify({'success': False, 'error': error_msg}), 500
|
||||
|
||||
@bp.route('/api/publish_event/<int:event_id>', methods=['POST'])
|
||||
@login_required
|
||||
def api_publish_event(event_id):
|
||||
|
||||
@@ -566,6 +566,11 @@
|
||||
<button class="btn btn-success" id="publish-all-events-btn">
|
||||
<i class="fas fa-paper-plane me-1"></i> Опубликовать все
|
||||
</button>
|
||||
{% if g.workmode == 'VOLK' %}
|
||||
<button class="btn btn-info ms-2" id="load-categories-btn">
|
||||
<i class="fas fa-sync-alt me-1"></i> Категории
|
||||
</button>
|
||||
{% endif %}
|
||||
<div id="event-selected-post-info" class="cross-tab-info" style="display: none;">
|
||||
<span>Выбранный пост: </span>
|
||||
<span id="event-selected-post-name"></span>
|
||||
@@ -857,6 +862,12 @@
|
||||
// Новые обработчики для кнопок событий
|
||||
document.getElementById('zk-rescan-btn').addEventListener('click', runZkRescan);
|
||||
document.getElementById('publish-all-events-btn').addEventListener('click', publishAllEvents);
|
||||
{% if g.workmode == 'VOLK' %}
|
||||
const loadCategoriesBtn = document.getElementById('load-categories-btn');
|
||||
if (loadCategoriesBtn) {
|
||||
loadCategoriesBtn.addEventListener('click', loadCategories);
|
||||
}
|
||||
{% endif %}
|
||||
// Обработчики для кнопок привязки
|
||||
document.getElementById('post-link-event-btn').addEventListener('click', togglePostEventLink);
|
||||
document.getElementById('event-link-post-btn').addEventListener('click', togglePostEventLink);
|
||||
@@ -977,6 +988,31 @@
|
||||
alert('Произошла ошибка при публикации всех событий');
|
||||
});
|
||||
}
|
||||
// Функция для загрузки категорий
|
||||
function loadCategories() {
|
||||
showProcessingMessage("Загрузка категорий...");
|
||||
fetch(`${PREFIX}/api/load_categories`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'X-Requested-With': 'XMLHttpRequest'
|
||||
}
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
hideProcessingMessage();
|
||||
if (data.success) {
|
||||
alert('Категории загружены успешно!');
|
||||
} else {
|
||||
alert('Ошибка загрузки категорий: ' + (data.error || 'неизвестная ошибка'));
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
hideProcessingMessage();
|
||||
console.error('Ошибка загрузки категорий:', error);
|
||||
alert('Произошла ошибка при загрузке категорий');
|
||||
});
|
||||
}
|
||||
// Функция для публикации конкретного события
|
||||
function publishCurrentEvent(eventId) {
|
||||
if (!eventId) return;
|
||||
|
||||
+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