server/avocano_api/settings.py (129 lines of code) (raw):

#!/usr/bin/python # # Copyright 2022 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. import io import os from pathlib import Path from urllib.parse import urlparse import environ from .cloudrun_helpers import MetadataError, get_service_url, get_project_id BASE_DIR = Path(__file__).resolve().parent.parent # Load settings from local .env, mounted .env, or envvar. env = environ.Env() env.read_env(BASE_DIR / ".env") env.read_env("/settings/.env") env.read_env(io.StringIO(os.environ.get("DJANGO_ENV", None))) SECRET_KEY = env("SECRET_KEY") DEBUG = env("DEBUG", default=False) # Application definition INSTALLED_APPS = [ "django.contrib.admin", "django.contrib.auth", "django.contrib.contenttypes", "django.contrib.sessions", "django.contrib.messages", "django.contrib.staticfiles", "store", "colorfield", "corsheaders", "rest_framework", "django_filters", "drf_spectacular", ] MIDDLEWARE = [ "avocano_api.healthchecks.HealthCheckMiddleware", "corsheaders.middleware.CorsMiddleware", "django.middleware.common.CommonMiddleware", "django.middleware.security.SecurityMiddleware", "django.contrib.sessions.middleware.SessionMiddleware", "django.middleware.common.CommonMiddleware", "django.middleware.csrf.CsrfViewMiddleware", "django.contrib.auth.middleware.AuthenticationMiddleware", "django.contrib.messages.middleware.MessageMiddleware", "django.middleware.clickjacking.XFrameOptionsMiddleware", ] ROOT_URLCONF = "avocano_api.urls" TEMPLATES = [ { "BACKEND": "django.template.backends.django.DjangoTemplates", "DIRS": [], "APP_DIRS": True, "OPTIONS": { "context_processors": [ "django.template.context_processors.debug", "django.template.context_processors.request", "django.contrib.auth.context_processors.auth", "django.contrib.messages.context_processors.messages", ], }, }, ] # Used for local dev or using Cloud Run proxy local_hosts = ["http://localhost:8000", "http://localhost:8081"] # Used for Cloud Shell dev with Web Preview cloudshell_host = "https://*.cloudshell.dev" # Used to identify the host of the deployed service # Supports a comma separated list of full URLs CLOUDRUN_SERVICE_URL = env("CLOUDRUN_SERVICE_URL", default=None) # If the Cloud Run service isn't defined, try dynamically retrieving it. if not CLOUDRUN_SERVICE_URL: try: CLOUDRUN_SERVICE_URL = get_service_url() except MetadataError: pass if CLOUDRUN_SERVICE_URL: # Setup as we are running in Cloud Run & Firebase service_urls = CLOUDRUN_SERVICE_URL.split(",") ALLOWED_HOSTS = [urlparse(url).netloc for url in service_urls] + ["127.0.0.1"] # Firebase hosting has multiple default URLs, so add those as well. project_id = get_project_id() # If a deployment suffix is provided, presume this is being used as # the Firebase Site URL, rather than just the default site (project-id). # From variable `random_suffix` in https://github.com/GoogleCloudPlatform/terraform-dynamic-python-webapp/blob/main/infra/variables.tf#L44 DEPLOYMENT_SUFFIX = env("DEPLOYMENT_SUFFIX", default=None) if DEPLOYMENT_SUFFIX: firebase_site_id = f"{project_id}-{DEPLOYMENT_SUFFIX}" else: firebase_site_id = project_id firebase_hosts = [ f"https://{firebase_site_id}.web.app", f"https://{firebase_site_id}.firebaseapp.com", ] CSRF_TRUSTED_ORIGINS = service_urls + local_hosts + firebase_hosts SECURE_SSL_REDIRECT = True SECURE_PROXY_SSL_HEADER = ("HTTP_X_FORWARDED_PROTO", "https") else: # Setup as we are running on localhost, or Cloud Shell ALLOWED_HOSTS = ["*"] CSRF_TRUSTED_ORIGINS = [cloudshell_host] + local_hosts # django-cors-headers settings CORS_ORIGIN_ALLOW_ALL = True CORS_ALLOW_CREDENTIALS = True WSGI_APPLICATION = "avocano_api.wsgi.application" # Database # https://docs.djangoproject.com/en/stable/ref/settings/#databases # Use django-environ to parse the connection string DATABASES = {"default": env.db()} # If the flag as been set, configure to use proxy if env("USE_CLOUD_SQL_AUTH_PROXY", default=None): DATABASES["default"]["HOST"] = "127.0.0.1" DATABASES["default"]["PORT"] = 5432 # Password validation # https://docs.djangoproject.com/en/stable/ref/settings/#auth-password-validators AUTH_PASSWORD_VALIDATORS = [ { "NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator", }, { "NAME": "django.contrib.auth.password_validation.MinimumLengthValidator", }, { "NAME": "django.contrib.auth.password_validation.CommonPasswordValidator", }, { "NAME": "django.contrib.auth.password_validation.NumericPasswordValidator", }, ] # Internationalization LANGUAGE_CODE = "en-us" TIME_ZONE = "UTC" USE_I18N = True USE_TZ = True # Default primary key field type DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField" # Django REST Framework REST_FRAMEWORK = { # Any exposed endpoints can be accessed by any client that has access to the API itself. "DEFAULT_PERMISSION_CLASSES": ["rest_framework.permissions.AllowAny"], # For automatic OpenAPI schema. "DEFAULT_SCHEMA_CLASS": "drf_spectacular.openapi.AutoSchema", } # Static files (CSS, JavaScript, Images) STATIC_URL = "/static/" MEDIA_URL = "/media/" # Use Cloud Storage if configured, otherwise use local storage. if GS_BUCKET_NAME := env("GS_BUCKET_NAME", default=None): STORAGES = { "default": {"BACKEND": "storages.backends.gcloud.GoogleCloudStorage"}, "staticfiles": {"BACKEND": "storages.backends.gcloud.GoogleCloudStorage"}, } GS_DEFAULT_ACL = "publicRead" else: STORAGES = { "default": {"BACKEND": "django.core.files.storage.FileSystemStorage"}, "staticfiles": { "BACKEND": "django.contrib.staticfiles.storage.StaticFilesStorage", }, } STATIC_ROOT = os.path.join(BASE_DIR, STATIC_URL.replace("/", "")) MEDIA_ROOT = os.path.join(BASE_DIR, MEDIA_URL.replace("/", ""))