refactor: bring common settings into common module (#37746)

This commit is contained in:
Taylor Payne
2026-01-09 09:20:59 -07:00
committed by GitHub
parent 7f1f8767a8
commit 7111e8b18c
13 changed files with 789 additions and 1222 deletions

View File

@@ -46,16 +46,13 @@ from datetime import timedelta
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
import lms.envs.common
from openedx.envs.common import * # pylint: disable=wildcard-import from openedx.envs.common import * # pylint: disable=wildcard-import
from path import Path as path 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.authoring_mixin import AuthoringMixin
from cms.lib.xblock.upstream_sync import UpstreamSyncMixin 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.derived import Derived
from openedx.core.lib.features_setting_proxy import FeaturesProxy from openedx.core.lib.features_setting_proxy import FeaturesProxy
@@ -269,117 +266,50 @@ MARKETING_EMAILS_OPT_IN = False
############################# MICROFRONTENDS ################################### ############################# MICROFRONTENDS ###################################
COURSE_AUTHORING_MICROFRONTEND_URL = None 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 ############################# ############################# SET PATH INFORMATION #############################
PROJECT_ROOT = path(__file__).abspath().dirname().dirname() # /edx-platform/cms 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" CMS_ROOT = REPO_ROOT / "cms"
LMS_ROOT = REPO_ROOT / "lms" 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" 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 ###########################
BRANCH_IO_KEY = '' BRANCH_IO_KEY = ''
######################## GOOGLE ANALYTICS ###########################
GOOGLE_ANALYTICS_ACCOUNT = None
######################## HOTJAR ########################### ######################## HOTJAR ###########################
HOTJAR_ID = 00000 HOTJAR_ID = 00000
############################# TEMPLATE CONFIGURATION ############################# ############################# 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 = ( MAKO_TEMPLATE_DIRS_BASE.insert(3, COMMON_ROOT / 'static')
'django.template.context_processors.request', MAKO_TEMPLATE_DIRS_BASE.append(CMS_ROOT / 'djangoapps' / 'pipeline_js' / 'templates')
'django.template.context_processors.static', MAKO_TEMPLATE_DIRS_BASE.append(XMODULE_ROOT / 'capa' / 'templates')
'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',
)
# Django templating
TEMPLATES = [ def make_lms_template_path(settings):
{ """
'NAME': 'django', Make the path for the LMS "templates" dir
'BACKEND': 'django.template.backends.django.DjangoTemplates', """
# Don't look for template source files inside installed applications. templates_path = settings.PROJECT_ROOT / 'templates'
'APP_DIRS': False, return templates_path.replace('cms', 'lms')
# Instead, look for template source files in these dirs.
'DIRS': Derived(make_mako_template_dirs), lms_mako_template_dirs_base[0] = Derived(make_lms_template_path)
# Options specific to this backend.
'OPTIONS': { TEMPLATES[0]['DIRS'] = Derived(make_mako_template_dirs)
'loaders': ( TEMPLATES.append(
# 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,
}
},
{ {
# This separate copy of the Mako backend is used to render previews using the LMS templates # This separate copy of the Mako backend is used to render previews using the LMS templates
'NAME': 'preview', 'NAME': 'preview',
'BACKEND': 'common.djangoapps.edxmako.backend.Mako', 'BACKEND': 'common.djangoapps.edxmako.backend.Mako',
'APP_DIRS': False, 'APP_DIRS': False,
'DIRS': lms.envs.common.MAKO_TEMPLATE_DIRS_BASE, 'DIRS': lms_mako_template_dirs_base,
'OPTIONS': { 'OPTIONS': {
'context_processors': CONTEXT_PROCESSORS, 'context_processors': CONTEXT_PROCESSORS,
'debug': False, 'debug': False,
'namespace': 'lms.main', 'namespace': 'lms.main',
} }
}, }
] )
DEFAULT_TEMPLATE_ENGINE = TEMPLATES[0]
#################################### AWS ####################################### #################################### AWS #######################################
AWS_SECURITY_TOKEN = None AWS_SECURITY_TOKEN = None
@@ -387,13 +317,8 @@ AWS_SECURITY_TOKEN = None
############################################################################## ##############################################################################
# use the ratelimit backend to prevent brute force attacks # use the ratelimit backend to prevent brute force attacks
AUTHENTICATION_BACKENDS = [ AUTHENTICATION_BACKENDS.insert(0, 'auth_backends.backends.EdXOAuth2')
'auth_backends.backends.EdXOAuth2', AUTHENTICATION_BACKENDS.insert(2, 'openedx.core.djangoapps.content_libraries.auth.LtiAuthenticationBackend')
'rules.permissions.ObjectPermissionBackend',
'openedx.core.djangoapps.content_libraries.auth.LtiAuthenticationBackend',
'django.contrib.auth.backends.AllowAllUsersModelBackend',
'bridgekeeper.backends.RulePermissionBackend',
]
LMS_BASE = None LMS_BASE = None
@@ -416,8 +341,6 @@ CMS_ROOT_URL = None
MAINTENANCE_BANNER_TEXT = 'Sample banner message' MAINTENANCE_BANNER_TEXT = 'Sample banner message'
WIKI_ENABLED = True
CERT_QUEUE = 'certificates' CERT_QUEUE = 'certificates'
################################# Middleware ################################### ################################# Middleware ###################################
@@ -510,27 +433,14 @@ EXTRA_MIDDLEWARE_CLASSES = []
############# XBlock Configuration ########## ############# XBlock Configuration ##########
# Import after sys.path fixup # DO NOT EXPAND THIS LIST!! See declaration in openedx/envs/common.py for more information
from xmodule.modulestore.inheritance import InheritanceMixin mixins = list(XBLOCK_MIXINS)
from xmodule.x_module import XModuleMixin, ResourceTemplates mixins.insert(2, ResourceTemplates)
mixins += [
# 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,
UpstreamSyncMixin, # Should be above AuthoringMixin for UpstreamSyncMixin.editor_saved to take effect UpstreamSyncMixin, # Should be above AuthoringMixin for UpstreamSyncMixin.editor_saved to take effect
AuthoringMixin, AuthoringMixin,
) ]
XBLOCK_MIXINS = tuple(mixins)
############################ ORA 2 ############################################ ############################ ORA 2 ############################################
@@ -539,116 +449,19 @@ ORA2_FILE_PREFIX = 'default_env-default_deployment/ora2'
############################ Modulestore Configuration ################################ ############################ Modulestore Configuration ################################
DOC_STORE_CONFIG = { CONTENTSTORE['DOC_STORE_CONFIG']['read_preference'] = 'PRIMARY'
'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
}
MODULESTORE_BRANCH = 'draft-preferred' 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_AUTO_FIELD = 'django.db.models.AutoField'
DEFAULT_HASHING_ALGORITHM = 'sha256'
#################### Python sandbox ############################################ #################### Python sandbox ############################################
CODE_JAIL = { # Needs to be non-zero so that jailed code can use it as their temp directory.(1MiB in bytes)
# from https://github.com/openedx/codejail/blob/master/codejail/django_integration.py#L24, '' should be same as None CODE_JAIL['limits']['FSIZE'] = 1048576
'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": {},
}
############################ DJANGO_BUILTINS ################################ ############################ DJANGO_BUILTINS ################################
ROOT_URLCONF = 'cms.urls'
COURSE_IMPORT_EXPORT_BUCKET = '' COURSE_IMPORT_EXPORT_BUCKET = ''
COURSE_METADATA_EXPORT_BUCKET = '' COURSE_METADATA_EXPORT_BUCKET = ''
@@ -684,48 +497,19 @@ PRESS_EMAIL = 'press@example.com'
STATIC_URL = '/static/studio/' STATIC_URL = '/static/studio/'
STATIC_ROOT = os.environ.get('STATIC_ROOT_CMS', ENV_ROOT / 'staticfiles' / 'studio') STATIC_ROOT = os.environ.get('STATIC_ROOT_CMS', ENV_ROOT / 'staticfiles' / 'studio')
STATICFILES_DIRS = [ # Storage
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",
]
COURSE_IMPORT_EXPORT_STORAGE = 'django.core.files.storage.FileSystemStorage' COURSE_IMPORT_EXPORT_STORAGE = 'django.core.files.storage.FileSystemStorage'
COURSE_METADATA_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 ##### ##### custom vendor plugin variables #####
############################### PIPELINE ####################################### ############################### PIPELINE #######################################
PIPELINE = { PIPELINE.update({
'PIPELINE_ENABLED': True,
# Don't use compression by default
'CSS_COMPRESSOR': None,
'JS_COMPRESSOR': None, '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': (), 'COMPILERS': (),
'YUI_BINARY': 'yui-compressor', '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'] = { PIPELINE['STYLESHEETS'] = {
'style-vendor': { 'style-vendor': {
@@ -825,78 +609,23 @@ PIPELINE['JAVASCRIPT'] = {
}, },
} }
STATICFILES_IGNORE_PATTERNS = ( STATICFILES_IGNORE_PATTERNS.append("common_static")
"*.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",
)
################################# DJANGO-REQUIRE ############################### ################################# 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. # The name of the require.js script used by your project, relative to REQUIRE_BASE_URL.
REQUIRE_JS = "js/vendor/requiresjs/require.js" 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 ##################################
# SERVICE_VARIANT specifies name of the variant used, which decides what JSON SERVICE_VARIANT = 'cms'
# 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 ""
################################# CELERY ###################################### ################################# CELERY ######################################
# Name the exchange and queues for each variant # Name the exchange and queues w.r.t the SERVICE_VARIANT
HIGH_PRIORITY_QUEUE = f'edx.{SERVICE_VARIANT}.core.high'
QUEUE_VARIANT = CONFIG_PREFIX.lower() DEFAULT_PRIORITY_QUEUE = f'edx.{SERVICE_VARIANT}.core.default'
LOW_PRIORITY_QUEUE = f'edx.{SERVICE_VARIANT}.core.low'
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
CELERY_QUEUES = { CELERY_QUEUES = {
HIGH_PRIORITY_QUEUE: {}, HIGH_PRIORITY_QUEUE: {},
@@ -904,17 +633,11 @@ CELERY_QUEUES = {
LOW_PRIORITY_QUEUE: {}, LOW_PRIORITY_QUEUE: {},
} }
# Queues configuration
CLEAR_REQUEST_CACHE_ON_TASK_COMPLETION = True CLEAR_REQUEST_CACHE_ON_TASK_COMPLETION = True
BROKER_USE_SSL = Derived(lambda settings: settings.CELERY_BROKER_USE_SSL)
CELERY_ALWAYS_EAGER = False CELERY_ALWAYS_EAGER = False
############################## HEARTBEAT ###################################### BROKER_USE_SSL = Derived(lambda settings: settings.CELERY_BROKER_USE_SSL)
HEARTBEAT_CELERY_ROUTING_KEY = HIGH_PRIORITY_QUEUE
############################## Video ########################################## ############################## Video ##########################################
@@ -923,12 +646,7 @@ EXTENDED_VIDEO_TRANSCRIPT_LANGUAGES = []
############################# SETTINGS FOR VIDEO UPLOAD PIPELINE ############################# ############################# SETTINGS FOR VIDEO UPLOAD PIPELINE #############################
VIDEO_UPLOAD_PIPELINE = { VIDEO_UPLOAD_PIPELINE['CONCURRENT_UPLOAD_LIMIT'] = 4
'VEM_S3_BUCKET': '',
'BUCKET': '',
'ROOT_PATH': '',
'CONCURRENT_UPLOAD_LIMIT': 4,
}
############################ APPS ##################################### ############################ APPS #####################################
@@ -1193,131 +911,14 @@ INSTALLED_APPS = [
"openedx_learning.apps.authoring.sections", "openedx_learning.apps.authoring.sections",
] ]
### Apps only installed in some instances
################# EDX MARKETING SITE ################################## add_optional_apps(OPTIONAL_APPS, INSTALLED_APPS)
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 = []
##### ACCOUNT LOCKOUT DEFAULT PARAMETERS ##### ##### ACCOUNT LOCKOUT DEFAULT PARAMETERS #####
MAX_FAILED_LOGIN_ATTEMPTS_ALLOWED = 6 MAX_FAILED_LOGIN_ATTEMPTS_ALLOWED = 6
MAX_FAILED_LOGIN_ATTEMPTS_LOCKOUT_PERIOD_SECS = 30 * 60 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 ### Size of chunks into which asset uploads will be divided
UPLOAD_CHUNK_SIZE_IN_MB = 10 UPLOAD_CHUNK_SIZE_IN_MB = 10
@@ -1413,27 +1014,11 @@ ELASTIC_FIELD_MAPPINGS = {
XBLOCK_FS_STORAGE_BUCKET = None XBLOCK_FS_STORAGE_BUCKET = None
XBLOCK_FS_STORAGE_PREFIX = None XBLOCK_FS_STORAGE_PREFIX = None
############################ Global Database Configuration #####################
DATABASE_ROUTERS = [
'openedx.core.lib.django_courseware_routers.StudentModuleHistoryExtendedRouter',
]
############################ OAUTH2 Provider ################################### ############################ OAUTH2 Provider ###################################
# 5 minute expiration time for JWT id tokens issued for external API requests. # 5 minute expiration time for JWT id tokens issued for external API requests.
OAUTH_ID_TOKEN_EXPIRATION = 5 * 60 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 ############## ############## DJANGO-USER-TASKS ##############
# How long until database records about the outcome of a task and its artifacts get deleted? # 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 #################################### ############################# Persistent Grades ####################################
# Queue to use for updating persistent grades
RECALCULATE_GRADES_ROUTING_KEY = DEFAULT_PRIORITY_QUEUE
# .. setting_name: DEFAULT_GRADE_DESIGNATIONS # .. setting_name: DEFAULT_GRADE_DESIGNATIONS
# .. setting_default: ['A', 'B', 'C', 'D'] # .. setting_default: ['A', 'B', 'C', 'D']
# .. setting_description: The default 'pass' grade cutoff designations to be used. The failure grade # .. 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_IMAGE_MAX_AGE = 31536000
########################## VIDEO TRANSCRIPTS STORAGE ############################
TRANSCRIPT_LANG_CACHE_TIMEOUT = 60 * 60 * 24
##### shoppingcart Payment ##### ##### shoppingcart Payment #####
PAYMENT_SUPPORT_EMAIL = 'billing@example.com' PAYMENT_SUPPORT_EMAIL = 'billing@example.com'
@@ -1582,19 +1160,7 @@ LEARNER_PORTAL_URL_ROOT = 'https://learner-portal-localhost:18000'
############################ JWT ################################# ############################ JWT #################################
REGISTRATION_EXTRA_FIELDS = { REGISTRATION_EXTRA_FIELDS['marketing_emails_opt_in'] = 'hidden'
'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',
}
EDXAPP_PARSE_KEYS = {} EDXAPP_PARSE_KEYS = {}
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): def _should_send_xblock_events(settings):
return settings.ENABLE_SEND_XBLOCK_LIFECYCLE_EVENTS_OVER_BUS return settings.ENABLE_SEND_XBLOCK_LIFECYCLE_EVENTS_OVER_BUS
# .. setting_name: EVENT_BUS_PRODUCER_CONFIG EVENT_BUS_PRODUCER_CONFIG.update({
# .. 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.content_authoring.course.catalog_info.changed.v1': { 'org.openedx.content_authoring.course.catalog_info.changed.v1': {
'course-catalog-info-changed': 'course-catalog-info-changed':
{'event_key_field': 'catalog_info.course_key', {'event_key_field': 'catalog_info.course_key',
@@ -1714,29 +1269,7 @@ EVENT_BUS_PRODUCER_CONFIG = {
'course-authoring-xblock-lifecycle': 'course-authoring-xblock-lifecycle':
{'event_key_field': 'xblock_info.usage_key', 'enabled': Derived(_should_send_xblock_events)}, {'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 ###################### ################### Authoring API ######################

View File

@@ -134,8 +134,6 @@ if STATIC_URL_BASE:
if STATIC_ROOT_BASE: if STATIC_ROOT_BASE:
STATIC_ROOT = path(STATIC_ROOT_BASE) / 'studio' 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) DATA_DIR = path(DATA_DIR)
@@ -263,7 +261,7 @@ if _YAML_CELERY_QUEUES:
# Then add alternate environment queues # Then add alternate environment queues
_YAML_ALTERNATE_WORKER_QUEUES = _YAML_TOKENS.get('ALTERNATE_WORKER_QUEUES', '').split() _YAML_ALTERNATE_WORKER_QUEUES = _YAML_TOKENS.get('ALTERNATE_WORKER_QUEUES', '').split()
ALTERNATE_QUEUES = [ ALTERNATE_QUEUES = [
DEFAULT_PRIORITY_QUEUE.replace(QUEUE_VARIANT, alternate + '.') DEFAULT_PRIORITY_QUEUE.replace(SERVICE_VARIANT, alternate)
for alternate in _YAML_ALTERNATE_WORKER_QUEUES for alternate in _YAML_ALTERNATE_WORKER_QUEUES
] ]

View File

@@ -14,6 +14,7 @@ sessions. Assumes structure:
import os import os
import tempfile
from django.utils.translation import gettext_lazy from django.utils.translation import gettext_lazy
from edx_django_utils.plugins import add_plugins 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" 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' WEBPACK_LOADER['DEFAULT']['LOADER_CLASS'] = 'webpack_loader.loader.FakeWebpackLoader'
GITHUB_REPO_ROOT = TEST_ROOT / "data" GITHUB_REPO_ROOT = TEST_ROOT / "data"

View File

@@ -40,7 +40,6 @@ Conventions
# and throws spurious errors. Therefore, we disable invalid-name checking. # and throws spurious errors. Therefore, we disable invalid-name checking.
# pylint: disable=invalid-name # pylint: disable=invalid-name
import importlib.util
import os import os
from corsheaders.defaults import default_headers as corsheaders_default_headers 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.core.lib.derived import Derived
from openedx.envs.common import * # pylint: disable=wildcard-import 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 from openedx.core.lib.features_setting_proxy import FeaturesProxy
# A proxy for feature flags stored in the settings namespace # 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 RETRY_CALENDAR_SYNC_EMAIL_MAX_ATTEMPTS = 5
############################# SET PATH INFORMATION ############################# ############################# SET PATH INFORMATION #############################
PROJECT_ROOT = path(__file__).abspath().dirname().dirname() # /edx-platform/lms 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" 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 # Where to look for a status message
STATUS_MESSAGE_PATH = ENV_ROOT / "status_message.json" STATUS_MESSAGE_PATH = ENV_ROOT / "status_message.json"
############################ Global Database Configuration ##################### ############################ Global Database Configuration #####################
DATABASE_ROUTERS = [ DATABASE_ROUTERS.append('edx_django_utils.db.read_replica.ReadReplicaRouter')
'openedx.core.lib.django_courseware_routers.StudentModuleHistoryExtendedRouter',
'edx_django_utils.db.read_replica.ReadReplicaRouter',
]
################################## DJANGO OAUTH TOOLKIT ####################################### ################################## DJANGO OAUTH TOOLKIT #######################################
@@ -812,27 +798,11 @@ TPA_PROVIDER_SUSTAINED_THROTTLE = '50/hr'
TPA_AUTOMATIC_LOGOUT_ENABLED = False TPA_AUTOMATIC_LOGOUT_ENABLED = False
################################## TEMPLATE CONFIGURATION ##################################### ################################## 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 = [ MAKO_TEMPLATE_DIRS_BASE = lms_mako_template_dirs_base
'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',
CONTEXT_PROCESSORS.remove('django.contrib.messages.context_processors.messages')
CONTEXT_PROCESSORS[5:5] = [
# Added for django-wiki # Added for django-wiki
'django.template.context_processors.media', 'django.template.context_processors.media',
'django.template.context_processors.tz', 'django.template.context_processors.tz',
@@ -844,11 +814,8 @@ CONTEXT_PROCESSORS = [
# Timezone processor (sends language and time_zone preference) # Timezone processor (sends language and time_zone preference)
'lms.djangoapps.courseware.context_processor.user_timezone_locale_prefs', 'lms.djangoapps.courseware.context_processor.user_timezone_locale_prefs',
]
# Online contextual help CONTEXT_PROCESSORS += [
'help_tokens.context_processor',
'openedx.core.djangoapps.site_configuration.context_processors.configuration_context',
# Mobile App processor (Detects if request is from the mobile app) # Mobile App processor (Detects if request is from the mobile app)
'lms.djangoapps.mobile_api.context_processor.is_from_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', 'openedx.features.survey_report.context_processors.admin_extra_context',
] ]
# Django templating DEFAULT_TEMPLATE_ENGINE_DIRS = Derived(lambda settings: settings.TEMPLATES[0]['DIRS'][:])
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'][:]
############################################################################################### ###############################################################################################
AUTHENTICATION_BACKENDS = [
'rules.permissions.ObjectPermissionBackend',
'django.contrib.auth.backends.AllowAllUsersModelBackend',
'bridgekeeper.backends.RulePermissionBackend',
]
STUDENT_FILEUPLOAD_MAX_SIZE = 4 * 1000 * 1000 # 4 MB STUDENT_FILEUPLOAD_MAX_SIZE = 4 * 1000 * 1000 # 4 MB
MAX_FILEUPLOADS_PER_INPUT = 20 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) 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. # IP addresses that are allowed to reload the course, etc.
@@ -969,66 +876,9 @@ LMS_MIGRATION_ALLOWED_IPS = []
############################## EVENT TRACKING ################################# ############################## EVENT TRACKING #################################
LMS_SEGMENT_KEY = None LMS_SEGMENT_KEY = None
# FIXME: Should we be doing this truncation?
TRACK_MAX_EVENT = 50000
DEBUG_TRACK_LOG = False DEBUG_TRACK_LOG = False
TRACKING_BACKENDS = { TRACKING_IGNORE_URL_PATTERNS += [r'^/segmentio/event', r'^/performance']
'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_SEGMENTIO_WEBHOOK_SECRET = None TRACKING_SEGMENTIO_WEBHOOK_SECRET = None
TRACKING_SEGMENTIO_ALLOWED_TYPES = ['track'] TRACKING_SEGMENTIO_ALLOWED_TYPES = ['track']
@@ -1039,7 +889,6 @@ TRACKING_SEGMENTIO_SOURCE_MAP = {
} }
######################## GOOGLE ANALYTICS ########################### ######################## GOOGLE ANALYTICS ###########################
GOOGLE_ANALYTICS_ACCOUNT = None
GOOGLE_SITE_VERIFICATION_ID = None GOOGLE_SITE_VERIFICATION_ID = None
GOOGLE_ANALYTICS_LINKEDIN = None GOOGLE_ANALYTICS_LINKEDIN = None
GOOGLE_ANALYTICS_TRACKING_ID = None GOOGLE_ANALYTICS_TRACKING_ID = None
@@ -1054,99 +903,13 @@ HOTJAR_SITE_ID = 00000
######################## subdomain specific settings ########################### ######################## subdomain specific settings ###########################
COURSE_LISTINGS = {} 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 ########## ############# ModuleStore Configuration ##########
CONTENTSTORE['DOC_STORE_CONFIG']['password'] = 'password'
CONTENTSTORE['DOC_STORE_CONFIG']['read_preference'] = 'SECONDARY_PREFERRED'
MODULESTORE_BRANCH = 'published-only' 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 = {} HOSTNAME_MODULESTORE_DEFAULT_MAPPINGS = {}
MONGODB_LOG = {} MONGODB_LOG = {}
@@ -1200,9 +963,6 @@ CMS_BASE = 'studio.edx.org'
STUDIO_NAME = 'Studio' STUDIO_NAME = 'Studio'
STUDIO_SHORT_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 # Platform Email
EMAIL_FILE_PATH = Derived(lambda settings: path(settings.DATA_DIR) / "emails" / "lms") EMAIL_FILE_PATH = Derived(lambda settings: path(settings.DATA_DIR) / "emails" / "lms")
DEFAULT_FROM_EMAIL = 'registration@example.com' DEFAULT_FROM_EMAIL = 'registration@example.com'
@@ -1225,17 +985,7 @@ ACTIVATION_EMAIL_FROM_ADDRESS = ''
STATIC_URL = '/static/' STATIC_URL = '/static/'
STATIC_ROOT = os.environ.get('STATIC_ROOT_LMS', ENV_ROOT / "staticfiles") STATIC_ROOT = os.environ.get('STATIC_ROOT_LMS', ENV_ROOT / "staticfiles")
STATICFILES_DIRS = [ STATICFILES_DIRS.insert(2, NODE_MODULES_ROOT / "@edx")
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"
# Guidelines for translators # Guidelines for translators
TRANSLATORS_GUIDE = 'https://docs.openedx.org/en/latest/translators/index.html' TRANSLATORS_GUIDE = 'https://docs.openedx.org/en/latest/translators/index.html'
@@ -1494,27 +1244,7 @@ MIDDLEWARE = [
############################### PIPELINE ####################################### ############################### PIPELINE #######################################
PIPELINE = { PIPELINE['JS_COMPRESSOR'] = 'pipeline.compressors.uglifyjs.UglifyJSCompressor'
'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',
]
from openedx.core.lib.rooted_paths import rooted_glob # pylint: disable=wrong-import-position 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 ############################### ################################# 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. # The name of the require.js script used by your project, relative to REQUIRE_BASE_URL.
REQUIRE_JS = "common/js/vendor/require.js" REQUIRE_JS = "common/js/vendor/require.js"
@@ -1934,18 +1635,9 @@ REQUIRE_JS_PATH_OVERRIDES = {
'hls': 'common/js/vendor/hls.js' 'hls': 'common/js/vendor/hls.js'
} }
########################## DJANGO WEBPACK LOADER ############################## ############################ SERVICE_VARIANT ##################################
WEBPACK_LOADER = { SERVICE_VARIANT = 'lms'
'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')
}
}
################################# CELERY ###################################### ################################# CELERY ######################################
@@ -1961,28 +1653,10 @@ CELERY_IMPORTS = [
# These packages are added in addition to those added by CELERY_IMPORTS. # These packages are added in addition to those added by CELERY_IMPORTS.
CELERY_EXTRA_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 # Name the exchange and queues w.r.t the SERVICE_VARIANT
QUEUE_VARIANT = CONFIG_PREFIX.lower() HIGH_PRIORITY_QUEUE = f'edx.{SERVICE_VARIANT}.core.high'
DEFAULT_PRIORITY_QUEUE = f'edx.{SERVICE_VARIANT}.core.default'
CELERY_DEFAULT_EXCHANGE = f'edx.{QUEUE_VARIANT}core' HIGH_MEM_QUEUE = f'edx.{SERVICE_VARIANT}.core.high_mem'
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
CELERY_QUEUES = { CELERY_QUEUES = {
HIGH_PRIORITY_QUEUE: {}, HIGH_PRIORITY_QUEUE: {},
@@ -1998,10 +1672,6 @@ CELERYD_HIJACK_ROOT_LOGGER = False
BROKER_USE_SSL = False BROKER_USE_SSL = False
############################## HEARTBEAT ######################################
HEARTBEAT_CELERY_ROUTING_KEY = HIGH_PRIORITY_QUEUE
################################ Bulk Email ################################### ################################ Bulk Email ###################################
# Initial delay used for retrying tasks. Additional retries use # Initial delay used for retrying tasks. Additional retries use
@@ -2386,6 +2056,24 @@ INSTALLED_APPS = [
"openedx_learning.apps.authoring.sections", "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 ######################## ######################### Django Rest Framework ########################
SWAGGER_SETTINGS = { SWAGGER_SETTINGS = {
@@ -2395,7 +2083,7 @@ SWAGGER_SETTINGS = {
######################### MARKETING SITE ############################### ######################### MARKETING SITE ###############################
MKTG_URL_LINK_MAP = { MKTG_URL_LINK_MAP.update({
'ABOUT': 'about', 'ABOUT': 'about',
'CONTACT': 'contact', 'CONTACT': 'contact',
'FAQ': 'help', 'FAQ': 'help',
@@ -2412,15 +2100,11 @@ MKTG_URL_LINK_MAP = {
# Verified Certificates # Verified Certificates
'WHAT_IS_VERIFIED_CERT': 'verified-certificate', 'WHAT_IS_VERIFIED_CERT': 'verified-certificate',
} })
STATIC_TEMPLATE_VIEW_DEFAULT_FILE_EXTENSION = 'html' STATIC_TEMPLATE_VIEW_DEFAULT_FILE_EXTENSION = 'html'
SEND_ACTIVATION_EMAIL_URL = '' 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_name: SECURITY_PAGE_URL
# .. setting_default: None # .. setting_default: None
@@ -2434,19 +2118,13 @@ ENTITLEMENT_EXPIRED_ALERT_PERIOD = 90
############################# SOCIAL MEDIA SHARING ############################# ############################# SOCIAL MEDIA SHARING #############################
# Social Media Sharing on Student Dashboard # Social Media Sharing on Student Dashboard
SOCIAL_SHARING_SETTINGS = { SOCIAL_SHARING_SETTINGS.update({
# Note: Ensure 'CUSTOM_COURSE_URLS' has a matching value in cms/envs/common.py
'CUSTOM_COURSE_URLS': False,
'DASHBOARD_FACEBOOK': False,
'FACEBOOK_BRAND': None, 'FACEBOOK_BRAND': None,
'CERTIFICATE_FACEBOOK': False,
'CERTIFICATE_FACEBOOK_TEXT': None, 'CERTIFICATE_FACEBOOK_TEXT': None,
'CERTIFICATE_TWITTER': False, 'TWITTER_BRAND': None,
'CERTIFICATE_TWITTER_TEXT': None, 'CERTIFICATE_TWITTER_TEXT': None,
'DASHBOARD_TWITTER': False,
'DASHBOARD_TWITTER_TEXT': None, 'DASHBOARD_TWITTER_TEXT': None,
'TWITTER_BRAND': None })
}
################# Social Media Footer Links ####################### ################# Social Media Footer Links #######################
# The names list controls the order of social media # The names list controls the order of social media
@@ -2575,30 +2253,6 @@ XDOMAIN_PROXY_CACHE_TIMEOUT = 60 * 15
###################### Registration ################################## ###################### 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 = [ REGISTRATION_FIELD_ORDER = [
"name", "name",
"first_name", "first_name",
@@ -2634,8 +2288,6 @@ CERT_NAME_LONG = "Certificate of Achievement"
# the ones that contain information other than grades. # the ones that contain information other than grades.
GRADES_DOWNLOAD_ROUTING_KEY = Derived(lambda settings: settings.HIGH_MEM_QUEUE) GRADES_DOWNLOAD_ROUTING_KEY = Derived(lambda settings: settings.HIGH_MEM_QUEUE)
RECALCULATE_GRADES_ROUTING_KEY = 'edx.lms.core.default'
############################ ORA 2 ############################################ ############################ ORA 2 ############################################
ORA_WORKFLOW_UPDATE_ROUTING_KEY = "edx.lms.core.ora_workflow_update" 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 ####### ##### LMS DEADLINE DISPLAY TIME_ZONE #######
TIME_ZONE_DISPLAYED_FOR_DEADLINES = 'UTC' 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
ANALYTICS_API_KEY = "" ANALYTICS_API_KEY = ""
ANALYTICS_API_URL = "http://localhost:18100" ANALYTICS_API_URL = "http://localhost:18100"
@@ -2966,13 +2555,8 @@ NOTIFICATION_EMAIL_EDX_LOGO = "templates/credit_notifications/edx-logo-header.pn
################################ Settings for JWTs ################################ ################################ Settings for JWTs ################################
EDX_DRF_EXTENSIONS = { # Allows JWT authentication to find the LMS user id for verification
# Set this value to an empty dict in order to prevent automatically updating EDX_DRF_EXTENSIONS['VERIFY_LMS_USER_ID_PROPERTY_NAME'] = 'id'
# 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',
}
################################ Settings for rss_proxy ################################ ################################ Settings for rss_proxy ################################
@@ -3030,10 +2614,6 @@ CREDENTIALS_COURSE_COMPLETION_STATE = 'awarded'
# Queue to use for award program certificates # Queue to use for award program certificates
PROGRAM_CERTIFICATES_ROUTING_KEY = Derived(lambda settings: settings.DEFAULT_PRIORITY_QUEUE) 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 ###################### ############## OPEN EDX ENTERPRISE SERVICE CONFIGURATION ######################
# The Open edX Enterprise service is currently hosted via the LMS container/process. # 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. # 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 DATA_CONSENT_SHARE_CACHE_TIMEOUT = 8 * 60 * 60 # 8 hours
TRANSCRIPT_LANG_CACHE_TIMEOUT = 60 * 60 * 24 # 24 hours
############## Settings for the Discovery App ###################### ############## Settings for the Discovery App ######################
COURSES_API_CACHE_TIMEOUT = 3600 # Value is in seconds 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 from openedx.core.djangoapps.ace_common.settings import common as ace_common_settings
ACE_ROUTING_KEY = ace_common_settings.ACE_ROUTING_KEY ACE_ROUTING_KEY = ace_common_settings.ACE_ROUTING_KEY
############### Settings swift #####################################
SWIFT_USE_TEMP_URLS = None
############### Settings for facebook ############################## ############### Settings for facebook ##############################
FACEBOOK_APP_ID = None FACEBOOK_APP_ID = None
FACEBOOK_APP_SECRET = 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)) INSTALLED_APPS.extend(get_plugin_apps(ProjectType.LMS))
add_plugins(__name__, ProjectType.LMS, SettingsType.COMMON) 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 PROCTORED_EXAM_VIEWABLE_PAST_DUE = False
######################### rate limit for yt_video_metadata api ############## ######################### rate limit for yt_video_metadata api ##############
@@ -3499,23 +3066,12 @@ GOAL_REMINDER_PROFILE_URL = ""
DISABLED_ORGS_FOR_PROGRAM_NUDGE = [] DISABLED_ORGS_FOR_PROGRAM_NUDGE = []
#### Event bus producing ####
def _should_send_certificate_events(settings): def _should_send_certificate_events(settings):
return settings.SEND_LEARNING_CERTIFICATE_LIFECYCLE_EVENTS_TO_BUS return settings.SEND_LEARNING_CERTIFICATE_LIFECYCLE_EVENTS_TO_BUS
EVENT_BUS_PRODUCER_CONFIG.update({
#### 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 = {
'org.openedx.learning.certificate.created.v1': { 'org.openedx.learning.certificate.created.v1': {
'learning-certificate-lifecycle': 'learning-certificate-lifecycle':
{'event_key_field': 'certificate.course.course_key', 'enabled': Derived(_should_send_certificate_events)}, {'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': 'learner-credit-course-enrollment-lifecycle':
{'event_key_field': 'learner_credit_course_enrollment.uuid', 'enabled': False}, {'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": { "org.openedx.learning.external_grader.score.submitted.v1": {
"learning-external-grader-score-lifecycle": { "learning-external-grader-score-lifecycle": {
"event_key_field": "score.submission_id", "event_key_field": "score.submission_id",
"enabled": False "enabled": False
}, },
}, },
} })
#### Survey Report #### #### Survey Report ####
# .. toggle_name: SURVEY_REPORT_ENABLE # .. toggle_name: SURVEY_REPORT_ENABLE

View File

@@ -122,9 +122,6 @@ CELERYD_PREFETCH_MULTIPLIER = 1
# collected # collected
if STATIC_ROOT_BASE: if STATIC_ROOT_BASE:
STATIC_ROOT = path(STATIC_ROOT_BASE) STATIC_ROOT = path(STATIC_ROOT_BASE)
WEBPACK_LOADER['DEFAULT']['STATS_FILE'] = STATIC_ROOT / "webpack-stats.json"
WEBPACK_LOADER['WORKERS']['STATS_FILE'] = STATIC_ROOT / "webpack-worker-stats.json"
# STATIC_URL_BASE specifies the base url to use for static files # STATIC_URL_BASE specifies the base url to use for static files
if STATIC_URL_BASE: if STATIC_URL_BASE:
@@ -165,7 +162,7 @@ if _YAML_CELERY_QUEUES:
# Then add alternate environment queues # Then add alternate environment queues
_YAML_ALTERNATE_WORKER_QUEUES = _YAML_TOKENS.get('ALTERNATE_WORKER_QUEUES', '').split() _YAML_ALTERNATE_WORKER_QUEUES = _YAML_TOKENS.get('ALTERNATE_WORKER_QUEUES', '').split()
ALTERNATE_QUEUES = [ ALTERNATE_QUEUES = [
DEFAULT_PRIORITY_QUEUE.replace(QUEUE_VARIANT, alternate + '.') DEFAULT_PRIORITY_QUEUE.replace(SERVICE_VARIANT, alternate)
for alternate in _YAML_ALTERNATE_WORKER_QUEUES for alternate in _YAML_ALTERNATE_WORKER_QUEUES
] ]

View File

@@ -53,7 +53,8 @@ ENABLE_BULK_USER_RETIREMENT = True
COMMON_TEST_DATA_ROOT = COMMON_ROOT / "test" / "data" 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' WEBPACK_LOADER['DEFAULT']['LOADER_CLASS'] = 'webpack_loader.loader.FakeWebpackLoader'
STATUS_MESSAGE_PATH = TEST_ROOT / "status_message.json" STATUS_MESSAGE_PATH = TEST_ROOT / "status_message.json"

View File

@@ -12,7 +12,6 @@ defuse_xml_libs()
import os # lint-amnesty, pylint: disable=wrong-import-order, wrong-import-position import os # lint-amnesty, pylint: disable=wrong-import-order, wrong-import-position
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "lms.envs.aws") os.environ.setdefault("DJANGO_SETTINGS_MODULE", "lms.envs.aws")
os.environ.setdefault("SERVICE_VARIANT", "lms")
# This application object is used by the development server # This application object is used by the development server
# as well as any WSGI server configured to use this file. # as well as any WSGI server configured to use this file.

View File

@@ -44,7 +44,6 @@ def parse_args():
help_string=lms.format_help(), help_string=lms.format_help(),
settings_base='lms/envs', settings_base='lms/envs',
default_settings='lms.envs.devstack', default_settings='lms.envs.devstack',
service_variant='lms',
) )
cms = subparsers.add_parser( cms = subparsers.add_parser(
@@ -62,16 +61,15 @@ def parse_args():
help_string=cms.format_help(), help_string=cms.format_help(),
settings_base='cms/envs', settings_base='cms/envs',
default_settings='cms.envs.devstack', 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:")
print(edx_args.help_string) print(known_args.help_string)
return edx_args, django_args return known_args, remaining_args
if __name__ == "__main__": 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["DJANGO_SETTINGS_MODULE"] = edx_args_base + os.environ["EDX_PLATFORM_SETTINGS"]
os.environ.setdefault("DJANGO_SETTINGS_MODULE", edx_args.default_settings) os.environ.setdefault("DJANGO_SETTINGS_MODULE", edx_args.default_settings)
os.environ.setdefault("SERVICE_VARIANT", edx_args.service_variant)
if edx_args.help: if edx_args.help:
print("Django:") print("Django:")

View File

@@ -15,12 +15,12 @@ behavior to trigger the necessary data updates.
import copy import copy
import logging import logging
import os
import sys import sys
import textwrap import textwrap
import time import time
from django.core.management.base import BaseCommand, CommandError from django.core.management.base import BaseCommand, CommandError
from django.conf import settings
from opaque_keys import InvalidKeyError from opaque_keys import InvalidKeyError
from opaque_keys.edx.keys import CourseKey from opaque_keys.edx.keys import CourseKey
from openedx.core.djangoapps.content.course_overviews.models import SimulateCoursePublishConfig from openedx.core.djangoapps.content.course_overviews.models import SimulateCoursePublishConfig
@@ -189,14 +189,14 @@ class Command(BaseCommand):
options['delay'] options['delay']
) )
if os.environ.get('SERVICE_VARIANT', 'cms').startswith('lms'): if settings.SERVICE_VARIANT == 'lms':
if options['force_lms']: if options['force_lms']:
log.info("Forcing simulate_publish to run in LMS process.") log.info("Forcing simulate_publish to run in LMS process.")
else: else:
log.fatal( # lint-amnesty, pylint: disable=logging-not-lazy log.fatal( # lint-amnesty, pylint: disable=logging-not-lazy
"simulate_publish should be run as a CMS (Studio) " + "simulate_publish should be run as a CMS (Studio) " +
"command, not %s (override with --force-lms).", "command, not %s (override with --force-lms).",
os.environ.get('SERVICE_VARIANT') settings.SERVICE_VARIANT
) )
sys.exit(1) sys.exit(1)

View File

@@ -95,7 +95,7 @@ class TestSimulatePublish(SharedModuleStoreTestCase):
receivers=default_receivers, receivers=default_receivers,
courses=None, courses=None,
delay=0, delay=0,
force_lms=False, force_lms=True,
skip_ccx=False, skip_ccx=False,
args_from_database=False args_from_database=False
) )
@@ -155,12 +155,12 @@ class TestSimulatePublish(SharedModuleStoreTestCase):
# Add a config # Add a config
config = SimulateCoursePublishConfig.current() config = SimulateCoursePublishConfig.current()
config.arguments = '--delay 20 --dry-run' config.arguments = '--delay 20 --dry-run --force-lms '
config.enabled = True config.enabled = True
config.save() config.save()
with LogCapture(LOGGER_NAME) as log: with LogCapture(LOGGER_NAME) as log:
call_command('simulate_publish') call_command('simulate_publish', '--force-lms')
log.check_present( log.check_present(
( (

View File

@@ -26,6 +26,7 @@ def center_with_hashes(text: str, width: int = 76):
``` ```
""" """
import os import os
import importlib.util
from path import Path as path from path import Path as path
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
@@ -48,6 +49,11 @@ from openedx.core.constants import ( # pylint: disable=unused-import
USAGE_ID_PATTERN, 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 ################ ################ Shared Functions for Derived Configuration ################
@@ -91,11 +97,22 @@ def _make_locale_paths(settings):
locale_paths += (path(locale_path), ) locale_paths += (path(locale_path), )
return locale_paths 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 ############################# ############################# Django Built-Ins #############################
DEBUG = False DEBUG = False
USE_TZ = True USE_TZ = True
TIME_ZONE = 'UTC'
# User-uploaded content # User-uploaded content
MEDIA_ROOT = '/edx/var/edxapp/media/' MEDIA_ROOT = '/edx/var/edxapp/media/'
@@ -117,18 +134,57 @@ SESSION_ENGINE = 'django.contrib.sessions.backends.cache'
SESSION_SAVE_EVERY_REQUEST = False SESSION_SAVE_EVERY_REQUEST = False
SESSION_SERIALIZER = 'openedx.core.lib.session_serializers.PickleSerializer' 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 = [] ADMINS = []
MANAGERS = ADMINS MANAGERS = ADMINS
DEFAULT_FROM_EMAIL = 'registration@example.com' DEFAULT_FROM_EMAIL = 'registration@example.com'
SERVER_EMAIL = 'devops@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. # See https://github.com/openedx/edx-django-sites-extensions for more info.
# Default site to use if site matching request headers does not exist. # Default site to use if site matching request headers does not exist.
SITE_ID = 1 SITE_ID = 1
# Clickjacking protection can be disbaled by setting this to 'ALLOW' STATICFILES_DIRS = [
X_FRAME_OPTIONS = 'DENY' 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 = [ AUTH_PASSWORD_VALIDATORS = [
{ {
@@ -160,6 +216,8 @@ STORAGES = {
# Messages # Messages
MESSAGE_STORAGE = 'django.contrib.messages.storage.session.SessionStorage' MESSAGE_STORAGE = 'django.contrib.messages.storage.session.SessionStorage'
USE_I18N = True
# these languages display right to left # these languages display right to left
LANGUAGES_BIDI = ("he", "ar", "fa", "ur", "fa-ir", "rtl") 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) 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 # Sourced from http://www.localeplanet.com/icu/ and wikipedia
LANGUAGES = [ LANGUAGES = [
('en', 'English'), ('en', 'English'),
@@ -251,6 +311,231 @@ LANGUAGES = [
('zh-tw', '中文 (台灣)'), # Chinese (Taiwan) ('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 ############################### ############################## Site Settings ###############################
HTTPS = 'on' HTTPS = 'on'
@@ -460,6 +745,62 @@ ALL_LANGUAGES = [
LANGUAGE_DICT = dict(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 ########################### ########################## Django Rest Framework ###########################
REST_FRAMEWORK = { REST_FRAMEWORK = {
@@ -537,14 +878,17 @@ CELERY_TRACK_STARTED = True
CELERY_SEND_EVENTS = True CELERY_SEND_EVENTS = True
CELERY_SEND_TASK_SENT_EVENT = True CELERY_SEND_TASK_SENT_EVENT = True
# Exchange configuration
CELERY_DEFAULT_EXCHANGE = 'edx.core'
CELERY_DEFAULT_EXCHANGE_TYPE = 'direct'
# Queues configuration # Queues configuration
CELERY_QUEUE_HA_POLICY = 'all' CELERY_QUEUE_HA_POLICY = 'all'
CELERY_CREATE_MISSING_QUEUES = True 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 # Checks run in normal mode by the heartbeat djangoapp
HEARTBEAT_CHECKS = [ HEARTBEAT_CHECKS = [
'openedx.core.djangoapps.heartbeat.default_checks.check_modulestore', 'openedx.core.djangoapps.heartbeat.default_checks.check_modulestore',
@@ -558,6 +902,8 @@ HEARTBEAT_EXTENDED_CHECKS = (
HEARTBEAT_CELERY_TIMEOUT = 5 HEARTBEAT_CELERY_TIMEOUT = 5
HEARTBEAT_CELERY_ROUTING_KEY = Derived(lambda settings: settings.HIGH_PRIORITY_QUEUE)
############################ RedirectMiddleware ############################ ############################ RedirectMiddleware ############################
# Setting this to None causes Redirect data to never expire # Setting this to None causes Redirect data to never expire
@@ -614,6 +960,12 @@ JWT_AUTH = {
'JWT_AUTH_HEADER_PREFIX': 'JWT', '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 ################################# ################################# Features #################################
# .. setting_name: PLATFORM_NAME # .. 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 ###################################
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 # If setting a cross-domain cookie, it's really important to choose
# a name for the cookie that is DIFFERENT than the cookies used # a name for the cookie that is DIFFERENT than the cookies used
# by each subdomain. For example, suppose the applications # 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. # the client won't be able to read the cookie.
CROSS_DOMAIN_CSRF_COOKIE_DOMAIN = '' CROSS_DOMAIN_CSRF_COOKIE_DOMAIN = ''
CSRF_TRUSTED_ORIGINS = []
ENABLE_CROSS_DOMAIN_CSRF_COOKIE = False ENABLE_CROSS_DOMAIN_CSRF_COOKIE = False
########################## Cross-domain Requests ########################### ########################## Cross-domain Requests ###########################
@@ -1212,6 +1463,21 @@ SOCIAL_MEDIA_LOGO_URLS = {
'facebook': 'http://email-media.s3.amazonaws.com/edX/2021/social_1_fb.png', '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 ############################# ############################# Block Structures #############################
# .. setting_name: BLOCK_STRUCTURES_SETTINGS # .. setting_name: BLOCK_STRUCTURES_SETTINGS
@@ -1316,6 +1582,16 @@ VIDEO_TRANSCRIPTS_SETTINGS = dict(
VIDEO_TRANSCRIPTS_MAX_AGE = 31536000 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 ############################# ############################ Parental Controls #############################
# .. setting_name: PARENTAL_CONSENT_AGE_LIMIT # .. 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 # .. toggle_creation_date: 2021-06-10
SHOW_ACCOUNT_ACTIVATION_CTA = False 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 ########################## ######################### Course Enrollment Modes ##########################
# The min_price key refers to the minimum price allowed for an instance # 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$)|(^.*~$)" ASSET_IGNORE_REGEX = r"(^\._.*$)|(^\.DS_Store$)|(^.*~$)"
DATABASES = { # This Django setting was removed in Django 4.0, but it is still being referenced
# edxapp's edxapp-migrate scripts and the edxapp_migrate play # in the code. It would be worth investigating if we still need this and, if we do,
# will ensure that any DB not named read_replica will be migrated # leave a comment explaining why here. See https://github.com/openedx/edx-platform/issues/37744.
# for both the lms and cms. 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': { 'default': {
'ATOMIC_REQUESTS': True, 'ENGINE': 'xmodule.modulestore.mixed.MixedModuleStore',
'CONN_MAX_AGE': 0, 'OPTIONS': {
'ENGINE': 'django.db.backends.mysql', 'mappings': {},
'HOST': '127.0.0.1', 'stores': [
'NAME': 'edxapp', {
'OPTIONS': {}, 'NAME': 'split',
'PASSWORD': 'password', 'ENGINE': 'xmodule.modulestore.split_mongo.split_draft.DraftVersioningModuleStore',
'PORT': '3306', 'DOC_STORE_CONFIG': DOC_STORE_CONFIG,
'USER': 'edxapp001' 'OPTIONS': {
}, 'default_class': 'xmodule.hidden_block.HiddenBlock',
'read_replica': { 'fs_root': Derived(lambda settings: settings.DATA_DIR),
'CONN_MAX_AGE': 0, 'render_template': 'common.djangoapps.edxmako.shortcuts.render_to_string',
'ENGINE': 'django.db.backends.mysql', }
'HOST': '127.0.0.1', },
'NAME': 'edxapp', {
'OPTIONS': {}, 'NAME': 'draft',
'PASSWORD': 'password', 'ENGINE': 'xmodule.modulestore.mongo.DraftMongoModuleStore',
'PORT': '3306', 'DOC_STORE_CONFIG': DOC_STORE_CONFIG,
'USER': 'edxapp001' 'OPTIONS': {
}, 'default_class': 'xmodule.hidden_block.HiddenBlock',
'student_module_history': { 'fs_root': Derived(lambda settings: settings.DATA_DIR),
'CONN_MAX_AGE': 0, 'render_template': 'common.djangoapps.edxmako.shortcuts.render_to_string',
'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' # Modulestore-level field override providers. These field override providers don't
DEFAULT_HASHING_ALGORITHM = 'sha256' # require student context.
MODULESTORE_FIELD_OVERRIDE_PROVIDERS = ()
############################# Micro-frontends ############################## ############################# 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. # .. 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' 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 ######################## ######################## Built-in Blocks Extraction ########################
# The following Django settings flags have been introduced temporarily to facilitate # The following Django settings flags have been introduced temporarily to facilitate
@@ -1748,9 +2099,15 @@ EDXMKTG_USER_INFO_COOKIE_VERSION = 1
MKTG_URLS = {} MKTG_URLS = {}
MKTG_URL_OVERRIDES = {} MKTG_URL_OVERRIDES = {}
MKTG_URL_LINK_MAP = {}
SUPPORT_SITE_LINK = '' 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 ################################## ################################# ChatGPT ##################################
CHAT_COMPLETION_API = '' CHAT_COMPLETION_API = ''
@@ -1791,6 +2148,31 @@ ZENDESK_GROUP_ID_MAPPING = {}
############################## Python sandbox ############################## ############################## 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 # 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. # 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 # Locale/Internationalization
CELERY_TIMEZONE = 'UTC' CELERY_TIMEZONE = 'UTC'
TIME_ZONE = 'UTC'
LANGUAGE_CODE = 'en' # http://www.i18nguy.com/unicode/language-identifiers.html
# Languages supported for custom course certificate templates # Languages supported for custom course certificate templates
CERTIFICATE_TEMPLATE_LANGUAGES = { CERTIFICATE_TEMPLATE_LANGUAGES = {
@@ -1840,26 +2220,58 @@ CERTIFICATE_TEMPLATE_LANGUAGES = {
'es': 'Español', 'es': 'Español',
} }
USE_I18N = True
USE_L10N = True
STATICI18N_FILENAME_FUNCTION = 'statici18n.utils.legacy_filename' STATICI18N_FILENAME_FUNCTION = 'statici18n.utils.legacy_filename'
STATICI18N_OUTPUT_DIR = "js/i18n" STATICI18N_OUTPUT_DIR = "js/i18n"
STATICI18N_ROOT = Derived(lambda settings: settings.PROJECT_ROOT / "static")
################################# Pipeline ################################# ################################# 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 = {} STATICFILES_STORAGE_KWARGS = {}
# List of finder classes that know how to find static files in various locations. STATICFILES_IGNORE_PATTERNS = [
# Note: the pipeline finder is included to be able to discover optimized files "*.py",
STATICFILES_FINDERS = [ "*.pyc",
'openedx.core.djangoapps.theming.finders.ThemeFilesFinder',
'django.contrib.staticfiles.finders.FileSystemFinder', # It would be nice if we could do, for example, "**/*.scss",
'django.contrib.staticfiles.finders.AppDirectoriesFinder', # but these strings get passed down to the `fnmatch` module,
'openedx.core.lib.xblock_pipeline.finder.XBlockPipelineFinder', # which doesn't support that. :(
'pipeline.finders.PipelineFinder', # 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 ############################## ############################## django-require ##############################
# The baseUrl to pass to the r.js optimizer, relative to STATIC_ROOT. # 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. # Whether to run django-require in debug mode.
REQUIRE_DEBUG = False 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 ########################### ########################### Student Verification ###########################
VERIFY_STUDENT = { VERIFY_STUDENT = {
@@ -1992,7 +2410,6 @@ DEFAULT_SITE_THEME = None
# .. toggle_creation_date: 2016-06-30 # .. toggle_creation_date: 2016-06-30
ENABLE_COMPREHENSIVE_THEMING = False ENABLE_COMPREHENSIVE_THEMING = False
################################ Ecommerce ################################# ################################ Ecommerce #################################
ECOMMERCE_PUBLIC_URL_ROOT = 'http://localhost:8002' 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_LANGUAGE_CODE = Derived(lambda settings: settings.LANGUAGE_CODE)
HELP_TOKENS_VERSION = Derived(lambda settings: doc_version()) 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 = { HELP_TOKENS_BOOKS = {
'learner': 'https://docs.openedx.org/en/latest/learners', 'learner': 'https://docs.openedx.org/en/latest/learners',
'course_author': 'https://docs.openedx.org/en/latest/educators', '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): def should_send_learning_badge_events(settings):
return settings.BADGES_ENABLED 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 ############################### ############################## Miscellaneous ###############################
@@ -2299,6 +2799,9 @@ VIDEO_CDN_URL = {
SOFTWARE_SECURE_VERIFICATION_ROUTING_KEY = Derived(lambda settings: settings.HIGH_PRIORITY_QUEUE) 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 # Queue to use for updating grades due to grading policy change
POLICY_CHANGE_GRADES_ROUTING_KEY = Derived(lambda settings: settings.DEFAULT_PRIORITY_QUEUE) 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 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 # License for serving content in China
ICP_LICENSE = None ICP_LICENSE = None
ICP_LICENSE_INFO = {} ICP_LICENSE_INFO = {}
@@ -2443,3 +2941,15 @@ FEEDBACK_SUBMISSION_EMAIL = ''
COURSE_LIVE_GLOBAL_CREDENTIALS = {} COURSE_LIVE_GLOBAL_CREDENTIALS = {}
BEAMER_PRODUCT_ID = "" 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

View File

@@ -90,7 +90,6 @@ PARENTAL_CONSENT_AGE_LIMIT = 13
# Test theme # Test theme
TEST_THEME = Derived(lambda settings: settings.COMMON_ROOT / "test" / "test-theme") TEST_THEME = Derived(lambda settings: settings.COMMON_ROOT / "test" / "test-theme")
ENABLE_COMPREHENSIVE_THEMING = True 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 for tests
ENABLE_EDXNOTES = True ENABLE_EDXNOTES = True

View File

@@ -85,11 +85,13 @@ ignore_imports =
############################################################################ ############################################################################
# cms side imports that we are ignoring for now # cms side imports that we are ignoring for now
cms.djangoapps.contentstore.views.tests.test_block -> lms.djangoapps.lms_xblock.mixin 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.signals.handlers -> lms.djangoapps.grades.api
cms.djangoapps.contentstore.course_group_config -> lms.lib.utils cms.djangoapps.contentstore.course_group_config -> lms.lib.utils
cms.djangoapps.contentstore.views.preview -> lms.djangoapps.lms_xblock.field_data 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 # cms.djangoapps.contentstore.views.tests.test_group_configurations
# -> openedx.features.content_type_gating.helpers # -> openedx.features.content_type_gating.helpers
# -> lms.djangoapps.courseware.masquerade # -> lms.djangoapps.courseware.masquerade