refactor: bring common settings into common module (#37746)
This commit is contained in:
@@ -46,16 +46,13 @@ from datetime import timedelta
|
||||
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
import lms.envs.common
|
||||
|
||||
from openedx.envs.common import * # pylint: disable=wildcard-import
|
||||
|
||||
from path import Path as path
|
||||
|
||||
from lms.djangoapps.lms_xblock.mixin import LmsBlockMixin
|
||||
from cms.lib.xblock.authoring_mixin import AuthoringMixin
|
||||
from cms.lib.xblock.upstream_sync import UpstreamSyncMixin
|
||||
from xmodule.modulestore.edit_info import EditInfoMixin
|
||||
from xmodule.x_module import ResourceTemplates
|
||||
from openedx.core.lib.derived import Derived
|
||||
from openedx.core.lib.features_setting_proxy import FeaturesProxy
|
||||
|
||||
@@ -269,117 +266,50 @@ MARKETING_EMAILS_OPT_IN = False
|
||||
############################# MICROFRONTENDS ###################################
|
||||
COURSE_AUTHORING_MICROFRONTEND_URL = None
|
||||
|
||||
############################# SOCIAL MEDIA SHARING #############################
|
||||
SOCIAL_SHARING_SETTINGS = {
|
||||
# Note: Ensure 'CUSTOM_COURSE_URLS' has a matching value in lms/envs/common.py
|
||||
'CUSTOM_COURSE_URLS': False,
|
||||
'DASHBOARD_FACEBOOK': False,
|
||||
'CERTIFICATE_FACEBOOK': False,
|
||||
'CERTIFICATE_TWITTER': False,
|
||||
'DASHBOARD_TWITTER': False
|
||||
}
|
||||
|
||||
############################# SET PATH INFORMATION #############################
|
||||
PROJECT_ROOT = path(__file__).abspath().dirname().dirname() # /edx-platform/cms
|
||||
REPO_ROOT = PROJECT_ROOT.dirname()
|
||||
COMMON_ROOT = REPO_ROOT / "common"
|
||||
OPENEDX_ROOT = REPO_ROOT / "openedx"
|
||||
CMS_ROOT = REPO_ROOT / "cms"
|
||||
LMS_ROOT = REPO_ROOT / "lms"
|
||||
ENV_ROOT = REPO_ROOT.dirname() # virtualenv dir /edx-platform is in
|
||||
COURSES_ROOT = ENV_ROOT / "data"
|
||||
XMODULE_ROOT = REPO_ROOT / "xmodule"
|
||||
|
||||
GITHUB_REPO_ROOT = ENV_ROOT / "data"
|
||||
|
||||
# For geolocation ip database
|
||||
GEOIP_PATH = REPO_ROOT / "common/static/data/geoip/GeoLite2-Country.mmdb"
|
||||
|
||||
DATA_DIR = COURSES_ROOT
|
||||
|
||||
######################## BRANCH.IO ###########################
|
||||
BRANCH_IO_KEY = ''
|
||||
|
||||
######################## GOOGLE ANALYTICS ###########################
|
||||
GOOGLE_ANALYTICS_ACCOUNT = None
|
||||
|
||||
######################## HOTJAR ###########################
|
||||
HOTJAR_ID = 00000
|
||||
|
||||
############################# TEMPLATE CONFIGURATION #############################
|
||||
# Mako templating
|
||||
import tempfile
|
||||
MAKO_MODULE_DIR = os.path.join(tempfile.gettempdir(), 'mako_cms')
|
||||
MAKO_TEMPLATE_DIRS_BASE = [
|
||||
PROJECT_ROOT / 'templates',
|
||||
COMMON_ROOT / 'templates',
|
||||
COMMON_ROOT / 'djangoapps' / 'pipeline_mako' / 'templates',
|
||||
COMMON_ROOT / 'static', # required to statically include common Underscore templates
|
||||
OPENEDX_ROOT / 'core' / 'djangoapps' / 'cors_csrf' / 'templates',
|
||||
OPENEDX_ROOT / 'core' / 'djangoapps' / 'dark_lang' / 'templates',
|
||||
OPENEDX_ROOT / 'core' / 'lib' / 'license' / 'templates',
|
||||
CMS_ROOT / 'djangoapps' / 'pipeline_js' / 'templates',
|
||||
XMODULE_ROOT / 'capa' / 'templates',
|
||||
]
|
||||
|
||||
CONTEXT_PROCESSORS = (
|
||||
'django.template.context_processors.request',
|
||||
'django.template.context_processors.static',
|
||||
'django.contrib.messages.context_processors.messages',
|
||||
'django.template.context_processors.i18n',
|
||||
'django.contrib.auth.context_processors.auth', # this is required for admin
|
||||
'django.template.context_processors.csrf',
|
||||
'help_tokens.context_processor',
|
||||
'openedx.core.djangoapps.site_configuration.context_processors.configuration_context',
|
||||
)
|
||||
MAKO_TEMPLATE_DIRS_BASE.insert(3, COMMON_ROOT / 'static')
|
||||
MAKO_TEMPLATE_DIRS_BASE.append(CMS_ROOT / 'djangoapps' / 'pipeline_js' / 'templates')
|
||||
MAKO_TEMPLATE_DIRS_BASE.append(XMODULE_ROOT / 'capa' / 'templates')
|
||||
|
||||
# Django templating
|
||||
TEMPLATES = [
|
||||
{
|
||||
'NAME': 'django',
|
||||
'BACKEND': 'django.template.backends.django.DjangoTemplates',
|
||||
# Don't look for template source files inside installed applications.
|
||||
'APP_DIRS': False,
|
||||
# Instead, look for template source files in these dirs.
|
||||
'DIRS': Derived(make_mako_template_dirs),
|
||||
# Options specific to this backend.
|
||||
'OPTIONS': {
|
||||
'loaders': (
|
||||
# We have to use mako-aware template loaders to be able to include
|
||||
# mako templates inside django templates (such as main_django.html).
|
||||
'openedx.core.djangoapps.theming.template_loaders.ThemeTemplateLoader',
|
||||
'common.djangoapps.edxmako.makoloader.MakoFilesystemLoader',
|
||||
'common.djangoapps.edxmako.makoloader.MakoAppDirectoriesLoader',
|
||||
),
|
||||
'context_processors': CONTEXT_PROCESSORS,
|
||||
# Change 'debug' in your environment settings files - not here.
|
||||
'debug': False
|
||||
}
|
||||
},
|
||||
{
|
||||
'NAME': 'mako',
|
||||
'BACKEND': 'common.djangoapps.edxmako.backend.Mako',
|
||||
'APP_DIRS': False,
|
||||
'DIRS': Derived(make_mako_template_dirs),
|
||||
'OPTIONS': {
|
||||
'context_processors': CONTEXT_PROCESSORS,
|
||||
'debug': False,
|
||||
}
|
||||
},
|
||||
|
||||
def make_lms_template_path(settings):
|
||||
"""
|
||||
Make the path for the LMS "templates" dir
|
||||
"""
|
||||
templates_path = settings.PROJECT_ROOT / 'templates'
|
||||
return templates_path.replace('cms', 'lms')
|
||||
|
||||
lms_mako_template_dirs_base[0] = Derived(make_lms_template_path)
|
||||
|
||||
TEMPLATES[0]['DIRS'] = Derived(make_mako_template_dirs)
|
||||
TEMPLATES.append(
|
||||
{
|
||||
# This separate copy of the Mako backend is used to render previews using the LMS templates
|
||||
'NAME': 'preview',
|
||||
'BACKEND': 'common.djangoapps.edxmako.backend.Mako',
|
||||
'APP_DIRS': False,
|
||||
'DIRS': lms.envs.common.MAKO_TEMPLATE_DIRS_BASE,
|
||||
'DIRS': lms_mako_template_dirs_base,
|
||||
'OPTIONS': {
|
||||
'context_processors': CONTEXT_PROCESSORS,
|
||||
'debug': False,
|
||||
'namespace': 'lms.main',
|
||||
}
|
||||
},
|
||||
]
|
||||
DEFAULT_TEMPLATE_ENGINE = TEMPLATES[0]
|
||||
}
|
||||
)
|
||||
|
||||
#################################### AWS #######################################
|
||||
AWS_SECURITY_TOKEN = None
|
||||
@@ -387,13 +317,8 @@ AWS_SECURITY_TOKEN = None
|
||||
##############################################################################
|
||||
|
||||
# use the ratelimit backend to prevent brute force attacks
|
||||
AUTHENTICATION_BACKENDS = [
|
||||
'auth_backends.backends.EdXOAuth2',
|
||||
'rules.permissions.ObjectPermissionBackend',
|
||||
'openedx.core.djangoapps.content_libraries.auth.LtiAuthenticationBackend',
|
||||
'django.contrib.auth.backends.AllowAllUsersModelBackend',
|
||||
'bridgekeeper.backends.RulePermissionBackend',
|
||||
]
|
||||
AUTHENTICATION_BACKENDS.insert(0, 'auth_backends.backends.EdXOAuth2')
|
||||
AUTHENTICATION_BACKENDS.insert(2, 'openedx.core.djangoapps.content_libraries.auth.LtiAuthenticationBackend')
|
||||
|
||||
LMS_BASE = None
|
||||
|
||||
@@ -416,8 +341,6 @@ CMS_ROOT_URL = None
|
||||
|
||||
MAINTENANCE_BANNER_TEXT = 'Sample banner message'
|
||||
|
||||
WIKI_ENABLED = True
|
||||
|
||||
CERT_QUEUE = 'certificates'
|
||||
|
||||
################################# Middleware ###################################
|
||||
@@ -510,27 +433,14 @@ EXTRA_MIDDLEWARE_CLASSES = []
|
||||
|
||||
############# XBlock Configuration ##########
|
||||
|
||||
# Import after sys.path fixup
|
||||
from xmodule.modulestore.inheritance import InheritanceMixin
|
||||
from xmodule.x_module import XModuleMixin, ResourceTemplates
|
||||
|
||||
# These are the Mixins that will be added to every Blocklike upon instantiation.
|
||||
# DO NOT EXPAND THIS LIST!! We want it eventually to be EMPTY. Why? Because dynamically adding functions/behaviors to
|
||||
# objects at runtime is confusing for both developers and static tooling (pylint/mypy). Instead...
|
||||
# - to add special Blocklike behaviors just for your site: override `XBLOCK_EXTRA_MIXINS` with your own XBlockMixins.
|
||||
# - to add new functionality to all Blocklikes: add it to the base Blocklike class in the core openedx/XBlock repo.
|
||||
XBLOCK_MIXINS = (
|
||||
# TODO: For each of these, either
|
||||
# (a) merge their functionality into the base Blocklike class, or
|
||||
# (b) refactor their functionality out of the Blocklike objects and into the edx-platform block runtimes.
|
||||
LmsBlockMixin,
|
||||
InheritanceMixin,
|
||||
ResourceTemplates,
|
||||
XModuleMixin,
|
||||
EditInfoMixin,
|
||||
# DO NOT EXPAND THIS LIST!! See declaration in openedx/envs/common.py for more information
|
||||
mixins = list(XBLOCK_MIXINS)
|
||||
mixins.insert(2, ResourceTemplates)
|
||||
mixins += [
|
||||
UpstreamSyncMixin, # Should be above AuthoringMixin for UpstreamSyncMixin.editor_saved to take effect
|
||||
AuthoringMixin,
|
||||
)
|
||||
]
|
||||
XBLOCK_MIXINS = tuple(mixins)
|
||||
|
||||
############################ ORA 2 ############################################
|
||||
|
||||
@@ -539,116 +449,19 @@ ORA2_FILE_PREFIX = 'default_env-default_deployment/ora2'
|
||||
|
||||
############################ Modulestore Configuration ################################
|
||||
|
||||
DOC_STORE_CONFIG = {
|
||||
'db': 'edxapp',
|
||||
'host': 'localhost',
|
||||
'replicaSet': '',
|
||||
'user': 'edxapp',
|
||||
'port': 27017,
|
||||
'collection': 'modulestore',
|
||||
'ssl': False,
|
||||
# https://api.mongodb.com/python/2.9.1/api/pymongo/mongo_client.html#module-pymongo.mongo_client
|
||||
# default is never timeout while the connection is open,
|
||||
#this means it needs to explicitly close raising pymongo.errors.NetworkTimeout
|
||||
'socketTimeoutMS': 6000,
|
||||
'connectTimeoutMS': 2000, # default is 20000, I believe raises pymongo.errors.ConnectionFailure
|
||||
# Not setting waitQueueTimeoutMS and waitQueueMultiple since pymongo defaults to nobody being allowed to wait
|
||||
'auth_source': None,
|
||||
'read_preference': 'PRIMARY'
|
||||
# If 'asset_collection' defined, it'll be used
|
||||
# as the collection name for asset metadata.
|
||||
# Otherwise, a default collection name will be used.
|
||||
}
|
||||
|
||||
CONTENTSTORE = {
|
||||
'ENGINE': 'xmodule.contentstore.mongo.MongoContentStore',
|
||||
# connection strings are duplicated temporarily for
|
||||
# backward compatibility
|
||||
'OPTIONS': {
|
||||
'db': 'edxapp',
|
||||
'host': 'localhost',
|
||||
'password': 'password',
|
||||
'port': 27017,
|
||||
'user': 'edxapp',
|
||||
'ssl': False,
|
||||
'auth_source': None
|
||||
},
|
||||
'ADDITIONAL_OPTIONS': {},
|
||||
'DOC_STORE_CONFIG': DOC_STORE_CONFIG
|
||||
}
|
||||
CONTENTSTORE['DOC_STORE_CONFIG']['read_preference'] = 'PRIMARY'
|
||||
|
||||
MODULESTORE_BRANCH = 'draft-preferred'
|
||||
|
||||
MODULESTORE = {
|
||||
'default': {
|
||||
'ENGINE': 'xmodule.modulestore.mixed.MixedModuleStore',
|
||||
'OPTIONS': {
|
||||
'mappings': {},
|
||||
'stores': [
|
||||
{
|
||||
'NAME': 'split',
|
||||
'ENGINE': 'xmodule.modulestore.split_mongo.split_draft.DraftVersioningModuleStore',
|
||||
'DOC_STORE_CONFIG': DOC_STORE_CONFIG,
|
||||
'OPTIONS': {
|
||||
'default_class': 'xmodule.hidden_block.HiddenBlock',
|
||||
'fs_root': DATA_DIR,
|
||||
'render_template': 'common.djangoapps.edxmako.shortcuts.render_to_string',
|
||||
}
|
||||
},
|
||||
{
|
||||
'NAME': 'draft',
|
||||
'ENGINE': 'xmodule.modulestore.mongo.DraftMongoModuleStore',
|
||||
'DOC_STORE_CONFIG': DOC_STORE_CONFIG,
|
||||
'OPTIONS': {
|
||||
'default_class': 'xmodule.hidden_block.HiddenBlock',
|
||||
'fs_root': DATA_DIR,
|
||||
'render_template': 'common.djangoapps.edxmako.shortcuts.render_to_string',
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Modulestore-level field override providers. These field override providers don't
|
||||
# require student context.
|
||||
MODULESTORE_FIELD_OVERRIDE_PROVIDERS = ()
|
||||
|
||||
DEFAULT_AUTO_FIELD = 'django.db.models.AutoField'
|
||||
DEFAULT_HASHING_ALGORITHM = 'sha256'
|
||||
|
||||
#################### Python sandbox ############################################
|
||||
|
||||
CODE_JAIL = {
|
||||
# from https://github.com/openedx/codejail/blob/master/codejail/django_integration.py#L24, '' should be same as None
|
||||
'python_bin': '/edx/app/edxapp/venvs/edxapp-sandbox/bin/python',
|
||||
# User to run as in the sandbox.
|
||||
'user': 'sandbox',
|
||||
|
||||
# Configurable limits.
|
||||
'limits': {
|
||||
# How many CPU seconds can jailed code use?
|
||||
'CPU': 1,
|
||||
# Limit the memory of the jailed process to something high but not
|
||||
# infinite (512MiB in bytes)
|
||||
'VMEM': 536870912,
|
||||
# Time in seconds that the jailed process has to run.
|
||||
'REALTIME': 3,
|
||||
'PROXY': 0,
|
||||
# Needs to be non-zero so that jailed code can use it as their temp directory.(1MiB in bytes)
|
||||
'FSIZE': 1048576,
|
||||
},
|
||||
|
||||
# Overrides to default configurable 'limits' (above).
|
||||
# Keys should be course run ids.
|
||||
# Values should be dictionaries that look like 'limits'.
|
||||
"limit_overrides": {},
|
||||
}
|
||||
# Needs to be non-zero so that jailed code can use it as their temp directory.(1MiB in bytes)
|
||||
CODE_JAIL['limits']['FSIZE'] = 1048576
|
||||
|
||||
############################ DJANGO_BUILTINS ################################
|
||||
|
||||
ROOT_URLCONF = 'cms.urls'
|
||||
|
||||
COURSE_IMPORT_EXPORT_BUCKET = ''
|
||||
COURSE_METADATA_EXPORT_BUCKET = ''
|
||||
|
||||
@@ -684,48 +497,19 @@ PRESS_EMAIL = 'press@example.com'
|
||||
STATIC_URL = '/static/studio/'
|
||||
STATIC_ROOT = os.environ.get('STATIC_ROOT_CMS', ENV_ROOT / 'staticfiles' / 'studio')
|
||||
|
||||
STATICFILES_DIRS = [
|
||||
COMMON_ROOT / "static",
|
||||
PROJECT_ROOT / "static",
|
||||
# Temporarily adding the following static path as we are migrating the built-in blocks' Sass to vanilla CSS.
|
||||
# Once all of the built-in blocks are extracted from edx-platform, we can remove this static path.
|
||||
# Relevant ticket: https://github.com/openedx/edx-platform/issues/35300
|
||||
XMODULE_ROOT / "static",
|
||||
]
|
||||
|
||||
# Storage
|
||||
COURSE_IMPORT_EXPORT_STORAGE = 'django.core.files.storage.FileSystemStorage'
|
||||
COURSE_METADATA_EXPORT_STORAGE = 'django.core.files.storage.FileSystemStorage'
|
||||
|
||||
STATICI18N_ROOT = PROJECT_ROOT / "static"
|
||||
|
||||
##### custom vendor plugin variables #####
|
||||
|
||||
############################### PIPELINE #######################################
|
||||
|
||||
PIPELINE = {
|
||||
'PIPELINE_ENABLED': True,
|
||||
# Don't use compression by default
|
||||
'CSS_COMPRESSOR': None,
|
||||
PIPELINE.update({
|
||||
'JS_COMPRESSOR': None,
|
||||
# Don't wrap JavaScript as there is code that depends upon updating the global namespace
|
||||
'DISABLE_WRAPPER': True,
|
||||
# Specify the UglifyJS binary to use
|
||||
'UGLIFYJS_BINARY': 'node_modules/.bin/uglifyjs',
|
||||
'COMPILERS': (),
|
||||
'YUI_BINARY': 'yui-compressor',
|
||||
}
|
||||
|
||||
STATICFILES_STORAGE_KWARGS = {}
|
||||
|
||||
# List of finder classes that know how to find static files in various locations.
|
||||
# Note: the pipeline finder is included to be able to discover optimized files
|
||||
STATICFILES_FINDERS = [
|
||||
'openedx.core.djangoapps.theming.finders.ThemeFilesFinder',
|
||||
'django.contrib.staticfiles.finders.FileSystemFinder',
|
||||
'django.contrib.staticfiles.finders.AppDirectoriesFinder',
|
||||
'openedx.core.lib.xblock_pipeline.finder.XBlockPipelineFinder',
|
||||
'pipeline.finders.PipelineFinder',
|
||||
]
|
||||
})
|
||||
|
||||
PIPELINE['STYLESHEETS'] = {
|
||||
'style-vendor': {
|
||||
@@ -825,78 +609,23 @@ PIPELINE['JAVASCRIPT'] = {
|
||||
},
|
||||
}
|
||||
|
||||
STATICFILES_IGNORE_PATTERNS = (
|
||||
"*.py",
|
||||
"*.pyc",
|
||||
|
||||
# It would be nice if we could do, for example, "**/*.scss",
|
||||
# but these strings get passed down to the `fnmatch` module,
|
||||
# which doesn't support that. :(
|
||||
# http://docs.python.org/2/library/fnmatch.html
|
||||
"sass/*.scss",
|
||||
"sass/*/*.scss",
|
||||
"sass/*/*/*.scss",
|
||||
"sass/*/*/*/*.scss",
|
||||
|
||||
# Ignore tests
|
||||
"spec",
|
||||
"spec_helpers",
|
||||
|
||||
# Symlinks used by js-test-tool
|
||||
"xmodule_js",
|
||||
"common_static",
|
||||
)
|
||||
STATICFILES_IGNORE_PATTERNS.append("common_static")
|
||||
|
||||
################################# DJANGO-REQUIRE ###############################
|
||||
|
||||
# The name of a build profile to use for your project, relative to REQUIRE_BASE_URL.
|
||||
# A sensible value would be 'app.build.js'. Leave blank to use the built-in default build profile.
|
||||
# Set to False to disable running the default profile (e.g. if only using it to build Standalone
|
||||
# Modules)
|
||||
REQUIRE_BUILD_PROFILE = "cms/js/build.js"
|
||||
|
||||
# The name of the require.js script used by your project, relative to REQUIRE_BASE_URL.
|
||||
REQUIRE_JS = "js/vendor/requiresjs/require.js"
|
||||
|
||||
########################## DJANGO WEBPACK LOADER ##############################
|
||||
|
||||
WEBPACK_LOADER = {
|
||||
'DEFAULT': {
|
||||
'BUNDLE_DIR_NAME': 'bundles/',
|
||||
'STATS_FILE': os.path.join(STATIC_ROOT, 'webpack-stats.json'),
|
||||
},
|
||||
'WORKERS': {
|
||||
'BUNDLE_DIR_NAME': 'bundles/',
|
||||
'STATS_FILE': os.path.join(STATIC_ROOT, 'webpack-worker-stats.json')
|
||||
}
|
||||
}
|
||||
|
||||
############################ SERVICE_VARIANT ##################################
|
||||
|
||||
# SERVICE_VARIANT specifies name of the variant used, which decides what JSON
|
||||
# configuration files are read during startup.
|
||||
SERVICE_VARIANT = os.environ.get('SERVICE_VARIANT', 'cms')
|
||||
|
||||
# CONFIG_PREFIX specifies the prefix of the JSON configuration files,
|
||||
# based on the service variant. If no variant is use, don't use a
|
||||
# prefix.
|
||||
CONFIG_PREFIX = SERVICE_VARIANT + "." if SERVICE_VARIANT else ""
|
||||
|
||||
SERVICE_VARIANT = 'cms'
|
||||
|
||||
################################# CELERY ######################################
|
||||
|
||||
# Name the exchange and queues for each variant
|
||||
|
||||
QUEUE_VARIANT = CONFIG_PREFIX.lower()
|
||||
|
||||
CELERY_DEFAULT_EXCHANGE = f'edx.{QUEUE_VARIANT}core'
|
||||
|
||||
HIGH_PRIORITY_QUEUE = f'edx.{QUEUE_VARIANT}core.high'
|
||||
DEFAULT_PRIORITY_QUEUE = f'edx.{QUEUE_VARIANT}core.default'
|
||||
LOW_PRIORITY_QUEUE = f'edx.{QUEUE_VARIANT}core.low'
|
||||
|
||||
CELERY_DEFAULT_QUEUE = DEFAULT_PRIORITY_QUEUE
|
||||
CELERY_DEFAULT_ROUTING_KEY = DEFAULT_PRIORITY_QUEUE
|
||||
# Name the exchange and queues w.r.t the SERVICE_VARIANT
|
||||
HIGH_PRIORITY_QUEUE = f'edx.{SERVICE_VARIANT}.core.high'
|
||||
DEFAULT_PRIORITY_QUEUE = f'edx.{SERVICE_VARIANT}.core.default'
|
||||
LOW_PRIORITY_QUEUE = f'edx.{SERVICE_VARIANT}.core.low'
|
||||
|
||||
CELERY_QUEUES = {
|
||||
HIGH_PRIORITY_QUEUE: {},
|
||||
@@ -904,17 +633,11 @@ CELERY_QUEUES = {
|
||||
LOW_PRIORITY_QUEUE: {},
|
||||
}
|
||||
|
||||
# Queues configuration
|
||||
|
||||
CLEAR_REQUEST_CACHE_ON_TASK_COMPLETION = True
|
||||
|
||||
BROKER_USE_SSL = Derived(lambda settings: settings.CELERY_BROKER_USE_SSL)
|
||||
|
||||
CELERY_ALWAYS_EAGER = False
|
||||
|
||||
############################## HEARTBEAT ######################################
|
||||
|
||||
HEARTBEAT_CELERY_ROUTING_KEY = HIGH_PRIORITY_QUEUE
|
||||
BROKER_USE_SSL = Derived(lambda settings: settings.CELERY_BROKER_USE_SSL)
|
||||
|
||||
############################## Video ##########################################
|
||||
|
||||
@@ -923,12 +646,7 @@ EXTENDED_VIDEO_TRANSCRIPT_LANGUAGES = []
|
||||
|
||||
############################# SETTINGS FOR VIDEO UPLOAD PIPELINE #############################
|
||||
|
||||
VIDEO_UPLOAD_PIPELINE = {
|
||||
'VEM_S3_BUCKET': '',
|
||||
'BUCKET': '',
|
||||
'ROOT_PATH': '',
|
||||
'CONCURRENT_UPLOAD_LIMIT': 4,
|
||||
}
|
||||
VIDEO_UPLOAD_PIPELINE['CONCURRENT_UPLOAD_LIMIT'] = 4
|
||||
|
||||
############################ APPS #####################################
|
||||
|
||||
@@ -1193,131 +911,14 @@ INSTALLED_APPS = [
|
||||
"openedx_learning.apps.authoring.sections",
|
||||
]
|
||||
|
||||
|
||||
################# EDX MARKETING SITE ##################################
|
||||
|
||||
MKTG_URL_LINK_MAP = {}
|
||||
|
||||
ID_VERIFICATION_SUPPORT_LINK = ''
|
||||
PASSWORD_RESET_SUPPORT_LINK = ''
|
||||
ACTIVATION_EMAIL_SUPPORT_LINK = ''
|
||||
LOGIN_ISSUE_SUPPORT_LINK = ''
|
||||
|
||||
############################## EVENT TRACKING #################################
|
||||
|
||||
TRACK_MAX_EVENT = 50000
|
||||
|
||||
TRACKING_BACKENDS = {
|
||||
'logger': {
|
||||
'ENGINE': 'common.djangoapps.track.backends.logger.LoggerBackend',
|
||||
'OPTIONS': {
|
||||
'name': 'tracking'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# We're already logging events, and we don't want to capture user
|
||||
# names/passwords. Heartbeat events are likely not interesting.
|
||||
TRACKING_IGNORE_URL_PATTERNS = [r'^/event', r'^/login', r'^/heartbeat']
|
||||
|
||||
EVENT_TRACKING_ENABLED = True
|
||||
EVENT_TRACKING_BACKENDS = {
|
||||
'tracking_logs': {
|
||||
'ENGINE': 'eventtracking.backends.routing.RoutingBackend',
|
||||
'OPTIONS': {
|
||||
'backends': {
|
||||
'logger': {
|
||||
'ENGINE': 'eventtracking.backends.logger.LoggerBackend',
|
||||
'OPTIONS': {
|
||||
'name': 'tracking',
|
||||
'max_event_size': TRACK_MAX_EVENT,
|
||||
}
|
||||
}
|
||||
},
|
||||
'processors': [
|
||||
{'ENGINE': 'common.djangoapps.track.shim.LegacyFieldMappingProcessor'},
|
||||
{'ENGINE': 'common.djangoapps.track.shim.PrefixedEventProcessor'}
|
||||
]
|
||||
}
|
||||
},
|
||||
'segmentio': {
|
||||
'ENGINE': 'eventtracking.backends.routing.RoutingBackend',
|
||||
'OPTIONS': {
|
||||
'backends': {
|
||||
'segment': {'ENGINE': 'eventtracking.backends.segment.SegmentBackend'}
|
||||
},
|
||||
'processors': [
|
||||
{
|
||||
'ENGINE': 'eventtracking.processors.whitelist.NameWhitelistProcessor',
|
||||
'OPTIONS': {
|
||||
'whitelist': []
|
||||
}
|
||||
},
|
||||
{
|
||||
'ENGINE': 'common.djangoapps.track.shim.GoogleAnalyticsProcessor'
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
EVENT_TRACKING_PROCESSORS = []
|
||||
|
||||
EVENT_TRACKING_SEGMENTIO_EMIT_WHITELIST = []
|
||||
### Apps only installed in some instances
|
||||
add_optional_apps(OPTIONAL_APPS, INSTALLED_APPS)
|
||||
|
||||
##### ACCOUNT LOCKOUT DEFAULT PARAMETERS #####
|
||||
MAX_FAILED_LOGIN_ATTEMPTS_ALLOWED = 6
|
||||
MAX_FAILED_LOGIN_ATTEMPTS_LOCKOUT_PERIOD_SECS = 30 * 60
|
||||
|
||||
|
||||
### Apps only installed in some instances
|
||||
# The order of INSTALLED_APPS matters, so this tuple is the app name and the item in INSTALLED_APPS
|
||||
# that this app should be inserted *before*. A None here means it should be appended to the list.
|
||||
OPTIONAL_APPS = (
|
||||
('problem_builder', 'openedx.core.djangoapps.content.course_overviews.apps.CourseOverviewsConfig'),
|
||||
('edx_sga', None),
|
||||
|
||||
# edx-ora2
|
||||
('submissions', 'openedx.core.djangoapps.content.course_overviews.apps.CourseOverviewsConfig'),
|
||||
('openassessment', 'openedx.core.djangoapps.content.course_overviews.apps.CourseOverviewsConfig'),
|
||||
('openassessment.assessment', 'openedx.core.djangoapps.content.course_overviews.apps.CourseOverviewsConfig'),
|
||||
('openassessment.fileupload', 'openedx.core.djangoapps.content.course_overviews.apps.CourseOverviewsConfig'),
|
||||
('openassessment.staffgrader', 'openedx.core.djangoapps.content.course_overviews.apps.CourseOverviewsConfig'),
|
||||
('openassessment.workflow', 'openedx.core.djangoapps.content.course_overviews.apps.CourseOverviewsConfig'),
|
||||
('openassessment.xblock', 'openedx.core.djangoapps.content.course_overviews.apps.CourseOverviewsConfig'),
|
||||
|
||||
# edxval
|
||||
('edxval', 'openedx.core.djangoapps.content.course_overviews.apps.CourseOverviewsConfig'),
|
||||
|
||||
# Enterprise App (http://github.com/openedx/edx-enterprise)
|
||||
('enterprise', None),
|
||||
('consent', None),
|
||||
('integrated_channels.integrated_channel', None),
|
||||
('integrated_channels.degreed', None),
|
||||
('integrated_channels.degreed2', None),
|
||||
('integrated_channels.sap_success_factors', None),
|
||||
('integrated_channels.xapi', None),
|
||||
('integrated_channels.cornerstone', None),
|
||||
('integrated_channels.blackboard', None),
|
||||
('integrated_channels.canvas', None),
|
||||
('integrated_channels.moodle', None),
|
||||
)
|
||||
|
||||
|
||||
for app_name, insert_before in OPTIONAL_APPS:
|
||||
# First attempt to only find the module rather than actually importing it,
|
||||
# to avoid circular references - only try to import if it can't be found
|
||||
# by find_spec, which doesn't work with import hooks
|
||||
if importlib.util.find_spec(app_name) is None:
|
||||
try:
|
||||
__import__(app_name)
|
||||
except ImportError:
|
||||
continue
|
||||
|
||||
try:
|
||||
INSTALLED_APPS.insert(INSTALLED_APPS.index(insert_before), app_name)
|
||||
except (IndexError, ValueError):
|
||||
INSTALLED_APPS.append(app_name)
|
||||
|
||||
### Size of chunks into which asset uploads will be divided
|
||||
UPLOAD_CHUNK_SIZE_IN_MB = 10
|
||||
|
||||
@@ -1413,27 +1014,11 @@ ELASTIC_FIELD_MAPPINGS = {
|
||||
XBLOCK_FS_STORAGE_BUCKET = None
|
||||
XBLOCK_FS_STORAGE_PREFIX = None
|
||||
|
||||
############################ Global Database Configuration #####################
|
||||
|
||||
DATABASE_ROUTERS = [
|
||||
'openedx.core.lib.django_courseware_routers.StudentModuleHistoryExtendedRouter',
|
||||
]
|
||||
|
||||
############################ OAUTH2 Provider ###################################
|
||||
|
||||
# 5 minute expiration time for JWT id tokens issued for external API requests.
|
||||
OAUTH_ID_TOKEN_EXPIRATION = 5 * 60
|
||||
|
||||
EDX_DRF_EXTENSIONS = {
|
||||
# Set this value to an empty dict in order to prevent automatically updating
|
||||
# user data from values in (possibly stale) JWTs.
|
||||
'JWT_PAYLOAD_USER_ATTRIBUTE_MAPPING': {},
|
||||
}
|
||||
|
||||
############## Settings for Studio Context Sensitive Help ##############
|
||||
|
||||
HELP_TOKENS_INI_FILE = REPO_ROOT / "cms" / "envs" / "help_tokens.ini"
|
||||
|
||||
############## DJANGO-USER-TASKS ##############
|
||||
|
||||
# How long until database records about the outcome of a task and its artifacts get deleted?
|
||||
@@ -1441,9 +1026,6 @@ USER_TASKS_MAX_AGE = timedelta(days=7)
|
||||
|
||||
############################# Persistent Grades ####################################
|
||||
|
||||
# Queue to use for updating persistent grades
|
||||
RECALCULATE_GRADES_ROUTING_KEY = DEFAULT_PRIORITY_QUEUE
|
||||
|
||||
# .. setting_name: DEFAULT_GRADE_DESIGNATIONS
|
||||
# .. setting_default: ['A', 'B', 'C', 'D']
|
||||
# .. setting_description: The default 'pass' grade cutoff designations to be used. The failure grade
|
||||
@@ -1534,10 +1116,6 @@ VIDEO_IMAGE_SETTINGS = dict(
|
||||
|
||||
VIDEO_IMAGE_MAX_AGE = 31536000
|
||||
|
||||
########################## VIDEO TRANSCRIPTS STORAGE ############################
|
||||
TRANSCRIPT_LANG_CACHE_TIMEOUT = 60 * 60 * 24
|
||||
|
||||
|
||||
##### shoppingcart Payment #####
|
||||
PAYMENT_SUPPORT_EMAIL = 'billing@example.com'
|
||||
|
||||
@@ -1582,19 +1160,7 @@ LEARNER_PORTAL_URL_ROOT = 'https://learner-portal-localhost:18000'
|
||||
|
||||
############################ JWT #################################
|
||||
|
||||
REGISTRATION_EXTRA_FIELDS = {
|
||||
'confirm_email': 'hidden',
|
||||
'level_of_education': 'optional',
|
||||
'gender': 'optional',
|
||||
'year_of_birth': 'optional',
|
||||
'mailing_address': 'optional',
|
||||
'goals': 'optional',
|
||||
'honor_code': 'required',
|
||||
'terms_of_service': 'hidden',
|
||||
'city': 'hidden',
|
||||
'country': 'hidden',
|
||||
'marketing_emails_opt_in': 'hidden',
|
||||
}
|
||||
REGISTRATION_EXTRA_FIELDS['marketing_emails_opt_in'] = 'hidden'
|
||||
EDXAPP_PARSE_KEYS = {}
|
||||
PARSE_KEYS = {}
|
||||
|
||||
@@ -1675,18 +1241,7 @@ DISCUSSIONS_INCONTEXT_LEARNMORE_URL = "https://docs.openedx.org/en/latest/educat
|
||||
def _should_send_xblock_events(settings):
|
||||
return settings.ENABLE_SEND_XBLOCK_LIFECYCLE_EVENTS_OVER_BUS
|
||||
|
||||
# .. setting_name: EVENT_BUS_PRODUCER_CONFIG
|
||||
# .. setting_default: all events disabled
|
||||
# .. setting_description: Dictionary of event_types mapped to dictionaries of topic to topic-related configuration.
|
||||
# Each topic configuration dictionary contains
|
||||
# * `enabled`: a toggle denoting whether the event will be published to the topic. These should be annotated
|
||||
# according to
|
||||
# https://docs.openedx.org/projects/edx-toggles/en/latest/how_to/documenting_new_feature_toggles.html
|
||||
# * `event_key_field` which is a period-delimited string path to event data field to use as event key.
|
||||
# Note: The topic names should not include environment prefix as it will be dynamically added based on
|
||||
# EVENT_BUS_TOPIC_PREFIX setting.
|
||||
|
||||
EVENT_BUS_PRODUCER_CONFIG = {
|
||||
EVENT_BUS_PRODUCER_CONFIG.update({
|
||||
'org.openedx.content_authoring.course.catalog_info.changed.v1': {
|
||||
'course-catalog-info-changed':
|
||||
{'event_key_field': 'catalog_info.course_key',
|
||||
@@ -1714,29 +1269,7 @@ EVENT_BUS_PRODUCER_CONFIG = {
|
||||
'course-authoring-xblock-lifecycle':
|
||||
{'event_key_field': 'xblock_info.usage_key', 'enabled': Derived(_should_send_xblock_events)},
|
||||
},
|
||||
# LMS events. These have to be copied over here because lms.common adds some derived entries as well,
|
||||
# and the derivation fails if the keys are missing. If we ever remove the import of lms.common, we can remove these.
|
||||
'org.openedx.learning.certificate.created.v1': {
|
||||
'learning-certificate-lifecycle':
|
||||
{'event_key_field': 'certificate.course.course_key', 'enabled': False},
|
||||
},
|
||||
'org.openedx.learning.certificate.revoked.v1': {
|
||||
'learning-certificate-lifecycle':
|
||||
{'event_key_field': 'certificate.course.course_key', 'enabled': False},
|
||||
},
|
||||
"org.openedx.learning.course.passing.status.updated.v1": {
|
||||
"learning-badges-lifecycle": {
|
||||
"event_key_field": "course_passing_status.course.course_key",
|
||||
"enabled": Derived(should_send_learning_badge_events),
|
||||
},
|
||||
},
|
||||
"org.openedx.learning.ccx.course.passing.status.updated.v1": {
|
||||
"learning-badges-lifecycle": {
|
||||
"event_key_field": "course_passing_status.course.ccx_course_key",
|
||||
"enabled": Derived(should_send_learning_badge_events),
|
||||
},
|
||||
},
|
||||
}
|
||||
})
|
||||
|
||||
################### Authoring API ######################
|
||||
|
||||
|
||||
@@ -134,8 +134,6 @@ if STATIC_URL_BASE:
|
||||
|
||||
if STATIC_ROOT_BASE:
|
||||
STATIC_ROOT = path(STATIC_ROOT_BASE) / 'studio'
|
||||
WEBPACK_LOADER['DEFAULT']['STATS_FILE'] = STATIC_ROOT / "webpack-stats.json"
|
||||
WEBPACK_LOADER['WORKERS']['STATS_FILE'] = STATIC_ROOT / "webpack-worker-stats.json"
|
||||
|
||||
DATA_DIR = path(DATA_DIR)
|
||||
|
||||
@@ -263,7 +261,7 @@ if _YAML_CELERY_QUEUES:
|
||||
# Then add alternate environment queues
|
||||
_YAML_ALTERNATE_WORKER_QUEUES = _YAML_TOKENS.get('ALTERNATE_WORKER_QUEUES', '').split()
|
||||
ALTERNATE_QUEUES = [
|
||||
DEFAULT_PRIORITY_QUEUE.replace(QUEUE_VARIANT, alternate + '.')
|
||||
DEFAULT_PRIORITY_QUEUE.replace(SERVICE_VARIANT, alternate)
|
||||
for alternate in _YAML_ALTERNATE_WORKER_QUEUES
|
||||
]
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@ sessions. Assumes structure:
|
||||
|
||||
|
||||
import os
|
||||
import tempfile
|
||||
|
||||
from django.utils.translation import gettext_lazy
|
||||
from edx_django_utils.plugins import add_plugins
|
||||
@@ -38,7 +39,8 @@ STUDIO_SHORT_NAME = gettext_lazy("𝓢𝓽𝓾𝓭𝓲𝓸")
|
||||
|
||||
COMMON_TEST_DATA_ROOT = COMMON_ROOT / "test" / "data"
|
||||
|
||||
WEBPACK_LOADER["DEFAULT"]["STATS_FILE"] = STATIC_ROOT / "webpack-stats.json"
|
||||
COMPREHENSIVE_THEME_DIRS = [REPO_ROOT / "themes", REPO_ROOT / "common/test"]
|
||||
|
||||
WEBPACK_LOADER['DEFAULT']['LOADER_CLASS'] = 'webpack_loader.loader.FakeWebpackLoader'
|
||||
|
||||
GITHUB_REPO_ROOT = TEST_ROOT / "data"
|
||||
|
||||
@@ -40,7 +40,6 @@ Conventions
|
||||
# and throws spurious errors. Therefore, we disable invalid-name checking.
|
||||
# pylint: disable=invalid-name
|
||||
|
||||
import importlib.util
|
||||
import os
|
||||
|
||||
from corsheaders.defaults import default_headers as corsheaders_default_headers
|
||||
@@ -65,7 +64,6 @@ from enterprise.constants import (
|
||||
from openedx.core.lib.derived import Derived
|
||||
from openedx.envs.common import * # pylint: disable=wildcard-import
|
||||
|
||||
from lms.djangoapps.lms_xblock.mixin import LmsBlockMixin
|
||||
from openedx.core.lib.features_setting_proxy import FeaturesProxy
|
||||
|
||||
# A proxy for feature flags stored in the settings namespace
|
||||
@@ -735,28 +733,16 @@ GRADEBOOK_FREEZE_DAYS = 30
|
||||
RETRY_CALENDAR_SYNC_EMAIL_MAX_ATTEMPTS = 5
|
||||
|
||||
############################# SET PATH INFORMATION #############################
|
||||
|
||||
PROJECT_ROOT = path(__file__).abspath().dirname().dirname() # /edx-platform/lms
|
||||
REPO_ROOT = PROJECT_ROOT.dirname()
|
||||
COMMON_ROOT = REPO_ROOT / "common"
|
||||
OPENEDX_ROOT = REPO_ROOT / "openedx"
|
||||
XMODULE_ROOT = REPO_ROOT / "xmodule"
|
||||
ENV_ROOT = REPO_ROOT.dirname() # virtualenv dir /edx-platform is in
|
||||
COURSES_ROOT = ENV_ROOT / "data"
|
||||
NODE_MODULES_ROOT = REPO_ROOT / "node_modules"
|
||||
|
||||
DATA_DIR = COURSES_ROOT
|
||||
|
||||
# For geolocation ip database
|
||||
GEOIP_PATH = REPO_ROOT / "common/static/data/geoip/GeoLite2-Country.mmdb"
|
||||
# Where to look for a status message
|
||||
STATUS_MESSAGE_PATH = ENV_ROOT / "status_message.json"
|
||||
|
||||
############################ Global Database Configuration #####################
|
||||
|
||||
DATABASE_ROUTERS = [
|
||||
'openedx.core.lib.django_courseware_routers.StudentModuleHistoryExtendedRouter',
|
||||
'edx_django_utils.db.read_replica.ReadReplicaRouter',
|
||||
]
|
||||
DATABASE_ROUTERS.append('edx_django_utils.db.read_replica.ReadReplicaRouter')
|
||||
|
||||
################################## DJANGO OAUTH TOOLKIT #######################################
|
||||
|
||||
@@ -812,27 +798,11 @@ TPA_PROVIDER_SUSTAINED_THROTTLE = '50/hr'
|
||||
TPA_AUTOMATIC_LOGOUT_ENABLED = False
|
||||
|
||||
################################## TEMPLATE CONFIGURATION #####################################
|
||||
# Mako templating
|
||||
import tempfile # pylint: disable=wrong-import-position,wrong-import-order
|
||||
MAKO_MODULE_DIR = os.path.join(tempfile.gettempdir(), 'mako_lms')
|
||||
MAKO_TEMPLATE_DIRS_BASE = [
|
||||
PROJECT_ROOT / 'templates',
|
||||
COMMON_ROOT / 'templates',
|
||||
XMODULE_ROOT / 'capa' / 'templates',
|
||||
COMMON_ROOT / 'djangoapps' / 'pipeline_mako' / 'templates',
|
||||
OPENEDX_ROOT / 'core' / 'djangoapps' / 'cors_csrf' / 'templates',
|
||||
OPENEDX_ROOT / 'core' / 'djangoapps' / 'dark_lang' / 'templates',
|
||||
OPENEDX_ROOT / 'core' / 'lib' / 'license' / 'templates',
|
||||
OPENEDX_ROOT / 'features' / 'course_experience' / 'templates',
|
||||
]
|
||||
|
||||
CONTEXT_PROCESSORS = [
|
||||
'django.template.context_processors.request',
|
||||
'django.template.context_processors.static',
|
||||
'django.template.context_processors.i18n',
|
||||
'django.contrib.auth.context_processors.auth', # this is required for admin
|
||||
'django.template.context_processors.csrf',
|
||||
MAKO_TEMPLATE_DIRS_BASE = lms_mako_template_dirs_base
|
||||
|
||||
CONTEXT_PROCESSORS.remove('django.contrib.messages.context_processors.messages')
|
||||
CONTEXT_PROCESSORS[5:5] = [
|
||||
# Added for django-wiki
|
||||
'django.template.context_processors.media',
|
||||
'django.template.context_processors.tz',
|
||||
@@ -844,11 +814,8 @@ CONTEXT_PROCESSORS = [
|
||||
|
||||
# Timezone processor (sends language and time_zone preference)
|
||||
'lms.djangoapps.courseware.context_processor.user_timezone_locale_prefs',
|
||||
|
||||
# Online contextual help
|
||||
'help_tokens.context_processor',
|
||||
'openedx.core.djangoapps.site_configuration.context_processors.configuration_context',
|
||||
|
||||
]
|
||||
CONTEXT_PROCESSORS += [
|
||||
# Mobile App processor (Detects if request is from the mobile app)
|
||||
'lms.djangoapps.mobile_api.context_processor.is_from_mobile_app',
|
||||
|
||||
@@ -856,61 +823,10 @@ CONTEXT_PROCESSORS = [
|
||||
'openedx.features.survey_report.context_processors.admin_extra_context',
|
||||
]
|
||||
|
||||
# Django templating
|
||||
TEMPLATES = [
|
||||
{
|
||||
'NAME': 'django',
|
||||
'BACKEND': 'django.template.backends.django.DjangoTemplates',
|
||||
# Don't look for template source files inside installed applications.
|
||||
'APP_DIRS': False,
|
||||
# Instead, look for template source files in these dirs.
|
||||
'DIRS': [
|
||||
PROJECT_ROOT / "templates",
|
||||
COMMON_ROOT / 'templates',
|
||||
XMODULE_ROOT / 'capa' / 'templates',
|
||||
COMMON_ROOT / 'djangoapps' / 'pipeline_mako' / 'templates',
|
||||
COMMON_ROOT / 'static', # required to statically include common Underscore templates
|
||||
],
|
||||
# Options specific to this backend.
|
||||
'OPTIONS': {
|
||||
'loaders': [
|
||||
# We have to use mako-aware template loaders to be able to include
|
||||
# mako templates inside django templates (such as main_django.html).
|
||||
'openedx.core.djangoapps.theming.template_loaders.ThemeTemplateLoader',
|
||||
'common.djangoapps.edxmako.makoloader.MakoFilesystemLoader',
|
||||
'common.djangoapps.edxmako.makoloader.MakoAppDirectoriesLoader',
|
||||
],
|
||||
'context_processors': CONTEXT_PROCESSORS,
|
||||
# Change 'debug' in your environment settings files - not here.
|
||||
'debug': False
|
||||
}
|
||||
},
|
||||
{
|
||||
'NAME': 'mako',
|
||||
'BACKEND': 'common.djangoapps.edxmako.backend.Mako',
|
||||
# Don't look for template source files inside installed applications.
|
||||
'APP_DIRS': False,
|
||||
# Instead, look for template source files in these dirs.
|
||||
'DIRS': Derived(make_mako_template_dirs),
|
||||
# Options specific to this backend.
|
||||
'OPTIONS': {
|
||||
'context_processors': CONTEXT_PROCESSORS,
|
||||
# Change 'debug' in your environment settings files - not here.
|
||||
'debug': False,
|
||||
}
|
||||
},
|
||||
]
|
||||
DEFAULT_TEMPLATE_ENGINE = TEMPLATES[0]
|
||||
DEFAULT_TEMPLATE_ENGINE_DIRS = DEFAULT_TEMPLATE_ENGINE['DIRS'][:]
|
||||
DEFAULT_TEMPLATE_ENGINE_DIRS = Derived(lambda settings: settings.TEMPLATES[0]['DIRS'][:])
|
||||
|
||||
###############################################################################################
|
||||
|
||||
AUTHENTICATION_BACKENDS = [
|
||||
'rules.permissions.ObjectPermissionBackend',
|
||||
'django.contrib.auth.backends.AllowAllUsersModelBackend',
|
||||
'bridgekeeper.backends.RulePermissionBackend',
|
||||
]
|
||||
|
||||
STUDENT_FILEUPLOAD_MAX_SIZE = 4 * 1000 * 1000 # 4 MB
|
||||
MAX_FILEUPLOADS_PER_INPUT = 20
|
||||
|
||||
@@ -951,15 +867,6 @@ CERTIFICATE_DATE_FORMAT = "%B %-d, %Y"
|
||||
|
||||
ENABLE_MULTICOURSE = False # set to False to disable multicourse display (see lib.util.views.edXhome)
|
||||
|
||||
# .. toggle_name: WIKI_ENABLED
|
||||
# .. toggle_implementation: DjangoSetting
|
||||
# .. toggle_default: True
|
||||
# .. toggle_description: This setting allows us to have a collaborative tool to contribute or
|
||||
# modify content of course related materials.
|
||||
# .. toggle_use_cases: open_edx
|
||||
# .. toggle_creation_date: 2012-07-13
|
||||
WIKI_ENABLED = True
|
||||
|
||||
###
|
||||
|
||||
# IP addresses that are allowed to reload the course, etc.
|
||||
@@ -969,66 +876,9 @@ LMS_MIGRATION_ALLOWED_IPS = []
|
||||
############################## EVENT TRACKING #################################
|
||||
LMS_SEGMENT_KEY = None
|
||||
|
||||
# FIXME: Should we be doing this truncation?
|
||||
TRACK_MAX_EVENT = 50000
|
||||
|
||||
DEBUG_TRACK_LOG = False
|
||||
|
||||
TRACKING_BACKENDS = {
|
||||
'logger': {
|
||||
'ENGINE': 'common.djangoapps.track.backends.logger.LoggerBackend',
|
||||
'OPTIONS': {
|
||||
'name': 'tracking'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# We're already logging events, and we don't want to capture user
|
||||
# names/passwords. Heartbeat events are likely not interesting.
|
||||
TRACKING_IGNORE_URL_PATTERNS = [r'^/event', r'^/login', r'^/heartbeat', r'^/segmentio/event', r'^/performance']
|
||||
|
||||
EVENT_TRACKING_ENABLED = True
|
||||
EVENT_TRACKING_BACKENDS = {
|
||||
'tracking_logs': {
|
||||
'ENGINE': 'eventtracking.backends.routing.RoutingBackend',
|
||||
'OPTIONS': {
|
||||
'backends': {
|
||||
'logger': {
|
||||
'ENGINE': 'eventtracking.backends.logger.LoggerBackend',
|
||||
'OPTIONS': {
|
||||
'name': 'tracking',
|
||||
'max_event_size': TRACK_MAX_EVENT,
|
||||
}
|
||||
}
|
||||
},
|
||||
'processors': [
|
||||
{'ENGINE': 'common.djangoapps.track.shim.LegacyFieldMappingProcessor'},
|
||||
{'ENGINE': 'common.djangoapps.track.shim.PrefixedEventProcessor'}
|
||||
]
|
||||
}
|
||||
},
|
||||
'segmentio': {
|
||||
'ENGINE': 'eventtracking.backends.routing.RoutingBackend',
|
||||
'OPTIONS': {
|
||||
'backends': {
|
||||
'segment': {'ENGINE': 'eventtracking.backends.segment.SegmentBackend'}
|
||||
},
|
||||
'processors': [
|
||||
{
|
||||
'ENGINE': 'eventtracking.processors.whitelist.NameWhitelistProcessor',
|
||||
'OPTIONS': {
|
||||
'whitelist': []
|
||||
}
|
||||
},
|
||||
{
|
||||
'ENGINE': 'common.djangoapps.track.shim.GoogleAnalyticsProcessor'
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
EVENT_TRACKING_PROCESSORS = []
|
||||
EVENT_TRACKING_SEGMENTIO_EMIT_WHITELIST = []
|
||||
TRACKING_IGNORE_URL_PATTERNS += [r'^/segmentio/event', r'^/performance']
|
||||
|
||||
TRACKING_SEGMENTIO_WEBHOOK_SECRET = None
|
||||
TRACKING_SEGMENTIO_ALLOWED_TYPES = ['track']
|
||||
@@ -1039,7 +889,6 @@ TRACKING_SEGMENTIO_SOURCE_MAP = {
|
||||
}
|
||||
|
||||
######################## GOOGLE ANALYTICS ###########################
|
||||
GOOGLE_ANALYTICS_ACCOUNT = None
|
||||
GOOGLE_SITE_VERIFICATION_ID = None
|
||||
GOOGLE_ANALYTICS_LINKEDIN = None
|
||||
GOOGLE_ANALYTICS_TRACKING_ID = None
|
||||
@@ -1054,99 +903,13 @@ HOTJAR_SITE_ID = 00000
|
||||
######################## subdomain specific settings ###########################
|
||||
COURSE_LISTINGS = {}
|
||||
|
||||
############# XBlock Configuration ##########
|
||||
|
||||
# Import after sys.path fixup
|
||||
from xmodule.modulestore.edit_info import EditInfoMixin # lint-amnesty, pylint: disable=wrong-import-order, wrong-import-position
|
||||
from xmodule.modulestore.inheritance import InheritanceMixin # lint-amnesty, pylint: disable=wrong-import-order, wrong-import-position
|
||||
from xmodule.x_module import XModuleMixin # lint-amnesty, pylint: disable=wrong-import-order, wrong-import-position
|
||||
|
||||
# These are the Mixins that will be added to every Blocklike upon instantiation.
|
||||
# DO NOT EXPAND THIS LIST!! We want it eventually to be EMPTY. Why? Because dynamically adding functions/behaviors to
|
||||
# objects at runtime is confusing for both developers and static tooling (pylint/mypy). Instead...
|
||||
# - to add special Blocklike behaviors just for your site: override `XBLOCK_EXTRA_MIXINS` with your own XBlockMixins.
|
||||
# - to add new functionality to all Blocklikes: add it to the base Blocklike class in the core openedx/XBlock repo.
|
||||
XBLOCK_MIXINS = (
|
||||
# TODO: For each of these, either
|
||||
# (a) merge their functionality into the base Blocklike class, or
|
||||
# (b) refactor their functionality out of the Blocklike objects and into the edx-platform block runtimes.
|
||||
LmsBlockMixin,
|
||||
InheritanceMixin,
|
||||
XModuleMixin,
|
||||
EditInfoMixin,
|
||||
)
|
||||
|
||||
############# ModuleStore Configuration ##########
|
||||
|
||||
CONTENTSTORE['DOC_STORE_CONFIG']['password'] = 'password'
|
||||
CONTENTSTORE['DOC_STORE_CONFIG']['read_preference'] = 'SECONDARY_PREFERRED'
|
||||
|
||||
MODULESTORE_BRANCH = 'published-only'
|
||||
|
||||
DOC_STORE_CONFIG = {
|
||||
'db': 'edxapp',
|
||||
'host': 'localhost',
|
||||
'replicaSet': '',
|
||||
'password': 'password',
|
||||
'port': 27017,
|
||||
'user': 'edxapp',
|
||||
'collection': 'modulestore',
|
||||
'ssl': False,
|
||||
# https://api.mongodb.com/python/2.9.1/api/pymongo/mongo_client.html#module-pymongo.mongo_client
|
||||
# default is never timeout while the connection is open,
|
||||
#this means it needs to explicitly close raising pymongo.errors.NetworkTimeout
|
||||
'socketTimeoutMS': 6000,
|
||||
'connectTimeoutMS': 2000, # default is 20000, I believe raises pymongo.errors.ConnectionFailure
|
||||
# Not setting waitQueueTimeoutMS and waitQueueMultiple since pymongo defaults to nobody being allowed to wait
|
||||
'auth_source': None,
|
||||
'read_preference': 'SECONDARY_PREFERRED'
|
||||
}
|
||||
|
||||
CONTENTSTORE = {
|
||||
'ENGINE': 'xmodule.contentstore.mongo.MongoContentStore',
|
||||
# connection strings are duplicated temporarily for
|
||||
# backward compatibility
|
||||
'OPTIONS': {
|
||||
'db': 'edxapp',
|
||||
'host': 'localhost',
|
||||
'password': 'password',
|
||||
'port': 27017,
|
||||
'user': 'edxapp',
|
||||
'ssl': False,
|
||||
'auth_source': None
|
||||
},
|
||||
'ADDITIONAL_OPTIONS': {},
|
||||
'DOC_STORE_CONFIG': DOC_STORE_CONFIG
|
||||
}
|
||||
|
||||
MODULESTORE = {
|
||||
'default': {
|
||||
'ENGINE': 'xmodule.modulestore.mixed.MixedModuleStore',
|
||||
'OPTIONS': {
|
||||
'mappings': {},
|
||||
'stores': [
|
||||
{
|
||||
'NAME': 'split',
|
||||
'ENGINE': 'xmodule.modulestore.split_mongo.split_draft.DraftVersioningModuleStore',
|
||||
'DOC_STORE_CONFIG': DOC_STORE_CONFIG,
|
||||
'OPTIONS': {
|
||||
'default_class': 'xmodule.hidden_block.HiddenBlock',
|
||||
'fs_root': Derived(lambda settings: settings.DATA_DIR),
|
||||
'render_template': 'common.djangoapps.edxmako.shortcuts.render_to_string',
|
||||
}
|
||||
},
|
||||
{
|
||||
'NAME': 'draft',
|
||||
'ENGINE': 'xmodule.modulestore.mongo.DraftMongoModuleStore',
|
||||
'DOC_STORE_CONFIG': DOC_STORE_CONFIG,
|
||||
'OPTIONS': {
|
||||
'default_class': 'xmodule.hidden_block.HiddenBlock',
|
||||
'fs_root': Derived(lambda settings: settings.DATA_DIR),
|
||||
'render_template': 'common.djangoapps.edxmako.shortcuts.render_to_string',
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
HOSTNAME_MODULESTORE_DEFAULT_MAPPINGS = {}
|
||||
MONGODB_LOG = {}
|
||||
|
||||
@@ -1200,9 +963,6 @@ CMS_BASE = 'studio.edx.org'
|
||||
STUDIO_NAME = 'Studio'
|
||||
STUDIO_SHORT_NAME = 'Studio'
|
||||
|
||||
# Site info
|
||||
ROOT_URLCONF = 'lms.urls'
|
||||
# NOTE: Please set ALLOWED_HOSTS to some sane value, as we do not allow the default '*'
|
||||
# Platform Email
|
||||
EMAIL_FILE_PATH = Derived(lambda settings: path(settings.DATA_DIR) / "emails" / "lms")
|
||||
DEFAULT_FROM_EMAIL = 'registration@example.com'
|
||||
@@ -1225,17 +985,7 @@ ACTIVATION_EMAIL_FROM_ADDRESS = ''
|
||||
STATIC_URL = '/static/'
|
||||
STATIC_ROOT = os.environ.get('STATIC_ROOT_LMS', ENV_ROOT / "staticfiles")
|
||||
|
||||
STATICFILES_DIRS = [
|
||||
COMMON_ROOT / "static",
|
||||
PROJECT_ROOT / "static",
|
||||
NODE_MODULES_ROOT / "@edx",
|
||||
# Temporarily adding the following static path as we are migrating the built-in blocks' Sass to vanilla CSS.
|
||||
# Once all of the built-in blocks are extracted from edx-platform, we can remove this static path.
|
||||
# Relevant ticket: https://github.com/openedx/edx-platform/issues/35300
|
||||
XMODULE_ROOT / "static",
|
||||
]
|
||||
|
||||
STATICI18N_ROOT = PROJECT_ROOT / "static"
|
||||
STATICFILES_DIRS.insert(2, NODE_MODULES_ROOT / "@edx")
|
||||
|
||||
# Guidelines for translators
|
||||
TRANSLATORS_GUIDE = 'https://docs.openedx.org/en/latest/translators/index.html'
|
||||
@@ -1494,27 +1244,7 @@ MIDDLEWARE = [
|
||||
|
||||
############################### PIPELINE #######################################
|
||||
|
||||
PIPELINE = {
|
||||
'PIPELINE_ENABLED': True,
|
||||
'CSS_COMPRESSOR': None,
|
||||
'JS_COMPRESSOR': 'pipeline.compressors.uglifyjs.UglifyJSCompressor',
|
||||
# Don't wrap JavaScript as there is code that depends upon updating the global namespace
|
||||
'DISABLE_WRAPPER': True,
|
||||
# Specify the UglifyJS binary to use
|
||||
'UGLIFYJS_BINARY': 'node_modules/.bin/uglifyjs',
|
||||
}
|
||||
|
||||
STATICFILES_STORAGE_KWARGS = {}
|
||||
|
||||
# List of finder classes that know how to find static files in various locations.
|
||||
# Note: the pipeline finder is included to be able to discover optimized files
|
||||
STATICFILES_FINDERS = [
|
||||
'openedx.core.djangoapps.theming.finders.ThemeFilesFinder',
|
||||
'django.contrib.staticfiles.finders.FileSystemFinder',
|
||||
'django.contrib.staticfiles.finders.AppDirectoriesFinder',
|
||||
'openedx.core.lib.xblock_pipeline.finder.XBlockPipelineFinder',
|
||||
'pipeline.finders.PipelineFinder',
|
||||
]
|
||||
PIPELINE['JS_COMPRESSOR'] = 'pipeline.compressors.uglifyjs.UglifyJSCompressor'
|
||||
|
||||
from openedx.core.lib.rooted_paths import rooted_glob # pylint: disable=wrong-import-position
|
||||
|
||||
@@ -1871,37 +1601,8 @@ PIPELINE['JAVASCRIPT'] = {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
STATICFILES_IGNORE_PATTERNS = (
|
||||
"*.py",
|
||||
"*.pyc",
|
||||
|
||||
# It would be nice if we could do, for example, "**/*.scss",
|
||||
# but these strings get passed down to the `fnmatch` module,
|
||||
# which doesn't support that. :(
|
||||
# http://docs.python.org/2/library/fnmatch.html
|
||||
"sass/*.scss",
|
||||
"sass/*/*.scss",
|
||||
"sass/*/*/*.scss",
|
||||
"sass/*/*/*/*.scss",
|
||||
|
||||
# Ignore tests
|
||||
"spec",
|
||||
"spec_helpers",
|
||||
|
||||
# Symlinks used by js-test-tool
|
||||
"xmodule_js",
|
||||
)
|
||||
|
||||
|
||||
################################# DJANGO-REQUIRE ###############################
|
||||
|
||||
# The name of a build profile to use for your project, relative to REQUIRE_BASE_URL.
|
||||
# A sensible value would be 'app.build.js'. Leave blank to use the built-in default build profile.
|
||||
# Set to False to disable running the default profile (e.g. if only using it to build Standalone
|
||||
# Modules)
|
||||
REQUIRE_BUILD_PROFILE = "lms/js/build.js"
|
||||
|
||||
# The name of the require.js script used by your project, relative to REQUIRE_BASE_URL.
|
||||
REQUIRE_JS = "common/js/vendor/require.js"
|
||||
|
||||
@@ -1934,18 +1635,9 @@ REQUIRE_JS_PATH_OVERRIDES = {
|
||||
'hls': 'common/js/vendor/hls.js'
|
||||
}
|
||||
|
||||
########################## DJANGO WEBPACK LOADER ##############################
|
||||
############################ SERVICE_VARIANT ##################################
|
||||
|
||||
WEBPACK_LOADER = {
|
||||
'DEFAULT': {
|
||||
'BUNDLE_DIR_NAME': 'bundles/',
|
||||
'STATS_FILE': os.path.join(STATIC_ROOT, 'webpack-stats.json'),
|
||||
},
|
||||
'WORKERS': {
|
||||
'BUNDLE_DIR_NAME': 'bundles/',
|
||||
'STATS_FILE': os.path.join(STATIC_ROOT, 'webpack-worker-stats.json')
|
||||
}
|
||||
}
|
||||
SERVICE_VARIANT = 'lms'
|
||||
|
||||
################################# CELERY ######################################
|
||||
|
||||
@@ -1961,28 +1653,10 @@ CELERY_IMPORTS = [
|
||||
# These packages are added in addition to those added by CELERY_IMPORTS.
|
||||
CELERY_EXTRA_IMPORTS = []
|
||||
|
||||
# SERVICE_VARIANT specifies name of the variant used, which decides what JSON
|
||||
# configuration files are read during startup.
|
||||
SERVICE_VARIANT = os.environ.get('SERVICE_VARIANT', "lms")
|
||||
|
||||
# CONFIG_PREFIX specifies the prefix of the JSON configuration files,
|
||||
# based on the service variant. If no variant is use, don't use a
|
||||
# prefix.
|
||||
CONFIG_PREFIX = SERVICE_VARIANT + "." if SERVICE_VARIANT else ""
|
||||
|
||||
# Queues configuration
|
||||
|
||||
# Name the exchange and queues w.r.t the SERVICE_VARIANT
|
||||
QUEUE_VARIANT = CONFIG_PREFIX.lower()
|
||||
|
||||
CELERY_DEFAULT_EXCHANGE = f'edx.{QUEUE_VARIANT}core'
|
||||
|
||||
HIGH_PRIORITY_QUEUE = f'edx.{QUEUE_VARIANT}core.high'
|
||||
DEFAULT_PRIORITY_QUEUE = f'edx.{QUEUE_VARIANT}core.default'
|
||||
HIGH_MEM_QUEUE = f'edx.{QUEUE_VARIANT}core.high_mem'
|
||||
|
||||
CELERY_DEFAULT_QUEUE = DEFAULT_PRIORITY_QUEUE
|
||||
CELERY_DEFAULT_ROUTING_KEY = DEFAULT_PRIORITY_QUEUE
|
||||
HIGH_PRIORITY_QUEUE = f'edx.{SERVICE_VARIANT}.core.high'
|
||||
DEFAULT_PRIORITY_QUEUE = f'edx.{SERVICE_VARIANT}.core.default'
|
||||
HIGH_MEM_QUEUE = f'edx.{SERVICE_VARIANT}.core.high_mem'
|
||||
|
||||
CELERY_QUEUES = {
|
||||
HIGH_PRIORITY_QUEUE: {},
|
||||
@@ -1998,10 +1672,6 @@ CELERYD_HIJACK_ROOT_LOGGER = False
|
||||
|
||||
BROKER_USE_SSL = False
|
||||
|
||||
############################## HEARTBEAT ######################################
|
||||
|
||||
HEARTBEAT_CELERY_ROUTING_KEY = HIGH_PRIORITY_QUEUE
|
||||
|
||||
################################ Bulk Email ###################################
|
||||
|
||||
# Initial delay used for retrying tasks. Additional retries use
|
||||
@@ -2386,6 +2056,24 @@ INSTALLED_APPS = [
|
||||
"openedx_learning.apps.authoring.sections",
|
||||
]
|
||||
|
||||
# Add LMS specific optional apps
|
||||
OPTIONAL_APPS += [
|
||||
# Channel Integrations Apps
|
||||
('channel_integrations.integrated_channel', None),
|
||||
('channel_integrations.degreed2', None),
|
||||
('channel_integrations.sap_success_factors', None),
|
||||
('channel_integrations.cornerstone', None),
|
||||
('channel_integrations.xapi', None),
|
||||
('channel_integrations.blackboard', None),
|
||||
('channel_integrations.canvas', None),
|
||||
('channel_integrations.moodle', None),
|
||||
|
||||
# Required by the Enterprise App
|
||||
('django_object_actions', None), # https://github.com/crccheck/django-object-actions
|
||||
]
|
||||
|
||||
add_optional_apps(OPTIONAL_APPS, INSTALLED_APPS)
|
||||
|
||||
######################### Django Rest Framework ########################
|
||||
|
||||
SWAGGER_SETTINGS = {
|
||||
@@ -2395,7 +2083,7 @@ SWAGGER_SETTINGS = {
|
||||
|
||||
######################### MARKETING SITE ###############################
|
||||
|
||||
MKTG_URL_LINK_MAP = {
|
||||
MKTG_URL_LINK_MAP.update({
|
||||
'ABOUT': 'about',
|
||||
'CONTACT': 'contact',
|
||||
'FAQ': 'help',
|
||||
@@ -2412,15 +2100,11 @@ MKTG_URL_LINK_MAP = {
|
||||
|
||||
# Verified Certificates
|
||||
'WHAT_IS_VERIFIED_CERT': 'verified-certificate',
|
||||
}
|
||||
})
|
||||
|
||||
STATIC_TEMPLATE_VIEW_DEFAULT_FILE_EXTENSION = 'html'
|
||||
|
||||
SEND_ACTIVATION_EMAIL_URL = ''
|
||||
ACTIVATION_EMAIL_SUPPORT_LINK = Derived(lambda settings: settings.SUPPORT_SITE_LINK)
|
||||
ID_VERIFICATION_SUPPORT_LINK = Derived(lambda settings: settings.SUPPORT_SITE_LINK)
|
||||
LOGIN_ISSUE_SUPPORT_LINK = Derived(lambda settings: settings.SUPPORT_SITE_LINK)
|
||||
PASSWORD_RESET_SUPPORT_LINK = Derived(lambda settings: settings.SUPPORT_SITE_LINK)
|
||||
|
||||
# .. setting_name: SECURITY_PAGE_URL
|
||||
# .. setting_default: None
|
||||
@@ -2434,19 +2118,13 @@ ENTITLEMENT_EXPIRED_ALERT_PERIOD = 90
|
||||
|
||||
############################# SOCIAL MEDIA SHARING #############################
|
||||
# Social Media Sharing on Student Dashboard
|
||||
SOCIAL_SHARING_SETTINGS = {
|
||||
# Note: Ensure 'CUSTOM_COURSE_URLS' has a matching value in cms/envs/common.py
|
||||
'CUSTOM_COURSE_URLS': False,
|
||||
'DASHBOARD_FACEBOOK': False,
|
||||
SOCIAL_SHARING_SETTINGS.update({
|
||||
'FACEBOOK_BRAND': None,
|
||||
'CERTIFICATE_FACEBOOK': False,
|
||||
'CERTIFICATE_FACEBOOK_TEXT': None,
|
||||
'CERTIFICATE_TWITTER': False,
|
||||
'TWITTER_BRAND': None,
|
||||
'CERTIFICATE_TWITTER_TEXT': None,
|
||||
'DASHBOARD_TWITTER': False,
|
||||
'DASHBOARD_TWITTER_TEXT': None,
|
||||
'TWITTER_BRAND': None
|
||||
}
|
||||
})
|
||||
|
||||
################# Social Media Footer Links #######################
|
||||
# The names list controls the order of social media
|
||||
@@ -2575,30 +2253,6 @@ XDOMAIN_PROXY_CACHE_TIMEOUT = 60 * 15
|
||||
|
||||
###################### Registration ##################################
|
||||
|
||||
# .. setting_name: REGISTRATION_EXTRA_FIELDS
|
||||
# .. setting_default: {'confirm_email': 'hidden', 'level_of_education': 'optional', 'gender': 'optional',
|
||||
# 'year_of_birth': 'optional', 'mailing_address': 'optional', 'goals': 'optional', 'honor_code': 'required',
|
||||
# 'terms_of_service': 'hidden', 'city': 'hidden', 'country': 'hidden'}
|
||||
# .. setting_description: The signup form may contain extra fields that are presented to every user. For every field, we
|
||||
# can specifiy whether it should be "required": to display the field, and make it mandatory; "optional": to display
|
||||
# the optional field as part of a toggled input field list; "optional-exposed": to display the optional fields among
|
||||
# the required fields, and make it non-mandatory; "hidden": to not display the field.
|
||||
# When the terms of service are not visible and agreement to the honor code is required (the default), the signup page
|
||||
# includes a paragraph that links to the honor code page (defined my MKTG_URLS["HONOR"]). This page might not be
|
||||
# available for all Open edX platforms. In such cases, the "honor_code" registration field should be "hidden".
|
||||
REGISTRATION_EXTRA_FIELDS = {
|
||||
'confirm_email': 'hidden',
|
||||
'level_of_education': 'optional',
|
||||
'gender': 'optional',
|
||||
'year_of_birth': 'optional',
|
||||
'mailing_address': 'optional',
|
||||
'goals': 'optional',
|
||||
'honor_code': 'required',
|
||||
'terms_of_service': 'hidden',
|
||||
'city': 'hidden',
|
||||
'country': 'hidden',
|
||||
}
|
||||
|
||||
REGISTRATION_FIELD_ORDER = [
|
||||
"name",
|
||||
"first_name",
|
||||
@@ -2634,8 +2288,6 @@ CERT_NAME_LONG = "Certificate of Achievement"
|
||||
# the ones that contain information other than grades.
|
||||
GRADES_DOWNLOAD_ROUTING_KEY = Derived(lambda settings: settings.HIGH_MEM_QUEUE)
|
||||
|
||||
RECALCULATE_GRADES_ROUTING_KEY = 'edx.lms.core.default'
|
||||
|
||||
############################ ORA 2 ############################################
|
||||
ORA_WORKFLOW_UPDATE_ROUTING_KEY = "edx.lms.core.ora_workflow_update"
|
||||
|
||||
@@ -2655,69 +2307,6 @@ ORA_STAFF_LEASE_EXPIRATION_HOURS = 8
|
||||
##### LMS DEADLINE DISPLAY TIME_ZONE #######
|
||||
TIME_ZONE_DISPLAYED_FOR_DEADLINES = 'UTC'
|
||||
|
||||
########################## VIDEO TRANSCRIPTS STORAGE ############################
|
||||
|
||||
### Apps only installed in some instances
|
||||
# The order of INSTALLED_APPS matters, so this tuple is the app name and the item in INSTALLED_APPS
|
||||
# that this app should be inserted *before*. A None here means it should be appended to the list.
|
||||
OPTIONAL_APPS = [
|
||||
('problem_builder', 'openedx.core.djangoapps.content.course_overviews.apps.CourseOverviewsConfig'),
|
||||
('edx_sga', None),
|
||||
|
||||
# edx-ora2
|
||||
('submissions', 'openedx.core.djangoapps.content.course_overviews.apps.CourseOverviewsConfig'),
|
||||
('openassessment', 'openedx.core.djangoapps.content.course_overviews.apps.CourseOverviewsConfig'),
|
||||
('openassessment.assessment', 'openedx.core.djangoapps.content.course_overviews.apps.CourseOverviewsConfig'),
|
||||
('openassessment.fileupload', 'openedx.core.djangoapps.content.course_overviews.apps.CourseOverviewsConfig'),
|
||||
('openassessment.staffgrader', 'openedx.core.djangoapps.content.course_overviews.apps.CourseOverviewsConfig'),
|
||||
('openassessment.workflow', 'openedx.core.djangoapps.content.course_overviews.apps.CourseOverviewsConfig'),
|
||||
('openassessment.xblock', 'openedx.core.djangoapps.content.course_overviews.apps.CourseOverviewsConfig'),
|
||||
|
||||
# edxval
|
||||
('edxval', 'openedx.core.djangoapps.content.course_overviews.apps.CourseOverviewsConfig'),
|
||||
|
||||
# Enterprise Apps (http://github.com/openedx/edx-enterprise)
|
||||
('enterprise', None),
|
||||
('consent', None),
|
||||
('integrated_channels.integrated_channel', None),
|
||||
('integrated_channels.degreed', None),
|
||||
('integrated_channels.degreed2', None),
|
||||
('integrated_channels.sap_success_factors', None),
|
||||
('integrated_channels.cornerstone', None),
|
||||
('integrated_channels.xapi', None),
|
||||
('integrated_channels.blackboard', None),
|
||||
('integrated_channels.canvas', None),
|
||||
('integrated_channels.moodle', None),
|
||||
|
||||
# Channel Integrations Apps
|
||||
('channel_integrations.integrated_channel', None),
|
||||
('channel_integrations.degreed2', None),
|
||||
('channel_integrations.sap_success_factors', None),
|
||||
('channel_integrations.cornerstone', None),
|
||||
('channel_integrations.xapi', None),
|
||||
('channel_integrations.blackboard', None),
|
||||
('channel_integrations.canvas', None),
|
||||
('channel_integrations.moodle', None),
|
||||
|
||||
# Required by the Enterprise App
|
||||
('django_object_actions', None), # https://github.com/crccheck/django-object-actions
|
||||
]
|
||||
|
||||
for app_name, insert_before in OPTIONAL_APPS:
|
||||
# First attempt to only find the module rather than actually importing it,
|
||||
# to avoid circular references - only try to import if it can't be found
|
||||
# by find_spec, which doesn't work with import hooks
|
||||
if importlib.util.find_spec(app_name) is None:
|
||||
try:
|
||||
__import__(app_name)
|
||||
except ImportError:
|
||||
continue
|
||||
|
||||
try:
|
||||
INSTALLED_APPS.insert(INSTALLED_APPS.index(insert_before), app_name)
|
||||
except (IndexError, ValueError):
|
||||
INSTALLED_APPS.append(app_name)
|
||||
|
||||
### Analytics API
|
||||
ANALYTICS_API_KEY = ""
|
||||
ANALYTICS_API_URL = "http://localhost:18100"
|
||||
@@ -2966,13 +2555,8 @@ NOTIFICATION_EMAIL_EDX_LOGO = "templates/credit_notifications/edx-logo-header.pn
|
||||
|
||||
################################ Settings for JWTs ################################
|
||||
|
||||
EDX_DRF_EXTENSIONS = {
|
||||
# Set this value to an empty dict in order to prevent automatically updating
|
||||
# user data from values in (possibly stale) JWTs.
|
||||
'JWT_PAYLOAD_USER_ATTRIBUTE_MAPPING': {},
|
||||
# Allows JWT authentication to find the LMS user id for verification
|
||||
'VERIFY_LMS_USER_ID_PROPERTY_NAME': 'id',
|
||||
}
|
||||
# Allows JWT authentication to find the LMS user id for verification
|
||||
EDX_DRF_EXTENSIONS['VERIFY_LMS_USER_ID_PROPERTY_NAME'] = 'id'
|
||||
|
||||
################################ Settings for rss_proxy ################################
|
||||
|
||||
@@ -3030,10 +2614,6 @@ CREDENTIALS_COURSE_COMPLETION_STATE = 'awarded'
|
||||
# Queue to use for award program certificates
|
||||
PROGRAM_CERTIFICATES_ROUTING_KEY = Derived(lambda settings: settings.DEFAULT_PRIORITY_QUEUE)
|
||||
|
||||
############## Settings for LMS Context Sensitive Help ##############
|
||||
|
||||
HELP_TOKENS_INI_FILE = REPO_ROOT / "lms" / "envs" / "help_tokens.ini"
|
||||
|
||||
############## 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.
|
||||
@@ -3145,9 +2725,6 @@ SYSTEM_TO_FEATURE_ROLE_MAPPING = {
|
||||
|
||||
DATA_CONSENT_SHARE_CACHE_TIMEOUT = 8 * 60 * 60 # 8 hours
|
||||
|
||||
TRANSCRIPT_LANG_CACHE_TIMEOUT = 60 * 60 * 24 # 24 hours
|
||||
|
||||
|
||||
############## Settings for the Discovery App ######################
|
||||
|
||||
COURSES_API_CACHE_TIMEOUT = 3600 # Value is in seconds
|
||||
@@ -3317,9 +2894,6 @@ ENFORCE_SESSION_EMAIL_MATCH = False
|
||||
from openedx.core.djangoapps.ace_common.settings import common as ace_common_settings
|
||||
ACE_ROUTING_KEY = ace_common_settings.ACE_ROUTING_KEY
|
||||
|
||||
############### Settings swift #####################################
|
||||
SWIFT_USE_TEMP_URLS = None
|
||||
|
||||
############### Settings for facebook ##############################
|
||||
FACEBOOK_APP_ID = None
|
||||
FACEBOOK_APP_SECRET = None
|
||||
@@ -3336,13 +2910,6 @@ from openedx.core.djangoapps.plugins.constants import ProjectType, SettingsType
|
||||
INSTALLED_APPS.extend(get_plugin_apps(ProjectType.LMS))
|
||||
add_plugins(__name__, ProjectType.LMS, SettingsType.COMMON)
|
||||
|
||||
############### Settings for video pipeline ##################
|
||||
VIDEO_UPLOAD_PIPELINE = {
|
||||
'VEM_S3_BUCKET': '',
|
||||
'BUCKET': '',
|
||||
'ROOT_PATH': '',
|
||||
}
|
||||
|
||||
PROCTORED_EXAM_VIEWABLE_PAST_DUE = False
|
||||
|
||||
######################### rate limit for yt_video_metadata api ##############
|
||||
@@ -3499,23 +3066,12 @@ GOAL_REMINDER_PROFILE_URL = ""
|
||||
DISABLED_ORGS_FOR_PROGRAM_NUDGE = []
|
||||
|
||||
|
||||
#### Event bus producing ####
|
||||
|
||||
def _should_send_certificate_events(settings):
|
||||
return settings.SEND_LEARNING_CERTIFICATE_LIFECYCLE_EVENTS_TO_BUS
|
||||
|
||||
|
||||
#### Event bus producing ####
|
||||
|
||||
# .. setting_name: EVENT_BUS_PRODUCER_CONFIG
|
||||
# .. setting_default: all events disabled
|
||||
# .. setting_description: Dictionary of event_types mapped to dictionaries of topic to topic-related configuration.
|
||||
# Each topic configuration dictionary contains
|
||||
# * `enabled`: a toggle denoting whether the event will be published to the topic. These should be annotated
|
||||
# according to
|
||||
# https://docs.openedx.org/projects/edx-toggles/en/latest/how_to/documenting_new_feature_toggles.html
|
||||
# * `event_key_field` which is a period-delimited string path to event data field to use as event key.
|
||||
# Note: The topic names should not include environment prefix as it will be dynamically added based on
|
||||
# EVENT_BUS_TOPIC_PREFIX setting.
|
||||
EVENT_BUS_PRODUCER_CONFIG = {
|
||||
EVENT_BUS_PRODUCER_CONFIG.update({
|
||||
'org.openedx.learning.certificate.created.v1': {
|
||||
'learning-certificate-lifecycle':
|
||||
{'event_key_field': 'certificate.course.course_key', 'enabled': Derived(_should_send_certificate_events)},
|
||||
@@ -3566,40 +3122,13 @@ EVENT_BUS_PRODUCER_CONFIG = {
|
||||
'learner-credit-course-enrollment-lifecycle':
|
||||
{'event_key_field': 'learner_credit_course_enrollment.uuid', 'enabled': False},
|
||||
},
|
||||
# CMS events. These have to be copied over here because cms.common adds some derived entries as well,
|
||||
# and the derivation fails if the keys are missing. If we ever fully decouple the lms and cms settings,
|
||||
# we can remove these.
|
||||
'org.openedx.content_authoring.xblock.published.v1': {
|
||||
'course-authoring-xblock-lifecycle':
|
||||
{'event_key_field': 'xblock_info.usage_key', 'enabled': False},
|
||||
},
|
||||
'org.openedx.content_authoring.xblock.deleted.v1': {
|
||||
'course-authoring-xblock-lifecycle':
|
||||
{'event_key_field': 'xblock_info.usage_key', 'enabled': False},
|
||||
},
|
||||
'org.openedx.content_authoring.xblock.duplicated.v1': {
|
||||
'course-authoring-xblock-lifecycle':
|
||||
{'event_key_field': 'xblock_info.usage_key', 'enabled': False},
|
||||
},
|
||||
"org.openedx.learning.course.passing.status.updated.v1": {
|
||||
"learning-badges-lifecycle": {
|
||||
"event_key_field": "course_passing_status.course.course_key",
|
||||
"enabled": Derived(should_send_learning_badge_events),
|
||||
},
|
||||
},
|
||||
"org.openedx.learning.ccx.course.passing.status.updated.v1": {
|
||||
"learning-badges-lifecycle": {
|
||||
"event_key_field": "course_passing_status.course.ccx_course_key",
|
||||
"enabled": Derived(should_send_learning_badge_events),
|
||||
},
|
||||
},
|
||||
"org.openedx.learning.external_grader.score.submitted.v1": {
|
||||
"learning-external-grader-score-lifecycle": {
|
||||
"event_key_field": "score.submission_id",
|
||||
"enabled": False
|
||||
},
|
||||
},
|
||||
}
|
||||
})
|
||||
|
||||
#### Survey Report ####
|
||||
# .. toggle_name: SURVEY_REPORT_ENABLE
|
||||
|
||||
@@ -122,9 +122,6 @@ CELERYD_PREFETCH_MULTIPLIER = 1
|
||||
# collected
|
||||
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
|
||||
if STATIC_URL_BASE:
|
||||
@@ -165,7 +162,7 @@ if _YAML_CELERY_QUEUES:
|
||||
# Then add alternate environment queues
|
||||
_YAML_ALTERNATE_WORKER_QUEUES = _YAML_TOKENS.get('ALTERNATE_WORKER_QUEUES', '').split()
|
||||
ALTERNATE_QUEUES = [
|
||||
DEFAULT_PRIORITY_QUEUE.replace(QUEUE_VARIANT, alternate + '.')
|
||||
DEFAULT_PRIORITY_QUEUE.replace(SERVICE_VARIANT, alternate)
|
||||
for alternate in _YAML_ALTERNATE_WORKER_QUEUES
|
||||
]
|
||||
|
||||
|
||||
@@ -53,7 +53,8 @@ ENABLE_BULK_USER_RETIREMENT = True
|
||||
|
||||
COMMON_TEST_DATA_ROOT = COMMON_ROOT / "test" / "data"
|
||||
|
||||
WEBPACK_LOADER['DEFAULT']['STATS_FILE'] = STATIC_ROOT / "webpack-stats.json"
|
||||
COMPREHENSIVE_THEME_DIRS = [REPO_ROOT / "themes", REPO_ROOT / "common/test"]
|
||||
|
||||
WEBPACK_LOADER['DEFAULT']['LOADER_CLASS'] = 'webpack_loader.loader.FakeWebpackLoader'
|
||||
|
||||
STATUS_MESSAGE_PATH = TEST_ROOT / "status_message.json"
|
||||
|
||||
@@ -12,7 +12,6 @@ defuse_xml_libs()
|
||||
import os # lint-amnesty, pylint: disable=wrong-import-order, wrong-import-position
|
||||
|
||||
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "lms.envs.aws")
|
||||
os.environ.setdefault("SERVICE_VARIANT", "lms")
|
||||
|
||||
# This application object is used by the development server
|
||||
# as well as any WSGI server configured to use this file.
|
||||
|
||||
11
manage.py
11
manage.py
@@ -44,7 +44,6 @@ def parse_args():
|
||||
help_string=lms.format_help(),
|
||||
settings_base='lms/envs',
|
||||
default_settings='lms.envs.devstack',
|
||||
service_variant='lms',
|
||||
)
|
||||
|
||||
cms = subparsers.add_parser(
|
||||
@@ -62,16 +61,15 @@ def parse_args():
|
||||
help_string=cms.format_help(),
|
||||
settings_base='cms/envs',
|
||||
default_settings='cms.envs.devstack',
|
||||
service_variant='cms',
|
||||
)
|
||||
|
||||
edx_args, django_args = parser.parse_known_args()
|
||||
known_args, remaining_args = parser.parse_known_args()
|
||||
|
||||
if edx_args.help:
|
||||
if known_args.help:
|
||||
print("edX:")
|
||||
print(edx_args.help_string)
|
||||
print(known_args.help_string)
|
||||
|
||||
return edx_args, django_args
|
||||
return known_args, remaining_args
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
@@ -84,7 +82,6 @@ if __name__ == "__main__":
|
||||
os.environ["DJANGO_SETTINGS_MODULE"] = edx_args_base + os.environ["EDX_PLATFORM_SETTINGS"]
|
||||
|
||||
os.environ.setdefault("DJANGO_SETTINGS_MODULE", edx_args.default_settings)
|
||||
os.environ.setdefault("SERVICE_VARIANT", edx_args.service_variant)
|
||||
|
||||
if edx_args.help:
|
||||
print("Django:")
|
||||
|
||||
@@ -15,12 +15,12 @@ behavior to trigger the necessary data updates.
|
||||
|
||||
import copy
|
||||
import logging
|
||||
import os
|
||||
import sys
|
||||
import textwrap
|
||||
import time
|
||||
|
||||
from django.core.management.base import BaseCommand, CommandError
|
||||
from django.conf import settings
|
||||
from opaque_keys import InvalidKeyError
|
||||
from opaque_keys.edx.keys import CourseKey
|
||||
from openedx.core.djangoapps.content.course_overviews.models import SimulateCoursePublishConfig
|
||||
@@ -189,14 +189,14 @@ class Command(BaseCommand):
|
||||
options['delay']
|
||||
)
|
||||
|
||||
if os.environ.get('SERVICE_VARIANT', 'cms').startswith('lms'):
|
||||
if settings.SERVICE_VARIANT == 'lms':
|
||||
if options['force_lms']:
|
||||
log.info("Forcing simulate_publish to run in LMS process.")
|
||||
else:
|
||||
log.fatal( # lint-amnesty, pylint: disable=logging-not-lazy
|
||||
"simulate_publish should be run as a CMS (Studio) " +
|
||||
"command, not %s (override with --force-lms).",
|
||||
os.environ.get('SERVICE_VARIANT')
|
||||
settings.SERVICE_VARIANT
|
||||
)
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
@@ -95,7 +95,7 @@ class TestSimulatePublish(SharedModuleStoreTestCase):
|
||||
receivers=default_receivers,
|
||||
courses=None,
|
||||
delay=0,
|
||||
force_lms=False,
|
||||
force_lms=True,
|
||||
skip_ccx=False,
|
||||
args_from_database=False
|
||||
)
|
||||
@@ -155,12 +155,12 @@ class TestSimulatePublish(SharedModuleStoreTestCase):
|
||||
|
||||
# Add a config
|
||||
config = SimulateCoursePublishConfig.current()
|
||||
config.arguments = '--delay 20 --dry-run'
|
||||
config.arguments = '--delay 20 --dry-run --force-lms '
|
||||
config.enabled = True
|
||||
config.save()
|
||||
|
||||
with LogCapture(LOGGER_NAME) as log:
|
||||
call_command('simulate_publish')
|
||||
call_command('simulate_publish', '--force-lms')
|
||||
|
||||
log.check_present(
|
||||
(
|
||||
|
||||
@@ -26,6 +26,7 @@ def center_with_hashes(text: str, width: int = 76):
|
||||
```
|
||||
"""
|
||||
import os
|
||||
import importlib.util
|
||||
from path import Path as path
|
||||
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
@@ -48,6 +49,11 @@ from openedx.core.constants import ( # pylint: disable=unused-import
|
||||
USAGE_ID_PATTERN,
|
||||
)
|
||||
|
||||
from xmodule.modulestore.edit_info import EditInfoMixin
|
||||
from xmodule.modulestore.inheritance import InheritanceMixin
|
||||
from xmodule.x_module import XModuleMixin
|
||||
from lms.djangoapps.lms_xblock.mixin import LmsBlockMixin
|
||||
|
||||
################ Shared Functions for Derived Configuration ################
|
||||
|
||||
|
||||
@@ -91,11 +97,22 @@ def _make_locale_paths(settings):
|
||||
locale_paths += (path(locale_path), )
|
||||
return locale_paths
|
||||
|
||||
################################## Paths ###################################
|
||||
|
||||
REPO_ROOT = path(__file__).abspath().dirname().dirname().dirname()
|
||||
COMMON_ROOT = REPO_ROOT / "common"
|
||||
OPENEDX_ROOT = REPO_ROOT / "openedx"
|
||||
ENV_ROOT = REPO_ROOT.dirname() # virtualenv dir /edx-platform is in
|
||||
COURSES_ROOT = ENV_ROOT / "data"
|
||||
XMODULE_ROOT = REPO_ROOT / "xmodule"
|
||||
DATA_DIR = COURSES_ROOT
|
||||
|
||||
############################# Django Built-Ins #############################
|
||||
|
||||
DEBUG = False
|
||||
|
||||
USE_TZ = True
|
||||
TIME_ZONE = 'UTC'
|
||||
|
||||
# User-uploaded content
|
||||
MEDIA_ROOT = '/edx/var/edxapp/media/'
|
||||
@@ -117,18 +134,57 @@ SESSION_ENGINE = 'django.contrib.sessions.backends.cache'
|
||||
SESSION_SAVE_EVERY_REQUEST = False
|
||||
SESSION_SERIALIZER = 'openedx.core.lib.session_serializers.PickleSerializer'
|
||||
|
||||
CSRF_COOKIE_AGE = 60 * 60 * 24 * 7 * 52
|
||||
CSRF_TRUSTED_ORIGINS = []
|
||||
# It is highly recommended that you override this in any environment accessed by end users
|
||||
CSRF_COOKIE_SECURE = False
|
||||
|
||||
ALLOWED_HOSTS = ['*']
|
||||
|
||||
# Clickjacking protection can be disbaled by setting this to 'ALLOW'
|
||||
X_FRAME_OPTIONS = 'DENY'
|
||||
|
||||
ROOT_URLCONF = Derived(lambda settings: f'{settings.SERVICE_VARIANT}.urls')
|
||||
|
||||
ADMINS = []
|
||||
MANAGERS = ADMINS
|
||||
|
||||
DEFAULT_FROM_EMAIL = 'registration@example.com'
|
||||
SERVER_EMAIL = 'devops@example.com'
|
||||
|
||||
# Set request limits for maximum size of a request body and maximum number of GET/POST parameters. (>=Django 1.10)
|
||||
# Limits are currently disabled - but can be used for finer-grained denial-of-service protection.
|
||||
DATA_UPLOAD_MAX_MEMORY_SIZE = None
|
||||
DATA_UPLOAD_MAX_NUMBER_FIELDS = None
|
||||
|
||||
# See https://github.com/openedx/edx-django-sites-extensions for more info.
|
||||
# Default site to use if site matching request headers does not exist.
|
||||
SITE_ID = 1
|
||||
|
||||
# Clickjacking protection can be disbaled by setting this to 'ALLOW'
|
||||
X_FRAME_OPTIONS = 'DENY'
|
||||
STATICFILES_DIRS = [
|
||||
COMMON_ROOT / "static",
|
||||
Derived(lambda settings: settings.PROJECT_ROOT / "static"),
|
||||
# Temporarily adding the following static path as we are migrating the built-in blocks' Sass to vanilla CSS.
|
||||
# Once all of the built-in blocks are extracted from edx-platform, we can remove this static path.
|
||||
# Relevant ticket: https://github.com/openedx/edx-platform/issues/35300
|
||||
XMODULE_ROOT / "static",
|
||||
]
|
||||
|
||||
# List of finder classes that know how to find static files in various locations.
|
||||
# Note: the pipeline finder is included to be able to discover optimized files
|
||||
STATICFILES_FINDERS = [
|
||||
'openedx.core.djangoapps.theming.finders.ThemeFilesFinder',
|
||||
'django.contrib.staticfiles.finders.FileSystemFinder',
|
||||
'django.contrib.staticfiles.finders.AppDirectoriesFinder',
|
||||
'openedx.core.lib.xblock_pipeline.finder.XBlockPipelineFinder',
|
||||
'pipeline.finders.PipelineFinder',
|
||||
]
|
||||
|
||||
AUTHENTICATION_BACKENDS = [
|
||||
'rules.permissions.ObjectPermissionBackend',
|
||||
'django.contrib.auth.backends.AllowAllUsersModelBackend',
|
||||
'bridgekeeper.backends.RulePermissionBackend',
|
||||
]
|
||||
|
||||
AUTH_PASSWORD_VALIDATORS = [
|
||||
{
|
||||
@@ -160,6 +216,8 @@ STORAGES = {
|
||||
# Messages
|
||||
MESSAGE_STORAGE = 'django.contrib.messages.storage.session.SessionStorage'
|
||||
|
||||
USE_I18N = True
|
||||
|
||||
# these languages display right to left
|
||||
LANGUAGES_BIDI = ("he", "ar", "fa", "ur", "fa-ir", "rtl")
|
||||
|
||||
@@ -167,6 +225,8 @@ LANGUAGE_COOKIE_NAME = "openedx-language-preference"
|
||||
|
||||
LOCALE_PATHS = Derived(_make_locale_paths)
|
||||
|
||||
LANGUAGE_CODE = 'en' # http://www.i18nguy.com/unicode/language-identifiers.html
|
||||
|
||||
# Sourced from http://www.localeplanet.com/icu/ and wikipedia
|
||||
LANGUAGES = [
|
||||
('en', 'English'),
|
||||
@@ -251,6 +311,231 @@ LANGUAGES = [
|
||||
('zh-tw', '中文 (台灣)'), # Chinese (Taiwan)
|
||||
]
|
||||
|
||||
CACHES = {
|
||||
'course_structure_cache': {
|
||||
'KEY_PREFIX': 'course_structure',
|
||||
'KEY_FUNCTION': 'common.djangoapps.util.memcache.safe_key',
|
||||
'LOCATION': ['localhost:11211'],
|
||||
'TIMEOUT': '604800', # 1 week
|
||||
'BACKEND': 'django.core.cache.backends.memcached.PyMemcacheCache',
|
||||
'OPTIONS': {
|
||||
'no_delay': True,
|
||||
'ignore_exc': True,
|
||||
'use_pooling': True,
|
||||
'connect_timeout': 0.5
|
||||
}
|
||||
},
|
||||
'celery': {
|
||||
'KEY_PREFIX': 'celery',
|
||||
'KEY_FUNCTION': 'common.djangoapps.util.memcache.safe_key',
|
||||
'LOCATION': ['localhost:11211'],
|
||||
'TIMEOUT': '7200',
|
||||
'BACKEND': 'django.core.cache.backends.memcached.PyMemcacheCache',
|
||||
'OPTIONS': {
|
||||
'no_delay': True,
|
||||
'ignore_exc': True,
|
||||
'use_pooling': True,
|
||||
'connect_timeout': 0.5
|
||||
}
|
||||
},
|
||||
'mongo_metadata_inheritance': {
|
||||
'KEY_PREFIX': 'mongo_metadata_inheritance',
|
||||
'KEY_FUNCTION': 'common.djangoapps.util.memcache.safe_key',
|
||||
'LOCATION': ['localhost:11211'],
|
||||
'TIMEOUT': 300,
|
||||
'BACKEND': 'django.core.cache.backends.memcached.PyMemcacheCache',
|
||||
'OPTIONS': {
|
||||
'no_delay': True,
|
||||
'ignore_exc': True,
|
||||
'use_pooling': True,
|
||||
'connect_timeout': 0.5
|
||||
}
|
||||
},
|
||||
'staticfiles': {
|
||||
'KEY_FUNCTION': 'common.djangoapps.util.memcache.safe_key',
|
||||
'LOCATION': ['localhost:11211'],
|
||||
'KEY_PREFIX': 'staticfiles_general',
|
||||
'BACKEND': 'django.core.cache.backends.memcached.PyMemcacheCache',
|
||||
'OPTIONS': {
|
||||
'no_delay': True,
|
||||
'ignore_exc': True,
|
||||
'use_pooling': True,
|
||||
'connect_timeout': 0.5
|
||||
}
|
||||
},
|
||||
'default': {
|
||||
'VERSION': '1',
|
||||
'KEY_FUNCTION': 'common.djangoapps.util.memcache.safe_key',
|
||||
'LOCATION': ['localhost:11211'],
|
||||
'KEY_PREFIX': 'default',
|
||||
'BACKEND': 'django.core.cache.backends.memcached.PyMemcacheCache',
|
||||
'OPTIONS': {
|
||||
'no_delay': True,
|
||||
'ignore_exc': True,
|
||||
'use_pooling': True,
|
||||
'connect_timeout': 0.5
|
||||
}
|
||||
},
|
||||
'configuration': {
|
||||
'KEY_FUNCTION': 'common.djangoapps.util.memcache.safe_key',
|
||||
'LOCATION': ['localhost:11211'],
|
||||
'KEY_PREFIX': 'configuration',
|
||||
'BACKEND': 'django.core.cache.backends.memcached.PyMemcacheCache',
|
||||
'OPTIONS': {
|
||||
'no_delay': True,
|
||||
'ignore_exc': True,
|
||||
'use_pooling': True,
|
||||
'connect_timeout': 0.5
|
||||
}
|
||||
},
|
||||
'general': {
|
||||
'KEY_FUNCTION': 'common.djangoapps.util.memcache.safe_key',
|
||||
'LOCATION': ['localhost:11211'],
|
||||
'KEY_PREFIX': 'general',
|
||||
'BACKEND': 'django.core.cache.backends.memcached.PyMemcacheCache',
|
||||
'OPTIONS': {
|
||||
'no_delay': True,
|
||||
'ignore_exc': True,
|
||||
'use_pooling': True,
|
||||
'connect_timeout': 0.5
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
DATABASES = {
|
||||
# edxapp's edxapp-migrate scripts and the edxapp_migrate play
|
||||
# will ensure that any DB not named read_replica will be migrated
|
||||
# for both the lms and cms.
|
||||
'default': {
|
||||
'ATOMIC_REQUESTS': True,
|
||||
'CONN_MAX_AGE': 0,
|
||||
'ENGINE': 'django.db.backends.mysql',
|
||||
'HOST': '127.0.0.1',
|
||||
'NAME': 'edxapp',
|
||||
'OPTIONS': {},
|
||||
'PASSWORD': 'password',
|
||||
'PORT': '3306',
|
||||
'USER': 'edxapp001'
|
||||
},
|
||||
'read_replica': {
|
||||
'CONN_MAX_AGE': 0,
|
||||
'ENGINE': 'django.db.backends.mysql',
|
||||
'HOST': '127.0.0.1',
|
||||
'NAME': 'edxapp',
|
||||
'OPTIONS': {},
|
||||
'PASSWORD': 'password',
|
||||
'PORT': '3306',
|
||||
'USER': 'edxapp001'
|
||||
},
|
||||
'student_module_history': {
|
||||
'CONN_MAX_AGE': 0,
|
||||
'ENGINE': 'django.db.backends.mysql',
|
||||
'HOST': '127.0.0.1',
|
||||
'NAME': 'edxapp_csmh',
|
||||
'OPTIONS': {},
|
||||
'PASSWORD': 'password',
|
||||
'PORT': '3306',
|
||||
'USER': 'edxapp001'
|
||||
}
|
||||
}
|
||||
|
||||
DEFAULT_AUTO_FIELD = 'django.db.models.AutoField'
|
||||
|
||||
DATABASE_ROUTERS = [
|
||||
'openedx.core.lib.django_courseware_routers.StudentModuleHistoryExtendedRouter',
|
||||
]
|
||||
|
||||
TEMPLATES = [
|
||||
{
|
||||
'NAME': 'django',
|
||||
'BACKEND': 'django.template.backends.django.DjangoTemplates',
|
||||
# Don't look for template source files inside installed applications.
|
||||
'APP_DIRS': False,
|
||||
# Instead, look for template source files in these dirs.
|
||||
'DIRS': [
|
||||
Derived(lambda settings: settings.PROJECT_ROOT / "templates"),
|
||||
COMMON_ROOT / 'templates',
|
||||
XMODULE_ROOT / 'capa' / 'templates',
|
||||
COMMON_ROOT / 'djangoapps' / 'pipeline_mako' / 'templates',
|
||||
COMMON_ROOT / 'static', # required to statically include common Underscore templates
|
||||
],
|
||||
# Options specific to this backend.
|
||||
'OPTIONS': {
|
||||
'loaders': [
|
||||
# We have to use mako-aware template loaders to be able to include
|
||||
# mako templates inside django templates (such as main_django.html).
|
||||
'openedx.core.djangoapps.theming.template_loaders.ThemeTemplateLoader',
|
||||
'common.djangoapps.edxmako.makoloader.MakoFilesystemLoader',
|
||||
'common.djangoapps.edxmako.makoloader.MakoAppDirectoriesLoader',
|
||||
],
|
||||
'context_processors': Derived(lambda settings: settings.CONTEXT_PROCESSORS),
|
||||
# Change 'debug' in your environment settings files - not here.
|
||||
'debug': False
|
||||
}
|
||||
},
|
||||
{
|
||||
'NAME': 'mako',
|
||||
'BACKEND': 'common.djangoapps.edxmako.backend.Mako',
|
||||
# Don't look for template source files inside installed applications.
|
||||
'APP_DIRS': False,
|
||||
# Instead, look for template source files in these dirs.
|
||||
'DIRS': Derived(make_mako_template_dirs),
|
||||
# Options specific to this backend.
|
||||
'OPTIONS': {
|
||||
'context_processors': Derived(lambda settings: settings.CONTEXT_PROCESSORS),
|
||||
# Change 'debug' in your environment settings files - not here.
|
||||
'debug': False,
|
||||
}
|
||||
},
|
||||
]
|
||||
|
||||
################################ Templates #################################
|
||||
|
||||
|
||||
def make_mako_module_dir(settings):
|
||||
"""
|
||||
Returns the directory where Mako templates are stored.
|
||||
|
||||
Args:
|
||||
settings: A Django settings module object.
|
||||
|
||||
Returns:
|
||||
list: A list of Mako template directories, potentially updated with additional
|
||||
theme directories.
|
||||
"""
|
||||
import tempfile
|
||||
return os.path.join(tempfile.gettempdir(), f'mako_{settings.SERVICE_VARIANT}')
|
||||
|
||||
MAKO_MODULE_DIR = Derived(make_mako_module_dir)
|
||||
MAKO_TEMPLATE_DIRS_BASE = [
|
||||
Derived(lambda settings: settings.PROJECT_ROOT / 'templates'),
|
||||
COMMON_ROOT / 'templates',
|
||||
COMMON_ROOT / 'djangoapps' / 'pipeline_mako' / 'templates',
|
||||
OPENEDX_ROOT / 'core' / 'djangoapps' / 'cors_csrf' / 'templates',
|
||||
OPENEDX_ROOT / 'core' / 'djangoapps' / 'dark_lang' / 'templates',
|
||||
OPENEDX_ROOT / 'core' / 'lib' / 'license' / 'templates',
|
||||
]
|
||||
|
||||
# Since the CMS uses the LMS's list of mako template directories for the "preview"
|
||||
# template engine, we define the list here
|
||||
lms_mako_template_dirs_base = list(MAKO_TEMPLATE_DIRS_BASE)
|
||||
lms_mako_template_dirs_base.insert(2, XMODULE_ROOT / 'capa' / 'templates')
|
||||
lms_mako_template_dirs_base.append(OPENEDX_ROOT / 'features' / 'course_experience' / 'templates')
|
||||
|
||||
CONTEXT_PROCESSORS = [
|
||||
'django.template.context_processors.request',
|
||||
'django.template.context_processors.static',
|
||||
'django.contrib.messages.context_processors.messages',
|
||||
'django.template.context_processors.i18n',
|
||||
'django.contrib.auth.context_processors.auth', # this is required for admin
|
||||
'django.template.context_processors.csrf',
|
||||
# Online contextual help
|
||||
'help_tokens.context_processor',
|
||||
'openedx.core.djangoapps.site_configuration.context_processors.configuration_context',
|
||||
]
|
||||
|
||||
DEFAULT_TEMPLATE_ENGINE = TEMPLATES[0]
|
||||
|
||||
############################## Site Settings ###############################
|
||||
|
||||
HTTPS = 'on'
|
||||
@@ -460,6 +745,62 @@ ALL_LANGUAGES = [
|
||||
|
||||
LANGUAGE_DICT = dict(LANGUAGES)
|
||||
|
||||
############################## Optional Apps ###############################
|
||||
|
||||
OPTIONAL_APPS = [
|
||||
('problem_builder', 'openedx.core.djangoapps.content.course_overviews.apps.CourseOverviewsConfig'),
|
||||
('edx_sga', None),
|
||||
|
||||
# edx-ora2
|
||||
('submissions', 'openedx.core.djangoapps.content.course_overviews.apps.CourseOverviewsConfig'),
|
||||
('openassessment', 'openedx.core.djangoapps.content.course_overviews.apps.CourseOverviewsConfig'),
|
||||
('openassessment.assessment', 'openedx.core.djangoapps.content.course_overviews.apps.CourseOverviewsConfig'),
|
||||
('openassessment.fileupload', 'openedx.core.djangoapps.content.course_overviews.apps.CourseOverviewsConfig'),
|
||||
('openassessment.staffgrader', 'openedx.core.djangoapps.content.course_overviews.apps.CourseOverviewsConfig'),
|
||||
('openassessment.workflow', 'openedx.core.djangoapps.content.course_overviews.apps.CourseOverviewsConfig'),
|
||||
('openassessment.xblock', 'openedx.core.djangoapps.content.course_overviews.apps.CourseOverviewsConfig'),
|
||||
|
||||
# edxval
|
||||
('edxval', 'openedx.core.djangoapps.content.course_overviews.apps.CourseOverviewsConfig'),
|
||||
|
||||
# Enterprise Apps (http://github.com/openedx/edx-enterprise)
|
||||
('enterprise', None),
|
||||
('consent', None),
|
||||
('integrated_channels.integrated_channel', None),
|
||||
('integrated_channels.degreed', None),
|
||||
('integrated_channels.degreed2', None),
|
||||
('integrated_channels.sap_success_factors', None),
|
||||
('integrated_channels.cornerstone', None),
|
||||
('integrated_channels.xapi', None),
|
||||
('integrated_channels.blackboard', None),
|
||||
('integrated_channels.canvas', None),
|
||||
('integrated_channels.moodle', None),
|
||||
]
|
||||
|
||||
|
||||
def add_optional_apps(optional_apps, installed_apps):
|
||||
"""
|
||||
Adds apps from optional_apps to installed_apps if they can be imported.
|
||||
|
||||
:param optional_apps: List of tuples (str, str). The tuples should contain the name
|
||||
of the app and the name of the app which it should be inserted before.
|
||||
:param installed_apps: List of installed Django apps to modify (i.e. INSTALLED_APPS)
|
||||
"""
|
||||
for app_name, insert_before in optional_apps:
|
||||
# First attempt to only find the module rather than actually importing it,
|
||||
# to avoid circular references - only try to import if it can't be found
|
||||
# by find_spec, which doesn't work with import hooks
|
||||
if importlib.util.find_spec(app_name) is None:
|
||||
try:
|
||||
__import__(app_name)
|
||||
except ImportError:
|
||||
continue
|
||||
|
||||
try:
|
||||
installed_apps.insert(installed_apps.index(insert_before), app_name)
|
||||
except (IndexError, ValueError):
|
||||
installed_apps.append(app_name)
|
||||
|
||||
########################## Django Rest Framework ###########################
|
||||
|
||||
REST_FRAMEWORK = {
|
||||
@@ -537,14 +878,17 @@ CELERY_TRACK_STARTED = True
|
||||
CELERY_SEND_EVENTS = True
|
||||
CELERY_SEND_TASK_SENT_EVENT = True
|
||||
|
||||
# Exchange configuration
|
||||
CELERY_DEFAULT_EXCHANGE = 'edx.core'
|
||||
CELERY_DEFAULT_EXCHANGE_TYPE = 'direct'
|
||||
|
||||
# Queues configuration
|
||||
CELERY_QUEUE_HA_POLICY = 'all'
|
||||
CELERY_CREATE_MISSING_QUEUES = True
|
||||
|
||||
# Exchange configuration
|
||||
CELERY_DEFAULT_EXCHANGE_TYPE = 'direct'
|
||||
CELERY_DEFAULT_EXCHANGE = Derived(lambda settings: f'edx.{settings.SERVICE_VARIANT}.core')
|
||||
|
||||
CELERY_DEFAULT_QUEUE = Derived(lambda settings: settings.DEFAULT_PRIORITY_QUEUE)
|
||||
CELERY_DEFAULT_ROUTING_KEY = CELERY_DEFAULT_QUEUE = Derived(lambda settings: settings.DEFAULT_PRIORITY_QUEUE)
|
||||
|
||||
# Checks run in normal mode by the heartbeat djangoapp
|
||||
HEARTBEAT_CHECKS = [
|
||||
'openedx.core.djangoapps.heartbeat.default_checks.check_modulestore',
|
||||
@@ -558,6 +902,8 @@ HEARTBEAT_EXTENDED_CHECKS = (
|
||||
|
||||
HEARTBEAT_CELERY_TIMEOUT = 5
|
||||
|
||||
HEARTBEAT_CELERY_ROUTING_KEY = Derived(lambda settings: settings.HIGH_PRIORITY_QUEUE)
|
||||
|
||||
############################ RedirectMiddleware ############################
|
||||
|
||||
# Setting this to None causes Redirect data to never expire
|
||||
@@ -614,6 +960,12 @@ JWT_AUTH = {
|
||||
'JWT_AUTH_HEADER_PREFIX': 'JWT',
|
||||
}
|
||||
|
||||
EDX_DRF_EXTENSIONS = {
|
||||
# Set this value to an empty dict in order to prevent automatically updating
|
||||
# user data from values in (possibly stale) JWTs.
|
||||
'JWT_PAYLOAD_USER_ATTRIBUTE_MAPPING': {},
|
||||
}
|
||||
|
||||
################################# Features #################################
|
||||
|
||||
# .. setting_name: PLATFORM_NAME
|
||||
@@ -1046,107 +1398,8 @@ XQUEUE_INTERFACE = {
|
||||
}
|
||||
}
|
||||
|
||||
########################### Cache Configuration ############################
|
||||
|
||||
CACHES = {
|
||||
'course_structure_cache': {
|
||||
'KEY_PREFIX': 'course_structure',
|
||||
'KEY_FUNCTION': 'common.djangoapps.util.memcache.safe_key',
|
||||
'LOCATION': ['localhost:11211'],
|
||||
'TIMEOUT': '604800', # 1 week
|
||||
'BACKEND': 'django.core.cache.backends.memcached.PyMemcacheCache',
|
||||
'OPTIONS': {
|
||||
'no_delay': True,
|
||||
'ignore_exc': True,
|
||||
'use_pooling': True,
|
||||
'connect_timeout': 0.5
|
||||
}
|
||||
},
|
||||
'celery': {
|
||||
'KEY_PREFIX': 'celery',
|
||||
'KEY_FUNCTION': 'common.djangoapps.util.memcache.safe_key',
|
||||
'LOCATION': ['localhost:11211'],
|
||||
'TIMEOUT': '7200',
|
||||
'BACKEND': 'django.core.cache.backends.memcached.PyMemcacheCache',
|
||||
'OPTIONS': {
|
||||
'no_delay': True,
|
||||
'ignore_exc': True,
|
||||
'use_pooling': True,
|
||||
'connect_timeout': 0.5
|
||||
}
|
||||
},
|
||||
'mongo_metadata_inheritance': {
|
||||
'KEY_PREFIX': 'mongo_metadata_inheritance',
|
||||
'KEY_FUNCTION': 'common.djangoapps.util.memcache.safe_key',
|
||||
'LOCATION': ['localhost:11211'],
|
||||
'TIMEOUT': 300,
|
||||
'BACKEND': 'django.core.cache.backends.memcached.PyMemcacheCache',
|
||||
'OPTIONS': {
|
||||
'no_delay': True,
|
||||
'ignore_exc': True,
|
||||
'use_pooling': True,
|
||||
'connect_timeout': 0.5
|
||||
}
|
||||
},
|
||||
'staticfiles': {
|
||||
'KEY_FUNCTION': 'common.djangoapps.util.memcache.safe_key',
|
||||
'LOCATION': ['localhost:11211'],
|
||||
'KEY_PREFIX': 'staticfiles_general',
|
||||
'BACKEND': 'django.core.cache.backends.memcached.PyMemcacheCache',
|
||||
'OPTIONS': {
|
||||
'no_delay': True,
|
||||
'ignore_exc': True,
|
||||
'use_pooling': True,
|
||||
'connect_timeout': 0.5
|
||||
}
|
||||
},
|
||||
'default': {
|
||||
'VERSION': '1',
|
||||
'KEY_FUNCTION': 'common.djangoapps.util.memcache.safe_key',
|
||||
'LOCATION': ['localhost:11211'],
|
||||
'KEY_PREFIX': 'default',
|
||||
'BACKEND': 'django.core.cache.backends.memcached.PyMemcacheCache',
|
||||
'OPTIONS': {
|
||||
'no_delay': True,
|
||||
'ignore_exc': True,
|
||||
'use_pooling': True,
|
||||
'connect_timeout': 0.5
|
||||
}
|
||||
},
|
||||
'configuration': {
|
||||
'KEY_FUNCTION': 'common.djangoapps.util.memcache.safe_key',
|
||||
'LOCATION': ['localhost:11211'],
|
||||
'KEY_PREFIX': 'configuration',
|
||||
'BACKEND': 'django.core.cache.backends.memcached.PyMemcacheCache',
|
||||
'OPTIONS': {
|
||||
'no_delay': True,
|
||||
'ignore_exc': True,
|
||||
'use_pooling': True,
|
||||
'connect_timeout': 0.5
|
||||
}
|
||||
},
|
||||
'general': {
|
||||
'KEY_FUNCTION': 'common.djangoapps.util.memcache.safe_key',
|
||||
'LOCATION': ['localhost:11211'],
|
||||
'KEY_PREFIX': 'general',
|
||||
'BACKEND': 'django.core.cache.backends.memcached.PyMemcacheCache',
|
||||
'OPTIONS': {
|
||||
'no_delay': True,
|
||||
'ignore_exc': True,
|
||||
'use_pooling': True,
|
||||
'connect_timeout': 0.5
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
################################### CSRF ###################################
|
||||
|
||||
CSRF_COOKIE_AGE = 60 * 60 * 24 * 7 * 52
|
||||
|
||||
# It is highly recommended that you override this in any environment accessed by
|
||||
# end users
|
||||
CSRF_COOKIE_SECURE = False
|
||||
|
||||
# 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
|
||||
@@ -1174,8 +1427,6 @@ CROSS_DOMAIN_CSRF_COOKIE_NAME = ''
|
||||
# the client won't be able to read the cookie.
|
||||
CROSS_DOMAIN_CSRF_COOKIE_DOMAIN = ''
|
||||
|
||||
CSRF_TRUSTED_ORIGINS = []
|
||||
|
||||
ENABLE_CROSS_DOMAIN_CSRF_COOKIE = False
|
||||
|
||||
########################## Cross-domain Requests ###########################
|
||||
@@ -1212,6 +1463,21 @@ SOCIAL_MEDIA_LOGO_URLS = {
|
||||
'facebook': 'http://email-media.s3.amazonaws.com/edX/2021/social_1_fb.png',
|
||||
}
|
||||
|
||||
########################### Social Media Sharing ###########################
|
||||
|
||||
# Social Media Sharing on Student Dashboard
|
||||
SOCIAL_SHARING_SETTINGS = {
|
||||
'CUSTOM_COURSE_URLS': False, # This value should not differ between lms/cms
|
||||
'DASHBOARD_FACEBOOK': False,
|
||||
'CERTIFICATE_FACEBOOK': False,
|
||||
'CERTIFICATE_TWITTER': False,
|
||||
'DASHBOARD_TWITTER': False,
|
||||
}
|
||||
|
||||
############################# Google Analytics #############################
|
||||
|
||||
GOOGLE_ANALYTICS_ACCOUNT = None
|
||||
|
||||
############################# Block Structures #############################
|
||||
|
||||
# .. setting_name: BLOCK_STRUCTURES_SETTINGS
|
||||
@@ -1316,6 +1582,16 @@ VIDEO_TRANSCRIPTS_SETTINGS = dict(
|
||||
|
||||
VIDEO_TRANSCRIPTS_MAX_AGE = 31536000
|
||||
|
||||
TRANSCRIPT_LANG_CACHE_TIMEOUT = 60 * 60 * 24 # 24 hours
|
||||
|
||||
############################## Video Pipeline ##############################
|
||||
|
||||
VIDEO_UPLOAD_PIPELINE = {
|
||||
'VEM_S3_BUCKET': '',
|
||||
'BUCKET': '',
|
||||
'ROOT_PATH': '',
|
||||
}
|
||||
|
||||
############################ Parental Controls #############################
|
||||
|
||||
# .. setting_name: PARENTAL_CONSENT_AGE_LIMIT
|
||||
@@ -1366,6 +1642,30 @@ SHOW_ACTIVATE_CTA_POPUP_COOKIE_NAME = 'show-account-activation-popup'
|
||||
# .. toggle_creation_date: 2021-06-10
|
||||
SHOW_ACCOUNT_ACTIVATION_CTA = False
|
||||
|
||||
# .. setting_name: REGISTRATION_EXTRA_FIELDS
|
||||
# .. setting_default: {'confirm_email': 'hidden', 'level_of_education': 'optional', 'gender': 'optional',
|
||||
# 'year_of_birth': 'optional', 'mailing_address': 'optional', 'goals': 'optional', 'honor_code': 'required',
|
||||
# 'terms_of_service': 'hidden', 'city': 'hidden', 'country': 'hidden'}
|
||||
# .. setting_description: The signup form may contain extra fields that are presented to every user. For every field, we
|
||||
# can specifiy whether it should be "required": to display the field, and make it mandatory; "optional": to display
|
||||
# the optional field as part of a toggled input field list; "optional-exposed": to display the optional fields among
|
||||
# the required fields, and make it non-mandatory; "hidden": to not display the field.
|
||||
# When the terms of service are not visible and agreement to the honor code is required (the default), the signup page
|
||||
# includes a paragraph that links to the honor code page (defined my MKTG_URLS["HONOR"]). This page might not be
|
||||
# available for all Open edX platforms. In such cases, the "honor_code" registration field should be "hidden".
|
||||
REGISTRATION_EXTRA_FIELDS = {
|
||||
'confirm_email': 'hidden',
|
||||
'level_of_education': 'optional',
|
||||
'gender': 'optional',
|
||||
'year_of_birth': 'optional',
|
||||
'mailing_address': 'optional',
|
||||
'goals': 'optional',
|
||||
'honor_code': 'required',
|
||||
'terms_of_service': 'hidden',
|
||||
'city': 'hidden',
|
||||
'country': 'hidden',
|
||||
}
|
||||
|
||||
######################### Course Enrollment Modes ##########################
|
||||
|
||||
# The min_price key refers to the minimum price allowed for an instance
|
||||
@@ -1465,45 +1765,81 @@ ENTERPRISE_BACKEND_SERVICE_EDX_OAUTH2_PROVIDER_URL = "http://127.0.0.1:8000/oaut
|
||||
|
||||
ASSET_IGNORE_REGEX = r"(^\._.*$)|(^\.DS_Store$)|(^.*~$)"
|
||||
|
||||
DATABASES = {
|
||||
# edxapp's edxapp-migrate scripts and the edxapp_migrate play
|
||||
# will ensure that any DB not named read_replica will be migrated
|
||||
# for both the lms and cms.
|
||||
# This Django setting was removed in Django 4.0, but it is still being referenced
|
||||
# in the code. It would be worth investigating if we still need this and, if we do,
|
||||
# leave a comment explaining why here. See https://github.com/openedx/edx-platform/issues/37744.
|
||||
DEFAULT_HASHING_ALGORITHM = 'sha256'
|
||||
|
||||
DOC_STORE_CONFIG = {
|
||||
'db': 'edxapp',
|
||||
'host': 'localhost',
|
||||
'replicaSet': '',
|
||||
'port': 27017,
|
||||
'user': 'edxapp',
|
||||
'collection': 'modulestore',
|
||||
'ssl': False,
|
||||
# https://api.mongodb.com/python/2.9.1/api/pymongo/mongo_client.html#module-pymongo.mongo_client
|
||||
# default is never timeout while the connection is open,
|
||||
#this means it needs to explicitly close raising pymongo.errors.NetworkTimeout
|
||||
'socketTimeoutMS': 6000,
|
||||
'connectTimeoutMS': 2000, # default is 20000, I believe raises pymongo.errors.ConnectionFailure
|
||||
# Not setting waitQueueTimeoutMS and waitQueueMultiple since pymongo defaults to nobody being allowed to wait
|
||||
'auth_source': None,
|
||||
# If 'asset_collection' defined, it'll be used as the collection name for asset metadata.
|
||||
# Otherwise, a default collection name will be used.
|
||||
}
|
||||
|
||||
CONTENTSTORE = {
|
||||
'ENGINE': 'xmodule.contentstore.mongo.MongoContentStore',
|
||||
# connection strings are duplicated temporarily for
|
||||
# backward compatibility
|
||||
'OPTIONS': {
|
||||
'db': 'edxapp',
|
||||
'host': 'localhost',
|
||||
'password': 'password',
|
||||
'port': 27017,
|
||||
'user': 'edxapp',
|
||||
'ssl': False,
|
||||
'auth_source': None
|
||||
},
|
||||
'ADDITIONAL_OPTIONS': {},
|
||||
'DOC_STORE_CONFIG': DOC_STORE_CONFIG
|
||||
}
|
||||
|
||||
MODULESTORE = {
|
||||
'default': {
|
||||
'ATOMIC_REQUESTS': True,
|
||||
'CONN_MAX_AGE': 0,
|
||||
'ENGINE': 'django.db.backends.mysql',
|
||||
'HOST': '127.0.0.1',
|
||||
'NAME': 'edxapp',
|
||||
'OPTIONS': {},
|
||||
'PASSWORD': 'password',
|
||||
'PORT': '3306',
|
||||
'USER': 'edxapp001'
|
||||
},
|
||||
'read_replica': {
|
||||
'CONN_MAX_AGE': 0,
|
||||
'ENGINE': 'django.db.backends.mysql',
|
||||
'HOST': '127.0.0.1',
|
||||
'NAME': 'edxapp',
|
||||
'OPTIONS': {},
|
||||
'PASSWORD': 'password',
|
||||
'PORT': '3306',
|
||||
'USER': 'edxapp001'
|
||||
},
|
||||
'student_module_history': {
|
||||
'CONN_MAX_AGE': 0,
|
||||
'ENGINE': 'django.db.backends.mysql',
|
||||
'HOST': '127.0.0.1',
|
||||
'NAME': 'edxapp_csmh',
|
||||
'OPTIONS': {},
|
||||
'PASSWORD': 'password',
|
||||
'PORT': '3306',
|
||||
'USER': 'edxapp001'
|
||||
'ENGINE': 'xmodule.modulestore.mixed.MixedModuleStore',
|
||||
'OPTIONS': {
|
||||
'mappings': {},
|
||||
'stores': [
|
||||
{
|
||||
'NAME': 'split',
|
||||
'ENGINE': 'xmodule.modulestore.split_mongo.split_draft.DraftVersioningModuleStore',
|
||||
'DOC_STORE_CONFIG': DOC_STORE_CONFIG,
|
||||
'OPTIONS': {
|
||||
'default_class': 'xmodule.hidden_block.HiddenBlock',
|
||||
'fs_root': Derived(lambda settings: settings.DATA_DIR),
|
||||
'render_template': 'common.djangoapps.edxmako.shortcuts.render_to_string',
|
||||
}
|
||||
},
|
||||
{
|
||||
'NAME': 'draft',
|
||||
'ENGINE': 'xmodule.modulestore.mongo.DraftMongoModuleStore',
|
||||
'DOC_STORE_CONFIG': DOC_STORE_CONFIG,
|
||||
'OPTIONS': {
|
||||
'default_class': 'xmodule.hidden_block.HiddenBlock',
|
||||
'fs_root': Derived(lambda settings: settings.DATA_DIR),
|
||||
'render_template': 'common.djangoapps.edxmako.shortcuts.render_to_string',
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DEFAULT_AUTO_FIELD = 'django.db.models.AutoField'
|
||||
DEFAULT_HASHING_ALGORITHM = 'sha256'
|
||||
# Modulestore-level field override providers. These field override providers don't
|
||||
# require student context.
|
||||
MODULESTORE_FIELD_OVERRIDE_PROVIDERS = ()
|
||||
|
||||
############################# Micro-frontends ##############################
|
||||
|
||||
@@ -1652,6 +1988,21 @@ XBLOCK_SETTINGS = {}
|
||||
# .. setting_description: The django cache key of the cache to use for storing anonymous user state for XBlocks.
|
||||
XBLOCK_RUNTIME_V2_EPHEMERAL_DATA_CACHE = 'default'
|
||||
|
||||
# These are the Mixins that will be added to every Blocklike upon instantiation.
|
||||
# DO NOT EXPAND THIS LIST!! We want it eventually to be EMPTY. Why? Because dynamically adding functions/behaviors to
|
||||
# objects at runtime is confusing for both developers and static tooling (pylint/mypy). Instead...
|
||||
# - to add special Blocklike behaviors just for your site: override `XBLOCK_EXTRA_MIXINS` with your own XBlockMixins.
|
||||
# - to add new functionality to all Blocklikes: add it to the base Blocklike class in the core openedx/XBlock repo.
|
||||
XBLOCK_MIXINS = (
|
||||
# TODO: For each of these, either
|
||||
# (a) merge their functionality into the base Blocklike class, or
|
||||
# (b) refactor their functionality out of the Blocklike objects and into the edx-platform block runtimes.
|
||||
LmsBlockMixin,
|
||||
InheritanceMixin,
|
||||
XModuleMixin,
|
||||
EditInfoMixin,
|
||||
)
|
||||
|
||||
######################## Built-in Blocks Extraction ########################
|
||||
|
||||
# The following Django settings flags have been introduced temporarily to facilitate
|
||||
@@ -1748,9 +2099,15 @@ EDXMKTG_USER_INFO_COOKIE_VERSION = 1
|
||||
|
||||
MKTG_URLS = {}
|
||||
MKTG_URL_OVERRIDES = {}
|
||||
MKTG_URL_LINK_MAP = {}
|
||||
|
||||
SUPPORT_SITE_LINK = ''
|
||||
|
||||
ACTIVATION_EMAIL_SUPPORT_LINK = Derived(lambda settings: settings.SUPPORT_SITE_LINK)
|
||||
ID_VERIFICATION_SUPPORT_LINK = Derived(lambda settings: settings.SUPPORT_SITE_LINK)
|
||||
LOGIN_ISSUE_SUPPORT_LINK = Derived(lambda settings: settings.SUPPORT_SITE_LINK)
|
||||
PASSWORD_RESET_SUPPORT_LINK = Derived(lambda settings: settings.SUPPORT_SITE_LINK)
|
||||
|
||||
################################# ChatGPT ##################################
|
||||
|
||||
CHAT_COMPLETION_API = ''
|
||||
@@ -1791,6 +2148,31 @@ ZENDESK_GROUP_ID_MAPPING = {}
|
||||
|
||||
############################## Python sandbox ##############################
|
||||
|
||||
CODE_JAIL = {
|
||||
# from https://github.com/openedx/codejail/blob/master/codejail/django_integration.py#L24, '' should be same as None
|
||||
'python_bin': '/edx/app/edxapp/venvs/edxapp-sandbox/bin/python',
|
||||
# User to run as in the sandbox.
|
||||
'user': 'sandbox',
|
||||
|
||||
# Configurable limits.
|
||||
'limits': {
|
||||
# How many CPU seconds can jailed code use?
|
||||
'CPU': 1,
|
||||
# Limit the memory of the jailed process to something high but not
|
||||
# infinite (512MiB in bytes)
|
||||
'VMEM': 536870912,
|
||||
# Time in seconds that the jailed process has to run.
|
||||
'REALTIME': 3,
|
||||
'PROXY': 0,
|
||||
},
|
||||
|
||||
# Overrides to default configurable 'limits' (above).
|
||||
# Keys should be course run ids (or, in the special case of code running
|
||||
# on the /debug/run_python page, the key is 'debug_run_python').
|
||||
# Values should be dictionaries that look like 'limits'.
|
||||
"limit_overrides": {},
|
||||
}
|
||||
|
||||
# Some courses are allowed to run unsafe code. This is a list of regexes, one
|
||||
# of them must match the course id for that course to run unsafe code.
|
||||
#
|
||||
@@ -1831,8 +2213,6 @@ CODE_JAIL_REST_SERVICE_READ_TIMEOUT = 3.5 # time in seconds
|
||||
|
||||
# Locale/Internationalization
|
||||
CELERY_TIMEZONE = 'UTC'
|
||||
TIME_ZONE = 'UTC'
|
||||
LANGUAGE_CODE = 'en' # http://www.i18nguy.com/unicode/language-identifiers.html
|
||||
|
||||
# Languages supported for custom course certificate templates
|
||||
CERTIFICATE_TEMPLATE_LANGUAGES = {
|
||||
@@ -1840,26 +2220,58 @@ CERTIFICATE_TEMPLATE_LANGUAGES = {
|
||||
'es': 'Español',
|
||||
}
|
||||
|
||||
USE_I18N = True
|
||||
USE_L10N = True
|
||||
|
||||
STATICI18N_FILENAME_FUNCTION = 'statici18n.utils.legacy_filename'
|
||||
STATICI18N_OUTPUT_DIR = "js/i18n"
|
||||
STATICI18N_ROOT = Derived(lambda settings: settings.PROJECT_ROOT / "static")
|
||||
|
||||
################################# Pipeline #################################
|
||||
|
||||
PIPELINE = {
|
||||
'PIPELINE_ENABLED': True,
|
||||
# Don't use compression by default
|
||||
'CSS_COMPRESSOR': None,
|
||||
# Don't wrap JavaScript as there is code that depends upon updating the global namespace
|
||||
'DISABLE_WRAPPER': True,
|
||||
# Specify the UglifyJS binary to use
|
||||
'UGLIFYJS_BINARY': 'node_modules/.bin/uglifyjs',
|
||||
}
|
||||
|
||||
STATICFILES_STORAGE_KWARGS = {}
|
||||
|
||||
# List of finder classes that know how to find static files in various locations.
|
||||
# Note: the pipeline finder is included to be able to discover optimized files
|
||||
STATICFILES_FINDERS = [
|
||||
'openedx.core.djangoapps.theming.finders.ThemeFilesFinder',
|
||||
'django.contrib.staticfiles.finders.FileSystemFinder',
|
||||
'django.contrib.staticfiles.finders.AppDirectoriesFinder',
|
||||
'openedx.core.lib.xblock_pipeline.finder.XBlockPipelineFinder',
|
||||
'pipeline.finders.PipelineFinder',
|
||||
STATICFILES_IGNORE_PATTERNS = [
|
||||
"*.py",
|
||||
"*.pyc",
|
||||
|
||||
# It would be nice if we could do, for example, "**/*.scss",
|
||||
# but these strings get passed down to the `fnmatch` module,
|
||||
# which doesn't support that. :(
|
||||
# http://docs.python.org/2/library/fnmatch.html
|
||||
"sass/*.scss",
|
||||
"sass/*/*.scss",
|
||||
"sass/*/*/*.scss",
|
||||
"sass/*/*/*/*.scss",
|
||||
|
||||
# Ignore tests
|
||||
"spec",
|
||||
"spec_helpers",
|
||||
|
||||
# Symlinks used by js-test-tool
|
||||
"xmodule_js",
|
||||
]
|
||||
|
||||
########################## Django Webpack Loader ###########################
|
||||
|
||||
WEBPACK_LOADER = {
|
||||
'DEFAULT': {
|
||||
'BUNDLE_DIR_NAME': 'bundles/',
|
||||
'STATS_FILE': Derived(lambda settings: os.path.join(settings.STATIC_ROOT, 'webpack-stats.json')),
|
||||
},
|
||||
'WORKERS': {
|
||||
'BUNDLE_DIR_NAME': 'bundles/',
|
||||
'STATS_FILE': Derived(lambda settings: os.path.join(settings.STATIC_ROOT, 'webpack-worker-stats.json')),
|
||||
}
|
||||
}
|
||||
|
||||
############################## django-require ##############################
|
||||
|
||||
# The baseUrl to pass to the r.js optimizer, relative to STATIC_ROOT.
|
||||
@@ -1868,6 +2280,12 @@ REQUIRE_BASE_URL = "./"
|
||||
# Whether to run django-require in debug mode.
|
||||
REQUIRE_DEBUG = False
|
||||
|
||||
# The name of a build profile to use for your project, relative to REQUIRE_BASE_URL.
|
||||
# A sensible value would be 'app.build.js'. Leave blank to use the built-in default build profile.
|
||||
# Set to False to disable running the default profile (e.g. if only using it to build Standalone
|
||||
# Modules)
|
||||
REQUIRE_BUILD_PROFILE = Derived(lambda settings: f"{settings.SERVICE_VARIANT}/js/build.js")
|
||||
|
||||
########################### Student Verification ###########################
|
||||
|
||||
VERIFY_STUDENT = {
|
||||
@@ -1992,7 +2410,6 @@ DEFAULT_SITE_THEME = None
|
||||
# .. toggle_creation_date: 2016-06-30
|
||||
ENABLE_COMPREHENSIVE_THEMING = False
|
||||
|
||||
|
||||
################################ Ecommerce #################################
|
||||
|
||||
ECOMMERCE_PUBLIC_URL_ROOT = 'http://localhost:8002'
|
||||
@@ -2068,7 +2485,7 @@ PASSWORD_RESET_EMAIL_RATE = '2/h'
|
||||
|
||||
HELP_TOKENS_LANGUAGE_CODE = Derived(lambda settings: settings.LANGUAGE_CODE)
|
||||
HELP_TOKENS_VERSION = Derived(lambda settings: doc_version())
|
||||
|
||||
HELP_TOKENS_INI_FILE = Derived(lambda settings: REPO_ROOT / settings.SERVICE_VARIANT / "envs" / "help_tokens.ini")
|
||||
HELP_TOKENS_BOOKS = {
|
||||
'learner': 'https://docs.openedx.org/en/latest/learners',
|
||||
'course_author': 'https://docs.openedx.org/en/latest/educators',
|
||||
@@ -2245,9 +2662,92 @@ AI_TRANSLATIONS_API_URL = 'http://localhost:18760/api/v1'
|
||||
def should_send_learning_badge_events(settings):
|
||||
return settings.BADGES_ENABLED
|
||||
|
||||
############################## ALLOWED_HOSTS ###############################
|
||||
# .. setting_name: EVENT_BUS_PRODUCER_CONFIG
|
||||
# .. setting_default: all events disabled
|
||||
# .. setting_description: Dictionary of event_types mapped to dictionaries of topic to topic-related configuration.
|
||||
# Each topic configuration dictionary contains
|
||||
# * `enabled`: a toggle denoting whether the event will be published to the topic. These should be annotated
|
||||
# according to
|
||||
# https://docs.openedx.org/projects/edx-toggles/en/latest/how_to/documenting_new_feature_toggles.html
|
||||
# * `event_key_field` which is a period-delimited string path to event data field to use as event key.
|
||||
# Note: The topic names should not include environment prefix as it will be dynamically added based on
|
||||
# EVENT_BUS_TOPIC_PREFIX setting.
|
||||
EVENT_BUS_PRODUCER_CONFIG = {
|
||||
"org.openedx.learning.course.passing.status.updated.v1": {
|
||||
"learning-badges-lifecycle": {
|
||||
"event_key_field": "course_passing_status.course.course_key",
|
||||
"enabled": Derived(should_send_learning_badge_events),
|
||||
},
|
||||
},
|
||||
"org.openedx.learning.ccx.course.passing.status.updated.v1": {
|
||||
"learning-badges-lifecycle": {
|
||||
"event_key_field": "course_passing_status.course.ccx_course_key",
|
||||
"enabled": Derived(should_send_learning_badge_events),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
ALLOWED_HOSTS = ['*']
|
||||
### event tracking
|
||||
|
||||
EVENT_TRACKING_ENABLED = True
|
||||
EVENT_TRACKING_PROCESSORS = []
|
||||
EVENT_TRACKING_SEGMENTIO_EMIT_WHITELIST = []
|
||||
|
||||
# FIXME: Should we be doing this truncation?
|
||||
TRACK_MAX_EVENT = 50000
|
||||
|
||||
TRACKING_BACKENDS = {
|
||||
'logger': {
|
||||
'ENGINE': 'common.djangoapps.track.backends.logger.LoggerBackend',
|
||||
'OPTIONS': {
|
||||
'name': 'tracking'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
EVENT_TRACKING_BACKENDS = {
|
||||
'tracking_logs': {
|
||||
'ENGINE': 'eventtracking.backends.routing.RoutingBackend',
|
||||
'OPTIONS': {
|
||||
'backends': {
|
||||
'logger': {
|
||||
'ENGINE': 'eventtracking.backends.logger.LoggerBackend',
|
||||
'OPTIONS': {
|
||||
'name': 'tracking',
|
||||
'max_event_size': TRACK_MAX_EVENT,
|
||||
}
|
||||
}
|
||||
},
|
||||
'processors': [
|
||||
{'ENGINE': 'common.djangoapps.track.shim.LegacyFieldMappingProcessor'},
|
||||
{'ENGINE': 'common.djangoapps.track.shim.PrefixedEventProcessor'}
|
||||
]
|
||||
}
|
||||
},
|
||||
'segmentio': {
|
||||
'ENGINE': 'eventtracking.backends.routing.RoutingBackend',
|
||||
'OPTIONS': {
|
||||
'backends': {
|
||||
'segment': {'ENGINE': 'eventtracking.backends.segment.SegmentBackend'}
|
||||
},
|
||||
'processors': [
|
||||
{
|
||||
'ENGINE': 'eventtracking.processors.whitelist.NameWhitelistProcessor',
|
||||
'OPTIONS': {
|
||||
'whitelist': []
|
||||
}
|
||||
},
|
||||
{
|
||||
'ENGINE': 'common.djangoapps.track.shim.GoogleAnalyticsProcessor'
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# We're already logging events, and we don't want to capture user
|
||||
# names/passwords. Heartbeat events are likely not interesting.
|
||||
TRACKING_IGNORE_URL_PATTERNS = [r'^/event', r'^/login', r'^/heartbeat']
|
||||
|
||||
############################## Miscellaneous ###############################
|
||||
|
||||
@@ -2299,6 +2799,9 @@ VIDEO_CDN_URL = {
|
||||
|
||||
SOFTWARE_SECURE_VERIFICATION_ROUTING_KEY = Derived(lambda settings: settings.HIGH_PRIORITY_QUEUE)
|
||||
|
||||
# Queue to use for updating persistent grades
|
||||
RECALCULATE_GRADES_ROUTING_KEY = Derived(lambda settings: settings.DEFAULT_PRIORITY_QUEUE)
|
||||
|
||||
# Queue to use for updating grades due to grading policy change
|
||||
POLICY_CHANGE_GRADES_ROUTING_KEY = Derived(lambda settings: settings.DEFAULT_PRIORITY_QUEUE)
|
||||
|
||||
@@ -2340,11 +2843,6 @@ SOFTWARE_SECURE_RETRY_MAX_ATTEMPTS = 6
|
||||
|
||||
MARKETING_EMAILS_OPT_IN = False
|
||||
|
||||
# Set request limits for maximum size of a request body and maximum number of GET/POST parameters. (>=Django 1.10)
|
||||
# Limits are currently disabled - but can be used for finer-grained denial-of-service protection.
|
||||
DATA_UPLOAD_MAX_MEMORY_SIZE = None
|
||||
DATA_UPLOAD_MAX_NUMBER_FIELDS = None
|
||||
|
||||
# License for serving content in China
|
||||
ICP_LICENSE = None
|
||||
ICP_LICENSE_INFO = {}
|
||||
@@ -2443,3 +2941,15 @@ FEEDBACK_SUBMISSION_EMAIL = ''
|
||||
COURSE_LIVE_GLOBAL_CREDENTIALS = {}
|
||||
|
||||
BEAMER_PRODUCT_ID = ""
|
||||
|
||||
# For geolocation ip database
|
||||
GEOIP_PATH = REPO_ROOT / "common/static/data/geoip/GeoLite2-Country.mmdb"
|
||||
|
||||
# .. toggle_name: WIKI_ENABLED
|
||||
# .. toggle_implementation: DjangoSetting
|
||||
# .. toggle_default: True
|
||||
# .. toggle_description: This setting allows us to have a collaborative tool to contribute or
|
||||
# modify content of course related materials.
|
||||
# .. toggle_use_cases: open_edx
|
||||
# .. toggle_creation_date: 2012-07-13
|
||||
WIKI_ENABLED = True
|
||||
|
||||
@@ -90,7 +90,6 @@ PARENTAL_CONSENT_AGE_LIMIT = 13
|
||||
# Test theme
|
||||
TEST_THEME = Derived(lambda settings: settings.COMMON_ROOT / "test" / "test-theme")
|
||||
ENABLE_COMPREHENSIVE_THEMING = True
|
||||
COMPREHENSIVE_THEME_DIRS = Derived(lambda settings: [settings.REPO_ROOT / "themes", settings.REPO_ROOT / "common/test"])
|
||||
|
||||
# Enable EdxNotes for tests
|
||||
ENABLE_EDXNOTES = True
|
||||
|
||||
@@ -85,11 +85,13 @@ ignore_imports =
|
||||
############################################################################
|
||||
# cms side imports that we are ignoring for now
|
||||
cms.djangoapps.contentstore.views.tests.test_block -> lms.djangoapps.lms_xblock.mixin
|
||||
cms.envs.common -> lms.envs.common
|
||||
cms.djangoapps.contentstore.signals.handlers -> lms.djangoapps.grades.api
|
||||
cms.djangoapps.contentstore.course_group_config -> lms.lib.utils
|
||||
cms.djangoapps.contentstore.views.preview -> lms.djangoapps.lms_xblock.field_data
|
||||
cms.envs.common -> lms.djangoapps.lms_xblock.mixin
|
||||
# cms.envs.common
|
||||
# -> openedx.envs.common
|
||||
# -> lms.djangoapps.lms_xblock.mixin
|
||||
openedx.envs.common -> lms.djangoapps.lms_xblock.mixin
|
||||
# cms.djangoapps.contentstore.views.tests.test_group_configurations
|
||||
# -> openedx.features.content_type_gating.helpers
|
||||
# -> lms.djangoapps.courseware.masquerade
|
||||
|
||||
Reference in New Issue
Block a user