Email notification

This commit is contained in:
James Pattinson
2025-10-25 13:31:03 +00:00
parent 91e820b9a8
commit d5f05941c9
9 changed files with 880 additions and 3 deletions

View File

@@ -8,6 +8,8 @@ from app.crud.crud_journal import journal as crud_journal
from app.schemas.ppr import PPR, PPRCreate, PPRUpdate, PPRStatus, PPRStatusUpdate, Journal
from app.models.ppr import User
from app.core.utils import get_client_ip
from app.core.email import email_service
from app.core.config import settings
router = APIRouter()
@@ -78,6 +80,23 @@ async def create_public_ppr(
}
})
# Send email if email provided
if ppr_in.email:
await email_service.send_email(
to_email=ppr_in.email,
subject="PPR Submitted Successfully",
template_name="ppr_submitted.html",
template_vars={
"name": ppr_in.captain,
"aircraft": ppr_in.ac_reg,
"arrival_time": ppr_in.eta.strftime("%Y-%m-%d %H:%M"),
"departure_time": ppr_in.etd.strftime("%Y-%m-%d %H:%M") if ppr_in.etd else "N/A",
"purpose": ppr_in.notes or "N/A",
"public_token": ppr.public_token,
"base_url": settings.base_url
}
)
return ppr
@@ -199,6 +218,20 @@ async def update_ppr_status(
}
})
# Send email if cancelled and email provided
if status_update.status == PPRStatus.CANCELED and ppr.email:
await email_service.send_email(
to_email=ppr.email,
subject="PPR Cancelled",
template_name="ppr_cancelled.html",
template_vars={
"name": ppr.captain,
"aircraft": ppr.ac_reg,
"arrival_time": ppr.eta.strftime("%Y-%m-%d %H:%M"),
"departure_time": ppr.etd.strftime("%Y-%m-%d %H:%M") if ppr.etd else "N/A"
}
)
return ppr
@@ -231,6 +264,100 @@ async def delete_ppr(
return ppr
@router.get("/public/edit/{token}", response_model=PPR)
async def get_ppr_for_edit(
token: str,
db: Session = Depends(get_db)
):
"""Get PPR details for public editing using token"""
ppr = crud_ppr.get_by_public_token(db, token)
if not ppr:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail="Invalid or expired token"
)
# Only allow editing if not already processed
if ppr.status in [PPRStatus.CANCELED, PPRStatus.DELETED, PPRStatus.LANDED, PPRStatus.DEPARTED]:
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail="PPR cannot be edited at this stage"
)
return ppr
@router.patch("/public/edit/{token}", response_model=PPR)
async def update_ppr_public(
token: str,
ppr_in: PPRUpdate,
request: Request,
db: Session = Depends(get_db)
):
"""Update PPR publicly using token"""
ppr = crud_ppr.get_by_public_token(db, token)
if not ppr:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail="Invalid or expired token"
)
# Only allow editing if not already processed
if ppr.status in [PPRStatus.CANCELED, PPRStatus.DELETED, PPRStatus.LANDED, PPRStatus.DEPARTED]:
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail="PPR cannot be edited at this stage"
)
client_ip = get_client_ip(request)
updated_ppr = crud_ppr.update(db, db_obj=ppr, obj_in=ppr_in, user="public", user_ip=client_ip)
return updated_ppr
@router.delete("/public/cancel/{token}", response_model=PPR)
async def cancel_ppr_public(
token: str,
request: Request,
db: Session = Depends(get_db)
):
"""Cancel PPR publicly using token"""
ppr = crud_ppr.get_by_public_token(db, token)
if not ppr:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail="Invalid or expired token"
)
# Only allow canceling if not already processed
if ppr.status in [PPRStatus.CANCELED, PPRStatus.DELETED, PPRStatus.LANDED, PPRStatus.DEPARTED]:
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail="PPR cannot be cancelled at this stage"
)
client_ip = get_client_ip(request)
# Cancel by setting status to CANCELED
cancelled_ppr = crud_ppr.update_status(
db,
ppr_id=ppr.id,
status=PPRStatus.CANCELED,
user="public",
user_ip=client_ip
)
# Send cancellation email if email provided
if cancelled_ppr.email:
await email_service.send_email(
to_email=cancelled_ppr.email,
subject="PPR Cancelled",
template_name="ppr_cancelled.html",
template_vars={
"name": cancelled_ppr.captain,
"aircraft": cancelled_ppr.ac_reg,
"arrival_time": cancelled_ppr.eta.strftime("%Y-%m-%d %H:%M"),
"departure_time": cancelled_ppr.etd.strftime("%Y-%m-%d %H:%M") if cancelled_ppr.etd else "N/A"
}
)
return cancelled_ppr
@router.get("/{ppr_id}/journal", response_model=List[Journal])
async def get_ppr_journal(
ppr_id: int,