Initial commit: NextGen PPR System
- FastAPI backend with JWT authentication - MySQL database with full schema - Docker Compose orchestration - CSV data import for 43,208 airports and 519,999 aircraft - Complete PPR management API - Modernized replacement for PHP-based system
This commit is contained in:
1
backend/app/core/__init__.py
Normal file
1
backend/app/core/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
# Empty __init__.py files to make Python packages
|
||||
43
backend/app/core/config.py
Normal file
43
backend/app/core/config.py
Normal file
@@ -0,0 +1,43 @@
|
||||
from pydantic_settings import BaseSettings
|
||||
from typing import Optional
|
||||
|
||||
|
||||
class Settings(BaseSettings):
|
||||
# Database settings
|
||||
db_host: str = "db" # Docker service name
|
||||
db_user: str = "ppr_user"
|
||||
db_password: str = "ppr_password123"
|
||||
db_name: str = "ppr_nextgen"
|
||||
db_port: int = 3306
|
||||
|
||||
# Security settings
|
||||
secret_key: str = "your-secret-key-change-this-in-production"
|
||||
algorithm: str = "HS256"
|
||||
access_token_expire_minutes: int = 30
|
||||
|
||||
# Mail settings
|
||||
mail_host: str = "send.one.com"
|
||||
mail_port: int = 465
|
||||
mail_username: str = "noreply@swansea-airport.wales"
|
||||
mail_password: str = "SASAGoForward2155"
|
||||
mail_from: str = "noreply@swansea-airport.wales"
|
||||
mail_from_name: str = "Swansea Airport"
|
||||
|
||||
# Application settings
|
||||
api_v1_str: str = "/api/v1"
|
||||
project_name: str = "Airfield PPR API"
|
||||
base_url: str = "https://pprdev.swansea-airport.wales"
|
||||
|
||||
# Redis settings (for future use)
|
||||
redis_url: Optional[str] = None
|
||||
|
||||
class Config:
|
||||
env_file = ".env"
|
||||
case_sensitive = False
|
||||
|
||||
@property
|
||||
def database_url(self) -> str:
|
||||
return f"mysql+pymysql://{self.db_user}:{self.db_password}@{self.db_host}:{self.db_port}/{self.db_name}"
|
||||
|
||||
|
||||
settings = Settings()
|
||||
47
backend/app/core/security.py
Normal file
47
backend/app/core/security.py
Normal file
@@ -0,0 +1,47 @@
|
||||
from datetime import datetime, timedelta
|
||||
from typing import Optional, Union
|
||||
from jose import JWTError, jwt
|
||||
from passlib.context import CryptContext
|
||||
from fastapi import HTTPException, status
|
||||
from app.core.config import settings
|
||||
|
||||
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
|
||||
|
||||
def create_access_token(
|
||||
subject: Union[str, int], expires_delta: Optional[timedelta] = None
|
||||
) -> str:
|
||||
"""Create a new access token"""
|
||||
if expires_delta:
|
||||
expire = datetime.utcnow() + expires_delta
|
||||
else:
|
||||
expire = datetime.utcnow() + timedelta(
|
||||
minutes=settings.access_token_expire_minutes
|
||||
)
|
||||
|
||||
to_encode = {"exp": expire, "sub": str(subject)}
|
||||
encoded_jwt = jwt.encode(to_encode, settings.secret_key, algorithm=settings.algorithm)
|
||||
return encoded_jwt
|
||||
|
||||
|
||||
def verify_password(plain_password: str, hashed_password: str) -> bool:
|
||||
"""Verify a password against its hash"""
|
||||
return pwd_context.verify(plain_password, hashed_password)
|
||||
|
||||
|
||||
def get_password_hash(password: str) -> str:
|
||||
"""Generate password hash"""
|
||||
return pwd_context.hash(password)
|
||||
|
||||
|
||||
def verify_token(token: str) -> Optional[str]:
|
||||
"""Verify JWT token and return username"""
|
||||
try:
|
||||
payload = jwt.decode(
|
||||
token, settings.secret_key, algorithms=[settings.algorithm]
|
||||
)
|
||||
username: str = payload.get("sub")
|
||||
if username is None:
|
||||
return None
|
||||
return username
|
||||
except JWTError:
|
||||
return None
|
||||
Reference in New Issue
Block a user