This commit is contained in:
Iliyan Angelov
2025-11-21 15:15:48 +02:00
parent 9a6190e8ef
commit f469cf7806
13 changed files with 129 additions and 88 deletions

View File

@@ -1,34 +1,94 @@
# ============================================
# Hotel Booking API - Environment Variables # Hotel Booking API - Environment Variables
# ============================================
# Copy this file to .env and fill in your actual values # Copy this file to .env and fill in your actual values
# All variables are optional and have sensible defaults
# See src/config/settings.py for default values
# ============================================ # ============================================
# Email/SMTP Configuration # Application Configuration
# ============================================ # ============================================
# SMTP Server Settings ENVIRONMENT=development
SMTP_HOST=smtp.gmail.com # Options: development, staging, production
SMTP_PORT=587 DEBUG=true
SMTP_USER=your-email@gmail.com # Set to false in production
SMTP_PASSWORD=your-app-specific-password HOST=0.0.0.0
PORT=8000
# Email Sender Information API_V1_PREFIX=/api/v1
SMTP_FROM_EMAIL=noreply@yourdomain.com
SMTP_FROM_NAME=Hotel Booking
# Alternative: Legacy environment variable names (for backward compatibility)
# MAIL_HOST=smtp.gmail.com
# MAIL_PORT=587
# MAIL_USER=your-email@gmail.com
# MAIL_PASS=your-app-specific-password
# MAIL_FROM=noreply@yourdomain.com
# MAIL_SECURE=false
# ============================================ # ============================================
# Other Required Variables # Database Configuration
# ============================================ # ============================================
CLIENT_URL=http://localhost:5173
DB_USER=root
DB_PASS=your_database_password
DB_NAME=hotel_db
DB_HOST=localhost DB_HOST=localhost
DB_PORT=3306 DB_PORT=3306
JWT_SECRET=your-super-secret-jwt-key-change-in-production DB_USER=root
DB_PASS=
# Leave empty if using MySQL without password
DB_NAME=hotel_db
# ============================================
# JWT Authentication
# ============================================
# JWT_SECRET will be auto-generated on startup if not set
# The generated secret will be saved here automatically
JWT_ALGORITHM=HS256
JWT_ACCESS_TOKEN_EXPIRE_MINUTES=30
JWT_REFRESH_TOKEN_EXPIRE_DAYS=7
# ============================================
# CORS & Client Configuration
# ============================================
CLIENT_URL=http://localhost:5173
# Frontend application URL
CORS_ORIGINS=["http://localhost:5173","http://localhost:3000","http://127.0.0.1:5173"]
# JSON array of allowed origins (only used in production)
# ============================================
# Email & Payment Settings
# ============================================
# NOTE: Email (SMTP) and Payment Gateway (Stripe, PayPal) settings
# are configured in the Admin Dashboard, not via environment variables.
# Log in as admin and go to Settings page to configure these.
# ============================================
# Redis Configuration (Optional)
# ============================================
REDIS_ENABLED=false
REDIS_HOST=localhost
REDIS_PORT=6379
REDIS_DB=0
REDIS_PASSWORD=
# Leave empty if Redis has no password
# ============================================
# File Upload Configuration
# ============================================
UPLOAD_DIR=uploads
MAX_UPLOAD_SIZE=5242880
# Max upload size in bytes (5MB default)
ALLOWED_EXTENSIONS=["jpg","jpeg","png","gif","webp"]
# JSON array
# ============================================
# Rate Limiting
# ============================================
RATE_LIMIT_ENABLED=true
RATE_LIMIT_PER_MINUTE=60
# ============================================
# Logging Configuration
# ============================================
LOG_LEVEL=INFO
# Options: DEBUG, INFO, WARNING, ERROR, CRITICAL
LOG_FILE=logs/app.log
LOG_MAX_BYTES=10485760
# Max log file size in bytes (10MB)
LOG_BACKUP_COUNT=5
# ============================================
# Server Configuration
# ============================================
REQUEST_TIMEOUT=30
# Request timeout in seconds (0 to disable)
HEALTH_CHECK_INTERVAL=30
# Health check interval in seconds

View File

