# storage/json_storage.py import json import os import logging from passlib.context import CryptContext from typing import Optional from models.auth import UserCreate, UserResponse logging.basicConfig(level=logging.INFO) logger = logging.getLogger(__name__) class JsonStorage: """Хранилище пользователей в JSON-файле""" def __init__(self, file_path: str = "/etc/gonets/users.json"): self.file_path = file_path self.pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto") self._ensure_file_exists() def _ensure_file_exists(self): """Создаёт JSON-файл, если он не существует""" try: logger.info(f"Проверка существования файла {self.file_path}") if not os.path.exists(self.file_path): logger.info(f"Создание директории {os.path.dirname(self.file_path)}") os.makedirs(os.path.dirname(self.file_path), exist_ok=True) logger.info(f"Создание файла {self.file_path}") with open(self.file_path, "w") as f: json.dump({"users": [], "next_id": 1}, f) os.chmod(self.file_path, 0o600) logger.info(f"Создан файл {self.file_path}") else: logger.info(f"Файл {self.file_path} уже существует") except Exception as e: logger.error( f"Ошибка при создании файла {self.file_path}: {type(e).__name__} - {str(e)}" ) raise def _read_data(self) -> dict: """Читает данные из JSON-файла""" try: with open(self.file_path, "r") as f: return json.load(f) except FileNotFoundError: logger.info( f"Файл {self.file_path} не существует, возвращаем пустую структуру" ) return {"users": [], "next_id": 1} except Exception as e: logger.error( f"Ошибка при чтении файла {self.file_path}: {type(e).__name__} - {str(e)}" ) raise def _write_data(self, data: dict): """Записывает данные в JSON файл""" try: with open(self.file_path, "w") as f: json.dump(data, f, indent=2) except Exception as e: logger.error( f"Ошибка при записи файла {self.file_path}: {type(e).__name__} - {str(e)}" ) raise def create_user(self, user: UserCreate) -> UserResponse: """Создаёт нового пользователя""" try: data = self._read_data() users = data["users"] next_id = data["next_id"] if any(u["username"] == user.username for u in users): logger.error(f"Пользователь {user.username} уже существует") raise ValueError("Пользователь уже существует") password_hash = self.pwd_context.hash(user.password) new_user = { "id": next_id, "username": user.username, "password_hash": password_hash, "is_admin": user.is_admin, } users.append(new_user) data["next_id"] = next_id + 1 self._write_data(data) logger.info(f"Пользователь {user.username} успешно зарегистрирован") return UserResponse( id=new_user["id"], username=new_user["username"], is_admin=new_user["is_admin"], ) except Exception as e: logger.error( f"Ошибка при создании пользователя {user.username}: {type(e).__name__} - {str(e)}" ) raise def get_user_by_username(self, username: str) -> Optional[dict]: """Получает пользователя по имени""" try: if not os.path.exists(self.file_path): logger.info( f"Файл {self.file_path} не существует, пользователь {username} не найден" ) return None data = self._read_data() for user in data["users"]: if user["username"] == username: return user return None except Exception as e: logger.error( f"Ошибка при получении пользователя {username}: {type(e).__name__} - {str(e)}" ) raise def verify_password(self, plain_password: str, hashed_password: str) -> bool: """Проверяет пароль""" return self.pwd_context.verify(plain_password, hashed_password)