Рефакторинг. docstring
This commit is contained in:
parent
060f4de175
commit
37f9e3abfb
14 changed files with 1234 additions and 243 deletions
|
|
@ -1,4 +1,3 @@
|
|||
# storage/json_storage.py
|
||||
import json
|
||||
import os
|
||||
import logging
|
||||
|
|
@ -9,22 +8,40 @@ from models.auth import UserCreate, UserResponse
|
|||
logging.basicConfig(level=logging.INFO)
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class JsonStorage:
|
||||
"""Хранилище пользователей в JSON-файле"""
|
||||
"""Хранилище пользователей в JSON-файле.
|
||||
|
||||
Предоставляет методы для создания, чтения и проверки данных пользователей,
|
||||
используя шифрование паролей с помощью bcrypt.
|
||||
"""
|
||||
|
||||
def __init__(self, file_path: str = "/etc/gonets/users.json"):
|
||||
"""Инициализирует хранилище пользователей.
|
||||
|
||||
Args:
|
||||
file_path (str, optional): Путь к JSON-файлу для хранения данных.
|
||||
По умолчанию "/etc/gonets/users.json".
|
||||
|
||||
Создаёт объект CryptContext для хеширования паролей и проверяет/создаёт
|
||||
файл, если он отсутствует.
|
||||
"""
|
||||
self.file_path = file_path
|
||||
self.pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
|
||||
self._ensure_file_exists()
|
||||
|
||||
def _ensure_file_exists(self):
|
||||
"""Создаёт JSON-файл, если он не существует"""
|
||||
"""Создаёт JSON-файл, если он не существует.
|
||||
|
||||
Создаёт родительские директории и файл с начальной структурой данных,
|
||||
устанавливая права доступа 600.
|
||||
|
||||
Raises:
|
||||
Exception: Если произошла ошибка при создании файла или директории.
|
||||
"""
|
||||
try:
|
||||
logger.info(f"Проверка существования файла {self.file_path}")
|
||||
if not os.path.exists(self.file_path):
|
||||
logger.info(
|
||||
f"Создание директории {os.path.dirname(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:
|
||||
|
|
@ -40,7 +57,15 @@ class JsonStorage:
|
|||
raise
|
||||
|
||||
def _read_data(self) -> dict:
|
||||
"""Читает данные из JSON-файла"""
|
||||
"""Читает данные из JSON-файла.
|
||||
|
||||
Returns:
|
||||
dict: Словарь с данными пользователей и следующим ID.
|
||||
|
||||
Raises:
|
||||
FileNotFoundError: Если файл отсутствует (возвращает пустую структуру).
|
||||
Exception: Если произошла ошибка при чтении файла.
|
||||
"""
|
||||
try:
|
||||
with open(self.file_path, "r") as f:
|
||||
return json.load(f)
|
||||
|
|
@ -56,7 +81,14 @@ class JsonStorage:
|
|||
raise
|
||||
|
||||
def _write_data(self, data: dict):
|
||||
"""Записывает данные в JSON файл"""
|
||||
"""Записывает данные в JSON-файл.
|
||||
|
||||
Args:
|
||||
data (dict): Словарь с данными для записи (пользователи и next_id).
|
||||
|
||||
Raises:
|
||||
Exception: Если произошла ошибка при записи в файл.
|
||||
"""
|
||||
try:
|
||||
with open(self.file_path, "w") as f:
|
||||
json.dump(data, f, indent=2)
|
||||
|
|
@ -67,7 +99,18 @@ class JsonStorage:
|
|||
raise
|
||||
|
||||
def create_user(self, user: UserCreate) -> UserResponse:
|
||||
"""Создаёт нового пользователя"""
|
||||
"""Создаёт нового пользователя с хешированием пароля.
|
||||
|
||||
Args:
|
||||
user (UserCreate): Объект с данными нового пользователя (username, password, is_admin).
|
||||
|
||||
Returns:
|
||||
UserResponse: Объект с данными созданного пользователя (id, username, is_admin).
|
||||
|
||||
Raises:
|
||||
ValueError: Если пользователь с таким именем уже существует.
|
||||
Exception: Если произошла ошибка при записи данных.
|
||||
"""
|
||||
try:
|
||||
data = self._read_data()
|
||||
users = data["users"]
|
||||
|
|
@ -99,7 +142,17 @@ class JsonStorage:
|
|||
raise
|
||||
|
||||
def get_user_by_username(self, username: str) -> Optional[dict]:
|
||||
"""Получает пользователя по имени"""
|
||||
"""Получает данные пользователя по имени.
|
||||
|
||||
Args:
|
||||
username (str): Имя пользователя для поиска.
|
||||
|
||||
Returns:
|
||||
Optional[dict]: Словарь с данными пользователя или None, если пользователь не найден.
|
||||
|
||||
Raises:
|
||||
Exception: Если произошла ошибка при чтении файла.
|
||||
"""
|
||||
try:
|
||||
if not os.path.exists(self.file_path):
|
||||
logger.info(
|
||||
|
|
@ -117,7 +170,14 @@ class JsonStorage:
|
|||
)
|
||||
raise
|
||||
|
||||
def verify_password(self, plain_password: str,
|
||||
hashed_password: str) -> bool:
|
||||
"""Проверяет пароль"""
|
||||
return self.pwd_context.verify(plain_password, hashed_password)
|
||||
def verify_password(self, plain_password: str, hashed_password: str) -> bool:
|
||||
"""Проверяет соответствие введённого пароля хэшированному.
|
||||
|
||||
Args:
|
||||
plain_password (str): Введённый пользователем пароль.
|
||||
hashed_password (str): Хэшированный пароль из хранилища.
|
||||
|
||||
Returns:
|
||||
bool: True, если пароль верен, False в противном случае.
|
||||
"""
|
||||
return self.pwd_context.verify(plain_password, hashed_password)
|
||||
|
|
@ -1,4 +1,3 @@
|
|||
# storage/session_storage.py
|
||||
import json
|
||||
import os
|
||||
import uuid
|
||||
|
|
@ -9,19 +8,38 @@ from datetime import datetime, timedelta
|
|||
logging.basicConfig(level=logging.INFO)
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class SessionStorage:
|
||||
"""Хранилище сессий пользователей в JSON-файле.
|
||||
|
||||
Предоставляет методы для создания, получения, удаления и очистки сессий с
|
||||
учётом срока действия.
|
||||
"""
|
||||
|
||||
def __init__(self, file_path: str = "/etc/gonets/sessions.json"):
|
||||
"""Инициализирует хранилище сессий.
|
||||
|
||||
Args:
|
||||
file_path (str, optional): Путь к JSON-файлу для хранения сессий.
|
||||
По умолчанию "/etc/gonets/sessions.json".
|
||||
|
||||
Создаёт файл и директории, если они отсутствуют, с правами доступа 600.
|
||||
"""
|
||||
self.file_path = file_path
|
||||
self._ensure_file_exists()
|
||||
|
||||
def _ensure_file_exists(self):
|
||||
"""Создаёт JSON-файл, если он не существует.
|
||||
|
||||
Создаёт родительские директории и файл с начальной структурой данных,
|
||||
устанавливая права доступа 600.
|
||||
|
||||
Raises:
|
||||
Exception: Если произошла ошибка при создании файла или директории.
|
||||
"""
|
||||
try:
|
||||
logger.info(f"Проверка существования файла {self.file_path}")
|
||||
if not os.path.exists(self.file_path):
|
||||
logger.info(
|
||||
f"Создание директории {os.path.dirname(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:
|
||||
|
|
@ -37,6 +55,14 @@ class SessionStorage:
|
|||
raise
|
||||
|
||||
def _read_data(self) -> Dict:
|
||||
"""Читает данные из JSON-файла.
|
||||
|
||||
Returns:
|
||||
Dict: Словарь с данными сессий.
|
||||
|
||||
Raises:
|
||||
Exception: Если произошла ошибка при чтении файла.
|
||||
"""
|
||||
try:
|
||||
with open(self.file_path, "r") as f:
|
||||
return json.load(f)
|
||||
|
|
@ -47,6 +73,14 @@ class SessionStorage:
|
|||
raise
|
||||
|
||||
def _write_data(self, data: Dict):
|
||||
"""Записывает данные в JSON-файл.
|
||||
|
||||
Args:
|
||||
data (Dict): Словарь с данными сессий для записи.
|
||||
|
||||
Raises:
|
||||
Exception: Если произошла ошибка при записи в файл.
|
||||
"""
|
||||
try:
|
||||
with open(self.file_path, "w") as f:
|
||||
json.dump(data, f, indent=2)
|
||||
|
|
@ -57,7 +91,23 @@ class SessionStorage:
|
|||
raise
|
||||
|
||||
def create_session(self, username: str, token: str, client_id: str) -> str:
|
||||
"""Создаёт новую сессию и возвращает session_id"""
|
||||
"""Создаёт новую сессию и возвращает уникальный session_id.
|
||||
|
||||
Args:
|
||||
username (str): Имя пользователя, для которого создаётся сессия.
|
||||
token (str): Токен аутентификации.
|
||||
client_id (str): Идентификатор клиента.
|
||||
|
||||
Returns:
|
||||
str: Уникальный идентификатор сессии (session_id).
|
||||
|
||||
Raises:
|
||||
Exception: Если произошла ошибка при создании или записи сессии.
|
||||
|
||||
Note:
|
||||
Удаляет истекшие сессии перед созданием новой и устанавливает срок
|
||||
действия 30 минут.
|
||||
"""
|
||||
try:
|
||||
self.clean_expired_sessions()
|
||||
data = self._read_data()
|
||||
|
|
@ -83,7 +133,22 @@ class SessionStorage:
|
|||
raise
|
||||
|
||||
def get_latest_session(self, client_id: str) -> Optional[Dict]:
|
||||
"""Получает последнюю активную сессию для client_id"""
|
||||
"""Получает последнюю активную сессию для указанного client_id.
|
||||
|
||||
Args:
|
||||
client_id (str): Идентификатор клиента.
|
||||
|
||||
Returns:
|
||||
Optional[Dict]: Словарь с данными последней активной сессии, включая
|
||||
"session_id", или None, если сессия не найдена.
|
||||
|
||||
Raises:
|
||||
Exception: Если произошла ошибка при чтении или обработке данных.
|
||||
|
||||
Note:
|
||||
Очищает истекшие сессии перед поиском и возвращает сессию с самым
|
||||
поздним временем создания.
|
||||
"""
|
||||
try:
|
||||
self.clean_expired_sessions()
|
||||
data = self._read_data()
|
||||
|
|
@ -114,7 +179,17 @@ class SessionStorage:
|
|||
raise
|
||||
|
||||
def delete_session(self, session_id: str):
|
||||
"""Удаляет сессию по session_id"""
|
||||
"""Удаляет сессию по указанному session_id.
|
||||
|
||||
Args:
|
||||
session_id (str): Уникальный идентификатор сессии.
|
||||
|
||||
Raises:
|
||||
Exception: Если произошла ошибка при чтении или записи данных.
|
||||
|
||||
Note:
|
||||
Очищает истекшие сессии перед удалением.
|
||||
"""
|
||||
try:
|
||||
self.clean_expired_sessions()
|
||||
data = self._read_data()
|
||||
|
|
@ -129,25 +204,30 @@ class SessionStorage:
|
|||
raise
|
||||
|
||||
def clean_expired_sessions(self):
|
||||
"""Удаляет все истекшие сессии из хранилища"""
|
||||
"""Удаляет все истекшие сессии из хранилища.
|
||||
|
||||
Raises:
|
||||
Exception: Если произошла ошибка при чтении или записи данных.
|
||||
|
||||
Note:
|
||||
Проверяет срок действия каждой сессии и удаляет те, что истекли,
|
||||
записывая обновлённые данные.
|
||||
"""
|
||||
try:
|
||||
data = self._read_data()
|
||||
expired_sessions = []
|
||||
current_time = datetime.utcnow()
|
||||
|
||||
# Находим истекшие сессии
|
||||
for session_id, session in list(data["sessions"].items()):
|
||||
expiry = datetime.fromisoformat(session["expiry"])
|
||||
if current_time > expiry:
|
||||
expired_sessions.append(session_id)
|
||||
|
||||
# Удаляем истекшие сессии
|
||||
for session_id in expired_sessions:
|
||||
del data["sessions"][session_id]
|
||||
logger.info(
|
||||
f"Удалена истекшая сессия с session_id {session_id}")
|
||||
|
||||
# Записываем обновлённые данные
|
||||
if expired_sessions:
|
||||
self._write_data(data)
|
||||
logger.info(f"Удалено {len(expired_sessions)} истекших сессий")
|
||||
|
|
@ -158,4 +238,4 @@ class SessionStorage:
|
|||
logger.error(
|
||||
f"Ошибка при очистке истекших сессий: {type(e).__name__} - {str(e)}"
|
||||
)
|
||||
raise
|
||||
raise
|
||||
Loading…
Add table
Add a link
Reference in a new issue