155 lines
		
	
	
		
			6.5 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			155 lines
		
	
	
		
			6.5 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
import httpx
 | 
						|
import asyncio
 | 
						|
from app.core import config
 | 
						|
from app.core.database import add_session, logout, get_session
 | 
						|
from app.core.localizer import localizer
 | 
						|
from app.core.http_client import get_client, authorized_get
 | 
						|
 | 
						|
 | 
						|
async def login(login, password):
 | 
						|
    """
 | 
						|
    Логин пользователя по логину и паролю.
 | 
						|
 | 
						|
    :param login: Логин пользователя
 | 
						|
    :param password: Пароль пользователя
 | 
						|
    :return: tuple (ok: bool, message: str)
 | 
						|
    """
 | 
						|
    url = f"{config.BASE_URL}/v1/auth/login"
 | 
						|
    try:
 | 
						|
        response = await get_client().post(url, json={"login": login, "password": password})
 | 
						|
 | 
						|
        if response.status_code == 200:
 | 
						|
            data = response.json()
 | 
						|
            if data.get("status") == "fine":
 | 
						|
                token_data = data["data"]
 | 
						|
                add_session(
 | 
						|
                    login=login,
 | 
						|
                    access_token=token_data["access_token"],
 | 
						|
                    refresh_token=token_data["refresh_token"],
 | 
						|
                    user_id=token_data.get("user_id"),
 | 
						|
                )
 | 
						|
                return True, localizer.translate("Вход выполнен успешно")
 | 
						|
            return False, data.get("detail", localizer.translate("Неизвестная ошибка"))
 | 
						|
 | 
						|
        if response.status_code == 401:
 | 
						|
            error_data = response.json()
 | 
						|
            return False, error_data.get("detail", localizer.translate("Неверный логин или пароль"))
 | 
						|
 | 
						|
        if response.status_code == 403:
 | 
						|
            error_data = response.json()
 | 
						|
            return False, error_data.get("detail", localizer.translate("Доступ запрещен"))
 | 
						|
 | 
						|
        if response.status_code == 422:
 | 
						|
            return False, localizer.translate("Некорректные входные данные")
 | 
						|
 | 
						|
        return False, f"{localizer.translate('Ошибка сервера')}: {response.status_code}"
 | 
						|
 | 
						|
    except httpx.RequestError as e:
 | 
						|
        return False, f"{localizer.translate('Сетевая ошибка')}: {e}"
 | 
						|
    except Exception as e:
 | 
						|
        return False, f"{localizer.translate('Произошла ошибка')}: {e}"
 | 
						|
 | 
						|
 | 
						|
async def register(login, password, invite=None):
 | 
						|
    """
 | 
						|
    Регистрация нового пользователя.
 | 
						|
 | 
						|
    :param login: Логин
 | 
						|
    :param password: Пароль
 | 
						|
    :param invite: Инвайт-код (опционально)
 | 
						|
    :return: tuple (ok: bool, message: str)
 | 
						|
    """
 | 
						|
    url = f"{config.BASE_URL}/v1/auth/register"
 | 
						|
    payload = {"login": login, "password": password}
 | 
						|
    if invite:
 | 
						|
        payload["invite"] = invite
 | 
						|
 | 
						|
    try:
 | 
						|
        response = await get_client().post(url, json=payload)
 | 
						|
 | 
						|
        if response.status_code == 201:
 | 
						|
            return True, localizer.translate("Регистрация прошла успешно!")
 | 
						|
 | 
						|
        error_data = response.json()
 | 
						|
        error_message = error_data.get("detail", localizer.translate("Произошла ошибка"))
 | 
						|
 | 
						|
        if response.status_code == 409:
 | 
						|
            return False, localizer.translate("Пользователь уже существует.")
 | 
						|
        if response.status_code == 400:
 | 
						|
            return False, localizer.translate("Некорректный запрос.")
 | 
						|
        if response.status_code == 403:
 | 
						|
            return False, localizer.translate("Регистрация по приглашению отключена.")
 | 
						|
        if response.status_code == 422:
 | 
						|
            return False, localizer.translate("Некорректные входные данные. Проверьте логин и пароль.")
 | 
						|
 | 
						|
        return False, f"{localizer.translate('Ошибка сервера')} ({response.status_code}): {error_message}"
 | 
						|
 | 
						|
    except httpx.RequestError as e:
 | 
						|
        return False, f"{localizer.translate('Сетевая ошибка')}: {e}"
 | 
						|
    except Exception as e:
 | 
						|
        return False, f"{localizer.translate('Произошла ошибка')}: {e}"
 | 
						|
 | 
						|
 | 
						|
