FastAPI + PostgreSQL 16. KYC, issue sistemi, permission/group yönetimi, session yönetimi, API client auth (kışla kapısı), officials/persons CRUD. Migration 0001–0013 dahil.
50 lines
1.7 KiB
Python
50 lines
1.7 KiB
Python
import hashlib
|
||
import secrets
|
||
from psycopg import AsyncConnection
|
||
|
||
|
||
def _hash_secret(secret: str) -> str:
|
||
return hashlib.sha256(secret.encode()).hexdigest()
|
||
|
||
|
||
def generate_secret() -> str:
|
||
return secrets.token_urlsafe(32)
|
||
|
||
|
||
async def verify_client(conn: AsyncConnection, secret: str) -> bool:
|
||
h = _hash_secret(secret)
|
||
row = await (await conn.execute(
|
||
"SELECT id FROM api_clients WHERE secret_hash = %s AND is_active = TRUE",
|
||
(h,)
|
||
)).fetchone()
|
||
return row is not None
|
||
|
||
|
||
async def create_client(conn: AsyncConnection, name: str) -> dict:
|
||
secret = generate_secret()
|
||
h = _hash_secret(secret)
|
||
row = await (await conn.execute(
|
||
"INSERT INTO api_clients (name, secret_hash) VALUES (%s, %s) RETURNING id, name, created_at",
|
||
(name, h)
|
||
)).fetchone()
|
||
await conn.commit()
|
||
# secret yalnızca bir kez döner, sonra erişilemez
|
||
return {"id": row[0], "name": row[1], "secret": secret, "created_at": row[2]}
|
||
|
||
|
||
async def list_clients(conn: AsyncConnection) -> list[dict]:
|
||
rows = await (await conn.execute(
|
||
"SELECT id, name, is_active, created_at FROM api_clients ORDER BY created_at DESC"
|
||
)).fetchall()
|
||
return [{"id": r[0], "name": r[1], "is_active": r[2], "created_at": r[3]} for r in rows]
|
||
|
||
|
||
async def set_active(conn: AsyncConnection, client_id: int, is_active: bool) -> dict:
|
||
row = await (await conn.execute(
|
||
"UPDATE api_clients SET is_active = %s WHERE id = %s RETURNING id, name, is_active, created_at",
|
||
(is_active, client_id)
|
||
)).fetchone()
|
||
if not row:
|
||
raise ValueError("Client bulunamadı")
|
||
await conn.commit()
|
||
return {"id": row[0], "name": row[1], "is_active": row[2], "created_at": row[3]}
|