"""Review service: HITL approval/rejection flow.""" from sqlalchemy.orm import Session from typing import List, Optional from datetime import datetime from app.models.review import Review from app.models.task import Task from app.schemas.review import ReviewCreate, ReviewDecision class ReviewService: @staticmethod def list_reviews( db: Session, tenant_id: int, status: Optional[str] = None, project_id: Optional[int] = None, skip: int = 0, limit: int = 100, ) -> List[Review]: q = db.query(Review).filter(Review.tenant_id == tenant_id) if status: q = q.filter(Review.status == status) if project_id: q = q.filter(Review.project_id == project_id) return q.order_by(Review.created_at.desc()).offset(skip).limit(limit).all() @staticmethod def get_review(db: Session, tenant_id: int, review_id: int) -> Optional[Review]: return ( db.query(Review) .filter(Review.id == review_id, Review.tenant_id == tenant_id) .first() ) @staticmethod def create_review( db: Session, tenant_id: int, req: ReviewCreate ) -> Review: review = Review( tenant_id=tenant_id, task_id=req.task_id, project_id=req.project_id, review_type=req.review_type, status="pending", review_content=req.review_content, auto_check_result=req.auto_check_result, submitted_at=datetime.utcnow(), ) db.add(review) db.commit() db.refresh(review) return review @staticmethod def make_decision( db: Session, tenant_id: int, review_id: int, reviewer_id: int, reviewer_role: str, req: ReviewDecision, ) -> Review: review = ReviewService.get_review(db, tenant_id, review_id) if not review: raise ValueError(f"Review #{review_id} not found") if review.status != "pending": raise ValueError(f"Review already {review.status}") review.status = req.status review.reviewer_id = reviewer_id review.reviewer_role = reviewer_role review.reviewer_comment = req.comment review.reviewed_at = datetime.utcnow() # Update task status task = ( db.query(Task) .filter(Task.id == review.task_id, Task.tenant_id == tenant_id) .first() ) if task: if req.status == "approved": task.status = "done" task.completed_at = datetime.utcnow() task.review_status = "approved" else: task.status = "rejected" task.review_status = "rejected" db.commit() db.refresh(review) return review