mirror of
https://github.com/makeplane/plane
synced 2024-06-14 14:31:34 +00:00
dev: API settings (#2594)
* dev: update settings file structure and added extra settings for CORS * dev: remove WEB_URL variable and add celery integration for sentry * dev: aws and minio settings * dev: add cors origins to env * dev: update settings
This commit is contained in:
parent
ad3e511328
commit
a675cd5755
@ -1,7 +1,7 @@
|
|||||||
# Backend
|
# Backend
|
||||||
# Debug value for api server use it as 0 for production use
|
# Debug value for api server use it as 0 for production use
|
||||||
DEBUG=0
|
DEBUG=0
|
||||||
DJANGO_SETTINGS_MODULE="plane.settings.production"
|
CORS_ALLOWED_ORIGINS="http://localhost"
|
||||||
|
|
||||||
# Error logs
|
# Error logs
|
||||||
SENTRY_DSN=""
|
SENTRY_DSN=""
|
||||||
@ -70,6 +70,5 @@ ENABLE_MAGIC_LINK_LOGIN="0"
|
|||||||
# Email redirections and minio domain settings
|
# Email redirections and minio domain settings
|
||||||
WEB_URL="http://localhost"
|
WEB_URL="http://localhost"
|
||||||
|
|
||||||
|
|
||||||
# Gunicorn Workers
|
# Gunicorn Workers
|
||||||
GUNICORN_WORKERS=2
|
GUNICORN_WORKERS=2
|
@ -33,7 +33,7 @@ from plane.bgtasks.forgot_password_task import forgot_password
|
|||||||
class RequestEmailVerificationEndpoint(BaseAPIView):
|
class RequestEmailVerificationEndpoint(BaseAPIView):
|
||||||
def get(self, request):
|
def get(self, request):
|
||||||
token = RefreshToken.for_user(request.user).access_token
|
token = RefreshToken.for_user(request.user).access_token
|
||||||
current_site = settings.WEB_URL
|
current_site = request.META.get('HTTP_ORIGIN')
|
||||||
email_verification.delay(
|
email_verification.delay(
|
||||||
request.user.first_name, request.user.email, token, current_site
|
request.user.first_name, request.user.email, token, current_site
|
||||||
)
|
)
|
||||||
@ -76,7 +76,7 @@ class ForgotPasswordEndpoint(BaseAPIView):
|
|||||||
uidb64 = urlsafe_base64_encode(smart_bytes(user.id))
|
uidb64 = urlsafe_base64_encode(smart_bytes(user.id))
|
||||||
token = PasswordResetTokenGenerator().make_token(user)
|
token = PasswordResetTokenGenerator().make_token(user)
|
||||||
|
|
||||||
current_site = settings.WEB_URL
|
current_site = request.META.get('HTTP_ORIGIN')
|
||||||
|
|
||||||
forgot_password.delay(
|
forgot_password.delay(
|
||||||
user.first_name, user.email, uidb64, token, current_site
|
user.first_name, user.email, uidb64, token, current_site
|
||||||
|
@ -287,7 +287,8 @@ class MagicSignInGenerateEndpoint(BaseAPIView):
|
|||||||
|
|
||||||
ri.set(key, json.dumps(value), ex=expiry)
|
ri.set(key, json.dumps(value), ex=expiry)
|
||||||
|
|
||||||
current_site = settings.WEB_URL
|
|
||||||
|
current_site = request.META.get('HTTP_ORIGIN')
|
||||||
magic_link.delay(email, key, token, current_site)
|
magic_link.delay(email, key, token, current_site)
|
||||||
|
|
||||||
return Response({"key": key}, status=status.HTTP_200_OK)
|
return Response({"key": key}, status=status.HTTP_200_OK)
|
||||||
|
@ -386,7 +386,7 @@ class InviteProjectEndpoint(BaseAPIView):
|
|||||||
token=token,
|
token=token,
|
||||||
role=role,
|
role=role,
|
||||||
)
|
)
|
||||||
domain = settings.WEB_URL
|
domain = request.META.get('HTTP_ORIGIN')
|
||||||
project_invitation.delay(email, project_id, token, domain)
|
project_invitation.delay(email, project_id, token, domain)
|
||||||
|
|
||||||
return Response(
|
return Response(
|
||||||
|
@ -330,7 +330,7 @@ class InviteWorkspaceEndpoint(BaseAPIView):
|
|||||||
invitation.email,
|
invitation.email,
|
||||||
workspace.id,
|
workspace.id,
|
||||||
invitation.token,
|
invitation.token,
|
||||||
settings.WEB_URL,
|
request.META.get('HTTP_ORIGIN'),
|
||||||
request.user.email,
|
request.user.email,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -1,22 +1,35 @@
|
|||||||
|
"""Global Settings"""
|
||||||
|
# Python imports
|
||||||
import os
|
import os
|
||||||
import datetime
|
import ssl
|
||||||
|
import certifi
|
||||||
from datetime import timedelta
|
from datetime import timedelta
|
||||||
|
from urllib.parse import urlparse
|
||||||
|
# Django imports
|
||||||
from django.core.management.utils import get_random_secret_key
|
from django.core.management.utils import get_random_secret_key
|
||||||
|
|
||||||
|
# Third party imports
|
||||||
|
import dj_database_url
|
||||||
|
import sentry_sdk
|
||||||
|
from sentry_sdk.integrations.django import DjangoIntegration
|
||||||
|
from sentry_sdk.integrations.redis import RedisIntegration
|
||||||
|
from sentry_sdk.integrations.celery import CeleryIntegration
|
||||||
|
|
||||||
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||||
|
|
||||||
|
# Secret Key
|
||||||
SECRET_KEY = os.environ.get("SECRET_KEY", get_random_secret_key())
|
SECRET_KEY = os.environ.get("SECRET_KEY", get_random_secret_key())
|
||||||
|
|
||||||
# SECURITY WARNING: don't run with debug turned on in production!
|
# SECURITY WARNING: don't run with debug turned on in production!
|
||||||
DEBUG = True
|
DEBUG = False
|
||||||
|
|
||||||
ALLOWED_HOSTS = []
|
# Allowed Hosts
|
||||||
|
ALLOWED_HOSTS = ["*"]
|
||||||
|
|
||||||
|
# Redirect if / is not present
|
||||||
|
APPEND_SLASH = True
|
||||||
|
|
||||||
# Application definition
|
# Application definition
|
||||||
|
|
||||||
INSTALLED_APPS = [
|
INSTALLED_APPS = [
|
||||||
"django.contrib.auth",
|
"django.contrib.auth",
|
||||||
"django.contrib.contenttypes",
|
"django.contrib.contenttypes",
|
||||||
@ -36,12 +49,13 @@ INSTALLED_APPS = [
|
|||||||
"corsheaders",
|
"corsheaders",
|
||||||
"taggit",
|
"taggit",
|
||||||
"django_celery_beat",
|
"django_celery_beat",
|
||||||
|
"storages",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
# Middlewares
|
||||||
MIDDLEWARE = [
|
MIDDLEWARE = [
|
||||||
"corsheaders.middleware.CorsMiddleware",
|
"corsheaders.middleware.CorsMiddleware",
|
||||||
"django.middleware.security.SecurityMiddleware",
|
"django.middleware.security.SecurityMiddleware",
|
||||||
# "whitenoise.middleware.WhiteNoiseMiddleware",
|
|
||||||
"django.contrib.sessions.middleware.SessionMiddleware",
|
"django.contrib.sessions.middleware.SessionMiddleware",
|
||||||
"django.middleware.common.CommonMiddleware",
|
"django.middleware.common.CommonMiddleware",
|
||||||
"django.middleware.csrf.CsrfViewMiddleware",
|
"django.middleware.csrf.CsrfViewMiddleware",
|
||||||
@ -49,8 +63,9 @@ MIDDLEWARE = [
|
|||||||
"django.middleware.clickjacking.XFrameOptionsMiddleware",
|
"django.middleware.clickjacking.XFrameOptionsMiddleware",
|
||||||
"crum.CurrentRequestUserMiddleware",
|
"crum.CurrentRequestUserMiddleware",
|
||||||
"django.middleware.gzip.GZipMiddleware",
|
"django.middleware.gzip.GZipMiddleware",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
# Rest Framework settings
|
||||||
REST_FRAMEWORK = {
|
REST_FRAMEWORK = {
|
||||||
"DEFAULT_AUTHENTICATION_CLASSES": (
|
"DEFAULT_AUTHENTICATION_CLASSES": (
|
||||||
"rest_framework_simplejwt.authentication.JWTAuthentication",
|
"rest_framework_simplejwt.authentication.JWTAuthentication",
|
||||||
@ -60,13 +75,13 @@ REST_FRAMEWORK = {
|
|||||||
"DEFAULT_FILTER_BACKENDS": ("django_filters.rest_framework.DjangoFilterBackend",),
|
"DEFAULT_FILTER_BACKENDS": ("django_filters.rest_framework.DjangoFilterBackend",),
|
||||||
}
|
}
|
||||||
|
|
||||||
AUTHENTICATION_BACKENDS = (
|
# Django Auth Backend
|
||||||
"django.contrib.auth.backends.ModelBackend", # default
|
AUTHENTICATION_BACKENDS = ("django.contrib.auth.backends.ModelBackend",) # default
|
||||||
# "guardian.backends.ObjectPermissionBackend",
|
|
||||||
)
|
|
||||||
|
|
||||||
|
# Root Urls
|
||||||
ROOT_URLCONF = "plane.urls"
|
ROOT_URLCONF = "plane.urls"
|
||||||
|
|
||||||
|
# Templates
|
||||||
TEMPLATES = [
|
TEMPLATES = [
|
||||||
{
|
{
|
||||||
"BACKEND": "django.template.backends.django.DjangoTemplates",
|
"BACKEND": "django.template.backends.django.DjangoTemplates",
|
||||||
@ -85,52 +100,68 @@ TEMPLATES = [
|
|||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
|
# Cookie Settings
|
||||||
|
SESSION_COOKIE_SECURE = True
|
||||||
|
CSRF_COOKIE_SECURE = True
|
||||||
|
|
||||||
JWT_AUTH = {
|
# CORS Settings
|
||||||
"JWT_ENCODE_HANDLER": "rest_framework_jwt.utils.jwt_encode_handler",
|
CORS_ALLOW_CREDENTIALS = True
|
||||||
"JWT_DECODE_HANDLER": "rest_framework_jwt.utils.jwt_decode_handler",
|
CORS_ALLOWED_ORIGINS = os.environ.get("CORS_ALLOWED_ORIGINS", "").split(",")
|
||||||
"JWT_PAYLOAD_HANDLER": "rest_framework_jwt.utils.jwt_payload_handler",
|
|
||||||
"JWT_PAYLOAD_GET_USER_ID_HANDLER": "rest_framework_jwt.utils.jwt_get_user_id_from_payload_handler",
|
|
||||||
"JWT_RESPONSE_PAYLOAD_HANDLER": "rest_framework_jwt.utils.jwt_response_payload_handler",
|
|
||||||
"JWT_SECRET_KEY": SECRET_KEY,
|
|
||||||
"JWT_GET_USER_SECRET_KEY": None,
|
|
||||||
"JWT_PUBLIC_KEY": None,
|
|
||||||
"JWT_PRIVATE_KEY": None,
|
|
||||||
"JWT_ALGORITHM": "HS256",
|
|
||||||
"JWT_VERIFY": True,
|
|
||||||
"JWT_VERIFY_EXPIRATION": True,
|
|
||||||
"JWT_LEEWAY": 0,
|
|
||||||
"JWT_EXPIRATION_DELTA": datetime.timedelta(seconds=604800),
|
|
||||||
"JWT_AUDIENCE": None,
|
|
||||||
"JWT_ISSUER": None,
|
|
||||||
"JWT_ALLOW_REFRESH": False,
|
|
||||||
"JWT_REFRESH_EXPIRATION_DELTA": datetime.timedelta(days=7),
|
|
||||||
"JWT_AUTH_HEADER_PREFIX": "JWT",
|
|
||||||
"JWT_AUTH_COOKIE": None,
|
|
||||||
}
|
|
||||||
|
|
||||||
|
# Application Settings
|
||||||
WSGI_APPLICATION = "plane.wsgi.application"
|
WSGI_APPLICATION = "plane.wsgi.application"
|
||||||
ASGI_APPLICATION = "plane.asgi.application"
|
ASGI_APPLICATION = "plane.asgi.application"
|
||||||
|
|
||||||
# Django Sites
|
# Django Sites
|
||||||
|
|
||||||
SITE_ID = 1
|
SITE_ID = 1
|
||||||
|
|
||||||
# User Model
|
# User Model
|
||||||
AUTH_USER_MODEL = "db.User"
|
AUTH_USER_MODEL = "db.User"
|
||||||
|
|
||||||
# Database
|
# Database
|
||||||
|
if bool(os.environ.get("DATABASE_URL")):
|
||||||
DATABASES = {
|
# Parse database configuration from $DATABASE_URL
|
||||||
"default": {
|
DATABASES = {
|
||||||
"ENGINE": "django.db.backends.sqlite3",
|
"default": dj_database_url.config(),
|
||||||
"NAME": os.path.join(BASE_DIR, "db.sqlite3"),
|
}
|
||||||
|
else:
|
||||||
|
DATABASES = {
|
||||||
|
"default": {
|
||||||
|
"ENGINE": "django.db.backends.postgresql",
|
||||||
|
"NAME": os.environ.get("POSTGRES_DB"),
|
||||||
|
"USER": os.environ.get("POSTGRES_USER"),
|
||||||
|
"PASSWORD": os.environ.get("POSTGRES_PASSWORD"),
|
||||||
|
"HOST": os.environ.get("POSTGRES_HOST"),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
# Redis Config
|
||||||
|
REDIS_URL = os.environ.get("REDIS_URL")
|
||||||
|
REDIS_SSL = "rediss" in REDIS_URL
|
||||||
|
|
||||||
# Password validation
|
if REDIS_SSL:
|
||||||
|
CACHES = {
|
||||||
|
"default": {
|
||||||
|
"BACKEND": "django_redis.cache.RedisCache",
|
||||||
|
"LOCATION": REDIS_URL,
|
||||||
|
"OPTIONS": {
|
||||||
|
"CLIENT_CLASS": "django_redis.client.DefaultClient",
|
||||||
|
"CONNECTION_POOL_KWARGS": {"ssl_cert_reqs": False},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else:
|
||||||
|
CACHES = {
|
||||||
|
"default": {
|
||||||
|
"BACKEND": "django_redis.cache.RedisCache",
|
||||||
|
"LOCATION": REDIS_URL,
|
||||||
|
"OPTIONS": {
|
||||||
|
"CLIENT_CLASS": "django_redis.client.DefaultClient",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Password validations
|
||||||
AUTH_PASSWORD_VALIDATORS = [
|
AUTH_PASSWORD_VALIDATORS = [
|
||||||
{
|
{
|
||||||
"NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator",
|
"NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator",
|
||||||
@ -147,7 +178,6 @@ AUTH_PASSWORD_VALIDATORS = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
# Static files (CSS, JavaScript, Images)
|
# Static files (CSS, JavaScript, Images)
|
||||||
|
|
||||||
STATIC_URL = "/static/"
|
STATIC_URL = "/static/"
|
||||||
STATIC_ROOT = os.path.join(BASE_DIR, "static-assets", "collected-static")
|
STATIC_ROOT = os.path.join(BASE_DIR, "static-assets", "collected-static")
|
||||||
STATICFILES_DIRS = (os.path.join(BASE_DIR, "static"),)
|
STATICFILES_DIRS = (os.path.join(BASE_DIR, "static"),)
|
||||||
@ -156,21 +186,19 @@ STATICFILES_DIRS = (os.path.join(BASE_DIR, "static"),)
|
|||||||
MEDIA_ROOT = "mediafiles"
|
MEDIA_ROOT = "mediafiles"
|
||||||
MEDIA_URL = "/media/"
|
MEDIA_URL = "/media/"
|
||||||
|
|
||||||
|
|
||||||
# Internationalization
|
# Internationalization
|
||||||
|
|
||||||
LANGUAGE_CODE = "en-us"
|
LANGUAGE_CODE = "en-us"
|
||||||
|
|
||||||
TIME_ZONE = "UTC"
|
|
||||||
|
|
||||||
USE_I18N = True
|
USE_I18N = True
|
||||||
|
|
||||||
USE_L10N = True
|
USE_L10N = True
|
||||||
|
|
||||||
|
# Timezones
|
||||||
USE_TZ = True
|
USE_TZ = True
|
||||||
|
TIME_ZONE = "UTC"
|
||||||
|
|
||||||
|
# Default Auto Field
|
||||||
DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField"
|
DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField"
|
||||||
|
|
||||||
|
# Email settings
|
||||||
EMAIL_BACKEND = "django.core.mail.backends.smtp.EmailBackend"
|
EMAIL_BACKEND = "django.core.mail.backends.smtp.EmailBackend"
|
||||||
# Host for sending e-mail.
|
# Host for sending e-mail.
|
||||||
EMAIL_HOST = os.environ.get("EMAIL_HOST")
|
EMAIL_HOST = os.environ.get("EMAIL_HOST")
|
||||||
@ -183,7 +211,30 @@ EMAIL_USE_TLS = os.environ.get("EMAIL_USE_TLS", "1") == "1"
|
|||||||
EMAIL_USE_SSL = os.environ.get("EMAIL_USE_SSL", "0") == "1"
|
EMAIL_USE_SSL = os.environ.get("EMAIL_USE_SSL", "0") == "1"
|
||||||
EMAIL_FROM = os.environ.get("EMAIL_FROM", "Team Plane <team@mailer.plane.so>")
|
EMAIL_FROM = os.environ.get("EMAIL_FROM", "Team Plane <team@mailer.plane.so>")
|
||||||
|
|
||||||
|
# Storage Settings
|
||||||
|
STORAGES = {
|
||||||
|
"staticfiles": {
|
||||||
|
"BACKEND": "whitenoise.storage.CompressedManifestStaticFilesStorage",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
STORAGES["default"] = {"BACKEND": "storages.backends.s3boto3.S3Boto3Storage"}
|
||||||
|
AWS_ACCESS_KEY_ID = os.environ.get("AWS_ACCESS_KEY_ID", "access-key")
|
||||||
|
AWS_SECRET_ACCESS_KEY = os.environ.get("AWS_SECRET_ACCESS_KEY", "secret-key")
|
||||||
|
AWS_STORAGE_BUCKET_NAME = os.environ.get("AWS_S3_BUCKET_NAME", "uploads")
|
||||||
|
AWS_DEFAULT_ACL = "public-read"
|
||||||
|
AWS_QUERYSTRING_AUTH = False
|
||||||
|
AWS_S3_FILE_OVERWRITE = False
|
||||||
|
AWS_S3_ENDPOINT_URL = os.environ.get("AWS_S3_ENDPOINT_URL", None) or os.environ.get(
|
||||||
|
"MINIO_ENDPOINT_URL", None
|
||||||
|
)
|
||||||
|
if AWS_S3_ENDPOINT_URL:
|
||||||
|
parsed_url = urlparse(os.environ.get("WEB_URL", "http://localhost"))
|
||||||
|
AWS_S3_CUSTOM_DOMAIN = f"{parsed_url.netloc}/{AWS_STORAGE_BUCKET_NAME}"
|
||||||
|
AWS_S3_URL_PROTOCOL = f"{parsed_url.scheme}:"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# JWT Auth Configuration
|
||||||
SIMPLE_JWT = {
|
SIMPLE_JWT = {
|
||||||
"ACCESS_TOKEN_LIFETIME": timedelta(minutes=10080),
|
"ACCESS_TOKEN_LIFETIME": timedelta(minutes=10080),
|
||||||
"REFRESH_TOKEN_LIFETIME": timedelta(days=43200),
|
"REFRESH_TOKEN_LIFETIME": timedelta(days=43200),
|
||||||
@ -211,7 +262,71 @@ SIMPLE_JWT = {
|
|||||||
"SLIDING_TOKEN_REFRESH_LIFETIME": timedelta(days=1),
|
"SLIDING_TOKEN_REFRESH_LIFETIME": timedelta(days=1),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# Celery Configuration
|
||||||
CELERY_TIMEZONE = TIME_ZONE
|
CELERY_TIMEZONE = TIME_ZONE
|
||||||
CELERY_TASK_SERIALIZER = 'json'
|
CELERY_TASK_SERIALIZER = "json"
|
||||||
CELERY_ACCEPT_CONTENT = ['application/json']
|
CELERY_ACCEPT_CONTENT = ["application/json"]
|
||||||
CELERY_IMPORTS = ("plane.bgtasks.issue_automation_task","plane.bgtasks.exporter_expired_task")
|
|
||||||
|
if REDIS_SSL:
|
||||||
|
redis_url = os.environ.get("REDIS_URL")
|
||||||
|
broker_url = (
|
||||||
|
f"{redis_url}?ssl_cert_reqs={ssl.CERT_NONE.name}&ssl_ca_certs={certifi.where()}"
|
||||||
|
)
|
||||||
|
CELERY_BROKER_URL = broker_url
|
||||||
|
CELERY_RESULT_BACKEND = broker_url
|
||||||
|
else:
|
||||||
|
CELERY_BROKER_URL = REDIS_URL
|
||||||
|
CELERY_RESULT_BACKEND = REDIS_URL
|
||||||
|
|
||||||
|
CELERY_IMPORTS = (
|
||||||
|
"plane.bgtasks.issue_automation_task",
|
||||||
|
"plane.bgtasks.exporter_expired_task",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
# Sentry Settings
|
||||||
|
# Enable Sentry Settings
|
||||||
|
if bool(os.environ.get("SENTRY_DSN", False)):
|
||||||
|
sentry_sdk.init(
|
||||||
|
dsn=os.environ.get("SENTRY_DSN", ""),
|
||||||
|
integrations=[
|
||||||
|
DjangoIntegration(),
|
||||||
|
RedisIntegration(),
|
||||||
|
CeleryIntegration(monitor_beat_tasks=True),
|
||||||
|
],
|
||||||
|
traces_sample_rate=1,
|
||||||
|
send_default_pii=True,
|
||||||
|
environment=os.environ.get("ENVIRONMENT", "development"),
|
||||||
|
profiles_sample_rate=1.0,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
# Application Envs
|
||||||
|
PROXY_BASE_URL = os.environ.get("PROXY_BASE_URL", False) # For External
|
||||||
|
SLACK_BOT_TOKEN = os.environ.get("SLACK_BOT_TOKEN", False)
|
||||||
|
FILE_SIZE_LIMIT = int(os.environ.get("FILE_SIZE_LIMIT", 5242880))
|
||||||
|
ENABLE_SIGNUP = os.environ.get("ENABLE_SIGNUP", "1") == "1"
|
||||||
|
|
||||||
|
# Unsplash Access key
|
||||||
|
UNSPLASH_ACCESS_KEY = os.environ.get("UNSPLASH_ACCESS_KEY")
|
||||||
|
# Github Access Token
|
||||||
|
GITHUB_ACCESS_TOKEN = os.environ.get("GITHUB_ACCESS_TOKEN", False)
|
||||||
|
|
||||||
|
# Analytics
|
||||||
|
ANALYTICS_SECRET_KEY = os.environ.get("ANALYTICS_SECRET_KEY", False)
|
||||||
|
ANALYTICS_BASE_API = os.environ.get("ANALYTICS_BASE_API", False)
|
||||||
|
|
||||||
|
# Open AI Settings
|
||||||
|
OPENAI_API_BASE = os.environ.get("OPENAI_API_BASE", "https://api.openai.com/v1")
|
||||||
|
OPENAI_API_KEY = os.environ.get("OPENAI_API_KEY", False)
|
||||||
|
GPT_ENGINE = os.environ.get("GPT_ENGINE", "gpt-3.5-turbo")
|
||||||
|
|
||||||
|
# Scout Settings
|
||||||
|
SCOUT_MONITOR = os.environ.get("SCOUT_MONITOR", False)
|
||||||
|
SCOUT_KEY = os.environ.get("SCOUT_KEY", "")
|
||||||
|
SCOUT_NAME = "Plane"
|
||||||
|
|
||||||
|
# Set the variable true if running in docker environment
|
||||||
|
DOCKERIZED = int(os.environ.get("DOCKERIZED", 1)) == 1
|
||||||
|
USE_MINIO = int(os.environ.get("USE_MINIO", 0)) == 1
|
||||||
|
@ -1,123 +1,39 @@
|
|||||||
"""Development settings and globals."""
|
"""Development settings"""
|
||||||
|
|
||||||
from __future__ import absolute_import
|
|
||||||
|
|
||||||
import dj_database_url
|
|
||||||
import sentry_sdk
|
|
||||||
from sentry_sdk.integrations.django import DjangoIntegration
|
|
||||||
from sentry_sdk.integrations.redis import RedisIntegration
|
|
||||||
|
|
||||||
|
|
||||||
from .common import * # noqa
|
from .common import * # noqa
|
||||||
|
|
||||||
DEBUG = int(os.environ.get("DEBUG", 1)) == 1
|
DEBUG = True
|
||||||
|
|
||||||
ALLOWED_HOSTS = [
|
ALLOWED_HOSTS = [
|
||||||
"*",
|
"*",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
# Debug Toolbar settings
|
||||||
|
INSTALLED_APPS += ("debug_toolbar",)
|
||||||
|
MIDDLEWARE += ("debug_toolbar.middleware.DebugToolbarMiddleware",)
|
||||||
|
|
||||||
|
DEBUG_TOOLBAR_PATCH_SETTINGS = False
|
||||||
|
|
||||||
|
# Only show emails in console don't send it to smtp
|
||||||
EMAIL_BACKEND = "django.core.mail.backends.console.EmailBackend"
|
EMAIL_BACKEND = "django.core.mail.backends.console.EmailBackend"
|
||||||
|
|
||||||
|
|
||||||
DATABASES = {
|
|
||||||
"default": {
|
|
||||||
"ENGINE": "django.db.backends.postgresql",
|
|
||||||
"NAME": os.environ.get("PGUSER", "plane"),
|
|
||||||
"USER": "",
|
|
||||||
"PASSWORD": "",
|
|
||||||
"HOST": os.environ.get("PGHOST", "localhost"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
DOCKERIZED = int(os.environ.get("DOCKERIZED", 0)) == 1
|
|
||||||
|
|
||||||
USE_MINIO = int(os.environ.get("USE_MINIO", 0)) == 1
|
|
||||||
|
|
||||||
FILE_SIZE_LIMIT = int(os.environ.get("FILE_SIZE_LIMIT", 5242880))
|
|
||||||
|
|
||||||
if DOCKERIZED:
|
|
||||||
DATABASES["default"] = dj_database_url.config()
|
|
||||||
|
|
||||||
CACHES = {
|
CACHES = {
|
||||||
"default": {
|
"default": {
|
||||||
"BACKEND": "django.core.cache.backends.locmem.LocMemCache",
|
"BACKEND": "django.core.cache.backends.locmem.LocMemCache",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
INSTALLED_APPS += ("debug_toolbar",)
|
|
||||||
|
|
||||||
MIDDLEWARE += ("debug_toolbar.middleware.DebugToolbarMiddleware",)
|
|
||||||
|
|
||||||
DEBUG_TOOLBAR_PATCH_SETTINGS = False
|
|
||||||
|
|
||||||
INTERNAL_IPS = ("127.0.0.1",)
|
INTERNAL_IPS = ("127.0.0.1",)
|
||||||
|
|
||||||
CORS_ORIGIN_ALLOW_ALL = True
|
CORS_ORIGIN_ALLOW_ALL = True
|
||||||
|
|
||||||
if os.environ.get("SENTRY_DSN", False):
|
|
||||||
sentry_sdk.init(
|
|
||||||
dsn=os.environ.get("SENTRY_DSN"),
|
|
||||||
integrations=[DjangoIntegration(), RedisIntegration()],
|
|
||||||
# If you wish to associate users to errors (assuming you are using
|
|
||||||
# django.contrib.auth) you may enable sending PII data.
|
|
||||||
send_default_pii=True,
|
|
||||||
environment="local",
|
|
||||||
traces_sample_rate=0.7,
|
|
||||||
profiles_sample_rate=1.0,
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
LOGGING = {
|
|
||||||
"version": 1,
|
|
||||||
"disable_existing_loggers": False,
|
|
||||||
"handlers": {
|
|
||||||
"console": {
|
|
||||||
"class": "logging.StreamHandler",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"root": {
|
|
||||||
"handlers": ["console"],
|
|
||||||
"level": "DEBUG",
|
|
||||||
},
|
|
||||||
"loggers": {
|
|
||||||
"*": {
|
|
||||||
"handlers": ["console"],
|
|
||||||
"level": "DEBUG",
|
|
||||||
"propagate": True,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
REDIS_HOST = "localhost"
|
|
||||||
REDIS_PORT = 6379
|
|
||||||
REDIS_URL = os.environ.get("REDIS_URL")
|
|
||||||
|
|
||||||
|
|
||||||
MEDIA_URL = "/uploads/"
|
MEDIA_URL = "/uploads/"
|
||||||
MEDIA_ROOT = os.path.join(BASE_DIR, "uploads")
|
MEDIA_ROOT = os.path.join(BASE_DIR, "uploads")
|
||||||
|
|
||||||
if DOCKERIZED:
|
# For local settings
|
||||||
REDIS_URL = os.environ.get("REDIS_URL")
|
CORS_ALLOW_ALL_ORIGINS = True
|
||||||
|
CORS_ALLOWED_ORIGINS = [
|
||||||
WEB_URL = os.environ.get("WEB_URL", "http://localhost:3000")
|
"http://localhost:3000",
|
||||||
PROXY_BASE_URL = os.environ.get("PROXY_BASE_URL", False)
|
"http://127.0.0.1:3000",
|
||||||
|
"http://localhost:4000",
|
||||||
ANALYTICS_SECRET_KEY = os.environ.get("ANALYTICS_SECRET_KEY", False)
|
"http://127.0.0.1:4000",
|
||||||
ANALYTICS_BASE_API = os.environ.get("ANALYTICS_BASE_API", False)
|
]
|
||||||
|
|
||||||
OPENAI_API_BASE = os.environ.get("OPENAI_API_BASE", "https://api.openai.com/v1")
|
|
||||||
OPENAI_API_KEY = os.environ.get("OPENAI_API_KEY", False)
|
|
||||||
GPT_ENGINE = os.environ.get("GPT_ENGINE", "gpt-3.5-turbo")
|
|
||||||
|
|
||||||
SLACK_BOT_TOKEN = os.environ.get("SLACK_BOT_TOKEN", False)
|
|
||||||
|
|
||||||
LOGGER_BASE_URL = os.environ.get("LOGGER_BASE_URL", False)
|
|
||||||
|
|
||||||
CELERY_RESULT_BACKEND = os.environ.get("REDIS_URL")
|
|
||||||
CELERY_BROKER_URL = os.environ.get("REDIS_URL")
|
|
||||||
|
|
||||||
GITHUB_ACCESS_TOKEN = os.environ.get("GITHUB_ACCESS_TOKEN", False)
|
|
||||||
|
|
||||||
ENABLE_SIGNUP = os.environ.get("ENABLE_SIGNUP", "1") == "1"
|
|
||||||
|
|
||||||
# Unsplash Access key
|
|
||||||
UNSPLASH_ACCESS_KEY = os.environ.get("UNSPLASH_ACCESS_KEY")
|
|
||||||
|
@ -1,282 +1,13 @@
|
|||||||
"""Production settings and globals."""
|
"""Production settings"""
|
||||||
import ssl
|
|
||||||
import certifi
|
|
||||||
|
|
||||||
import dj_database_url
|
|
||||||
|
|
||||||
import sentry_sdk
|
|
||||||
from sentry_sdk.integrations.django import DjangoIntegration
|
|
||||||
from sentry_sdk.integrations.redis import RedisIntegration
|
|
||||||
from urllib.parse import urlparse
|
|
||||||
|
|
||||||
from .common import * # noqa
|
from .common import * # noqa
|
||||||
|
|
||||||
# Database
|
# SECURITY WARNING: don't run with debug turned on in production!
|
||||||
DEBUG = int(os.environ.get("DEBUG", 0)) == 1
|
DEBUG = int(os.environ.get("DEBUG", 0)) == 1
|
||||||
|
|
||||||
if bool(os.environ.get("DATABASE_URL")):
|
|
||||||
# Parse database configuration from $DATABASE_URL
|
|
||||||
DATABASES["default"] = dj_database_url.config()
|
|
||||||
else:
|
|
||||||
DATABASES = {
|
|
||||||
"default": {
|
|
||||||
"ENGINE": "django.db.backends.postgresql",
|
|
||||||
"NAME": os.environ.get("POSTGRES_DB"),
|
|
||||||
"USER": os.environ.get("POSTGRES_USER"),
|
|
||||||
"PASSWORD": os.environ.get("POSTGRES_PASSWORD"),
|
|
||||||
"HOST": os.environ.get("POSTGRES_HOST"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
SITE_ID = 1
|
|
||||||
|
|
||||||
# Set the variable true if running in docker environment
|
|
||||||
DOCKERIZED = int(os.environ.get("DOCKERIZED", 0)) == 1
|
|
||||||
|
|
||||||
USE_MINIO = int(os.environ.get("USE_MINIO", 0)) == 1
|
|
||||||
|
|
||||||
FILE_SIZE_LIMIT = int(os.environ.get("FILE_SIZE_LIMIT", 5242880))
|
|
||||||
|
|
||||||
# Enable Connection Pooling (if desired)
|
|
||||||
# DATABASES['default']['ENGINE'] = 'django_postgrespool'
|
|
||||||
|
|
||||||
# Honor the 'X-Forwarded-Proto' header for request.is_secure()
|
# Honor the 'X-Forwarded-Proto' header for request.is_secure()
|
||||||
SECURE_PROXY_SSL_HEADER = ("HTTP_X_FORWARDED_PROTO", "https")
|
SECURE_PROXY_SSL_HEADER = ("HTTP_X_FORWARDED_PROTO", "https")
|
||||||
|
|
||||||
|
|
||||||
# TODO: Make it FALSE and LIST DOMAINS IN FULL PROD.
|
|
||||||
CORS_ALLOW_ALL_ORIGINS = True
|
|
||||||
|
|
||||||
|
|
||||||
CORS_ALLOW_METHODS = [
|
|
||||||
"DELETE",
|
|
||||||
"GET",
|
|
||||||
"OPTIONS",
|
|
||||||
"PATCH",
|
|
||||||
"POST",
|
|
||||||
"PUT",
|
|
||||||
]
|
|
||||||
|
|
||||||
CORS_ALLOW_HEADERS = [
|
|
||||||
"accept",
|
|
||||||
"accept-encoding",
|
|
||||||
"authorization",
|
|
||||||
"content-type",
|
|
||||||
"dnt",
|
|
||||||
"origin",
|
|
||||||
"user-agent",
|
|
||||||
"x-csrftoken",
|
|
||||||
"x-requested-with",
|
|
||||||
]
|
|
||||||
|
|
||||||
CORS_ALLOW_CREDENTIALS = True
|
|
||||||
|
|
||||||
INSTALLED_APPS += ("scout_apm.django",)
|
INSTALLED_APPS += ("scout_apm.django",)
|
||||||
|
|
||||||
STORAGES = {
|
|
||||||
"staticfiles": {
|
|
||||||
"BACKEND": "whitenoise.storage.CompressedManifestStaticFilesStorage",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
if bool(os.environ.get("SENTRY_DSN", False)):
|
|
||||||
sentry_sdk.init(
|
|
||||||
dsn=os.environ.get("SENTRY_DSN", ""),
|
|
||||||
integrations=[DjangoIntegration(), RedisIntegration()],
|
|
||||||
# If you wish to associate users to errors (assuming you are using
|
|
||||||
# django.contrib.auth) you may enable sending PII data.
|
|
||||||
traces_sample_rate=1,
|
|
||||||
send_default_pii=True,
|
|
||||||
environment="production",
|
|
||||||
profiles_sample_rate=1.0,
|
|
||||||
)
|
|
||||||
|
|
||||||
if DOCKERIZED and USE_MINIO:
|
|
||||||
INSTALLED_APPS += ("storages",)
|
|
||||||
STORAGES["default"] = {"BACKEND": "storages.backends.s3boto3.S3Boto3Storage"}
|
|
||||||
# The AWS access key to use.
|
|
||||||
AWS_ACCESS_KEY_ID = os.environ.get("AWS_ACCESS_KEY_ID", "access-key")
|
|
||||||
# The AWS secret access key to use.
|
|
||||||
AWS_SECRET_ACCESS_KEY = os.environ.get("AWS_SECRET_ACCESS_KEY", "secret-key")
|
|
||||||
# The name of the bucket to store files in.
|
|
||||||
AWS_STORAGE_BUCKET_NAME = os.environ.get("AWS_S3_BUCKET_NAME", "uploads")
|
|
||||||
# The full URL to the S3 endpoint. Leave blank to use the default region URL.
|
|
||||||
AWS_S3_ENDPOINT_URL = os.environ.get(
|
|
||||||
"AWS_S3_ENDPOINT_URL", "http://plane-minio:9000"
|
|
||||||
)
|
|
||||||
# Default permissions
|
|
||||||
AWS_DEFAULT_ACL = "public-read"
|
|
||||||
AWS_QUERYSTRING_AUTH = False
|
|
||||||
AWS_S3_FILE_OVERWRITE = False
|
|
||||||
|
|
||||||
# Custom Domain settings
|
|
||||||
parsed_url = urlparse(os.environ.get("WEB_URL", "http://localhost"))
|
|
||||||
AWS_S3_CUSTOM_DOMAIN = f"{parsed_url.netloc}/{AWS_STORAGE_BUCKET_NAME}"
|
|
||||||
AWS_S3_URL_PROTOCOL = f"{parsed_url.scheme}:"
|
|
||||||
else:
|
|
||||||
# The AWS region to connect to.
|
|
||||||
AWS_REGION = os.environ.get("AWS_REGION", "")
|
|
||||||
|
|
||||||
# The AWS access key to use.
|
|
||||||
AWS_ACCESS_KEY_ID = os.environ.get("AWS_ACCESS_KEY_ID", "")
|
|
||||||
|
|
||||||
# The AWS secret access key to use.
|
|
||||||
AWS_SECRET_ACCESS_KEY = os.environ.get("AWS_SECRET_ACCESS_KEY", "")
|
|
||||||
|
|
||||||
# The optional AWS session token to use.
|
|
||||||
# AWS_SESSION_TOKEN = ""
|
|
||||||
|
|
||||||
# The name of the bucket to store files in.
|
|
||||||
AWS_S3_BUCKET_NAME = os.environ.get("AWS_S3_BUCKET_NAME")
|
|
||||||
|
|
||||||
# How to construct S3 URLs ("auto", "path", "virtual").
|
|
||||||
AWS_S3_ADDRESSING_STYLE = "auto"
|
|
||||||
|
|
||||||
# The full URL to the S3 endpoint. Leave blank to use the default region URL.
|
|
||||||
AWS_S3_ENDPOINT_URL = os.environ.get("AWS_S3_ENDPOINT_URL", "")
|
|
||||||
|
|
||||||
# A prefix to be applied to every stored file. This will be joined to every filename using the "/" separator.
|
|
||||||
AWS_S3_KEY_PREFIX = ""
|
|
||||||
|
|
||||||
# Whether to enable authentication for stored files. If True, then generated URLs will include an authentication
|
|
||||||
# token valid for `AWS_S3_MAX_AGE_SECONDS`. If False, then generated URLs will not include an authentication token,
|
|
||||||
# and their permissions will be set to "public-read".
|
|
||||||
AWS_S3_BUCKET_AUTH = False
|
|
||||||
|
|
||||||
# How long generated URLs are valid for. This affects the expiry of authentication tokens if `AWS_S3_BUCKET_AUTH`
|
|
||||||
# is True. It also affects the "Cache-Control" header of the files.
|
|
||||||
# Important: Changing this setting will not affect existing files.
|
|
||||||
AWS_S3_MAX_AGE_SECONDS = 60 * 60 # 1 hours.
|
|
||||||
|
|
||||||
# A URL prefix to be used for generated URLs. This is useful if your bucket is served through a CDN. This setting
|
|
||||||
# cannot be used with `AWS_S3_BUCKET_AUTH`.
|
|
||||||
AWS_S3_PUBLIC_URL = ""
|
|
||||||
|
|
||||||
# If True, then files will be stored with reduced redundancy. Check the S3 documentation and make sure you
|
|
||||||
# understand the consequences before enabling.
|
|
||||||
# Important: Changing this setting will not affect existing files.
|
|
||||||
AWS_S3_REDUCED_REDUNDANCY = False
|
|
||||||
|
|
||||||
# The Content-Disposition header used when the file is downloaded. This can be a string, or a function taking a
|
|
||||||
# single `name` argument.
|
|
||||||
# Important: Changing this setting will not affect existing files.
|
|
||||||
AWS_S3_CONTENT_DISPOSITION = ""
|
|
||||||
|
|
||||||
# The Content-Language header used when the file is downloaded. This can be a string, or a function taking a
|
|
||||||
# single `name` argument.
|
|
||||||
# Important: Changing this setting will not affect existing files.
|
|
||||||
AWS_S3_CONTENT_LANGUAGE = ""
|
|
||||||
|
|
||||||
# A mapping of custom metadata for each file. Each value can be a string, or a function taking a
|
|
||||||
# single `name` argument.
|
|
||||||
# Important: Changing this setting will not affect existing files.
|
|
||||||
AWS_S3_METADATA = {}
|
|
||||||
|
|
||||||
# If True, then files will be stored using AES256 server-side encryption.
|
|
||||||
# If this is a string value (e.g., "aws:kms"), that encryption type will be used.
|
|
||||||
# Otherwise, server-side encryption is not be enabled.
|
|
||||||
# Important: Changing this setting will not affect existing files.
|
|
||||||
AWS_S3_ENCRYPT_KEY = False
|
|
||||||
|
|
||||||
# The AWS S3 KMS encryption key ID (the `SSEKMSKeyId` parameter) is set from this string if present.
|
|
||||||
# This is only relevant if AWS S3 KMS server-side encryption is enabled (above).
|
|
||||||
# AWS_S3_KMS_ENCRYPTION_KEY_ID = ""
|
|
||||||
|
|
||||||
# If True, then text files will be stored using gzip content encoding. Files will only be gzipped if their
|
|
||||||
# compressed size is smaller than their uncompressed size.
|
|
||||||
# Important: Changing this setting will not affect existing files.
|
|
||||||
AWS_S3_GZIP = True
|
|
||||||
|
|
||||||
# The signature version to use for S3 requests.
|
|
||||||
AWS_S3_SIGNATURE_VERSION = None
|
|
||||||
|
|
||||||
# If True, then files with the same name will overwrite each other. By default it's set to False to have
|
|
||||||
# extra characters appended.
|
|
||||||
AWS_S3_FILE_OVERWRITE = False
|
|
||||||
|
|
||||||
STORAGES["default"] = {
|
|
||||||
"BACKEND": "django_s3_storage.storage.S3Storage",
|
|
||||||
}
|
|
||||||
# AWS Settings End
|
|
||||||
|
|
||||||
# Enable Connection Pooling (if desired)
|
|
||||||
# DATABASES['default']['ENGINE'] = 'django_postgrespool'
|
|
||||||
|
|
||||||
# Honor the 'X-Forwarded-Proto' header for request.is_secure()
|
# Honor the 'X-Forwarded-Proto' header for request.is_secure()
|
||||||
SECURE_PROXY_SSL_HEADER = ("HTTP_X_FORWARDED_PROTO", "https")
|
SECURE_PROXY_SSL_HEADER = ("HTTP_X_FORWARDED_PROTO", "https")
|
||||||
|
|
||||||
# Allow all host headers
|
|
||||||
ALLOWED_HOSTS = [
|
|
||||||
"*",
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
SESSION_COOKIE_SECURE = True
|
|
||||||
CSRF_COOKIE_SECURE = True
|
|
||||||
|
|
||||||
|
|
||||||
REDIS_URL = os.environ.get("REDIS_URL")
|
|
||||||
|
|
||||||
if DOCKERIZED:
|
|
||||||
CACHES = {
|
|
||||||
"default": {
|
|
||||||
"BACKEND": "django_redis.cache.RedisCache",
|
|
||||||
"LOCATION": REDIS_URL,
|
|
||||||
"OPTIONS": {
|
|
||||||
"CLIENT_CLASS": "django_redis.client.DefaultClient",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else:
|
|
||||||
CACHES = {
|
|
||||||
"default": {
|
|
||||||
"BACKEND": "django_redis.cache.RedisCache",
|
|
||||||
"LOCATION": REDIS_URL,
|
|
||||||
"OPTIONS": {
|
|
||||||
"CLIENT_CLASS": "django_redis.client.DefaultClient",
|
|
||||||
"CONNECTION_POOL_KWARGS": {"ssl_cert_reqs": False},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
WEB_URL = os.environ.get("WEB_URL", "https://app.plane.so")
|
|
||||||
|
|
||||||
PROXY_BASE_URL = os.environ.get("PROXY_BASE_URL", False)
|
|
||||||
|
|
||||||
ANALYTICS_SECRET_KEY = os.environ.get("ANALYTICS_SECRET_KEY", False)
|
|
||||||
ANALYTICS_BASE_API = os.environ.get("ANALYTICS_BASE_API", False)
|
|
||||||
|
|
||||||
OPENAI_API_BASE = os.environ.get("OPENAI_API_BASE", "https://api.openai.com/v1")
|
|
||||||
OPENAI_API_KEY = os.environ.get("OPENAI_API_KEY", False)
|
|
||||||
GPT_ENGINE = os.environ.get("GPT_ENGINE", "gpt-3.5-turbo")
|
|
||||||
|
|
||||||
SLACK_BOT_TOKEN = os.environ.get("SLACK_BOT_TOKEN", False)
|
|
||||||
|
|
||||||
LOGGER_BASE_URL = os.environ.get("LOGGER_BASE_URL", False)
|
|
||||||
|
|
||||||
redis_url = os.environ.get("REDIS_URL")
|
|
||||||
broker_url = (
|
|
||||||
f"{redis_url}?ssl_cert_reqs={ssl.CERT_NONE.name}&ssl_ca_certs={certifi.where()}"
|
|
||||||
)
|
|
||||||
|
|
||||||
if DOCKERIZED:
|
|
||||||
CELERY_BROKER_URL = REDIS_URL
|
|
||||||
CELERY_RESULT_BACKEND = REDIS_URL
|
|
||||||
else:
|
|
||||||
CELERY_BROKER_URL = broker_url
|
|
||||||
CELERY_RESULT_BACKEND = broker_url
|
|
||||||
|
|
||||||
GITHUB_ACCESS_TOKEN = os.environ.get("GITHUB_ACCESS_TOKEN", False)
|
|
||||||
|
|
||||||
# Enable or Disable signups
|
|
||||||
ENABLE_SIGNUP = os.environ.get("ENABLE_SIGNUP", "1") == "1"
|
|
||||||
|
|
||||||
# Scout Settings
|
|
||||||
SCOUT_MONITOR = os.environ.get("SCOUT_MONITOR", False)
|
|
||||||
SCOUT_KEY = os.environ.get("SCOUT_KEY", "")
|
|
||||||
SCOUT_NAME = "Plane"
|
|
||||||
|
|
||||||
# Unsplash Access key
|
|
||||||
UNSPLASH_ACCESS_KEY = os.environ.get("UNSPLASH_ACCESS_KEY")
|
|
||||||
|
@ -1,129 +0,0 @@
|
|||||||
"""Self hosted settings and globals."""
|
|
||||||
from urllib.parse import urlparse
|
|
||||||
|
|
||||||
import dj_database_url
|
|
||||||
from urllib.parse import urlparse
|
|
||||||
|
|
||||||
|
|
||||||
from .common import * # noqa
|
|
||||||
|
|
||||||
# Database
|
|
||||||
DEBUG = int(os.environ.get("DEBUG", 0)) == 1
|
|
||||||
|
|
||||||
# Docker configurations
|
|
||||||
DOCKERIZED = 1
|
|
||||||
USE_MINIO = 1
|
|
||||||
|
|
||||||
DATABASES = {
|
|
||||||
"default": {
|
|
||||||
"ENGINE": "django.db.backends.postgresql",
|
|
||||||
"NAME": "plane",
|
|
||||||
"USER": os.environ.get("PGUSER", ""),
|
|
||||||
"PASSWORD": os.environ.get("PGPASSWORD", ""),
|
|
||||||
"HOST": os.environ.get("PGHOST", ""),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
# Parse database configuration from $DATABASE_URL
|
|
||||||
DATABASES["default"] = dj_database_url.config()
|
|
||||||
SITE_ID = 1
|
|
||||||
|
|
||||||
# File size limit
|
|
||||||
FILE_SIZE_LIMIT = int(os.environ.get("FILE_SIZE_LIMIT", 5242880))
|
|
||||||
|
|
||||||
CORS_ALLOW_METHODS = [
|
|
||||||
"DELETE",
|
|
||||||
"GET",
|
|
||||||
"OPTIONS",
|
|
||||||
"PATCH",
|
|
||||||
"POST",
|
|
||||||
"PUT",
|
|
||||||
]
|
|
||||||
|
|
||||||
CORS_ALLOW_HEADERS = [
|
|
||||||
"accept",
|
|
||||||
"accept-encoding",
|
|
||||||
"authorization",
|
|
||||||
"content-type",
|
|
||||||
"dnt",
|
|
||||||
"origin",
|
|
||||||
"user-agent",
|
|
||||||
"x-csrftoken",
|
|
||||||
"x-requested-with",
|
|
||||||
]
|
|
||||||
|
|
||||||
CORS_ALLOW_CREDENTIALS = True
|
|
||||||
CORS_ALLOW_ALL_ORIGINS = True
|
|
||||||
|
|
||||||
STORAGES = {
|
|
||||||
"staticfiles": {
|
|
||||||
"BACKEND": "whitenoise.storage.CompressedManifestStaticFilesStorage",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
INSTALLED_APPS += ("storages",)
|
|
||||||
STORAGES["default"] = {"BACKEND": "storages.backends.s3boto3.S3Boto3Storage"}
|
|
||||||
# The AWS access key to use.
|
|
||||||
AWS_ACCESS_KEY_ID = os.environ.get("AWS_ACCESS_KEY_ID", "access-key")
|
|
||||||
# The AWS secret access key to use.
|
|
||||||
AWS_SECRET_ACCESS_KEY = os.environ.get("AWS_SECRET_ACCESS_KEY", "secret-key")
|
|
||||||
# The name of the bucket to store files in.
|
|
||||||
AWS_STORAGE_BUCKET_NAME = os.environ.get("AWS_S3_BUCKET_NAME", "uploads")
|
|
||||||
# The full URL to the S3 endpoint. Leave blank to use the default region URL.
|
|
||||||
AWS_S3_ENDPOINT_URL = os.environ.get(
|
|
||||||
"AWS_S3_ENDPOINT_URL", "http://plane-minio:9000"
|
|
||||||
)
|
|
||||||
# Default permissions
|
|
||||||
AWS_DEFAULT_ACL = "public-read"
|
|
||||||
AWS_QUERYSTRING_AUTH = False
|
|
||||||
AWS_S3_FILE_OVERWRITE = False
|
|
||||||
|
|
||||||
# Custom Domain settings
|
|
||||||
parsed_url = urlparse(os.environ.get("WEB_URL", "http://localhost"))
|
|
||||||
AWS_S3_CUSTOM_DOMAIN = f"{parsed_url.netloc}/{AWS_STORAGE_BUCKET_NAME}"
|
|
||||||
AWS_S3_URL_PROTOCOL = f"{parsed_url.scheme}:"
|
|
||||||
|
|
||||||
# Honor the 'X-Forwarded-Proto' header for request.is_secure()
|
|
||||||
SECURE_PROXY_SSL_HEADER = ("HTTP_X_FORWARDED_PROTO", "https")
|
|
||||||
|
|
||||||
# Allow all host headers
|
|
||||||
ALLOWED_HOSTS = [
|
|
||||||
"*",
|
|
||||||
]
|
|
||||||
|
|
||||||
# Security settings
|
|
||||||
SESSION_COOKIE_SECURE = True
|
|
||||||
CSRF_COOKIE_SECURE = True
|
|
||||||
|
|
||||||
# Redis URL
|
|
||||||
REDIS_URL = os.environ.get("REDIS_URL")
|
|
||||||
|
|
||||||
# Caches
|
|
||||||
CACHES = {
|
|
||||||
"default": {
|
|
||||||
"BACKEND": "django_redis.cache.RedisCache",
|
|
||||||
"LOCATION": REDIS_URL,
|
|
||||||
"OPTIONS": {
|
|
||||||
"CLIENT_CLASS": "django_redis.client.DefaultClient",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
# URL used for email redirects
|
|
||||||
WEB_URL = os.environ.get("WEB_URL", "http://localhost")
|
|
||||||
|
|
||||||
# Celery settings
|
|
||||||
CELERY_BROKER_URL = REDIS_URL
|
|
||||||
CELERY_RESULT_BACKEND = REDIS_URL
|
|
||||||
|
|
||||||
# Enable or Disable signups
|
|
||||||
ENABLE_SIGNUP = os.environ.get("ENABLE_SIGNUP", "1") == "1"
|
|
||||||
|
|
||||||
# Analytics
|
|
||||||
ANALYTICS_BASE_API = False
|
|
||||||
|
|
||||||
# OPEN AI Settings
|
|
||||||
OPENAI_API_BASE = os.environ.get("OPENAI_API_BASE", "https://api.openai.com/v1")
|
|
||||||
OPENAI_API_KEY = os.environ.get("OPENAI_API_KEY", False)
|
|
||||||
GPT_ENGINE = os.environ.get("GPT_ENGINE", "gpt-3.5-turbo")
|
|
||||||
|
|
@ -1,223 +0,0 @@
|
|||||||
"""Production settings and globals."""
|
|
||||||
from urllib.parse import urlparse
|
|
||||||
import ssl
|
|
||||||
import certifi
|
|
||||||
|
|
||||||
import dj_database_url
|
|
||||||
|
|
||||||
import sentry_sdk
|
|
||||||
from sentry_sdk.integrations.django import DjangoIntegration
|
|
||||||
from sentry_sdk.integrations.redis import RedisIntegration
|
|
||||||
|
|
||||||
from .common import * # noqa
|
|
||||||
|
|
||||||
# Database
|
|
||||||
DEBUG = int(os.environ.get("DEBUG", 1)) == 1
|
|
||||||
DATABASES = {
|
|
||||||
"default": {
|
|
||||||
"ENGINE": "django.db.backends.postgresql",
|
|
||||||
"NAME": os.environ.get("PGUSER", "plane"),
|
|
||||||
"USER": "",
|
|
||||||
"PASSWORD": "",
|
|
||||||
"HOST": os.environ.get("PGHOST", "localhost"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
# CORS WHITELIST ON PROD
|
|
||||||
CORS_ORIGIN_WHITELIST = [
|
|
||||||
# "https://example.com",
|
|
||||||
# "https://sub.example.com",
|
|
||||||
# "http://localhost:8080",
|
|
||||||
# "http://127.0.0.1:9000"
|
|
||||||
]
|
|
||||||
# Parse database configuration from $DATABASE_URL
|
|
||||||
DATABASES["default"] = dj_database_url.config()
|
|
||||||
SITE_ID = 1
|
|
||||||
|
|
||||||
# Enable Connection Pooling (if desired)
|
|
||||||
# DATABASES['default']['ENGINE'] = 'django_postgrespool'
|
|
||||||
|
|
||||||
# Honor the 'X-Forwarded-Proto' header for request.is_secure()
|
|
||||||
SECURE_PROXY_SSL_HEADER = ("HTTP_X_FORWARDED_PROTO", "https")
|
|
||||||
|
|
||||||
# Allow all host headers
|
|
||||||
ALLOWED_HOSTS = ["*"]
|
|
||||||
|
|
||||||
# TODO: Make it FALSE and LIST DOMAINS IN FULL PROD.
|
|
||||||
CORS_ALLOW_ALL_ORIGINS = True
|
|
||||||
|
|
||||||
STORAGES = {
|
|
||||||
"staticfiles": {
|
|
||||||
"BACKEND": "whitenoise.storage.CompressedManifestStaticFilesStorage",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
# Make true if running in a docker environment
|
|
||||||
DOCKERIZED = int(os.environ.get("DOCKERIZED", 0)) == 1
|
|
||||||
FILE_SIZE_LIMIT = int(os.environ.get("FILE_SIZE_LIMIT", 5242880))
|
|
||||||
USE_MINIO = int(os.environ.get("USE_MINIO", 0)) == 1
|
|
||||||
|
|
||||||
sentry_sdk.init(
|
|
||||||
dsn=os.environ.get("SENTRY_DSN"),
|
|
||||||
integrations=[DjangoIntegration(), RedisIntegration()],
|
|
||||||
# If you wish to associate users to errors (assuming you are using
|
|
||||||
# django.contrib.auth) you may enable sending PII data.
|
|
||||||
traces_sample_rate=1,
|
|
||||||
send_default_pii=True,
|
|
||||||
environment="staging",
|
|
||||||
profiles_sample_rate=1.0,
|
|
||||||
)
|
|
||||||
|
|
||||||
# The AWS region to connect to.
|
|
||||||
AWS_REGION = os.environ.get("AWS_REGION")
|
|
||||||
|
|
||||||
# The AWS access key to use.
|
|
||||||
AWS_ACCESS_KEY_ID = os.environ.get("AWS_ACCESS_KEY_ID")
|
|
||||||
|
|
||||||
# The AWS secret access key to use.
|
|
||||||
AWS_SECRET_ACCESS_KEY = os.environ.get("AWS_SECRET_ACCESS_KEY")
|
|
||||||
|
|
||||||
# The optional AWS session token to use.
|
|
||||||
# AWS_SESSION_TOKEN = ""
|
|
||||||
|
|
||||||
|
|
||||||
# The name of the bucket to store files in.
|
|
||||||
AWS_S3_BUCKET_NAME = os.environ.get("AWS_S3_BUCKET_NAME")
|
|
||||||
|
|
||||||
# How to construct S3 URLs ("auto", "path", "virtual").
|
|
||||||
AWS_S3_ADDRESSING_STYLE = "auto"
|
|
||||||
|
|
||||||
# The full URL to the S3 endpoint. Leave blank to use the default region URL.
|
|
||||||
AWS_S3_ENDPOINT_URL = os.environ.get("AWS_S3_ENDPOINT_URL", "")
|
|
||||||
|
|
||||||
# A prefix to be applied to every stored file. This will be joined to every filename using the "/" separator.
|
|
||||||
AWS_S3_KEY_PREFIX = ""
|
|
||||||
|
|
||||||
# Whether to enable authentication for stored files. If True, then generated URLs will include an authentication
|
|
||||||
# token valid for `AWS_S3_MAX_AGE_SECONDS`. If False, then generated URLs will not include an authentication token,
|
|
||||||
# and their permissions will be set to "public-read".
|
|
||||||
AWS_S3_BUCKET_AUTH = False
|
|
||||||
|
|
||||||
# How long generated URLs are valid for. This affects the expiry of authentication tokens if `AWS_S3_BUCKET_AUTH`
|
|
||||||
# is True. It also affects the "Cache-Control" header of the files.
|
|
||||||
# Important: Changing this setting will not affect existing files.
|
|
||||||
AWS_S3_MAX_AGE_SECONDS = 60 * 60 # 1 hours.
|
|
||||||
|
|
||||||
# A URL prefix to be used for generated URLs. This is useful if your bucket is served through a CDN. This setting
|
|
||||||
# cannot be used with `AWS_S3_BUCKET_AUTH`.
|
|
||||||
AWS_S3_PUBLIC_URL = ""
|
|
||||||
|
|
||||||
# If True, then files will be stored with reduced redundancy. Check the S3 documentation and make sure you
|
|
||||||
# understand the consequences before enabling.
|
|
||||||
# Important: Changing this setting will not affect existing files.
|
|
||||||
AWS_S3_REDUCED_REDUNDANCY = False
|
|
||||||
|
|
||||||
# The Content-Disposition header used when the file is downloaded. This can be a string, or a function taking a
|
|
||||||
# single `name` argument.
|
|
||||||
# Important: Changing this setting will not affect existing files.
|
|
||||||
AWS_S3_CONTENT_DISPOSITION = ""
|
|
||||||
|
|
||||||
# The Content-Language header used when the file is downloaded. This can be a string, or a function taking a
|
|
||||||
# single `name` argument.
|
|
||||||
# Important: Changing this setting will not affect existing files.
|
|
||||||
AWS_S3_CONTENT_LANGUAGE = ""
|
|
||||||
|
|
||||||
# A mapping of custom metadata for each file. Each value can be a string, or a function taking a
|
|
||||||
# single `name` argument.
|
|
||||||
# Important: Changing this setting will not affect existing files.
|
|
||||||
AWS_S3_METADATA = {}
|
|
||||||
|
|
||||||
# If True, then files will be stored using AES256 server-side encryption.
|
|
||||||
# If this is a string value (e.g., "aws:kms"), that encryption type will be used.
|
|
||||||
# Otherwise, server-side encryption is not be enabled.
|
|
||||||
# Important: Changing this setting will not affect existing files.
|
|
||||||
AWS_S3_ENCRYPT_KEY = False
|
|
||||||
|
|
||||||
# The AWS S3 KMS encryption key ID (the `SSEKMSKeyId` parameter) is set from this string if present.
|
|
||||||
# This is only relevant if AWS S3 KMS server-side encryption is enabled (above).
|
|
||||||
# AWS_S3_KMS_ENCRYPTION_KEY_ID = ""
|
|
||||||
|
|
||||||
# If True, then text files will be stored using gzip content encoding. Files will only be gzipped if their
|
|
||||||
# compressed size is smaller than their uncompressed size.
|
|
||||||
# Important: Changing this setting will not affect existing files.
|
|
||||||
AWS_S3_GZIP = True
|
|
||||||
|
|
||||||
# The signature version to use for S3 requests.
|
|
||||||
AWS_S3_SIGNATURE_VERSION = None
|
|
||||||
|
|
||||||
# If True, then files with the same name will overwrite each other. By default it's set to False to have
|
|
||||||
# extra characters appended.
|
|
||||||
AWS_S3_FILE_OVERWRITE = False
|
|
||||||
|
|
||||||
# AWS Settings End
|
|
||||||
STORAGES["default"] = {
|
|
||||||
"BACKEND": "django_s3_storage.storage.S3Storage",
|
|
||||||
}
|
|
||||||
|
|
||||||
# Enable Connection Pooling (if desired)
|
|
||||||
# DATABASES['default']['ENGINE'] = 'django_postgrespool'
|
|
||||||
|
|
||||||
# Honor the 'X-Forwarded-Proto' header for request.is_secure()
|
|
||||||
SECURE_PROXY_SSL_HEADER = ("HTTP_X_FORWARDED_PROTO", "https")
|
|
||||||
|
|
||||||
# Allow all host headers
|
|
||||||
ALLOWED_HOSTS = [
|
|
||||||
"*",
|
|
||||||
]
|
|
||||||
|
|
||||||
SESSION_COOKIE_SECURE = True
|
|
||||||
CSRF_COOKIE_SECURE = True
|
|
||||||
|
|
||||||
|
|
||||||
REDIS_URL = os.environ.get("REDIS_URL")
|
|
||||||
|
|
||||||
CACHES = {
|
|
||||||
"default": {
|
|
||||||
"BACKEND": "django_redis.cache.RedisCache",
|
|
||||||
"LOCATION": REDIS_URL,
|
|
||||||
"OPTIONS": {
|
|
||||||
"CLIENT_CLASS": "django_redis.client.DefaultClient",
|
|
||||||
"CONNECTION_POOL_KWARGS": {"ssl_cert_reqs": False},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
RQ_QUEUES = {
|
|
||||||
"default": {
|
|
||||||
"USE_REDIS_CACHE": "default",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
WEB_URL = os.environ.get("WEB_URL")
|
|
||||||
|
|
||||||
PROXY_BASE_URL = os.environ.get("PROXY_BASE_URL", False)
|
|
||||||
|
|
||||||
ANALYTICS_SECRET_KEY = os.environ.get("ANALYTICS_SECRET_KEY", False)
|
|
||||||
ANALYTICS_BASE_API = os.environ.get("ANALYTICS_BASE_API", False)
|
|
||||||
|
|
||||||
|
|
||||||
OPENAI_API_BASE = os.environ.get("OPENAI_API_BASE", "https://api.openai.com/v1")
|
|
||||||
OPENAI_API_KEY = os.environ.get("OPENAI_API_KEY", False)
|
|
||||||
GPT_ENGINE = os.environ.get("GPT_ENGINE", "gpt-3.5-turbo")
|
|
||||||
|
|
||||||
SLACK_BOT_TOKEN = os.environ.get("SLACK_BOT_TOKEN", False)
|
|
||||||
|
|
||||||
LOGGER_BASE_URL = os.environ.get("LOGGER_BASE_URL", False)
|
|
||||||
|
|
||||||
redis_url = os.environ.get("REDIS_URL")
|
|
||||||
broker_url = (
|
|
||||||
f"{redis_url}?ssl_cert_reqs={ssl.CERT_NONE.name}&ssl_ca_certs={certifi.where()}"
|
|
||||||
)
|
|
||||||
|
|
||||||
CELERY_RESULT_BACKEND = broker_url
|
|
||||||
CELERY_BROKER_URL = broker_url
|
|
||||||
|
|
||||||
GITHUB_ACCESS_TOKEN = os.environ.get("GITHUB_ACCESS_TOKEN", False)
|
|
||||||
|
|
||||||
ENABLE_SIGNUP = os.environ.get("ENABLE_SIGNUP", "1") == "1"
|
|
||||||
|
|
||||||
|
|
||||||
# Unsplash Access key
|
|
||||||
UNSPLASH_ACCESS_KEY = os.environ.get("UNSPLASH_ACCESS_KEY")
|
|
@ -1,45 +1,9 @@
|
|||||||
from __future__ import absolute_import
|
"""Test Settings"""
|
||||||
|
|
||||||
from .common import * # noqa
|
from .common import * # noqa
|
||||||
|
|
||||||
DEBUG = True
|
DEBUG = True
|
||||||
|
|
||||||
INSTALLED_APPS.append("plane.tests")
|
# Send it in a dummy outbox
|
||||||
|
EMAIL_BACKEND = "django.core.mail.backends.locmem.EmailBackend"
|
||||||
|
|
||||||
if os.environ.get('GITHUB_WORKFLOW'):
|
INSTALLED_APPS.append("plane.tests",)
|
||||||
DATABASES = {
|
|
||||||
'default': {
|
|
||||||
'ENGINE': 'django.db.backends.postgresql',
|
|
||||||
'NAME': 'github_actions',
|
|
||||||
'USER': 'postgres',
|
|
||||||
'PASSWORD': 'postgres',
|
|
||||||
'HOST': '127.0.0.1',
|
|
||||||
'PORT': '5432',
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else:
|
|
||||||
DATABASES = {
|
|
||||||
'default': {
|
|
||||||
'ENGINE': 'django.db.backends.postgresql',
|
|
||||||
'NAME': 'plane_test',
|
|
||||||
'USER': 'postgres',
|
|
||||||
'PASSWORD': 'password123',
|
|
||||||
'HOST': '127.0.0.1',
|
|
||||||
'PORT': '5432',
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
REDIS_HOST = "localhost"
|
|
||||||
REDIS_PORT = 6379
|
|
||||||
REDIS_URL = False
|
|
||||||
|
|
||||||
RQ_QUEUES = {
|
|
||||||
"default": {
|
|
||||||
"HOST": "localhost",
|
|
||||||
"PORT": 6379,
|
|
||||||
"DB": 0,
|
|
||||||
"DEFAULT_TIMEOUT": 360,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
WEB_URL = "http://localhost:3000"
|
|
||||||
|
@ -10,6 +10,7 @@ x-app-env : &app-env
|
|||||||
- SENTRY_DSN=${SENTRY_DSN:-""}
|
- SENTRY_DSN=${SENTRY_DSN:-""}
|
||||||
- GITHUB_CLIENT_SECRET=${GITHUB_CLIENT_SECRET:-""}
|
- GITHUB_CLIENT_SECRET=${GITHUB_CLIENT_SECRET:-""}
|
||||||
- DOCKERIZED=${DOCKERIZED:-1}
|
- DOCKERIZED=${DOCKERIZED:-1}
|
||||||
|
- CORS_ALLOWED_ORIGINS=${CORS_ALLOWED_ORIGINS:-http://localhost}
|
||||||
# Gunicorn Workers
|
# Gunicorn Workers
|
||||||
- GUNICORN_WORKERS=${GUNICORN_WORKERS:-2}
|
- GUNICORN_WORKERS=${GUNICORN_WORKERS:-2}
|
||||||
#DB SETTINGS
|
#DB SETTINGS
|
||||||
|
@ -12,6 +12,7 @@ NEXT_PUBLIC_DEPLOY_URL=http://localhost/spaces
|
|||||||
SENTRY_DSN=""
|
SENTRY_DSN=""
|
||||||
GITHUB_CLIENT_SECRET=""
|
GITHUB_CLIENT_SECRET=""
|
||||||
DOCKERIZED=1
|
DOCKERIZED=1
|
||||||
|
CORS_ALLOWED_ORIGINS="http://localhost"
|
||||||
|
|
||||||
#DB SETTINGS
|
#DB SETTINGS
|
||||||
PGHOST=plane-db
|
PGHOST=plane-db
|
||||||
|
Loading…
Reference in New Issue
Block a user