first commit

This commit is contained in:
2025-11-30 00:07:24 +01:00
commit b5e642aecb
78 changed files with 15162 additions and 0 deletions

View File

@ -0,0 +1,171 @@
"""
Token Repository - Data Access Layer for Token operations
Following Python Quick Start Guide:
- Repository layer contains ONLY database operations
- No business logic (that goes in services)
- Simple CRUD operations and queries
"""
from typing import Optional, List, Dict, Any
from datetime import datetime
from sqlalchemy import func
from app.core.database import db
from models import AuthorizationCode, AccessToken, User, Client
class TokenRepository:
"""
Token repository - handles all token database operations.
Responsibilities:
- CRUD operations for authorization codes and access tokens
- Database queries
- No business logic
"""
def __init__(self, db_session=None):
"""Initialize repository with database session."""
self.db = db_session or db.session
# Authorization Code operations
def find_auth_code_by_code(self, code: str) -> Optional[AuthorizationCode]:
"""Find authorization code by code value."""
return AuthorizationCode.query.filter_by(code=code).first()
def create_auth_code(self, auth_code: AuthorizationCode) -> AuthorizationCode:
"""
Create a new authorization code.
Args:
auth_code: AuthorizationCode object to create
Returns:
Created authorization code
"""
self.db.add(auth_code)
self.db.commit()
return auth_code
def update_auth_code(self, auth_code: AuthorizationCode) -> AuthorizationCode:
"""
Update an existing authorization code.
Args:
auth_code: AuthorizationCode object with updated fields
Returns:
Updated authorization code
"""
self.db.commit()
return auth_code
# Access Token operations
def find_access_token_by_token(self, token: str) -> Optional[AccessToken]:
"""Find access token by token value."""
return AccessToken.query.filter_by(token=token).first()
def create_access_token(self, access_token: AccessToken) -> AccessToken:
"""
Create a new access token.
Args:
access_token: AccessToken object to create
Returns:
Created access token
"""
self.db.add(access_token)
self.db.commit()
return access_token
def update_access_token(self, access_token: AccessToken) -> AccessToken:
"""
Update an existing access token.
Args:
access_token: AccessToken object with updated fields
Returns:
Updated access token
"""
self.db.commit()
return access_token
def rollback(self) -> None:
"""Rollback current transaction."""
self.db.rollback()
# Analytics operations
def get_active_tokens_by_client(self) -> List[Dict[str, Any]]:
"""
Get all active (non-expired, non-revoked) tokens grouped by client.
Returns:
List of dicts with client_id, client_name, user_id, username, email, created_at
"""
now = datetime.utcnow()
query = (
self.db.query(
AccessToken.client_id,
Client.client_name,
AccessToken.user_id,
User.username,
User.email,
AccessToken.created_at,
AccessToken.expires_at
)
.join(User, AccessToken.user_id == User.id)
.outerjoin(Client, AccessToken.client_id == Client.client_id)
.filter(AccessToken.revoked == False)
.filter(AccessToken.expires_at > now)
.order_by(Client.client_name, User.username)
)
results = []
for row in query.all():
results.append({
'client_id': row.client_id,
'client_name': row.client_name or 'Unknown Client',
'user_id': row.user_id,
'username': row.username,
'email': row.email,
'created_at': row.created_at,
'expires_at': row.expires_at
})
return results
def get_active_sessions_summary(self) -> List[Dict[str, Any]]:
"""
Get summary of active sessions grouped by client.
Returns:
List of dicts with client_id, client_name, active_users_count, total_tokens
"""
now = datetime.utcnow()
query = (
self.db.query(
AccessToken.client_id,
Client.client_name,
func.count(func.distinct(AccessToken.user_id)).label('active_users'),
func.count(AccessToken.id).label('total_tokens')
)
.outerjoin(Client, AccessToken.client_id == Client.client_id)
.filter(AccessToken.revoked == False)
.filter(AccessToken.expires_at > now)
.group_by(AccessToken.client_id, Client.client_name)
.order_by(func.count(func.distinct(AccessToken.user_id)).desc())
)
results = []
for row in query.all():
results.append({
'client_id': row.client_id or 'unknown',
'client_name': row.client_name or 'Unknown Client',
'active_users_count': row.active_users,
'total_tokens': row.total_tokens
})
return results