""" Rules.py Contiene los endpoints de CRUD de reglas. """ import re from fastapi import APIRouter, Depends, HTTPException, Request, status from sqlalchemy.orm import Session from database import get_db import models import schemas from typing import List from datetime import datetime from auth import get_current_user from audit import log_action router = APIRouter() @router.post("/rules/", response_model=schemas.RuleResponse, tags=['Rules']) def create_rule( rule: schemas.RuleCreate, request: Request, db: Session = Depends(get_db), current_user: int = Depends(get_current_user) ): # Validar que la regex compile antes de guardar try: re.compile(rule.regex) except re.error as e: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail=f"Expresión regular inválida: {e}" ) db_rule = models.Rule(**rule.model_dump(exclude={"apply_to_history"})) db.add(db_rule) db.flush() # para tener db_rule.id antes del commit # Auditoría log_action( db=db, entity_type='rule', entity_id=db_rule.id, action='create', user_id=current_user, after=db_rule, ip_address=request.client.host ) if rule.apply_to_history: # Traer mensajes en batches para no cargar todo en memoria batch_size = 500 offset = 0 while True: messages = db.query(models.Message).offset(offset).limit(batch_size).all() if not messages: break for message in messages: try: if re.search(rule.regex, message.content, re.IGNORECASE): new_alert = models.Alert( message_id=message.id_mess_g, group_id=message.group_id, rule_id=db_rule.id, status="open", notes=f"Detected pattern: {rule.regex}", created_at=datetime.utcnow() ) db.add(new_alert) except re.error: break offset += batch_size db.commit() db.refresh(db_rule) return db_rule @router.get("/rules/", response_model=List[schemas.RuleResponse], tags=['Rules']) def read_rules( skip: int = 0, limit: int = 100, db: Session = Depends(get_db), current_user: int = Depends(get_current_user) ): return db.query(models.Rule).offset(skip).limit(limit).all() @router.get("/rules/search/", response_model=List[schemas.RuleResponse], tags=['Rules']) def search_rules( q: str, skip: int = 0, limit: int = 100, db: Session = Depends(get_db), current_user: int = Depends(get_current_user) ): return db.query(models.Rule).filter( models.Rule.description.ilike(f"%{q}%") ).offset(skip).limit(limit).all() @router.get("/rules/{rule_id}", response_model=schemas.RuleResponse, tags=['Rules']) def read_rule( rule_id: int, db: Session = Depends(get_db), current_user: int = Depends(get_current_user) ): db_rule = db.query(models.Rule).filter(models.Rule.id == rule_id).first() if not db_rule: raise HTTPException(status_code=404, detail="Rule not found") return db_rule @router.put("/rules/{rule_id}", response_model=schemas.RuleResponse, tags=['Rules']) def update_rule( rule_id: int, rule: schemas.RuleCreate, request: Request, db: Session = Depends(get_db), current_user: int = Depends(get_current_user) ): db_rule = db.query(models.Rule).filter(models.Rule.id == rule_id).first() if not db_rule: raise HTTPException(status_code=404, detail="Rule not found") # Capturar estado anterior antes de modificar before_snapshot = { 'id': db_rule.id, 'description': db_rule.description, 'regex': db_rule.regex, 'severity': db_rule.severity, 'is_active': db_rule.is_active, } for field, value in rule.model_dump().items(): setattr(db_rule, field, value) log_action( db=db, entity_type='rule', entity_id=rule_id, action='update', user_id=current_user, before=before_snapshot, after=db_rule, ip_address=request.client.host ) db.commit() db.refresh(db_rule) return db_rule @router.delete("/rules/{rule_id}", tags=['Rules']) def delete_rule( rule_id: int, request: Request, db: Session = Depends(get_db), current_user: int = Depends(get_current_user) ): db_rule = db.query(models.Rule).filter(models.Rule.id == rule_id).first() if not db_rule: raise HTTPException(status_code=404, detail="Rule not found") log_action( db=db, entity_type='rule', entity_id=rule_id, action='delete', user_id=current_user, before=db_rule, ip_address=request.client.host ) db.delete(db_rule) db.commit() return {"message": "Rule deleted successfully"}