2025-07-04 15:09:14 +05:00
|
|
|
|
import os
|
|
|
|
|
|
import logging
|
2025-07-10 13:34:45 +05:00
|
|
|
|
from pathlib import Path
|
|
|
|
|
|
|
|
|
|
|
|
import polib
|
|
|
|
|
|
from docutils.nodes import entry
|
2025-07-08 15:08:32 +05:00
|
|
|
|
from fastapi import APIRouter, HTTPException, Depends
|
2025-07-04 15:09:14 +05:00
|
|
|
|
from starlette.responses import FileResponse
|
2025-06-23 15:19:56 +05:00
|
|
|
|
from services.settings_service import SettingsService
|
2025-07-08 15:02:39 +05:00
|
|
|
|
from utils.i18n import get_translations, _
|
|
|
|
|
|
from babel.support import Translations
|
2025-07-09 13:16:34 +05:00
|
|
|
|
|
2025-07-04 15:09:14 +05:00
|
|
|
|
|
2025-07-08 15:08:32 +05:00
|
|
|
|
logging.basicConfig(level=logging.DEBUG)
|
2025-07-04 15:09:14 +05:00
|
|
|
|
logger = logging.getLogger(__name__)
|
2025-06-23 15:19:56 +05:00
|
|
|
|
|
|
|
|
|
|
router = APIRouter()
|
|
|
|
|
|
settings_service = SettingsService()
|
|
|
|
|
|
|
|
|
|
|
|
@router.post("/clear_subnet")
|
2025-07-08 15:02:39 +05:00
|
|
|
|
def clear_subnet(translations: Translations = Depends(get_translations("api_v1"))):
|
2025-06-23 15:19:56 +05:00
|
|
|
|
"""Очищает данные узлов подсети, сохранённые в devices.json.
|
|
|
|
|
|
|
|
|
|
|
|
Удаляет все записи об узлах подсети, оставляя файл пустым.
|
|
|
|
|
|
|
2025-07-08 15:02:39 +05:00
|
|
|
|
Args:
|
|
|
|
|
|
translations: Объект переводов для текущего языка.
|
|
|
|
|
|
|
2025-06-23 15:19:56 +05:00
|
|
|
|
Returns:
|
|
|
|
|
|
dict: Словарь с сообщением об успешной очистке.
|
|
|
|
|
|
|
|
|
|
|
|
Raises:
|
|
|
|
|
|
HTTPException: Если произошла ошибка очистки (status_code=500).
|
|
|
|
|
|
"""
|
|
|
|
|
|
try:
|
|
|
|
|
|
success = settings_service.clear_subnet()
|
|
|
|
|
|
if success:
|
2025-07-08 15:02:39 +05:00
|
|
|
|
return {"message": translations.gettext("Данные узлов подсети успешно очищены")}
|
|
|
|
|
|
else:
|
|
|
|
|
|
raise HTTPException(status_code=500, detail=translations.gettext("Не удалось очистить данные узлов подсети"))
|
2025-06-23 15:19:56 +05:00
|
|
|
|
except Exception as e:
|
2025-07-08 15:02:39 +05:00
|
|
|
|
logger.error(f"Error clearing subnet data: {str(e)}")
|
|
|
|
|
|
raise HTTPException(status_code=500, detail=translations.gettext("Ошибка очистки: {error}").format(error=str(e)))
|
2025-06-23 15:19:56 +05:00
|
|
|
|
|
|
|
|
|
|
@router.post("/clear_wifi")
|
2025-07-08 15:02:39 +05:00
|
|
|
|
def clear_wifi(translations: Translations = Depends(get_translations("api_v1"))):
|
2025-06-23 15:19:56 +05:00
|
|
|
|
"""Очищает данные точек доступа Wi-Fi, сохранённые в wifi.json.
|
|
|
|
|
|
|
|
|
|
|
|
Удаляет все записи о точках доступа, оставляя файл пустым.
|
|
|
|
|
|
|
2025-07-08 15:02:39 +05:00
|
|
|
|
Args:
|
|
|
|
|
|
translations: Объект переводов для текущего языка.
|
|
|
|
|
|
|
2025-06-23 15:19:56 +05:00
|
|
|
|
Returns:
|
|
|
|
|
|
dict: Словарь с сообщением об успешной очистке.
|
|
|
|
|
|
|
|
|
|
|
|
Raises:
|
|
|
|
|
|
HTTPException: Если произошла ошибка очистки (status_code=500).
|
|
|
|
|
|
"""
|
|
|
|
|
|
try:
|
|
|
|
|
|
success = settings_service.clear_wifi()
|
|
|
|
|
|
if success:
|
2025-07-08 15:02:39 +05:00
|
|
|
|
return {"message": translations.gettext("Данные точек доступа Wi-Fi успешно очищены")}
|
|
|
|
|
|
else:
|
|
|
|
|
|
raise HTTPException(status_code=500, detail=translations.gettext("Не удалось очистить данные точек доступа Wi-Fi"))
|
2025-06-23 15:19:56 +05:00
|
|
|
|
except Exception as e:
|
2025-07-08 15:02:39 +05:00
|
|
|
|
logger.error(f"Error clearing wifi data: {str(e)}")
|
|
|
|
|
|
raise HTTPException(status_code=500, detail=translations.gettext("Ошибка очистки: {error}").format(error=str(e)))
|
2025-06-23 15:19:56 +05:00
|
|
|
|
|
|
|
|
|
|
@router.post("/clear_all_data")
|
2025-07-08 15:02:39 +05:00
|
|
|
|
def clear_all_data(translations: Translations = Depends(get_translations("api_v1"))):
|
2025-06-23 15:19:56 +05:00
|
|
|
|
"""Очищает данные узлов подсети и точек доступа Wi-Fi в обоих файлах.
|
|
|
|
|
|
|
|
|
|
|
|
Удаляет все записи из devices.json и wifi.json.
|
|
|
|
|
|
|
2025-07-08 15:02:39 +05:00
|
|
|
|
Args:
|
|
|
|
|
|
translations: Объект переводов для текущего языка.
|
|
|
|
|
|
|
2025-06-23 15:19:56 +05:00
|
|
|
|
Returns:
|
|
|
|
|
|
dict: Словарь с сообщением об успешной очистке.
|
|
|
|
|
|
|
|
|
|
|
|
Raises:
|
|
|
|
|
|
HTTPException: Если произошла ошибка очистки (status_code=500).
|
|
|
|
|
|
"""
|
|
|
|
|
|
try:
|
|
|
|
|
|
success = settings_service.clear_all_data()
|
|
|
|
|
|
if success:
|
2025-07-08 15:02:39 +05:00
|
|
|
|
return {"message": translations.gettext("Все сетевые данные успешно очищены")}
|
|
|
|
|
|
else:
|
|
|
|
|
|
raise HTTPException(status_code=500, detail=translations.gettext("Не удалось очистить все сетевые данные"))
|
2025-06-23 15:19:56 +05:00
|
|
|
|
except Exception as e:
|
2025-07-08 15:02:39 +05:00
|
|
|
|
logger.error(f"Error clearing all data: {str(e)}")
|
|
|
|
|
|
raise HTTPException(status_code=500, detail=translations.gettext("Ошибка очистки: {error}").format(error=str(e)))
|
2025-07-04 15:09:14 +05:00
|
|
|
|
|
2025-07-04 16:03:59 +05:00
|
|
|
|
DEVICE_PATH = "storage/devices/devices.json"
|
|
|
|
|
|
WIFI_PATH = "storage/wifi/wifi.json"
|
2025-07-04 15:09:14 +05:00
|
|
|
|
|
2025-07-04 16:03:59 +05:00
|
|
|
|
@router.get("/export_devices", response_class=FileResponse)
|
2025-07-08 15:02:39 +05:00
|
|
|
|
async def export_devices(translations: Translations = Depends(get_translations("api_v1"))):
|
2025-07-04 16:03:59 +05:00
|
|
|
|
"""
|
|
|
|
|
|
Экспортирует файл с данными устройств в формате JSON.
|
|
|
|
|
|
|
2025-07-08 15:02:39 +05:00
|
|
|
|
Args:
|
|
|
|
|
|
translations: Объект переводов для текущего языка.
|
|
|
|
|
|
|
2025-07-04 16:03:59 +05:00
|
|
|
|
Returns:
|
|
|
|
|
|
FileResponse: Файл devices.json для скачивания.
|
|
|
|
|
|
|
|
|
|
|
|
Raises:
|
|
|
|
|
|
HTTPException: Если файл не найден (status_code=404).
|
|
|
|
|
|
"""
|
2025-07-04 15:09:14 +05:00
|
|
|
|
if not os.path.exists(DEVICE_PATH):
|
2025-07-08 15:02:39 +05:00
|
|
|
|
logger.warning(f"Export file not found: {DEVICE_PATH}")
|
|
|
|
|
|
raise HTTPException(status_code=404, detail=translations.gettext("Файл не найден"))
|
|
|
|
|
|
logger.info(f"Exporting file: {DEVICE_PATH}")
|
2025-07-04 15:09:14 +05:00
|
|
|
|
return FileResponse(
|
|
|
|
|
|
path=DEVICE_PATH,
|
2025-07-04 16:03:59 +05:00
|
|
|
|
filename="devices.json",
|
|
|
|
|
|
media_type="application/json"
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
@router.get("/export_wifi", response_class=FileResponse)
|
2025-07-08 15:02:39 +05:00
|
|
|
|
async def export_wifi(translations: Translations = Depends(get_translations("api_v1"))):
|
2025-07-04 16:03:59 +05:00
|
|
|
|
"""
|
|
|
|
|
|
Экспортирует файл с данными устройств в формате JSON.
|
|
|
|
|
|
|
2025-07-08 15:02:39 +05:00
|
|
|
|
Args:
|
|
|
|
|
|
translations: Объект переводов для текущего языка.
|
|
|
|
|
|
|
2025-07-04 16:03:59 +05:00
|
|
|
|
Returns:
|
2025-07-08 15:02:39 +05:00
|
|
|
|
FileResponse: Файл wifi.json для скачивания.
|
2025-07-04 16:03:59 +05:00
|
|
|
|
|
|
|
|
|
|
Raises:
|
|
|
|
|
|
HTTPException: Если файл не найден (status_code=404).
|
|
|
|
|
|
"""
|
|
|
|
|
|
if not os.path.exists(WIFI_PATH):
|
2025-07-08 15:02:39 +05:00
|
|
|
|
logger.warning(f"Export file not found: {WIFI_PATH}")
|
|
|
|
|
|
raise HTTPException(status_code=404, detail=translations.gettext("Файл не найден"))
|
|
|
|
|
|
logger.info(f"Exporting file: {WIFI_PATH}")
|
2025-07-04 16:03:59 +05:00
|
|
|
|
return FileResponse(
|
|
|
|
|
|
path=WIFI_PATH,
|
|
|
|
|
|
filename="wifi.json",
|
2025-07-04 15:09:14 +05:00
|
|
|
|
media_type="application/json"
|
2025-07-10 13:34:45 +05:00
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
@router.get("/{locale}/{domain}")
|
|
|
|
|
|
async def get_translations(locale: str, domain: str):
|
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
|
|
Args:
|
|
|
|
|
|
locale:
|
|
|
|
|
|
domain:
|
|
|
|
|
|
|
|
|
|
|
|
Returns:
|
|
|
|
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
|
try:
|
|
|
|
|
|
po_file = Path(f"locales/{locale}/LC_MESSAGES/{domain}.po")
|
|
|
|
|
|
if not po_file.exists():
|
|
|
|
|
|
logger.warning(f"Файл интернационализации для {locale} и домена {domain} не найдены")
|
|
|
|
|
|
raise HTTPException(status_code=404, detail=f"Файл интернационализации для {locale} и домена {domain} не найдены")
|
|
|
|
|
|
po = polib.pofile(str(po_file))
|
|
|
|
|
|
translations = {entry.msgid: entry.msgstr or entry.msgid for entry in po}
|
|
|
|
|
|
logger.info(f"Загрузка {len(translations)} перевода для локали {locale} и домена {domain}")
|
|
|
|
|
|
return translations
|
|
|
|
|
|
except Exception as e:
|
|
|
|
|
|
logger.error(f"Ошибка загрузки перевода для локали {locale} и домена {domain}: {str(e)}")
|
|
|
|
|
|
raise HTTPException(status_code=500, detail=f"Ошибка на сервере: {str(e)}")
|