
Updated scripts and backend to dynamically retrieve project name and version from `pyproject.toml`. This ensures consistent metadata across the OpenAPI client generation and the FastAPI application.
166 lines
5.6 KiB
Python
166 lines
5.6 KiB
Python
# app/main.py
|
|
import sys
|
|
import os
|
|
import json
|
|
import tomllib
|
|
from pathlib import Path
|
|
from fastapi import FastAPI
|
|
from fastapi.middleware.cors import CORSMiddleware
|
|
from app import ssl_heidi
|
|
|
|
|
|
from app.routers import (
|
|
address,
|
|
contact,
|
|
proposal,
|
|
dewar,
|
|
shipment,
|
|
puck,
|
|
spreadsheet,
|
|
logistics,
|
|
auth,
|
|
sample,
|
|
)
|
|
from app.database import Base, engine, SessionLocal, load_sample_data
|
|
|
|
|
|
# Utility function to fetch metadata from pyproject.toml
|
|
def get_project_metadata():
|
|
with open("pyproject.toml", "rb") as f:
|
|
pyproject = tomllib.load(f)
|
|
name = pyproject["project"]["name"]
|
|
version = pyproject["project"]["version"]
|
|
return name, version
|
|
|
|
|
|
# Get project metadata from pyproject.toml
|
|
project_name, project_version = get_project_metadata()
|
|
app = FastAPI(
|
|
title=project_name, # Syncs with project `name`
|
|
description="Backend for next-gen sample management system",
|
|
version=project_version, # Syncs with project `version`
|
|
)
|
|
|
|
# Determine environment and configuration file path
|
|
environment = os.getenv("ENVIRONMENT", "dev")
|
|
config_file = Path(__file__).resolve().parent.parent / f"config_{environment}.json"
|
|
|
|
# Load configuration
|
|
with open(config_file) as f:
|
|
config = json.load(f)
|
|
|
|
cert_path = config["ssl_cert_path"]
|
|
key_path = config["ssl_key_path"]
|
|
|
|
# Generate SSL Key and Certificate if not exist (only for development)
|
|
if environment == "dev":
|
|
Path("ssl").mkdir(parents=True, exist_ok=True)
|
|
if not Path(cert_path).exists() or not Path(key_path).exists():
|
|
ssl_heidi.generate_self_signed_cert(cert_path, key_path)
|
|
|
|
# Apply CORS middleware
|
|
app.add_middleware(
|
|
CORSMiddleware,
|
|
allow_origins=["*"], # Enable CORS for all origins
|
|
allow_credentials=True,
|
|
allow_methods=["*"],
|
|
allow_headers=["*"],
|
|
)
|
|
|
|
|
|
@app.on_event("startup")
|
|
def on_startup():
|
|
# Drop and recreate database schema
|
|
Base.metadata.drop_all(bind=engine)
|
|
Base.metadata.create_all(bind=engine)
|
|
|
|
db = SessionLocal()
|
|
try:
|
|
load_sample_data(db)
|
|
finally:
|
|
db.close()
|
|
|
|
|
|
# Include routers with correct configuration
|
|
app.include_router(auth.router, prefix="/auth", tags=["auth"])
|
|
app.include_router(contact.router, prefix="/contacts", tags=["contacts"])
|
|
app.include_router(address.router, prefix="/addresses", tags=["addresses"])
|
|
app.include_router(proposal.router, prefix="/proposals", tags=["proposals"])
|
|
app.include_router(dewar.router, prefix="/dewars", tags=["dewars"])
|
|
app.include_router(shipment.router, prefix="/shipments", tags=["shipments"])
|
|
app.include_router(puck.router, prefix="/pucks", tags=["pucks"])
|
|
app.include_router(spreadsheet.router, tags=["spreadsheet"])
|
|
app.include_router(logistics.router, prefix="/logistics", tags=["logistics"])
|
|
app.include_router(sample.router, prefix="/samples", tags=["samples"])
|
|
|
|
|
|
if __name__ == "__main__":
|
|
import uvicorn
|
|
|
|
# Check if the user has passed "generate-openapi" as the first CLI argument
|
|
if len(sys.argv) > 1 and sys.argv[1] == "generate-openapi":
|
|
# Generate and save the OpenAPI schema
|
|
openapi_schema = app.openapi()
|
|
with open("openapi.json", "w") as openapi_file:
|
|
json.dump(openapi_schema, openapi_file, indent=2)
|
|
print("OpenAPI schema has been generated and saved to 'openapi.json'.")
|
|
else:
|
|
# Default behavior: Run the FastAPI server
|
|
import os
|
|
from multiprocessing import Process
|
|
from time import sleep
|
|
|
|
# Get environment from an environment variable
|
|
environment = os.getenv("ENVIRONMENT", "dev")
|
|
is_ci = os.getenv("CI", "false").lower() == "true" # Check if running in CI
|
|
port = int(os.getenv("PORT", 8000)) # Default to 8000 if PORT is not set
|
|
|
|
# Paths for SSL certificates
|
|
if is_ci:
|
|
cert_path = "ssl/cert.pem"
|
|
key_path = "ssl/key.pem"
|
|
host = "127.0.0.1"
|
|
print("Running in CI mode with self-signed certificates...")
|
|
# Ensure SSL certificate and key are generated
|
|
if is_ci or environment == "dev":
|
|
Path("ssl").mkdir(exist_ok=True)
|
|
|
|
if not Path(cert_path).exists() or not Path(key_path).exists():
|
|
print(
|
|
f"Generating self-signed SSL certificate"
|
|
f"at {cert_path} and {key_path}"
|
|
)
|
|
ssl_heidi.generate_self_signed_cert(cert_path, key_path)
|
|
elif environment == "test":
|
|
cert_path = "ssl/mx-aare-test.psi.ch.pem"
|
|
key_path = "ssl/mx-aare-test.psi.ch.key"
|
|
host = "0.0.0.0"
|
|
print("Using test SSL certificates...")
|
|
else:
|
|
cert_path = "ssl/cert.pem"
|
|
key_path = "ssl/key.pem"
|
|
host = "127.0.0.1"
|
|
print("Using development SSL certificates...")
|
|
|
|
def run_server():
|
|
uvicorn.run(
|
|
app,
|
|
host=host,
|
|
port=port,
|
|
log_level="debug",
|
|
ssl_keyfile=key_path,
|
|
ssl_certfile=cert_path,
|
|
)
|
|
|
|
if is_ci:
|
|
# In CI, start server in a subprocess and exit after a short delay
|
|
server_process = Process(target=run_server)
|
|
server_process.start()
|
|
sleep(5) # Wait for 5 seconds to ensure the server starts without errors
|
|
server_process.terminate() # Terminate the server process
|
|
server_process.join() # Clean up the process
|
|
print("CI: Server started successfully and exited.")
|
|
else:
|
|
# Normal behavior for running the FastAPI server
|
|
run_server()
|