İlk commit: Stepstead backend (FastAPI)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
jts 2026-07-11 11:30:24 +03:00
commit ea049b8ccd
45 changed files with 6751 additions and 0 deletions

76
deps.py Normal file
View file

@ -0,0 +1,76 @@
from typing import Annotated
from fastapi import Depends, Header, HTTPException, status
from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession
from models import Role, User, get_db
from security import decode_token
# Eski davranışla uyumluluk: bu hesaplar rol atanmasa da tam yetkili.
LEGACY_ADMIN_EMAILS = {"jts@jts.rocks", "afm@jts.rocks"}
# Panel izin kataloğu (kullanıcı yönetimi UI'ı buradan okur)
PERMISSIONS = {
"upload": "Dosya yükleme + Asset Takip",
"lore": "Lore notları (görme + ekleme + düzenleme)",
"map_view": "Harita editörünü görüntüleme (salt okunur)",
"npc": "NPC listesi (görme + ekleme + düzenleme)",
"map_edit": "Harita etiketi ekleme / düzenleme / silme",
"chars": "Karakterler (sınıf + skill tanımları)",
"users": "Kullanıcı ve rol yönetimi",
}
async def get_user_perms(user: User, db: AsyncSession) -> set[str]:
if user.email in LEGACY_ADMIN_EMAILS:
return {"*"}
if not user.role_id:
return set()
role = (await db.execute(select(Role).where(Role.id == user.role_id))).scalar_one_or_none()
return set(role.permissions or []) if role else set()
def has_perm(perms: set[str], perm: str) -> bool:
return "*" in perms or perm in perms
def require_perm(perm: str):
async def dep(
user: User = Depends(get_current_user),
db: AsyncSession = Depends(get_db),
) -> User:
perms = await get_user_perms(user, db)
if not has_perm(perms, perm):
raise HTTPException(status.HTTP_403_FORBIDDEN, "Yetkin yok")
return user
return dep
async def get_current_user(
authorization: Annotated[str | None, Header()] = None,
db: AsyncSession = Depends(get_db),
) -> User:
if not authorization or not authorization.lower().startswith("bearer "):
raise HTTPException(status.HTTP_401_UNAUTHORIZED, "Missing bearer token")
token = authorization.split(None, 1)[1].strip()
try:
payload = decode_token(token)
except Exception as e:
raise HTTPException(status.HTTP_401_UNAUTHORIZED, f"Invalid token: {e}")
user_id = int(payload["sub"])
user = (await db.execute(select(User).where(User.id == user_id))).scalar_one_or_none()
if not user or not user.is_active:
raise HTTPException(status.HTTP_401_UNAUTHORIZED, "User not found or inactive")
return user
async def require_panel(
user: User = Depends(get_current_user),
db: AsyncSession = Depends(get_db),
) -> User:
"""Herhangi bir panel yetkisi olan (bir rolü/izni bulunan) her yetkili."""
perms = await get_user_perms(user, db)
if not perms:
raise HTTPException(status.HTTP_403_FORBIDDEN, "Panel yetkin yok")
return user