from __future__ import annotations from uuid import UUID from fastapi import APIRouter, Depends, HTTPException from sqlalchemy.orm import Session from app.core.dependencies import get_current_user from app.database.session import get_db from app.models.user import User from app.models.workspace import Workspace from app.repositories.rule_repository import RuleRepository from app.schemas.rule import RuleCreate, RuleResponse, RuleUpdate router = APIRouter( prefix="/rules", tags=["Rules"], ) def _verify_workspace_access( db: Session, workspace_id: UUID, user_id: UUID, ) -> Workspace: workspace = ( db.query(Workspace) .filter( Workspace.id == workspace_id, Workspace.created_by == user_id, ) .first() ) if workspace is None: raise HTTPException( status_code=403, detail="You do not have access to this workspace.", ) return workspace @router.get("", response_model=list[RuleResponse]) def list_rules( workspace_id: UUID, current_user: User = Depends(get_current_user), db: Session = Depends(get_db), ): _verify_workspace_access(db, workspace_id, current_user.id) repo = RuleRepository(db) rules = repo.list_by_workspace(workspace_id) return [RuleResponse.from_rule(r) for r in rules] @router.post("", response_model=RuleResponse, status_code=201) def create_rule( workspace_id: UUID, payload: RuleCreate, current_user: User = Depends(get_current_user), db: Session = Depends(get_db), ): _verify_workspace_access(db, workspace_id, current_user.id) repo = RuleRepository(db) # Merge operator into configuration for storage configuration = {**payload.configuration, "operator": payload.operator} rule = repo.create( workspace_id=workspace_id, name=payload.name, description=payload.description, rule_type=payload.rule_type, configuration=configuration, enabled=payload.enabled, ) return RuleResponse.from_rule(rule) @router.get("/{rule_id}", response_model=RuleResponse) def get_rule( rule_id: UUID, current_user: User = Depends(get_current_user), db: Session = Depends(get_db), ): repo = RuleRepository(db) rule = repo.get(rule_id) if rule is None: raise HTTPException(status_code=404, detail="Rule not found.") _verify_workspace_access(db, rule.workspace_id, current_user.id) return RuleResponse.from_rule(rule) @router.patch("/{rule_id}", response_model=RuleResponse) def update_rule( rule_id: UUID, payload: RuleUpdate, current_user: User = Depends(get_current_user), db: Session = Depends(get_db), ): repo = RuleRepository(db) rule = repo.get(rule_id) if rule is None: raise HTTPException(status_code=404, detail="Rule not found.") _verify_workspace_access(db, rule.workspace_id, current_user.id) update_kwargs = {} if payload.name is not None: update_kwargs["name"] = payload.name if payload.description is not None: update_kwargs["description"] = payload.description if payload.rule_type is not None: update_kwargs["rule_type"] = payload.rule_type if payload.enabled is not None: update_kwargs["enabled"] = payload.enabled # Handle operator/configuration updates if payload.operator is not None or payload.configuration is not None: current_config = dict(rule.configuration or {}) if payload.configuration is not None: current_config.update(payload.configuration) if payload.operator is not None: current_config["operator"] = payload.operator update_kwargs["configuration"] = current_config if update_kwargs: rule = repo.update(rule, **update_kwargs) return RuleResponse.from_rule(rule) @router.post("/{rule_id}/enable", response_model=RuleResponse) def enable_rule( rule_id: UUID, current_user: User = Depends(get_current_user), db: Session = Depends(get_db), ): repo = RuleRepository(db) rule = repo.get(rule_id) if rule is None: raise HTTPException(status_code=404, detail="Rule not found.") _verify_workspace_access(db, rule.workspace_id, current_user.id) rule = repo.update(rule, enabled=True) return RuleResponse.from_rule(rule) @router.post("/{rule_id}/disable", response_model=RuleResponse) def disable_rule( rule_id: UUID, current_user: User = Depends(get_current_user), db: Session = Depends(get_db), ): repo = RuleRepository(db) rule = repo.get(rule_id) if rule is None: raise HTTPException(status_code=404, detail="Rule not found.") _verify_workspace_access(db, rule.workspace_id, current_user.id) rule = repo.update(rule, enabled=False) return RuleResponse.from_rule(rule) @router.delete("/{rule_id}", status_code=204) def delete_rule( rule_id: UUID, current_user: User = Depends(get_current_user), db: Session = Depends(get_db), ): repo = RuleRepository(db) rule = repo.get(rule_id) if rule is None: raise HTTPException(status_code=404, detail="Rule not found.") _verify_workspace_access(db, rule.workspace_id, current_user.id) repo.delete(rule)