227 lines
7.1 KiB
Python
227 lines
7.1 KiB
Python
import os
|
|
from pathlib import Path
|
|
from datetime import timedelta
|
|
import logging
|
|
from logging.handlers import RotatingFileHandler
|
|
|
|
# Base directories
|
|
BASE_DIR = Path(__file__).parent.parent
|
|
INSTANCE_DIR = BASE_DIR / 'instance'
|
|
|
|
# Default values
|
|
DEFAULT_NET_BASE = 12.5
|
|
|
|
# Allowed emails for registration
|
|
ALLOWED_EMAILS = {
|
|
'jenny.tay@adidas.com',
|
|
'gema.yostisiano@adidas.com',
|
|
'dirgasapto.nugratama@adidas.com',
|
|
'test@example.com', # Original test email
|
|
'test1@example.com',
|
|
'test2@example.com',
|
|
'test3@example.com',
|
|
'test4@example.com',
|
|
'test5@example.com',
|
|
'test6@example.com',
|
|
'test7@example.com',
|
|
'test8@example.com',
|
|
'test9@example.com',
|
|
'test10@example.com'
|
|
}
|
|
|
|
# Tax rates by country
|
|
TAX_RATES = {
|
|
'China': 0.06,
|
|
'Vietnam': 0.10,
|
|
'Indonesia': 0.07
|
|
}
|
|
|
|
# Cost factors for calculations
|
|
COST_FACTORS = {
|
|
'mold': {
|
|
'Flat & Thin': 1.0,
|
|
'Flat & Thick': 1.25,
|
|
'Flat with Top/Heat Tip': 1.35,
|
|
'Top PL': 1.05,
|
|
'Short PL (Heat/Forefoot)': 1.18,
|
|
'Visible PL': 1.28,
|
|
'Wave PL': 1.32,
|
|
'2 Plates Mold': 1.0,
|
|
'3 Plates Mold': 1.35,
|
|
'Breathable + In-mold channel': 1.45,
|
|
'With Upper Bandage': 1.15,
|
|
'2 plate without Bandage': 1.05,
|
|
'Co-shot mold': 1.25,
|
|
'Foaming mold': 1.4
|
|
},
|
|
'complexity': {
|
|
'high_sidewall': 0.18,
|
|
'slider': 0.1,
|
|
'cavity': 0.12
|
|
},
|
|
'texture': {
|
|
'standard': 0.0,
|
|
'custom': 0.15,
|
|
'laser': 0.2
|
|
}
|
|
}
|
|
|
|
class Config:
|
|
"""Base configuration class."""
|
|
|
|
# Flask configuration
|
|
SECRET_KEY = os.getenv('SECRET_KEY') # Get SECRET_KEY directly from environment
|
|
FLASK_APP = 'app'
|
|
FLASK_ENV = 'development'
|
|
FLASK_DEBUG = True
|
|
|
|
# Security configuration
|
|
SESSION_COOKIE_SECURE = True
|
|
SESSION_COOKIE_HTTPONLY = True
|
|
SESSION_COOKIE_SAMESITE = 'Lax'
|
|
PERMANENT_SESSION_LIFETIME = timedelta(days=7)
|
|
REMEMBER_COOKIE_DURATION = timedelta(days=30)
|
|
REMEMBER_COOKIE_SECURE = True
|
|
REMEMBER_COOKIE_HTTPONLY = True
|
|
REMEMBER_COOKIE_SAMESITE = 'Lax'
|
|
|
|
# Database configuration
|
|
SQLALCHEMY_DATABASE_URI = None # Will be set from environment variable
|
|
SQLALCHEMY_TRACK_MODIFICATIONS = False
|
|
SQLALCHEMY_ENGINE_OPTIONS = {
|
|
'pool_size': 10,
|
|
'pool_recycle': 3600,
|
|
'pool_pre_ping': True
|
|
}
|
|
|
|
# Email configuration
|
|
MAIL_SERVER = None # Will be set from environment variable
|
|
MAIL_PORT = 587
|
|
MAIL_USE_TLS = True
|
|
MAIL_USERNAME = None # Will be set from environment variable
|
|
MAIL_PASSWORD = None # Will be set from environment variable
|
|
MAIL_DEFAULT_SENDER = None # Will be set from environment variable
|
|
|
|
# Admin account configuration
|
|
ADMIN_EMAIL = None # Will be set from environment variable
|
|
ADMIN_PASSWORD = None # Will be set from environment variable
|
|
|
|
# Logging configuration
|
|
LOG_LEVEL = 'INFO'
|
|
LOG_TO_STDOUT = True
|
|
LOG_FORMAT = '%(asctime)s %(levelname)s: %(message)s [in %(pathname)s:%(lineno)d]'
|
|
LOG_DATE_FORMAT = '%Y-%m-%d %H:%M:%S'
|
|
|
|
# Application config
|
|
ALLOWED_EMAILS = ALLOWED_EMAILS
|
|
TAX_RATES = TAX_RATES
|
|
DEFAULT_NET_BASE = DEFAULT_NET_BASE
|
|
WTF_CSRF_ENABLED = True
|
|
|
|
# Rate Limiting Configuration
|
|
RATELIMIT_DEFAULT = "200 per day;50 per hour;10 per minute"
|
|
RATELIMIT_STORAGE_URL = "memory://"
|
|
RATELIMIT_STRATEGY = "fixed-window"
|
|
RATELIMIT_HEADERS_ENABLED = True
|
|
RATELIMIT_HEADERS_RESET = True
|
|
RATELIMIT_HEADERS_RETRY_AFTER = True
|
|
|
|
# Cache Configuration
|
|
CACHE_TYPE = "SimpleCache"
|
|
CACHE_DEFAULT_TIMEOUT = 300
|
|
CACHE_THRESHOLD = 1000
|
|
|
|
@classmethod
|
|
def init_app(cls, app):
|
|
"""Initialize application with configuration."""
|
|
# Load configuration from environment variables
|
|
db_user = os.getenv('POSTGRES_USER')
|
|
db_password = os.getenv('POSTGRES_PASSWORD')
|
|
db_host = os.getenv('DATABASE_HOST')
|
|
db_name = os.getenv('POSTGRES_DB')
|
|
|
|
if db_user and db_password and db_host and db_name:
|
|
cls.SQLALCHEMY_DATABASE_URI = f"postgresql://{db_user}:{db_password}@{db_host}/{db_name}"
|
|
else:
|
|
cls.SQLALCHEMY_DATABASE_URI = os.getenv('DATABASE_URL') # Fallback for other setups
|
|
|
|
cls.MAIL_SERVER = os.getenv('MAIL_SERVER')
|
|
cls.MAIL_USERNAME = os.getenv('MAIL_USERNAME')
|
|
cls.MAIL_PASSWORD = os.getenv('MAIL_PASSWORD')
|
|
cls.MAIL_DEFAULT_SENDER = os.getenv('MAIL_DEFAULT_SENDER')
|
|
cls.ADMIN_EMAIL = os.getenv('ADMIN_EMAIL')
|
|
cls.ADMIN_PASSWORD = os.getenv('ADMIN_PASSWORD')
|
|
cls.LOG_LEVEL = os.getenv('LOG_LEVEL', 'INFO')
|
|
cls.LOG_TO_STDOUT = os.getenv('LOG_TO_STDOUT', 'True').lower() == 'true'
|
|
|
|
# Ensure SECRET_KEY is set
|
|
if not cls.SECRET_KEY:
|
|
raise ValueError("SECRET_KEY environment variable is not set")
|
|
|
|
# Set SQLALCHEMY_DATABASE_URI on the app config
|
|
if not cls.SQLALCHEMY_DATABASE_URI:
|
|
raise ValueError("Database connection URI is not set. Please check DATABASE_URL or its components.")
|
|
app.config['SQLALCHEMY_DATABASE_URI'] = cls.SQLALCHEMY_DATABASE_URI
|
|
|
|
# Configure logging
|
|
if not os.path.exists('logs'):
|
|
os.mkdir('logs')
|
|
file_handler = RotatingFileHandler('logs/app.log',
|
|
maxBytes=10240,
|
|
backupCount=10)
|
|
file_handler.setFormatter(logging.Formatter(cls.LOG_FORMAT))
|
|
file_handler.setLevel(logging.INFO)
|
|
app.logger.addHandler(file_handler)
|
|
app.logger.setLevel(logging.INFO)
|
|
app.logger.info('Application startup')
|
|
|
|
class DevelopmentConfig(Config):
|
|
DEBUG = True
|
|
TESTING = False
|
|
REMEMBER_COOKIE_SECURE = False
|
|
SESSION_COOKIE_SECURE = False
|
|
SQLALCHEMY_ECHO = True
|
|
LOG_LEVEL = 'DEBUG'
|
|
WTF_CSRF_ENABLED = True
|
|
|
|
# Development-specific settings
|
|
RATELIMIT_DEFAULT = "1000 per day;100 per hour;20 per minute"
|
|
CACHE_TYPE = "SimpleCache"
|
|
|
|
class ProductionConfig(Config):
|
|
DEBUG = False
|
|
TESTING = False
|
|
REMEMBER_COOKIE_SECURE = True
|
|
SESSION_COOKIE_SECURE = True
|
|
SQLALCHEMY_ECHO = False
|
|
LOG_LEVEL = 'INFO'
|
|
WTF_CSRF_ENABLED = True
|
|
|
|
# Production-specific settings
|
|
CACHE_TYPE = "SimpleCache"
|
|
CACHE_DEFAULT_TIMEOUT = 300
|
|
|
|
class TestingConfig(Config):
|
|
TESTING = True
|
|
DEBUG = True
|
|
SQLALCHEMY_DATABASE_URI = 'sqlite:///:memory:'
|
|
WTF_CSRF_ENABLED = False
|
|
LOG_LEVEL = 'DEBUG'
|
|
|
|
# Testing-specific settings
|
|
SECRET_KEY = 'testing-secret-key-not-used-in-production'
|
|
MAIL_SUPPRESS_SEND = True
|
|
RATELIMIT_ENABLED = False
|
|
RATELIMIT_DEFAULT = "1000 per day;100 per hour;20 per minute"
|
|
CACHE_TYPE = "SimpleCache"
|
|
SQLALCHEMY_ENGINE_OPTIONS = {}
|
|
|
|
def get_config():
|
|
"""Get the appropriate configuration class based on environment."""
|
|
config_name = os.getenv('FLASK_CONFIG', 'development')
|
|
config_map = {
|
|
'development': DevelopmentConfig,
|
|
'production': ProductionConfig,
|
|
'testing': TestingConfig
|
|
}
|
|
return config_map.get(config_name, DevelopmentConfig) |