Initial YakPanel commit

This commit is contained in:
Niranjan
2026-04-07 02:04:22 +05:30
commit 2826d3e7f3
5359 changed files with 1390724 additions and 0 deletions

View File

@@ -0,0 +1,90 @@
"""YakPanel - Auth API"""
from datetime import timedelta
from fastapi import APIRouter, Depends, HTTPException
from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import select
from pydantic import BaseModel
from app.core.database import get_db
from app.core.security import verify_password, get_password_hash, create_access_token, decode_token
from app.core.config import get_settings
from app.models.user import User
router = APIRouter(prefix="/auth", tags=["auth"])
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="api/v1/auth/login")
async def get_current_user(
token: str = Depends(oauth2_scheme),
db: AsyncSession = Depends(get_db),
) -> User:
"""Get current authenticated user from JWT"""
credentials_exception = HTTPException(status_code=401, detail="Invalid credentials")
payload = decode_token(token)
if not payload:
raise credentials_exception
sub = payload.get("sub")
user_id = int(sub) if isinstance(sub, str) else sub
if not user_id:
raise credentials_exception
result = await db.execute(select(User).where(User.id == user_id))
user = result.scalar_one_or_none()
if not user:
raise credentials_exception
if not user.is_active:
raise HTTPException(status_code=400, detail="User inactive")
return user
@router.post("/login")
async def login(
form_data: OAuth2PasswordRequestForm = Depends(),
db: AsyncSession = Depends(get_db),
):
"""Login and return JWT token"""
from sqlalchemy import select
result = await db.execute(select(User).where(User.username == form_data.username))
user = result.scalar_one_or_none()
if not user or not verify_password(form_data.password, user.password):
raise HTTPException(status_code=401, detail="Incorrect username or password")
if not user.is_active:
raise HTTPException(status_code=400, detail="User inactive")
access_token = create_access_token(
data={"sub": str(user.id)},
expires_delta=timedelta(minutes=get_settings().access_token_expire_minutes),
)
return {"access_token": access_token, "token_type": "bearer", "user": {"id": user.id, "username": user.username}}
@router.post("/logout")
async def logout():
"""Logout (client should discard token)"""
return {"message": "Logged out"}
@router.get("/me")
async def get_me(current_user: User = Depends(get_current_user)):
"""Get current user info"""
return {"id": current_user.id, "username": current_user.username, "email": current_user.email, "is_superuser": current_user.is_superuser}
class ChangePasswordRequest(BaseModel):
old_password: str
new_password: str
@router.post("/change-password")
async def change_password(
body: ChangePasswordRequest,
current_user: User = Depends(get_current_user),
db: AsyncSession = Depends(get_db),
):
"""Change password"""
if not verify_password(body.old_password, current_user.password):
raise HTTPException(status_code=400, detail="Incorrect current password")
result = await db.execute(select(User).where(User.id == current_user.id))
user = result.scalar_one()
user.password = get_password_hash(body.new_password)
await db.commit()
return {"message": "Password changed"}