feat(api): add permission checks for analysis and sketches

This commit is contained in:
dextmorgn
2025-11-11 20:13:13 +01:00
parent 4b7f1da797
commit 3294065ee3
2 changed files with 73 additions and 17 deletions

View File

@@ -1,4 +1,5 @@
from uuid import UUID, uuid4
from app.security.permissions import check_investigation_permission
from fastapi import APIRouter, HTTPException, Depends, status
from typing import List
from datetime import datetime
@@ -29,6 +30,9 @@ def create_analysis(
db: Session = Depends(get_db),
current_user: Profile = Depends(get_current_user),
):
check_investigation_permission(
current_user.id, payload.investigation_id, actions=["create"], db=db
)
new_analysis = Analysis(
id=uuid4(),
title=payload.title,
@@ -54,11 +58,14 @@ def get_analysis_by_id(
):
analysis = (
db.query(Analysis)
.filter(Analysis.id == analysis_id, Analysis.owner_id == current_user.id)
.filter(Analysis.id == analysis_id)
.first()
)
if not analysis:
raise HTTPException(status_code=404, detail="Analysis not found")
check_investigation_permission(
current_user.id, analysis.investigation_id, actions=["read"], db=db
)
return analysis
@@ -69,12 +76,12 @@ def get_analyses_by_investigation(
db: Session = Depends(get_db),
current_user: Profile = Depends(get_current_user),
):
check_investigation_permission(
current_user.id, investigation_id, actions=["read"], db=db
)
analyses = (
db.query(Analysis)
.filter(
Analysis.investigation_id == investigation_id,
Analysis.owner_id == current_user.id,
)
.filter(Analysis.investigation_id == investigation_id)
.all()
)
return analyses
@@ -90,11 +97,14 @@ def update_analysis(
):
analysis = (
db.query(Analysis)
.filter(Analysis.id == analysis_id, Analysis.owner_id == current_user.id)
.filter(Analysis.id == analysis_id)
.first()
)
if not analysis:
raise HTTPException(status_code=404, detail="Analysis not found")
check_investigation_permission(
current_user.id, analysis.investigation_id, actions=["update"], db=db
)
if payload.title is not None:
analysis.title = payload.title
if payload.description is not None:
@@ -102,6 +112,10 @@ def update_analysis(
if payload.content is not None:
analysis.content = payload.content
if payload.investigation_id is not None:
# Check permission for the new investigation as well
check_investigation_permission(
current_user.id, payload.investigation_id, actions=["update"], db=db
)
analysis.investigation_id = payload.investigation_id
analysis.last_updated_at = datetime.utcnow()
db.commit()
@@ -118,11 +132,14 @@ def delete_analysis(
):
analysis = (
db.query(Analysis)
.filter(Analysis.id == analysis_id, Analysis.owner_id == current_user.id)
.filter(Analysis.id == analysis_id)
.first()
)
if not analysis:
raise HTTPException(status_code=404, detail="Analysis not found")
check_investigation_permission(
current_user.id, analysis.investigation_id, actions=["delete"], db=db
)
db.delete(analysis)
db.commit()
return None

View File

@@ -98,6 +98,9 @@ def get_sketch_by_id(
sketch = db.query(Sketch).filter(Sketch.id == sketch_id).first()
if not sketch:
raise HTTPException(status_code=404, detail="Sketch not found")
check_investigation_permission(
current_user.id, sketch.investigation_id, actions=["read"], db=db
)
return sketch
@@ -110,12 +113,14 @@ def update_sketch(
):
sketch = (
db.query(Sketch)
.filter(Sketch.owner_id == current_user.id)
.filter(Sketch.id == id)
.first()
)
if not sketch:
raise HTTPException(status_code=404, detail="Sketch not found")
check_investigation_permission(
current_user.id, sketch.investigation_id, actions=["update"], db=db
)
for key, value in payload.model_dump(exclude_unset=True).items():
setattr(sketch, key, value)
db.commit()
@@ -131,11 +136,14 @@ def delete_sketch(
):
sketch = (
db.query(Sketch)
.filter(Sketch.id == id, Sketch.owner_id == current_user.id)
.filter(Sketch.id == id)
.first()
)
if not sketch:
raise HTTPException(status_code=404, detail="Sketch not found")
check_investigation_permission(
current_user.id, sketch.investigation_id, actions=["delete"], db=db
)
# Delete all nodes and relationships in Neo4j first
neo4j_query = """
@@ -158,7 +166,7 @@ async def get_sketch_nodes(
id: str,
format: str = None,
db: Session = Depends(get_db),
# current_user: Profile = Depends(get_current_user)
current_user: Profile = Depends(get_current_user)
):
"""
Get the nodes and relationships for a sketch.
@@ -175,14 +183,14 @@ async def get_sketch_nodes(
"""
sketch = (
db.query(Sketch)
.filter(
Sketch.id == id,
# Sketch.owner_id == current_user.id
)
.filter(Sketch.id == id)
.first()
)
if not sketch:
raise HTTPException(status_code=404, detail="Graph not found")
check_investigation_permission(
current_user.id, sketch.investigation_id, actions=["read"], db=db
)
import random
nodes_query = """
@@ -241,6 +249,13 @@ def add_node(
db: Session = Depends(get_db),
current_user: Profile = Depends(get_current_user),
):
sketch = db.query(Sketch).filter(Sketch.id == sketch_id).first()
if not sketch:
raise HTTPException(status_code=404, detail="Sketch not found")
check_investigation_permission(
current_user.id, sketch.investigation_id, actions=["update"], db=db
)
node_data = node.data.model_dump()
node_type = node_data["type"]
@@ -308,6 +323,12 @@ def add_edge(
db: Session = Depends(get_db),
current_user: Profile = Depends(get_current_user),
):
sketch = db.query(Sketch).filter(Sketch.id == sketch_id).first()
if not sketch:
raise HTTPException(status_code=404, detail="Sketch not found")
check_investigation_permission(
current_user.id, sketch.investigation_id, actions=["update"], db=db
)
query = f"""
MATCH (a) WHERE elementId(a) = $from_id
@@ -350,6 +371,9 @@ def edit_node(
sketch = db.query(Sketch).filter(Sketch.id == sketch_id).first()
if not sketch:
raise HTTPException(status_code=404, detail="Sketch not found")
check_investigation_permission(
current_user.id, sketch.investigation_id, actions=["update"], db=db
)
node_data = node_edit.data.model_dump()
node_type = node_data.get("type", "Node")
@@ -409,6 +433,9 @@ def delete_nodes(
sketch = db.query(Sketch).filter(Sketch.id == sketch_id).first()
if not sketch:
raise HTTPException(status_code=404, detail="Sketch not found")
check_investigation_permission(
current_user.id, sketch.investigation_id, actions=["update"], db=db
)
# Delete nodes and their relationships
query = """
@@ -443,6 +470,9 @@ def merge_nodes(
sketch = db.query(Sketch).filter(Sketch.id == sketch_id).first()
if not sketch:
raise HTTPException(status_code=404, detail="Sketch not found")
check_investigation_permission(
current_user.id, sketch.investigation_id, actions=["update"], db=db
)
if not oldNodes or len(oldNodes) == 0:
raise HTTPException(status_code=400, detail="oldNodes cannot be empty")
@@ -576,9 +606,12 @@ def get_related_nodes(
current_user: Profile = Depends(get_current_user)
):
# First verify the sketch exists and belongs to the user
sketch = db.query(Sketch).filter(Sketch.id == sketch_id, Sketch.owner_id == current_user.id).first()
sketch = db.query(Sketch).filter(Sketch.id == sketch_id).first()
if not sketch:
raise HTTPException(status_code=404, detail="Sketch not found")
check_investigation_permission(
current_user.id, sketch.investigation_id, actions=["read"], db=db
)
# Query to get all direct relationships and connected nodes
# First, let's get the center node
@@ -743,11 +776,14 @@ async def analyze_import_file(
# Verify sketch exists and user has access
sketch = (
db.query(Sketch)
.filter(Sketch.id == sketch_id, Sketch.owner_id == current_user.id)
.filter(Sketch.id == sketch_id)
.first()
)
if not sketch:
raise HTTPException(status_code=404, detail="Sketch not found")
check_investigation_permission(
current_user.id, sketch.investigation_id, actions=["read"], db=db
)
# Read file content
try:
@@ -825,11 +861,14 @@ async def execute_import(
# Verify sketch exists and user has access
sketch = (
db.query(Sketch)
.filter(Sketch.id == sketch_id, Sketch.owner_id == current_user.id)
.filter(Sketch.id == sketch_id)
.first()
)
if not sketch:
raise HTTPException(status_code=404, detail="Sketch not found")
check_investigation_permission(
current_user.id, sketch.investigation_id, actions=["update"], db=db
)
# Parse entity mappings
try: