This is so that the lms default celery queue does not get backed up when coursegraph is hosed (which is likely when coursegraph has been redeployed and needs to get the full set of courses). TNL-8386
1051 lines
45 KiB
Python
1051 lines
45 KiB
Python
"""
|
|
This is the default template for our main set of AWS servers.
|
|
|
|
Common traits:
|
|
* Use memcached, and cache-backed sessions
|
|
* Use a MySQL 5.1 database
|
|
"""
|
|
|
|
# We intentionally define lots of variables that aren't used, and
|
|
# want to import all variables from base settings files
|
|
# pylint: disable=wildcard-import, unused-wildcard-import
|
|
|
|
# Pylint gets confused by path.py instances, which report themselves as class
|
|
# objects. As a result, pylint applies the wrong regex in validating names,
|
|
# and throws spurious errors. Therefore, we disable invalid-name checking.
|
|
# pylint: disable=invalid-name
|
|
|
|
|
|
import codecs
|
|
import copy
|
|
import datetime
|
|
import os
|
|
|
|
import yaml
|
|
from corsheaders.defaults import default_headers as corsheaders_default_headers
|
|
from django.core.exceptions import ImproperlyConfigured
|
|
from edx_django_utils.plugins import add_plugins
|
|
from path import Path as path
|
|
|
|
from openedx.core.djangoapps.plugins.constants import ProjectType, SettingsType
|
|
from openedx.core.lib.derived import derive_settings
|
|
from openedx.core.lib.logsettings import get_logger_config
|
|
from xmodule.modulestore.modulestore_settings import convert_module_store_setting_if_needed
|
|
|
|
from .common import *
|
|
|
|
|
|
def get_env_setting(setting):
|
|
""" Get the environment setting or return exception """
|
|
try:
|
|
return os.environ[setting]
|
|
except KeyError:
|
|
error_msg = "Set the %s env variable" % setting
|
|
raise ImproperlyConfigured(error_msg) # lint-amnesty, pylint: disable=raise-missing-from
|
|
|
|
################################ ALWAYS THE SAME ##############################
|
|
|
|
DEBUG = False
|
|
DEFAULT_TEMPLATE_ENGINE['OPTIONS']['debug'] = False
|
|
|
|
SESSION_ENGINE = 'django.contrib.sessions.backends.cache'
|
|
|
|
# IMPORTANT: With this enabled, the server must always be behind a proxy that
|
|
# strips the header HTTP_X_FORWARDED_PROTO from client requests. Otherwise,
|
|
# a user can fool our server into thinking it was an https connection.
|
|
# See
|
|
# https://docs.djangoproject.com/en/dev/ref/settings/#secure-proxy-ssl-header
|
|
# for other warnings.
|
|
SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')
|
|
################################ END ALWAYS THE SAME ##############################
|
|
|
|
# A file path to a YAML file from which to load all the configuration for the edx platform
|
|
CONFIG_FILE = get_env_setting('LMS_CFG')
|
|
|
|
with codecs.open(CONFIG_FILE, encoding='utf-8') as f:
|
|
__config__ = yaml.safe_load(f)
|
|
|
|
# ENV_TOKENS and AUTH_TOKENS are included for reverse compatibility.
|
|
# Removing them may break plugins that rely on them.
|
|
ENV_TOKENS = __config__
|
|
AUTH_TOKENS = __config__
|
|
|
|
# Add the key/values from config into the global namespace of this module.
|
|
# But don't override the FEATURES dict because we do that in an additive way.
|
|
__config_copy__ = copy.deepcopy(__config__)
|
|
|
|
KEYS_WITH_MERGED_VALUES = [
|
|
'FEATURES',
|
|
'TRACKING_BACKENDS',
|
|
'EVENT_TRACKING_BACKENDS',
|
|
'JWT_AUTH',
|
|
'CELERY_QUEUES',
|
|
'MKTG_URL_LINK_MAP',
|
|
'MKTG_URL_OVERRIDES',
|
|
]
|
|
for key in KEYS_WITH_MERGED_VALUES:
|
|
if key in __config_copy__:
|
|
del __config_copy__[key]
|
|
|
|
vars().update(__config_copy__)
|
|
|
|
|
|
try:
|
|
# A file path to a YAML file from which to load all the code revisions currently deployed
|
|
REVISION_CONFIG_FILE = get_env_setting('REVISION_CFG')
|
|
|
|
with codecs.open(REVISION_CONFIG_FILE, encoding='utf-8') as f:
|
|
REVISION_CONFIG = yaml.safe_load(f)
|
|
except Exception: # pylint: disable=broad-except
|
|
REVISION_CONFIG = {}
|
|
|
|
# Do NOT calculate this dynamically at startup with git because it's *slow*.
|
|
EDX_PLATFORM_REVISION = REVISION_CONFIG.get('EDX_PLATFORM_REVISION', EDX_PLATFORM_REVISION)
|
|
|
|
###################################### CELERY ################################
|
|
|
|
# Don't use a connection pool, since connections are dropped by ELB.
|
|
BROKER_POOL_LIMIT = 0
|
|
BROKER_CONNECTION_TIMEOUT = 1
|
|
|
|
# For the Result Store, use the django cache named 'celery'
|
|
CELERY_RESULT_BACKEND = 'django-cache'
|
|
|
|
# When the broker is behind an ELB, use a heartbeat to refresh the
|
|
# connection and to detect if it has been dropped.
|
|
BROKER_HEARTBEAT = ENV_TOKENS.get('BROKER_HEARTBEAT', 60.0)
|
|
BROKER_HEARTBEAT_CHECKRATE = ENV_TOKENS.get('BROKER_HEARTBEAT_CHECKRATE', 2)
|
|
|
|
# Each worker should only fetch one message at a time
|
|
CELERYD_PREFETCH_MULTIPLIER = 1
|
|
|
|
# STATIC_ROOT specifies the directory where static files are
|
|
# collected
|
|
STATIC_ROOT_BASE = ENV_TOKENS.get('STATIC_ROOT_BASE', None)
|
|
if STATIC_ROOT_BASE:
|
|
STATIC_ROOT = path(STATIC_ROOT_BASE)
|
|
WEBPACK_LOADER['DEFAULT']['STATS_FILE'] = STATIC_ROOT / "webpack-stats.json"
|
|
WEBPACK_LOADER['WORKERS']['STATS_FILE'] = STATIC_ROOT / "webpack-worker-stats.json"
|
|
|
|
|
|
# STATIC_URL_BASE specifies the base url to use for static files
|
|
STATIC_URL_BASE = ENV_TOKENS.get('STATIC_URL_BASE', None)
|
|
if STATIC_URL_BASE:
|
|
STATIC_URL = STATIC_URL_BASE
|
|
if not STATIC_URL.endswith("/"):
|
|
STATIC_URL += "/"
|
|
|
|
# Allow overriding build profile used by RequireJS with one
|
|
# contained on a custom theme
|
|
REQUIRE_BUILD_PROFILE = ENV_TOKENS.get('REQUIRE_BUILD_PROFILE', REQUIRE_BUILD_PROFILE)
|
|
|
|
# The following variables use (or) instead of the default value inside (get). This is to enforce using the Lazy Text
|
|
# values when the varibale is an empty string. Therefore, setting these variable as empty text in related
|
|
# json files will make the system reads thier values from django translation files
|
|
PLATFORM_NAME = ENV_TOKENS.get('PLATFORM_NAME') or PLATFORM_NAME
|
|
PLATFORM_DESCRIPTION = ENV_TOKENS.get('PLATFORM_DESCRIPTION') or PLATFORM_DESCRIPTION
|
|
|
|
CC_MERCHANT_NAME = ENV_TOKENS.get('CC_MERCHANT_NAME', PLATFORM_NAME)
|
|
EMAIL_FILE_PATH = ENV_TOKENS.get('EMAIL_FILE_PATH', None)
|
|
EMAIL_HOST = ENV_TOKENS.get('EMAIL_HOST', 'localhost') # django default is localhost
|
|
EMAIL_PORT = ENV_TOKENS.get('EMAIL_PORT', 25) # django default is 25
|
|
EMAIL_USE_TLS = ENV_TOKENS.get('EMAIL_USE_TLS', False) # django default is False
|
|
SITE_NAME = ENV_TOKENS['SITE_NAME']
|
|
SESSION_COOKIE_DOMAIN = ENV_TOKENS.get('SESSION_COOKIE_DOMAIN')
|
|
SESSION_COOKIE_HTTPONLY = ENV_TOKENS.get('SESSION_COOKIE_HTTPONLY', True)
|
|
|
|
DCS_SESSION_COOKIE_SAMESITE = ENV_TOKENS.get('DCS_SESSION_COOKIE_SAMESITE', DCS_SESSION_COOKIE_SAMESITE)
|
|
DCS_SESSION_COOKIE_SAMESITE_FORCE_ALL = ENV_TOKENS.get('DCS_SESSION_COOKIE_SAMESITE_FORCE_ALL', DCS_SESSION_COOKIE_SAMESITE_FORCE_ALL) # lint-amnesty, pylint: disable=line-too-long
|
|
|
|
# As django-cookies-samesite package is set to be removed from base requirements when we upgrade to Django 3.2,
|
|
# we should follow the settings name provided by Django.
|
|
# https://docs.djangoproject.com/en/3.2/ref/settings/#session-cookie-samesite
|
|
SESSION_COOKIE_SAMESITE = DCS_SESSION_COOKIE_SAMESITE
|
|
|
|
AWS_SES_REGION_NAME = ENV_TOKENS.get('AWS_SES_REGION_NAME', 'us-east-1')
|
|
AWS_SES_REGION_ENDPOINT = ENV_TOKENS.get('AWS_SES_REGION_ENDPOINT', 'email.us-east-1.amazonaws.com')
|
|
|
|
REGISTRATION_EMAIL_PATTERNS_ALLOWED = ENV_TOKENS.get('REGISTRATION_EMAIL_PATTERNS_ALLOWED')
|
|
|
|
LMS_ROOT_URL = ENV_TOKENS.get('LMS_ROOT_URL')
|
|
LMS_INTERNAL_ROOT_URL = ENV_TOKENS.get('LMS_INTERNAL_ROOT_URL', LMS_ROOT_URL)
|
|
|
|
# List of logout URIs for each IDA that the learner should be logged out of when they logout of the LMS. Only applies to
|
|
# IDA for which the social auth flow uses DOT (Django OAuth Toolkit).
|
|
IDA_LOGOUT_URI_LIST = ENV_TOKENS.get('IDA_LOGOUT_URI_LIST', [])
|
|
|
|
ENV_FEATURES = ENV_TOKENS.get('FEATURES', {})
|
|
for feature, value in ENV_FEATURES.items():
|
|
FEATURES[feature] = value
|
|
|
|
CMS_BASE = ENV_TOKENS.get('CMS_BASE', 'studio.edx.org')
|
|
|
|
ALLOWED_HOSTS = [
|
|
# TODO: bbeggs remove this before prod, temp fix to get load testing running
|
|
"*",
|
|
ENV_TOKENS.get('LMS_BASE'),
|
|
FEATURES['PREVIEW_LMS_BASE'],
|
|
]
|
|
|
|
# Sometimes, OAuth2 clients want the user to redirect back to their site after logout. But to determine if the given
|
|
# redirect URL/path is safe for redirection, the following variable is used by edX.
|
|
LOGIN_REDIRECT_WHITELIST = ENV_TOKENS.get(
|
|
'LOGIN_REDIRECT_WHITELIST',
|
|
LOGIN_REDIRECT_WHITELIST
|
|
)
|
|
|
|
# allow for environments to specify what cookie name our login subsystem should use
|
|
# this is to fix a bug regarding simultaneous logins between edx.org and edge.edx.org which can
|
|
# happen with some browsers (e.g. Firefox)
|
|
if ENV_TOKENS.get('SESSION_COOKIE_NAME', None):
|
|
# NOTE, there's a bug in Django (http://bugs.python.org/issue18012) which necessitates this being a str()
|
|
SESSION_COOKIE_NAME = str(ENV_TOKENS.get('SESSION_COOKIE_NAME'))
|
|
|
|
# This is the domain that is used to set shared cookies between various sub-domains.
|
|
# By default, it's set to the same thing as the SESSION_COOKIE_DOMAIN, but we want to make it overrideable.
|
|
SHARED_COOKIE_DOMAIN = ENV_TOKENS.get('SHARED_COOKIE_DOMAIN', SESSION_COOKIE_DOMAIN)
|
|
|
|
CACHES = ENV_TOKENS['CACHES']
|
|
# Cache used for location mapping -- called many times with the same key/value
|
|
# in a given request.
|
|
if 'loc_cache' not in CACHES:
|
|
CACHES['loc_cache'] = {
|
|
'BACKEND': 'django.core.cache.backends.locmem.LocMemCache',
|
|
'LOCATION': 'edx_location_mem_cache',
|
|
}
|
|
|
|
if 'staticfiles' in CACHES:
|
|
CACHES['staticfiles']['KEY_PREFIX'] = EDX_PLATFORM_REVISION
|
|
|
|
# In order to transition from local disk asset storage to S3 backed asset storage,
|
|
# we need to run asset collection twice, once for local disk and once for S3.
|
|
# Once we have migrated to service assets off S3, then we can convert this back to
|
|
# managed by the yaml file contents
|
|
STATICFILES_STORAGE = os.environ.get('STATICFILES_STORAGE', ENV_TOKENS.get('STATICFILES_STORAGE', STATICFILES_STORAGE))
|
|
|
|
# Load all AWS_ prefixed variables to allow an S3Boto3Storage to be configured
|
|
_locals = locals()
|
|
for key, value in ENV_TOKENS.items():
|
|
if key.startswith('AWS_'):
|
|
_locals[key] = value
|
|
|
|
# Currency
|
|
PAID_COURSE_REGISTRATION_CURRENCY = ENV_TOKENS.get('PAID_COURSE_REGISTRATION_CURRENCY',
|
|
PAID_COURSE_REGISTRATION_CURRENCY)
|
|
|
|
# We want Bulk Email running on the high-priority queue, so we define the
|
|
# routing key that points to it. At the moment, the name is the same.
|
|
# We have to reset the value here, since we have changed the value of the queue name.
|
|
BULK_EMAIL_ROUTING_KEY = ENV_TOKENS.get('BULK_EMAIL_ROUTING_KEY', HIGH_PRIORITY_QUEUE)
|
|
|
|
# We can run smaller jobs on the low priority queue. See note above for why
|
|
# we have to reset the value here.
|
|
BULK_EMAIL_ROUTING_KEY_SMALL_JOBS = ENV_TOKENS.get('BULK_EMAIL_ROUTING_KEY_SMALL_JOBS', DEFAULT_PRIORITY_QUEUE)
|
|
|
|
# Queue to use for expiring old entitlements
|
|
ENTITLEMENTS_EXPIRATION_ROUTING_KEY = ENV_TOKENS.get('ENTITLEMENTS_EXPIRATION_ROUTING_KEY', DEFAULT_PRIORITY_QUEUE)
|
|
|
|
# Message expiry time in seconds
|
|
CELERY_EVENT_QUEUE_TTL = ENV_TOKENS.get('CELERY_EVENT_QUEUE_TTL', None)
|
|
|
|
# Allow CELERY_QUEUES to be overwritten by ENV_TOKENS,
|
|
ENV_CELERY_QUEUES = ENV_TOKENS.get('CELERY_QUEUES', None)
|
|
if ENV_CELERY_QUEUES:
|
|
CELERY_QUEUES = {queue: {} for queue in ENV_CELERY_QUEUES}
|
|
|
|
# Then add alternate environment queues
|
|
ALTERNATE_QUEUE_ENVS = ENV_TOKENS.get('ALTERNATE_WORKER_QUEUES', '').split()
|
|
ALTERNATE_QUEUES = [
|
|
DEFAULT_PRIORITY_QUEUE.replace(QUEUE_VARIANT, alternate + '.')
|
|
for alternate in ALTERNATE_QUEUE_ENVS
|
|
]
|
|
CELERY_QUEUES.update(
|
|
{
|
|
alternate: {}
|
|
for alternate in ALTERNATE_QUEUES
|
|
if alternate not in list(CELERY_QUEUES.keys())
|
|
}
|
|
)
|
|
|
|
# following setting is for backward compatibility
|
|
if ENV_TOKENS.get('COMPREHENSIVE_THEME_DIR', None):
|
|
COMPREHENSIVE_THEME_DIR = ENV_TOKENS.get('COMPREHENSIVE_THEME_DIR')
|
|
|
|
|
|
# COMPREHENSIVE_THEME_LOCALE_PATHS contain the paths to themes locale directories e.g.
|
|
# "COMPREHENSIVE_THEME_LOCALE_PATHS" : [
|
|
# "/edx/src/edx-themes/conf/locale"
|
|
# ],
|
|
COMPREHENSIVE_THEME_LOCALE_PATHS = ENV_TOKENS.get('COMPREHENSIVE_THEME_LOCALE_PATHS', [])
|
|
|
|
|
|
MKTG_URL_LINK_MAP.update(ENV_TOKENS.get('MKTG_URL_LINK_MAP', {}))
|
|
ENTERPRISE_MARKETING_FOOTER_QUERY_PARAMS = ENV_TOKENS.get(
|
|
'ENTERPRISE_MARKETING_FOOTER_QUERY_PARAMS',
|
|
ENTERPRISE_MARKETING_FOOTER_QUERY_PARAMS
|
|
)
|
|
# Marketing link overrides
|
|
MKTG_URL_OVERRIDES.update(ENV_TOKENS.get('MKTG_URL_OVERRIDES', MKTG_URL_OVERRIDES))
|
|
|
|
# Intentional defaults.
|
|
ID_VERIFICATION_SUPPORT_LINK = ENV_TOKENS.get('ID_VERIFICATION_SUPPORT_LINK', SUPPORT_SITE_LINK)
|
|
PASSWORD_RESET_SUPPORT_LINK = ENV_TOKENS.get('PASSWORD_RESET_SUPPORT_LINK', SUPPORT_SITE_LINK)
|
|
ACTIVATION_EMAIL_SUPPORT_LINK = ENV_TOKENS.get('ACTIVATION_EMAIL_SUPPORT_LINK', SUPPORT_SITE_LINK)
|
|
LOGIN_ISSUE_SUPPORT_LINK = ENV_TOKENS.get('LOGIN_ISSUE_SUPPORT_LINK', SUPPORT_SITE_LINK)
|
|
|
|
# Timezone overrides
|
|
TIME_ZONE = ENV_TOKENS.get('CELERY_TIMEZONE', CELERY_TIMEZONE)
|
|
|
|
# Translation overrides
|
|
LANGUAGE_DICT = dict(LANGUAGES)
|
|
|
|
LANGUAGE_COOKIE_NAME = ENV_TOKENS.get('LANGUAGE_COOKIE', None) or ENV_TOKENS.get(
|
|
'LANGUAGE_COOKIE_NAME', LANGUAGE_COOKIE_NAME)
|
|
|
|
# Additional installed apps
|
|
for app in ENV_TOKENS.get('ADDL_INSTALLED_APPS', []):
|
|
INSTALLED_APPS.append(app)
|
|
|
|
|
|
local_loglevel = ENV_TOKENS.get('LOCAL_LOGLEVEL', 'INFO')
|
|
LOG_DIR = ENV_TOKENS['LOG_DIR']
|
|
DATA_DIR = path(ENV_TOKENS.get('DATA_DIR', DATA_DIR))
|
|
|
|
LOGGING = get_logger_config(LOG_DIR,
|
|
logging_env=ENV_TOKENS['LOGGING_ENV'],
|
|
local_loglevel=local_loglevel,
|
|
service_variant=SERVICE_VARIANT)
|
|
|
|
COURSE_LISTINGS = ENV_TOKENS.get('COURSE_LISTINGS', {})
|
|
COMMENTS_SERVICE_URL = ENV_TOKENS.get("COMMENTS_SERVICE_URL", '')
|
|
COMMENTS_SERVICE_KEY = ENV_TOKENS.get("COMMENTS_SERVICE_KEY", '')
|
|
CERT_QUEUE = ENV_TOKENS.get("CERT_QUEUE", 'test-pull')
|
|
|
|
# Python lib settings
|
|
PYTHON_LIB_FILENAME = ENV_TOKENS.get('PYTHON_LIB_FILENAME', 'python_lib.zip')
|
|
|
|
# Code jail settings
|
|
for name, value in ENV_TOKENS.get("CODE_JAIL", {}).items():
|
|
oldvalue = CODE_JAIL.get(name)
|
|
if isinstance(oldvalue, dict):
|
|
for subname, subvalue in value.items():
|
|
oldvalue[subname] = subvalue
|
|
else:
|
|
CODE_JAIL[name] = value
|
|
|
|
COURSES_WITH_UNSAFE_CODE = ENV_TOKENS.get("COURSES_WITH_UNSAFE_CODE", [])
|
|
|
|
# Event Tracking
|
|
if "TRACKING_IGNORE_URL_PATTERNS" in ENV_TOKENS:
|
|
TRACKING_IGNORE_URL_PATTERNS = ENV_TOKENS.get("TRACKING_IGNORE_URL_PATTERNS")
|
|
|
|
# SSL external authentication settings
|
|
SSL_AUTH_EMAIL_DOMAIN = ENV_TOKENS.get("SSL_AUTH_EMAIL_DOMAIN", "MIT.EDU")
|
|
SSL_AUTH_DN_FORMAT_STRING = ENV_TOKENS.get(
|
|
"SSL_AUTH_DN_FORMAT_STRING",
|
|
"/C=US/ST=Massachusetts/O=Massachusetts Institute of Technology/OU=Client CA v1/CN={0}/emailAddress={1}"
|
|
)
|
|
|
|
# Video Caching. Pairing country codes with CDN URLs.
|
|
# Example: {'CN': 'http://api.xuetangx.com/edx/video?s3_url='}
|
|
VIDEO_CDN_URL = ENV_TOKENS.get('VIDEO_CDN_URL', {})
|
|
|
|
# Determines whether the CSRF token can be transported on
|
|
# unencrypted channels. It is set to False here for backward compatibility,
|
|
# but it is highly recommended that this is True for enviroments accessed
|
|
# by end users.
|
|
CSRF_COOKIE_SECURE = ENV_TOKENS.get('CSRF_COOKIE_SECURE', False)
|
|
|
|
# Determines which origins are trusted for unsafe requests eg. POST requests.
|
|
CSRF_TRUSTED_ORIGINS = ENV_TOKENS.get('CSRF_TRUSTED_ORIGINS', [])
|
|
|
|
############# CORS headers for cross-domain requests #################
|
|
|
|
if FEATURES.get('ENABLE_CORS_HEADERS') or FEATURES.get('ENABLE_CROSS_DOMAIN_CSRF_COOKIE'):
|
|
CORS_ALLOW_CREDENTIALS = True
|
|
CORS_ORIGIN_WHITELIST = ENV_TOKENS.get('CORS_ORIGIN_WHITELIST', ())
|
|
|
|
CORS_ORIGIN_ALLOW_ALL = ENV_TOKENS.get('CORS_ORIGIN_ALLOW_ALL', False)
|
|
CORS_ALLOW_INSECURE = ENV_TOKENS.get('CORS_ALLOW_INSECURE', False)
|
|
CORS_ALLOW_HEADERS = corsheaders_default_headers + (
|
|
'use-jwt-cookie',
|
|
)
|
|
|
|
# If setting a cross-domain cookie, it's really important to choose
|
|
# a name for the cookie that is DIFFERENT than the cookies used
|
|
# by each subdomain. For example, suppose the applications
|
|
# at these subdomains are configured to use the following cookie names:
|
|
#
|
|
# 1) foo.example.com --> "csrftoken"
|
|
# 2) baz.example.com --> "csrftoken"
|
|
# 3) bar.example.com --> "csrftoken"
|
|
#
|
|
# For the cross-domain version of the CSRF cookie, you need to choose
|
|
# a name DIFFERENT than "csrftoken"; otherwise, the new token configured
|
|
# for ".example.com" could conflict with the other cookies,
|
|
# non-deterministically causing 403 responses.
|
|
#
|
|
# Because of the way Django stores cookies, the cookie name MUST
|
|
# be a `str`, not unicode. Otherwise there will `TypeError`s will be raised
|
|
# when Django tries to call the unicode `translate()` method with the wrong
|
|
# number of parameters.
|
|
CROSS_DOMAIN_CSRF_COOKIE_NAME = str(ENV_TOKENS.get('CROSS_DOMAIN_CSRF_COOKIE_NAME'))
|
|
|
|
# When setting the domain for the "cross-domain" version of the CSRF
|
|
# cookie, you should choose something like: ".example.com"
|
|
# (note the leading dot), where both the referer and the host
|
|
# are subdomains of "example.com".
|
|
#
|
|
# Browser security rules require that
|
|
# the cookie domain matches the domain of the server; otherwise
|
|
# the cookie won't get set. And once the cookie gets set, the client
|
|
# needs to be on a domain that matches the cookie domain, otherwise
|
|
# the client won't be able to read the cookie.
|
|
CROSS_DOMAIN_CSRF_COOKIE_DOMAIN = ENV_TOKENS.get('CROSS_DOMAIN_CSRF_COOKIE_DOMAIN')
|
|
|
|
|
|
# Field overrides. To use the IDDE feature, add
|
|
# 'courseware.student_field_overrides.IndividualStudentOverrideProvider'.
|
|
FIELD_OVERRIDE_PROVIDERS = tuple(ENV_TOKENS.get('FIELD_OVERRIDE_PROVIDERS', []))
|
|
|
|
############### XBlock filesystem field config ##########
|
|
if 'DJFS' in AUTH_TOKENS and AUTH_TOKENS['DJFS'] is not None:
|
|
DJFS = AUTH_TOKENS['DJFS']
|
|
|
|
############### Module Store Items ##########
|
|
HOSTNAME_MODULESTORE_DEFAULT_MAPPINGS = ENV_TOKENS.get('HOSTNAME_MODULESTORE_DEFAULT_MAPPINGS', {})
|
|
# PREVIEW DOMAIN must be present in HOSTNAME_MODULESTORE_DEFAULT_MAPPINGS for the preview to show draft changes
|
|
if 'PREVIEW_LMS_BASE' in FEATURES and FEATURES['PREVIEW_LMS_BASE'] != '':
|
|
PREVIEW_DOMAIN = FEATURES['PREVIEW_LMS_BASE'].split(':')[0]
|
|
# update dictionary with preview domain regex
|
|
HOSTNAME_MODULESTORE_DEFAULT_MAPPINGS.update({
|
|
PREVIEW_DOMAIN: 'draft-preferred'
|
|
})
|
|
|
|
MODULESTORE_FIELD_OVERRIDE_PROVIDERS = ENV_TOKENS.get(
|
|
'MODULESTORE_FIELD_OVERRIDE_PROVIDERS',
|
|
MODULESTORE_FIELD_OVERRIDE_PROVIDERS
|
|
)
|
|
|
|
XBLOCK_FIELD_DATA_WRAPPERS = ENV_TOKENS.get(
|
|
'XBLOCK_FIELD_DATA_WRAPPERS',
|
|
XBLOCK_FIELD_DATA_WRAPPERS
|
|
)
|
|
|
|
############### Mixed Related(Secure/Not-Secure) Items ##########
|
|
LMS_SEGMENT_KEY = AUTH_TOKENS.get('SEGMENT_KEY')
|
|
|
|
SECRET_KEY = AUTH_TOKENS['SECRET_KEY']
|
|
|
|
AWS_ACCESS_KEY_ID = AUTH_TOKENS["AWS_ACCESS_KEY_ID"]
|
|
if AWS_ACCESS_KEY_ID == "":
|
|
AWS_ACCESS_KEY_ID = None
|
|
|
|
AWS_SECRET_ACCESS_KEY = AUTH_TOKENS["AWS_SECRET_ACCESS_KEY"]
|
|
if AWS_SECRET_ACCESS_KEY == "":
|
|
AWS_SECRET_ACCESS_KEY = None
|
|
|
|
AWS_STORAGE_BUCKET_NAME = AUTH_TOKENS.get('AWS_STORAGE_BUCKET_NAME', 'edxuploads')
|
|
|
|
# Disabling querystring auth instructs Boto to exclude the querystring parameters (e.g. signature, access key) it
|
|
# normally appends to every returned URL.
|
|
AWS_QUERYSTRING_AUTH = AUTH_TOKENS.get('AWS_QUERYSTRING_AUTH', True)
|
|
AWS_S3_CUSTOM_DOMAIN = AUTH_TOKENS.get('AWS_S3_CUSTOM_DOMAIN', 'edxuploads.s3.amazonaws.com')
|
|
|
|
if AUTH_TOKENS.get('DEFAULT_FILE_STORAGE'):
|
|
DEFAULT_FILE_STORAGE = AUTH_TOKENS.get('DEFAULT_FILE_STORAGE')
|
|
elif AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY:
|
|
DEFAULT_FILE_STORAGE = 'storages.backends.s3boto.S3BotoStorage'
|
|
else:
|
|
DEFAULT_FILE_STORAGE = 'django.core.files.storage.FileSystemStorage'
|
|
|
|
# If there is a database called 'read_replica', you can use the use_read_replica_if_available
|
|
# function in util/query.py, which is useful for very large database reads
|
|
DATABASES = AUTH_TOKENS['DATABASES']
|
|
|
|
# The normal database user does not have enough permissions to run migrations.
|
|
# Migrations are run with separate credentials, given as DB_MIGRATION_*
|
|
# environment variables
|
|
for name, database in DATABASES.items():
|
|
if name != 'read_replica':
|
|
database.update({
|
|
'ENGINE': os.environ.get('DB_MIGRATION_ENGINE', database['ENGINE']),
|
|
'USER': os.environ.get('DB_MIGRATION_USER', database['USER']),
|
|
'PASSWORD': os.environ.get('DB_MIGRATION_PASS', database['PASSWORD']),
|
|
'NAME': os.environ.get('DB_MIGRATION_NAME', database['NAME']),
|
|
'HOST': os.environ.get('DB_MIGRATION_HOST', database['HOST']),
|
|
'PORT': os.environ.get('DB_MIGRATION_PORT', database['PORT']),
|
|
})
|
|
|
|
XQUEUE_INTERFACE = AUTH_TOKENS['XQUEUE_INTERFACE']
|
|
|
|
# Get the MODULESTORE from auth.json, but if it doesn't exist,
|
|
# use the one from common.py
|
|
MODULESTORE = convert_module_store_setting_if_needed(AUTH_TOKENS.get('MODULESTORE', MODULESTORE))
|
|
MONGODB_LOG = AUTH_TOKENS.get('MONGODB_LOG', {})
|
|
|
|
EMAIL_HOST_USER = AUTH_TOKENS.get('EMAIL_HOST_USER', '') # django default is ''
|
|
EMAIL_HOST_PASSWORD = AUTH_TOKENS.get('EMAIL_HOST_PASSWORD', '') # django default is ''
|
|
|
|
############################### BLOCKSTORE #####################################
|
|
BLOCKSTORE_API_URL = ENV_TOKENS.get('BLOCKSTORE_API_URL', None) # e.g. "https://blockstore.example.com/api/v1/"
|
|
# Configure an API auth token at (blockstore URL)/admin/authtoken/token/
|
|
BLOCKSTORE_API_AUTH_TOKEN = AUTH_TOKENS.get('BLOCKSTORE_API_AUTH_TOKEN', None)
|
|
|
|
# Datadog for events!
|
|
DATADOG = AUTH_TOKENS.get("DATADOG", {})
|
|
DATADOG.update(ENV_TOKENS.get("DATADOG", {}))
|
|
|
|
# TODO: deprecated (compatibility with previous settings)
|
|
if 'DATADOG_API' in AUTH_TOKENS:
|
|
DATADOG['api_key'] = AUTH_TOKENS['DATADOG_API']
|
|
|
|
# Analytics API
|
|
ANALYTICS_API_KEY = AUTH_TOKENS.get("ANALYTICS_API_KEY", ANALYTICS_API_KEY)
|
|
ANALYTICS_API_URL = ENV_TOKENS.get("ANALYTICS_API_URL", ANALYTICS_API_URL)
|
|
|
|
# Zendesk
|
|
ZENDESK_USER = AUTH_TOKENS.get("ZENDESK_USER")
|
|
ZENDESK_API_KEY = AUTH_TOKENS.get("ZENDESK_API_KEY")
|
|
|
|
# API Key for inbound requests from Notifier service
|
|
EDX_API_KEY = AUTH_TOKENS.get("EDX_API_KEY")
|
|
|
|
# Celery Broker
|
|
CELERY_BROKER_TRANSPORT = ENV_TOKENS.get("CELERY_BROKER_TRANSPORT", "")
|
|
CELERY_BROKER_HOSTNAME = ENV_TOKENS.get("CELERY_BROKER_HOSTNAME", "")
|
|
CELERY_BROKER_VHOST = ENV_TOKENS.get("CELERY_BROKER_VHOST", "")
|
|
CELERY_BROKER_USER = AUTH_TOKENS.get("CELERY_BROKER_USER", "")
|
|
CELERY_BROKER_PASSWORD = AUTH_TOKENS.get("CELERY_BROKER_PASSWORD", "")
|
|
|
|
BROKER_URL = "{}://{}:{}@{}/{}".format(CELERY_BROKER_TRANSPORT,
|
|
CELERY_BROKER_USER,
|
|
CELERY_BROKER_PASSWORD,
|
|
CELERY_BROKER_HOSTNAME,
|
|
CELERY_BROKER_VHOST)
|
|
BROKER_USE_SSL = ENV_TOKENS.get('CELERY_BROKER_USE_SSL', False)
|
|
|
|
try:
|
|
BROKER_TRANSPORT_OPTIONS = {
|
|
'fanout_patterns': True,
|
|
'fanout_prefix': True,
|
|
**ENV_TOKENS.get('CELERY_BROKER_TRANSPORT_OPTIONS', {})
|
|
}
|
|
except TypeError as exc:
|
|
raise ImproperlyConfigured('CELERY_BROKER_TRANSPORT_OPTIONS must be a dict') from exc
|
|
|
|
# Block Structures
|
|
|
|
# upload limits
|
|
STUDENT_FILEUPLOAD_MAX_SIZE = ENV_TOKENS.get("STUDENT_FILEUPLOAD_MAX_SIZE", STUDENT_FILEUPLOAD_MAX_SIZE)
|
|
|
|
# Event tracking
|
|
TRACKING_BACKENDS.update(AUTH_TOKENS.get("TRACKING_BACKENDS", {}))
|
|
EVENT_TRACKING_BACKENDS['tracking_logs']['OPTIONS']['backends'].update(AUTH_TOKENS.get("EVENT_TRACKING_BACKENDS", {}))
|
|
EVENT_TRACKING_BACKENDS['segmentio']['OPTIONS']['processors'][0]['OPTIONS']['whitelist'].extend(
|
|
AUTH_TOKENS.get("EVENT_TRACKING_SEGMENTIO_EMIT_WHITELIST", []))
|
|
TRACKING_SEGMENTIO_WEBHOOK_SECRET = AUTH_TOKENS.get(
|
|
"TRACKING_SEGMENTIO_WEBHOOK_SECRET",
|
|
TRACKING_SEGMENTIO_WEBHOOK_SECRET
|
|
)
|
|
TRACKING_SEGMENTIO_ALLOWED_TYPES = ENV_TOKENS.get("TRACKING_SEGMENTIO_ALLOWED_TYPES", TRACKING_SEGMENTIO_ALLOWED_TYPES)
|
|
TRACKING_SEGMENTIO_DISALLOWED_SUBSTRING_NAMES = ENV_TOKENS.get(
|
|
"TRACKING_SEGMENTIO_DISALLOWED_SUBSTRING_NAMES",
|
|
TRACKING_SEGMENTIO_DISALLOWED_SUBSTRING_NAMES
|
|
)
|
|
TRACKING_SEGMENTIO_SOURCE_MAP = ENV_TOKENS.get("TRACKING_SEGMENTIO_SOURCE_MAP", TRACKING_SEGMENTIO_SOURCE_MAP)
|
|
|
|
# Heartbeat
|
|
HEARTBEAT_CELERY_ROUTING_KEY = ENV_TOKENS.get('HEARTBEAT_CELERY_ROUTING_KEY', HEARTBEAT_CELERY_ROUTING_KEY)
|
|
|
|
# Student identity verification settings
|
|
VERIFY_STUDENT = AUTH_TOKENS.get("VERIFY_STUDENT", VERIFY_STUDENT)
|
|
DISABLE_ACCOUNT_ACTIVATION_REQUIREMENT_SWITCH = ENV_TOKENS.get(
|
|
"DISABLE_ACCOUNT_ACTIVATION_REQUIREMENT_SWITCH",
|
|
DISABLE_ACCOUNT_ACTIVATION_REQUIREMENT_SWITCH
|
|
)
|
|
|
|
# Grades download
|
|
GRADES_DOWNLOAD_ROUTING_KEY = ENV_TOKENS.get('GRADES_DOWNLOAD_ROUTING_KEY', HIGH_MEM_QUEUE)
|
|
|
|
GRADES_DOWNLOAD = ENV_TOKENS.get("GRADES_DOWNLOAD", GRADES_DOWNLOAD)
|
|
|
|
# Rate limit for regrading tasks that a grading policy change can kick off
|
|
|
|
# financial reports
|
|
FINANCIAL_REPORTS = ENV_TOKENS.get("FINANCIAL_REPORTS", FINANCIAL_REPORTS)
|
|
|
|
##### ORA2 ######
|
|
# Prefix for uploads of example-based assessment AI classifiers
|
|
# This can be used to separate uploads for different environments
|
|
# within the same S3 bucket.
|
|
ORA2_FILE_PREFIX = ENV_TOKENS.get("ORA2_FILE_PREFIX", ORA2_FILE_PREFIX)
|
|
|
|
##### ACCOUNT LOCKOUT DEFAULT PARAMETERS #####
|
|
MAX_FAILED_LOGIN_ATTEMPTS_ALLOWED = ENV_TOKENS.get(
|
|
"MAX_FAILED_LOGIN_ATTEMPTS_ALLOWED", MAX_FAILED_LOGIN_ATTEMPTS_ALLOWED
|
|
)
|
|
|
|
MAX_FAILED_LOGIN_ATTEMPTS_LOCKOUT_PERIOD_SECS = ENV_TOKENS.get(
|
|
"MAX_FAILED_LOGIN_ATTEMPTS_LOCKOUT_PERIOD_SECS", MAX_FAILED_LOGIN_ATTEMPTS_LOCKOUT_PERIOD_SECS
|
|
)
|
|
|
|
##### LOGISTRATION RATE LIMIT SETTINGS #####
|
|
LOGISTRATION_RATELIMIT_RATE = ENV_TOKENS.get('LOGISTRATION_RATELIMIT_RATE', LOGISTRATION_RATELIMIT_RATE)
|
|
LOGISTRATION_API_RATELIMIT = ENV_TOKENS.get('LOGISTRATION_API_RATELIMIT', LOGISTRATION_API_RATELIMIT)
|
|
LOGIN_AND_REGISTER_FORM_RATELIMIT = ENV_TOKENS.get(
|
|
'LOGIN_AND_REGISTER_FORM_RATELIMIT', LOGIN_AND_REGISTER_FORM_RATELIMIT
|
|
)
|
|
RESET_PASSWORD_TOKEN_VALIDATE_API_RATELIMIT = ENV_TOKENS.get(
|
|
'RESET_PASSWORD_TOKEN_VALIDATE_API_RATELIMIT', RESET_PASSWORD_TOKEN_VALIDATE_API_RATELIMIT
|
|
)
|
|
RESET_PASSWORD_API_RATELIMIT = ENV_TOKENS.get('RESET_PASSWORD_API_RATELIMIT', RESET_PASSWORD_API_RATELIMIT)
|
|
|
|
##### REGISTRATION RATE LIMIT SETTINGS #####
|
|
REGISTRATION_VALIDATION_RATELIMIT = ENV_TOKENS.get(
|
|
'REGISTRATION_VALIDATION_RATELIMIT', REGISTRATION_VALIDATION_RATELIMIT
|
|
)
|
|
|
|
REGISTRATION_RATELIMIT = ENV_TOKENS.get('REGISTRATION_RATELIMIT', REGISTRATION_RATELIMIT)
|
|
|
|
#### PASSWORD POLICY SETTINGS #####
|
|
AUTH_PASSWORD_VALIDATORS = ENV_TOKENS.get("AUTH_PASSWORD_VALIDATORS", AUTH_PASSWORD_VALIDATORS)
|
|
|
|
### INACTIVITY SETTINGS ####
|
|
SESSION_INACTIVITY_TIMEOUT_IN_SECONDS = AUTH_TOKENS.get("SESSION_INACTIVITY_TIMEOUT_IN_SECONDS")
|
|
|
|
##### LMS DEADLINE DISPLAY TIME_ZONE #######
|
|
TIME_ZONE_DISPLAYED_FOR_DEADLINES = ENV_TOKENS.get("TIME_ZONE_DISPLAYED_FOR_DEADLINES",
|
|
TIME_ZONE_DISPLAYED_FOR_DEADLINES)
|
|
|
|
#### PROCTORED EXAM SETTINGS ####
|
|
PROCTORED_EXAM_VIEWABLE_PAST_DUE = ENV_TOKENS.get('PROCTORED_EXAM_VIEWABLE_PAST_DUE', False)
|
|
|
|
##### Third-party auth options ################################################
|
|
ENABLE_REQUIRE_THIRD_PARTY_AUTH = ENV_TOKENS.get('ENABLE_REQUIRE_THIRD_PARTY_AUTH', False)
|
|
|
|
if FEATURES.get('ENABLE_THIRD_PARTY_AUTH'):
|
|
tmp_backends = ENV_TOKENS.get('THIRD_PARTY_AUTH_BACKENDS', [
|
|
'social_core.backends.google.GoogleOAuth2',
|
|
'social_core.backends.linkedin.LinkedinOAuth2',
|
|
'social_core.backends.facebook.FacebookOAuth2',
|
|
'social_core.backends.azuread.AzureADOAuth2',
|
|
'common.djangoapps.third_party_auth.appleid.AppleIdAuth', # vendored 'social_core.backends.apple.AppleIdAuth'
|
|
'common.djangoapps.third_party_auth.identityserver3.IdentityServer3',
|
|
'common.djangoapps.third_party_auth.saml.SAMLAuthBackend',
|
|
'common.djangoapps.third_party_auth.lti.LTIAuthBackend',
|
|
])
|
|
|
|
AUTHENTICATION_BACKENDS = list(tmp_backends) + list(AUTHENTICATION_BACKENDS)
|
|
del tmp_backends
|
|
|
|
# The reduced session expiry time during the third party login pipeline. (Value in seconds)
|
|
SOCIAL_AUTH_PIPELINE_TIMEOUT = ENV_TOKENS.get('SOCIAL_AUTH_PIPELINE_TIMEOUT', 600)
|
|
|
|
# Most provider configuration is done via ConfigurationModels but for a few sensitive values
|
|
# we allow configuration via AUTH_TOKENS instead (optionally).
|
|
# The SAML private/public key values do not need the delimiter lines (such as
|
|
# "-----BEGIN PRIVATE KEY-----", "-----END PRIVATE KEY-----" etc.) but they may be included
|
|
# if you want (though it's easier to format the key values as JSON without the delimiters).
|
|
SOCIAL_AUTH_SAML_SP_PRIVATE_KEY = AUTH_TOKENS.get('SOCIAL_AUTH_SAML_SP_PRIVATE_KEY', '')
|
|
SOCIAL_AUTH_SAML_SP_PUBLIC_CERT = AUTH_TOKENS.get('SOCIAL_AUTH_SAML_SP_PUBLIC_CERT', '')
|
|
SOCIAL_AUTH_SAML_SP_PRIVATE_KEY_DICT = AUTH_TOKENS.get('SOCIAL_AUTH_SAML_SP_PRIVATE_KEY_DICT', {})
|
|
SOCIAL_AUTH_SAML_SP_PUBLIC_CERT_DICT = AUTH_TOKENS.get('SOCIAL_AUTH_SAML_SP_PUBLIC_CERT_DICT', {})
|
|
SOCIAL_AUTH_OAUTH_SECRETS = AUTH_TOKENS.get('SOCIAL_AUTH_OAUTH_SECRETS', {})
|
|
SOCIAL_AUTH_LTI_CONSUMER_SECRETS = AUTH_TOKENS.get('SOCIAL_AUTH_LTI_CONSUMER_SECRETS', {})
|
|
|
|
# third_party_auth config moved to ConfigurationModels. This is for data migration only:
|
|
THIRD_PARTY_AUTH_OLD_CONFIG = AUTH_TOKENS.get('THIRD_PARTY_AUTH', None)
|
|
|
|
if ENV_TOKENS.get('THIRD_PARTY_AUTH_SAML_FETCH_PERIOD_HOURS', 24) is not None:
|
|
CELERYBEAT_SCHEDULE['refresh-saml-metadata'] = {
|
|
'task': 'common.djangoapps.third_party_auth.fetch_saml_metadata',
|
|
'schedule': datetime.timedelta(hours=ENV_TOKENS.get('THIRD_PARTY_AUTH_SAML_FETCH_PERIOD_HOURS', 24)),
|
|
}
|
|
|
|
# The following can be used to integrate a custom login form with third_party_auth.
|
|
# It should be a dict where the key is a word passed via ?auth_entry=, and the value is a
|
|
# dict with an arbitrary 'secret_key' and a 'url'.
|
|
THIRD_PARTY_AUTH_CUSTOM_AUTH_FORMS = AUTH_TOKENS.get('THIRD_PARTY_AUTH_CUSTOM_AUTH_FORMS', {})
|
|
|
|
##### OAUTH2 Provider ##############
|
|
if FEATURES.get('ENABLE_OAUTH2_PROVIDER'):
|
|
OAUTH_ENFORCE_SECURE = ENV_TOKENS.get('OAUTH_ENFORCE_SECURE', True)
|
|
OAUTH_ENFORCE_CLIENT_SECURE = ENV_TOKENS.get('OAUTH_ENFORCE_CLIENT_SECURE', True)
|
|
# Defaults for the following are defined in lms.envs.common
|
|
OAUTH_EXPIRE_DELTA = datetime.timedelta(
|
|
days=ENV_TOKENS.get('OAUTH_EXPIRE_CONFIDENTIAL_CLIENT_DAYS', OAUTH_EXPIRE_CONFIDENTIAL_CLIENT_DAYS)
|
|
)
|
|
OAUTH_EXPIRE_DELTA_PUBLIC = datetime.timedelta(
|
|
days=ENV_TOKENS.get('OAUTH_EXPIRE_PUBLIC_CLIENT_DAYS', OAUTH_EXPIRE_PUBLIC_CLIENT_DAYS)
|
|
)
|
|
|
|
|
|
##### GOOGLE ANALYTICS IDS #####
|
|
GOOGLE_ANALYTICS_ACCOUNT = AUTH_TOKENS.get('GOOGLE_ANALYTICS_ACCOUNT')
|
|
GOOGLE_ANALYTICS_TRACKING_ID = AUTH_TOKENS.get('GOOGLE_ANALYTICS_TRACKING_ID')
|
|
GOOGLE_ANALYTICS_LINKEDIN = AUTH_TOKENS.get('GOOGLE_ANALYTICS_LINKEDIN')
|
|
GOOGLE_SITE_VERIFICATION_ID = ENV_TOKENS.get('GOOGLE_SITE_VERIFICATION_ID')
|
|
|
|
##### BRANCH.IO KEY #####
|
|
BRANCH_IO_KEY = AUTH_TOKENS.get('BRANCH_IO_KEY')
|
|
|
|
#### Course Registration Code length ####
|
|
REGISTRATION_CODE_LENGTH = ENV_TOKENS.get('REGISTRATION_CODE_LENGTH', 8)
|
|
|
|
# Which access.py permission names to check;
|
|
# We default this to the legacy permission 'see_exists'.
|
|
COURSE_CATALOG_VISIBILITY_PERMISSION = ENV_TOKENS.get(
|
|
'COURSE_CATALOG_VISIBILITY_PERMISSION',
|
|
COURSE_CATALOG_VISIBILITY_PERMISSION
|
|
)
|
|
COURSE_ABOUT_VISIBILITY_PERMISSION = ENV_TOKENS.get(
|
|
'COURSE_ABOUT_VISIBILITY_PERMISSION',
|
|
COURSE_ABOUT_VISIBILITY_PERMISSION
|
|
)
|
|
|
|
DEFAULT_COURSE_VISIBILITY_IN_CATALOG = ENV_TOKENS.get(
|
|
'DEFAULT_COURSE_VISIBILITY_IN_CATALOG',
|
|
DEFAULT_COURSE_VISIBILITY_IN_CATALOG
|
|
)
|
|
|
|
DEFAULT_MOBILE_AVAILABLE = ENV_TOKENS.get(
|
|
'DEFAULT_MOBILE_AVAILABLE',
|
|
DEFAULT_MOBILE_AVAILABLE
|
|
)
|
|
|
|
# Enrollment API Cache Timeout
|
|
ENROLLMENT_COURSE_DETAILS_CACHE_TIMEOUT = ENV_TOKENS.get('ENROLLMENT_COURSE_DETAILS_CACHE_TIMEOUT', 60)
|
|
|
|
# Ecommerce Orders API Cache Timeout
|
|
ECOMMERCE_ORDERS_API_CACHE_TIMEOUT = ENV_TOKENS.get('ECOMMERCE_ORDERS_API_CACHE_TIMEOUT', 3600)
|
|
|
|
if FEATURES.get('ENABLE_COURSEWARE_SEARCH') or \
|
|
FEATURES.get('ENABLE_DASHBOARD_SEARCH') or \
|
|
FEATURES.get('ENABLE_COURSE_DISCOVERY') or \
|
|
FEATURES.get('ENABLE_TEAMS'):
|
|
# Use ElasticSearch as the search engine herein
|
|
SEARCH_ENGINE = "search.elastic.ElasticSearchEngine"
|
|
SEARCH_FILTER_GENERATOR = ENV_TOKENS.get('SEARCH_FILTER_GENERATOR', SEARCH_FILTER_GENERATOR)
|
|
|
|
# TODO: Once we have successfully upgraded to ES7, switch this back to ELASTIC_SEARCH_CONFIG.
|
|
ELASTIC_SEARCH_CONFIG = ENV_TOKENS.get('ELASTIC_SEARCH_CONFIG_ES7', [{}])
|
|
|
|
# Facebook app
|
|
FACEBOOK_API_VERSION = AUTH_TOKENS.get("FACEBOOK_API_VERSION")
|
|
FACEBOOK_APP_SECRET = AUTH_TOKENS.get("FACEBOOK_APP_SECRET")
|
|
FACEBOOK_APP_ID = AUTH_TOKENS.get("FACEBOOK_APP_ID")
|
|
|
|
XBLOCK_SETTINGS = ENV_TOKENS.get('XBLOCK_SETTINGS', {})
|
|
XBLOCK_SETTINGS.setdefault("VideoBlock", {})["licensing_enabled"] = FEATURES.get("LICENSING", False)
|
|
XBLOCK_SETTINGS.setdefault("VideoBlock", {})['YOUTUBE_API_KEY'] = AUTH_TOKENS.get('YOUTUBE_API_KEY', YOUTUBE_API_KEY)
|
|
|
|
##### Custom Courses for EdX #####
|
|
if FEATURES.get('CUSTOM_COURSES_EDX'):
|
|
INSTALLED_APPS += ['lms.djangoapps.ccx', 'openedx.core.djangoapps.ccxcon.apps.CCXConnectorConfig']
|
|
MODULESTORE_FIELD_OVERRIDE_PROVIDERS += (
|
|
'lms.djangoapps.ccx.overrides.CustomCoursesForEdxOverrideProvider',
|
|
)
|
|
|
|
##### Individual Due Date Extensions #####
|
|
if FEATURES.get('INDIVIDUAL_DUE_DATES'):
|
|
FIELD_OVERRIDE_PROVIDERS += (
|
|
'courseware.student_field_overrides.IndividualStudentOverrideProvider',
|
|
)
|
|
|
|
##### Show Answer Override for Self-Paced Courses #####
|
|
FIELD_OVERRIDE_PROVIDERS += (
|
|
'openedx.features.personalized_learner_schedules.show_answer.show_answer_field_override.ShowAnswerFieldOverride',
|
|
)
|
|
|
|
##### Self-Paced Course Due Dates #####
|
|
XBLOCK_FIELD_DATA_WRAPPERS += (
|
|
'lms.djangoapps.courseware.field_overrides:OverrideModulestoreFieldData.wrap',
|
|
)
|
|
|
|
MODULESTORE_FIELD_OVERRIDE_PROVIDERS += (
|
|
'lms.djangoapps.courseware.self_paced_overrides.SelfPacedDateOverrideProvider',
|
|
)
|
|
|
|
# PROFILE IMAGE CONFIG
|
|
PROFILE_IMAGE_DEFAULT_FILENAME = 'images/profiles/default'
|
|
PROFILE_IMAGE_SIZES_MAP = ENV_TOKENS.get(
|
|
'PROFILE_IMAGE_SIZES_MAP',
|
|
PROFILE_IMAGE_SIZES_MAP
|
|
)
|
|
|
|
##### Credit Provider Integration #####
|
|
|
|
CREDIT_PROVIDER_SECRET_KEYS = AUTH_TOKENS.get("CREDIT_PROVIDER_SECRET_KEYS", {})
|
|
|
|
##################### LTI Provider #####################
|
|
if FEATURES.get('ENABLE_LTI_PROVIDER'):
|
|
INSTALLED_APPS.append('lms.djangoapps.lti_provider.apps.LtiProviderConfig')
|
|
AUTHENTICATION_BACKENDS.append('lms.djangoapps.lti_provider.users.LtiBackend')
|
|
|
|
LTI_USER_EMAIL_DOMAIN = ENV_TOKENS.get('LTI_USER_EMAIL_DOMAIN', 'lti.example.com')
|
|
|
|
# For more info on this, see the notes in common.py
|
|
LTI_AGGREGATE_SCORE_PASSBACK_DELAY = ENV_TOKENS.get(
|
|
'LTI_AGGREGATE_SCORE_PASSBACK_DELAY', LTI_AGGREGATE_SCORE_PASSBACK_DELAY
|
|
)
|
|
|
|
##################### Credit Provider help link ####################
|
|
|
|
#### JWT configuration ####
|
|
JWT_AUTH.update(ENV_TOKENS.get('JWT_AUTH', {}))
|
|
JWT_AUTH.update(AUTH_TOKENS.get('JWT_AUTH', {}))
|
|
|
|
# Offset for pk of courseware.StudentModuleHistoryExtended
|
|
STUDENTMODULEHISTORYEXTENDED_OFFSET = ENV_TOKENS.get(
|
|
'STUDENTMODULEHISTORYEXTENDED_OFFSET', STUDENTMODULEHISTORYEXTENDED_OFFSET
|
|
)
|
|
|
|
################################ Settings for Credentials Service ################################
|
|
|
|
CREDENTIALS_GENERATION_ROUTING_KEY = ENV_TOKENS.get('CREDENTIALS_GENERATION_ROUTING_KEY', DEFAULT_PRIORITY_QUEUE)
|
|
|
|
# Queue to use for award program certificates
|
|
PROGRAM_CERTIFICATES_ROUTING_KEY = ENV_TOKENS.get('PROGRAM_CERTIFICATES_ROUTING_KEY', DEFAULT_PRIORITY_QUEUE)
|
|
SOFTWARE_SECURE_VERIFICATION_ROUTING_KEY = ENV_TOKENS.get(
|
|
'SOFTWARE_SECURE_VERIFICATION_ROUTING_KEY',
|
|
HIGH_PRIORITY_QUEUE
|
|
)
|
|
|
|
API_ACCESS_MANAGER_EMAIL = ENV_TOKENS.get('API_ACCESS_MANAGER_EMAIL')
|
|
API_ACCESS_FROM_EMAIL = ENV_TOKENS.get('API_ACCESS_FROM_EMAIL')
|
|
|
|
############## OPEN EDX ENTERPRISE SERVICE CONFIGURATION ######################
|
|
# The Open edX Enterprise service is currently hosted via the LMS container/process.
|
|
# However, for all intents and purposes this service is treated as a standalone IDA.
|
|
# These configuration settings are specific to the Enterprise service and you should
|
|
# not find references to them within the edx-platform project.
|
|
|
|
# Publicly-accessible enrollment URL, for use on the client side.
|
|
ENTERPRISE_PUBLIC_ENROLLMENT_API_URL = ENV_TOKENS.get(
|
|
'ENTERPRISE_PUBLIC_ENROLLMENT_API_URL',
|
|
(LMS_ROOT_URL or '') + LMS_ENROLLMENT_API_PATH
|
|
)
|
|
|
|
# Enrollment URL used on the server-side.
|
|
ENTERPRISE_ENROLLMENT_API_URL = ENV_TOKENS.get(
|
|
'ENTERPRISE_ENROLLMENT_API_URL',
|
|
(LMS_INTERNAL_ROOT_URL or '') + LMS_ENROLLMENT_API_PATH
|
|
)
|
|
|
|
# Enterprise logo image size limit in KB's
|
|
ENTERPRISE_CUSTOMER_LOGO_IMAGE_SIZE = ENV_TOKENS.get(
|
|
'ENTERPRISE_CUSTOMER_LOGO_IMAGE_SIZE',
|
|
ENTERPRISE_CUSTOMER_LOGO_IMAGE_SIZE
|
|
)
|
|
|
|
# Course enrollment modes to be hidden in the Enterprise enrollment page
|
|
# if the "Hide audit track" flag is enabled for an EnterpriseCustomer
|
|
ENTERPRISE_COURSE_ENROLLMENT_AUDIT_MODES = ENV_TOKENS.get(
|
|
'ENTERPRISE_COURSE_ENROLLMENT_AUDIT_MODES',
|
|
ENTERPRISE_COURSE_ENROLLMENT_AUDIT_MODES
|
|
)
|
|
|
|
# A support URL used on Enterprise landing pages for when a warning
|
|
# message goes off.
|
|
ENTERPRISE_SUPPORT_URL = ENV_TOKENS.get(
|
|
'ENTERPRISE_SUPPORT_URL',
|
|
ENTERPRISE_SUPPORT_URL
|
|
)
|
|
|
|
# A default dictionary to be used for filtering out enterprise customer catalog.
|
|
ENTERPRISE_CUSTOMER_CATALOG_DEFAULT_CONTENT_FILTER = ENV_TOKENS.get(
|
|
'ENTERPRISE_CUSTOMER_CATALOG_DEFAULT_CONTENT_FILTER',
|
|
ENTERPRISE_CUSTOMER_CATALOG_DEFAULT_CONTENT_FILTER
|
|
)
|
|
INTEGRATED_CHANNELS_API_CHUNK_TRANSMISSION_LIMIT = ENV_TOKENS.get(
|
|
'INTEGRATED_CHANNELS_API_CHUNK_TRANSMISSION_LIMIT',
|
|
INTEGRATED_CHANNELS_API_CHUNK_TRANSMISSION_LIMIT
|
|
)
|
|
|
|
############## ENTERPRISE SERVICE API CLIENT CONFIGURATION ######################
|
|
# The LMS communicates with the Enterprise service via the EdxRestApiClient class
|
|
# The below environmental settings are utilized by the LMS when interacting with
|
|
# the service, and override the default parameters which are defined in common.py
|
|
|
|
DEFAULT_ENTERPRISE_API_URL = None
|
|
if LMS_INTERNAL_ROOT_URL is not None:
|
|
DEFAULT_ENTERPRISE_API_URL = LMS_INTERNAL_ROOT_URL + '/enterprise/api/v1/'
|
|
ENTERPRISE_API_URL = ENV_TOKENS.get('ENTERPRISE_API_URL', DEFAULT_ENTERPRISE_API_URL)
|
|
|
|
DEFAULT_ENTERPRISE_CONSENT_API_URL = None
|
|
if LMS_INTERNAL_ROOT_URL is not None:
|
|
DEFAULT_ENTERPRISE_CONSENT_API_URL = LMS_INTERNAL_ROOT_URL + '/consent/api/v1/'
|
|
ENTERPRISE_CONSENT_API_URL = ENV_TOKENS.get('ENTERPRISE_CONSENT_API_URL', DEFAULT_ENTERPRISE_CONSENT_API_URL)
|
|
|
|
ENTERPRISE_SERVICE_WORKER_USERNAME = ENV_TOKENS.get(
|
|
'ENTERPRISE_SERVICE_WORKER_USERNAME',
|
|
ENTERPRISE_SERVICE_WORKER_USERNAME
|
|
)
|
|
ENTERPRISE_API_CACHE_TIMEOUT = ENV_TOKENS.get(
|
|
'ENTERPRISE_API_CACHE_TIMEOUT',
|
|
ENTERPRISE_API_CACHE_TIMEOUT
|
|
)
|
|
ENTERPRISE_CATALOG_INTERNAL_ROOT_URL = ENV_TOKENS.get(
|
|
'ENTERPRISE_CATALOG_INTERNAL_ROOT_URL',
|
|
ENTERPRISE_CATALOG_INTERNAL_ROOT_URL
|
|
)
|
|
|
|
############## ENTERPRISE SERVICE LMS CONFIGURATION ##################################
|
|
# The LMS has some features embedded that are related to the Enterprise service, but
|
|
# which are not provided by the Enterprise service. These settings override the
|
|
# base values for the parameters as defined in common.py
|
|
|
|
ENTERPRISE_PLATFORM_WELCOME_TEMPLATE = ENV_TOKENS.get(
|
|
'ENTERPRISE_PLATFORM_WELCOME_TEMPLATE',
|
|
ENTERPRISE_PLATFORM_WELCOME_TEMPLATE
|
|
)
|
|
ENTERPRISE_SPECIFIC_BRANDED_WELCOME_TEMPLATE = ENV_TOKENS.get(
|
|
'ENTERPRISE_SPECIFIC_BRANDED_WELCOME_TEMPLATE',
|
|
ENTERPRISE_SPECIFIC_BRANDED_WELCOME_TEMPLATE
|
|
)
|
|
ENTERPRISE_TAGLINE = ENV_TOKENS.get(
|
|
'ENTERPRISE_TAGLINE',
|
|
ENTERPRISE_TAGLINE
|
|
)
|
|
ENTERPRISE_EXCLUDED_REGISTRATION_FIELDS = set(
|
|
ENV_TOKENS.get(
|
|
'ENTERPRISE_EXCLUDED_REGISTRATION_FIELDS',
|
|
ENTERPRISE_EXCLUDED_REGISTRATION_FIELDS
|
|
)
|
|
)
|
|
BASE_COOKIE_DOMAIN = ENV_TOKENS.get(
|
|
'BASE_COOKIE_DOMAIN',
|
|
BASE_COOKIE_DOMAIN
|
|
)
|
|
SYSTEM_TO_FEATURE_ROLE_MAPPING = ENV_TOKENS.get(
|
|
'SYSTEM_TO_FEATURE_ROLE_MAPPING',
|
|
SYSTEM_TO_FEATURE_ROLE_MAPPING
|
|
)
|
|
|
|
# Add an ICP license for serving content in China if your organization is registered to do so
|
|
ICP_LICENSE = ENV_TOKENS.get('ICP_LICENSE', None)
|
|
ICP_LICENSE_INFO = ENV_TOKENS.get('ICP_LICENSE_INFO', {})
|
|
|
|
# How long to cache OpenAPI schemas and UI, in seconds.
|
|
OPENAPI_CACHE_TIMEOUT = ENV_TOKENS.get('OPENAPI_CACHE_TIMEOUT', 60 * 60)
|
|
|
|
########################## Parental controls config #######################
|
|
|
|
# The age at which a learner no longer requires parental consent, or None
|
|
# if parental consent is never required.
|
|
PARENTAL_CONSENT_AGE_LIMIT = ENV_TOKENS.get(
|
|
'PARENTAL_CONSENT_AGE_LIMIT',
|
|
PARENTAL_CONSENT_AGE_LIMIT
|
|
)
|
|
|
|
########################## Extra middleware classes #######################
|
|
|
|
# Allow extra middleware classes to be added to the app through configuration.
|
|
MIDDLEWARE.extend(ENV_TOKENS.get('EXTRA_MIDDLEWARE_CLASSES', []))
|
|
|
|
################# Settings for the maintenance banner #################
|
|
MAINTENANCE_BANNER_TEXT = ENV_TOKENS.get('MAINTENANCE_BANNER_TEXT', None)
|
|
|
|
########################## limiting dashboard courses ######################
|
|
DASHBOARD_COURSE_LIMIT = ENV_TOKENS.get('DASHBOARD_COURSE_LIMIT', None)
|
|
|
|
######################## Setting for content libraries ########################
|
|
MAX_BLOCKS_PER_CONTENT_LIBRARY = ENV_TOKENS.get('MAX_BLOCKS_PER_CONTENT_LIBRARY', MAX_BLOCKS_PER_CONTENT_LIBRARY)
|
|
|
|
############################### Plugin Settings ###############################
|
|
|
|
# This is at the bottom because it is going to load more settings after base settings are loaded
|
|
|
|
# Load production.py in plugins
|
|
add_plugins(__name__, ProjectType.LMS, SettingsType.PRODUCTION)
|
|
|
|
########################## Derive Any Derived Settings #######################
|
|
|
|
derive_settings(__name__)
|
|
|
|
############## Settings for Completion API #########################
|
|
|
|
# Once a user has watched this percentage of a video, mark it as complete:
|
|
# (0.0 = 0%, 1.0 = 100%)
|
|
COMPLETION_VIDEO_COMPLETE_PERCENTAGE = ENV_TOKENS.get('COMPLETION_VIDEO_COMPLETE_PERCENTAGE',
|
|
COMPLETION_VIDEO_COMPLETE_PERCENTAGE)
|
|
COMPLETION_BY_VIEWING_DELAY_MS = ENV_TOKENS.get('COMPLETION_BY_VIEWING_DELAY_MS',
|
|
COMPLETION_BY_VIEWING_DELAY_MS)
|
|
|
|
################# Settings for brand logos. #################
|
|
LOGO_URL = ENV_TOKENS.get('LOGO_URL', LOGO_URL)
|
|
LOGO_URL_PNG = ENV_TOKENS.get('LOGO_URL_PNG', LOGO_URL_PNG)
|
|
LOGO_TRADEMARK_URL = ENV_TOKENS.get('LOGO_TRADEMARK_URL', LOGO_TRADEMARK_URL)
|
|
FAVICON_URL = ENV_TOKENS.get('FAVICON_URL', FAVICON_URL)
|
|
|
|
######################## CELERY ROUTING ########################
|
|
|
|
# Defines alternate environment tasks, as a dict of form { task_name: alternate_queue }
|
|
ALTERNATE_ENV_TASKS = {}
|
|
|
|
# Defines the task -> alternate worker queue to be used when routing.
|
|
EXPLICIT_QUEUES = {
|
|
'openedx.core.djangoapps.content.course_overviews.tasks.async_course_overview_update': {
|
|
'queue': GRADES_DOWNLOAD_ROUTING_KEY},
|
|
'lms.djangoapps.bulk_email.tasks.send_course_email': {
|
|
'queue': BULK_EMAIL_ROUTING_KEY},
|
|
'openedx.core.djangoapps.heartbeat.tasks.sample_task': {
|
|
'queue': HEARTBEAT_CELERY_ROUTING_KEY},
|
|
'lms.djangoapps.instructor_task.tasks.calculate_grades_csv': {
|
|
'queue': GRADES_DOWNLOAD_ROUTING_KEY},
|
|
'lms.djangoapps.instructor_task.tasks.calculate_problem_grade_report': {
|
|
'queue': GRADES_DOWNLOAD_ROUTING_KEY},
|
|
'lms.djangoapps.instructor_task.tasks.generate_certificates': {
|
|
'queue': GRADES_DOWNLOAD_ROUTING_KEY},
|
|
'lms.djangoapps.verify_student.tasks.send_verification_status_email': {
|
|
'queue': ACE_ROUTING_KEY},
|
|
'lms.djangoapps.verify_student.tasks.send_ace_message': {
|
|
'queue': ACE_ROUTING_KEY},
|
|
'lms.djangoapps.verify_student.tasks.send_request_to_ss_for_user': {
|
|
'queue': SOFTWARE_SECURE_VERIFICATION_ROUTING_KEY},
|
|
'openedx.core.djangoapps.schedules.tasks._recurring_nudge_schedule_send': {
|
|
'queue': ACE_ROUTING_KEY},
|
|
'openedx.core.djangoapps.schedules.tasks._upgrade_reminder_schedule_send': {
|
|
'queue': ACE_ROUTING_KEY},
|
|
'openedx.core.djangoapps.schedules.tasks._course_update_schedule_send': {
|
|
'queue': ACE_ROUTING_KEY},
|
|
'openedx.core.djangoapps.schedules.tasks.v1.tasks.send_grade_to_credentials': {
|
|
'queue': CREDENTIALS_GENERATION_ROUTING_KEY},
|
|
'common.djangoapps.entitlements.tasks.expire_old_entitlements': {
|
|
'queue': ENTITLEMENTS_EXPIRATION_ROUTING_KEY},
|
|
'lms.djangoapps.grades.tasks.recalculate_course_and_subsection_grades_for_user': {
|
|
'queue': POLICY_CHANGE_GRADES_ROUTING_KEY},
|
|
'lms.djangoapps.grades.tasks.recalculate_subsection_grade_v3': {
|
|
'queue': RECALCULATE_GRADES_ROUTING_KEY},
|
|
'openedx.core.djangoapps.programs.tasks.award_program_certificates': {
|
|
'queue': PROGRAM_CERTIFICATES_ROUTING_KEY},
|
|
'openedx.core.djangoapps.programs.tasks.revoke_program_certificates': {
|
|
'queue': PROGRAM_CERTIFICATES_ROUTING_KEY},
|
|
'openedx.core.djangoapps.programs.tasks.update_certificate_visible_date_on_course_update': {
|
|
'queue': PROGRAM_CERTIFICATES_ROUTING_KEY},
|
|
'openedx.core.djangoapps.programs.tasks.award_course_certificate': {
|
|
'queue': PROGRAM_CERTIFICATES_ROUTING_KEY},
|
|
}
|
|
|
|
LOGO_IMAGE_EXTRA_TEXT = ENV_TOKENS.get('LOGO_IMAGE_EXTRA_TEXT', '')
|
|
|
|
############## XBlock extra mixins ############################
|
|
XBLOCK_MIXINS += tuple(XBLOCK_EXTRA_MIXINS)
|
|
|
|
############## Settings for course import olx validation ############################
|
|
COURSE_OLX_VALIDATION_STAGE = ENV_TOKENS.get('COURSE_OLX_VALIDATION_STAGE', COURSE_OLX_VALIDATION_STAGE)
|
|
COURSE_OLX_VALIDATION_IGNORE_LIST = ENV_TOKENS.get(
|
|
'COURSE_OLX_VALIDATION_IGNORE_LIST',
|
|
COURSE_OLX_VALIDATION_IGNORE_LIST
|
|
)
|
|
|
|
################# show account activate cta after register ########################
|
|
SHOW_ACCOUNT_ACTIVATION_CTA = ENV_TOKENS.get('SHOW_ACCOUNT_ACTIVATION_CTA', SHOW_ACCOUNT_ACTIVATION_CTA)
|
|
|
|
################# Settings for Chrome-specific origin trials ########
|
|
# Token for "Disable Different Origin Subframe Dialog Suppression" Chrome Origin Trial, which must be origin-specific.
|
|
CHROME_DISABLE_SUBFRAME_DIALOG_SUPPRESSION_TOKEN = ENV_TOKENS.get(
|
|
'CHROME_DISABLE_SUBFRAME_DIALOG_SUPPRESSION_TOKEN', CHROME_DISABLE_SUBFRAME_DIALOG_SUPPRESSION_TOKEN
|
|
)
|