This commit is contained in:
@@ -0,0 +1,4 @@
|
||||
from decimal import DefaultContext, getcontext
|
||||
|
||||
DefaultContext.prec = 60
|
||||
getcontext().prec = 60
|
||||
@@ -0,0 +1,102 @@
|
||||
import os
|
||||
from pathlib import Path
|
||||
from urllib.parse import unquote, urlparse
|
||||
|
||||
from django.core.exceptions import ImproperlyConfigured
|
||||
|
||||
BASE_DIR = Path(__file__).resolve().parent.parent
|
||||
PRODUCTION = os.environ.get("APP_ENV") == "production"
|
||||
SECRET_KEY = os.environ.get("SECRET_KEY", "development-only-not-for-production-traceiq")
|
||||
if PRODUCTION and (len(SECRET_KEY) < 50 or SECRET_KEY.startswith("development")):
|
||||
raise ImproperlyConfigured("Set a random SECRET_KEY of at least 50 characters")
|
||||
DEBUG = not PRODUCTION
|
||||
ALLOWED_HOSTS = os.environ.get("ALLOWED_HOSTS", "localhost,127.0.0.1,testserver").split(",")
|
||||
CSRF_TRUSTED_ORIGINS = [x for x in os.environ.get("CSRF_TRUSTED_ORIGINS", "").split(",") if x]
|
||||
INSTALLED_APPS = [
|
||||
"django.contrib.auth",
|
||||
"django.contrib.contenttypes",
|
||||
"django.contrib.sessions",
|
||||
"django.contrib.staticfiles",
|
||||
"finance",
|
||||
]
|
||||
MIDDLEWARE = [
|
||||
"django.middleware.security.SecurityMiddleware",
|
||||
"whitenoise.middleware.WhiteNoiseMiddleware",
|
||||
"django.contrib.sessions.middleware.SessionMiddleware",
|
||||
"django.middleware.common.CommonMiddleware",
|
||||
"django.middleware.csrf.CsrfViewMiddleware",
|
||||
"django.contrib.auth.middleware.AuthenticationMiddleware",
|
||||
"django.middleware.clickjacking.XFrameOptionsMiddleware",
|
||||
"finance.middleware.SecurityHeaders",
|
||||
]
|
||||
ROOT_URLCONF = "server.urls"
|
||||
WSGI_APPLICATION = "server.wsgi.application"
|
||||
url = os.environ.get("DATABASE_URL")
|
||||
if url:
|
||||
db = urlparse(url)
|
||||
if db.scheme not in ("postgres", "postgresql"):
|
||||
raise ImproperlyConfigured("DATABASE_URL must be PostgreSQL")
|
||||
DATABASES = {
|
||||
"default": {
|
||||
"ENGINE": "django.db.backends.postgresql",
|
||||
"NAME": db.path[1:],
|
||||
"USER": unquote(db.username or ""),
|
||||
"PASSWORD": unquote(db.password or ""),
|
||||
"HOST": db.hostname,
|
||||
"PORT": db.port or 5432,
|
||||
"CONN_MAX_AGE": 60,
|
||||
"OPTIONS": {"sslmode": os.environ.get("DB_SSLMODE", "prefer")},
|
||||
}
|
||||
}
|
||||
else:
|
||||
if PRODUCTION:
|
||||
raise ImproperlyConfigured("Production requires DATABASE_URL")
|
||||
DATABASES = {
|
||||
"default": {
|
||||
"ENGINE": "django.db.backends.sqlite3",
|
||||
"NAME": os.environ.get("SQLITE_PATH", str(BASE_DIR / "var/db.sqlite3")),
|
||||
"OPTIONS": {"timeout": 30},
|
||||
}
|
||||
}
|
||||
AUTH_PASSWORD_VALIDATORS = [
|
||||
{"NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator"},
|
||||
{"NAME": "django.contrib.auth.password_validation.MinimumLengthValidator", "OPTIONS": {"min_length": 12}},
|
||||
{"NAME": "django.contrib.auth.password_validation.CommonPasswordValidator"},
|
||||
{"NAME": "django.contrib.auth.password_validation.NumericPasswordValidator"},
|
||||
]
|
||||
LANGUAGE_CODE = "zh-hans"
|
||||
TIME_ZONE = "UTC"
|
||||
USE_TZ = True
|
||||
DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField"
|
||||
SESSION_COOKIE_HTTPONLY = True
|
||||
SESSION_COOKIE_SAMESITE = "Lax"
|
||||
SESSION_COOKIE_AGE = 8 * 3600
|
||||
SESSION_COOKIE_SECURE = PRODUCTION
|
||||
CSRF_COOKIE_SECURE = PRODUCTION
|
||||
SECURE_SSL_REDIRECT = PRODUCTION and os.environ.get("SECURE_SSL_REDIRECT", "1") == "1"
|
||||
SECURE_HSTS_SECONDS = 31536000 if PRODUCTION else 0
|
||||
SECURE_HSTS_INCLUDE_SUBDOMAINS = PRODUCTION
|
||||
SECURE_HSTS_PRELOAD = PRODUCTION
|
||||
# Enable only behind the private reverse proxy which overwrites this header.
|
||||
TRUST_PROXY = os.environ.get("TRUST_PROXY", "0") == "1"
|
||||
if TRUST_PROXY:
|
||||
SECURE_PROXY_SSL_HEADER = ("HTTP_X_FORWARDED_PROTO", "https")
|
||||
SECURE_CONTENT_TYPE_NOSNIFF = True
|
||||
X_FRAME_OPTIONS = "DENY"
|
||||
DATA_UPLOAD_MAX_MEMORY_SIZE = 2 * 1024 * 1024
|
||||
FILE_UPLOAD_MAX_MEMORY_SIZE = 1024 * 1024
|
||||
MEDIA_ROOT = Path(os.environ.get("MEDIA_ROOT", BASE_DIR / "var/uploads"))
|
||||
STATIC_URL = "/assets/"
|
||||
STATIC_ROOT = BASE_DIR / "staticfiles"
|
||||
STATICFILES_DIRS = [BASE_DIR / "frontend/dist/assets"] if (BASE_DIR / "frontend/dist/assets").exists() else []
|
||||
MAX_UPLOAD_BYTES = int(os.environ.get("MAX_UPLOAD_BYTES", 64 * 1024 * 1024))
|
||||
MAX_IMPORT_ROWS = int(os.environ.get("MAX_IMPORT_ROWS", 1000000))
|
||||
OPENAI_API_KEY = os.environ.get("OPENAI_API_KEY", "")
|
||||
OPENAI_MODEL = os.environ.get("OPENAI_MODEL", "")
|
||||
AI_ENABLED = os.environ.get("AI_ENABLED", "0") == "1"
|
||||
LOGGING = {
|
||||
"version": 1,
|
||||
"disable_existing_loggers": False,
|
||||
"handlers": {"console": {"class": "logging.StreamHandler"}},
|
||||
"root": {"handlers": ["console"], "level": "INFO"},
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
from django.urls import path
|
||||
|
||||
from finance import formula_views, views
|
||||
from finance.assistant import assistant
|
||||
|
||||
urlpatterns = [
|
||||
path("api/session", views.session),
|
||||
path("api/login", views.sign_in),
|
||||
path("api/logout", views.sign_out),
|
||||
path("api/health", views.health),
|
||||
path("api/datasets", views.datasets),
|
||||
path("api/users", views.users),
|
||||
path("api/audit", views.audit_log),
|
||||
path("api/datasets/<uuid:dataset_id>", views.dataset_detail),
|
||||
path("api/datasets/<uuid:dataset_id>/mapping", views.mapping),
|
||||
path("api/datasets/<uuid:dataset_id>/query", views.query),
|
||||
path("api/datasets/<uuid:dataset_id>/evidence", views.evidence),
|
||||
path("api/datasets/<uuid:dataset_id>/export", views.export),
|
||||
path("api/datasets/<uuid:dataset_id>/formula-design", formula_views.formula_design),
|
||||
path(
|
||||
"api/datasets/<uuid:dataset_id>/formula-definitions",
|
||||
formula_views.formula_definitions,
|
||||
),
|
||||
path(
|
||||
"api/datasets/<uuid:dataset_id>/formula-definitions/<uuid:definition_id>",
|
||||
formula_views.formula_definition_delete,
|
||||
),
|
||||
path("api/datasets/<uuid:dataset_id>/formula-exports", formula_views.formula_export_create),
|
||||
path(
|
||||
"api/datasets/<uuid:dataset_id>/formula-exports/<uuid:export_id>", formula_views.formula_export_status
|
||||
),
|
||||
path(
|
||||
"api/datasets/<uuid:dataset_id>/formula-exports/<uuid:export_id>/download",
|
||||
formula_views.formula_export_download,
|
||||
),
|
||||
path("api/datasets/<uuid:dataset_id>/settings", views.settings_view),
|
||||
path("api/datasets/<uuid:dataset_id>/investigations", views.investigations),
|
||||
path("api/datasets/<uuid:dataset_id>/assistant", assistant),
|
||||
path("", views.index),
|
||||
]
|
||||
@@ -0,0 +1,6 @@
|
||||
import os
|
||||
|
||||
from django.core.wsgi import get_wsgi_application
|
||||
|
||||
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "server.settings")
|
||||
application = get_wsgi_application()
|
||||
Reference in New Issue
Block a user