async def refresh_token(access_token: str, refresh_token: str):
 | 
						|
    """
 | 
						|
    Обновление пары токенов по refresh_token.
 | 
						|
 | 
						|
    :param access_token: Текущий access token
 | 
						|
    :param refresh_token: Refresh token
 | 
						|
    :return: tuple (ok: bool, data: dict | str)
 | 
						|
    """
 | 
						|
    url = f"{config.BASE_URL}/v1/auth/token/refresh"
 | 
						|
    payload = {"access_token": access_token, "refresh_token": refresh_token}
 | 
						|
 | 
						|
    try:
 | 
						|
        response = await get_client().post(url, json=payload)
 | 
						|
 | 
						|
        if response.status_code == 200:
 | 
						|
            data = response.json()
 | 
						|
            if data.get("status") == "fine":
 | 
						|
                token_data = data["data"]
 | 
						|
                add_session(
 | 
						|
                    login=None,
 | 
						|
                    access_token=token_data["access_token"],
 | 
						|
                    refresh_token=token_data["refresh_token"],
 | 
						|
                    update_existing=True,
 | 
						|
                )
 | 
						|
                return True, token_data
 | 
						|
            return False, data.get("detail", localizer.translate("Неизвестная ошибка"))
 | 
						|
 | 
						|
        if response.status_code == 401:
 | 
						|
            return False, localizer.translate("Refresh token недействителен или истек")
 | 
						|
 | 
						|
        return False, f"{localizer.translate('Ошибка сервера')}: {response.status_code}"
 | 
						|
 | 
						|
    except httpx.RequestError as e:
 | 
						|
        return False, f"{localizer.translate('Сетевая ошибка')}: {e}"
 | 
						|
    except Exception as e:
 | 
						|
        return False, f"{localizer.translate('Произошла ошибка')}: {e}"
 | 
						|
 | 
						|
 | 
						|
async def get_user_role(access_token: str, login: str):
 | 
						|
    """
 | 
						|
    Получение роли пользователя. При 401 выполняется автообновление токена внутри authorized_get.
 | 
						|
    """
 | 
						|
    url = f"{config.BASE_URL}/v1/user/role"
 | 
						|
    headers = {"Authorization": f"Bearer {access_token}"}
 | 
						|
 | 
						|
    try:
 | 
						|
        response = await authorized_get(url, login=login, access_token=access_token, headers=headers)
 | 
						|
 | 
						|
        if response.status_code == 200:
 | 
						|
            data = response.json()
 | 
						|
            return (True, data['data']) if data.get("status") == "fine" else (False, data.get("detail", localizer.translate("Неизвестная ошибка")))
 | 
						|
 | 
						|
        if response.status_code == 401:
 | 
						|
            return False, localizer.translate("Сессия истекла, войдите снова")
 | 
						|
 | 
						|
        return False, f"{localizer.translate('Ошибка сервера')}: {response.status_code}"
 | 
						|
 | 
						|
    except httpx.RequestError as e:
 | 
						|
        return False, f"{localizer.translate('Сетевая ошибка')}: {e}"
 | 
						|
    except Exception as e:
 | 
						|
        return False, f"{localizer.translate('Произошла ошибка')}: {e}"
 | 
						|
 |