Разделение сканирования на разные подсети. Хранение каждой из просканированных подсетей. Исправление багов с заметками и обновленные локали
This commit is contained in:
parent
c326edfb9a
commit
b1306ff66f
10 changed files with 1124 additions and 285 deletions
|
|
@ -1,5 +1,6 @@
|
||||||
import os
|
import os
|
||||||
import logging
|
import logging
|
||||||
|
from typing import Optional
|
||||||
from fastapi import APIRouter, HTTPException, Depends, Response, Request
|
from fastapi import APIRouter, HTTPException, Depends, Response, Request
|
||||||
from starlette.responses import FileResponse
|
from starlette.responses import FileResponse
|
||||||
from services.settings_service import SettingsService
|
from services.settings_service import SettingsService
|
||||||
|
|
@ -13,12 +14,14 @@ router = APIRouter()
|
||||||
settings_service = SettingsService()
|
settings_service = SettingsService()
|
||||||
|
|
||||||
@router.post("/clear_subnet")
|
@router.post("/clear_subnet")
|
||||||
def clear_subnet(translations: Translations = Depends(get_translations())):
|
def clear_subnet(subnet: Optional[str] = None, translations: Translations = Depends(get_translations())):
|
||||||
"""Очищает данные узлов подсети, сохранённые в devices.json.
|
"""Очищает данные узлов подсети, сохранённые в devices.json.
|
||||||
|
|
||||||
Удаляет все записи об узлах подсети, оставляя файл пустым.
|
Удаляет все записи об узлах подсети, оставляя файл пустым.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
|
subnet (Optional[str]): Подсеть в формате CIDR (например, "10.1.1.0/24").
|
||||||
|
Если None, очищает все подсети.
|
||||||
translations: Объект переводов для текущего языка.
|
translations: Объект переводов для текущего языка.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
|
|
@ -28,9 +31,12 @@ def clear_subnet(translations: Translations = Depends(get_translations())):
|
||||||
HTTPException: Если произошла ошибка очистки (status_code=500).
|
HTTPException: Если произошла ошибка очистки (status_code=500).
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
success = settings_service.clear_subnet()
|
success = settings_service.clear_subnet(subnet)
|
||||||
if success:
|
if success:
|
||||||
return {"message": translations.gettext("Данные узлов подсети успешно очищены")}
|
if subnet:
|
||||||
|
return {"message": translations.gettext("Данные узлов подсети {subnet} успешно очищены").format(subnet=subnet)}
|
||||||
|
else:
|
||||||
|
return {"message": translations.gettext("Данные всех подсетей успешно очищены")}
|
||||||
else:
|
else:
|
||||||
raise HTTPException(status_code=500, detail=translations.gettext("Не удалось очистить данные узлов подсети"))
|
raise HTTPException(status_code=500, detail=translations.gettext("Не удалось очистить данные узлов подсети"))
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
|
@ -91,26 +97,28 @@ DEVICE_PATH = "storage/devices/devices.json"
|
||||||
WIFI_PATH = "storage/wifi/wifi.json"
|
WIFI_PATH = "storage/wifi/wifi.json"
|
||||||
|
|
||||||
@router.get("/export_devices", response_class=FileResponse)
|
@router.get("/export_devices", response_class=FileResponse)
|
||||||
async def export_devices(translations: Translations = Depends(get_translations())):
|
async def export_devices(subnet: str, translations: Translations = Depends(get_translations())):
|
||||||
"""
|
"""
|
||||||
Экспортирует файл с данными устройств в формате JSON.
|
Экспортирует файл с данными устройств в формате JSON для указанной подсети.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
|
subnet (str): Подсеть в формате CIDR (например, "10.1.1.0/24").
|
||||||
translations: Объект переводов для текущего языка.
|
translations: Объект переводов для текущего языка.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
FileResponse: Файл devices.json для скачивания.
|
FileResponse: Файл <subnet>.json для скачивания.
|
||||||
|
|
||||||
Raises:
|
Raises:
|
||||||
HTTPException: Если файл не найден (status_code=404).
|
HTTPException: Если файл не найден (status_code=404).
|
||||||
"""
|
"""
|
||||||
if not os.path.exists(DEVICE_PATH):
|
file_path = f"storage/subnets/{subnet.replace('/', '_')}.json"
|
||||||
logger.warning(f"Export file not found: {DEVICE_PATH}")
|
if not os.path.exists(file_path):
|
||||||
|
logger.warning(f"Export file not found: {file_path}")
|
||||||
raise HTTPException(status_code=404, detail=translations.gettext("Файл не найден"))
|
raise HTTPException(status_code=404, detail=translations.gettext("Файл не найден"))
|
||||||
logger.info(f"Exporting file: {DEVICE_PATH}")
|
logger.info(f"Exporting file: {file_path}")
|
||||||
return FileResponse(
|
return FileResponse(
|
||||||
path=DEVICE_PATH,
|
path=file_path,
|
||||||
filename="devices.json",
|
filename=f"{subnet.replace('/', '_')}.json",
|
||||||
media_type="application/json"
|
media_type="application/json"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ from fastapi import APIRouter, HTTPException, Body, Depends
|
||||||
from models.subnet import SubnetScanResult, SubnetScanRequest
|
from models.subnet import SubnetScanResult, SubnetScanRequest
|
||||||
from models.wifi import WifiScanResult
|
from models.wifi import WifiScanResult
|
||||||
from models.request import NoteRequest, WifiConnectRequest, WifiDisconnectRequest
|
from models.request import NoteRequest, WifiConnectRequest, WifiDisconnectRequest
|
||||||
from services.subnet_service import SubnetService
|
from services.subnet_service import SubnetService, get_subnet_service
|
||||||
from services.wifi_service import WifiService
|
from services.wifi_service import WifiService
|
||||||
from services.connect_service import WifiConnectionService
|
from services.connect_service import WifiConnectionService
|
||||||
from utils.i18n import get_translations, _
|
from utils.i18n import get_translations, _
|
||||||
|
|
@ -14,15 +14,15 @@ router = APIRouter()
|
||||||
logging.basicConfig(level=logging.INFO)
|
logging.basicConfig(level=logging.INFO)
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
@router.post("/devices", response_model=SubnetScanResult)
|
@router.post("/devices", response_model=SubnetScanResult)
|
||||||
def scan_subnet(request: SubnetScanRequest = Body(...), translations: Translations = Depends(get_translations())):
|
def scan_subnet(request: SubnetScanRequest = Body(...), subnet_service: SubnetService = Depends(get_subnet_service), translations: Translations = Depends(get_translations())):
|
||||||
"""Сканирует локальную подсеть и возвращает данные об устройствах.
|
"""Сканирует локальную подсеть и возвращает данные об устройствах.
|
||||||
|
|
||||||
Выполняет сканирование указанной подсети для обнаружения активных устройств.
|
Выполняет сканирование указанной подсети для обнаружения активных устройств.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
request (SubnetScanRequest): Объект с полем subnet.
|
request (SubnetScanRequest): Объект с полем subnet.
|
||||||
|
subnet_service: Сервис сканирования подсети.
|
||||||
translations: Объект переводов для текущего языка.
|
translations: Объект переводов для текущего языка.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
|
|
@ -32,17 +32,16 @@ def scan_subnet(request: SubnetScanRequest = Body(...), translations: Translatio
|
||||||
HTTPException: Если произошла ошибка сканирования (status_code=500).
|
HTTPException: Если произошла ошибка сканирования (status_code=500).
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
subnet_service = SubnetService()
|
|
||||||
# Если subnet пустая строка, определяем автоматически
|
# Если subnet пустая строка, определяем автоматически
|
||||||
subnet = request.subnet.strip() if request.subnet else None
|
subnet = request.subnet.strip() if request.subnet else None
|
||||||
logger.info(f"Requested subnet scan for: {subnet or 'auto-detected'}")
|
logger.info(f"Requested subnet scan for: {subnet or 'auto-detected'}")
|
||||||
result = subnet_service.scan_subnet(subnet)
|
result = subnet_service.scan_subnet(subnet)
|
||||||
if not result.devices:
|
if not result.devices and result.error:
|
||||||
logger.warning(f"No devices found in subnet {subnet or 'auto-detected'}")
|
logger.warning(f"No devices found in subnet {subnet or 'auto-detected'}")
|
||||||
return result
|
return result
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"Error in scan_subnet: {str(e)}")
|
logger.error(f"Error in scan_subnet: {str(e)}")
|
||||||
raise HTTPException(status_code=500, detail=translations.gettext("Ошибка сканирования: {error}").format(error=str(e)))
|
raise HTTPException(status_code=500, detail=translations.gettext("Ошибка сканирования подсети: {error}").format(error=str(e)))
|
||||||
|
|
||||||
@router.get("/wifi", response_model=WifiScanResult)
|
@router.get("/wifi", response_model=WifiScanResult)
|
||||||
def scan_wifi(timeout: int = 30, translations: Translations = Depends(get_translations())):
|
def scan_wifi(timeout: int = 30, translations: Translations = Depends(get_translations())):
|
||||||
|
|
@ -68,7 +67,7 @@ def scan_wifi(timeout: int = 30, translations: Translations = Depends(get_transl
|
||||||
raise HTTPException(status_code=500, detail=translations.gettext("Ошибка сканирования Wi-Fi: {error}").format(error=str(e)))
|
raise HTTPException(status_code=500, detail=translations.gettext("Ошибка сканирования Wi-Fi: {error}").format(error=str(e)))
|
||||||
|
|
||||||
@router.post("/devices/{mac}/note")
|
@router.post("/devices/{mac}/note")
|
||||||
def add_note(mac: str, request: NoteRequest, translations: Translations = Depends(get_translations())):
|
def add_note(mac: str, request: NoteRequest, subnet_service: SubnetService = Depends(get_subnet_service), translations: Translations = Depends(get_translations())):
|
||||||
"""Добавляет заметку для устройства по MAC-адресу.
|
"""Добавляет заметку для устройства по MAC-адресу.
|
||||||
|
|
||||||
Привязывает заметку к устройству, идентифицируемому по MAC-адресу.
|
Привязывает заметку к устройству, идентифицируемому по MAC-адресу.
|
||||||
|
|
@ -76,6 +75,7 @@ def add_note(mac: str, request: NoteRequest, translations: Translations = Depend
|
||||||
Args:
|
Args:
|
||||||
mac (str): MAC-адрес устройства.
|
mac (str): MAC-адрес устройства.
|
||||||
request (NoteRequest): Объект с полем "note" для текста заметки.
|
request (NoteRequest): Объект с полем "note" для текста заметки.
|
||||||
|
subnet_service: Сервис сканирования подсети.
|
||||||
translations: Объект переводов для текущего языка.
|
translations: Объект переводов для текущего языка.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
|
|
@ -86,13 +86,14 @@ def add_note(mac: str, request: NoteRequest, translations: Translations = Depend
|
||||||
существует (status_code=400), или произошла внутренняя ошибка (status_code=500).
|
существует (status_code=400), или произошла внутренняя ошибка (status_code=500).
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
subnet_service = SubnetService()
|
success, result = subnet_service.add_note(mac, request.note, translations)
|
||||||
success, error_message = subnet_service.add_note(mac, request.note)
|
|
||||||
if not success:
|
if not success:
|
||||||
if "не найдено" in error_message.lower():
|
if result[0] == "not_found":
|
||||||
raise HTTPException(status_code=404, detail=translations.gettext(error_message))
|
raise HTTPException(status_code=404, detail=translations.gettext("Устройство с MAC {mac} не найдено").format(mac=mac))
|
||||||
elif "уже существует" in error_message.lower():
|
elif result[0] == "note_exists":
|
||||||
raise HTTPException(status_code=400, detail=translations.gettext(error_message))
|
raise HTTPException(status_code=400, detail=translations.gettext("Заметка для устройства с MAC {mac} уже существует").format(mac=mac))
|
||||||
|
else:
|
||||||
|
raise HTTPException(status_code=500, detail=translations.gettext("Внутренняя ошибка сервера: {error}").format(error=result[1]["error"]))
|
||||||
return {"message": translations.gettext("Заметка '{note}' добавлена для устройства {mac}").format(note=request.note, mac=mac)}
|
return {"message": translations.gettext("Заметка '{note}' добавлена для устройства {mac}").format(note=request.note, mac=mac)}
|
||||||
except HTTPException as e:
|
except HTTPException as e:
|
||||||
raise e
|
raise e
|
||||||
|
|
@ -100,7 +101,7 @@ def add_note(mac: str, request: NoteRequest, translations: Translations = Depend
|
||||||
raise HTTPException(status_code=500, detail=translations.gettext("Ошибка добавления заметки: {error}").format(error=str(e)))
|
raise HTTPException(status_code=500, detail=translations.gettext("Ошибка добавления заметки: {error}").format(error=str(e)))
|
||||||
|
|
||||||
@router.put("/devices/{mac}/note")
|
@router.put("/devices/{mac}/note")
|
||||||
def update_note(mac: str, request: NoteRequest, translations: Translations = Depends(get_translations())):
|
def update_note(mac: str, request: NoteRequest, subnet_service: SubnetService = Depends(get_subnet_service), translations: Translations = Depends(get_translations())):
|
||||||
"""Обновляет заметку для устройства по MAC-адресу.
|
"""Обновляет заметку для устройства по MAC-адресу.
|
||||||
|
|
||||||
Изменяет существующую заметку, привязанную к устройству.
|
Изменяет существующую заметку, привязанную к устройству.
|
||||||
|
|
@ -108,6 +109,7 @@ def update_note(mac: str, request: NoteRequest, translations: Translations = Dep
|
||||||
Args:
|
Args:
|
||||||
mac (str): MAC-адрес устройства.
|
mac (str): MAC-адрес устройства.
|
||||||
request (NoteRequest): Объект с полем "note" для нового текста заметки.
|
request (NoteRequest): Объект с полем "note" для нового текста заметки.
|
||||||
|
subnet_service: Сервис сканирования подсети.
|
||||||
translations: Объект переводов для текущего языка.
|
translations: Объект переводов для текущего языка.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
|
|
@ -118,13 +120,14 @@ def update_note(mac: str, request: NoteRequest, translations: Translations = Dep
|
||||||
существует (status_code=400), или произошла внутренняя ошибка (status_code=500).
|
существует (status_code=400), или произошла внутренняя ошибка (status_code=500).
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
subnet_service = SubnetService()
|
success, result = subnet_service.update_note(mac, request.note, translations)
|
||||||
success, error_message = subnet_service.update_note(mac, request.note)
|
|
||||||
if not success:
|
if not success:
|
||||||
if "не найдено" in error_message.lower():
|
if result[0] == "not_found":
|
||||||
raise HTTPException(status_code=404, detail=translations.gettext(error_message))
|
raise HTTPException(status_code=404, detail=translations.gettext("Устройство с MAC {mac} не найдено").format(mac=mac))
|
||||||
elif "не существует" in error_message.lower():
|
elif result[0] == "note_not_exists":
|
||||||
raise HTTPException(status_code=400, detail=translations.gettext(error_message))
|
raise HTTPException(status_code=400, detail=translations.gettext("Заметка для устройства с MAC {mac} не существует").format(mac=mac))
|
||||||
|
else:
|
||||||
|
raise HTTPException(status_code=500, detail=translations.gettext("Внутренняя ошибка сервера: {error}").format(error=result[1]["error"]))
|
||||||
return {"message": translations.gettext("Заметка '{note}' обновлена для устройства {mac}").format(note=request.note, mac=mac)}
|
return {"message": translations.gettext("Заметка '{note}' обновлена для устройства {mac}").format(note=request.note, mac=mac)}
|
||||||
except HTTPException as e:
|
except HTTPException as e:
|
||||||
raise e
|
raise e
|
||||||
|
|
@ -132,13 +135,14 @@ def update_note(mac: str, request: NoteRequest, translations: Translations = Dep
|
||||||
raise HTTPException(status_code=500, detail=translations.gettext("Ошибка обновления заметки: {error}").format(error=str(e)))
|
raise HTTPException(status_code=500, detail=translations.gettext("Ошибка обновления заметки: {error}").format(error=str(e)))
|
||||||
|
|
||||||
@router.delete("/devices/{mac}/note")
|
@router.delete("/devices/{mac}/note")
|
||||||
def delete_note(mac: str, translations: Translations = Depends(get_translations())):
|
def delete_note(mac: str, subnet_service: SubnetService = Depends(get_subnet_service), translations: Translations = Depends(get_translations())):
|
||||||
"""Удаляет заметку для устройства по MAC-адресу.
|
"""Удаляет заметку для устройства по MAC-адресу.
|
||||||
|
|
||||||
Удаляет привязанную заметку для указанного устройства.
|
Удаляет привязанную заметку для указанного устройства.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
mac (str): MAC-адрес устройства.
|
mac (str): MAC-адрес устройства.
|
||||||
|
subnet_service: Сервис сканирования подсети.
|
||||||
translations: Объект переводов для текущего языка.
|
translations: Объект переводов для текущего языка.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
|
|
@ -149,13 +153,14 @@ def delete_note(mac: str, translations: Translations = Depends(get_translations(
|
||||||
существует (status_code=400), или произошла внутренняя ошибка (status_code=500).
|
существует (status_code=400), или произошла внутренняя ошибка (status_code=500).
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
subnet_service = SubnetService()
|
success, result = subnet_service.delete_note(mac, translations)
|
||||||
success, error_message = subnet_service.delete_note(mac)
|
|
||||||
if not success:
|
if not success:
|
||||||
if "не найдено" in error_message.lower():
|
if result[0] == "not_found":
|
||||||
raise HTTPException(status_code=404, detail=translations.gettext(error_message))
|
raise HTTPException(status_code=404, detail=translations.gettext("Устройство с MAC {mac} не найдено").format(mac=mac))
|
||||||
elif "не существует" in error_message.lower():
|
elif result[0] == "note_not_exists":
|
||||||
raise HTTPException(status_code=400, detail=translations.gettext(error_message))
|
raise HTTPException(status_code=400, detail=translations.gettext("Заметка для устройства с MAC {mac} не существует").format(mac=mac))
|
||||||
|
else:
|
||||||
|
raise HTTPException(status_code=500, detail=translations.gettext("Внутренняя ошибка сервера: {error}").format(error=result[1]["error"]))
|
||||||
return {"message": translations.gettext("Заметка удалена для устройства {mac}").format(mac=mac)}
|
return {"message": translations.gettext("Заметка удалена для устройства {mac}").format(mac=mac)}
|
||||||
except HTTPException as e:
|
except HTTPException as e:
|
||||||
raise e
|
raise e
|
||||||
|
|
@ -182,12 +187,14 @@ def add_wifi_note(ssid: str, request: NoteRequest, translations: Translations =
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
wifi_service = WifiService()
|
wifi_service = WifiService()
|
||||||
success, error_message = wifi_service.add_note(ssid, request.note)
|
success, result = wifi_service.add_note(ssid, request.note)
|
||||||
if not success:
|
if not success:
|
||||||
if "не найдена" in error_message.lower():
|
if result[0] == "not_found":
|
||||||
raise HTTPException(status_code=404, detail=translations.gettext(error_message))
|
raise HTTPException(status_code=404, detail=translations.gettext("Сеть с SSID {ssid} не найдена").format(ssid=ssid))
|
||||||
elif "уже существует" in error_message.lower():
|
elif result[0] == "note_exists":
|
||||||
raise HTTPException(status_code=400, detail=translations.gettext(error_message))
|
raise HTTPException(status_code=400, detail=translations.gettext("Заметка для сети с SSID {ssid} уже существует").format(ssid=ssid))
|
||||||
|
else:
|
||||||
|
raise HTTPException(status_code=500, detail=translations.gettext("Внутренняя ошибка сервера: {error}").format(error=result[1]["error"]))
|
||||||
return {"message": translations.gettext("Заметка '{note}' добавлена для сети с SSID {ssid}").format(note=request.note, ssid=ssid)}
|
return {"message": translations.gettext("Заметка '{note}' добавлена для сети с SSID {ssid}").format(note=request.note, ssid=ssid)}
|
||||||
except HTTPException as e:
|
except HTTPException as e:
|
||||||
raise e
|
raise e
|
||||||
|
|
@ -214,12 +221,14 @@ def update_wifi_note(ssid: str, request: NoteRequest, translations: Translations
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
wifi_service = WifiService()
|
wifi_service = WifiService()
|
||||||
success, error_message = wifi_service.update_note(ssid, request.note)
|
success, result = wifi_service.update_note(ssid, request.note)
|
||||||
if not success:
|
if not success:
|
||||||
if "не найдена" in error_message.lower():
|
if result[0] == "not_found":
|
||||||
raise HTTPException(status_code=404, detail=translations.gettext(error_message))
|
raise HTTPException(status_code=404, detail=translations.gettext("Сеть с SSID {ssid} не найдена").format(ssid=ssid))
|
||||||
elif "не существует" in error_message.lower():
|
elif result[0] == "note_not_exists":
|
||||||
raise HTTPException(status_code=400, detail=translations.gettext(error_message))
|
raise HTTPException(status_code=400, detail=translations.gettext("Заметка для сети с SSID {ssid} не существует").format(ssid=ssid))
|
||||||
|
else:
|
||||||
|
raise HTTPException(status_code=500, detail=translations.gettext("Внутренняя ошибка сервера: {error}").format(error=result[1]["error"]))
|
||||||
return {"message": translations.gettext("Заметка '{note}' обновлена для сети с SSID {ssid}").format(note=request.note, ssid=ssid)}
|
return {"message": translations.gettext("Заметка '{note}' обновлена для сети с SSID {ssid}").format(note=request.note, ssid=ssid)}
|
||||||
except HTTPException as e:
|
except HTTPException as e:
|
||||||
raise e
|
raise e
|
||||||
|
|
@ -245,12 +254,14 @@ def delete_wifi_note(ssid: str, translations: Translations = Depends(get_transla
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
wifi_service = WifiService()
|
wifi_service = WifiService()
|
||||||
success, error_message = wifi_service.delete_note(ssid)
|
success, result = wifi_service.delete_note(ssid)
|
||||||
if not success:
|
if not success:
|
||||||
if "не найдена" in error_message.lower():
|
if result[0] == "not_found":
|
||||||
raise HTTPException(status_code=404, detail=translations.gettext(error_message))
|
raise HTTPException(status_code=404, detail=translations.gettext("Сеть с SSID {ssid} не найдена").format(ssid=ssid))
|
||||||
elif "не существует" in error_message.lower():
|
elif result[0] == "note_not_exists":
|
||||||
raise HTTPException(status_code=400, detail=translations.gettext(error_message))
|
raise HTTPException(status_code=400, detail=translations.gettext("Заметка для сети с SSID {ssid} не существует").format(ssid=ssid))
|
||||||
|
else:
|
||||||
|
raise HTTPException(status_code=500, detail=translations.gettext("Внутренняя ошибка сервера: {error}").format(error=result[1]["error"]))
|
||||||
return {"message": translations.gettext("Заметка удалена для сети с SSID {ssid}").format(ssid=ssid)}
|
return {"message": translations.gettext("Заметка удалена для сети с SSID {ssid}").format(ssid=ssid)}
|
||||||
except HTTPException as e:
|
except HTTPException as e:
|
||||||
raise e
|
raise e
|
||||||
|
|
|
||||||
Binary file not shown.
|
|
@ -7,8 +7,8 @@ msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: PROJECT VERSION\n"
|
"Project-Id-Version: PROJECT VERSION\n"
|
||||||
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
||||||
"POT-Creation-Date: 2025-07-15 15:01+0500\n"
|
"POT-Creation-Date: 2025-07-16 13:15+0500\n"
|
||||||
"PO-Revision-Date: 2025-07-15 15:02+0500\n"
|
"PO-Revision-Date: 2025-07-16 13:15+0500\n"
|
||||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||||
"Language: en\n"
|
"Language: en\n"
|
||||||
"Language-Team: en <LL@li.org>\n"
|
"Language-Team: en <LL@li.org>\n"
|
||||||
|
|
@ -48,11 +48,11 @@ msgstr "The users.json file exists and contains users"
|
||||||
|
|
||||||
#: api/v1/auth.py:179
|
#: api/v1/auth.py:179
|
||||||
msgid "Файл users.json существует, но не содержит пользователей"
|
msgid "Файл users.json существует, но не содержит пользователей"
|
||||||
msgstr "The users.json file exists but does not contain users"
|
msgstr "The users.json file exists but contains no users"
|
||||||
|
|
||||||
#: api/v1/auth.py:183
|
#: api/v1/auth.py:183
|
||||||
msgid "Ошибка при проверке файла"
|
msgid "Ошибка при проверке файла"
|
||||||
msgstr "Error checking the file"
|
msgstr "Error checking file"
|
||||||
|
|
||||||
#: api/v1/ip.py:36 api/v1/ip.py:73 api/v1/ip.py:110
|
#: api/v1/ip.py:36 api/v1/ip.py:73 api/v1/ip.py:110
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
|
|
@ -96,145 +96,190 @@ msgstr "Failed to update container position: {error}"
|
||||||
msgid "Не удалось получить имя хоста"
|
msgid "Не удалось получить имя хоста"
|
||||||
msgstr "Failed to retrieve hostname"
|
msgstr "Failed to retrieve hostname"
|
||||||
|
|
||||||
#: api/v1/settings.py:33
|
#: api/v1/settings.py:37
|
||||||
msgid "Данные узлов подсети успешно очищены"
|
#, python-brace-format
|
||||||
msgstr "Subnet node data successfully cleared"
|
msgid "Данные узлов подсети {subnet} успешно очищены"
|
||||||
|
msgstr "Subnet node data for {subnet} successfully cleared"
|
||||||
|
|
||||||
#: api/v1/settings.py:35
|
#: api/v1/settings.py:39
|
||||||
|
msgid "Данные всех подсетей успешно очищены"
|
||||||
|
msgstr "All subnet data successfully cleared"
|
||||||
|
|
||||||
|
#: api/v1/settings.py:41
|
||||||
msgid "Не удалось очистить данные узлов подсети"
|
msgid "Не удалось очистить данные узлов подсети"
|
||||||
msgstr "Failed to clear subnet node data"
|
msgstr "Failed to clear subnet node data"
|
||||||
|
|
||||||
#: api/v1/settings.py:38 api/v1/settings.py:63 api/v1/settings.py:88
|
#: api/v1/settings.py:44 api/v1/settings.py:69 api/v1/settings.py:94
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "Ошибка очистки: {error}"
|
msgid "Ошибка очистки: {error}"
|
||||||
msgstr "Clear error: {error}"
|
msgstr "Clear error: {error}"
|
||||||
|
|
||||||
#: api/v1/settings.py:58
|
#: api/v1/settings.py:64
|
||||||
msgid "Данные точек доступа Wi-Fi успешно очищены"
|
msgid "Данные точек доступа Wi-Fi успешно очищены"
|
||||||
msgstr "Wi-Fi access point data successfully cleared"
|
msgstr "Wi-Fi access point data successfully cleared"
|
||||||
|
|
||||||
#: api/v1/settings.py:60
|
#: api/v1/settings.py:66
|
||||||
msgid "Не удалось очистить данные точек доступа Wi-Fi"
|
msgid "Не удалось очистить данные точек доступа Wi-Fi"
|
||||||
msgstr "Failed to clear Wi-Fi access point data"
|
msgstr "Failed to clear Wi-Fi access point data"
|
||||||
|
|
||||||
#: api/v1/settings.py:83
|
#: api/v1/settings.py:89
|
||||||
msgid "Все сетевые данные успешно очищены"
|
msgid "Все сетевые данные успешно очищены"
|
||||||
msgstr "All network data successfully cleared"
|
msgstr "All network data successfully cleared"
|
||||||
|
|
||||||
#: api/v1/settings.py:85
|
#: api/v1/settings.py:91
|
||||||
msgid "Не удалось очистить все сетевые данные"
|
msgid "Не удалось очистить все сетевые данные"
|
||||||
msgstr "Failed to clear all network data"
|
msgstr "Failed to clear all network data"
|
||||||
|
|
||||||
#: api/v1/settings.py:109 api/v1/settings.py:133
|
#: api/v1/settings.py:117 api/v1/settings.py:141
|
||||||
msgid "Файл не найден"
|
msgid "Файл не найден"
|
||||||
msgstr "File not found"
|
msgstr "File not found"
|
||||||
|
|
||||||
#: api/v1/settings.py:158
|
#: api/v1/settings.py:166
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "Язык '{locale}' не поддерживается."
|
msgid "Язык '{locale}' не поддерживается."
|
||||||
msgstr "Language '{locale}' is not supported."
|
msgstr "Language '{locale}' is not supported."
|
||||||
|
|
||||||
#: api/v1/settings.py:164
|
#: api/v1/settings.py:172
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "Язык '{locale}' не поддерживается (нет файлов переводов)."
|
msgid "Язык '{locale}' не поддерживается (нет файлов переводов)."
|
||||||
msgstr "Language '{locale}' is not supported (no translation files)."
|
msgstr "Language '{locale}' is not supported (no translation files)."
|
||||||
|
|
||||||
#: api/v1/settings.py:167
|
#: api/v1/settings.py:175
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "Язык успешно установлен: {locale}"
|
msgid "Язык успешно установлен: {locale}"
|
||||||
msgstr "Language successfully set: {locale}"
|
msgstr "Language successfully set: {locale}"
|
||||||
|
|
||||||
#: api/v1/subnet.py:45
|
#: api/v1/subnet.py:44
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "Ошибка сканирования: {error}"
|
msgid "Ошибка сканирования подсети: {error}"
|
||||||
msgstr "Scan error: {error}"
|
msgstr "Subnet scan error: {error}"
|
||||||
|
|
||||||
#: api/v1/subnet.py:68
|
#: api/v1/subnet.py:67
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "Ошибка сканирования Wi-Fi: {error}"
|
msgid "Ошибка сканирования Wi-Fi: {error}"
|
||||||
msgstr "Wi-Fi scan error: {error}"
|
msgstr "Wi-Fi scan error: {error}"
|
||||||
|
|
||||||
#: api/v1/subnet.py:96
|
#: api/v1/subnet.py:92 api/v1/subnet.py:126 api/v1/subnet.py:159
|
||||||
|
#, python-brace-format
|
||||||
|
msgid "Устройство с MAC {mac} не найдено"
|
||||||
|
msgstr "Device with MAC {mac} not found"
|
||||||
|
|
||||||
|
#: api/v1/subnet.py:94
|
||||||
|
#, python-brace-format
|
||||||
|
msgid "Заметка для устройства с MAC {mac} уже существует"
|
||||||
|
msgstr "Note for device with MAC {mac} already exists"
|
||||||
|
|
||||||
|
#: api/v1/subnet.py:96 api/v1/subnet.py:130 api/v1/subnet.py:163 \
|
||||||
|
#: api/v1/subnet.py:197 api/v1/subnet.py:231 api/v1/subnet.py:264 \
|
||||||
|
#: services/wifi_service.py:319 services/wifi_service.py:337 \
|
||||||
|
#: services/wifi_service.py:355
|
||||||
|
#, python-brace-format
|
||||||
|
msgid "Внутренняя ошибка сервера: {error}"
|
||||||
|
msgstr "Internal server error: {error}"
|
||||||
|
|
||||||
|
#: api/v1/subnet.py:97
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "Заметка '{note}' добавлена для устройства {mac}"
|
msgid "Заметка '{note}' добавлена для устройства {mac}"
|
||||||
msgstr "Note '{note}' added for device {mac}"
|
msgstr "Note '{note}' added for device {mac}"
|
||||||
|
|
||||||
#: api/v1/subnet.py:100 api/v1/subnet.py:195
|
#: api/v1/subnet.py:101 api/v1/subnet.py:202
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "Ошибка добавления заметки: {error}"
|
msgid "Ошибка добавления заметки: {error}"
|
||||||
msgstr "Error adding note: {error}"
|
msgstr "Error adding note: {error}"
|
||||||
|
|
||||||
#: api/v1/subnet.py:128
|
#: api/v1/subnet.py:128 api/v1/subnet.py:161
|
||||||
|
#, python-brace-format
|
||||||
|
msgid "Заметка для устройства с MAC {mac} не существует"
|
||||||
|
msgstr "Note for device with MAC {mac} does not exist"
|
||||||
|
|
||||||
|
#: api/v1/subnet.py:131
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "Заметка '{note}' обновлена для устройства {mac}"
|
msgid "Заметка '{note}' обновлена для устройства {mac}"
|
||||||
msgstr "Note '{note}' updated for device {mac}"
|
msgstr "Note '{note}' updated for device {mac}"
|
||||||
|
|
||||||
#: api/v1/subnet.py:132 api/v1/subnet.py:227
|
#: api/v1/subnet.py:135 api/v1/subnet.py:236
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "Ошибка обновления заметки: {error}"
|
msgid "Ошибка обновления заметки: {error}"
|
||||||
msgstr "Error updating note: {error}"
|
msgstr "Error updating note: {error}"
|
||||||
|
|
||||||
#: api/v1/subnet.py:159
|
#: api/v1/subnet.py:164
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "Заметка удалена для устройства {mac}"
|
msgid "Заметка удалена для устройства {mac}"
|
||||||
msgstr "Note deleted for device {mac}"
|
msgstr "Note deleted for device {mac}"
|
||||||
|
|
||||||
#: api/v1/subnet.py:163 api/v1/subnet.py:258
|
#: api/v1/subnet.py:168 api/v1/subnet.py:269
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "Ошибка удаления заметки: {error}"
|
msgid "Ошибка удаления заметки: {error}"
|
||||||
msgstr "Error deleting note: {error}"
|
msgstr "Error deleting note: {error}"
|
||||||
|
|
||||||
#: api/v1/subnet.py:191
|
#: api/v1/subnet.py:193 api/v1/subnet.py:227 api/v1/subnet.py:260 \
|
||||||
|
#: services/wifi_service.py:327 services/wifi_service.py:345
|
||||||
|
#, python-brace-format
|
||||||
|
msgid "Сеть с SSID {ssid} не найдена"
|
||||||
|
msgstr "Network with SSID {ssid} not found"
|
||||||
|
|
||||||
|
#: api/v1/subnet.py:195 services/wifi_service.py:312
|
||||||
|
#, python-brace-format
|
||||||
|
msgid "Заметка для сети с SSID {ssid} уже существует"
|
||||||
|
msgstr "Note for network with SSID {ssid} already exists"
|
||||||
|
|
||||||
|
#: api/v1/subnet.py:198
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "Заметка '{note}' добавлена для сети с SSID {ssid}"
|
msgid "Заметка '{note}' добавлена для сети с SSID {ssid}"
|
||||||
msgstr "Note '{note}' added for network with SSID {ssid}"
|
msgstr "Note '{note}' added for network with SSID {ssid}"
|
||||||
|
|
||||||
#: api/v1/subnet.py:223
|
#: api/v1/subnet.py:229 api/v1/subnet.py:262 services/wifi_service.py:330 \
|
||||||
|
#: services/wifi_service.py:348
|
||||||
|
#, python-brace-format
|
||||||
|
msgid "Заметка для сети с SSID {ssid} не существует"
|
||||||
|
msgstr "Note for network with SSID {ssid} does not exist"
|
||||||
|
|
||||||
|
#: api/v1/subnet.py:232
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "Заметка '{note}' обновлена для сети с SSID {ssid}"
|
msgid "Заметка '{note}' обновлена для сети с SSID {ssid}"
|
||||||
msgstr "Note '{note}' updated for network with SSID {ssid}"
|
msgstr "Note '{note}' updated for network with SSID {ssid}"
|
||||||
|
|
||||||
#: api/v1/subnet.py:254
|
#: api/v1/subnet.py:265
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "Заметка удалена для сети с SSID {ssid}"
|
msgid "Заметка удалена для сети с SSID {ssid}"
|
||||||
msgstr "Note deleted for network with SSID {ssid}"
|
msgstr "Note deleted for network with SSID {ssid}"
|
||||||
|
|
||||||
#: api/v1/subnet.py:282
|
#: api/v1/subnet.py:293
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "Успешно подключено к {ssid}"
|
msgid "Успешно подключено к {ssid}"
|
||||||
msgstr "Successfully connected to {ssid}"
|
msgstr "Successfully connected to {ssid}"
|
||||||
|
|
||||||
#: api/v1/subnet.py:286
|
#: api/v1/subnet.py:297
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "Ошибка подключения к Wi-Fi: {error}"
|
msgid "Ошибка подключения к Wi-Fi: {error}"
|
||||||
msgstr "Wi-Fi connection error: {error}"
|
msgstr "Wi-Fi connection error: {error}"
|
||||||
|
|
||||||
#: api/v1/subnet.py:309
|
#: api/v1/subnet.py:320
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "Успешно отключено от {ssid}"
|
msgid "Успешно отключено от {ssid}"
|
||||||
msgstr "Successfully disconnected from {ssid}"
|
msgstr "Successfully disconnected from {ssid}"
|
||||||
|
|
||||||
#: api/v1/subnet.py:313
|
#: api/v1/subnet.py:324
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "Ошибка отключения от Wi-Fi: {error}"
|
msgid "Ошибка отключения от Wi-Fi: {error}"
|
||||||
msgstr "Wi-Fi disconnection error: {error}"
|
msgstr "Wi-Fi disconnection error: {error}"
|
||||||
|
|
||||||
#: api/v1/subnet.py:337
|
#: api/v1/subnet.py:348
|
||||||
msgid "connected"
|
msgid "connected"
|
||||||
msgstr "connected"
|
msgstr "connected"
|
||||||
|
|
||||||
#: api/v1/subnet.py:341
|
#: api/v1/subnet.py:352
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "Ошибка проверки статуса Wi-Fi: {error}"
|
msgid "Ошибка проверки статуса Wi-Fi: {error}"
|
||||||
msgstr "Wi-Fi status check error: {error}"
|
msgstr "Wi-Fi status check error: {error}"
|
||||||
|
|
||||||
#: api/v1/websocket.py:145
|
#: api/v1/websocket.py:145
|
||||||
msgid "Ошибка: Ключ 'activation' отсутствует в полученных данных сети"
|
msgid "Ошибка: Ключ 'activation' отсутствует в полученных данных сети"
|
||||||
msgstr "Error: The 'activation' key is missing in the received network data"
|
msgstr "Error: 'activation' key is missing in received network data"
|
||||||
|
|
||||||
#: services/arp_service.py:102
|
#: services/arp_service.py:102
|
||||||
msgid "Доступные устройства в сети:"
|
msgid "Доступные устройства в сети:"
|
||||||
msgstr "Available devices in the network:"
|
msgstr "Available devices on the network:"
|
||||||
|
|
||||||
#: services/arp_service.py:103
|
#: services/arp_service.py:103
|
||||||
msgid "IP"
|
msgid "IP"
|
||||||
|
|
@ -276,10 +321,10 @@ msgstr "Successfully logged out"
|
||||||
msgid "Ошибка при выходе из системы"
|
msgid "Ошибка при выходе из системы"
|
||||||
msgstr "Error during logout"
|
msgstr "Error during logout"
|
||||||
|
|
||||||
#: services/connect_service.py:70 services/connect_service.py:117
|
#: services/connect_service.py:70 services/connect_service.py:117 \
|
||||||
#: services/connect_service.py:154 services/wifi_service.py:227
|
#: services/connect_service.py:154 services/wifi_service.py:227
|
||||||
msgid "Wi-Fi-интерфейс не доступен"
|
msgid "Wi-Fi-интерфейс не доступен"
|
||||||
msgstr "Wi-Fi interface is not available"
|
msgstr "Wi-Fi interface not available"
|
||||||
|
|
||||||
#: services/connect_service.py:74
|
#: services/connect_service.py:74
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
|
|
@ -289,7 +334,7 @@ msgstr "Network with SSID {ssid} not found in the list of available networks"
|
||||||
#: services/connect_service.py:81 services/connect_service.py:92
|
#: services/connect_service.py:81 services/connect_service.py:92
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "Ошибка подключения к {ssid}: Неверный пароль"
|
msgid "Ошибка подключения к {ssid}: Неверный пароль"
|
||||||
msgstr "Connection error to {ssid}: Invalid password"
|
msgstr "Connection error to {ssid}: Incorrect password"
|
||||||
|
|
||||||
#: services/connect_service.py:83 services/connect_service.py:94
|
#: services/connect_service.py:83 services/connect_service.py:94
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
|
|
@ -361,52 +406,42 @@ msgstr "Failed to execute hostname command: {error}"
|
||||||
msgid "Ошибка обработки вывода hostname: {error}"
|
msgid "Ошибка обработки вывода hostname: {error}"
|
||||||
msgstr "Error processing hostname output: {error}"
|
msgstr "Error processing hostname output: {error}"
|
||||||
|
|
||||||
#: services/settings_service.py:37
|
#: services/settings_service.py:55
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "Ошибка очистки узлов подсети: {error}"
|
msgid "Ошибка очистки узлов подсети: {error}"
|
||||||
msgstr "Error clearing subnet nodes: {error}"
|
msgstr "Subnet node clear error: {error}"
|
||||||
|
|
||||||
#: services/settings_service.py:58
|
#: services/settings_service.py:76
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "Ошибка очистки точек доступа Wi-Fi: {error}"
|
msgid "Ошибка очистки точек доступа Wi-Fi: {error}"
|
||||||
msgstr "Error clearing Wi-Fi access points: {error}"
|
msgstr "Wi-Fi access point clear error: {error}"
|
||||||
|
|
||||||
#: services/settings_service.py:84
|
#: services/settings_service.py:104
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "Ошибка очистки всех сетевых данных: {error}"
|
msgid "Ошибка очистки всех сетевых данных: {error}"
|
||||||
msgstr "Error clearing all network data: {error}"
|
msgstr "All network data clear error: {error}"
|
||||||
|
|
||||||
#: services/subnet_service.py:75 services/wifi_service.py:115
|
#: services/subnet_service.py:75 services/wifi_service.py:115
|
||||||
msgid "Неизвестный"
|
msgid "Неизвестный"
|
||||||
msgstr "Unknown"
|
msgstr "Unknown"
|
||||||
|
|
||||||
#: services/subnet_service.py:179
|
#: services/subnet_service.py:185
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "Ошибка при сохранении устройств: {error}"
|
msgid "Ошибка при сохранении устройств: {error}"
|
||||||
msgstr "Error saving devices: {error}"
|
msgstr "Error saving devices: {error}"
|
||||||
|
|
||||||
#: services/subnet_service.py:374 services/subnet_service.py:391
|
#: services/subnet_service.py:268
|
||||||
#: services/subnet_service.py:408
|
msgid "Недопустимая подсеть по умолчанию"
|
||||||
#, python-brace-format
|
msgstr "Invalid default subnet"
|
||||||
msgid "Устройство с MAC {mac} не найдено"
|
|
||||||
msgstr "Device with MAC {mac} not found"
|
|
||||||
|
|
||||||
#: services/subnet_service.py:377
|
#: services/subnet_service.py:288
|
||||||
#, python-brace-format
|
msgid "В данной подсети не обнаружено устройств"
|
||||||
msgid "Заметка для устройства с MAC {mac} уже существует"
|
msgstr "No devices found in this subnet"
|
||||||
msgstr "Note for device with MAC {mac} already exists"
|
|
||||||
|
|
||||||
#: services/subnet_service.py:384 services/subnet_service.py:401
|
#: services/subnet_service.py:345
|
||||||
#: services/subnet_service.py:418 services/wifi_service.py:319
|
|
||||||
#: services/wifi_service.py:337 services/wifi_service.py:355
|
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "Внутренняя ошибка сервера: {error}"
|
msgid "Ошибка сканирования: {error}"
|
||||||
msgstr "Internal server error: {error}"
|
msgstr "Scan error: {error}"
|
||||||
|
|
||||||
#: services/subnet_service.py:394 services/subnet_service.py:411
|
|
||||||
#, python-brace-format
|
|
||||||
msgid "Заметка для устройства с MAC {mac} не существует"
|
|
||||||
msgstr "Note for device with MAC {mac} does not exist"
|
|
||||||
|
|
||||||
#: services/wifi_service.py:61
|
#: services/wifi_service.py:61
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
|
|
@ -451,23 +486,8 @@ msgstr "5 GHz"
|
||||||
|
|
||||||
#: services/wifi_service.py:165
|
#: services/wifi_service.py:165
|
||||||
msgid "Интерфейс не определён"
|
msgid "Интерфейс не определён"
|
||||||
msgstr "Interface not defined"
|
msgstr "Interface not specified"
|
||||||
|
|
||||||
#: services/wifi_service.py:215
|
#: services/wifi_service.py:215
|
||||||
msgid "Таймаут при выполнении iw scan"
|
msgid "Таймаут при выполнении iw scan"
|
||||||
msgstr "Timeout during iw scan"
|
msgstr "Timeout during iw scan"
|
||||||
|
|
||||||
#: services/wifi_service.py:312
|
|
||||||
#, python-brace-format
|
|
||||||
msgid "Заметка для сети с SSID {ssid} уже существует"
|
|
||||||
msgstr "Note for network with SSID {ssid} already exists"
|
|
||||||
|
|
||||||
#: services/wifi_service.py:327 services/wifi_service.py:345
|
|
||||||
#, python-brace-format
|
|
||||||
msgid "Сеть с SSID {ssid} не найдена"
|
|
||||||
msgstr "Network with SSID {ssid} not found"
|
|
||||||
|
|
||||||
#: services/wifi_service.py:330 services/wifi_service.py:348
|
|
||||||
#, python-brace-format
|
|
||||||
msgid "Заметка для сети с SSID {ssid} не существует"
|
|
||||||
msgstr "Note for network with SSID {ssid} does not exist"
|
|
||||||
493
SRV/locales/messages.pot
Normal file
493
SRV/locales/messages.pot
Normal file
|
|
@ -0,0 +1,493 @@
|
||||||
|
# Translations template for PROJECT.
|
||||||
|
# Copyright (C) 2025 ORGANIZATION
|
||||||
|
# This file is distributed under the same license as the PROJECT project.
|
||||||
|
# FIRST AUTHOR <EMAIL@ADDRESS>, 2025.
|
||||||
|
#
|
||||||
|
#, fuzzy
|
||||||
|
msgid ""
|
||||||
|
msgstr ""
|
||||||
|
"Project-Id-Version: PROJECT VERSION\n"
|
||||||
|
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
||||||
|
"POT-Creation-Date: 2025-07-16 13:15+0500\n"
|
||||||
|
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||||
|
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||||
|
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||||
|
"MIME-Version: 1.0\n"
|
||||||
|
"Content-Type: text/plain; charset=utf-8\n"
|
||||||
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
|
"Generated-By: Babel 2.17.0\n"
|
||||||
|
|
||||||
|
#: api/v1/auth.py:44
|
||||||
|
msgid "Не удалось зарегистрировать пользователя"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: api/v1/auth.py:75
|
||||||
|
msgid "Не удалось авторизовать пользователя"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: api/v1/auth.py:103
|
||||||
|
msgid "bearer"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: api/v1/auth.py:109
|
||||||
|
msgid "Не удалось получить данные пользователя"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: api/v1/auth.py:136
|
||||||
|
msgid "Не удалось выйти из системы"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: api/v1/auth.py:162
|
||||||
|
msgid "Файл users.json не существует"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: api/v1/auth.py:172
|
||||||
|
msgid "Файл users.json существует и содержит пользователей"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: api/v1/auth.py:179
|
||||||
|
msgid "Файл users.json существует, но не содержит пользователей"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: api/v1/auth.py:183
|
||||||
|
msgid "Ошибка при проверке файла"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: api/v1/ip.py:36 api/v1/ip.py:73 api/v1/ip.py:110
|
||||||
|
#, python-brace-format
|
||||||
|
msgid "Ошибка проверки IP конфигурации: {error}"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: api/v1/ip.py:64 api/v1/ip.py:101
|
||||||
|
#, python-brace-format
|
||||||
|
msgid "Настройки сетевого профиля для {connection_id} применены"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: api/v1/network.py:62
|
||||||
|
#, python-brace-format
|
||||||
|
msgid "Неверное имя контейнера: {container_name}"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: api/v1/network.py:129
|
||||||
|
msgid "Не удалось получить сетевые данные"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: api/v1/network.py:182
|
||||||
|
msgid ""
|
||||||
|
"Отсутствуют обязательные поля: container_id, container_x, container_y, "
|
||||||
|
"isOpen"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: api/v1/network.py:194
|
||||||
|
msgid "Неверный тип данных в запросе"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: api/v1/network.py:199
|
||||||
|
msgid "Позиция и состояние контейнера обновлены"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: api/v1/network.py:203
|
||||||
|
#, python-brace-format
|
||||||
|
msgid "Не удалось обновить положение контейнера: {error}"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: api/v1/network.py:225
|
||||||
|
msgid "Не удалось получить имя хоста"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: api/v1/settings.py:37
|
||||||
|
#, python-brace-format
|
||||||
|
msgid "Данные узлов подсети {subnet} успешно очищены"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: api/v1/settings.py:39
|
||||||
|
msgid "Данные всех подсетей успешно очищены"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: api/v1/settings.py:41
|
||||||
|
msgid "Не удалось очистить данные узлов подсети"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: api/v1/settings.py:44 api/v1/settings.py:69 api/v1/settings.py:94
|
||||||
|
#, python-brace-format
|
||||||
|
msgid "Ошибка очистки: {error}"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: api/v1/settings.py:64
|
||||||
|
msgid "Данные точек доступа Wi-Fi успешно очищены"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: api/v1/settings.py:66
|
||||||
|
msgid "Не удалось очистить данные точек доступа Wi-Fi"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: api/v1/settings.py:89
|
||||||
|
msgid "Все сетевые данные успешно очищены"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: api/v1/settings.py:91
|
||||||
|
msgid "Не удалось очистить все сетевые данные"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: api/v1/settings.py:117 api/v1/settings.py:141
|
||||||
|
msgid "Файл не найден"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: api/v1/settings.py:166
|
||||||
|
#, python-brace-format
|
||||||
|
msgid "Язык '{locale}' не поддерживается."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: api/v1/settings.py:172
|
||||||
|
#, python-brace-format
|
||||||
|
msgid "Язык '{locale}' не поддерживается (нет файлов переводов)."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: api/v1/settings.py:175
|
||||||
|
#, python-brace-format
|
||||||
|
msgid "Язык успешно установлен: {locale}"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: api/v1/subnet.py:44
|
||||||
|
#, python-brace-format
|
||||||
|
msgid "Ошибка сканирования подсети: {error}"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: api/v1/subnet.py:67
|
||||||
|
#, python-brace-format
|
||||||
|
msgid "Ошибка сканирования Wi-Fi: {error}"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: api/v1/subnet.py:92 api/v1/subnet.py:126 api/v1/subnet.py:159
|
||||||
|
#, python-brace-format
|
||||||
|
msgid "Устройство с MAC {mac} не найдено"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: api/v1/subnet.py:94
|
||||||
|
#, python-brace-format
|
||||||
|
msgid "Заметка для устройства с MAC {mac} уже существует"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: api/v1/subnet.py:96 api/v1/subnet.py:130 api/v1/subnet.py:163
|
||||||
|
#: api/v1/subnet.py:197 api/v1/subnet.py:231 api/v1/subnet.py:264
|
||||||
|
#: services/wifi_service.py:319 services/wifi_service.py:337
|
||||||
|
#: services/wifi_service.py:355
|
||||||
|
#, python-brace-format
|
||||||
|
msgid "Внутренняя ошибка сервера: {error}"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: api/v1/subnet.py:97
|
||||||
|
#, python-brace-format
|
||||||
|
msgid "Заметка '{note}' добавлена для устройства {mac}"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: api/v1/subnet.py:101 api/v1/subnet.py:202
|
||||||
|
#, python-brace-format
|
||||||
|
msgid "Ошибка добавления заметки: {error}"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: api/v1/subnet.py:128 api/v1/subnet.py:161
|
||||||
|
#, python-brace-format
|
||||||
|
msgid "Заметка для устройства с MAC {mac} не существует"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: api/v1/subnet.py:131
|
||||||
|
#, python-brace-format
|
||||||
|
msgid "Заметка '{note}' обновлена для устройства {mac}"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: api/v1/subnet.py:135 api/v1/subnet.py:236
|
||||||
|
#, python-brace-format
|
||||||
|
msgid "Ошибка обновления заметки: {error}"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: api/v1/subnet.py:164
|
||||||
|
#, python-brace-format
|
||||||
|
msgid "Заметка удалена для устройства {mac}"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: api/v1/subnet.py:168 api/v1/subnet.py:269
|
||||||
|
#, python-brace-format
|
||||||
|
msgid "Ошибка удаления заметки: {error}"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: api/v1/subnet.py:193 api/v1/subnet.py:227 api/v1/subnet.py:260
|
||||||
|
#: services/wifi_service.py:327 services/wifi_service.py:345
|
||||||
|
#, python-brace-format
|
||||||
|
msgid "Сеть с SSID {ssid} не найдена"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: api/v1/subnet.py:195 services/wifi_service.py:312
|
||||||
|
#, python-brace-format
|
||||||
|
msgid "Заметка для сети с SSID {ssid} уже существует"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: api/v1/subnet.py:198
|
||||||
|
#, python-brace-format
|
||||||
|
msgid "Заметка '{note}' добавлена для сети с SSID {ssid}"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: api/v1/subnet.py:229 api/v1/subnet.py:262 services/wifi_service.py:330
|
||||||
|
#: services/wifi_service.py:348
|
||||||
|
#, python-brace-format
|
||||||
|
msgid "Заметка для сети с SSID {ssid} не существует"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: api/v1/subnet.py:232
|
||||||
|
#, python-brace-format
|
||||||
|
msgid "Заметка '{note}' обновлена для сети с SSID {ssid}"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: api/v1/subnet.py:265
|
||||||
|
#, python-brace-format
|
||||||
|
msgid "Заметка удалена для сети с SSID {ssid}"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: api/v1/subnet.py:293
|
||||||
|
#, python-brace-format
|
||||||
|
msgid "Успешно подключено к {ssid}"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: api/v1/subnet.py:297
|
||||||
|
#, python-brace-format
|
||||||
|
msgid "Ошибка подключения к Wi-Fi: {error}"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: api/v1/subnet.py:320
|
||||||
|
#, python-brace-format
|
||||||
|
msgid "Успешно отключено от {ssid}"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: api/v1/subnet.py:324
|
||||||
|
#, python-brace-format
|
||||||
|
msgid "Ошибка отключения от Wi-Fi: {error}"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: api/v1/subnet.py:348
|
||||||
|
msgid "connected"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: api/v1/subnet.py:352
|
||||||
|
#, python-brace-format
|
||||||
|
msgid "Ошибка проверки статуса Wi-Fi: {error}"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: api/v1/websocket.py:145
|
||||||
|
msgid "Ошибка: Ключ 'activation' отсутствует в полученных данных сети"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: services/arp_service.py:102
|
||||||
|
msgid "Доступные устройства в сети:"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: services/arp_service.py:103
|
||||||
|
msgid "IP"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: services/arp_service.py:103
|
||||||
|
msgid "MAC"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: services/auth_service.py:72
|
||||||
|
msgid "Ошибка регистрации"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: services/auth_service.py:80 services/auth_service.py:84
|
||||||
|
msgid "Неверный логин или пароль"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: services/auth_service.py:100
|
||||||
|
msgid "Ошибка авторизации"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: services/auth_service.py:108
|
||||||
|
msgid "Неверный токен"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: services/auth_service.py:113 services/auth_service.py:128
|
||||||
|
msgid "Пользователь не найден"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: services/auth_service.py:122
|
||||||
|
msgid "Сессия недействительна"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: services/auth_service.py:144
|
||||||
|
msgid "Успешный выход из системы"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: services/auth_service.py:148
|
||||||
|
msgid "Ошибка при выходе из системы"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: services/connect_service.py:70 services/connect_service.py:117
|
||||||
|
#: services/connect_service.py:154 services/wifi_service.py:227
|
||||||
|
msgid "Wi-Fi-интерфейс не доступен"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: services/connect_service.py:74
|
||||||
|
#, python-brace-format
|
||||||
|
msgid "Сеть с SSID {ssid} не найдена в списке доступных сетей"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: services/connect_service.py:81 services/connect_service.py:92
|
||||||
|
#, python-brace-format
|
||||||
|
msgid "Ошибка подключения к {ssid}: Неверный пароль"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: services/connect_service.py:83 services/connect_service.py:94
|
||||||
|
#, python-brace-format
|
||||||
|
msgid ""
|
||||||
|
"Ошибка подключения к {ssid}: Сеть с SSID {ssid} недоступна или неверно "
|
||||||
|
"указана"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: services/connect_service.py:85 services/connect_service.py:95
|
||||||
|
#, python-brace-format
|
||||||
|
msgid "Ошибка подключения к {ssid}: {error}"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: services/connect_service.py:98
|
||||||
|
#, python-brace-format
|
||||||
|
msgid "Ошибка подключения к {ssid}: Неизвестная ошибка - {error}"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: services/connect_service.py:122
|
||||||
|
#, python-brace-format
|
||||||
|
msgid "Нет активного подключения для SSID {ssid}"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: services/connect_service.py:133
|
||||||
|
#, python-brace-format
|
||||||
|
msgid "Активное подключение с SSID {ssid} не найдено"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: services/connect_service.py:136 services/connect_service.py:139
|
||||||
|
#, python-brace-format
|
||||||
|
msgid "Ошибка отключения от {ssid}: {error}"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: services/connect_service.py:160
|
||||||
|
msgid "Не подключено к Wi-Fi"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: services/connect_service.py:163
|
||||||
|
#, python-brace-format
|
||||||
|
msgid "Ошибка проверки статуса: {error}"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: services/ip_service.py:69
|
||||||
|
#, python-brace-format
|
||||||
|
msgid "IP-адрес {ip} уже занят."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: services/ip_service.py:73
|
||||||
|
msgid "Настройки сетевого профиля доступны для использования."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: services/ip_service.py:102
|
||||||
|
#, python-brace-format
|
||||||
|
msgid "Подключение {connection_id} не найдено"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: services/ip_service.py:130
|
||||||
|
#, python-brace-format
|
||||||
|
msgid "Устройство для интерфейса {interface} не найдено"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: services/network_service.py:232
|
||||||
|
#, python-brace-format
|
||||||
|
msgid "Не удалось выполнить команду hostname: {error}"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: services/network_service.py:234
|
||||||
|
#, python-brace-format
|
||||||
|
msgid "Ошибка обработки вывода hostname: {error}"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: services/settings_service.py:55
|
||||||
|
#, python-brace-format
|
||||||
|
msgid "Ошибка очистки узлов подсети: {error}"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: services/settings_service.py:76
|
||||||
|
#, python-brace-format
|
||||||
|
msgid "Ошибка очистки точек доступа Wi-Fi: {error}"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: services/settings_service.py:104
|
||||||
|
#, python-brace-format
|
||||||
|
msgid "Ошибка очистки всех сетевых данных: {error}"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: services/subnet_service.py:75 services/wifi_service.py:115
|
||||||
|
msgid "Неизвестный"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: services/subnet_service.py:185
|
||||||
|
#, python-brace-format
|
||||||
|
msgid "Ошибка при сохранении устройств: {error}"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: services/subnet_service.py:268
|
||||||
|
msgid "Недопустимая подсеть по умолчанию"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: services/subnet_service.py:288
|
||||||
|
msgid "В данной подсети не обнаружено устройств"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: services/subnet_service.py:345
|
||||||
|
#, python-brace-format
|
||||||
|
msgid "Ошибка сканирования: {error}"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: services/wifi_service.py:61
|
||||||
|
#, python-brace-format
|
||||||
|
msgid "Ошибка при сохранении заметок: {error}"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: services/wifi_service.py:81
|
||||||
|
msgid "Не найдено сетевых интерфейсов"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: services/wifi_service.py:102
|
||||||
|
msgid "Не найден активный Wi-Fi-интерфейс"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: services/wifi_service.py:122
|
||||||
|
msgid "WPA3"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: services/wifi_service.py:124
|
||||||
|
msgid "WPA2"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: services/wifi_service.py:126
|
||||||
|
msgid "WPA"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: services/wifi_service.py:128
|
||||||
|
msgid "WEP"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: services/wifi_service.py:129
|
||||||
|
msgid "Открытая"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: services/wifi_service.py:152
|
||||||
|
msgid "2.4 ГГц"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: services/wifi_service.py:154
|
||||||
|
msgid "5 ГГц"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: services/wifi_service.py:165
|
||||||
|
msgid "Интерфейс не определён"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: services/wifi_service.py:215
|
||||||
|
msgid "Таймаут при выполнении iw scan"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
Binary file not shown.
|
|
@ -7,8 +7,8 @@ msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: PROJECT VERSION\n"
|
"Project-Id-Version: PROJECT VERSION\n"
|
||||||
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
||||||
"POT-Creation-Date: 2025-07-15 15:01+0500\n"
|
"POT-Creation-Date: 2025-07-16 13:15+0500\n"
|
||||||
"PO-Revision-Date: 2025-07-15 15:02+0500\n"
|
"PO-Revision-Date: 2025-07-16 13:15+0500\n"
|
||||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||||
"Language: ru\n"
|
"Language: ru\n"
|
||||||
"Language-Team: ru <LL@li.org>\n"
|
"Language-Team: ru <LL@li.org>\n"
|
||||||
|
|
@ -99,134 +99,179 @@ msgstr "Не удалось обновить положение контейне
|
||||||
msgid "Не удалось получить имя хоста"
|
msgid "Не удалось получить имя хоста"
|
||||||
msgstr "Не удалось получить имя хоста"
|
msgstr "Не удалось получить имя хоста"
|
||||||
|
|
||||||
#: api/v1/settings.py:33
|
#: api/v1/settings.py:37
|
||||||
msgid "Данные узлов подсети успешно очищены"
|
#, python-brace-format
|
||||||
msgstr "Данные узлов подсети успешно очищены"
|
msgid "Данные узлов подсети {subnet} успешно очищены"
|
||||||
|
msgstr "Данные узлов подсети {subnet} успешно очищены"
|
||||||
|
|
||||||
#: api/v1/settings.py:35
|
#: api/v1/settings.py:39
|
||||||
|
msgid "Данные всех подсетей успешно очищены"
|
||||||
|
msgstr "Данные всех подсетей успешно очищены"
|
||||||
|
|
||||||
|
#: api/v1/settings.py:41
|
||||||
msgid "Не удалось очистить данные узлов подсети"
|
msgid "Не удалось очистить данные узлов подсети"
|
||||||
msgstr "Не удалось очистить данные узлов подсети"
|
msgstr "Не удалось очистить данные узлов подсети"
|
||||||
|
|
||||||
#: api/v1/settings.py:38 api/v1/settings.py:63 api/v1/settings.py:88
|
#: api/v1/settings.py:44 api/v1/settings.py:69 api/v1/settings.py:94
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "Ошибка очистки: {error}"
|
msgid "Ошибка очистки: {error}"
|
||||||
msgstr "Ошибка очистки: {error}"
|
msgstr "Ошибка очистки: {error}"
|
||||||
|
|
||||||
#: api/v1/settings.py:58
|
#: api/v1/settings.py:64
|
||||||
msgid "Данные точек доступа Wi-Fi успешно очищены"
|
msgid "Данные точек доступа Wi-Fi успешно очищены"
|
||||||
msgstr "Данные точек доступа Wi-Fi успешно очищены"
|
msgstr "Данные точек доступа Wi-Fi успешно очищены"
|
||||||
|
|
||||||
#: api/v1/settings.py:60
|
#: api/v1/settings.py:66
|
||||||
msgid "Не удалось очистить данные точек доступа Wi-Fi"
|
msgid "Не удалось очистить данные точек доступа Wi-Fi"
|
||||||
msgstr "Не удалось очистить данные точек доступа Wi-Fi"
|
msgstr "Не удалось очистить данные точек доступа Wi-Fi"
|
||||||
|
|
||||||
#: api/v1/settings.py:83
|
#: api/v1/settings.py:89
|
||||||
msgid "Все сетевые данные успешно очищены"
|
msgid "Все сетевые данные успешно очищены"
|
||||||
msgstr "Все сетевые данные успешно очищены"
|
msgstr "Все сетевые данные успешно очищены"
|
||||||
|
|
||||||
#: api/v1/settings.py:85
|
#: api/v1/settings.py:91
|
||||||
msgid "Не удалось очистить все сетевые данные"
|
msgid "Не удалось очистить все сетевые данные"
|
||||||
msgstr "Не удалось очистить все сетевые данные"
|
msgstr "Не удалось очистить все сетевые данные"
|
||||||
|
|
||||||
#: api/v1/settings.py:109 api/v1/settings.py:133
|
#: api/v1/settings.py:117 api/v1/settings.py:141
|
||||||
msgid "Файл не найден"
|
msgid "Файл не найден"
|
||||||
msgstr "Файл не найден"
|
msgstr "Файл не найден"
|
||||||
|
|
||||||
#: api/v1/settings.py:158
|
#: api/v1/settings.py:166
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "Язык '{locale}' не поддерживается."
|
msgid "Язык '{locale}' не поддерживается."
|
||||||
msgstr "Язык '{locale}' не поддерживается."
|
msgstr "Язык '{locale}' не поддерживается."
|
||||||
|
|
||||||
#: api/v1/settings.py:164
|
#: api/v1/settings.py:172
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "Язык '{locale}' не поддерживается (нет файлов переводов)."
|
msgid "Язык '{locale}' не поддерживается (нет файлов переводов)."
|
||||||
msgstr "Язык '{locale}' не поддерживается (нет файлов переводов)."
|
msgstr "Язык '{locale}' не поддерживается (нет файлов переводов)."
|
||||||
|
|
||||||
#: api/v1/settings.py:167
|
#: api/v1/settings.py:175
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "Язык успешно установлен: {locale}"
|
msgid "Язык успешно установлен: {locale}"
|
||||||
msgstr "Язык успешно установлен: {locale}"
|
msgstr "Язык успешно установлен: {locale}"
|
||||||
|
|
||||||
#: api/v1/subnet.py:45
|
#: api/v1/subnet.py:44
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "Ошибка сканирования: {error}"
|
msgid "Ошибка сканирования подсети: {error}"
|
||||||
msgstr "Ошибка сканирования: {error}"
|
msgstr "Ошибка сканирования подсети: {error}"
|
||||||
|
|
||||||
#: api/v1/subnet.py:68
|
#: api/v1/subnet.py:67
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "Ошибка сканирования Wi-Fi: {error}"
|
msgid "Ошибка сканирования Wi-Fi: {error}"
|
||||||
msgstr "Ошибка сканирования Wi-Fi: {error}"
|
msgstr "Ошибка сканирования Wi-Fi: {error}"
|
||||||
|
|
||||||
#: api/v1/subnet.py:96
|
#: api/v1/subnet.py:92 api/v1/subnet.py:126 api/v1/subnet.py:159
|
||||||
|
#, python-brace-format
|
||||||
|
msgid "Устройство с MAC {mac} не найдено"
|
||||||
|
msgstr "Устройство с MAC {mac} не найдено"
|
||||||
|
|
||||||
|
#: api/v1/subnet.py:94
|
||||||
|
#, python-brace-format
|
||||||
|
msgid "Заметка для устройства с MAC {mac} уже существует"
|
||||||
|
msgstr "Заметка для устройства с MAC {mac} уже существует"
|
||||||
|
|
||||||
|
#: api/v1/subnet.py:96 api/v1/subnet.py:130 api/v1/subnet.py:163
|
||||||
|
#: api/v1/subnet.py:197 api/v1/subnet.py:231 api/v1/subnet.py:264
|
||||||
|
#: services/wifi_service.py:319 services/wifi_service.py:337
|
||||||
|
#: services/wifi_service.py:355
|
||||||
|
#, python-brace-format
|
||||||
|
msgid "Внутренняя ошибка сервера: {error}"
|
||||||
|
msgstr "Внутренняя ошибка сервера: {error}"
|
||||||
|
|
||||||
|
#: api/v1/subnet.py:97
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "Заметка '{note}' добавлена для устройства {mac}"
|
msgid "Заметка '{note}' добавлена для устройства {mac}"
|
||||||
msgstr "Заметка '{note}' добавлена для устройства {mac}"
|
msgstr "Заметка '{note}' добавлена для устройства {mac}"
|
||||||
|
|
||||||
#: api/v1/subnet.py:100 api/v1/subnet.py:195
|
#: api/v1/subnet.py:101 api/v1/subnet.py:202
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "Ошибка добавления заметки: {error}"
|
msgid "Ошибка добавления заметки: {error}"
|
||||||
msgstr "Ошибка добавления заметки: {error}"
|
msgstr "Ошибка добавления заметки: {error}"
|
||||||
|
|
||||||
#: api/v1/subnet.py:128
|
#: api/v1/subnet.py:128 api/v1/subnet.py:161
|
||||||
|
#, python-brace-format
|
||||||
|
msgid "Заметка для устройства с MAC {mac} не существует"
|
||||||
|
msgstr "Заметка для устройства с MAC {mac} не существует"
|
||||||
|
|
||||||
|
#: api/v1/subnet.py:131
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "Заметка '{note}' обновлена для устройства {mac}"
|
msgid "Заметка '{note}' обновлена для устройства {mac}"
|
||||||
msgstr "Заметка '{note}' обновлена для устройства {mac}"
|
msgstr "Заметка '{note}' обновлена для устройства {mac}"
|
||||||
|
|
||||||
#: api/v1/subnet.py:132 api/v1/subnet.py:227
|
#: api/v1/subnet.py:135 api/v1/subnet.py:236
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "Ошибка обновления заметки: {error}"
|
msgid "Ошибка обновления заметки: {error}"
|
||||||
msgstr "Ошибка обновления заметки: {error}"
|
msgstr "Ошибка обновления заметки: {error}"
|
||||||
|
|
||||||
#: api/v1/subnet.py:159
|
#: api/v1/subnet.py:164
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "Заметка удалена для устройства {mac}"
|
msgid "Заметка удалена для устройства {mac}"
|
||||||
msgstr "Заметка удалена для устройства {mac}"
|
msgstr "Заметка удалена для устройства {mac}"
|
||||||
|
|
||||||
#: api/v1/subnet.py:163 api/v1/subnet.py:258
|
#: api/v1/subnet.py:168 api/v1/subnet.py:269
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "Ошибка удаления заметки: {error}"
|
msgid "Ошибка удаления заметки: {error}"
|
||||||
msgstr "Ошибка удаления заметки: {error}"
|
msgstr "Ошибка удаления заметки: {error}"
|
||||||
|
|
||||||
#: api/v1/subnet.py:191
|
#: api/v1/subnet.py:193 api/v1/subnet.py:227 api/v1/subnet.py:260
|
||||||
|
#: services/wifi_service.py:327 services/wifi_service.py:345
|
||||||
|
#, python-brace-format
|
||||||
|
msgid "Сеть с SSID {ssid} не найдена"
|
||||||
|
msgstr "Сеть с SSID {ssid} не найдена"
|
||||||
|
|
||||||
|
#: api/v1/subnet.py:195 services/wifi_service.py:312
|
||||||
|
#, python-brace-format
|
||||||
|
msgid "Заметка для сети с SSID {ssid} уже существует"
|
||||||
|
msgstr "Заметка для сети с SSID {ssid} уже существует"
|
||||||
|
|
||||||
|
#: api/v1/subnet.py:198
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "Заметка '{note}' добавлена для сети с SSID {ssid}"
|
msgid "Заметка '{note}' добавлена для сети с SSID {ssid}"
|
||||||
msgstr "Заметка '{note}' добавлена для сети с SSID {ssid}"
|
msgstr "Заметка '{note}' добавлена для сети с SSID {ssid}"
|
||||||
|
|
||||||
#: api/v1/subnet.py:223
|
#: api/v1/subnet.py:229 api/v1/subnet.py:262 services/wifi_service.py:330
|
||||||
|
#: services/wifi_service.py:348
|
||||||
|
#, python-brace-format
|
||||||
|
msgid "Заметка для сети с SSID {ssid} не существует"
|
||||||
|
msgstr "Заметка для сети с SSID {ssid} не существует"
|
||||||
|
|
||||||
|
#: api/v1/subnet.py:232
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "Заметка '{note}' обновлена для сети с SSID {ssid}"
|
msgid "Заметка '{note}' обновлена для сети с SSID {ssid}"
|
||||||
msgstr "Заметка '{note}' обновлена для сети с SSID {ssid}"
|
msgstr "Заметка '{note}' обновлена для сети с SSID {ssid}"
|
||||||
|
|
||||||
#: api/v1/subnet.py:254
|
#: api/v1/subnet.py:265
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "Заметка удалена для сети с SSID {ssid}"
|
msgid "Заметка удалена для сети с SSID {ssid}"
|
||||||
msgstr "Заметка удалена для сети с SSID {ssid}"
|
msgstr "Заметка удалена для сети с SSID {ssid}"
|
||||||
|
|
||||||
#: api/v1/subnet.py:282
|
#: api/v1/subnet.py:293
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "Успешно подключено к {ssid}"
|
msgid "Успешно подключено к {ssid}"
|
||||||
msgstr "Успешно подключено к {ssid}"
|
msgstr "Успешно подключено к {ssid}"
|
||||||
|
|
||||||
#: api/v1/subnet.py:286
|
#: api/v1/subnet.py:297
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "Ошибка подключения к Wi-Fi: {error}"
|
msgid "Ошибка подключения к Wi-Fi: {error}"
|
||||||
msgstr "Ошибка подключения к Wi-Fi: {error}"
|
msgstr "Ошибка подключения к Wi-Fi: {error}"
|
||||||
|
|
||||||
#: api/v1/subnet.py:309
|
#: api/v1/subnet.py:320
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "Успешно отключено от {ssid}"
|
msgid "Успешно отключено от {ssid}"
|
||||||
msgstr "Успешно отключено от {ssid}"
|
msgstr "Успешно отключено от {ssid}"
|
||||||
|
|
||||||
#: api/v1/subnet.py:313
|
#: api/v1/subnet.py:324
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "Ошибка отключения от Wi-Fi: {error}"
|
msgid "Ошибка отключения от Wi-Fi: {error}"
|
||||||
msgstr "Ошибка отключения от Wi-Fi: {error}"
|
msgstr "Ошибка отключения от Wi-Fi: {error}"
|
||||||
|
|
||||||
#: api/v1/subnet.py:337
|
#: api/v1/subnet.py:348
|
||||||
msgid "connected"
|
msgid "connected"
|
||||||
msgstr "connected"
|
msgstr "connected"
|
||||||
|
|
||||||
#: api/v1/subnet.py:341
|
#: api/v1/subnet.py:352
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "Ошибка проверки статуса Wi-Fi: {error}"
|
msgid "Ошибка проверки статуса Wi-Fi: {error}"
|
||||||
msgstr "Ошибка проверки статуса Wi-Fi: {error}"
|
msgstr "Ошибка проверки статуса Wi-Fi: {error}"
|
||||||
|
|
@ -366,17 +411,17 @@ msgstr "Не удалось выполнить команду hostname: {error}"
|
||||||
msgid "Ошибка обработки вывода hostname: {error}"
|
msgid "Ошибка обработки вывода hostname: {error}"
|
||||||
msgstr "Ошибка обработки вывода hostname: {error}"
|
msgstr "Ошибка обработки вывода hostname: {error}"
|
||||||
|
|
||||||
#: services/settings_service.py:37
|
#: services/settings_service.py:55
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "Ошибка очистки узлов подсети: {error}"
|
msgid "Ошибка очистки узлов подсети: {error}"
|
||||||
msgstr "Ошибка очистки узлов подсети: {error}"
|
msgstr "Ошибка очистки узлов подсети: {error}"
|
||||||
|
|
||||||
#: services/settings_service.py:58
|
#: services/settings_service.py:76
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "Ошибка очистки точек доступа Wi-Fi: {error}"
|
msgid "Ошибка очистки точек доступа Wi-Fi: {error}"
|
||||||
msgstr "Ошибка очистки точек доступа Wi-Fi: {error}"
|
msgstr "Ошибка очистки точек доступа Wi-Fi: {error}"
|
||||||
|
|
||||||
#: services/settings_service.py:84
|
#: services/settings_service.py:104
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "Ошибка очистки всех сетевых данных: {error}"
|
msgid "Ошибка очистки всех сетевых данных: {error}"
|
||||||
msgstr "Ошибка очистки всех сетевых данных: {error}"
|
msgstr "Ошибка очистки всех сетевых данных: {error}"
|
||||||
|
|
@ -385,33 +430,23 @@ msgstr "Ошибка очистки всех сетевых данных: {error
|
||||||
msgid "Неизвестный"
|
msgid "Неизвестный"
|
||||||
msgstr "Неизвестный"
|
msgstr "Неизвестный"
|
||||||
|
|
||||||
#: services/subnet_service.py:179
|
#: services/subnet_service.py:185
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "Ошибка при сохранении устройств: {error}"
|
msgid "Ошибка при сохранении устройств: {error}"
|
||||||
msgstr "Ошибка при сохранении устройств: {error}"
|
msgstr "Ошибка при сохранении устройств: {error}"
|
||||||
|
|
||||||
#: services/subnet_service.py:374 services/subnet_service.py:391
|
#: services/subnet_service.py:268
|
||||||
#: services/subnet_service.py:408
|
msgid "Недопустимая подсеть по умолчанию"
|
||||||
#, python-brace-format
|
msgstr "Недопустимая подсеть по умолчанию"
|
||||||
msgid "Устройство с MAC {mac} не найдено"
|
|
||||||
msgstr "Устройство с MAC {mac} не найдено"
|
|
||||||
|
|
||||||
#: services/subnet_service.py:377
|
#: services/subnet_service.py:288
|
||||||
#, python-brace-format
|
msgid "В данной подсети не обнаружено устройств"
|
||||||
msgid "Заметка для устройства с MAC {mac} уже существует"
|
msgstr "В данной подсети не обнаружено устройств"
|
||||||
msgstr "Заметка для устройства с MAC {mac} уже существует"
|
|
||||||
|
|
||||||
#: services/subnet_service.py:384 services/subnet_service.py:401
|
#: services/subnet_service.py:345
|
||||||
#: services/subnet_service.py:418 services/wifi_service.py:319
|
|
||||||
#: services/wifi_service.py:337 services/wifi_service.py:355
|
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "Внутренняя ошибка сервера: {error}"
|
msgid "Ошибка сканирования: {error}"
|
||||||
msgstr "Внутренняя ошибка сервера: {error}"
|
msgstr "Ошибка сканирования: {error}"
|
||||||
|
|
||||||
#: services/subnet_service.py:394 services/subnet_service.py:411
|
|
||||||
#, python-brace-format
|
|
||||||
msgid "Заметка для устройства с MAC {mac} не существует"
|
|
||||||
msgstr "Заметка для устройства с MAC {mac} не существует"
|
|
||||||
|
|
||||||
#: services/wifi_service.py:61
|
#: services/wifi_service.py:61
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
|
|
@ -461,18 +496,3 @@ msgstr "Интерфейс не определён"
|
||||||
#: services/wifi_service.py:215
|
#: services/wifi_service.py:215
|
||||||
msgid "Таймаут при выполнении iw scan"
|
msgid "Таймаут при выполнении iw scan"
|
||||||
msgstr "Таймаут при выполнении iw scan"
|
msgstr "Таймаут при выполнении iw scan"
|
||||||
|
|
||||||
#: services/wifi_service.py:312
|
|
||||||
#, python-brace-format
|
|
||||||
msgid "Заметка для сети с SSID {ssid} уже существует"
|
|
||||||
msgstr "Заметка для сети с SSID {ssid} уже существует"
|
|
||||||
|
|
||||||
#: services/wifi_service.py:327 services/wifi_service.py:345
|
|
||||||
#, python-brace-format
|
|
||||||
msgid "Сеть с SSID {ssid} не найдена"
|
|
||||||
msgstr "Сеть с SSID {ssid} не найдена"
|
|
||||||
|
|
||||||
#: services/wifi_service.py:330 services/wifi_service.py:348
|
|
||||||
#, python-brace-format
|
|
||||||
msgid "Заметка для сети с SSID {ssid} не существует"
|
|
||||||
msgstr "Заметка для сети с SSID {ssid} не существует"
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
from pydantic import BaseModel
|
from pydantic import BaseModel
|
||||||
from typing import Optional, List
|
from typing import Optional, List
|
||||||
|
|
||||||
|
|
||||||
class Device(BaseModel):
|
class Device(BaseModel):
|
||||||
"""
|
"""
|
||||||
Сканируемое устройство в подсети
|
Сканируемое устройство в подсети
|
||||||
|
|
@ -26,17 +25,17 @@ class Device(BaseModel):
|
||||||
last_seen: Optional[str] = None
|
last_seen: Optional[str] = None
|
||||||
note: Optional[str] = None
|
note: Optional[str] = None
|
||||||
|
|
||||||
|
|
||||||
class SubnetScanResult(BaseModel):
|
class SubnetScanResult(BaseModel):
|
||||||
"""
|
"""
|
||||||
Результат сканирования устройств в подсети
|
Результат сканирования устройств в подсети
|
||||||
|
|
||||||
Атрибуты:
|
Атрибуты:
|
||||||
devices (List[Device]): Список просканированных устройств
|
devices (List[Device]): Список просканированных устройств
|
||||||
|
error (Optional[str]): Сообщение об ошибке, если сканирование не удалось
|
||||||
"""
|
"""
|
||||||
|
|
||||||
devices: List[Device] = []
|
devices: List[Device] = []
|
||||||
|
error: Optional[str] = None
|
||||||
|
|
||||||
class SubnetScanRequest(BaseModel):
|
class SubnetScanRequest(BaseModel):
|
||||||
"""
|
"""
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,11 @@
|
||||||
import json
|
import json
|
||||||
import logging
|
import logging
|
||||||
from utils.i18n import get_translations, _
|
from typing import Optional
|
||||||
|
|
||||||
|
from utils.i18n import get_translations
|
||||||
from babel.support import Translations
|
from babel.support import Translations
|
||||||
from fastapi import Depends
|
from fastapi import Depends
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
logging.basicConfig(level=logging.INFO)
|
logging.basicConfig(level=logging.INFO)
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
@ -11,12 +14,16 @@ class SettingsService:
|
||||||
"""Сервис для управления настройками и очистки данных сети."""
|
"""Сервис для управления настройками и очистки данных сети."""
|
||||||
|
|
||||||
def __init__(self, translations: Translations = Depends(get_translations())):
|
def __init__(self, translations: Translations = Depends(get_translations())):
|
||||||
self.subnet_file = "storage/devices/devices.json"
|
self.subnet_base_path = "storage/subnets"
|
||||||
self.wifi_file = "storage/wifi/wifi.json"
|
self.wifi_file = "storage/wifi/wifi.json"
|
||||||
self.translations = translations
|
self.translations = translations
|
||||||
|
|
||||||
def clear_subnet(self) -> bool:
|
def clear_subnet(self, subnet: Optional[str] = None) -> bool:
|
||||||
"""Очищает данные узлов подсети в файле devices.json.
|
"""Очищает данные узлов подсети в указанном файле или во всех файлах.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
subnet (Optional[str]): Подсеть в формате CIDR (например, "10.1.1.0/24").
|
||||||
|
Если None, очищает все подсети.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
bool: True, если очистка успешна.
|
bool: True, если очистка успешна.
|
||||||
|
|
@ -25,12 +32,23 @@ class SettingsService:
|
||||||
Exception: Если произошла ошибка при записи в файл.
|
Exception: Если произошла ошибка при записи в файл.
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
with open(self.subnet_file, "w") as f:
|
if subnet:
|
||||||
json.dump([], f)
|
file_path = Path(self.subnet_base_path) / f"{subnet.replace('/', '_')}.json"
|
||||||
logger.info("Subnet nodes data successfully cleared")
|
if file_path.exists():
|
||||||
return True
|
with open(file_path, "w") as f:
|
||||||
|
json.dump([], f)
|
||||||
|
logger.info(f"Subnet nodes data cleared for {subnet}")
|
||||||
|
else:
|
||||||
|
logger.info(f"Subnet file not found for {subnet}, clearing considered successful")
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
for file_path in Path(self.subnet_base_path).glob("*.json"):
|
||||||
|
with open(file_path, "w") as f:
|
||||||
|
json.dump([], f)
|
||||||
|
logger.info(f"Cleared subnet data in {file_path}")
|
||||||
|
return True
|
||||||
except FileNotFoundError:
|
except FileNotFoundError:
|
||||||
logger.info("Devices file not found, clearing considered successful")
|
logger.info("No subnet files found, clearing considered successful")
|
||||||
return True
|
return True
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"Error clearing subnet nodes: {str(e)}")
|
logger.error(f"Error clearing subnet nodes: {str(e)}")
|
||||||
|
|
@ -58,7 +76,7 @@ class SettingsService:
|
||||||
raise Exception(self.translations.gettext("Ошибка очистки точек доступа Wi-Fi: {error}").format(error=str(e)))
|
raise Exception(self.translations.gettext("Ошибка очистки точек доступа Wi-Fi: {error}").format(error=str(e)))
|
||||||
|
|
||||||
def clear_all_data(self) -> bool:
|
def clear_all_data(self) -> bool:
|
||||||
"""Очищает данные узлов подсети и точек доступа Wi-Fi в обоих файлах.
|
"""Очищает данные узлов всех подсетей и точек доступа Wi-Fi.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
bool: True, если очистка успешна.
|
bool: True, если очистка успешна.
|
||||||
|
|
@ -68,10 +86,12 @@ class SettingsService:
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
try:
|
try:
|
||||||
with open(self.subnet_file, "w") as f:
|
for file_path in Path(self.subnet_base_path).glob("*.json"):
|
||||||
json.dump([], f)
|
with open(file_path, "w") as f:
|
||||||
|
json.dump([], f)
|
||||||
|
logger.info(f"Cleared subnet data in {file_path}")
|
||||||
except FileNotFoundError:
|
except FileNotFoundError:
|
||||||
logger.info("Devices file not found, clearing considered successful")
|
logger.info("No subnet files found, clearing considered successful")
|
||||||
try:
|
try:
|
||||||
with open(self.wifi_file, "w") as f:
|
with open(self.wifi_file, "w") as f:
|
||||||
json.dump([], f)
|
json.dump([], f)
|
||||||
|
|
|
||||||
|
|
@ -27,14 +27,53 @@ logging.basicConfig(
|
||||||
)
|
)
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
def get_subnet_service(translations: Translations = Depends(get_translations())):
|
||||||
|
"""Фабричная функция для создания экземпляра SubnetService.
|
||||||
|
|
||||||
|
Использует зависимости FastAPI для получения объекта переводов и возвращает
|
||||||
|
экземпляр SubnetService с текущей локализацией.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
translations (Translations): Объект переводов для текущего языка.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
SubnetService: Экземпляр сервиса для работы с подсетями.
|
||||||
|
"""
|
||||||
|
return SubnetService(translations)
|
||||||
|
|
||||||
class NetworkScanner:
|
class NetworkScanner:
|
||||||
"""Класс для сканирования подсети с использованием ARP-запросов."""
|
"""Класс для сканирования подсети с использованием ARP-запросов.
|
||||||
def __init__(self, interface: str, translations: Translations = Depends(get_translations())):
|
|
||||||
|
Выполняет отправку ARP-запросов для обнаружения устройств в указанной подсети.
|
||||||
|
"""
|
||||||
|
def __init__(self, interface: str, translations: Translations):
|
||||||
|
"""Инициализирует сканер сети.
|
||||||
|
|
||||||
|
Устанавливает интерфейс для сканирования и объект переводов.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
interface (str): Имя сетевого интерфейса (например, "wlp0s20f3").
|
||||||
|
translations (Translations): Объект переводов для текущего языка.
|
||||||
|
"""
|
||||||
self.interface = interface
|
self.interface = interface
|
||||||
conf.iface = interface
|
conf.iface = interface
|
||||||
self.translations = translations
|
self.translations = translations
|
||||||
|
|
||||||
def scan(self, subnet: str) -> List[Tuple[str, str]]:
|
def scan(self, subnet: str) -> List[Tuple[str, str]]:
|
||||||
|
"""Сканирует подсеть с использованием ARP-запросов.
|
||||||
|
|
||||||
|
Отправляет ARP-пакеты для обнаружения активных устройств и возвращает
|
||||||
|
список кортежей (IP, MAC).
|
||||||
|
|
||||||
|
Args:
|
||||||
|
subnet (str): Подсеть в формате CIDR (например, "10.1.1.0/24").
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
List[Tuple[str, str]]: Список кортежей (IP-адрес, MAC-адрес) обнаруженных устройств.
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
Exception: Если произошла ошибка сканирования.
|
||||||
|
"""
|
||||||
try:
|
try:
|
||||||
arp = ARP(pdst=subnet)
|
arp = ARP(pdst=subnet)
|
||||||
ether = Ether(dst="ff:ff:ff:ff:ff:ff")
|
ether = Ether(dst="ff:ff:ff:ff:ff:ff")
|
||||||
|
|
@ -46,17 +85,48 @@ class NetworkScanner:
|
||||||
return []
|
return []
|
||||||
|
|
||||||
class PortScanner:
|
class PortScanner:
|
||||||
"""Класс для сканирования открытых портов на устройствах."""
|
"""Класс для сканирования открытых портов на устройствах.
|
||||||
def __init__(self, interface: str, translations: Translations = Depends(get_translations())):
|
|
||||||
|
Предоставляет функциональность для проверки доступности портов, пока не реализована.
|
||||||
|
"""
|
||||||
|
def __init__(self, interface: str, translations: Translations):
|
||||||
|
"""Инициализирует сканер портов.
|
||||||
|
|
||||||
|
Устанавливает интерфейс для сканирования и объект переводов.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
interface (str): Имя сетевого интерфейса.
|
||||||
|
translations (Translations): Объект переводов для текущего языка.
|
||||||
|
"""
|
||||||
self.interface = interface
|
self.interface = interface
|
||||||
self.translations = translations
|
self.translations = translations
|
||||||
|
|
||||||
def scan(self, ip: str) -> List[str]:
|
def scan(self, ip: str) -> List[str]:
|
||||||
|
"""Сканирует открытые порты на указанном IP-адресе.
|
||||||
|
|
||||||
|
Пока возвращает пустой список, так как функциональность не реализована.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
ip (str): IP-адрес устройства для сканирования.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
List[str]: Список открытых портов (пока пустой).
|
||||||
|
"""
|
||||||
return []
|
return []
|
||||||
|
|
||||||
class DeviceInfoCollector:
|
class DeviceInfoCollector:
|
||||||
"""Класс для сбора информации об устройствах, включая вендоров и хостнеймы."""
|
"""Класс для сбора информации об устройствах, включая вендоров и хостнеймы.
|
||||||
def __init__(self, translations: Translations = Depends(get_translations())):
|
|
||||||
|
Использует внешние сервисы (MacLookup, NBTSCAN, DNS) для получения данных.
|
||||||
|
"""
|
||||||
|
def __init__(self, translations: Translations):
|
||||||
|
"""Инициализирует коллектор информации об устройствах.
|
||||||
|
|
||||||
|
Настраивает кэширование и объект переводов.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
translations (Translations): Объект переводов для текущего языка.
|
||||||
|
"""
|
||||||
self.mac_lookup = MacLookup()
|
self.mac_lookup = MacLookup()
|
||||||
self.nbtscan_cache = {}
|
self.nbtscan_cache = {}
|
||||||
self.nbtscan_results = {}
|
self.nbtscan_results = {}
|
||||||
|
|
@ -64,6 +134,16 @@ class DeviceInfoCollector:
|
||||||
|
|
||||||
@lru_cache(maxsize=1000)
|
@lru_cache(maxsize=1000)
|
||||||
def get_vendor(self, mac: str) -> str:
|
def get_vendor(self, mac: str) -> str:
|
||||||
|
"""Получает вендора устройства по MAC-адресу.
|
||||||
|
|
||||||
|
Использует кэширование для повышения производительности.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
mac (str): MAC-адрес устройства.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
str: Название вендора или "Неизвестный" в случае ошибки.
|
||||||
|
"""
|
||||||
try:
|
try:
|
||||||
return self.mac_lookup.lookup(mac)
|
return self.mac_lookup.lookup(mac)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
|
@ -71,6 +151,13 @@ class DeviceInfoCollector:
|
||||||
return self.translations.gettext("Неизвестный")
|
return self.translations.gettext("Неизвестный")
|
||||||
|
|
||||||
def scan_nbtscan(self, subnet: str) -> None:
|
def scan_nbtscan(self, subnet: str) -> None:
|
||||||
|
"""Сканирует подсеть с помощью nbtscan для получения хостнеймов.
|
||||||
|
|
||||||
|
Сохраняет результаты в кэш и логирует процесс.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
subnet (str): Подсеть в формате CIDR.
|
||||||
|
"""
|
||||||
if subnet not in self.nbtscan_results:
|
if subnet not in self.nbtscan_results:
|
||||||
try:
|
try:
|
||||||
logger.debug(f"Starting nbtscan for subnet {subnet}")
|
logger.debug(f"Starting nbtscan for subnet {subnet}")
|
||||||
|
|
@ -97,6 +184,16 @@ class DeviceInfoCollector:
|
||||||
logger.error(f"NetBIOS: Error for subnet {subnet}: {str(e)}")
|
logger.error(f"NetBIOS: Error for subnet {subnet}: {str(e)}")
|
||||||
|
|
||||||
def get_hostname(self, ip: str) -> Optional[str]:
|
def get_hostname(self, ip: str) -> Optional[str]:
|
||||||
|
"""Получает хостнейм для указанного IP-адреса.
|
||||||
|
|
||||||
|
Пробует сначала DNS, затем NetBIOS.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
ip (str): IP-адрес устройства.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Optional[str]: Хостнейм или None, если не удалось определить.
|
||||||
|
"""
|
||||||
try:
|
try:
|
||||||
socket.setdefaulttimeout(2)
|
socket.setdefaulttimeout(2)
|
||||||
return socket.gethostbyaddr(ip)[0]
|
return socket.gethostbyaddr(ip)[0]
|
||||||
|
|
@ -114,20 +211,56 @@ class DeviceInfoCollector:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
class DeviceStorage:
|
class DeviceStorage:
|
||||||
"""Класс для хранения и управления данными об устройствах."""
|
"""Класс для хранения и управления данными об устройствах.
|
||||||
def __init__(self, storage_path: str = "storage/devices/devices.json", translations: Translations = Depends(get_translations())):
|
|
||||||
self.storage_file = Path(storage_path)
|
|
||||||
self.storage_file.parent.mkdir(parents=True, exist_ok=True)
|
|
||||||
self.offline_timeout = timedelta(days=7)
|
|
||||||
self.translations = translations
|
|
||||||
|
|
||||||
def load_devices(self) -> Dict[str, Device]:
|
Обеспечивает загрузку и сохранение данных в JSON-файлы.
|
||||||
|
"""
|
||||||
|
def __init__(self, base_path: str = "storage/subnets", translations: Translations = None):
|
||||||
|
"""Инициализирует хранилище устройств.
|
||||||
|
|
||||||
|
Создаёт директорию, если её нет, и задаёт параметры очистки.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
base_path (str): Путь к директории хранения данных.
|
||||||
|
translations (Translations, optional): Объект переводов.
|
||||||
|
"""
|
||||||
|
self.base_path = Path(base_path)
|
||||||
|
self.base_path.mkdir(parents=True, exist_ok=True)
|
||||||
|
self.offline_timeout = timedelta(days=7)
|
||||||
|
self.translations = translations or Translations.load("locales", ["ru"], "messages") # Fallback на русский
|
||||||
|
|
||||||
|
def get_subnet_file(self, subnet: str) -> Path:
|
||||||
|
"""Возвращает путь к файлу для конкретной подсети.
|
||||||
|
|
||||||
|
Заменяет символы '/' на '_' для корректного имени файла.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
subnet (str): Подсеть в формате CIDR.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Path: Путь к файлу.
|
||||||
|
"""
|
||||||
|
sanitized_subnet = subnet.replace("/", "_")
|
||||||
|
return self.base_path / f"{sanitized_subnet}.json"
|
||||||
|
|
||||||
|
def load_devices(self, subnet: str) -> Dict[str, Device]:
|
||||||
|
"""Загружает устройства для указанной подсети.
|
||||||
|
|
||||||
|
Читает данные из JSON-файла и фильтрует устаревшие устройства.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
subnet (str): Подсеть в формате CIDR.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Dict[str, Device]: Словарь устройств с MAC как ключом.
|
||||||
|
"""
|
||||||
|
file_path = self.get_subnet_file(subnet)
|
||||||
try:
|
try:
|
||||||
if self.storage_file.exists():
|
if file_path.exists():
|
||||||
with open(self.storage_file, "r", encoding="utf-8") as f:
|
with open(file_path, "r", encoding="utf-8") as f:
|
||||||
data = json.load(f)
|
data = json.load(f)
|
||||||
if not isinstance(data, dict) or "devices" not in data:
|
if not isinstance(data, dict) or "devices" not in data:
|
||||||
logger.warning(f"Invalid JSON structure in {self.storage_file}, expected {'devices': [...]}, got {data}")
|
logger.warning(f"Invalid JSON structure in {file_path}, expected {'devices': [...]}, got {data}")
|
||||||
return {}
|
return {}
|
||||||
devices = {}
|
devices = {}
|
||||||
for device_data in data.get("devices", []):
|
for device_data in data.get("devices", []):
|
||||||
|
|
@ -137,13 +270,23 @@ class DeviceStorage:
|
||||||
return self._clean_old_devices(devices)
|
return self._clean_old_devices(devices)
|
||||||
return {}
|
return {}
|
||||||
except json.JSONDecodeError as e:
|
except json.JSONDecodeError as e:
|
||||||
logger.error(f"JSON decode error in {self.storage_file}: {str(e)}")
|
logger.error(f"JSON decode error in {file_path}: {str(e)}")
|
||||||
return {}
|
return {}
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"Error loading devices: {str(e)}")
|
logger.error(f"Error loading devices for subnet {subnet}: {str(e)}")
|
||||||
return {}
|
return {}
|
||||||
|
|
||||||
def _clean_old_devices(self, devices: Dict[str, Device]) -> Dict[str, Device]:
|
def _clean_old_devices(self, devices: Dict[str, Device]) -> Dict[str, Device]:
|
||||||
|
"""Очищает список устройств от устаревших оффлайн-устройств.
|
||||||
|
|
||||||
|
Удаляет устройства, которые оффлайн более 7 дней.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
devices (Dict[str, Device]): Словарь устройств.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Dict[str, Device]: Отфильтрованный словарь устройств.
|
||||||
|
"""
|
||||||
now = datetime.now()
|
now = datetime.now()
|
||||||
filtered = {}
|
filtered = {}
|
||||||
for mac, device in devices.items():
|
for mac, device in devices.items():
|
||||||
|
|
@ -160,28 +303,63 @@ class DeviceStorage:
|
||||||
filtered[mac] = device
|
filtered[mac] = device
|
||||||
return filtered
|
return filtered
|
||||||
|
|
||||||
def save_devices(self, devices: List[Device]) -> None:
|
def save_devices(self, subnet: str, devices: List[Device]) -> None:
|
||||||
|
"""Сохраняет устройства для указанной подсети.
|
||||||
|
|
||||||
|
Записывает данные в JSON-файл.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
subnet (str): Подсеть в формате CIDR.
|
||||||
|
devices (List[Device]): Список устройств для сохранения.
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
Exception: Если произошла ошибка при сохранении.
|
||||||
|
"""
|
||||||
|
file_path = self.get_subnet_file(subnet)
|
||||||
try:
|
try:
|
||||||
data = SubnetScanResult(devices=devices).model_dump()
|
data = SubnetScanResult(devices=devices).model_dump()
|
||||||
with open(self.storage_file, "w", encoding="utf-8") as f:
|
with open(file_path, "w", encoding="utf-8") as f:
|
||||||
json.dump(data, f, indent=2, ensure_ascii=False)
|
json.dump(data, f, indent=2, ensure_ascii=False)
|
||||||
logger.info(f"Saved {len(devices)} devices to {self.storage_file}")
|
logger.info(f"Saved {len(devices)} devices to {file_path}")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"Error saving devices: {str(e)}")
|
logger.error(f"Error saving devices for subnet {subnet}: {str(e)}")
|
||||||
raise Exception(self.translations.gettext("Ошибка при сохранении устройств: {error}").format(error=str(e)))
|
if self.translations:
|
||||||
|
raise Exception(self.translations.gettext("Ошибка при сохранении устройств: {error}").format(error=str(e)))
|
||||||
|
else:
|
||||||
|
raise Exception(f"Ошибка при сохранении устройств: {str(e)}")
|
||||||
|
|
||||||
class SubnetService:
|
class SubnetService:
|
||||||
"""Сервис для сканирования подсетей и управления устройствами."""
|
"""Сервис для сканирования подсетей и управления устройствами.
|
||||||
def __init__(self, translations: Translations = Depends(get_translations())):
|
|
||||||
|
Объединяет функциональность сканирования, сбора информации и хранения данных.
|
||||||
|
"""
|
||||||
|
def __init__(self, translations: Translations):
|
||||||
|
"""Инициализирует сервис подсети.
|
||||||
|
|
||||||
|
Настраивает интерфейс, сканеры и хранилище с текущей локализацией.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
translations (Translations): Объект переводов для текущего языка.
|
||||||
|
"""
|
||||||
self.interface = self._get_default_interface()
|
self.interface = self._get_default_interface()
|
||||||
self.network_scanner = NetworkScanner(self.interface)
|
self.network_scanner = NetworkScanner(self.interface, translations)
|
||||||
self.port_scanner = PortScanner(self.interface)
|
self.port_scanner = PortScanner(self.interface, translations)
|
||||||
self.device_info = DeviceInfoCollector()
|
self.device_info = DeviceInfoCollector(translations)
|
||||||
self.storage = DeviceStorage()
|
self.storage = DeviceStorage(translations=translations)
|
||||||
self.translations = translations
|
self.translations = translations
|
||||||
logger.info(f"Initialized SubnetService with interface: {self.interface}")
|
logger.info(f"Initialized SubnetService with interface: {self.interface}")
|
||||||
|
|
||||||
def _get_default_interface(self) -> str:
|
def _get_default_interface(self) -> str:
|
||||||
|
"""Определяет интерфейс по умолчанию.
|
||||||
|
|
||||||
|
Использует информацию о шлюзе или первый доступный интерфейс.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
str: Имя интерфейса (например, "wlp0s20f3" или "eth0").
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
Exception: Если не удалось определить интерфейс.
|
||||||
|
"""
|
||||||
try:
|
try:
|
||||||
gateways = netifaces.gateways()
|
gateways = netifaces.gateways()
|
||||||
default_gateway = gateways.get("default", {}).get(netifaces.AF_INET)
|
default_gateway = gateways.get("default", {}).get(netifaces.AF_INET)
|
||||||
|
|
@ -203,7 +381,16 @@ class SubnetService:
|
||||||
return "eth0"
|
return "eth0"
|
||||||
|
|
||||||
def _get_default_subnet(self) -> str:
|
def _get_default_subnet(self) -> str:
|
||||||
"""Автоматически определяет подсеть локального устройства."""
|
"""Автоматически определяет подсеть локального устройства.
|
||||||
|
|
||||||
|
Использует информацию о текущем интерфейсе для определения подсети.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
str: Подсеть в формате CIDR (например, "10.1.1.0/24").
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
Exception: Если не удалось определить подсеть.
|
||||||
|
"""
|
||||||
try:
|
try:
|
||||||
interfaces = netifaces.interfaces()
|
interfaces = netifaces.interfaces()
|
||||||
for iface in interfaces:
|
for iface in interfaces:
|
||||||
|
|
@ -228,13 +415,18 @@ class SubnetService:
|
||||||
def scan_subnet(self, subnet: Optional[str] = None) -> SubnetScanResult:
|
def scan_subnet(self, subnet: Optional[str] = None) -> SubnetScanResult:
|
||||||
"""Сканирует указанную подсеть и возвращает результаты.
|
"""Сканирует указанную подсеть и возвращает результаты.
|
||||||
|
|
||||||
|
Выполняет ARP-сканирование, собирает информацию о устройствах и сохраняет данные.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
subnet (Optional[str]): Подсеть в формате CIDR (например, "10.1.1.0/24").
|
subnet (Optional[str]): Подсеть в формате CIDR (например, "10.1.1.0/24").
|
||||||
Если None или пустая строка, определяется автоматически.
|
Если None или пустая строка, определяется автоматически.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
SubnetScanResult: Объект с результатами сканирования, содержащий список
|
SubnetScanResult: Объект с результатами сканирования, содержащий список
|
||||||
устройств.
|
устройств или сообщение об ошибке.
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
Exception: Если произошла ошибка сканирования.
|
||||||
"""
|
"""
|
||||||
start_time = time.time()
|
start_time = time.time()
|
||||||
devices = []
|
devices = []
|
||||||
|
|
@ -246,9 +438,9 @@ class SubnetService:
|
||||||
subnet = self._get_default_subnet()
|
subnet = self._get_default_subnet()
|
||||||
if subnet == "0.0.0.0/0":
|
if subnet == "0.0.0.0/0":
|
||||||
logger.warning("Default subnet is invalid, scan aborted")
|
logger.warning("Default subnet is invalid, scan aborted")
|
||||||
return SubnetScanResult(devices=devices)
|
return SubnetScanResult(devices=devices, error=self.translations.gettext("Недопустимая подсеть по умолчанию"))
|
||||||
|
|
||||||
saved_devices = self.storage.load_devices()
|
saved_devices = self.storage.load_devices(subnet)
|
||||||
|
|
||||||
local_device = self._get_local_device(subnet)
|
local_device = self._get_local_device(subnet)
|
||||||
if local_device:
|
if local_device:
|
||||||
|
|
@ -264,6 +456,10 @@ class SubnetService:
|
||||||
logger.info(f"Discovered devices: {len(discovered_devices)}")
|
logger.info(f"Discovered devices: {len(discovered_devices)}")
|
||||||
self.device_info.scan_nbtscan(subnet)
|
self.device_info.scan_nbtscan(subnet)
|
||||||
|
|
||||||
|
if not discovered_devices and not local_device:
|
||||||
|
logger.warning(f"No devices found in subnet {subnet}")
|
||||||
|
return SubnetScanResult(devices=[], error=self.translations.gettext("В данной подсети не обнаружено устройств"))
|
||||||
|
|
||||||
def process_device(ip_mac: Tuple[str, str]) -> Optional[Device]:
|
def process_device(ip_mac: Tuple[str, str]) -> Optional[Device]:
|
||||||
ip, mac = ip_mac
|
ip, mac = ip_mac
|
||||||
if local_device and ip == local_device.ip:
|
if local_device and ip == local_device.ip:
|
||||||
|
|
@ -309,7 +505,7 @@ class SubnetService:
|
||||||
for device in devices:
|
for device in devices:
|
||||||
if device.mac:
|
if device.mac:
|
||||||
saved_devices[device.mac] = device
|
saved_devices[device.mac] = device
|
||||||
self.storage.save_devices(list(saved_devices.values()))
|
self.storage.save_devices(subnet, list(saved_devices.values()))
|
||||||
|
|
||||||
logger.info(
|
logger.info(
|
||||||
f"Subnet scan {subnet} completed in {time.time() - start_time:.2f} seconds, "
|
f"Subnet scan {subnet} completed in {time.time() - start_time:.2f} seconds, "
|
||||||
|
|
@ -319,9 +515,19 @@ class SubnetService:
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"Error scanning subnet {subnet}: {str(e)}")
|
logger.error(f"Error scanning subnet {subnet}: {str(e)}")
|
||||||
return SubnetScanResult(devices=devices)
|
return SubnetScanResult(devices=devices, error=self.translations.gettext("Ошибка сканирования: {error}").format(error=str(e)))
|
||||||
|
|
||||||
def _get_local_device(self, subnet: str) -> Optional[Device]:
|
def _get_local_device(self, subnet: str) -> Optional[Device]:
|
||||||
|
"""Определяет локальное устройство в указанной подсети.
|
||||||
|
|
||||||
|
Использует информацию об интерфейсе для обнаружения.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
subnet (str): Подсеть в формате CIDR.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Optional[Device]: Объект устройства или None, если не найдено.
|
||||||
|
"""
|
||||||
now = datetime.now().astimezone()
|
now = datetime.now().astimezone()
|
||||||
formatted_now = now.strftime("%d-%m-%Y, %H:%M")
|
formatted_now = now.strftime("%d-%m-%Y, %H:%M")
|
||||||
try:
|
try:
|
||||||
|
|
@ -354,53 +560,115 @@ class SubnetService:
|
||||||
logger.warning(f"Failed to get local device: {str(e)}")
|
logger.warning(f"Failed to get local device: {str(e)}")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def add_note(self, mac: str, note: str) -> Tuple[bool, Optional[str]]:
|
def add_note(self, mac: str, note: str, translations: Translations) -> Tuple[bool, Optional[Tuple[str, Dict]]]:
|
||||||
|
"""Добавляет заметку для устройства по MAC-адресу.
|
||||||
|
|
||||||
|
Привязывает заметку к устройству, если оно существует.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
mac (str): MAC-адрес устройства.
|
||||||
|
note (str): Текст заметки.
|
||||||
|
translations (Translations): Объект переводов для текущего языка.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Tuple[bool, Optional[Tuple[str, Dict]]]: Кортеж (успех, результат),
|
||||||
|
где результат содержит код ошибки/успеха и данные.
|
||||||
|
"""
|
||||||
try:
|
try:
|
||||||
saved_devices = self.storage.load_devices()
|
saved_devices = {}
|
||||||
|
for subnet in self.storage.base_path.glob("*.json"):
|
||||||
|
devices = self.storage.load_devices(subnet.stem.replace("_", "/"))
|
||||||
|
saved_devices.update(devices)
|
||||||
if mac not in saved_devices:
|
if mac not in saved_devices:
|
||||||
logger.warning(f"Device with MAC {mac} not found")
|
logger.warning(f"Device with MAC {mac} not found")
|
||||||
return False, self.translations.gettext("Устройство с MAC {mac} не найдено").format(mac=mac)
|
return False, ("not_found", {"mac": mac})
|
||||||
if saved_devices[mac].note is not None:
|
if saved_devices[mac].note is not None:
|
||||||
logger.error(f"Note for device with MAC {mac} already exists")
|
logger.error(f"Note for device with MAC {mac} already exists")
|
||||||
return False, self.translations.gettext("Заметка для устройства с MAC {mac} уже существует").format(mac=mac)
|
return False, ("note_exists", {"mac": mac})
|
||||||
saved_devices[mac].note = note
|
for subnet_file in self.storage.base_path.glob("*.json"):
|
||||||
self.storage.save_devices(list(saved_devices.values()))
|
subnet = subnet_file.stem.replace("_", "/")
|
||||||
|
devices = self.storage.load_devices(subnet)
|
||||||
|
if mac in devices:
|
||||||
|
devices[mac].note = note
|
||||||
|
self.storage.save_devices(subnet, list(devices.values()))
|
||||||
|
break
|
||||||
logger.info(f"Added note '{note}' for device with MAC {mac}")
|
logger.info(f"Added note '{note}' for device with MAC {mac}")
|
||||||
return True, None
|
return True, ("success", {"mac": mac, "note": note})
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"Error adding note for MAC {mac}: {str(e)}")
|
logger.error(f"Error adding note for MAC {mac}: {str(e)}")
|
||||||
return False, self.translations.gettext("Внутренняя ошибка сервера: {error}").format(error=str(e))
|
return False, ("internal_error", {"error": str(e)})
|
||||||
|
|
||||||
def update_note(self, mac: str, note: str) -> Tuple[bool, Optional[str]]:
|
def update_note(self, mac: str, note: str, translations: Translations) -> Tuple[bool, Optional[Tuple[str, Dict]]]:
|
||||||
|
"""Обновляет заметку для устройства по MAC-адресу.
|
||||||
|
|
||||||
|
Изменяет существующую заметку, если она есть.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
mac (str): MAC-адрес устройства.
|
||||||
|
note (str): Новый текст заметки.
|
||||||
|
translations (Translations): Объект переводов для текущего языка.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Tuple[bool, Optional[Tuple[str, Dict]]]: Кортеж (успех, результат),
|
||||||
|
где результат содержит код ошибки/успеха и данные.
|
||||||
|
"""
|
||||||
try:
|
try:
|
||||||
saved_devices = self.storage.load_devices()
|
saved_devices = {}
|
||||||
|
for subnet in self.storage.base_path.glob("*.json"):
|
||||||
|
devices = self.storage.load_devices(subnet.stem.replace("_", "/"))
|
||||||
|
saved_devices.update(devices)
|
||||||
if mac not in saved_devices:
|
if mac not in saved_devices:
|
||||||
logger.warning(f"Device with MAC {mac} not found")
|
logger.warning(f"Device with MAC {mac} not found")
|
||||||
return False, self.translations.gettext("Устройство с MAC {mac} не найдено").format(mac=mac)
|
return False, ("not_found", {"mac": mac})
|
||||||
if saved_devices[mac].note is None:
|
if saved_devices[mac].note is None:
|
||||||
logger.error(f"Note for device with MAC {mac} does not exist")
|
logger.error(f"Note for device with MAC {mac} does not exist")
|
||||||
return False, self.translations.gettext("Заметка для устройства с MAC {mac} не существует").format(mac=mac)
|
return False, ("note_not_exists", {"mac": mac})
|
||||||
saved_devices[mac].note = note
|
for subnet_file in self.storage.base_path.glob("*.json"):
|
||||||
self.storage.save_devices(list(saved_devices.values()))
|
subnet = subnet_file.stem.replace("_", "/")
|
||||||
|
devices = self.storage.load_devices(subnet)
|
||||||
|
if mac in devices:
|
||||||
|
devices[mac].note = note
|
||||||
|
self.storage.save_devices(subnet, list(devices.values()))
|
||||||
|
break
|
||||||
logger.info(f"Updated note '{note}' for device with MAC {mac}")
|
logger.info(f"Updated note '{note}' for device with MAC {mac}")
|
||||||
return True, None
|
return True, ("success", {"mac": mac, "note": note})
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"Error updating note for MAC {mac}: {str(e)}")
|
logger.error(f"Error updating note for MAC {mac}: {str(e)}")
|
||||||
return False, self.translations.gettext("Внутренняя ошибка сервера: {error}").format(error=str(e))
|
return False, ("internal_error", {"error": str(e)})
|
||||||
|
|
||||||
def delete_note(self, mac: str) -> Tuple[bool, Optional[str]]:
|
def delete_note(self, mac: str, translations: Translations) -> Tuple[bool, Optional[Tuple[str, Dict]]]:
|
||||||
|
"""Удаляет заметку для устройства по MAC-адресу.
|
||||||
|
|
||||||
|
Удаляет привязанную заметку, если она существует.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
mac (str): MAC-адрес устройства.
|
||||||
|
translations (Translations): Объект переводов для текущего языка.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Tuple[bool, Optional[Tuple[str, Dict]]]: Кортеж (успех, результат),
|
||||||
|
где результат содержит код ошибки/успеха и данные.
|
||||||
|
"""
|
||||||
try:
|
try:
|
||||||
saved_devices = self.storage.load_devices()
|
saved_devices = {}
|
||||||
|
for subnet in self.storage.base_path.glob("*.json"):
|
||||||
|
devices = self.storage.load_devices(subnet.stem.replace("_", "/"))
|
||||||
|
saved_devices.update(devices)
|
||||||
if mac not in saved_devices:
|
if mac not in saved_devices:
|
||||||
logger.warning(f"Device with MAC {mac} not found")
|
logger.warning(f"Device with MAC {mac} not found")
|
||||||
return False, self.translations.gettext("Устройство с MAC {mac} не найдено").format(mac=mac)
|
return False, ("not_found", {"mac": mac})
|
||||||
if saved_devices[mac].note is None:
|
if saved_devices[mac].note is None:
|
||||||
logger.error(f"Note for device with MAC {mac} does not exist")
|
logger.error(f"Note for device with MAC {mac} does not exist")
|
||||||
return False, self.translations.gettext("Заметка для устройства с MAC {mac} не существует").format(mac=mac)
|
return False, ("note_not_exists", {"mac": mac})
|
||||||
saved_devices[mac].note = None
|
for subnet_file in self.storage.base_path.glob("*.json"):
|
||||||
self.storage.save_devices(list(saved_devices.values()))
|
subnet = subnet_file.stem.replace("_", "/")
|
||||||
|
devices = self.storage.load_devices(subnet)
|
||||||
|
if mac in devices:
|
||||||
|
devices[mac].note = None
|
||||||
|
self.storage.save_devices(subnet, list(devices.values()))
|
||||||
|
break
|
||||||
logger.info(f"Deleted note for device with MAC {mac}")
|
logger.info(f"Deleted note for device with MAC {mac}")
|
||||||
return True, None
|
return True, ("success", {"mac": mac})
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"Error deleting note for MAC {mac}: {str(e)}")
|
logger.error(f"Error deleting note for MAC {mac}: {str(e)}")
|
||||||
return False, self.translations.gettext("Внутренняя ошибка сервера: {error}").format(error=str(e))
|
return False, ("internal_error", {"error": str(e)})
|
||||||
Loading…
Add table
Add a link
Reference in a new issue