05/06/2026 Initial commit

This commit is contained in:
2026-05-06 14:19:07 -04:00
parent 9da1dffd9a
commit dde18a2cd2
116 changed files with 4276 additions and 7 deletions
+98
View File
@@ -0,0 +1,98 @@
"""
config.py
Configuration classes for Development, Production, and Testing.
Loaded by both app factories via: from config import config
"""
import os
from datetime import timedelta
from dotenv import load_dotenv
load_dotenv()
class Config:
SECRET_KEY = os.environ.get("SECRET_KEY", "dev-fallback-secret-change-me")
SQLALCHEMY_DATABASE_URI = os.environ.get(
"DATABASE_URL", "mysql+pymysql://root:password@localhost/salon_pos"
)
SQLALCHEMY_TRACK_MODIFICATIONS = False
SQLALCHEMY_ENGINE_OPTIONS = {"pool_recycle": 280, "pool_pre_ping": True}
MAIL_SERVER = os.environ.get("MAIL_SERVER", "localhost")
MAIL_PORT = int(os.environ.get("MAIL_PORT", 587))
MAIL_USE_TLS = os.environ.get("MAIL_USE_TLS", "true").lower() == "true"
MAIL_USERNAME = os.environ.get("MAIL_USERNAME")
MAIL_PASSWORD = os.environ.get("MAIL_PASSWORD")
MAIL_DEFAULT_SENDER = os.environ.get("MAIL_USERNAME", "noreply@mydomain.com")
JWT_ACCESS_TOKEN_EXPIRES = timedelta(seconds=int(os.environ.get("JWT_ACCESS_TOKEN_EXPIRES", 900)))
JWT_REFRESH_TOKEN_EXPIRES = timedelta(seconds=int(os.environ.get("JWT_REFRESH_TOKEN_EXPIRES", 604800)))
JWT_TOKEN_LOCATION = ["cookies"]
JWT_COOKIE_SECURE = True
JWT_COOKIE_SAMESITE = "Lax"
JWT_COOKIE_CSRF_PROTECT = True
SESSION_COOKIE_SECURE = True
SESSION_COOKIE_HTTPONLY = True
SESSION_COOKIE_SAMESITE = "Lax"
RATELIMIT_STORAGE_URI = os.environ.get("RATELIMIT_STORAGE_URI", "memory://")
RATELIMIT_DEFAULT = "200 per minute"
RATELIMIT_ENABLED = True
ADMIN_DOMAIN = os.environ.get("ADMIN_DOMAIN", "admin.mydomain.com")
TENANT_DOMAIN = os.environ.get("TENANT_DOMAIN", "mydomain.com")
DEMO_TENANT_SLUG = os.environ.get("DEMO_TENANT_SLUG", "demo")
ADMIN_IP_ALLOWLIST = os.environ.get("ADMIN_IP_ALLOWLIST", "")
MAX_LOGIN_ATTEMPTS = int(os.environ.get("MAX_LOGIN_ATTEMPTS", 5))
LOGIN_LOCKOUT_MINUTES = int(os.environ.get("LOGIN_LOCKOUT_MINUTES", 15))
STAFF_PASSCODE_MIN_LENGTH = int(os.environ.get("STAFF_PASSCODE_MIN_LENGTH", 4))
STAFF_PASSCODE_MAX_LENGTH = int(os.environ.get("STAFF_PASSCODE_MAX_LENGTH", 6))
MAX_CONTENT_LENGTH = 5 * 1024 * 1024
UPLOAD_EXTENSIONS = {"jpg", "jpeg", "png", "gif"}
UPLOAD_FOLDER = os.environ.get("UPLOAD_FOLDER", "/var/www/salon_pos_uploads")
WTF_CSRF_ENABLED = True
WTF_CSRF_TIME_LIMIT = 3600
class DevelopmentConfig(Config):
DEBUG = True
SQLALCHEMY_DATABASE_URI = os.environ.get(
"DATABASE_URL", "mysql+pymysql://root:password@localhost/salon_pos_dev"
)
SESSION_COOKIE_SECURE = False
JWT_COOKIE_SECURE = False
RATELIMIT_ENABLED = False
SESSION_TIMEOUT_TENANT = 1800
SESSION_TIMEOUT_ADMIN = 3600
class ProductionConfig(Config):
DEBUG = False
TESTING = False
SESSION_TIMEOUT_TENANT = int(os.environ.get("SESSION_TIMEOUT_TENANT", 1800))
SESSION_TIMEOUT_ADMIN = int(os.environ.get("SESSION_TIMEOUT_ADMIN", 3600))
class TestingConfig(Config):
TESTING = True
DEBUG = True
SQLALCHEMY_DATABASE_URI = "sqlite:///:memory:"
WTF_CSRF_ENABLED = False
JWT_COOKIE_SECURE = False
SESSION_COOKIE_SECURE = False
RATELIMIT_ENABLED = False
SESSION_TIMEOUT_TENANT = 1800
SESSION_TIMEOUT_ADMIN = 3600
BCRYPT_LOG_ROUNDS = 4
config = {
"development": DevelopmentConfig,
"production": ProductionConfig,
"testing": TestingConfig,
"default": DevelopmentConfig,
}
def get_config():
"""Return the config class for the current FLASK_ENV. Used by app factories."""
import os
env = os.environ.get("FLASK_ENV", "development")
return config.get(env, DevelopmentConfig)