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 _
import lms.envs.common
from openedx.envs.common import * # pylint: disable=wildcard-import
from path import Path as path
from lms.djangoapps.lms_xblock.mixin import LmsBlockMixin
from cms.lib.xblock.authoring_mixin import AuthoringMixin
from cms.lib.xblock.upstream_sync import UpstreamSyncMixin
from xmodule.modulestore.edit_info import EditInfoMixin
from xmodule.x_module import ResourceTemplates
from openedx.core.lib.derived import Derived
from openedx.core.lib.features_setting_proxy import FeaturesProxy
@@ -269,117 +266,50 @@ MARKETING_EMAILS_OPT_IN = False
############################# MICROFRONTENDS ###################################
COURSE_AUTHORING_MICROFRONTEND_URL = None
############################# SOCIAL MEDIA SHARING #############################
SOCIAL_SHARING_SETTINGS = {
# Note: Ensure 'CUSTOM_COURSE_URLS' has a matching value in lms/envs/common.py
'CUSTOM_COURSE_URLS': False,
'DASHBOARD_FACEBOOK': False,
'CERTIFICATE_FACEBOOK': False,
'CERTIFICATE_TWITTER': False,
'DASHBOARD_TWITTER': False
}
############################# SET PATH INFORMATION #############################
PROJECT_ROOT = path(__file__).abspath().dirname().dirname() # /edx-platform/cms
REPO_ROOT = PROJECT_ROOT.dirname()
COMMON_ROOT = REPO_ROOT / "common"
OPENEDX_ROOT = REPO_ROOT / "openedx"
CMS_ROOT = REPO_ROOT / "cms"
LMS_ROOT = REPO_ROOT / "lms"
ENV_ROOT = REPO_ROOT.dirname() # virtualenv dir /edx-platform is in
COURSES_ROOT = ENV_ROOT / "data"
XMODULE_ROOT = REPO_ROOT / "xmodule"
GITHUB_REPO_ROOT = ENV_ROOT / "data"
# For geolocation ip database
GEOIP_PATH = REPO_ROOT / "common/static/data/geoip/GeoLite2-Country.mmdb"
DATA_DIR = COURSES_ROOT
######################## BRANCH.IO ###########################
BRANCH_IO_KEY = ''
######################## GOOGLE ANALYTICS ###########################
GOOGLE_ANALYTICS_ACCOUNT = None
######################## HOTJAR ###########################
HOTJAR_ID = 00000
############################# TEMPLATE CONFIGURATION #############################
# Mako templating
import tempfile
MAKO_MODULE_DIR = os.path.join(tempfile.gettempdir(), 'mako_cms')
MAKO_TEMPLATE_DIRS_BASE = [
PROJECT_ROOT / 'templates',
COMMON_ROOT / 'templates',
COMMON_ROOT / 'djangoapps' / 'pipeline_mako' / 'templates',
COMMON_ROOT / 'static', # required to statically include common Underscore templates
OPENEDX_ROOT / 'core' / 'djangoapps' / 'cors_csrf' / 'templates',
OPENEDX_ROOT / 'core' / 'djangoapps' / 'dark_lang' / 'templates',
OPENEDX_ROOT / 'core' / 'lib' / 'license' / 'templates',
CMS_ROOT / 'djangoapps' / 'pipeline_js' / 'templates',
XMODULE_ROOT / 'capa' / 'templates',
]
CONTEXT_PROCESSORS = (
'django.template.context_processors.request',
'django.template.context_processors.static',
'django.contrib.messages.context_processors.messages',
'django.template.context_processors.i18n',
'django.contrib.auth.context_processors.auth', # this is required for admin
'django.template.context_processors.csrf',
'help_tokens.context_processor',
'openedx.core.djangoapps.site_configuration.context_processors.configuration_context',
)
MAKO_TEMPLATE_DIRS_BASE.insert(3, COMMON_ROOT / 'static')
MAKO_TEMPLATE_DIRS_BASE.append(CMS_ROOT / 'djangoapps' / 'pipeline_js' / 'templates')
MAKO_TEMPLATE_DIRS_BASE.append(XMODULE_ROOT / 'capa' / 'templates')
# Django templating
TEMPLATES = [
{
'NAME': 'django',
'BACKEND': 'django.template.backends.django.DjangoTemplates',
# Don't look for template source files inside installed applications.
'APP_DIRS': False,
# Instead, look for template source files in these dirs.
'DIRS': Derived(make_mako_template_dirs),
# Options specific to this backend.
'OPTIONS': {
'loaders': (
# We have to use mako-aware template loaders to be able to include
# mako templates inside django templates (such as main_django.html).
'openedx.core.djangoapps.theming.template_loaders.ThemeTemplateLoader',
'common.djangoapps.edxmako.makoloader.MakoFilesystemLoader',
'common.djangoapps.edxmako.makoloader.MakoAppDirectoriesLoader',
),
'context_processors': CONTEXT_PROCESSORS,
# Change 'debug' in your environment settings files - not here.
'debug': False
}
},
{
'NAME': 'mako',
'BACKEND': 'common.djangoapps.edxmako.backend.Mako',
'APP_DIRS': False,
'DIRS': Derived(make_mako_template_dirs),
'OPTIONS': {
'context_processors': CONTEXT_PROCESSORS,
'debug': False,
}
},
def make_lms_template_path(settings):
"""
Make the path for the LMS "templates" dir
"""
templates_path = settings.PROJECT_ROOT / 'templates'
return templates_path.replace('cms', 'lms')
lms_mako_template_dirs_base[0] = Derived(make_lms_template_path)
TEMPLATES[0]['DIRS'] = Derived(make_mako_template_dirs)
TEMPLATES.append(
{
# This separate copy of the Mako backend is used to render previews using the LMS templates
'NAME': 'preview',
'BACKEND': 'common.djangoapps.edxmako.backend.Mako',
'APP_DIRS': False,
'DIRS': lms.envs.common.MAKO_TEMPLATE_DIRS_BASE,
'DIRS': lms_mako_template_dirs_base,
'OPTIONS': {
'context_processors': CONTEXT_PROCESSORS,
'debug': False,
'namespace': 'lms.main',
}
},
]
DEFAULT_TEMPLATE_ENGINE = TEMPLATES[0]
}
)
#################################### AWS #######################################
AWS_SECURITY_TOKEN = None
@@ -387,13 +317,8 @@ AWS_SECURITY_TOKEN = None
##############################################################################
# use the ratelimit backend to prevent brute force attacks
AUTHENTICATION_BACKENDS = [
'auth_backends.backends.EdXOAuth2',
'rules.permissions.ObjectPermissionBackend',
'openedx.core.djangoapps.content_libraries.auth.LtiAuthenticationBackend',
'django.contrib.auth.backends.AllowAllUsersModelBackend',
'bridgekeeper.backends.RulePermissionBackend',
]
AUTHENTICATION_BACKENDS.insert(0, 'auth_backends.backends.EdXOAuth2')
AUTHENTICATION_BACKENDS.insert(2, 'openedx.core.djangoapps.content_libraries.auth.LtiAuthenticationBackend')
LMS_BASE = None
@@ -416,8 +341,6 @@ CMS_ROOT_URL = None
MAINTENANCE_BANNER_TEXT = 'Sample banner message'
WIKI_ENABLED = True
CERT_QUEUE = 'certificates'
################################# Middleware ###################################
@@ -510,27 +433,14 @@ EXTRA_MIDDLEWARE_CLASSES = []
############# XBlock Configuration ##########
# Import after sys.path fixup
from xmodule.modulestore.inheritance import InheritanceMixin
from xmodule.x_module import XModuleMixin, ResourceTemplates
# These are the Mixins that will be added to every Blocklike upon instantiation.
# DO NOT EXPAND THIS LIST!! We want it eventually to be EMPTY. Why? Because dynamically adding functions/behaviors to
# objects at runtime is confusing for both developers and static tooling (pylint/mypy). Instead...
# - to add special Blocklike behaviors just for your site: override `XBLOCK_EXTRA_MIXINS` with your own XBlockMixins.
# - to add new functionality to all Blocklikes: add it to the base Blocklike class in the core openedx/XBlock repo.
XBLOCK_MIXINS = (
# TODO: For each of these, either
# (a) merge their functionality into the base Blocklike class, or
# (b) refactor their functionality out of the Blocklike objects and into the edx-platform block runtimes.
LmsBlockMixin,
InheritanceMixin,
ResourceTemplates,
XModuleMixin,
EditInfoMixin,
# DO NOT EXPAND THIS LIST!! See declaration in openedx/envs/common.py for more information
mixins = list(XBLOCK_MIXINS)
mixins.insert(2, ResourceTemplates)
mixins += [
UpstreamSyncMixin, # Should be above AuthoringMixin for UpstreamSyncMixin.editor_saved to take effect
AuthoringMixin,
)
]
XBLOCK_MIXINS = tuple(mixins)
############################ ORA 2 ############################################
@@ -539,116 +449,19 @@ ORA2_FILE_PREFIX = 'default_env-default_deployment/ora2'
############################ Modulestore Configuration ################################
DOC_STORE_CONFIG = {
'db': 'edxapp',
'host': 'localhost',
'replicaSet': '',
'user': 'edxapp',
'port': 27017,
'collection': 'modulestore',
'ssl': False,
# https://api.mongodb.com/python/2.9.1/api/pymongo/mongo_client.html#module-pymongo.mongo_client
# default is never timeout while the connection is open,
#this means it needs to explicitly close raising pymongo.errors.NetworkTimeout
'socketTimeoutMS': 6000,
'connectTimeoutMS': 2000, # default is 20000, I believe raises pymongo.errors.ConnectionFailure
# Not setting waitQueueTimeoutMS and waitQueueMultiple since pymongo defaults to nobody being allowed to wait
'auth_source': None,
'read_preference': 'PRIMARY'
# If 'asset_collection' defined, it'll be used
# as the collection name for asset metadata.
# Otherwise, a default collection name will be used.
}
CONTENTSTORE = {
'ENGINE': 'xmodule.contentstore.mongo.MongoContentStore',
# connection strings are duplicated temporarily for
# backward compatibility
'OPTIONS': {
'db': 'edxapp',
'host': 'localhost',
'password': 'password',
'port': 27017,
'user': 'edxapp',
'ssl': False,
'auth_source': None
},
'ADDITIONAL_OPTIONS': {},
'DOC_STORE_CONFIG': DOC_STORE_CONFIG
}
CONTENTSTORE['DOC_STORE_CONFIG']['read_preference'] = 'PRIMARY'
MODULESTORE_BRANCH = 'draft-preferred'
MODULESTORE = {
'default': {
'ENGINE': 'xmodule.modulestore.mixed.MixedModuleStore',
'OPTIONS': {
'mappings': {},
'stores': [
{
'NAME': 'split',
'ENGINE': 'xmodule.modulestore.split_mongo.split_draft.DraftVersioningModuleStore',
'DOC_STORE_CONFIG': DOC_STORE_CONFIG,
'OPTIONS': {
'default_class': 'xmodule.hidden_block.HiddenBlock',
'fs_root': DATA_DIR,
'render_template': 'common.djangoapps.edxmako.shortcuts.render_to_string',
}
},
{
'NAME': 'draft',
'ENGINE': 'xmodule.modulestore.mongo.DraftMongoModuleStore',
'DOC_STORE_CONFIG': DOC_STORE_CONFIG,
'OPTIONS': {
'default_class': 'xmodule.hidden_block.HiddenBlock',
'fs_root': DATA_DIR,
'render_template': 'common.djangoapps.edxmako.shortcuts.render_to_string',
}
}
]
}
}
}
# Modulestore-level field override providers. These field override providers don't
# require student context.
MODULESTORE_FIELD_OVERRIDE_PROVIDERS = ()
DEFAULT_AUTO_FIELD = 'django.db.models.AutoField'
DEFAULT_HASHING_ALGORITHM = 'sha256'
#################### Python sandbox ############################################
CODE_JAIL = {
# from https://github.com/openedx/codejail/blob/master/codejail/django_integration.py#L24, '' should be same as None
'python_bin': '/edx/app/edxapp/venvs/edxapp-sandbox/bin/python',
# User to run as in the sandbox.
'user': 'sandbox',
# Configurable limits.
'limits': {
# How many CPU seconds can jailed code use?
'CPU': 1,
# Limit the memory of the jailed process to something high but not
# infinite (512MiB in bytes)
'VMEM': 536870912,
# Time in seconds that the jailed process has to run.
'REALTIME': 3,
'PROXY': 0,
# Needs to be non-zero so that jailed code can use it as their temp directory.(1MiB in bytes)
'FSIZE': 1048576,
},
# Overrides to default configurable 'limits' (above).
# Keys should be course run ids.
# Values should be dictionaries that look like 'limits'.
"limit_overrides": {},
}
# Needs to be non-zero so that jailed code can use it as their temp directory.(1MiB in bytes)
CODE_JAIL['limits']['FSIZE'] = 1048576
############################ DJANGO_BUILTINS ################################
ROOT_URLCONF = 'cms.urls'
COURSE_IMPORT_EXPORT_BUCKET = ''
COURSE_METADATA_EXPORT_BUCKET = ''
@@ -684,48 +497,19 @@ PRESS_EMAIL = 'press@example.com'
STATIC_URL = '/static/studio/'
STATIC_ROOT = os.environ.get('STATIC_ROOT_CMS', ENV_ROOT / 'staticfiles' / 'studio')
STATICFILES_DIRS = [
COMMON_ROOT / "static",
PROJECT_ROOT / "static",
# Temporarily adding the following static path as we are migrating the built-in blocks' Sass to vanilla CSS.
# Once all of the built-in blocks are extracted from edx-platform, we can remove this static path.
# Relevant ticket: https://github.com/openedx/edx-platform/issues/35300
XMODULE_ROOT / "static",
]
# Storage
COURSE_IMPORT_EXPORT_STORAGE = 'django.core.files.storage.FileSystemStorage'
COURSE_METADATA_EXPORT_STORAGE = 'django.core.files.storage.FileSystemStorage'
STATICI18N_ROOT = PROJECT_ROOT / "static"
##### custom vendor plugin variables #####
############################### PIPELINE #######################################
PIPELINE = {
'PIPELINE_ENABLED': True,
# Don't use compression by default
'CSS_COMPRESSOR': None,
PIPELINE.update({
'JS_COMPRESSOR': None,
# Don't wrap JavaScript as there is code that depends upon updating the global namespace
'DISABLE_WRAPPER': True,
# Specify the UglifyJS binary to use
'UGLIFYJS_BINARY': 'node_modules/.bin/uglifyjs',
'COMPILERS': (),
'YUI_BINARY': 'yui-compressor',
}
STATICFILES_STORAGE_KWARGS = {}
# List of finder classes that know how to find static files in various locations.
# Note: the pipeline finder is included to be able to discover optimized files
STATICFILES_FINDERS = [
'openedx.core.djangoapps.theming.finders.ThemeFilesFinder',
'django.contrib.staticfiles.finders.FileSystemFinder',
'django.contrib.staticfiles.finders.AppDirectoriesFinder',
'openedx.core.lib.xblock_pipeline.finder.XBlockPipelineFinder',
'pipeline.finders.PipelineFinder',
]
})
PIPELINE['STYLESHEETS'] = {
'style-vendor': {
@@ -825,78 +609,23 @@ PIPELINE['JAVASCRIPT'] = {
},
}
STATICFILES_IGNORE_PATTERNS = (
"*.py",
"*.pyc",
# It would be nice if we could do, for example, "**/*.scss",
# but these strings get passed down to the `fnmatch` module,
# which doesn't support that. :(
# http://docs.python.org/2/library/fnmatch.html
"sass/*.scss",
"sass/*/*.scss",
"sass/*/*/*.scss",
"sass/*/*/*/*.scss",
# Ignore tests
"spec",
"spec_helpers",
# Symlinks used by js-test-tool
"xmodule_js",
"common_static",
)
STATICFILES_IGNORE_PATTERNS.append("common_static")
################################# DJANGO-REQUIRE ###############################
# The name of a build profile to use for your project, relative to REQUIRE_BASE_URL.
# A sensible value would be 'app.build.js'. Leave blank to use the built-in default build profile.
# Set to False to disable running the default profile (e.g. if only using it to build Standalone
# Modules)
REQUIRE_BUILD_PROFILE = "cms/js/build.js"
# The name of the require.js script used by your project, relative to REQUIRE_BASE_URL.
REQUIRE_JS = "js/vendor/requiresjs/require.js"
########################## DJANGO WEBPACK LOADER ##############################
WEBPACK_LOADER = {
'DEFAULT': {
'BUNDLE_DIR_NAME': 'bundles/',
'STATS_FILE': os.path.join(STATIC_ROOT, 'webpack-stats.json'),
},
'WORKERS': {
'BUNDLE_DIR_NAME': 'bundles/',
'STATS_FILE': os.path.join(STATIC_ROOT, 'webpack-worker-stats.json')
}
}
############################ SERVICE_VARIANT ##################################
# SERVICE_VARIANT specifies name of the variant used, which decides what JSON
# configuration files are read during startup.
SERVICE_VARIANT = os.environ.get('SERVICE_VARIANT', 'cms')
# CONFIG_PREFIX specifies the prefix of the JSON configuration files,
# based on the service variant. If no variant is use, don't use a
# prefix.
CONFIG_PREFIX = SERVICE_VARIANT + "." if SERVICE_VARIANT else ""
SERVICE_VARIANT = 'cms'
################################# CELERY ######################################
# Name the exchange and queues for each variant
QUEUE_VARIANT = CONFIG_PREFIX.lower()
CELERY_DEFAULT_EXCHANGE = f'edx.{QUEUE_VARIANT}core'
HIGH_PRIORITY_QUEUE = f'edx.{QUEUE_VARIANT}core.high'
DEFAULT_PRIORITY_QUEUE = f'edx.{QUEUE_VARIANT}core.default'
LOW_PRIORITY_QUEUE = f'edx.{QUEUE_VARIANT}core.low'
CELERY_DEFAULT_QUEUE = DEFAULT_PRIORITY_QUEUE
CELERY_DEFAULT_ROUTING_KEY = DEFAULT_PRIORITY_QUEUE
# Name the exchange and queues w.r.t the SERVICE_VARIANT
HIGH_PRIORITY_QUEUE = f'edx.{SERVICE_VARIANT}.core.high'
DEFAULT_PRIORITY_QUEUE = f'edx.{SERVICE_VARIANT}.core.default'
LOW_PRIORITY_QUEUE = f'edx.{SERVICE_VARIANT}.core.low'
CELERY_QUEUES = {
HIGH_PRIORITY_QUEUE: {},
@@ -904,17 +633,11 @@ CELERY_QUEUES = {
LOW_PRIORITY_QUEUE: {},
}
# Queues configuration
CLEAR_REQUEST_CACHE_ON_TASK_COMPLETION = True
BROKER_USE_SSL = Derived(lambda settings: settings.CELERY_BROKER_USE_SSL)
CELERY_ALWAYS_EAGER = False
############################## HEARTBEAT ######################################
HEARTBEAT_CELERY_ROUTING_KEY = HIGH_PRIORITY_QUEUE
BROKER_USE_SSL = Derived(lambda settings: settings.CELERY_BROKER_USE_SSL)
############################## Video ##########################################
@@ -923,12 +646,7 @@ EXTENDED_VIDEO_TRANSCRIPT_LANGUAGES = []
############################# SETTINGS FOR VIDEO UPLOAD PIPELINE #############################
VIDEO_UPLOAD_PIPELINE = {
'VEM_S3_BUCKET': '',
'BUCKET': '',
'ROOT_PATH': '',
'CONCURRENT_UPLOAD_LIMIT': 4,
}
VIDEO_UPLOAD_PIPELINE['CONCURRENT_UPLOAD_LIMIT'] = 4
############################ APPS #####################################
@@ -1193,131 +911,14 @@ INSTALLED_APPS = [
"openedx_learning.apps.authoring.sections",
]
################# EDX MARKETING SITE ##################################
MKTG_URL_LINK_MAP = {}
ID_VERIFICATION_SUPPORT_LINK = ''
PASSWORD_RESET_SUPPORT_LINK = ''
ACTIVATION_EMAIL_SUPPORT_LINK = ''
LOGIN_ISSUE_SUPPORT_LINK = ''
############################## EVENT TRACKING #################################
TRACK_MAX_EVENT = 50000
TRACKING_BACKENDS = {
'logger': {
'ENGINE': 'common.djangoapps.track.backends.logger.LoggerBackend',
'OPTIONS': {
'name': 'tracking'
}
}
}
# We're already logging events, and we don't want to capture user
# names/passwords. Heartbeat events are likely not interesting.
TRACKING_IGNORE_URL_PATTERNS = [r'^/event', r'^/login', r'^/heartbeat']
EVENT_TRACKING_ENABLED = True
EVENT_TRACKING_BACKENDS = {
'tracking_logs': {
'ENGINE': 'eventtracking.backends.routing.RoutingBackend',
'OPTIONS': {
'backends': {
'logger': {
'ENGINE': 'eventtracking.backends.logger.LoggerBackend',
'OPTIONS': {
'name': 'tracking',
'max_event_size': TRACK_MAX_EVENT,
}
}
},
'processors': [
{'ENGINE': 'common.djangoapps.track.shim.LegacyFieldMappingProcessor'},
{'ENGINE': 'common.djangoapps.track.shim.PrefixedEventProcessor'}
]
}
},
'segmentio': {
'ENGINE': 'eventtracking.backends.routing.RoutingBackend',
'OPTIONS': {
'backends': {
'segment': {'ENGINE': 'eventtracking.backends.segment.SegmentBackend'}
},
'processors': [
{
'ENGINE': 'eventtracking.processors.whitelist.NameWhitelistProcessor',
'OPTIONS': {
'whitelist': []
}
},
{
'ENGINE': 'common.djangoapps.track.shim.GoogleAnalyticsProcessor'
}
]
}
}
}
EVENT_TRACKING_PROCESSORS = []
EVENT_TRACKING_SEGMENTIO_EMIT_WHITELIST = []
### Apps only installed in some instances
add_optional_apps(OPTIONAL_APPS, INSTALLED_APPS)
##### ACCOUNT LOCKOUT DEFAULT PARAMETERS #####
MAX_FAILED_LOGIN_ATTEMPTS_ALLOWED = 6
MAX_FAILED_LOGIN_ATTEMPTS_LOCKOUT_PERIOD_SECS = 30 * 60
### Apps only installed in some instances
# The order of INSTALLED_APPS matters, so this tuple is the app name and the item in INSTALLED_APPS
# that this app should be inserted *before*. A None here means it should be appended to the list.
OPTIONAL_APPS = (
('problem_builder', 'openedx.core.djangoapps.content.course_overviews.apps.CourseOverviewsConfig'),
('edx_sga', None),
# edx-ora2
('submissions', 'openedx.core.djangoapps.content.course_overviews.apps.CourseOverviewsConfig'),
('openassessment', 'openedx.core.djangoapps.content.course_overviews.apps.CourseOverviewsConfig'),
('openassessment.assessment', 'openedx.core.djangoapps.content.course_overviews.apps.CourseOverviewsConfig'),
('openassessment.fileupload', 'openedx.core.djangoapps.content.course_overviews.apps.CourseOverviewsConfig'),
('openassessment.staffgrader', 'openedx.core.djangoapps.content.course_overviews.apps.CourseOverviewsConfig'),
('openassessment.workflow', 'openedx.core.djangoapps.content.course_overviews.apps.CourseOverviewsConfig'),
('openassessment.xblock', 'openedx.core.djangoapps.content.course_overviews.apps.CourseOverviewsConfig'),
# edxval
('edxval', 'openedx.core.djangoapps.content.course_overviews.apps.CourseOverviewsConfig'),
# Enterprise App (http://github.com/openedx/edx-enterprise)
('enterprise', None),
('consent', None),
('integrated_channels.integrated_channel', None),
('integrated_channels.degreed', None),
('integrated_channels.degreed2', None),
('integrated_channels.sap_success_factors', None),
('integrated_channels.xapi', None),
('integrated_channels.cornerstone', None),
('integrated_channels.blackboard', None),
('integrated_channels.canvas', None),
('integrated_channels.moodle', None),
)
for app_name, insert_before in OPTIONAL_APPS:
# First attempt to only find the module rather than actually importing it,
# to avoid circular references - only try to import if it can't be found
# by find_spec, which doesn't work with import hooks
if importlib.util.find_spec(app_name) is None:
try:
__import__(app_name)
except ImportError:
continue
try:
INSTALLED_APPS.insert(INSTALLED_APPS.index(insert_before), app_name)
except (IndexError, ValueError):
INSTALLED_APPS.append(app_name)
### Size of chunks into which asset uploads will be divided
UPLOAD_CHUNK_SIZE_IN_MB = 10
@@ -1413,27 +1014,11 @@ ELASTIC_FIELD_MAPPINGS = {
XBLOCK_FS_STORAGE_BUCKET = None
XBLOCK_FS_STORAGE_PREFIX = None
############################ Global Database Configuration #####################
DATABASE_ROUTERS = [
'openedx.core.lib.django_courseware_routers.StudentModuleHistoryExtendedRouter',
]
############################ OAUTH2 Provider ###################################
# 5 minute expiration time for JWT id tokens issued for external API requests.
OAUTH_ID_TOKEN_EXPIRATION = 5 * 60
EDX_DRF_EXTENSIONS = {
# Set this value to an empty dict in order to prevent automatically updating
# user data from values in (possibly stale) JWTs.
'JWT_PAYLOAD_USER_ATTRIBUTE_MAPPING': {},
}
############## Settings for Studio Context Sensitive Help ##############
HELP_TOKENS_INI_FILE = REPO_ROOT / "cms" / "envs" / "help_tokens.ini"
############## DJANGO-USER-TASKS ##############
# How long until database records about the outcome of a task and its artifacts get deleted?
@@ -1441,9 +1026,6 @@ USER_TASKS_MAX_AGE = timedelta(days=7)
############################# Persistent Grades ####################################
# Queue to use for updating persistent grades
RECALCULATE_GRADES_ROUTING_KEY = DEFAULT_PRIORITY_QUEUE
# .. setting_name: DEFAULT_GRADE_DESIGNATIONS
# .. setting_default: ['A', 'B', 'C', 'D']
# .. setting_description: The default 'pass' grade cutoff designations to be used. The failure grade
@@ -1534,10 +1116,6 @@ VIDEO_IMAGE_SETTINGS = dict(
VIDEO_IMAGE_MAX_AGE = 31536000
########################## VIDEO TRANSCRIPTS STORAGE ############################
TRANSCRIPT_LANG_CACHE_TIMEOUT = 60 * 60 * 24
##### shoppingcart Payment #####
PAYMENT_SUPPORT_EMAIL = 'billing@example.com'
@@ -1582,19 +1160,7 @@ LEARNER_PORTAL_URL_ROOT = 'https://learner-portal-localhost:18000'
############################ JWT #################################
REGISTRATION_EXTRA_FIELDS = {
'confirm_email': 'hidden',
'level_of_education': 'optional',
'gender': 'optional',
'year_of_birth': 'optional',
'mailing_address': 'optional',
'goals': 'optional',
'honor_code': 'required',
'terms_of_service': 'hidden',
'city': 'hidden',
'country': 'hidden',
'marketing_emails_opt_in': 'hidden',
}
REGISTRATION_EXTRA_FIELDS['marketing_emails_opt_in'] = 'hidden'
EDXAPP_PARSE_KEYS = {}
PARSE_KEYS = {}
@@ -1675,18 +1241,7 @@ DISCUSSIONS_INCONTEXT_LEARNMORE_URL = "https://docs.openedx.org/en/latest/educat
def _should_send_xblock_events(settings):
return settings.ENABLE_SEND_XBLOCK_LIFECYCLE_EVENTS_OVER_BUS
# .. setting_name: EVENT_BUS_PRODUCER_CONFIG
# .. setting_default: all events disabled
# .. setting_description: Dictionary of event_types mapped to dictionaries of topic to topic-related configuration.
# Each topic configuration dictionary contains
# * `enabled`: a toggle denoting whether the event will be published to the topic. These should be annotated
# according to
# https://docs.openedx.org/projects/edx-toggles/en/latest/how_to/documenting_new_feature_toggles.html
# * `event_key_field` which is a period-delimited string path to event data field to use as event key.
# Note: The topic names should not include environment prefix as it will be dynamically added based on
# EVENT_BUS_TOPIC_PREFIX setting.
EVENT_BUS_PRODUCER_CONFIG = {
EVENT_BUS_PRODUCER_CONFIG.update({
'org.openedx.content_authoring.course.catalog_info.changed.v1': {
'course-catalog-info-changed':
{'event_key_field': 'catalog_info.course_key',
@@ -1714,29 +1269,7 @@ EVENT_BUS_PRODUCER_CONFIG = {
'course-authoring-xblock-lifecycle':
{'event_key_field': 'xblock_info.usage_key', 'enabled': Derived(_should_send_xblock_events)},
},
# LMS events. These have to be copied over here because lms.common adds some derived entries as well,
# and the derivation fails if the keys are missing. If we ever remove the import of lms.common, we can remove these.
'org.openedx.learning.certificate.created.v1': {
'learning-certificate-lifecycle':
{'event_key_field': 'certificate.course.course_key', 'enabled': False},
},
'org.openedx.learning.certificate.revoked.v1': {
'learning-certificate-lifecycle':
{'event_key_field': 'certificate.course.course_key', 'enabled': False},
},
"org.openedx.learning.course.passing.status.updated.v1": {
"learning-badges-lifecycle": {
"event_key_field": "course_passing_status.course.course_key",
"enabled": Derived(should_send_learning_badge_events),
},
},
"org.openedx.learning.ccx.course.passing.status.updated.v1": {
"learning-badges-lifecycle": {
"event_key_field": "course_passing_status.course.ccx_course_key",
"enabled": Derived(should_send_learning_badge_events),
},
},
}
})
################### Authoring API ######################

View File

@@ -134,8 +134,6 @@ if STATIC_URL_BASE:
if STATIC_ROOT_BASE:
STATIC_ROOT = path(STATIC_ROOT_BASE) / 'studio'
WEBPACK_LOADER['DEFAULT']['STATS_FILE'] = STATIC_ROOT / "webpack-stats.json"
WEBPACK_LOADER['WORKERS']['STATS_FILE'] = STATIC_ROOT / "webpack-worker-stats.json"
DATA_DIR = path(DATA_DIR)
@@ -263,7 +261,7 @@ if _YAML_CELERY_QUEUES:
# Then add alternate environment queues
_YAML_ALTERNATE_WORKER_QUEUES = _YAML_TOKENS.get('ALTERNATE_WORKER_QUEUES', '').split()
ALTERNATE_QUEUES = [
DEFAULT_PRIORITY_QUEUE.replace(QUEUE_VARIANT, alternate + '.')
DEFAULT_PRIORITY_QUEUE.replace(SERVICE_VARIANT, alternate)
for alternate in _YAML_ALTERNATE_WORKER_QUEUES
]

View File

@@ -14,6 +14,7 @@ sessions. Assumes structure:
import os
import tempfile
from django.utils.translation import gettext_lazy
from edx_django_utils.plugins import add_plugins
@@ -38,7 +39,8 @@ STUDIO_SHORT_NAME = gettext_lazy("𝓢𝓽𝓾𝓭𝓲𝓸")
COMMON_TEST_DATA_ROOT = COMMON_ROOT / "test" / "data"
WEBPACK_LOADER["DEFAULT"]["STATS_FILE"] = STATIC_ROOT / "webpack-stats.json"
COMPREHENSIVE_THEME_DIRS = [REPO_ROOT / "themes", REPO_ROOT / "common/test"]
WEBPACK_LOADER['DEFAULT']['LOADER_CLASS'] = 'webpack_loader.loader.FakeWebpackLoader'
GITHUB_REPO_ROOT = TEST_ROOT / "data"

View File

@@ -40,7 +40,6 @@ Conventions
# and throws spurious errors. Therefore, we disable invalid-name checking.
# pylint: disable=invalid-name
import importlib.util
import os
from corsheaders.defaults import default_headers as corsheaders_default_headers
@@ -65,7 +64,6 @@ from enterprise.constants import (
from openedx.core.lib.derived import Derived
from openedx.envs.common import * # pylint: disable=wildcard-import
from lms.djangoapps.lms_xblock.mixin import LmsBlockMixin
from openedx.core.lib.features_setting_proxy import FeaturesProxy
# A proxy for feature flags stored in the settings namespace
@@ -735,28 +733,16 @@ GRADEBOOK_FREEZE_DAYS = 30
RETRY_CALENDAR_SYNC_EMAIL_MAX_ATTEMPTS = 5
############################# SET PATH INFORMATION #############################
PROJECT_ROOT = path(__file__).abspath().dirname().dirname() # /edx-platform/lms
REPO_ROOT = PROJECT_ROOT.dirname()
COMMON_ROOT = REPO_ROOT / "common"
OPENEDX_ROOT = REPO_ROOT / "openedx"
XMODULE_ROOT = REPO_ROOT / "xmodule"
ENV_ROOT = REPO_ROOT.dirname() # virtualenv dir /edx-platform is in
COURSES_ROOT = ENV_ROOT / "data"
NODE_MODULES_ROOT = REPO_ROOT / "node_modules"
DATA_DIR = COURSES_ROOT
# For geolocation ip database
GEOIP_PATH = REPO_ROOT / "common/static/data/geoip/GeoLite2-Country.mmdb"
# Where to look for a status message
STATUS_MESSAGE_PATH = ENV_ROOT / "status_message.json"
############################ Global Database Configuration #####################
DATABASE_ROUTERS = [
'openedx.core.lib.django_courseware_routers.StudentModuleHistoryExtendedRouter',
'edx_django_utils.db.read_replica.ReadReplicaRouter',
]
DATABASE_ROUTERS.append('edx_django_utils.db.read_replica.ReadReplicaRouter')
################################## DJANGO OAUTH TOOLKIT #######################################
@@ -812,27 +798,11 @@ TPA_PROVIDER_SUSTAINED_THROTTLE = '50/hr'
TPA_AUTOMATIC_LOGOUT_ENABLED = False
################################## TEMPLATE CONFIGURATION #####################################
# Mako templating
import tempfile # pylint: disable=wrong-import-position,wrong-import-order
MAKO_MODULE_DIR = os.path.join(tempfile.gettempdir(), 'mako_lms')
MAKO_TEMPLATE_DIRS_BASE = [
PROJECT_ROOT / 'templates',
COMMON_ROOT / 'templates',
XMODULE_ROOT / 'capa' / 'templates',
COMMON_ROOT / 'djangoapps' / 'pipeline_mako' / 'templates',
OPENEDX_ROOT / 'core' / 'djangoapps' / 'cors_csrf' / 'templates',
OPENEDX_ROOT / 'core' / 'djangoapps' / 'dark_lang' / 'templates',
OPENEDX_ROOT / 'core' / 'lib' / 'license' / 'templates',
OPENEDX_ROOT / 'features' / 'course_experience' / 'templates',
]
CONTEXT_PROCESSORS = [
'django.template.context_processors.request',
'django.template.context_processors.static',
'django.template.context_processors.i18n',
'django.contrib.auth.context_processors.auth', # this is required for admin
'django.template.context_processors.csrf',
MAKO_TEMPLATE_DIRS_BASE = lms_mako_template_dirs_base
CONTEXT_PROCESSORS.remove('django.contrib.messages.context_processors.messages')
CONTEXT_PROCESSORS[5:5] = [
# Added for django-wiki
'django.template.context_processors.media',
'django.template.context_processors.tz',
@@ -844,11 +814,8 @@ CONTEXT_PROCESSORS = [
# Timezone processor (sends language and time_zone preference)
'lms.djangoapps.courseware.context_processor.user_timezone_locale_prefs',
# Online contextual help
'help_tokens.context_processor',
'openedx.core.djangoapps.site_configuration.context_processors.configuration_context',
]
CONTEXT_PROCESSORS += [
# Mobile App processor (Detects if request is from the mobile app)
'lms.djangoapps.mobile_api.context_processor.is_from_mobile_app',
@@ -856,61 +823,10 @@ CONTEXT_PROCESSORS = [
'openedx.features.survey_report.context_processors.admin_extra_context',
]
# Django templating
TEMPLATES = [
{
'NAME': 'django',
'BACKEND': 'django.template.backends.django.DjangoTemplates',
# Don't look for template source files inside installed applications.
'APP_DIRS': False,
# Instead, look for template source files in these dirs.
'DIRS': [
PROJECT_ROOT / "templates",
COMMON_ROOT / 'templates',
XMODULE_ROOT / 'capa' / 'templates',
COMMON_ROOT / 'djangoapps' / 'pipeline_mako' / 'templates',
COMMON_ROOT / 'static', # required to statically include common Underscore templates
],
# Options specific to this backend.
'OPTIONS': {
'loaders': [
# We have to use mako-aware template loaders to be able to include
# mako templates inside django templates (such as main_django.html).
'openedx.core.djangoapps.theming.template_loaders.ThemeTemplateLoader',
'common.djangoapps.edxmako.makoloader.MakoFilesystemLoader',
'common.djangoapps.edxmako.makoloader.MakoAppDirectoriesLoader',
],
'context_processors': CONTEXT_PROCESSORS,
# Change 'debug' in your environment settings files - not here.
'debug': False
}
},
{
'NAME': 'mako',
'BACKEND': 'common.djangoapps.edxmako.backend.Mako',
# Don't look for template source files inside installed applications.
'APP_DIRS': False,
# Instead, look for template source files in these dirs.
'DIRS': Derived(make_mako_template_dirs),
# Options specific to this backend.
'OPTIONS': {
'context_processors': CONTEXT_PROCESSORS,
# Change 'debug' in your environment settings files - not here.
'debug': False,
}
},
]
DEFAULT_TEMPLATE_ENGINE = TEMPLATES[0]
DEFAULT_TEMPLATE_ENGINE_DIRS = DEFAULT_TEMPLATE_ENGINE['DIRS'][:]
DEFAULT_TEMPLATE_ENGINE_DIRS = Derived(lambda settings: settings.TEMPLATES[0]['DIRS'][:])
###############################################################################################
AUTHENTICATION_BACKENDS = [
'rules.permissions.ObjectPermissionBackend',
'django.contrib.auth.backends.AllowAllUsersModelBackend',
'bridgekeeper.backends.RulePermissionBackend',
]
STUDENT_FILEUPLOAD_MAX_SIZE = 4 * 1000 * 1000 # 4 MB
MAX_FILEUPLOADS_PER_INPUT = 20
@@ -951,15 +867,6 @@ CERTIFICATE_DATE_FORMAT = "%B %-d, %Y"
ENABLE_MULTICOURSE = False # set to False to disable multicourse display (see lib.util.views.edXhome)
# .. toggle_name: WIKI_ENABLED
# .. toggle_implementation: DjangoSetting
# .. toggle_default: True
# .. toggle_description: This setting allows us to have a collaborative tool to contribute or
# modify content of course related materials.
# .. toggle_use_cases: open_edx
# .. toggle_creation_date: 2012-07-13
WIKI_ENABLED = True
###
# IP addresses that are allowed to reload the course, etc.
@@ -969,66 +876,9 @@ LMS_MIGRATION_ALLOWED_IPS = []
############################## EVENT TRACKING #################################
LMS_SEGMENT_KEY = None
# FIXME: Should we be doing this truncation?
TRACK_MAX_EVENT = 50000
DEBUG_TRACK_LOG = False
TRACKING_BACKENDS = {
'logger': {
'ENGINE': 'common.djangoapps.track.backends.logger.LoggerBackend',
'OPTIONS': {
'name': 'tracking'
}
}
}
# We're already logging events, and we don't want to capture user
# names/passwords. Heartbeat events are likely not interesting.
TRACKING_IGNORE_URL_PATTERNS = [r'^/event', r'^/login', r'^/heartbeat', r'^/segmentio/event', r'^/performance']
EVENT_TRACKING_ENABLED = True
EVENT_TRACKING_BACKENDS = {
'tracking_logs': {
'ENGINE': 'eventtracking.backends.routing.RoutingBackend',
'OPTIONS': {
'backends': {
'logger': {
'ENGINE': 'eventtracking.backends.logger.LoggerBackend',
'OPTIONS': {
'name': 'tracking',
'max_event_size': TRACK_MAX_EVENT,
}
}
},
'processors': [
{'ENGINE': 'common.djangoapps.track.shim.LegacyFieldMappingProcessor'},
{'ENGINE': 'common.djangoapps.track.shim.PrefixedEventProcessor'}
]
}
},
'segmentio': {
'ENGINE': 'eventtracking.backends.routing.RoutingBackend',
'OPTIONS': {
'backends': {
'segment': {'ENGINE': 'eventtracking.backends.segment.SegmentBackend'}
},
'processors': [
{
'ENGINE': 'eventtracking.processors.whitelist.NameWhitelistProcessor',
'OPTIONS': {
'whitelist': []
}
},
{
'ENGINE': 'common.djangoapps.track.shim.GoogleAnalyticsProcessor'
}
]
}
}
}
EVENT_TRACKING_PROCESSORS = []
EVENT_TRACKING_SEGMENTIO_EMIT_WHITELIST = []
TRACKING_IGNORE_URL_PATTERNS += [r'^/segmentio/event', r'^/performance']
TRACKING_SEGMENTIO_WEBHOOK_SECRET = None
TRACKING_SEGMENTIO_ALLOWED_TYPES = ['track']
@@ -1039,7 +889,6 @@ TRACKING_SEGMENTIO_SOURCE_MAP = {
}
######################## GOOGLE ANALYTICS ###########################
GOOGLE_ANALYTICS_ACCOUNT = None
GOOGLE_SITE_VERIFICATION_ID = None
GOOGLE_ANALYTICS_LINKEDIN = None
GOOGLE_ANALYTICS_TRACKING_ID = None
@@ -1054,99 +903,13 @@ HOTJAR_SITE_ID = 00000
######################## subdomain specific settings ###########################
COURSE_LISTINGS = {}
############# XBlock Configuration ##########
# Import after sys.path fixup
from xmodule.modulestore.edit_info import EditInfoMixin # lint-amnesty, pylint: disable=wrong-import-order, wrong-import-position
from xmodule.modulestore.inheritance import InheritanceMixin # lint-amnesty, pylint: disable=wrong-import-order, wrong-import-position
from xmodule.x_module import XModuleMixin # lint-amnesty, pylint: disable=wrong-import-order, wrong-import-position
# These are the Mixins that will be added to every Blocklike upon instantiation.
# DO NOT EXPAND THIS LIST!! We want it eventually to be EMPTY. Why? Because dynamically adding functions/behaviors to
# objects at runtime is confusing for both developers and static tooling (pylint/mypy). Instead...
# - to add special Blocklike behaviors just for your site: override `XBLOCK_EXTRA_MIXINS` with your own XBlockMixins.
# - to add new functionality to all Blocklikes: add it to the base Blocklike class in the core openedx/XBlock repo.
XBLOCK_MIXINS = (
# TODO: For each of these, either
# (a) merge their functionality into the base Blocklike class, or
# (b) refactor their functionality out of the Blocklike objects and into the edx-platform block runtimes.
LmsBlockMixin,
InheritanceMixin,
XModuleMixin,
EditInfoMixin,
)
############# ModuleStore Configuration ##########
CONTENTSTORE['DOC_STORE_CONFIG']['password'] = 'password'
CONTENTSTORE['DOC_STORE_CONFIG']['read_preference'] = 'SECONDARY_PREFERRED'
MODULESTORE_BRANCH = 'published-only'
DOC_STORE_CONFIG = {
'db': 'edxapp',
'host': 'localhost',
'replicaSet': '',
'password': 'password',
'port': 27017,
'user': 'edxapp',
'collection': 'modulestore',
'ssl': False,
# https://api.mongodb.com/python/2.9.1/api/pymongo/mongo_client.html#module-pymongo.mongo_client
# default is never timeout while the connection is open,
#this means it needs to explicitly close raising pymongo.errors.NetworkTimeout
'socketTimeoutMS': 6000,
'connectTimeoutMS': 2000, # default is 20000, I believe raises pymongo.errors.ConnectionFailure
# Not setting waitQueueTimeoutMS and waitQueueMultiple since pymongo defaults to nobody being allowed to wait
'auth_source': None,
'read_preference': 'SECONDARY_PREFERRED'
}
CONTENTSTORE = {
'ENGINE': 'xmodule.contentstore.mongo.MongoContentStore',
# connection strings are duplicated temporarily for
# backward compatibility
'OPTIONS': {
'db': 'edxapp',
'host': 'localhost',
'password': 'password',
'port': 27017,
'user': 'edxapp',
'ssl': False,
'auth_source': None
},
'ADDITIONAL_OPTIONS': {},
'DOC_STORE_CONFIG': DOC_STORE_CONFIG
}
MODULESTORE = {
'default': {
'ENGINE': 'xmodule.modulestore.mixed.MixedModuleStore',
'OPTIONS': {
'mappings': {},
'stores': [
{
'NAME': 'split',
'ENGINE': 'xmodule.modulestore.split_mongo.split_draft.DraftVersioningModuleStore',
'DOC_STORE_CONFIG': DOC_STORE_CONFIG,
'OPTIONS': {
'default_class': 'xmodule.hidden_block.HiddenBlock',
'fs_root': Derived(lambda settings: settings.DATA_DIR),
'render_template': 'common.djangoapps.edxmako.shortcuts.render_to_string',
}
},
{
'NAME': 'draft',
'ENGINE': 'xmodule.modulestore.mongo.DraftMongoModuleStore',
'DOC_STORE_CONFIG': DOC_STORE_CONFIG,
'OPTIONS': {
'default_class': 'xmodule.hidden_block.HiddenBlock',
'fs_root': Derived(lambda settings: settings.DATA_DIR),
'render_template': 'common.djangoapps.edxmako.shortcuts.render_to_string',
}
}
]
}
}
}
HOSTNAME_MODULESTORE_DEFAULT_MAPPINGS = {}
MONGODB_LOG = {}
@@ -1200,9 +963,6 @@ CMS_BASE = 'studio.edx.org'
STUDIO_NAME = 'Studio'
STUDIO_SHORT_NAME = 'Studio'
# Site info
ROOT_URLCONF = 'lms.urls'
# NOTE: Please set ALLOWED_HOSTS to some sane value, as we do not allow the default '*'
# Platform Email
EMAIL_FILE_PATH = Derived(lambda settings: path(settings.DATA_DIR) / "emails" / "lms")
DEFAULT_FROM_EMAIL = 'registration@example.com'
@@ -1225,17 +985,7 @@ ACTIVATION_EMAIL_FROM_ADDRESS = ''
STATIC_URL = '/static/'
STATIC_ROOT = os.environ.get('STATIC_ROOT_LMS', ENV_ROOT / "staticfiles")
STATICFILES_DIRS = [
COMMON_ROOT / "static",
PROJECT_ROOT / "static",
NODE_MODULES_ROOT / "@edx",
# Temporarily adding the following static path as we are migrating the built-in blocks' Sass to vanilla CSS.
# Once all of the built-in blocks are extracted from edx-platform, we can remove this static path.
# Relevant ticket: https://github.com/openedx/edx-platform/issues/35300
XMODULE_ROOT / "static",
]
STATICI18N_ROOT = PROJECT_ROOT / "static"
STATICFILES_DIRS.insert(2, NODE_MODULES_ROOT / "@edx")
# Guidelines for translators
TRANSLATORS_GUIDE = 'https://docs.openedx.org/en/latest/translators/index.html'
@@ -1494,27 +1244,7 @@ MIDDLEWARE = [
############################### PIPELINE #######################################
PIPELINE = {
'PIPELINE_ENABLED': True,
'CSS_COMPRESSOR': None,
'JS_COMPRESSOR': 'pipeline.compressors.uglifyjs.UglifyJSCompressor',
# Don't wrap JavaScript as there is code that depends upon updating the global namespace
'DISABLE_WRAPPER': True,
# Specify the UglifyJS binary to use
'UGLIFYJS_BINARY': 'node_modules/.bin/uglifyjs',
}
STATICFILES_STORAGE_KWARGS = {}
# List of finder classes that know how to find static files in various locations.
# Note: the pipeline finder is included to be able to discover optimized files
STATICFILES_FINDERS = [
'openedx.core.djangoapps.theming.finders.ThemeFilesFinder',
'django.contrib.staticfiles.finders.FileSystemFinder',
'django.contrib.staticfiles.finders.AppDirectoriesFinder',
'openedx.core.lib.xblock_pipeline.finder.XBlockPipelineFinder',
'pipeline.finders.PipelineFinder',
]
PIPELINE['JS_COMPRESSOR'] = 'pipeline.compressors.uglifyjs.UglifyJSCompressor'
from openedx.core.lib.rooted_paths import rooted_glob # pylint: disable=wrong-import-position
@@ -1871,37 +1601,8 @@ PIPELINE['JAVASCRIPT'] = {
}
}
STATICFILES_IGNORE_PATTERNS = (
"*.py",
"*.pyc",
# It would be nice if we could do, for example, "**/*.scss",
# but these strings get passed down to the `fnmatch` module,
# which doesn't support that. :(
# http://docs.python.org/2/library/fnmatch.html
"sass/*.scss",
"sass/*/*.scss",
"sass/*/*/*.scss",
"sass/*/*/*/*.scss",
# Ignore tests
"spec",
"spec_helpers",
# Symlinks used by js-test-tool
"xmodule_js",
)
################################# DJANGO-REQUIRE ###############################
# The name of a build profile to use for your project, relative to REQUIRE_BASE_URL.
# A sensible value would be 'app.build.js'. Leave blank to use the built-in default build profile.
# Set to False to disable running the default profile (e.g. if only using it to build Standalone
# Modules)
REQUIRE_BUILD_PROFILE = "lms/js/build.js"
# The name of the require.js script used by your project, relative to REQUIRE_BASE_URL.
REQUIRE_JS = "common/js/vendor/require.js"
@@ -1934,18 +1635,9 @@ REQUIRE_JS_PATH_OVERRIDES = {
'hls': 'common/js/vendor/hls.js'
}
########################## DJANGO WEBPACK LOADER ##############################
############################ SERVICE_VARIANT ##################################
WEBPACK_LOADER = {
'DEFAULT': {
'BUNDLE_DIR_NAME': 'bundles/',
'STATS_FILE': os.path.join(STATIC_ROOT, 'webpack-stats.json'),
},
'WORKERS': {
'BUNDLE_DIR_NAME': 'bundles/',
'STATS_FILE': os.path.join(STATIC_ROOT, 'webpack-worker-stats.json')
}
}
SERVICE_VARIANT = 'lms'
################################# CELERY ######################################
@@ -1961,28 +1653,10 @@ CELERY_IMPORTS = [
# These packages are added in addition to those added by CELERY_IMPORTS.
CELERY_EXTRA_IMPORTS = []
# SERVICE_VARIANT specifies name of the variant used, which decides what JSON
# configuration files are read during startup.
SERVICE_VARIANT = os.environ.get('SERVICE_VARIANT', "lms")
# CONFIG_PREFIX specifies the prefix of the JSON configuration files,
# based on the service variant. If no variant is use, don't use a
# prefix.
CONFIG_PREFIX = SERVICE_VARIANT + "." if SERVICE_VARIANT else ""
# Queues configuration
# Name the exchange and queues w.r.t the SERVICE_VARIANT
QUEUE_VARIANT = CONFIG_PREFIX.lower()
CELERY_DEFAULT_EXCHANGE = f'edx.{QUEUE_VARIANT}core'
HIGH_PRIORITY_QUEUE = f'edx.{QUEUE_VARIANT}core.high'
DEFAULT_PRIORITY_QUEUE = f'edx.{QUEUE_VARIANT}core.default'
HIGH_MEM_QUEUE = f'edx.{QUEUE_VARIANT}core.high_mem'
CELERY_DEFAULT_QUEUE = DEFAULT_PRIORITY_QUEUE
CELERY_DEFAULT_ROUTING_KEY = DEFAULT_PRIORITY_QUEUE
HIGH_PRIORITY_QUEUE = f'edx.{SERVICE_VARIANT}.core.high'
DEFAULT_PRIORITY_QUEUE = f'edx.{SERVICE_VARIANT}.core.default'
HIGH_MEM_QUEUE = f'edx.{SERVICE_VARIANT}.core.high_mem'
CELERY_QUEUES = {
HIGH_PRIORITY_QUEUE: {},
@@ -1998,10 +1672,6 @@ CELERYD_HIJACK_ROOT_LOGGER = False
BROKER_USE_SSL = False
############################## HEARTBEAT ######################################
HEARTBEAT_CELERY_ROUTING_KEY = HIGH_PRIORITY_QUEUE
################################ Bulk Email ###################################
# Initial delay used for retrying tasks. Additional retries use
@@ -2386,6 +2056,24 @@ INSTALLED_APPS = [
"openedx_learning.apps.authoring.sections",
]
# Add LMS specific optional apps
OPTIONAL_APPS += [
# Channel Integrations Apps
('channel_integrations.integrated_channel', None),
('channel_integrations.degreed2', None),
('channel_integrations.sap_success_factors', None),
('channel_integrations.cornerstone', None),
('channel_integrations.xapi', None),
('channel_integrations.blackboard', None),
('channel_integrations.canvas', None),
('channel_integrations.moodle', None),
# Required by the Enterprise App
('django_object_actions', None), # https://github.com/crccheck/django-object-actions
]
add_optional_apps(OPTIONAL_APPS, INSTALLED_APPS)
######################### Django Rest Framework ########################
SWAGGER_SETTINGS = {
@@ -2395,7 +2083,7 @@ SWAGGER_SETTINGS = {
######################### MARKETING SITE ###############################
MKTG_URL_LINK_MAP = {
MKTG_URL_LINK_MAP.update({
'ABOUT': 'about',
'CONTACT': 'contact',
'FAQ': 'help',
@@ -2412,15 +2100,11 @@ MKTG_URL_LINK_MAP = {
# Verified Certificates
'WHAT_IS_VERIFIED_CERT': 'verified-certificate',
}
})
STATIC_TEMPLATE_VIEW_DEFAULT_FILE_EXTENSION = 'html'
SEND_ACTIVATION_EMAIL_URL = ''
ACTIVATION_EMAIL_SUPPORT_LINK = Derived(lambda settings: settings.SUPPORT_SITE_LINK)
ID_VERIFICATION_SUPPORT_LINK = Derived(lambda settings: settings.SUPPORT_SITE_LINK)
LOGIN_ISSUE_SUPPORT_LINK = Derived(lambda settings: settings.SUPPORT_SITE_LINK)
PASSWORD_RESET_SUPPORT_LINK = Derived(lambda settings: settings.SUPPORT_SITE_LINK)
# .. setting_name: SECURITY_PAGE_URL
# .. setting_default: None
@@ -2434,19 +2118,13 @@ ENTITLEMENT_EXPIRED_ALERT_PERIOD = 90
############################# SOCIAL MEDIA SHARING #############################
# Social Media Sharing on Student Dashboard
SOCIAL_SHARING_SETTINGS = {
# Note: Ensure 'CUSTOM_COURSE_URLS' has a matching value in cms/envs/common.py
'CUSTOM_COURSE_URLS': False,
'DASHBOARD_FACEBOOK': False,
SOCIAL_SHARING_SETTINGS.update({
'FACEBOOK_BRAND': None,
'CERTIFICATE_FACEBOOK': False,
'CERTIFICATE_FACEBOOK_TEXT': None,
'CERTIFICATE_TWITTER': False,
'TWITTER_BRAND': None,
'CERTIFICATE_TWITTER_TEXT': None,
'DASHBOARD_TWITTER': False,
'DASHBOARD_TWITTER_TEXT': None,
'TWITTER_BRAND': None
}
})
################# Social Media Footer Links #######################
# The names list controls the order of social media
@@ -2575,30 +2253,6 @@ XDOMAIN_PROXY_CACHE_TIMEOUT = 60 * 15
###################### Registration ##################################
# .. setting_name: REGISTRATION_EXTRA_FIELDS
# .. setting_default: {'confirm_email': 'hidden', 'level_of_education': 'optional', 'gender': 'optional',
# 'year_of_birth': 'optional', 'mailing_address': 'optional', 'goals': 'optional', 'honor_code': 'required',
# 'terms_of_service': 'hidden', 'city': 'hidden', 'country': 'hidden'}
# .. setting_description: The signup form may contain extra fields that are presented to every user. For every field, we
# can specifiy whether it should be "required": to display the field, and make it mandatory; "optional": to display
# the optional field as part of a toggled input field list; "optional-exposed": to display the optional fields among
# the required fields, and make it non-mandatory; "hidden": to not display the field.
# When the terms of service are not visible and agreement to the honor code is required (the default), the signup page
# includes a paragraph that links to the honor code page (defined my MKTG_URLS["HONOR"]). This page might not be
# available for all Open edX platforms. In such cases, the "honor_code" registration field should be "hidden".
REGISTRATION_EXTRA_FIELDS = {
'confirm_email': 'hidden',
'level_of_education': 'optional',
'gender': 'optional',
'year_of_birth': 'optional',
'mailing_address': 'optional',
'goals': 'optional',
'honor_code': 'required',
'terms_of_service': 'hidden',
'city': 'hidden',
'country': 'hidden',
}
REGISTRATION_FIELD_ORDER = [
"name",
"first_name",
@@ -2634,8 +2288,6 @@ CERT_NAME_LONG = "Certificate of Achievement"
# the ones that contain information other than grades.
GRADES_DOWNLOAD_ROUTING_KEY = Derived(lambda settings: settings.HIGH_MEM_QUEUE)
RECALCULATE_GRADES_ROUTING_KEY = 'edx.lms.core.default'
############################ ORA 2 ############################################
ORA_WORKFLOW_UPDATE_ROUTING_KEY = "edx.lms.core.ora_workflow_update"
@@ -2655,69 +2307,6 @@ ORA_STAFF_LEASE_EXPIRATION_HOURS = 8
##### LMS DEADLINE DISPLAY TIME_ZONE #######
TIME_ZONE_DISPLAYED_FOR_DEADLINES = 'UTC'
########################## VIDEO TRANSCRIPTS STORAGE ############################
### Apps only installed in some instances
# The order of INSTALLED_APPS matters, so this tuple is the app name and the item in INSTALLED_APPS
# that this app should be inserted *before*. A None here means it should be appended to the list.
OPTIONAL_APPS = [
('problem_builder', 'openedx.core.djangoapps.content.course_overviews.apps.CourseOverviewsConfig'),
('edx_sga', None),
# edx-ora2
('submissions', 'openedx.core.djangoapps.content.course_overviews.apps.CourseOverviewsConfig'),
('openassessment', 'openedx.core.djangoapps.content.course_overviews.apps.CourseOverviewsConfig'),
('openassessment.assessment', 'openedx.core.djangoapps.content.course_overviews.apps.CourseOverviewsConfig'),
('openassessment.fileupload', 'openedx.core.djangoapps.content.course_overviews.apps.CourseOverviewsConfig'),
('openassessment.staffgrader', 'openedx.core.djangoapps.content.course_overviews.apps.CourseOverviewsConfig'),
('openassessment.workflow', 'openedx.core.djangoapps.content.course_overviews.apps.CourseOverviewsConfig'),
('openassessment.xblock', 'openedx.core.djangoapps.content.course_overviews.apps.CourseOverviewsConfig'),
# edxval
('edxval', 'openedx.core.djangoapps.content.course_overviews.apps.CourseOverviewsConfig'),
# Enterprise Apps (http://github.com/openedx/edx-enterprise)
('enterprise', None),
('consent', None),
('integrated_channels.integrated_channel', None),
('integrated_channels.degreed', None),
('integrated_channels.degreed2', None),
('integrated_channels.sap_success_factors', None),
('integrated_channels.cornerstone', None),
('integrated_channels.xapi', None),
('integrated_channels.blackboard', None),
('integrated_channels.canvas', None),
('integrated_channels.moodle', None),
# Channel Integrations Apps
('channel_integrations.integrated_channel', None),
('channel_integrations.degreed2', None),
('channel_integrations.sap_success_factors', None),
('channel_integrations.cornerstone', None),
('channel_integrations.xapi', None),
('channel_integrations.blackboard', None),
('channel_integrations.canvas', None),
('channel_integrations.moodle', None),
# Required by the Enterprise App
('django_object_actions', None), # https://github.com/crccheck/django-object-actions
]
for app_name, insert_before in OPTIONAL_APPS:
# First attempt to only find the module rather than actually importing it,
# to avoid circular references - only try to import if it can't be found
# by find_spec, which doesn't work with import hooks
if importlib.util.find_spec(app_name) is None:
try:
__import__(app_name)
except ImportError:
continue
try:
INSTALLED_APPS.insert(INSTALLED_APPS.index(insert_before), app_name)
except (IndexError, ValueError):
INSTALLED_APPS.append(app_name)
### Analytics API
ANALYTICS_API_KEY = ""
ANALYTICS_API_URL = "http://localhost:18100"
@@ -2966,13 +2555,8 @@ NOTIFICATION_EMAIL_EDX_LOGO = "templates/credit_notifications/edx-logo-header.pn
################################ Settings for JWTs ################################
EDX_DRF_EXTENSIONS = {
# Set this value to an empty dict in order to prevent automatically updating
# user data from values in (possibly stale) JWTs.
'JWT_PAYLOAD_USER_ATTRIBUTE_MAPPING': {},
# Allows JWT authentication to find the LMS user id for verification
'VERIFY_LMS_USER_ID_PROPERTY_NAME': 'id',
}
# Allows JWT authentication to find the LMS user id for verification
EDX_DRF_EXTENSIONS['VERIFY_LMS_USER_ID_PROPERTY_NAME'] = 'id'
################################ Settings for rss_proxy ################################
@@ -3030,10 +2614,6 @@ CREDENTIALS_COURSE_COMPLETION_STATE = 'awarded'
# Queue to use for award program certificates
PROGRAM_CERTIFICATES_ROUTING_KEY = Derived(lambda settings: settings.DEFAULT_PRIORITY_QUEUE)
############## Settings for LMS Context Sensitive Help ##############
HELP_TOKENS_INI_FILE = REPO_ROOT / "lms" / "envs" / "help_tokens.ini"
############## OPEN EDX ENTERPRISE SERVICE CONFIGURATION ######################
# The Open edX Enterprise service is currently hosted via the LMS container/process.
# However, for all intents and purposes this service is treated as a standalone IDA.
@@ -3145,9 +2725,6 @@ SYSTEM_TO_FEATURE_ROLE_MAPPING = {
DATA_CONSENT_SHARE_CACHE_TIMEOUT = 8 * 60 * 60 # 8 hours
TRANSCRIPT_LANG_CACHE_TIMEOUT = 60 * 60 * 24 # 24 hours
############## Settings for the Discovery App ######################
COURSES_API_CACHE_TIMEOUT = 3600 # Value is in seconds
@@ -3317,9 +2894,6 @@ ENFORCE_SESSION_EMAIL_MATCH = False
from openedx.core.djangoapps.ace_common.settings import common as ace_common_settings
ACE_ROUTING_KEY = ace_common_settings.ACE_ROUTING_KEY
############### Settings swift #####################################
SWIFT_USE_TEMP_URLS = None
############### Settings for facebook ##############################
FACEBOOK_APP_ID = None
FACEBOOK_APP_SECRET = None
@@ -3336,13 +2910,6 @@ from openedx.core.djangoapps.plugins.constants import ProjectType, SettingsType
INSTALLED_APPS.extend(get_plugin_apps(ProjectType.LMS))
add_plugins(__name__, ProjectType.LMS, SettingsType.COMMON)
############### Settings for video pipeline ##################
VIDEO_UPLOAD_PIPELINE = {
'VEM_S3_BUCKET': '',
'BUCKET': '',
'ROOT_PATH': '',
}
PROCTORED_EXAM_VIEWABLE_PAST_DUE = False
######################### rate limit for yt_video_metadata api ##############
@@ -3499,23 +3066,12 @@ GOAL_REMINDER_PROFILE_URL = ""
DISABLED_ORGS_FOR_PROGRAM_NUDGE = []
#### Event bus producing ####
def _should_send_certificate_events(settings):
return settings.SEND_LEARNING_CERTIFICATE_LIFECYCLE_EVENTS_TO_BUS
#### Event bus producing ####
# .. setting_name: EVENT_BUS_PRODUCER_CONFIG
# .. setting_default: all events disabled
# .. setting_description: Dictionary of event_types mapped to dictionaries of topic to topic-related configuration.
# Each topic configuration dictionary contains
# * `enabled`: a toggle denoting whether the event will be published to the topic. These should be annotated
# according to
# https://docs.openedx.org/projects/edx-toggles/en/latest/how_to/documenting_new_feature_toggles.html
# * `event_key_field` which is a period-delimited string path to event data field to use as event key.
# Note: The topic names should not include environment prefix as it will be dynamically added based on
# EVENT_BUS_TOPIC_PREFIX setting.
EVENT_BUS_PRODUCER_CONFIG = {
EVENT_BUS_PRODUCER_CONFIG.update({
'org.openedx.learning.certificate.created.v1': {
'learning-certificate-lifecycle':
{'event_key_field': 'certificate.course.course_key', 'enabled': Derived(_should_send_certificate_events)},
@@ -3566,40 +3122,13 @@ EVENT_BUS_PRODUCER_CONFIG = {
'learner-credit-course-enrollment-lifecycle':
{'event_key_field': 'learner_credit_course_enrollment.uuid', 'enabled': False},
},
# CMS events. These have to be copied over here because cms.common adds some derived entries as well,
# and the derivation fails if the keys are missing. If we ever fully decouple the lms and cms settings,
# we can remove these.
'org.openedx.content_authoring.xblock.published.v1': {
'course-authoring-xblock-lifecycle':
{'event_key_field': 'xblock_info.usage_key', 'enabled': False},
},
'org.openedx.content_authoring.xblock.deleted.v1': {
'course-authoring-xblock-lifecycle':
{'event_key_field': 'xblock_info.usage_key', 'enabled': False},
},
'org.openedx.content_authoring.xblock.duplicated.v1': {
'course-authoring-xblock-lifecycle':
{'event_key_field': 'xblock_info.usage_key', 'enabled': False},
},
"org.openedx.learning.course.passing.status.updated.v1": {
"learning-badges-lifecycle": {
"event_key_field": "course_passing_status.course.course_key",
"enabled": Derived(should_send_learning_badge_events),
},
},
"org.openedx.learning.ccx.course.passing.status.updated.v1": {
"learning-badges-lifecycle": {
"event_key_field": "course_passing_status.course.ccx_course_key",
"enabled": Derived(should_send_learning_badge_events),
},
},
"org.openedx.learning.external_grader.score.submitted.v1": {
"learning-external-grader-score-lifecycle": {
"event_key_field": "score.submission_id",
"enabled": False
},
},
}
})
#### Survey Report ####
# .. toggle_name: SURVEY_REPORT_ENABLE

View File

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

View File

@@ -53,7 +53,8 @@ ENABLE_BULK_USER_RETIREMENT = True
COMMON_TEST_DATA_ROOT = COMMON_ROOT / "test" / "data"
WEBPACK_LOADER['DEFAULT']['STATS_FILE'] = STATIC_ROOT / "webpack-stats.json"
COMPREHENSIVE_THEME_DIRS = [REPO_ROOT / "themes", REPO_ROOT / "common/test"]
WEBPACK_LOADER['DEFAULT']['LOADER_CLASS'] = 'webpack_loader.loader.FakeWebpackLoader'
STATUS_MESSAGE_PATH = TEST_ROOT / "status_message.json"

View File

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

View File

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

View File

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

View File

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

View File

@@ -26,6 +26,7 @@ def center_with_hashes(text: str, width: int = 76):
```
"""
import os
import importlib.util
from path import Path as path
from django.utils.translation import gettext_lazy as _
@@ -48,6 +49,11 @@ from openedx.core.constants import ( # pylint: disable=unused-import
USAGE_ID_PATTERN,
)
from xmodule.modulestore.edit_info import EditInfoMixin
from xmodule.modulestore.inheritance import InheritanceMixin
from xmodule.x_module import XModuleMixin
from lms.djangoapps.lms_xblock.mixin import LmsBlockMixin
################ Shared Functions for Derived Configuration ################
@@ -91,11 +97,22 @@ def _make_locale_paths(settings):
locale_paths += (path(locale_path), )
return locale_paths
################################## Paths ###################################
REPO_ROOT = path(__file__).abspath().dirname().dirname().dirname()
COMMON_ROOT = REPO_ROOT / "common"
OPENEDX_ROOT = REPO_ROOT / "openedx"
ENV_ROOT = REPO_ROOT.dirname() # virtualenv dir /edx-platform is in
COURSES_ROOT = ENV_ROOT / "data"
XMODULE_ROOT = REPO_ROOT / "xmodule"
DATA_DIR = COURSES_ROOT
############################# Django Built-Ins #############################
DEBUG = False
USE_TZ = True
TIME_ZONE = 'UTC'
# User-uploaded content
MEDIA_ROOT = '/edx/var/edxapp/media/'
@@ -117,18 +134,57 @@ SESSION_ENGINE = 'django.contrib.sessions.backends.cache'
SESSION_SAVE_EVERY_REQUEST = False
SESSION_SERIALIZER = 'openedx.core.lib.session_serializers.PickleSerializer'
CSRF_COOKIE_AGE = 60 * 60 * 24 * 7 * 52
CSRF_TRUSTED_ORIGINS = []
# It is highly recommended that you override this in any environment accessed by end users
CSRF_COOKIE_SECURE = False
ALLOWED_HOSTS = ['*']
# Clickjacking protection can be disbaled by setting this to 'ALLOW'
X_FRAME_OPTIONS = 'DENY'
ROOT_URLCONF = Derived(lambda settings: f'{settings.SERVICE_VARIANT}.urls')
ADMINS = []
MANAGERS = ADMINS
DEFAULT_FROM_EMAIL = 'registration@example.com'
SERVER_EMAIL = 'devops@example.com'
# Set request limits for maximum size of a request body and maximum number of GET/POST parameters. (>=Django 1.10)
# Limits are currently disabled - but can be used for finer-grained denial-of-service protection.
DATA_UPLOAD_MAX_MEMORY_SIZE = None
DATA_UPLOAD_MAX_NUMBER_FIELDS = None
# See https://github.com/openedx/edx-django-sites-extensions for more info.
# Default site to use if site matching request headers does not exist.
SITE_ID = 1
# Clickjacking protection can be disbaled by setting this to 'ALLOW'
X_FRAME_OPTIONS = 'DENY'
STATICFILES_DIRS = [
COMMON_ROOT / "static",
Derived(lambda settings: settings.PROJECT_ROOT / "static"),
# Temporarily adding the following static path as we are migrating the built-in blocks' Sass to vanilla CSS.
# Once all of the built-in blocks are extracted from edx-platform, we can remove this static path.
# Relevant ticket: https://github.com/openedx/edx-platform/issues/35300
XMODULE_ROOT / "static",
]
# List of finder classes that know how to find static files in various locations.
# Note: the pipeline finder is included to be able to discover optimized files
STATICFILES_FINDERS = [
'openedx.core.djangoapps.theming.finders.ThemeFilesFinder',
'django.contrib.staticfiles.finders.FileSystemFinder',
'django.contrib.staticfiles.finders.AppDirectoriesFinder',
'openedx.core.lib.xblock_pipeline.finder.XBlockPipelineFinder',
'pipeline.finders.PipelineFinder',
]
AUTHENTICATION_BACKENDS = [
'rules.permissions.ObjectPermissionBackend',
'django.contrib.auth.backends.AllowAllUsersModelBackend',
'bridgekeeper.backends.RulePermissionBackend',
]
AUTH_PASSWORD_VALIDATORS = [
{
@@ -160,6 +216,8 @@ STORAGES = {
# Messages
MESSAGE_STORAGE = 'django.contrib.messages.storage.session.SessionStorage'
USE_I18N = True
# these languages display right to left
LANGUAGES_BIDI = ("he", "ar", "fa", "ur", "fa-ir", "rtl")
@@ -167,6 +225,8 @@ LANGUAGE_COOKIE_NAME = "openedx-language-preference"
LOCALE_PATHS = Derived(_make_locale_paths)
LANGUAGE_CODE = 'en' # http://www.i18nguy.com/unicode/language-identifiers.html
# Sourced from http://www.localeplanet.com/icu/ and wikipedia
LANGUAGES = [
('en', 'English'),
@@ -251,6 +311,231 @@ LANGUAGES = [
('zh-tw', '中文 (台灣)'), # Chinese (Taiwan)
]
CACHES = {
'course_structure_cache': {
'KEY_PREFIX': 'course_structure',
'KEY_FUNCTION': 'common.djangoapps.util.memcache.safe_key',
'LOCATION': ['localhost:11211'],
'TIMEOUT': '604800', # 1 week
'BACKEND': 'django.core.cache.backends.memcached.PyMemcacheCache',
'OPTIONS': {
'no_delay': True,
'ignore_exc': True,
'use_pooling': True,
'connect_timeout': 0.5
}
},
'celery': {
'KEY_PREFIX': 'celery',
'KEY_FUNCTION': 'common.djangoapps.util.memcache.safe_key',
'LOCATION': ['localhost:11211'],
'TIMEOUT': '7200',
'BACKEND': 'django.core.cache.backends.memcached.PyMemcacheCache',
'OPTIONS': {
'no_delay': True,
'ignore_exc': True,
'use_pooling': True,
'connect_timeout': 0.5
}
},
'mongo_metadata_inheritance': {
'KEY_PREFIX': 'mongo_metadata_inheritance',
'KEY_FUNCTION': 'common.djangoapps.util.memcache.safe_key',
'LOCATION': ['localhost:11211'],
'TIMEOUT': 300,
'BACKEND': 'django.core.cache.backends.memcached.PyMemcacheCache',
'OPTIONS': {
'no_delay': True,
'ignore_exc': True,
'use_pooling': True,
'connect_timeout': 0.5
}
},
'staticfiles': {
'KEY_FUNCTION': 'common.djangoapps.util.memcache.safe_key',
'LOCATION': ['localhost:11211'],
'KEY_PREFIX': 'staticfiles_general',
'BACKEND': 'django.core.cache.backends.memcached.PyMemcacheCache',
'OPTIONS': {
'no_delay': True,
'ignore_exc': True,
'use_pooling': True,
'connect_timeout': 0.5
}
},
'default': {
'VERSION': '1',
'KEY_FUNCTION': 'common.djangoapps.util.memcache.safe_key',
'LOCATION': ['localhost:11211'],
'KEY_PREFIX': 'default',
'BACKEND': 'django.core.cache.backends.memcached.PyMemcacheCache',
'OPTIONS': {
'no_delay': True,
'ignore_exc': True,
'use_pooling': True,
'connect_timeout': 0.5
}
},
'configuration': {
'KEY_FUNCTION': 'common.djangoapps.util.memcache.safe_key',
'LOCATION': ['localhost:11211'],
'KEY_PREFIX': 'configuration',
'BACKEND': 'django.core.cache.backends.memcached.PyMemcacheCache',
'OPTIONS': {
'no_delay': True,
'ignore_exc': True,
'use_pooling': True,
'connect_timeout': 0.5
}
},
'general': {
'KEY_FUNCTION': 'common.djangoapps.util.memcache.safe_key',
'LOCATION': ['localhost:11211'],
'KEY_PREFIX': 'general',
'BACKEND': 'django.core.cache.backends.memcached.PyMemcacheCache',
'OPTIONS': {
'no_delay': True,
'ignore_exc': True,
'use_pooling': True,
'connect_timeout': 0.5
}
},
}
DATABASES = {
# edxapp's edxapp-migrate scripts and the edxapp_migrate play
# will ensure that any DB not named read_replica will be migrated
# for both the lms and cms.
'default': {
'ATOMIC_REQUESTS': True,
'CONN_MAX_AGE': 0,
'ENGINE': 'django.db.backends.mysql',
'HOST': '127.0.0.1',
'NAME': 'edxapp',
'OPTIONS': {},
'PASSWORD': 'password',
'PORT': '3306',
'USER': 'edxapp001'
},
'read_replica': {
'CONN_MAX_AGE': 0,
'ENGINE': 'django.db.backends.mysql',
'HOST': '127.0.0.1',
'NAME': 'edxapp',
'OPTIONS': {},
'PASSWORD': 'password',
'PORT': '3306',
'USER': 'edxapp001'
},
'student_module_history': {
'CONN_MAX_AGE': 0,
'ENGINE': 'django.db.backends.mysql',
'HOST': '127.0.0.1',
'NAME': 'edxapp_csmh',
'OPTIONS': {},
'PASSWORD': 'password',
'PORT': '3306',
'USER': 'edxapp001'
}
}
DEFAULT_AUTO_FIELD = 'django.db.models.AutoField'
DATABASE_ROUTERS = [
'openedx.core.lib.django_courseware_routers.StudentModuleHistoryExtendedRouter',
]
TEMPLATES = [
{
'NAME': 'django',
'BACKEND': 'django.template.backends.django.DjangoTemplates',
# Don't look for template source files inside installed applications.
'APP_DIRS': False,
# Instead, look for template source files in these dirs.
'DIRS': [
Derived(lambda settings: settings.PROJECT_ROOT / "templates"),
COMMON_ROOT / 'templates',
XMODULE_ROOT / 'capa' / 'templates',
COMMON_ROOT / 'djangoapps' / 'pipeline_mako' / 'templates',
COMMON_ROOT / 'static', # required to statically include common Underscore templates
],
# Options specific to this backend.
'OPTIONS': {
'loaders': [
# We have to use mako-aware template loaders to be able to include
# mako templates inside django templates (such as main_django.html).
'openedx.core.djangoapps.theming.template_loaders.ThemeTemplateLoader',
'common.djangoapps.edxmako.makoloader.MakoFilesystemLoader',
'common.djangoapps.edxmako.makoloader.MakoAppDirectoriesLoader',
],
'context_processors': Derived(lambda settings: settings.CONTEXT_PROCESSORS),
# Change 'debug' in your environment settings files - not here.
'debug': False
}
},
{
'NAME': 'mako',
'BACKEND': 'common.djangoapps.edxmako.backend.Mako',
# Don't look for template source files inside installed applications.
'APP_DIRS': False,
# Instead, look for template source files in these dirs.
'DIRS': Derived(make_mako_template_dirs),
# Options specific to this backend.
'OPTIONS': {
'context_processors': Derived(lambda settings: settings.CONTEXT_PROCESSORS),
# Change 'debug' in your environment settings files - not here.
'debug': False,
}
},
]
################################ Templates #################################
def make_mako_module_dir(settings):
"""
Returns the directory where Mako templates are stored.
Args:
settings: A Django settings module object.
Returns:
list: A list of Mako template directories, potentially updated with additional
theme directories.
"""
import tempfile
return os.path.join(tempfile.gettempdir(), f'mako_{settings.SERVICE_VARIANT}')
MAKO_MODULE_DIR = Derived(make_mako_module_dir)
MAKO_TEMPLATE_DIRS_BASE = [
Derived(lambda settings: settings.PROJECT_ROOT / 'templates'),
COMMON_ROOT / 'templates',
COMMON_ROOT / 'djangoapps' / 'pipeline_mako' / 'templates',
OPENEDX_ROOT / 'core' / 'djangoapps' / 'cors_csrf' / 'templates',
OPENEDX_ROOT / 'core' / 'djangoapps' / 'dark_lang' / 'templates',
OPENEDX_ROOT / 'core' / 'lib' / 'license' / 'templates',
]
# Since the CMS uses the LMS's list of mako template directories for the "preview"
# template engine, we define the list here
lms_mako_template_dirs_base = list(MAKO_TEMPLATE_DIRS_BASE)
lms_mako_template_dirs_base.insert(2, XMODULE_ROOT / 'capa' / 'templates')
lms_mako_template_dirs_base.append(OPENEDX_ROOT / 'features' / 'course_experience' / 'templates')
CONTEXT_PROCESSORS = [
'django.template.context_processors.request',
'django.template.context_processors.static',
'django.contrib.messages.context_processors.messages',
'django.template.context_processors.i18n',
'django.contrib.auth.context_processors.auth', # this is required for admin
'django.template.context_processors.csrf',
# Online contextual help
'help_tokens.context_processor',
'openedx.core.djangoapps.site_configuration.context_processors.configuration_context',
]
DEFAULT_TEMPLATE_ENGINE = TEMPLATES[0]
############################## Site Settings ###############################
HTTPS = 'on'
@@ -460,6 +745,62 @@ ALL_LANGUAGES = [
LANGUAGE_DICT = dict(LANGUAGES)
############################## Optional Apps ###############################
OPTIONAL_APPS = [
('problem_builder', 'openedx.core.djangoapps.content.course_overviews.apps.CourseOverviewsConfig'),
('edx_sga', None),
# edx-ora2
('submissions', 'openedx.core.djangoapps.content.course_overviews.apps.CourseOverviewsConfig'),
('openassessment', 'openedx.core.djangoapps.content.course_overviews.apps.CourseOverviewsConfig'),
('openassessment.assessment', 'openedx.core.djangoapps.content.course_overviews.apps.CourseOverviewsConfig'),
('openassessment.fileupload', 'openedx.core.djangoapps.content.course_overviews.apps.CourseOverviewsConfig'),
('openassessment.staffgrader', 'openedx.core.djangoapps.content.course_overviews.apps.CourseOverviewsConfig'),
('openassessment.workflow', 'openedx.core.djangoapps.content.course_overviews.apps.CourseOverviewsConfig'),
('openassessment.xblock', 'openedx.core.djangoapps.content.course_overviews.apps.CourseOverviewsConfig'),
# edxval
('edxval', 'openedx.core.djangoapps.content.course_overviews.apps.CourseOverviewsConfig'),
# Enterprise Apps (http://github.com/openedx/edx-enterprise)
('enterprise', None),
('consent', None),
('integrated_channels.integrated_channel', None),
('integrated_channels.degreed', None),
('integrated_channels.degreed2', None),
('integrated_channels.sap_success_factors', None),
('integrated_channels.cornerstone', None),
('integrated_channels.xapi', None),
('integrated_channels.blackboard', None),
('integrated_channels.canvas', None),
('integrated_channels.moodle', None),
]
def add_optional_apps(optional_apps, installed_apps):
"""
Adds apps from optional_apps to installed_apps if they can be imported.
:param optional_apps: List of tuples (str, str). The tuples should contain the name
of the app and the name of the app which it should be inserted before.
:param installed_apps: List of installed Django apps to modify (i.e. INSTALLED_APPS)
"""
for app_name, insert_before in optional_apps:
# First attempt to only find the module rather than actually importing it,
# to avoid circular references - only try to import if it can't be found
# by find_spec, which doesn't work with import hooks
if importlib.util.find_spec(app_name) is None:
try:
__import__(app_name)
except ImportError:
continue
try:
installed_apps.insert(installed_apps.index(insert_before), app_name)
except (IndexError, ValueError):
installed_apps.append(app_name)
########################## Django Rest Framework ###########################
REST_FRAMEWORK = {
@@ -537,14 +878,17 @@ CELERY_TRACK_STARTED = True
CELERY_SEND_EVENTS = True
CELERY_SEND_TASK_SENT_EVENT = True
# Exchange configuration
CELERY_DEFAULT_EXCHANGE = 'edx.core'
CELERY_DEFAULT_EXCHANGE_TYPE = 'direct'
# Queues configuration
CELERY_QUEUE_HA_POLICY = 'all'
CELERY_CREATE_MISSING_QUEUES = True
# Exchange configuration
CELERY_DEFAULT_EXCHANGE_TYPE = 'direct'
CELERY_DEFAULT_EXCHANGE = Derived(lambda settings: f'edx.{settings.SERVICE_VARIANT}.core')
CELERY_DEFAULT_QUEUE = Derived(lambda settings: settings.DEFAULT_PRIORITY_QUEUE)
CELERY_DEFAULT_ROUTING_KEY = CELERY_DEFAULT_QUEUE = Derived(lambda settings: settings.DEFAULT_PRIORITY_QUEUE)
# Checks run in normal mode by the heartbeat djangoapp
HEARTBEAT_CHECKS = [
'openedx.core.djangoapps.heartbeat.default_checks.check_modulestore',
@@ -558,6 +902,8 @@ HEARTBEAT_EXTENDED_CHECKS = (
HEARTBEAT_CELERY_TIMEOUT = 5
HEARTBEAT_CELERY_ROUTING_KEY = Derived(lambda settings: settings.HIGH_PRIORITY_QUEUE)
############################ RedirectMiddleware ############################
# Setting this to None causes Redirect data to never expire
@@ -614,6 +960,12 @@ JWT_AUTH = {
'JWT_AUTH_HEADER_PREFIX': 'JWT',
}
EDX_DRF_EXTENSIONS = {
# Set this value to an empty dict in order to prevent automatically updating
# user data from values in (possibly stale) JWTs.
'JWT_PAYLOAD_USER_ATTRIBUTE_MAPPING': {},
}
################################# Features #################################
# .. setting_name: PLATFORM_NAME
@@ -1046,107 +1398,8 @@ XQUEUE_INTERFACE = {
}
}
########################### Cache Configuration ############################
CACHES = {
'course_structure_cache': {
'KEY_PREFIX': 'course_structure',
'KEY_FUNCTION': 'common.djangoapps.util.memcache.safe_key',
'LOCATION': ['localhost:11211'],
'TIMEOUT': '604800', # 1 week
'BACKEND': 'django.core.cache.backends.memcached.PyMemcacheCache',
'OPTIONS': {
'no_delay': True,
'ignore_exc': True,
'use_pooling': True,
'connect_timeout': 0.5
}
},
'celery': {
'KEY_PREFIX': 'celery',
'KEY_FUNCTION': 'common.djangoapps.util.memcache.safe_key',
'LOCATION': ['localhost:11211'],
'TIMEOUT': '7200',
'BACKEND': 'django.core.cache.backends.memcached.PyMemcacheCache',
'OPTIONS': {
'no_delay': True,
'ignore_exc': True,
'use_pooling': True,
'connect_timeout': 0.5
}
},
'mongo_metadata_inheritance': {
'KEY_PREFIX': 'mongo_metadata_inheritance',
'KEY_FUNCTION': 'common.djangoapps.util.memcache.safe_key',
'LOCATION': ['localhost:11211'],
'TIMEOUT': 300,
'BACKEND': 'django.core.cache.backends.memcached.PyMemcacheCache',
'OPTIONS': {
'no_delay': True,
'ignore_exc': True,
'use_pooling': True,
'connect_timeout': 0.5
}
},
'staticfiles': {
'KEY_FUNCTION': 'common.djangoapps.util.memcache.safe_key',
'LOCATION': ['localhost:11211'],
'KEY_PREFIX': 'staticfiles_general',
'BACKEND': 'django.core.cache.backends.memcached.PyMemcacheCache',
'OPTIONS': {
'no_delay': True,
'ignore_exc': True,
'use_pooling': True,
'connect_timeout': 0.5
}
},
'default': {
'VERSION': '1',
'KEY_FUNCTION': 'common.djangoapps.util.memcache.safe_key',
'LOCATION': ['localhost:11211'],
'KEY_PREFIX': 'default',
'BACKEND': 'django.core.cache.backends.memcached.PyMemcacheCache',
'OPTIONS': {
'no_delay': True,
'ignore_exc': True,
'use_pooling': True,
'connect_timeout': 0.5
}
},
'configuration': {
'KEY_FUNCTION': 'common.djangoapps.util.memcache.safe_key',
'LOCATION': ['localhost:11211'],
'KEY_PREFIX': 'configuration',
'BACKEND': 'django.core.cache.backends.memcached.PyMemcacheCache',
'OPTIONS': {
'no_delay': True,
'ignore_exc': True,
'use_pooling': True,
'connect_timeout': 0.5
}
},
'general': {
'KEY_FUNCTION': 'common.djangoapps.util.memcache.safe_key',
'LOCATION': ['localhost:11211'],
'KEY_PREFIX': 'general',
'BACKEND': 'django.core.cache.backends.memcached.PyMemcacheCache',
'OPTIONS': {
'no_delay': True,
'ignore_exc': True,
'use_pooling': True,
'connect_timeout': 0.5
}
},
}
################################### CSRF ###################################
CSRF_COOKIE_AGE = 60 * 60 * 24 * 7 * 52
# It is highly recommended that you override this in any environment accessed by
# end users
CSRF_COOKIE_SECURE = False
# If setting a cross-domain cookie, it's really important to choose
# a name for the cookie that is DIFFERENT than the cookies used
# by each subdomain. For example, suppose the applications
@@ -1174,8 +1427,6 @@ CROSS_DOMAIN_CSRF_COOKIE_NAME = ''
# the client won't be able to read the cookie.
CROSS_DOMAIN_CSRF_COOKIE_DOMAIN = ''
CSRF_TRUSTED_ORIGINS = []
ENABLE_CROSS_DOMAIN_CSRF_COOKIE = False
########################## Cross-domain Requests ###########################
@@ -1212,6 +1463,21 @@ SOCIAL_MEDIA_LOGO_URLS = {
'facebook': 'http://email-media.s3.amazonaws.com/edX/2021/social_1_fb.png',
}
########################### Social Media Sharing ###########################
# Social Media Sharing on Student Dashboard
SOCIAL_SHARING_SETTINGS = {
'CUSTOM_COURSE_URLS': False, # This value should not differ between lms/cms
'DASHBOARD_FACEBOOK': False,
'CERTIFICATE_FACEBOOK': False,
'CERTIFICATE_TWITTER': False,
'DASHBOARD_TWITTER': False,
}
############################# Google Analytics #############################
GOOGLE_ANALYTICS_ACCOUNT = None
############################# Block Structures #############################
# .. setting_name: BLOCK_STRUCTURES_SETTINGS
@@ -1316,6 +1582,16 @@ VIDEO_TRANSCRIPTS_SETTINGS = dict(
VIDEO_TRANSCRIPTS_MAX_AGE = 31536000
TRANSCRIPT_LANG_CACHE_TIMEOUT = 60 * 60 * 24 # 24 hours
############################## Video Pipeline ##############################
VIDEO_UPLOAD_PIPELINE = {
'VEM_S3_BUCKET': '',
'BUCKET': '',
'ROOT_PATH': '',
}
############################ Parental Controls #############################
# .. setting_name: PARENTAL_CONSENT_AGE_LIMIT
@@ -1366,6 +1642,30 @@ SHOW_ACTIVATE_CTA_POPUP_COOKIE_NAME = 'show-account-activation-popup'
# .. toggle_creation_date: 2021-06-10
SHOW_ACCOUNT_ACTIVATION_CTA = False
# .. setting_name: REGISTRATION_EXTRA_FIELDS
# .. setting_default: {'confirm_email': 'hidden', 'level_of_education': 'optional', 'gender': 'optional',
# 'year_of_birth': 'optional', 'mailing_address': 'optional', 'goals': 'optional', 'honor_code': 'required',
# 'terms_of_service': 'hidden', 'city': 'hidden', 'country': 'hidden'}
# .. setting_description: The signup form may contain extra fields that are presented to every user. For every field, we
# can specifiy whether it should be "required": to display the field, and make it mandatory; "optional": to display
# the optional field as part of a toggled input field list; "optional-exposed": to display the optional fields among
# the required fields, and make it non-mandatory; "hidden": to not display the field.
# When the terms of service are not visible and agreement to the honor code is required (the default), the signup page
# includes a paragraph that links to the honor code page (defined my MKTG_URLS["HONOR"]). This page might not be
# available for all Open edX platforms. In such cases, the "honor_code" registration field should be "hidden".
REGISTRATION_EXTRA_FIELDS = {
'confirm_email': 'hidden',
'level_of_education': 'optional',
'gender': 'optional',
'year_of_birth': 'optional',
'mailing_address': 'optional',
'goals': 'optional',
'honor_code': 'required',
'terms_of_service': 'hidden',
'city': 'hidden',
'country': 'hidden',
}
######################### Course Enrollment Modes ##########################
# The min_price key refers to the minimum price allowed for an instance
@@ -1465,45 +1765,81 @@ ENTERPRISE_BACKEND_SERVICE_EDX_OAUTH2_PROVIDER_URL = "http://127.0.0.1:8000/oaut
ASSET_IGNORE_REGEX = r"(^\._.*$)|(^\.DS_Store$)|(^.*~$)"
DATABASES = {
# edxapp's edxapp-migrate scripts and the edxapp_migrate play
# will ensure that any DB not named read_replica will be migrated
# for both the lms and cms.
# This Django setting was removed in Django 4.0, but it is still being referenced
# in the code. It would be worth investigating if we still need this and, if we do,
# leave a comment explaining why here. See https://github.com/openedx/edx-platform/issues/37744.
DEFAULT_HASHING_ALGORITHM = 'sha256'
DOC_STORE_CONFIG = {
'db': 'edxapp',
'host': 'localhost',
'replicaSet': '',
'port': 27017,
'user': 'edxapp',
'collection': 'modulestore',
'ssl': False,
# https://api.mongodb.com/python/2.9.1/api/pymongo/mongo_client.html#module-pymongo.mongo_client
# default is never timeout while the connection is open,
#this means it needs to explicitly close raising pymongo.errors.NetworkTimeout
'socketTimeoutMS': 6000,
'connectTimeoutMS': 2000, # default is 20000, I believe raises pymongo.errors.ConnectionFailure
# Not setting waitQueueTimeoutMS and waitQueueMultiple since pymongo defaults to nobody being allowed to wait
'auth_source': None,
# If 'asset_collection' defined, it'll be used as the collection name for asset metadata.
# Otherwise, a default collection name will be used.
}
CONTENTSTORE = {
'ENGINE': 'xmodule.contentstore.mongo.MongoContentStore',
# connection strings are duplicated temporarily for
# backward compatibility
'OPTIONS': {
'db': 'edxapp',
'host': 'localhost',
'password': 'password',
'port': 27017,
'user': 'edxapp',
'ssl': False,
'auth_source': None
},
'ADDITIONAL_OPTIONS': {},
'DOC_STORE_CONFIG': DOC_STORE_CONFIG
}
MODULESTORE = {
'default': {
'ATOMIC_REQUESTS': True,
'CONN_MAX_AGE': 0,
'ENGINE': 'django.db.backends.mysql',
'HOST': '127.0.0.1',
'NAME': 'edxapp',
'OPTIONS': {},
'PASSWORD': 'password',
'PORT': '3306',
'USER': 'edxapp001'
},
'read_replica': {
'CONN_MAX_AGE': 0,
'ENGINE': 'django.db.backends.mysql',
'HOST': '127.0.0.1',
'NAME': 'edxapp',
'OPTIONS': {},
'PASSWORD': 'password',
'PORT': '3306',
'USER': 'edxapp001'
},
'student_module_history': {
'CONN_MAX_AGE': 0,
'ENGINE': 'django.db.backends.mysql',
'HOST': '127.0.0.1',
'NAME': 'edxapp_csmh',
'OPTIONS': {},
'PASSWORD': 'password',
'PORT': '3306',
'USER': 'edxapp001'
'ENGINE': 'xmodule.modulestore.mixed.MixedModuleStore',
'OPTIONS': {
'mappings': {},
'stores': [
{
'NAME': 'split',
'ENGINE': 'xmodule.modulestore.split_mongo.split_draft.DraftVersioningModuleStore',
'DOC_STORE_CONFIG': DOC_STORE_CONFIG,
'OPTIONS': {
'default_class': 'xmodule.hidden_block.HiddenBlock',
'fs_root': Derived(lambda settings: settings.DATA_DIR),
'render_template': 'common.djangoapps.edxmako.shortcuts.render_to_string',
}
},
{
'NAME': 'draft',
'ENGINE': 'xmodule.modulestore.mongo.DraftMongoModuleStore',
'DOC_STORE_CONFIG': DOC_STORE_CONFIG,
'OPTIONS': {
'default_class': 'xmodule.hidden_block.HiddenBlock',
'fs_root': Derived(lambda settings: settings.DATA_DIR),
'render_template': 'common.djangoapps.edxmako.shortcuts.render_to_string',
}
}
]
}
}
}
DEFAULT_AUTO_FIELD = 'django.db.models.AutoField'
DEFAULT_HASHING_ALGORITHM = 'sha256'
# Modulestore-level field override providers. These field override providers don't
# require student context.
MODULESTORE_FIELD_OVERRIDE_PROVIDERS = ()
############################# Micro-frontends ##############################
@@ -1652,6 +1988,21 @@ XBLOCK_SETTINGS = {}
# .. setting_description: The django cache key of the cache to use for storing anonymous user state for XBlocks.
XBLOCK_RUNTIME_V2_EPHEMERAL_DATA_CACHE = 'default'
# These are the Mixins that will be added to every Blocklike upon instantiation.
# DO NOT EXPAND THIS LIST!! We want it eventually to be EMPTY. Why? Because dynamically adding functions/behaviors to
# objects at runtime is confusing for both developers and static tooling (pylint/mypy). Instead...
# - to add special Blocklike behaviors just for your site: override `XBLOCK_EXTRA_MIXINS` with your own XBlockMixins.
# - to add new functionality to all Blocklikes: add it to the base Blocklike class in the core openedx/XBlock repo.
XBLOCK_MIXINS = (
# TODO: For each of these, either
# (a) merge their functionality into the base Blocklike class, or
# (b) refactor their functionality out of the Blocklike objects and into the edx-platform block runtimes.
LmsBlockMixin,
InheritanceMixin,
XModuleMixin,
EditInfoMixin,
)
######################## Built-in Blocks Extraction ########################
# The following Django settings flags have been introduced temporarily to facilitate
@@ -1748,9 +2099,15 @@ EDXMKTG_USER_INFO_COOKIE_VERSION = 1
MKTG_URLS = {}
MKTG_URL_OVERRIDES = {}
MKTG_URL_LINK_MAP = {}
SUPPORT_SITE_LINK = ''
ACTIVATION_EMAIL_SUPPORT_LINK = Derived(lambda settings: settings.SUPPORT_SITE_LINK)
ID_VERIFICATION_SUPPORT_LINK = Derived(lambda settings: settings.SUPPORT_SITE_LINK)
LOGIN_ISSUE_SUPPORT_LINK = Derived(lambda settings: settings.SUPPORT_SITE_LINK)
PASSWORD_RESET_SUPPORT_LINK = Derived(lambda settings: settings.SUPPORT_SITE_LINK)
################################# ChatGPT ##################################
CHAT_COMPLETION_API = ''
@@ -1791,6 +2148,31 @@ ZENDESK_GROUP_ID_MAPPING = {}
############################## Python sandbox ##############################
CODE_JAIL = {
# from https://github.com/openedx/codejail/blob/master/codejail/django_integration.py#L24, '' should be same as None
'python_bin': '/edx/app/edxapp/venvs/edxapp-sandbox/bin/python',
# User to run as in the sandbox.
'user': 'sandbox',
# Configurable limits.
'limits': {
# How many CPU seconds can jailed code use?
'CPU': 1,
# Limit the memory of the jailed process to something high but not
# infinite (512MiB in bytes)
'VMEM': 536870912,
# Time in seconds that the jailed process has to run.
'REALTIME': 3,
'PROXY': 0,
},
# Overrides to default configurable 'limits' (above).
# Keys should be course run ids (or, in the special case of code running
# on the /debug/run_python page, the key is 'debug_run_python').
# Values should be dictionaries that look like 'limits'.
"limit_overrides": {},
}
# Some courses are allowed to run unsafe code. This is a list of regexes, one
# of them must match the course id for that course to run unsafe code.
#
@@ -1831,8 +2213,6 @@ CODE_JAIL_REST_SERVICE_READ_TIMEOUT = 3.5 # time in seconds
# Locale/Internationalization
CELERY_TIMEZONE = 'UTC'
TIME_ZONE = 'UTC'
LANGUAGE_CODE = 'en' # http://www.i18nguy.com/unicode/language-identifiers.html
# Languages supported for custom course certificate templates
CERTIFICATE_TEMPLATE_LANGUAGES = {
@@ -1840,26 +2220,58 @@ CERTIFICATE_TEMPLATE_LANGUAGES = {
'es': 'Español',
}
USE_I18N = True
USE_L10N = True
STATICI18N_FILENAME_FUNCTION = 'statici18n.utils.legacy_filename'
STATICI18N_OUTPUT_DIR = "js/i18n"
STATICI18N_ROOT = Derived(lambda settings: settings.PROJECT_ROOT / "static")
################################# Pipeline #################################
PIPELINE = {
'PIPELINE_ENABLED': True,
# Don't use compression by default
'CSS_COMPRESSOR': None,
# Don't wrap JavaScript as there is code that depends upon updating the global namespace
'DISABLE_WRAPPER': True,
# Specify the UglifyJS binary to use
'UGLIFYJS_BINARY': 'node_modules/.bin/uglifyjs',
}
STATICFILES_STORAGE_KWARGS = {}
# List of finder classes that know how to find static files in various locations.
# Note: the pipeline finder is included to be able to discover optimized files
STATICFILES_FINDERS = [
'openedx.core.djangoapps.theming.finders.ThemeFilesFinder',
'django.contrib.staticfiles.finders.FileSystemFinder',
'django.contrib.staticfiles.finders.AppDirectoriesFinder',
'openedx.core.lib.xblock_pipeline.finder.XBlockPipelineFinder',
'pipeline.finders.PipelineFinder',
STATICFILES_IGNORE_PATTERNS = [
"*.py",
"*.pyc",
# It would be nice if we could do, for example, "**/*.scss",
# but these strings get passed down to the `fnmatch` module,
# which doesn't support that. :(
# http://docs.python.org/2/library/fnmatch.html
"sass/*.scss",
"sass/*/*.scss",
"sass/*/*/*.scss",
"sass/*/*/*/*.scss",
# Ignore tests
"spec",
"spec_helpers",
# Symlinks used by js-test-tool
"xmodule_js",
]
########################## Django Webpack Loader ###########################
WEBPACK_LOADER = {
'DEFAULT': {
'BUNDLE_DIR_NAME': 'bundles/',
'STATS_FILE': Derived(lambda settings: os.path.join(settings.STATIC_ROOT, 'webpack-stats.json')),
},
'WORKERS': {
'BUNDLE_DIR_NAME': 'bundles/',
'STATS_FILE': Derived(lambda settings: os.path.join(settings.STATIC_ROOT, 'webpack-worker-stats.json')),
}
}
############################## django-require ##############################
# The baseUrl to pass to the r.js optimizer, relative to STATIC_ROOT.
@@ -1868,6 +2280,12 @@ REQUIRE_BASE_URL = "./"
# Whether to run django-require in debug mode.
REQUIRE_DEBUG = False
# The name of a build profile to use for your project, relative to REQUIRE_BASE_URL.
# A sensible value would be 'app.build.js'. Leave blank to use the built-in default build profile.
# Set to False to disable running the default profile (e.g. if only using it to build Standalone
# Modules)
REQUIRE_BUILD_PROFILE = Derived(lambda settings: f"{settings.SERVICE_VARIANT}/js/build.js")
########################### Student Verification ###########################
VERIFY_STUDENT = {
@@ -1992,7 +2410,6 @@ DEFAULT_SITE_THEME = None
# .. toggle_creation_date: 2016-06-30
ENABLE_COMPREHENSIVE_THEMING = False
################################ Ecommerce #################################
ECOMMERCE_PUBLIC_URL_ROOT = 'http://localhost:8002'
@@ -2068,7 +2485,7 @@ PASSWORD_RESET_EMAIL_RATE = '2/h'
HELP_TOKENS_LANGUAGE_CODE = Derived(lambda settings: settings.LANGUAGE_CODE)
HELP_TOKENS_VERSION = Derived(lambda settings: doc_version())
HELP_TOKENS_INI_FILE = Derived(lambda settings: REPO_ROOT / settings.SERVICE_VARIANT / "envs" / "help_tokens.ini")
HELP_TOKENS_BOOKS = {
'learner': 'https://docs.openedx.org/en/latest/learners',
'course_author': 'https://docs.openedx.org/en/latest/educators',
@@ -2245,9 +2662,92 @@ AI_TRANSLATIONS_API_URL = 'http://localhost:18760/api/v1'
def should_send_learning_badge_events(settings):
return settings.BADGES_ENABLED
############################## ALLOWED_HOSTS ###############################
# .. setting_name: EVENT_BUS_PRODUCER_CONFIG
# .. setting_default: all events disabled
# .. setting_description: Dictionary of event_types mapped to dictionaries of topic to topic-related configuration.
# Each topic configuration dictionary contains
# * `enabled`: a toggle denoting whether the event will be published to the topic. These should be annotated
# according to
# https://docs.openedx.org/projects/edx-toggles/en/latest/how_to/documenting_new_feature_toggles.html
# * `event_key_field` which is a period-delimited string path to event data field to use as event key.
# Note: The topic names should not include environment prefix as it will be dynamically added based on
# EVENT_BUS_TOPIC_PREFIX setting.
EVENT_BUS_PRODUCER_CONFIG = {
"org.openedx.learning.course.passing.status.updated.v1": {
"learning-badges-lifecycle": {
"event_key_field": "course_passing_status.course.course_key",
"enabled": Derived(should_send_learning_badge_events),
},
},
"org.openedx.learning.ccx.course.passing.status.updated.v1": {
"learning-badges-lifecycle": {
"event_key_field": "course_passing_status.course.ccx_course_key",
"enabled": Derived(should_send_learning_badge_events),
},
},
}
ALLOWED_HOSTS = ['*']
### event tracking
EVENT_TRACKING_ENABLED = True
EVENT_TRACKING_PROCESSORS = []
EVENT_TRACKING_SEGMENTIO_EMIT_WHITELIST = []
# FIXME: Should we be doing this truncation?
TRACK_MAX_EVENT = 50000
TRACKING_BACKENDS = {
'logger': {
'ENGINE': 'common.djangoapps.track.backends.logger.LoggerBackend',
'OPTIONS': {
'name': 'tracking'
}
}
}
EVENT_TRACKING_BACKENDS = {
'tracking_logs': {
'ENGINE': 'eventtracking.backends.routing.RoutingBackend',
'OPTIONS': {
'backends': {
'logger': {
'ENGINE': 'eventtracking.backends.logger.LoggerBackend',
'OPTIONS': {
'name': 'tracking',
'max_event_size': TRACK_MAX_EVENT,
}
}
},
'processors': [
{'ENGINE': 'common.djangoapps.track.shim.LegacyFieldMappingProcessor'},
{'ENGINE': 'common.djangoapps.track.shim.PrefixedEventProcessor'}
]
}
},
'segmentio': {
'ENGINE': 'eventtracking.backends.routing.RoutingBackend',
'OPTIONS': {
'backends': {
'segment': {'ENGINE': 'eventtracking.backends.segment.SegmentBackend'}
},
'processors': [
{
'ENGINE': 'eventtracking.processors.whitelist.NameWhitelistProcessor',
'OPTIONS': {
'whitelist': []
}
},
{
'ENGINE': 'common.djangoapps.track.shim.GoogleAnalyticsProcessor'
}
]
}
}
}
# We're already logging events, and we don't want to capture user
# names/passwords. Heartbeat events are likely not interesting.
TRACKING_IGNORE_URL_PATTERNS = [r'^/event', r'^/login', r'^/heartbeat']
############################## Miscellaneous ###############################
@@ -2299,6 +2799,9 @@ VIDEO_CDN_URL = {
SOFTWARE_SECURE_VERIFICATION_ROUTING_KEY = Derived(lambda settings: settings.HIGH_PRIORITY_QUEUE)
# Queue to use for updating persistent grades
RECALCULATE_GRADES_ROUTING_KEY = Derived(lambda settings: settings.DEFAULT_PRIORITY_QUEUE)
# Queue to use for updating grades due to grading policy change
POLICY_CHANGE_GRADES_ROUTING_KEY = Derived(lambda settings: settings.DEFAULT_PRIORITY_QUEUE)
@@ -2340,11 +2843,6 @@ SOFTWARE_SECURE_RETRY_MAX_ATTEMPTS = 6
MARKETING_EMAILS_OPT_IN = False
# Set request limits for maximum size of a request body and maximum number of GET/POST parameters. (>=Django 1.10)
# Limits are currently disabled - but can be used for finer-grained denial-of-service protection.
DATA_UPLOAD_MAX_MEMORY_SIZE = None
DATA_UPLOAD_MAX_NUMBER_FIELDS = None
# License for serving content in China
ICP_LICENSE = None
ICP_LICENSE_INFO = {}
@@ -2443,3 +2941,15 @@ FEEDBACK_SUBMISSION_EMAIL = ''
COURSE_LIVE_GLOBAL_CREDENTIALS = {}
BEAMER_PRODUCT_ID = ""
# For geolocation ip database
GEOIP_PATH = REPO_ROOT / "common/static/data/geoip/GeoLite2-Country.mmdb"
# .. toggle_name: WIKI_ENABLED
# .. toggle_implementation: DjangoSetting
# .. toggle_default: True
# .. toggle_description: This setting allows us to have a collaborative tool to contribute or
# modify content of course related materials.
# .. toggle_use_cases: open_edx
# .. toggle_creation_date: 2012-07-13
WIKI_ENABLED = True

View File

@@ -90,7 +90,6 @@ PARENTAL_CONSENT_AGE_LIMIT = 13
# Test theme
TEST_THEME = Derived(lambda settings: settings.COMMON_ROOT / "test" / "test-theme")
ENABLE_COMPREHENSIVE_THEMING = True
COMPREHENSIVE_THEME_DIRS = Derived(lambda settings: [settings.REPO_ROOT / "themes", settings.REPO_ROOT / "common/test"])
# Enable EdxNotes for tests
ENABLE_EDXNOTES = True

View File

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