Разделение сканирования на разные подсети. Хранение каждой из просканированных подсетей. Исправление багов с заметками и обновленные локали
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 logging
|
||||
from typing import Optional
|
||||
from fastapi import APIRouter, HTTPException, Depends, Response, Request
|
||||
from starlette.responses import FileResponse
|
||||
from services.settings_service import SettingsService
|
||||
|
|
@ -13,12 +14,14 @@ router = APIRouter()
|
|||
settings_service = SettingsService()
|
||||
|
||||
@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.
|
||||
|
||||
Удаляет все записи об узлах подсети, оставляя файл пустым.
|
||||
|
||||
Args:
|
||||
subnet (Optional[str]): Подсеть в формате CIDR (например, "10.1.1.0/24").
|
||||
Если None, очищает все подсети.
|
||||
translations: Объект переводов для текущего языка.
|
||||
|
||||
Returns:
|
||||
|
|
@ -28,9 +31,12 @@ def clear_subnet(translations: Translations = Depends(get_translations())):
|
|||
HTTPException: Если произошла ошибка очистки (status_code=500).
|
||||
"""
|
||||
try:
|
||||
success = settings_service.clear_subnet()
|
||||
success = settings_service.clear_subnet(subnet)
|
||||
if success:
|
||||
return {"message": translations.gettext("Данные узлов подсети успешно очищены")}
|
||||
if subnet:
|
||||
return {"message": translations.gettext("Данные узлов подсети {subnet} успешно очищены").format(subnet=subnet)}
|
||||
else:
|
||||
return {"message": translations.gettext("Данные всех подсетей успешно очищены")}
|
||||
else:
|
||||
raise HTTPException(status_code=500, detail=translations.gettext("Не удалось очистить данные узлов подсети"))
|
||||
except Exception as e:
|
||||
|
|
@ -91,26 +97,28 @@ DEVICE_PATH = "storage/devices/devices.json"
|
|||
WIFI_PATH = "storage/wifi/wifi.json"
|
||||
|
||||
@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:
|
||||
subnet (str): Подсеть в формате CIDR (например, "10.1.1.0/24").
|
||||
translations: Объект переводов для текущего языка.
|
||||
|
||||
Returns:
|
||||
FileResponse: Файл devices.json для скачивания.
|
||||
FileResponse: Файл <subnet>.json для скачивания.
|
||||
|
||||
Raises:
|
||||
HTTPException: Если файл не найден (status_code=404).
|
||||
"""
|
||||
if not os.path.exists(DEVICE_PATH):
|
||||
logger.warning(f"Export file not found: {DEVICE_PATH}")
|
||||
file_path = f"storage/subnets/{subnet.replace('/', '_')}.json"
|
||||
if not os.path.exists(file_path):
|
||||
logger.warning(f"Export file not found: {file_path}")
|
||||
raise HTTPException(status_code=404, detail=translations.gettext("Файл не найден"))
|
||||
logger.info(f"Exporting file: {DEVICE_PATH}")
|
||||
logger.info(f"Exporting file: {file_path}")
|
||||
return FileResponse(
|
||||
path=DEVICE_PATH,
|
||||
filename="devices.json",
|
||||
path=file_path,
|
||||
filename=f"{subnet.replace('/', '_')}.json",
|
||||
media_type="application/json"
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ from fastapi import APIRouter, HTTPException, Body, Depends
|
|||
from models.subnet import SubnetScanResult, SubnetScanRequest
|
||||
from models.wifi import WifiScanResult
|
||||
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.connect_service import WifiConnectionService
|
||||
from utils.i18n import get_translations, _
|
||||
|
|
@ -14,15 +14,15 @@ router = APIRouter()
|
|||
logging.basicConfig(level=logging.INFO)
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@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:
|
||||
request (SubnetScanRequest): Объект с полем subnet.
|
||||
subnet_service: Сервис сканирования подсети.
|
||||
translations: Объект переводов для текущего языка.
|
||||
|
||||
Returns:
|
||||
|
|
@ -32,17 +32,16 @@ def scan_subnet(request: SubnetScanRequest = Body(...), translations: Translatio
|
|||
HTTPException: Если произошла ошибка сканирования (status_code=500).
|
||||
"""
|
||||
try:
|
||||
subnet_service = SubnetService()
|
||||
# Если subnet пустая строка, определяем автоматически
|
||||
subnet = request.subnet.strip() if request.subnet else None
|
||||
logger.info(f"Requested subnet scan for: {subnet or 'auto-detected'}")
|
||||
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'}")
|
||||
return result
|
||||
except Exception as 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)
|
||||
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)))
|
||||
|
||||
@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-адресу.
|
||||
|
|
@ -76,6 +75,7 @@ def add_note(mac: str, request: NoteRequest, translations: Translations = Depend
|
|||
Args:
|
||||
mac (str): MAC-адрес устройства.
|
||||
request (NoteRequest): Объект с полем "note" для текста заметки.
|
||||
subnet_service: Сервис сканирования подсети.
|
||||
translations: Объект переводов для текущего языка.
|
||||
|
||||
Returns:
|
||||
|
|
@ -86,13 +86,14 @@ def add_note(mac: str, request: NoteRequest, translations: Translations = Depend
|
|||
существует (status_code=400), или произошла внутренняя ошибка (status_code=500).
|
||||
"""
|
||||
try:
|
||||
subnet_service = SubnetService()
|
||||
success, error_message = subnet_service.add_note(mac, request.note)
|
||||
success, result = subnet_service.add_note(mac, request.note, translations)
|
||||
if not success:
|
||||
if "не найдено" in error_message.lower():
|
||||
raise HTTPException(status_code=404, detail=translations.gettext(error_message))
|
||||
elif "уже существует" in error_message.lower():
|
||||
raise HTTPException(status_code=400, detail=translations.gettext(error_message))
|
||||
if result[0] == "not_found":
|
||||
raise HTTPException(status_code=404, detail=translations.gettext("Устройство с MAC {mac} не найдено").format(mac=mac))
|
||||
elif result[0] == "note_exists":
|
||||
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)}
|
||||
except HTTPException as 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)))
|
||||
|
||||
@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-адресу.
|
||||
|
||||
Изменяет существующую заметку, привязанную к устройству.
|
||||
|
|
@ -108,6 +109,7 @@ def update_note(mac: str, request: NoteRequest, translations: Translations = Dep
|
|||
Args:
|
||||
mac (str): MAC-адрес устройства.
|
||||
request (NoteRequest): Объект с полем "note" для нового текста заметки.
|
||||
subnet_service: Сервис сканирования подсети.
|
||||
translations: Объект переводов для текущего языка.
|
||||
|
||||
Returns:
|
||||
|
|
@ -118,13 +120,14 @@ def update_note(mac: str, request: NoteRequest, translations: Translations = Dep
|
|||
существует (status_code=400), или произошла внутренняя ошибка (status_code=500).
|
||||
"""
|
||||
try:
|
||||
subnet_service = SubnetService()
|
||||
success, error_message = subnet_service.update_note(mac, request.note)
|
||||
success, result = subnet_service.update_note(mac, request.note, translations)
|
||||
if not success:
|
||||
if "не найдено" in error_message.lower():
|
||||
raise HTTPException(status_code=404, detail=translations.gettext(error_message))
|
||||
elif "не существует" in error_message.lower():
|
||||
raise HTTPException(status_code=400, detail=translations.gettext(error_message))
|
||||
if result[0] == "not_found":
|
||||
raise HTTPException(status_code=404, detail=translations.gettext("Устройство с MAC {mac} не найдено").format(mac=mac))
|
||||
elif result[0] == "note_not_exists":
|
||||
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)}
|
||||
except HTTPException as 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)))
|
||||
|
||||
@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-адресу.
|
||||
|
||||
Удаляет привязанную заметку для указанного устройства.
|
||||
|
||||
Args:
|
||||
mac (str): MAC-адрес устройства.
|
||||
subnet_service: Сервис сканирования подсети.
|
||||
translations: Объект переводов для текущего языка.
|
||||
|
||||
Returns:
|
||||
|
|
@ -149,13 +153,14 @@ def delete_note(mac: str, translations: Translations = Depends(get_translations(
|
|||
существует (status_code=400), или произошла внутренняя ошибка (status_code=500).
|
||||
"""
|
||||
try:
|
||||
subnet_service = SubnetService()
|
||||
success, error_message = subnet_service.delete_note(mac)
|
||||
success, result = subnet_service.delete_note(mac, translations)
|
||||
if not success:
|
||||
if "не найдено" in error_message.lower():
|
||||
raise HTTPException(status_code=404, detail=translations.gettext(error_message))
|
||||
elif "не существует" in error_message.lower():
|
||||
raise HTTPException(status_code=400, detail=translations.gettext(error_message))
|
||||
if result[0] == "not_found":
|
||||
raise HTTPException(status_code=404, detail=translations.gettext("Устройство с MAC {mac} не найдено").format(mac=mac))
|
||||
elif result[0] == "note_not_exists":
|
||||
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)}
|
||||
except HTTPException as e:
|
||||
raise e
|
||||
|
|
@ -182,12 +187,14 @@ def add_wifi_note(ssid: str, request: NoteRequest, translations: Translations =
|
|||
"""
|
||||
try:
|
||||
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 "не найдена" in error_message.lower():
|
||||
raise HTTPException(status_code=404, detail=translations.gettext(error_message))
|
||||
elif "уже существует" in error_message.lower():
|
||||
raise HTTPException(status_code=400, detail=translations.gettext(error_message))
|
||||
if result[0] == "not_found":
|
||||
raise HTTPException(status_code=404, detail=translations.gettext("Сеть с SSID {ssid} не найдена").format(ssid=ssid))
|
||||
elif result[0] == "note_exists":
|
||||
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)}
|
||||
except HTTPException as e:
|
||||
raise e
|
||||
|
|
@ -214,12 +221,14 @@ def update_wifi_note(ssid: str, request: NoteRequest, translations: Translations
|
|||
"""
|
||||
try:
|
||||
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 "не найдена" in error_message.lower():
|
||||
raise HTTPException(status_code=404, detail=translations.gettext(error_message))
|
||||
elif "не существует" in error_message.lower():
|
||||
raise HTTPException(status_code=400, detail=translations.gettext(error_message))
|
||||
if result[0] == "not_found":
|
||||
raise HTTPException(status_code=404, detail=translations.gettext("Сеть с SSID {ssid} не найдена").format(ssid=ssid))
|
||||
elif result[0] == "note_not_exists":
|
||||
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)}
|
||||
except HTTPException as e:
|
||||
raise e
|
||||
|
|
@ -245,12 +254,14 @@ def delete_wifi_note(ssid: str, translations: Translations = Depends(get_transla
|
|||
"""
|
||||
try:
|
||||
wifi_service = WifiService()
|
||||
success, error_message = wifi_service.delete_note(ssid)
|
||||
success, result = wifi_service.delete_note(ssid)
|
||||
if not success:
|
||||
if "не найдена" in error_message.lower():
|
||||
raise HTTPException(status_code=404, detail=translations.gettext(error_message))
|
||||
elif "не существует" in error_message.lower():
|
||||
raise HTTPException(status_code=400, detail=translations.gettext(error_message))
|
||||
if result[0] == "not_found":
|
||||
raise HTTPException(status_code=404, detail=translations.gettext("Сеть с SSID {ssid} не найдена").format(ssid=ssid))
|
||||
elif result[0] == "note_not_exists":
|
||||
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)}
|
||||
except HTTPException as e:
|
||||
raise e
|
||||
|
|
|
|||
Binary file not shown.
|
|
@ -7,8 +7,8 @@ msgid ""
|
|||
msgstr ""
|
||||
"Project-Id-Version: PROJECT VERSION\n"
|
||||
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
||||
"POT-Creation-Date: 2025-07-15 15:01+0500\n"
|
||||
"PO-Revision-Date: 2025-07-15 15:02+0500\n"
|
||||
"POT-Creation-Date: 2025-07-16 13:15+0500\n"
|
||||
"PO-Revision-Date: 2025-07-16 13:15+0500\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language: en\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
|
||||
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
|
||||
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
|
||||
#, python-brace-format
|
||||
|
|
@ -96,145 +96,190 @@ msgstr "Failed to update container position: {error}"
|
|||
msgid "Не удалось получить имя хоста"
|
||||
msgstr "Failed to retrieve hostname"
|
||||
|
||||
#: api/v1/settings.py:33
|
||||
msgid "Данные узлов подсети успешно очищены"
|
||||
msgstr "Subnet node data successfully cleared"
|
||||
#: api/v1/settings.py:37
|
||||
#, python-brace-format
|
||||
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 "Не удалось очистить данные узлов подсети"
|
||||
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
|
||||
msgid "Ошибка очистки: {error}"
|
||||
msgstr "Clear error: {error}"
|
||||
|
||||
#: api/v1/settings.py:58
|
||||
#: api/v1/settings.py:64
|
||||
msgid "Данные точек доступа Wi-Fi успешно очищены"
|
||||
msgstr "Wi-Fi access point data successfully cleared"
|
||||
|
||||
#: api/v1/settings.py:60
|
||||
#: api/v1/settings.py:66
|
||||
msgid "Не удалось очистить данные точек доступа Wi-Fi"
|
||||
msgstr "Failed to clear Wi-Fi access point data"
|
||||
|
||||
#: api/v1/settings.py:83
|
||||
#: api/v1/settings.py:89
|
||||
msgid "Все сетевые данные успешно очищены"
|
||||
msgstr "All network data successfully cleared"
|
||||
|
||||
#: api/v1/settings.py:85
|
||||
#: api/v1/settings.py:91
|
||||
msgid "Не удалось очистить все сетевые данные"
|
||||
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 "Файл не найден"
|
||||
msgstr "File not found"
|
||||
|
||||
#: api/v1/settings.py:158
|
||||
#: api/v1/settings.py:166
|
||||
#, python-brace-format
|
||||
msgid "Язык '{locale}' не поддерживается."
|
||||
msgstr "Language '{locale}' is not supported."
|
||||
|
||||
#: api/v1/settings.py:164
|
||||
#: api/v1/settings.py:172
|
||||
#, python-brace-format
|
||||
msgid "Язык '{locale}' не поддерживается (нет файлов переводов)."
|
||||
msgstr "Language '{locale}' is not supported (no translation files)."
|
||||
|
||||
#: api/v1/settings.py:167
|
||||
#: api/v1/settings.py:175
|
||||
#, python-brace-format
|
||||
msgid "Язык успешно установлен: {locale}"
|
||||
msgstr "Language successfully set: {locale}"
|
||||
|
||||
#: api/v1/subnet.py:45
|
||||
#: api/v1/subnet.py:44
|
||||
#, python-brace-format
|
||||
msgid "Ошибка сканирования: {error}"
|
||||
msgstr "Scan error: {error}"
|
||||
msgid "Ошибка сканирования подсети: {error}"
|
||||
msgstr "Subnet scan error: {error}"
|
||||
|
||||
#: api/v1/subnet.py:68
|
||||
#: api/v1/subnet.py:67
|
||||
#, python-brace-format
|
||||
msgid "Ошибка сканирования Wi-Fi: {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
|
||||
msgid "Заметка '{note}' добавлена для устройства {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
|
||||
msgid "Ошибка добавления заметки: {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
|
||||
msgid "Заметка '{note}' обновлена для устройства {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
|
||||
msgid "Ошибка обновления заметки: {error}"
|
||||
msgstr "Error updating note: {error}"
|
||||
|
||||
#: api/v1/subnet.py:159
|
||||
#: api/v1/subnet.py:164
|
||||
#, python-brace-format
|
||||
msgid "Заметка удалена для устройства {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
|
||||
msgid "Ошибка удаления заметки: {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
|
||||
msgid "Заметка '{note}' добавлена для сети с 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
|
||||
msgid "Заметка '{note}' обновлена для сети с SSID {ssid}"
|
||||
msgstr "Note '{note}' updated for network with SSID {ssid}"
|
||||
|
||||
#: api/v1/subnet.py:254
|
||||
#: api/v1/subnet.py:265
|
||||
#, python-brace-format
|
||||
msgid "Заметка удалена для сети с SSID {ssid}"
|
||||
msgstr "Note deleted for network with SSID {ssid}"
|
||||
|
||||
#: api/v1/subnet.py:282
|
||||
#: api/v1/subnet.py:293
|
||||
#, python-brace-format
|
||||
msgid "Успешно подключено к {ssid}"
|
||||
msgstr "Successfully connected to {ssid}"
|
||||
|
||||
#: api/v1/subnet.py:286
|
||||
#: api/v1/subnet.py:297
|
||||
#, python-brace-format
|
||||
msgid "Ошибка подключения к Wi-Fi: {error}"
|
||||
msgstr "Wi-Fi connection error: {error}"
|
||||
|
||||
#: api/v1/subnet.py:309
|
||||
#: api/v1/subnet.py:320
|
||||
#, python-brace-format
|
||||
msgid "Успешно отключено от {ssid}"
|
||||
msgstr "Successfully disconnected from {ssid}"
|
||||
|
||||
#: api/v1/subnet.py:313
|
||||
#: api/v1/subnet.py:324
|
||||
#, python-brace-format
|
||||
msgid "Ошибка отключения от Wi-Fi: {error}"
|
||||
msgstr "Wi-Fi disconnection error: {error}"
|
||||
|
||||
#: api/v1/subnet.py:337
|
||||
#: api/v1/subnet.py:348
|
||||
msgid "connected"
|
||||
msgstr "connected"
|
||||
|
||||
#: api/v1/subnet.py:341
|
||||
#: api/v1/subnet.py:352
|
||||
#, python-brace-format
|
||||
msgid "Ошибка проверки статуса Wi-Fi: {error}"
|
||||
msgstr "Wi-Fi status check error: {error}"
|
||||
|
||||
#: api/v1/websocket.py:145
|
||||
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
|
||||
msgid "Доступные устройства в сети:"
|
||||
msgstr "Available devices in the network:"
|
||||
msgstr "Available devices on the network:"
|
||||
|
||||
#: services/arp_service.py:103
|
||||
msgid "IP"
|
||||
|
|
@ -276,10 +321,10 @@ msgstr "Successfully logged out"
|
|||
msgid "Ошибка при выходе из системы"
|
||||
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
|
||||
msgid "Wi-Fi-интерфейс не доступен"
|
||||
msgstr "Wi-Fi interface is not available"
|
||||
msgstr "Wi-Fi interface not available"
|
||||
|
||||
#: services/connect_service.py:74
|
||||
#, 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
|
||||
#, python-brace-format
|
||||
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
|
||||
#, python-brace-format
|
||||
|
|
@ -361,52 +406,42 @@ msgstr "Failed to execute hostname command: {error}"
|
|||
msgid "Ошибка обработки вывода hostname: {error}"
|
||||
msgstr "Error processing hostname output: {error}"
|
||||
|
||||
#: services/settings_service.py:37
|
||||
#: services/settings_service.py:55
|
||||
#, python-brace-format
|
||||
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
|
||||
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
|
||||
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
|
||||
msgid "Неизвестный"
|
||||
msgstr "Unknown"
|
||||
|
||||
#: services/subnet_service.py:179
|
||||
#: services/subnet_service.py:185
|
||||
#, python-brace-format
|
||||
msgid "Ошибка при сохранении устройств: {error}"
|
||||
msgstr "Error saving devices: {error}"
|
||||
|
||||
#: services/subnet_service.py:374 services/subnet_service.py:391
|
||||
#: services/subnet_service.py:408
|
||||
#, python-brace-format
|
||||
msgid "Устройство с MAC {mac} не найдено"
|
||||
msgstr "Device with MAC {mac} not found"
|
||||
#: services/subnet_service.py:268
|
||||
msgid "Недопустимая подсеть по умолчанию"
|
||||
msgstr "Invalid default subnet"
|
||||
|
||||
#: services/subnet_service.py:377
|
||||
#, python-brace-format
|
||||
msgid "Заметка для устройства с MAC {mac} уже существует"
|
||||
msgstr "Note for device with MAC {mac} already exists"
|
||||
#: services/subnet_service.py:288
|
||||
msgid "В данной подсети не обнаружено устройств"
|
||||
msgstr "No devices found in this subnet"
|
||||
|
||||
#: services/subnet_service.py:384 services/subnet_service.py:401
|
||||
#: services/subnet_service.py:418 services/wifi_service.py:319
|
||||
#: services/wifi_service.py:337 services/wifi_service.py:355
|
||||
#: services/subnet_service.py:345
|
||||
#, python-brace-format
|
||||
msgid "Внутренняя ошибка сервера: {error}"
|
||||
msgstr "Internal server 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"
|
||||
msgid "Ошибка сканирования: {error}"
|
||||
msgstr "Scan error: {error}"
|
||||
|
||||
#: services/wifi_service.py:61
|
||||
#, python-brace-format
|
||||
|
|
@ -451,23 +486,8 @@ msgstr "5 GHz"
|
|||
|
||||
#: services/wifi_service.py:165
|
||||
msgid "Интерфейс не определён"
|
||||
msgstr "Interface not defined"
|
||||
msgstr "Interface not specified"
|
||||
|
||||
#: services/wifi_service.py:215
|
||||
msgid "Таймаут при выполнении 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 ""
|
||||
"Project-Id-Version: PROJECT VERSION\n"
|
||||
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
||||
"POT-Creation-Date: 2025-07-15 15:01+0500\n"
|
||||
"PO-Revision-Date: 2025-07-15 15:02+0500\n"
|
||||
"POT-Creation-Date: 2025-07-16 13:15+0500\n"
|
||||
"PO-Revision-Date: 2025-07-16 13:15+0500\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language: ru\n"
|
||||
"Language-Team: ru <LL@li.org>\n"
|
||||
|
|
@ -99,134 +99,179 @@ msgstr "Не удалось обновить положение контейне
|
|||
msgid "Не удалось получить имя хоста"
|
||||
msgstr "Не удалось получить имя хоста"
|
||||
|
||||
#: api/v1/settings.py:33
|
||||
msgid "Данные узлов подсети успешно очищены"
|
||||
msgstr "Данные узлов подсети успешно очищены"
|
||||
#: api/v1/settings.py:37
|
||||
#, python-brace-format
|
||||
msgid "Данные узлов подсети {subnet} успешно очищены"
|
||||
msgstr "Данные узлов подсети {subnet} успешно очищены"
|
||||
|
||||
#: api/v1/settings.py:35
|
||||
#: api/v1/settings.py:39
|
||||
msgid "Данные всех подсетей успешно очищены"
|
||||
msgstr "Данные всех подсетей успешно очищены"
|
||||
|
||||
#: api/v1/settings.py:41
|
||||
msgid "Не удалось очистить данные узлов подсети"
|
||||
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
|
||||
msgid "Ошибка очистки: {error}"
|
||||
msgstr "Ошибка очистки: {error}"
|
||||
|
||||
#: api/v1/settings.py:58
|
||||
#: api/v1/settings.py:64
|
||||
msgid "Данные точек доступа Wi-Fi успешно очищены"
|
||||
msgstr "Данные точек доступа Wi-Fi успешно очищены"
|
||||
|
||||
#: api/v1/settings.py:60
|
||||
#: api/v1/settings.py:66
|
||||
msgid "Не удалось очистить данные точек доступа Wi-Fi"
|
||||
msgstr "Не удалось очистить данные точек доступа Wi-Fi"
|
||||
|
||||
#: api/v1/settings.py:83
|
||||
#: api/v1/settings.py:89
|
||||
msgid "Все сетевые данные успешно очищены"
|
||||
msgstr "Все сетевые данные успешно очищены"
|
||||
|
||||
#: api/v1/settings.py:85
|
||||
#: api/v1/settings.py:91
|
||||
msgid "Не удалось очистить все сетевые данные"
|
||||
msgstr "Не удалось очистить все сетевые данные"
|
||||
|
||||
#: api/v1/settings.py:109 api/v1/settings.py:133
|
||||
#: api/v1/settings.py:117 api/v1/settings.py:141
|
||||
msgid "Файл не найден"
|
||||
msgstr "Файл не найден"
|
||||
|
||||
#: api/v1/settings.py:158
|
||||
#: api/v1/settings.py:166
|
||||
#, python-brace-format
|
||||
msgid "Язык '{locale}' не поддерживается."
|
||||
msgstr "Язык '{locale}' не поддерживается."
|
||||
|
||||
#: api/v1/settings.py:164
|
||||
#: api/v1/settings.py:172
|
||||
#, python-brace-format
|
||||
msgid "Язык '{locale}' не поддерживается (нет файлов переводов)."
|
||||
msgstr "Язык '{locale}' не поддерживается (нет файлов переводов)."
|
||||
|
||||
#: api/v1/settings.py:167
|
||||
#: api/v1/settings.py:175
|
||||
#, python-brace-format
|
||||
msgid "Язык успешно установлен: {locale}"
|
||||
msgstr "Язык успешно установлен: {locale}"
|
||||
|
||||
#: api/v1/subnet.py:45
|
||||
#: api/v1/subnet.py:44
|
||||
#, python-brace-format
|
||||
msgid "Ошибка сканирования: {error}"
|
||||
msgstr "Ошибка сканирования: {error}"
|
||||
msgid "Ошибка сканирования подсети: {error}"
|
||||
msgstr "Ошибка сканирования подсети: {error}"
|
||||
|
||||
#: api/v1/subnet.py:68
|
||||
#: api/v1/subnet.py:67
|
||||
#, python-brace-format
|
||||
msgid "Ошибка сканирования 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
|
||||
msgid "Заметка '{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
|
||||
msgid "Ошибка добавления заметки: {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
|
||||
msgid "Заметка '{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
|
||||
msgid "Ошибка обновления заметки: {error}"
|
||||
msgstr "Ошибка обновления заметки: {error}"
|
||||
|
||||
#: api/v1/subnet.py:159
|
||||
#: api/v1/subnet.py:164
|
||||
#, python-brace-format
|
||||
msgid "Заметка удалена для устройства {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
|
||||
msgid "Ошибка удаления заметки: {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
|
||||
msgid "Заметка '{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
|
||||
msgid "Заметка '{note}' обновлена для сети с SSID {ssid}"
|
||||
msgstr "Заметка '{note}' обновлена для сети с SSID {ssid}"
|
||||
|
||||
#: api/v1/subnet.py:254
|
||||
#: api/v1/subnet.py:265
|
||||
#, python-brace-format
|
||||
msgid "Заметка удалена для сети с SSID {ssid}"
|
||||
msgstr "Заметка удалена для сети с SSID {ssid}"
|
||||
|
||||
#: api/v1/subnet.py:282
|
||||
#: api/v1/subnet.py:293
|
||||
#, python-brace-format
|
||||
msgid "Успешно подключено к {ssid}"
|
||||
msgstr "Успешно подключено к {ssid}"
|
||||
|
||||
#: api/v1/subnet.py:286
|
||||
#: api/v1/subnet.py:297
|
||||
#, python-brace-format
|
||||
msgid "Ошибка подключения к Wi-Fi: {error}"
|
||||
msgstr "Ошибка подключения к Wi-Fi: {error}"
|
||||
|
||||
#: api/v1/subnet.py:309
|
||||
#: api/v1/subnet.py:320
|
||||
#, python-brace-format
|
||||
msgid "Успешно отключено от {ssid}"
|
||||
msgstr "Успешно отключено от {ssid}"
|
||||
|
||||
#: api/v1/subnet.py:313
|
||||
#: api/v1/subnet.py:324
|
||||
#, python-brace-format
|
||||
msgid "Ошибка отключения от Wi-Fi: {error}"
|
||||
msgstr "Ошибка отключения от Wi-Fi: {error}"
|
||||
|
||||
#: api/v1/subnet.py:337
|
||||
#: api/v1/subnet.py:348
|
||||
msgid "connected"
|
||||
msgstr "connected"
|
||||
|
||||
#: api/v1/subnet.py:341
|
||||
#: api/v1/subnet.py:352
|
||||
#, python-brace-format
|
||||
msgid "Ошибка проверки статуса Wi-Fi: {error}"
|
||||
msgstr "Ошибка проверки статуса Wi-Fi: {error}"
|
||||
|
|
@ -366,17 +411,17 @@ msgstr "Не удалось выполнить команду hostname: {error}"
|
|||
msgid "Ошибка обработки вывода hostname: {error}"
|
||||
msgstr "Ошибка обработки вывода hostname: {error}"
|
||||
|
||||
#: services/settings_service.py:37
|
||||
#: services/settings_service.py:55
|
||||
#, python-brace-format
|
||||
msgid "Ошибка очистки узлов подсети: {error}"
|
||||
msgstr "Ошибка очистки узлов подсети: {error}"
|
||||
|
||||
#: services/settings_service.py:58
|
||||
#: services/settings_service.py:76
|
||||
#, python-brace-format
|
||||
msgid "Ошибка очистки точек доступа Wi-Fi: {error}"
|
||||
msgstr "Ошибка очистки точек доступа Wi-Fi: {error}"
|
||||
|
||||
#: services/settings_service.py:84
|
||||
#: services/settings_service.py:104
|
||||
#, python-brace-format
|
||||
msgid "Ошибка очистки всех сетевых данных: {error}"
|
||||
msgstr "Ошибка очистки всех сетевых данных: {error}"
|
||||
|
|
@ -385,33 +430,23 @@ msgstr "Ошибка очистки всех сетевых данных: {error
|
|||
msgid "Неизвестный"
|
||||
msgstr "Неизвестный"
|
||||
|
||||
#: services/subnet_service.py:179
|
||||
#: services/subnet_service.py:185
|
||||
#, python-brace-format
|
||||
msgid "Ошибка при сохранении устройств: {error}"
|
||||
msgstr "Ошибка при сохранении устройств: {error}"
|
||||
|
||||
#: services/subnet_service.py:374 services/subnet_service.py:391
|
||||
#: services/subnet_service.py:408
|
||||
#, python-brace-format
|
||||
msgid "Устройство с MAC {mac} не найдено"
|
||||
msgstr "Устройство с MAC {mac} не найдено"
|
||||
#: services/subnet_service.py:268
|
||||
msgid "Недопустимая подсеть по умолчанию"
|
||||
msgstr "Недопустимая подсеть по умолчанию"
|
||||
|
||||
#: services/subnet_service.py:377
|
||||
#, python-brace-format
|
||||
msgid "Заметка для устройства с MAC {mac} уже существует"
|
||||
msgstr "Заметка для устройства с MAC {mac} уже существует"
|
||||
#: services/subnet_service.py:288
|
||||
msgid "В данной подсети не обнаружено устройств"
|
||||
msgstr "В данной подсети не обнаружено устройств"
|
||||
|
||||
#: services/subnet_service.py:384 services/subnet_service.py:401
|
||||
#: services/subnet_service.py:418 services/wifi_service.py:319
|
||||
#: services/wifi_service.py:337 services/wifi_service.py:355
|
||||
#: services/subnet_service.py:345
|
||||
#, python-brace-format
|
||||
msgid "Внутренняя ошибка сервера: {error}"
|
||||
msgstr "Внутренняя ошибка сервера: {error}"
|
||||
|
||||
#: services/subnet_service.py:394 services/subnet_service.py:411
|
||||
#, python-brace-format
|
||||
msgid "Заметка для устройства с MAC {mac} не существует"
|
||||
msgstr "Заметка для устройства с MAC {mac} не существует"
|
||||
msgid "Ошибка сканирования: {error}"
|
||||
msgstr "Ошибка сканирования: {error}"
|
||||
|
||||
#: services/wifi_service.py:61
|
||||
#, python-brace-format
|
||||
|
|
@ -461,18 +496,3 @@ msgstr "Интерфейс не определён"
|
|||
#: services/wifi_service.py:215
|
||||
msgid "Таймаут при выполнении 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 typing import Optional, List
|
||||
|
||||
|
||||
class Device(BaseModel):
|
||||
"""
|
||||
Сканируемое устройство в подсети
|
||||
|
|
@ -26,17 +25,17 @@ class Device(BaseModel):
|
|||
last_seen: Optional[str] = None
|
||||
note: Optional[str] = None
|
||||
|
||||
|
||||
class SubnetScanResult(BaseModel):
|
||||
"""
|
||||
Результат сканирования устройств в подсети
|
||||
|
||||
Атрибуты:
|
||||
devices (List[Device]): Список просканированных устройств
|
||||
error (Optional[str]): Сообщение об ошибке, если сканирование не удалось
|
||||
"""
|
||||
|
||||
devices: List[Device] = []
|
||||
|
||||
error: Optional[str] = None
|
||||
|
||||
class SubnetScanRequest(BaseModel):
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -1,8 +1,11 @@
|
|||
import json
|
||||
import logging
|
||||
from utils.i18n import get_translations, _
|
||||
from typing import Optional
|
||||
|
||||
from utils.i18n import get_translations
|
||||
from babel.support import Translations
|
||||
from fastapi import Depends
|
||||
from pathlib import Path
|
||||
|
||||
logging.basicConfig(level=logging.INFO)
|
||||
logger = logging.getLogger(__name__)
|
||||
|
|
@ -11,12 +14,16 @@ class SettingsService:
|
|||
"""Сервис для управления настройками и очистки данных сети."""
|
||||
|
||||
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.translations = translations
|
||||
|
||||
def clear_subnet(self) -> bool:
|
||||
"""Очищает данные узлов подсети в файле devices.json.
|
||||
def clear_subnet(self, subnet: Optional[str] = None) -> bool:
|
||||
"""Очищает данные узлов подсети в указанном файле или во всех файлах.
|
||||
|
||||
Args:
|
||||
subnet (Optional[str]): Подсеть в формате CIDR (например, "10.1.1.0/24").
|
||||
Если None, очищает все подсети.
|
||||
|
||||
Returns:
|
||||
bool: True, если очистка успешна.
|
||||
|
|
@ -25,12 +32,23 @@ class SettingsService:
|
|||
Exception: Если произошла ошибка при записи в файл.
|
||||
"""
|
||||
try:
|
||||
with open(self.subnet_file, "w") as f:
|
||||
json.dump([], f)
|
||||
logger.info("Subnet nodes data successfully cleared")
|
||||
return True
|
||||
if subnet:
|
||||
file_path = Path(self.subnet_base_path) / f"{subnet.replace('/', '_')}.json"
|
||||
if file_path.exists():
|
||||
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:
|
||||
logger.info("Devices file not found, clearing considered successful")
|
||||
logger.info("No subnet files found, clearing considered successful")
|
||||
return True
|
||||
except Exception as 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)))
|
||||
|
||||
def clear_all_data(self) -> bool:
|
||||
"""Очищает данные узлов подсети и точек доступа Wi-Fi в обоих файлах.
|
||||
"""Очищает данные узлов всех подсетей и точек доступа Wi-Fi.
|
||||
|
||||
Returns:
|
||||
bool: True, если очистка успешна.
|
||||
|
|
@ -68,10 +86,12 @@ class SettingsService:
|
|||
"""
|
||||
try:
|
||||
try:
|
||||
with open(self.subnet_file, "w") as f:
|
||||
json.dump([], f)
|
||||
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}")
|
||||
except FileNotFoundError:
|
||||
logger.info("Devices file not found, clearing considered successful")
|
||||
logger.info("No subnet files found, clearing considered successful")
|
||||
try:
|
||||
with open(self.wifi_file, "w") as f:
|
||||
json.dump([], f)
|
||||
|
|
|
|||
|
|
@ -27,14 +27,53 @@ logging.basicConfig(
|
|||
)
|
||||
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:
|
||||
"""Класс для сканирования подсети с использованием ARP-запросов."""
|
||||
def __init__(self, interface: str, translations: Translations = Depends(get_translations())):
|
||||
"""Класс для сканирования подсети с использованием ARP-запросов.
|
||||
|
||||
Выполняет отправку ARP-запросов для обнаружения устройств в указанной подсети.
|
||||
"""
|
||||
def __init__(self, interface: str, translations: Translations):
|
||||
"""Инициализирует сканер сети.
|
||||
|
||||
Устанавливает интерфейс для сканирования и объект переводов.
|
||||
|
||||
Args:
|
||||
interface (str): Имя сетевого интерфейса (например, "wlp0s20f3").
|
||||
translations (Translations): Объект переводов для текущего языка.
|
||||
"""
|
||||
self.interface = interface
|
||||
conf.iface = interface
|
||||
self.translations = translations
|
||||
|
||||
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:
|
||||
arp = ARP(pdst=subnet)
|
||||
ether = Ether(dst="ff:ff:ff:ff:ff:ff")
|
||||
|
|
@ -46,17 +85,48 @@ class NetworkScanner:
|
|||
return []
|
||||
|
||||
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.translations = translations
|
||||
|
||||
def scan(self, ip: str) -> List[str]:
|
||||
"""Сканирует открытые порты на указанном IP-адресе.
|
||||
|
||||
Пока возвращает пустой список, так как функциональность не реализована.
|
||||
|
||||
Args:
|
||||
ip (str): IP-адрес устройства для сканирования.
|
||||
|
||||
Returns:
|
||||
List[str]: Список открытых портов (пока пустой).
|
||||
"""
|
||||
return []
|
||||
|
||||
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.nbtscan_cache = {}
|
||||
self.nbtscan_results = {}
|
||||
|
|
@ -64,6 +134,16 @@ class DeviceInfoCollector:
|
|||
|
||||
@lru_cache(maxsize=1000)
|
||||
def get_vendor(self, mac: str) -> str:
|
||||
"""Получает вендора устройства по MAC-адресу.
|
||||
|
||||
Использует кэширование для повышения производительности.
|
||||
|
||||
Args:
|
||||
mac (str): MAC-адрес устройства.
|
||||
|
||||
Returns:
|
||||
str: Название вендора или "Неизвестный" в случае ошибки.
|
||||
"""
|
||||
try:
|
||||
return self.mac_lookup.lookup(mac)
|
||||
except Exception as e:
|
||||
|
|
@ -71,6 +151,13 @@ class DeviceInfoCollector:
|
|||
return self.translations.gettext("Неизвестный")
|
||||
|
||||
def scan_nbtscan(self, subnet: str) -> None:
|
||||
"""Сканирует подсеть с помощью nbtscan для получения хостнеймов.
|
||||
|
||||
Сохраняет результаты в кэш и логирует процесс.
|
||||
|
||||
Args:
|
||||
subnet (str): Подсеть в формате CIDR.
|
||||
"""
|
||||
if subnet not in self.nbtscan_results:
|
||||
try:
|
||||
logger.debug(f"Starting nbtscan for subnet {subnet}")
|
||||
|
|
@ -97,6 +184,16 @@ class DeviceInfoCollector:
|
|||
logger.error(f"NetBIOS: Error for subnet {subnet}: {str(e)}")
|
||||
|
||||
def get_hostname(self, ip: str) -> Optional[str]:
|
||||
"""Получает хостнейм для указанного IP-адреса.
|
||||
|
||||
Пробует сначала DNS, затем NetBIOS.
|
||||
|
||||
Args:
|
||||
ip (str): IP-адрес устройства.
|
||||
|
||||
Returns:
|
||||
Optional[str]: Хостнейм или None, если не удалось определить.
|
||||
"""
|
||||
try:
|
||||
socket.setdefaulttimeout(2)
|
||||
return socket.gethostbyaddr(ip)[0]
|
||||
|
|
@ -114,20 +211,56 @@ class DeviceInfoCollector:
|
|||
return None
|
||||
|
||||
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:
|
||||
if self.storage_file.exists():
|
||||
with open(self.storage_file, "r", encoding="utf-8") as f:
|
||||
if file_path.exists():
|
||||
with open(file_path, "r", encoding="utf-8") as f:
|
||||
data = json.load(f)
|
||||
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 {}
|
||||
devices = {}
|
||||
for device_data in data.get("devices", []):
|
||||
|
|
@ -137,13 +270,23 @@ class DeviceStorage:
|
|||
return self._clean_old_devices(devices)
|
||||
return {}
|
||||
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 {}
|
||||
except Exception as e:
|
||||
logger.error(f"Error loading devices: {str(e)}")
|
||||
logger.error(f"Error loading devices for subnet {subnet}: {str(e)}")
|
||||
return {}
|
||||
|
||||
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()
|
||||
filtered = {}
|
||||
for mac, device in devices.items():
|
||||
|
|
@ -160,28 +303,63 @@ class DeviceStorage:
|
|||
filtered[mac] = device
|
||||
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:
|
||||
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)
|
||||
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:
|
||||
logger.error(f"Error saving devices: {str(e)}")
|
||||
raise Exception(self.translations.gettext("Ошибка при сохранении устройств: {error}").format(error=str(e)))
|
||||
logger.error(f"Error saving devices for subnet {subnet}: {str(e)}")
|
||||
if self.translations:
|
||||
raise Exception(self.translations.gettext("Ошибка при сохранении устройств: {error}").format(error=str(e)))
|
||||
else:
|
||||
raise Exception(f"Ошибка при сохранении устройств: {str(e)}")
|
||||
|
||||
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.network_scanner = NetworkScanner(self.interface)
|
||||
self.port_scanner = PortScanner(self.interface)
|
||||
self.device_info = DeviceInfoCollector()
|
||||
self.storage = DeviceStorage()
|
||||
self.network_scanner = NetworkScanner(self.interface, translations)
|
||||
self.port_scanner = PortScanner(self.interface, translations)
|
||||
self.device_info = DeviceInfoCollector(translations)
|
||||
self.storage = DeviceStorage(translations=translations)
|
||||
self.translations = translations
|
||||
logger.info(f"Initialized SubnetService with interface: {self.interface}")
|
||||
|
||||
def _get_default_interface(self) -> str:
|
||||
"""Определяет интерфейс по умолчанию.
|
||||
|
||||
Использует информацию о шлюзе или первый доступный интерфейс.
|
||||
|
||||
Returns:
|
||||
str: Имя интерфейса (например, "wlp0s20f3" или "eth0").
|
||||
|
||||
Raises:
|
||||
Exception: Если не удалось определить интерфейс.
|
||||
"""
|
||||
try:
|
||||
gateways = netifaces.gateways()
|
||||
default_gateway = gateways.get("default", {}).get(netifaces.AF_INET)
|
||||
|
|
@ -203,7 +381,16 @@ class SubnetService:
|
|||
return "eth0"
|
||||
|
||||
def _get_default_subnet(self) -> str:
|
||||
"""Автоматически определяет подсеть локального устройства."""
|
||||
"""Автоматически определяет подсеть локального устройства.
|
||||
|
||||
Использует информацию о текущем интерфейсе для определения подсети.
|
||||
|
||||
Returns:
|
||||
str: Подсеть в формате CIDR (например, "10.1.1.0/24").
|
||||
|
||||
Raises:
|
||||
Exception: Если не удалось определить подсеть.
|
||||
"""
|
||||
try:
|
||||
interfaces = netifaces.interfaces()
|
||||
for iface in interfaces:
|
||||
|
|
@ -228,13 +415,18 @@ class SubnetService:
|
|||
def scan_subnet(self, subnet: Optional[str] = None) -> SubnetScanResult:
|
||||
"""Сканирует указанную подсеть и возвращает результаты.
|
||||
|
||||
Выполняет ARP-сканирование, собирает информацию о устройствах и сохраняет данные.
|
||||
|
||||
Args:
|
||||
subnet (Optional[str]): Подсеть в формате CIDR (например, "10.1.1.0/24").
|
||||
Если None или пустая строка, определяется автоматически.
|
||||
|
||||
Returns:
|
||||
SubnetScanResult: Объект с результатами сканирования, содержащий список
|
||||
устройств.
|
||||
устройств или сообщение об ошибке.
|
||||
|
||||
Raises:
|
||||
Exception: Если произошла ошибка сканирования.
|
||||
"""
|
||||
start_time = time.time()
|
||||
devices = []
|
||||
|
|
@ -246,9 +438,9 @@ class SubnetService:
|
|||
subnet = self._get_default_subnet()
|
||||
if subnet == "0.0.0.0/0":
|
||||
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)
|
||||
if local_device:
|
||||
|
|
@ -264,6 +456,10 @@ class SubnetService:
|
|||
logger.info(f"Discovered devices: {len(discovered_devices)}")
|
||||
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]:
|
||||
ip, mac = ip_mac
|
||||
if local_device and ip == local_device.ip:
|
||||
|
|
@ -309,7 +505,7 @@ class SubnetService:
|
|||
for device in devices:
|
||||
if device.mac:
|
||||
saved_devices[device.mac] = device
|
||||
self.storage.save_devices(list(saved_devices.values()))
|
||||
self.storage.save_devices(subnet, list(saved_devices.values()))
|
||||
|
||||
logger.info(
|
||||
f"Subnet scan {subnet} completed in {time.time() - start_time:.2f} seconds, "
|
||||
|
|
@ -319,9 +515,19 @@ class SubnetService:
|
|||
|
||||
except Exception as 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]:
|
||||
"""Определяет локальное устройство в указанной подсети.
|
||||
|
||||
Использует информацию об интерфейсе для обнаружения.
|
||||
|
||||
Args:
|
||||
subnet (str): Подсеть в формате CIDR.
|
||||
|
||||
Returns:
|
||||
Optional[Device]: Объект устройства или None, если не найдено.
|
||||
"""
|
||||
now = datetime.now().astimezone()
|
||||
formatted_now = now.strftime("%d-%m-%Y, %H:%M")
|
||||
try:
|
||||
|
|
@ -354,53 +560,115 @@ class SubnetService:
|
|||
logger.warning(f"Failed to get local device: {str(e)}")
|
||||
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:
|
||||
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:
|
||||
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:
|
||||
logger.error(f"Note for device with MAC {mac} already exists")
|
||||
return False, self.translations.gettext("Заметка для устройства с MAC {mac} уже существует").format(mac=mac)
|
||||
saved_devices[mac].note = note
|
||||
self.storage.save_devices(list(saved_devices.values()))
|
||||
return False, ("note_exists", {"mac": mac})
|
||||
for subnet_file in self.storage.base_path.glob("*.json"):
|
||||
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}")
|
||||
return True, None
|
||||
return True, ("success", {"mac": mac, "note": note})
|
||||
except Exception as 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:
|
||||
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:
|
||||
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:
|
||||
logger.error(f"Note for device with MAC {mac} does not exist")
|
||||
return False, self.translations.gettext("Заметка для устройства с MAC {mac} не существует").format(mac=mac)
|
||||
saved_devices[mac].note = note
|
||||
self.storage.save_devices(list(saved_devices.values()))
|
||||
return False, ("note_not_exists", {"mac": mac})
|
||||
for subnet_file in self.storage.base_path.glob("*.json"):
|
||||
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}")
|
||||
return True, None
|
||||
return True, ("success", {"mac": mac, "note": note})
|
||||
except Exception as 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:
|
||||
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:
|
||||
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:
|
||||
logger.error(f"Note for device with MAC {mac} does not exist")
|
||||
return False, self.translations.gettext("Заметка для устройства с MAC {mac} не существует").format(mac=mac)
|
||||
saved_devices[mac].note = None
|
||||
self.storage.save_devices(list(saved_devices.values()))
|
||||
return False, ("note_not_exists", {"mac": mac})
|
||||
for subnet_file in self.storage.base_path.glob("*.json"):
|
||||
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}")
|
||||
return True, None
|
||||
return True, ("success", {"mac": mac})
|
||||
except Exception as 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