@@ -1,64 +0,0 @@
#!/usr/bin/env python3
import sys
import os
import bcrypt
sys.path.insert(0, os.path.join(os.path.dirname(__file__), 'src'))
from sqlalchemy.orm import Session
from src.config.database import SessionLocal
from src.models.user import User
from src.config.logging_config import setup_logging
logger = setup_logging()
def hash_password(password: str) -> str:
password_bytes = password.encode('utf-8')
salt = bcrypt.gensalt()
hashed = bcrypt.hashpw(password_bytes, salt)
return hashed.decode('utf-8')
def reset_password(db: Session, email: str, new_password: str) -> bool:
user = db.query(User).filter(User.email == email).first()
if not user:
print(f"❌ User with email '{email}' not found")
return False
hashed_password = hash_password(new_password)
user.password = hashed_password
db.commit()
db.refresh(user)
print(f"✅ Password reset for {email}")
print(f" New password: {new_password}")
print(f" Hash length: {len(user.password)} characters")
print()
return True
def main():
db = SessionLocal()
try:
print("="*80)
print("RESETTING TEST USER PASSWORDS")
print("="*80)
print()
except Exception as e:
logger.error(f"Error: {e}", exc_info=True)
print(f"\n❌ Error: {e}")
db.rollback()
finally:
db.close()
if __name__ == "__main__":
main()

View File

@@ -11,6 +11,9 @@ from slowapi.errors import RateLimitExceeded
from pathlib import Path from pathlib import Path
from datetime import datetime from datetime import datetime
import sys import sys
import secrets
import os
import re
from .config.settings import settings from .config.settings import settings
from .config.logging_config import setup_logging, get_logger from .config.logging_config import setup_logging, get_logger
from .config.database import engine, Base, get_db from .config.database import engine, Base, get_db
@@ -151,8 +154,50 @@ app.include_router(page_content_routes.router, prefix='/api')
app.include_router(page_content_routes.router, prefix=settings.API_V1_PREFIX) app.include_router(page_content_routes.router, prefix=settings.API_V1_PREFIX)
logger.info('All routes registered successfully') logger.info('All routes registered successfully')
def ensure_jwt_secret():
"""Generate and save JWT secret if it's using the default value."""
default_secret = 'dev-secret-key-change-in-production-12345'
current_secret = settings.JWT_SECRET
if not current_secret or current_secret == default_secret:
new_secret = secrets.token_urlsafe(64)
os.environ['JWT_SECRET'] = new_secret
env_file = Path(__file__).parent.parent / '.env'
if env_file.exists():
try:
env_content = env_file.read_text(encoding='utf-8')
jwt_pattern = re.compile(r'^JWT_SECRET=.*$', re.MULTILINE)
if jwt_pattern.search(env_content):
env_content = jwt_pattern.sub(f'JWT_SECRET={new_secret}', env_content)
else:
jwt_section_pattern = re.compile(r'(# =+.*JWT.*=+.*\n)', re.IGNORECASE | re.MULTILINE)
match = jwt_section_pattern.search(env_content)
if match:
insert_pos = match.end()
env_content = env_content[:insert_pos] + f'JWT_SECRET={new_secret}\n' + env_content[insert_pos:]
else:
env_content += f'\nJWT_SECRET={new_secret}\n'
env_file.write_text(env_content, encoding='utf-8')
logger.info('✓ JWT secret generated and saved to .env file')
except Exception as e:
logger.warning(f'Could not update .env file: {e}')
logger.info(f'Generated JWT secret (add to .env manually): JWT_SECRET={new_secret}')
else:
logger.info(f'Generated JWT secret (add to .env file): JWT_SECRET={new_secret}')
logger.info('✓ Secure JWT secret generated automatically')
else:
logger.info('✓ JWT secret is configured')
@app.on_event('startup') @app.on_event('startup')
async def startup_event(): async def startup_event():
ensure_jwt_secret()
logger.info(f'{settings.APP_NAME} started successfully') logger.info(f'{settings.APP_NAME} started successfully')
logger.info(f'Environment: {settings.ENVIRONMENT}') logger.info(f'Environment: {settings.ENVIRONMENT}')
logger.info(f'Debug mode: {settings.DEBUG}') logger.info(f'Debug mode: {settings.DEBUG}')