Journaling improvements
This commit is contained in:
@@ -159,7 +159,8 @@ async def cancel_arrival(
|
||||
current_user: User = Depends(get_current_operator_user)
|
||||
):
|
||||
"""Cancel an arrival record"""
|
||||
arrival = crud_arrival.cancel(db, arrival_id=arrival_id)
|
||||
client_ip = get_client_ip(request)
|
||||
arrival = crud_arrival.cancel(db, arrival_id=arrival_id, user=current_user.username, user_ip=client_ip)
|
||||
if not arrival:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
|
||||
@@ -87,7 +87,7 @@ async def create_user(
|
||||
status_code=status.HTTP_400_BAD_REQUEST,
|
||||
detail="Username already registered"
|
||||
)
|
||||
user = crud_user.create(db, obj_in=user_in)
|
||||
user = crud_user.create(db, obj_in=user_in, admin_user=current_user.username)
|
||||
return user
|
||||
|
||||
|
||||
@@ -105,7 +105,7 @@ async def update_user(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail="User not found"
|
||||
)
|
||||
user = crud_user.update(db, db_obj=user, obj_in=user_in)
|
||||
user = crud_user.update(db, db_obj=user, obj_in=user_in, admin_user=current_user.username)
|
||||
return user
|
||||
|
||||
|
||||
@@ -123,5 +123,5 @@ async def change_user_password(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail="User not found"
|
||||
)
|
||||
user = crud_user.change_password(db, db_obj=user, new_password=password_data.password)
|
||||
user = crud_user.change_password(db, db_obj=user, new_password=password_data.password, admin_user=current_user.username)
|
||||
return user
|
||||
@@ -64,7 +64,8 @@ async def create_circuit(
|
||||
detail="Cannot provide both local_flight_id and arrival_id"
|
||||
)
|
||||
|
||||
circuit = crud_circuit.create(db, obj_in=circuit_in)
|
||||
client_ip = get_client_ip(request)
|
||||
circuit = crud_circuit.create(db, obj_in=circuit_in, user=current_user.username, user_ip=client_ip)
|
||||
|
||||
# Send real-time update via WebSocket
|
||||
if hasattr(request.app.state, 'connection_manager'):
|
||||
@@ -116,6 +117,7 @@ async def update_circuit(
|
||||
|
||||
@router.delete("/{circuit_id}")
|
||||
async def delete_circuit(
|
||||
request: Request,
|
||||
circuit_id: int,
|
||||
db: Session = Depends(get_db),
|
||||
current_user: User = Depends(get_current_operator_user)
|
||||
@@ -127,5 +129,6 @@ async def delete_circuit(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail="Circuit record not found"
|
||||
)
|
||||
crud_circuit.delete(db, circuit_id=circuit_id)
|
||||
client_ip = get_client_ip(request)
|
||||
crud_circuit.delete(db, circuit_id=circuit_id, user=current_user.username, user_ip=client_ip)
|
||||
return {"detail": "Circuit record deleted"}
|
||||
|
||||
@@ -159,7 +159,8 @@ async def cancel_departure(
|
||||
current_user: User = Depends(get_current_operator_user)
|
||||
):
|
||||
"""Cancel a departure record"""
|
||||
departure = crud_departure.cancel(db, departure_id=departure_id)
|
||||
client_ip = get_client_ip(request)
|
||||
departure = crud_departure.cancel(db, departure_id=departure_id, user=current_user.username, user_ip=client_ip)
|
||||
if not departure:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
|
||||
@@ -4,11 +4,79 @@ from app.api import deps
|
||||
from app.crud.crud_journal import journal
|
||||
from app.models.journal import EntityType
|
||||
from app.schemas.journal import JournalEntryResponse, EntityJournalResponse
|
||||
from typing import List
|
||||
from typing import List, Optional
|
||||
from datetime import datetime, date
|
||||
|
||||
router = APIRouter(tags=["journal"])
|
||||
|
||||
|
||||
@router.get("/search/all", response_model=List[JournalEntryResponse])
|
||||
async def search_journal(
|
||||
date_from: Optional[date] = None,
|
||||
date_to: Optional[date] = None,
|
||||
entity_type: Optional[str] = None,
|
||||
entity_id: Optional[int] = None,
|
||||
user: Optional[str] = None,
|
||||
limit: int = 500,
|
||||
db: Session = Depends(deps.get_db),
|
||||
current_user = Depends(deps.get_current_user)
|
||||
):
|
||||
"""
|
||||
Search journal entries with optional filters.
|
||||
|
||||
Parameters:
|
||||
- date_from: Filter entries from this date (YYYY-MM-DD)
|
||||
- date_to: Filter entries until this date (YYYY-MM-DD)
|
||||
- entity_type: Filter by entity type (PPR, LOCAL_FLIGHT, ARRIVAL, DEPARTURE, OVERFLIGHT, CIRCUIT, USER)
|
||||
- entity_id: Filter by specific entity ID
|
||||
- user: Filter by user who created the entry
|
||||
- limit: Maximum number of entries to return (default 500, max 5000)
|
||||
|
||||
All filters are optional and can be combined.
|
||||
Returns entries in reverse chronological order (newest first).
|
||||
"""
|
||||
if limit > 5000:
|
||||
limit = 5000
|
||||
|
||||
# Validate entity_type if provided
|
||||
if entity_type:
|
||||
try:
|
||||
EntityType[entity_type.upper()]
|
||||
except KeyError:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_400_BAD_REQUEST,
|
||||
detail=f"Invalid entity_type. Must be one of: {', '.join([e.value for e in EntityType])}"
|
||||
)
|
||||
|
||||
entries = journal.search_entries(
|
||||
db,
|
||||
date_from=date_from,
|
||||
date_to=date_to,
|
||||
entity_type=entity_type,
|
||||
entity_id=entity_id,
|
||||
user=user,
|
||||
limit=limit
|
||||
)
|
||||
|
||||
return entries
|
||||
|
||||
|
||||
@router.get("/user/{username}", response_model=List[JournalEntryResponse])
|
||||
async def get_user_journal(
|
||||
username: str,
|
||||
limit: int = 100,
|
||||
db: Session = Depends(deps.get_db),
|
||||
current_user = Depends(deps.get_current_user)
|
||||
):
|
||||
"""
|
||||
Get all journal entries created by a specific user.
|
||||
|
||||
This endpoint is read-only and returns entries in reverse chronological order.
|
||||
"""
|
||||
entries = journal.get_user_journal(db, username, limit=limit)
|
||||
return entries
|
||||
|
||||
|
||||
@router.get("/{entity_type}/{entity_id}", response_model=EntityJournalResponse)
|
||||
async def get_entity_journal(
|
||||
entity_type: str,
|
||||
@@ -45,19 +113,3 @@ async def get_entity_journal(
|
||||
entries=entries,
|
||||
total_entries=len(entries)
|
||||
)
|
||||
|
||||
|
||||
@router.get("/user/{username}", response_model=List[JournalEntryResponse])
|
||||
async def get_user_journal(
|
||||
username: str,
|
||||
limit: int = 100,
|
||||
db: Session = Depends(deps.get_db),
|
||||
current_user = Depends(deps.get_current_user)
|
||||
):
|
||||
"""
|
||||
Get all journal entries created by a specific user.
|
||||
|
||||
This endpoint is read-only and returns entries in reverse chronological order.
|
||||
"""
|
||||
entries = journal.get_user_journal(db, username, limit=limit)
|
||||
return entries
|
||||
|
||||
@@ -160,7 +160,8 @@ async def cancel_local_flight(
|
||||
current_user: User = Depends(get_current_operator_user)
|
||||
):
|
||||
"""Cancel a local flight record"""
|
||||
flight = crud_local_flight.cancel(db, flight_id=flight_id)
|
||||
client_ip = get_client_ip(request)
|
||||
flight = crud_local_flight.cancel(db, flight_id=flight_id, user=current_user.username, user_ip=client_ip)
|
||||
if not flight:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
|
||||
@@ -56,7 +56,7 @@ async def public_book_local_flight(
|
||||
notes=flight_in.notes,
|
||||
)
|
||||
|
||||
flight = crud_local_flight.create(db, obj_in=flight_create, created_by="PUBLIC_PILOT", submitted_via="PUBLIC")
|
||||
flight = crud_local_flight.create(db, obj_in=flight_create, created_by="PUBLIC_PILOT", submitted_via="PUBLIC", user_ip=request.client.host if request.client else None)
|
||||
|
||||
# Update with submission source and pilot email
|
||||
db.query(type(flight)).filter(type(flight).id == flight.id).update({
|
||||
@@ -98,7 +98,7 @@ async def public_record_circuit(
|
||||
circuit_timestamp=circuit_in.circuit_timestamp,
|
||||
)
|
||||
|
||||
circuit = crud_circuit.create(db, obj_in=circuit_create)
|
||||
circuit = crud_circuit.create(db, obj_in=circuit_create, user="PUBLIC_PILOT", user_ip=request.client.host if request.client else None)
|
||||
|
||||
# Send real-time update via WebSocket
|
||||
if hasattr(request.app.state, 'connection_manager'):
|
||||
@@ -136,7 +136,7 @@ async def public_book_departure(
|
||||
notes=departure_in.notes,
|
||||
)
|
||||
|
||||
departure = crud_departure.create(db, obj_in=departure_create, created_by="PUBLIC_PILOT", submitted_via="PUBLIC")
|
||||
departure = crud_departure.create(db, obj_in=departure_create, created_by="PUBLIC_PILOT", submitted_via="PUBLIC", user_ip=request.client.host if request.client else None)
|
||||
|
||||
# Update with pilot email (submitted_via is already set in create method)
|
||||
db.query(type(departure)).filter(type(departure).id == departure.id).update({
|
||||
@@ -181,7 +181,7 @@ async def public_book_arrival(
|
||||
notes=arrival_in.notes,
|
||||
)
|
||||
|
||||
arrival = crud_arrival.create(db, obj_in=arrival_create, created_by="PUBLIC_PILOT", submitted_via="PUBLIC")
|
||||
arrival = crud_arrival.create(db, obj_in=arrival_create, created_by="PUBLIC_PILOT", submitted_via="PUBLIC", user_ip=request.client.host if request.client else None)
|
||||
|
||||
# Update with pilot email
|
||||
db.query(type(arrival)).filter(type(arrival).id == arrival.id).update({
|
||||
|
||||
Reference in New Issue
Block a user