Files
api-copp/web/info.py
2026-03-31 13:25:14 +05:00

137 lines
5.3 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import os
import secrets
import httpx
import flet as ft
API_URL = os.getenv("API_URL", "http://api:8000")
_TOKEN_KEY = "auth_token"
class AuthService:
"""Сервис авторизации: логин, логаут, проверка токена."""
def __init__(self, page: ft.Page):
self._page = page
async def login(self, username: str, password: str) -> str | None:
"""
Отправляет запрос на POST /auth/login.
Возвращает None при успехе, строку с ошибкой при неудаче.
"""
try:
async with httpx.AsyncClient(base_url=API_URL, timeout=10) as client:
resp = await client.post(
"/auth/login",
data={"username": username, "password": password},
)
if resp.status_code == 200:
token = resp.json()["access_token"]
self._page.session.store.set(_TOKEN_KEY, token)
# Случайный ключ для URL профиля — хранится только в памяти сессии
self._page.session.store.set("session_key", secrets.token_hex(16))
# user_id Для фетчинга данных
me = await self._get_me(token)
if me:
self._page.session.store.set("user_id", me["id"])
return None
elif resp.status_code == 401:
return "Неверный логин или пароль"
else:
return f"Ошибка сервера: {resp.status_code}"
except httpx.ConnectError:
return "Не удалось подключиться к серверу"
except Exception as e:
return f"Ошибка: {e}"
async def _get_me(self, token: str) -> dict | None:
"""Внутренний метод: получает данные текущего пользователя по токену."""
try:
async with httpx.AsyncClient(base_url=API_URL, timeout=10) as client:
resp = await client.get(
"/users/me",
headers={"Authorization": f"Bearer {token}"},
)
if resp.status_code == 200:
return resp.json()
except Exception:
pass
return None
async def get_me(self) -> dict | None:
"""Возвращает данные текущего пользователя или None."""
token = self._page.session.store.get(_TOKEN_KEY)
if not token:
return None
return await self._get_me(token)
async def logout(self):
"""Удаляет токен — пользователь разлогинен."""
self._page.session.store.remove(_TOKEN_KEY)
self._page.session.store.remove("user_id")
self._page.session.store.remove("session_key")
async def get_token(self) -> str | None:
"""Возвращает сохранённый токен или None если не авторизован."""
return self._page.session.store.get(_TOKEN_KEY)
async def is_authenticated(self) -> bool:
token = await self.get_token()
return token is not None and token != ""
async def register(
self,
username: str,
password: str,
first_name: str,
last_name: str,
group_id: str | None = None,
organization_id: str | None = None,
) -> str | None:
"""
Отправляет запрос на POST /auth/register.
Возвращает None при успехе, строку с ошибкой при неудаче.
"""
payload = {
"username": username,
"password": password,
"first_name": first_name,
"last_name": last_name,
}
if group_id:
payload["group_id"] = group_id
if organization_id:
payload["organization_id"] = organization_id
try:
async with httpx.AsyncClient(base_url=API_URL, timeout=10) as client:
resp = await client.post("/auth/register", json=payload)
if resp.status_code == 201:
return None
elif resp.status_code == 400:
return resp.json().get("detail", "Ошибка регистрации")
else:
return f"Ошибка сервера: {resp.status_code}"
except httpx.ConnectError:
return "Не удалось подключиться к серверу"
except Exception as e:
return f"Ошибка: {e}"
async def get_organizations(self) -> list:
try:
async with httpx.AsyncClient(base_url=API_URL, timeout=10) as client:
resp = await client.get("/organizations/")
if resp.status_code == 200:
return resp.json()
except Exception:
pass
return []
async def get_groups(self) -> list:
try:
async with httpx.AsyncClient(base_url=API_URL, timeout=10) as client:
resp = await client.get("/groups/")
if resp.status_code == 200:
return resp.json()
except Exception:
pass
return []