Core modules: - Laws: CRUD, search, AI-powered QA - Analysis: legal research and case management - Contracts: lifecycle management with templates - Signatures: electronic signature workflow Infrastructure: - FastAPI + SQLite + async SQLAlchemy - Docker deployment support - 54 unit tests passing Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
135 lines
3.8 KiB
Python
135 lines
3.8 KiB
Python
"""Analysis service for legal research."""
|
|
from typing import List, Optional
|
|
from sqlalchemy import select
|
|
from sqlalchemy.ext.asyncio import AsyncSession
|
|
|
|
from app.models.analysis import LegalAnalysis, Case, AnalysisStatus
|
|
|
|
|
|
class AnalysisService:
|
|
"""Service for legal analysis operations."""
|
|
|
|
def __init__(self, db: AsyncSession):
|
|
self.db = db
|
|
|
|
async def create_analysis(
|
|
self,
|
|
user_id: int,
|
|
title: str,
|
|
case_description: str,
|
|
legal_basis: Optional[dict] = None,
|
|
) -> LegalAnalysis:
|
|
"""Create a new legal analysis."""
|
|
analysis = LegalAnalysis(
|
|
user_id=user_id,
|
|
title=title,
|
|
case_description=case_description,
|
|
legal_basis=legal_basis,
|
|
)
|
|
self.db.add(analysis)
|
|
await self.db.flush()
|
|
await self.db.refresh(analysis)
|
|
return analysis
|
|
|
|
async def get_analysis_by_id(self, analysis_id: int) -> Optional[LegalAnalysis]:
|
|
"""Get an analysis by ID."""
|
|
result = await self.db.execute(
|
|
select(LegalAnalysis).where(LegalAnalysis.id == analysis_id)
|
|
)
|
|
return result.scalar_one_or_none()
|
|
|
|
async def get_analyses_by_user(
|
|
self,
|
|
user_id: int,
|
|
skip: int = 0,
|
|
limit: int = 20,
|
|
) -> List[LegalAnalysis]:
|
|
"""Get analyses by user ID."""
|
|
result = await self.db.execute(
|
|
select(LegalAnalysis)
|
|
.where(LegalAnalysis.user_id == user_id)
|
|
.offset(skip)
|
|
.limit(limit)
|
|
.order_by(LegalAnalysis.created_at.desc())
|
|
)
|
|
return list(result.scalars().all())
|
|
|
|
async def update_analysis(
|
|
self,
|
|
analysis_id: int,
|
|
**kwargs
|
|
) -> Optional[LegalAnalysis]:
|
|
"""Update an analysis."""
|
|
analysis = await self.get_analysis_by_id(analysis_id)
|
|
if not analysis:
|
|
return None
|
|
|
|
for key, value in kwargs.items():
|
|
if hasattr(analysis, key) and value is not None:
|
|
setattr(analysis, key, value)
|
|
|
|
await self.db.flush()
|
|
await self.db.refresh(analysis)
|
|
return analysis
|
|
|
|
async def delete_analysis(self, analysis_id: int) -> bool:
|
|
"""Delete an analysis."""
|
|
analysis = await self.get_analysis_by_id(analysis_id)
|
|
if not analysis:
|
|
return False
|
|
|
|
await self.db.delete(analysis)
|
|
await self.db.flush()
|
|
return True
|
|
|
|
|
|
class CaseService:
|
|
"""Service for case operations."""
|
|
|
|
def __init__(self, db: AsyncSession):
|
|
self.db = db
|
|
|
|
async def create_case(
|
|
self,
|
|
title: str,
|
|
case_number: Optional[str] = None,
|
|
court: Optional[str] = None,
|
|
case_type: Optional[str] = None,
|
|
**kwargs
|
|
) -> Case:
|
|
"""Create a new case."""
|
|
case = Case(
|
|
title=title,
|
|
case_number=case_number,
|
|
court=court,
|
|
case_type=case_type,
|
|
**kwargs
|
|
)
|
|
self.db.add(case)
|
|
await self.db.flush()
|
|
await self.db.refresh(case)
|
|
return case
|
|
|
|
async def get_case_by_id(self, case_id: int) -> Optional[Case]:
|
|
"""Get a case by ID."""
|
|
result = await self.db.execute(
|
|
select(Case).where(Case.id == case_id)
|
|
)
|
|
return result.scalar_one_or_none()
|
|
|
|
async def get_cases_list(
|
|
self,
|
|
skip: int = 0,
|
|
limit: int = 20,
|
|
case_type: Optional[str] = None,
|
|
) -> List[Case]:
|
|
"""Get list of cases."""
|
|
query = select(Case)
|
|
|
|
if case_type:
|
|
query = query.where(Case.case_type == case_type)
|
|
|
|
query = query.offset(skip).limit(limit).order_by(Case.created_at.desc())
|
|
result = await self.db.execute(query)
|
|
return list(result.scalars().all())
|