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,11 @@
"""
Repositories package - Data Access Layer
Repositories handle ALL database operations. They provide a clean
interface for services to work with data without knowing SQL/ORM details.
"""
from app.repositories.user_repository import UserRepository
from app.repositories.client_repository import ClientRepository
from app.repositories.token_repository import TokenRepository
__all__ = ['UserRepository', 'ClientRepository', 'TokenRepository']

View File

@ -0,0 +1,79 @@
"""
Client Repository - Data Access Layer for Client 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
from app.core.database import db
from models import Client
class ClientRepository:
"""
Client repository - handles all Client database operations.
Responsibilities:
- CRUD operations
- Database queries
- No business logic
"""
def __init__(self, db_session=None):
"""Initialize repository with database session."""
self.db = db_session or db.session
def find_by_id(self, client_id_pk: int) -> Optional[Client]:
"""Find client by primary key ID."""
return Client.query.get(client_id_pk)
def find_by_client_id(self, client_id: str) -> Optional[Client]:
"""Find client by client_id (OIDC identifier)."""
return Client.query.filter_by(client_id=client_id).first()
def find_all(self) -> List[Client]:
"""Find all clients."""
return Client.query.all()
def create(self, client: Client) -> Client:
"""
Create a new client.
Args:
client: Client object to create
Returns:
Created client with ID
"""
self.db.add(client)
self.db.commit()
return client
def update(self, client: Client) -> Client:
"""
Update an existing client.
Args:
client: Client object with updated fields
Returns:
Updated client
"""
self.db.commit()
return client
def delete(self, client: Client) -> None:
"""
Delete a client.
Args:
client: Client object to delete
"""
self.db.delete(client)
self.db.commit()
def rollback(self) -> None:
"""Rollback current transaction."""
self.db.rollback()

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

View File

@ -0,0 +1,108 @@
"""
User Repository - Data Access Layer for User 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 app.core.database import db
from models import User
class UserRepository:
"""
User repository - handles all User database operations.
Responsibilities:
- CRUD operations
- Database queries
- No business logic
"""
def __init__(self, db_session=None):
"""Initialize repository with database session."""
self.db = db_session or db.session
def find_by_id(self, user_id: int) -> Optional[User]:
"""Find user by ID."""
return User.query.get(user_id)
def find_by_username(self, username: str) -> Optional[User]:
"""Find user by username."""
return User.query.filter_by(username=username).first()
def find_by_email(self, email: str) -> Optional[User]:
"""Find user by email."""
return User.query.filter_by(email=email).first()
def find_all(self, page: int = 1, per_page: int = 50) -> Any:
"""
Find all users with pagination.
Returns:
Pagination object with users
"""
return User.query.order_by(User.id.desc()).paginate(
page=page,
per_page=per_page,
error_out=False
)
def count_all(self) -> int:
"""Count total users."""
return User.query.count()
def count_active(self) -> int:
"""Count active users."""
return User.query.filter_by(is_active=True).count()
def count_inactive(self) -> int:
"""Count inactive users."""
return User.query.filter_by(is_active=False).count()
def count_admins(self) -> int:
"""Count admin users."""
return User.query.filter_by(is_admin=True).count()
def create(self, user: User) -> User:
"""
Create a new user.
Args:
user: User object to create
Returns:
Created user with ID
"""
self.db.add(user)
self.db.commit()
return user
def update(self, user: User) -> User:
"""
Update an existing user.
Args:
user: User object with updated fields
Returns:
Updated user
"""
self.db.commit()
return user
def delete(self, user: User) -> None:
"""
Delete a user.
Args:
user: User object to delete
"""
self.db.delete(user)
self.db.commit()
def rollback(self) -> None:
"""Rollback current transaction."""
self.db.rollback()