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
# ============================================
# 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
SMTP_HOST=smtp.gmail.com
SMTP_PORT=587
SMTP_USER=your-email@gmail.com
SMTP_PASSWORD=your-app-specific-password
# Email Sender Information
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
ENVIRONMENT=development
# Options: development, staging, production
DEBUG=true
# Set to false in production
HOST=0.0.0.0
PORT=8000
API_V1_PREFIX=/api/v1
# ============================================
# 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_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 datetime import datetime
import sys
import secrets
import os
import re
from .config.settings import settings
from .config.logging_config import setup_logging, get_logger
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)
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')
async def startup_event():
ensure_jwt_secret()
logger.info(f'{settings.APP_NAME} started successfully')
logger.info(f'Environment: {settings.ENVIRONMENT}')
logger.info(f'Debug mode: {settings.DEBUG}')