feat: Add database migrations and auth system
- Add Alembic for database migrations - Implement user authentication system - Update frontend styles and components - Add new test audio functionality - Update stream management and UI
This commit is contained in:
106
auth_router.py
Normal file
106
auth_router.py
Normal file
@ -0,0 +1,106 @@
|
||||
"""Authentication routes for dicta2stream"""
|
||||
from fastapi import APIRouter, Depends, Request, Response, HTTPException, status
|
||||
from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
|
||||
from sqlmodel import Session
|
||||
|
||||
from models import Session as DBSession, User
|
||||
from database import get_db
|
||||
from auth import get_current_user
|
||||
|
||||
router = APIRouter()
|
||||
security = HTTPBearer()
|
||||
|
||||
@router.post("/logout")
|
||||
async def logout(
|
||||
request: Request,
|
||||
response: Response,
|
||||
db: Session = Depends(get_db),
|
||||
credentials: HTTPAuthorizationCredentials = Depends(security)
|
||||
):
|
||||
"""Log out by invalidating the current session"""
|
||||
token = credentials.credentials
|
||||
|
||||
# Find and invalidate the session
|
||||
session = db.exec(
|
||||
select(DBSession)
|
||||
.where(DBSession.token == token)
|
||||
.where(DBSession.is_active == True) # noqa: E712
|
||||
).first()
|
||||
|
||||
if session:
|
||||
session.is_active = False
|
||||
db.add(session)
|
||||
db.commit()
|
||||
|
||||
# Clear the session cookie
|
||||
response.delete_cookie(
|
||||
key="sessionid", # Must match the cookie name in main.py
|
||||
httponly=True,
|
||||
secure=True, # Must match the cookie settings from login
|
||||
samesite="lax",
|
||||
path="/"
|
||||
)
|
||||
|
||||
return {"message": "Successfully logged out"}
|
||||
|
||||
|
||||
@router.get("/me")
|
||||
async def get_current_user_info(
|
||||
current_user: User = Depends(get_current_user),
|
||||
db: Session = Depends(get_db)
|
||||
):
|
||||
"""Get current user information"""
|
||||
return {
|
||||
"username": current_user.username,
|
||||
"email": current_user.email,
|
||||
"created_at": current_user.token_created.isoformat(),
|
||||
"is_confirmed": current_user.confirmed
|
||||
}
|
||||
|
||||
|
||||
@router.get("/sessions")
|
||||
async def list_sessions(
|
||||
current_user: User = Depends(get_current_user),
|
||||
db: Session = Depends(get_db)
|
||||
):
|
||||
"""List all active sessions for the current user"""
|
||||
sessions = DBSession.get_active_sessions(db, current_user.username)
|
||||
return [
|
||||
{
|
||||
"id": s.id,
|
||||
"ip_address": s.ip_address,
|
||||
"user_agent": s.user_agent,
|
||||
"created_at": s.created_at.isoformat(),
|
||||
"last_used_at": s.last_used_at.isoformat(),
|
||||
"expires_at": s.expires_at.isoformat()
|
||||
}
|
||||
for s in sessions
|
||||
]
|
||||
|
||||
|
||||
@router.post("/sessions/{session_id}/revoke")
|
||||
async def revoke_session(
|
||||
session_id: int,
|
||||
current_user: User = Depends(get_current_user),
|
||||
db: Session = Depends(get_db)
|
||||
):
|
||||
"""Revoke a specific session"""
|
||||
session = db.get(DBSession, session_id)
|
||||
|
||||
if not session or session.user_id != current_user.username:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail="Session not found"
|
||||
)
|
||||
|
||||
if not session.is_active:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_400_BAD_REQUEST,
|
||||
detail="Session is already inactive"
|
||||
)
|
||||
|
||||
session.is_active = False
|
||||
db.add(session)
|
||||
db.commit()
|
||||
|
||||
return {"message": "Session revoked"}
|
Reference in New Issue
Block a user