Files
TIP/app/routers/rules.py
T
2026-06-09 21:18:13 -03:00

162 lines
5.1 KiB
Python

"""
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"}