diff --git a/.circleci/config.yml b/.circleci/config.yml index 99178b92..24fdced6 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -163,21 +163,14 @@ jobs: # # Note that the job name should match the EDX_RELEASE value - # No changes detected for dogwood.3-bare # No changes detected for dogwood.3-fun # No changes detected for eucalyptus.3-bare # No changes detected for eucalyptus.3-wb - # Run jobs for the hawthorn.1-bare release - hawthorn.1-bare: - <<: [*defaults, *build_steps] - # Run jobs for the hawthorn.1-oee release - hawthorn.1-oee: - <<: [*defaults, *build_steps] + # No changes detected for hawthorn.1-bare + # No changes detected for hawthorn.1-oee # No changes detected for ironwood.2-bare # No changes detected for ironwood.2-oee - # Run jobs for the master.0-bare release - master.0-bare: - <<: [*defaults, *build_steps] + # No changes detected for master.0-bare # Hub job hub: @@ -266,33 +259,14 @@ workflows: # Build jobs - # No changes detected so no job to run for dogwood.3-bare # No changes detected so no job to run for dogwood.3-fun # No changes detected so no job to run for eucalyptus.3-bare # No changes detected so no job to run for eucalyptus.3-wb - # Run jobs for the hawthorn.1-bare release - - hawthorn.1-bare: - requires: - - check-configuration - filters: - tags: - ignore: /.*/ - # Run jobs for the hawthorn.1-oee release - - hawthorn.1-oee: - requires: - - check-configuration - filters: - tags: - ignore: /.*/ + # No changes detected so no job to run for hawthorn.1-bare + # No changes detected so no job to run for hawthorn.1-oee # No changes detected so no job to run for ironwood.2-bare # No changes detected so no job to run for ironwood.2-oee - # Run jobs for the master.0-bare release - - master.0-bare: - requires: - - check-configuration - filters: - tags: - ignore: /.*/ + # No changes detected so no job to run for master.0-bare # We are pushing to Docker only images that are the result of a tag respecting the pattern: # **{branch-name}-x.y.z** diff --git a/releases/dogwood/3/bare/CHANGELOG.md b/releases/dogwood/3/bare/CHANGELOG.md deleted file mode 100644 index ae54fe92..00000000 --- a/releases/dogwood/3/bare/CHANGELOG.md +++ /dev/null @@ -1,127 +0,0 @@ -# Changelog - -All notable changes to this project will be documented in this file. - -The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), -and this project adheres to [Semantic -Versioning](https://semver.org/spec/v2.0.0.html) for each flavored OpenEdx -release. - -## [Unreleased] - -- Fix pip install for python 2.7 - -## [dogwood.3-1.3.1] - 2020-11-10 - -### Fixed - -- Fix missing `DEFAULT_COURSE_ABOUT_IMAGE_URL` setting in cms config -- Pin splinter to 0.13.0 to avoid breaking change in 0.14.0 - -## [dogwood.3-1.3.0] - 2020-05-14 - -### Added - -- Allow serving static files via a CDN -- Rate limiting authentication backend that works behind proxies - -### Changed - -- Collect static files in the `edxapp` image so it can run without mounting a volume - for its static files in Kubernetes -- Refactor the way authentication backends are configured to make it straightforward -- Set basic authentification backend for development environment - -## [dogwood.3-1.2.2] - 2020-03-13 - -### Fixed - -- Fix setting AUTHENTICATION_BACKENDS to allow activating third party authentication -- Remove hardcoded FILE_UPLOAD_STORAGE_BUCKET_NAME value to make sure it is configurable -- Downgrade and pin `virtualenv` to version 16.7.9 - -## [dogwood.3-1.2.1] - 2020-01-11 - -### Removed - -- Checks that ensure required directories exist in volumes - -## [dogwood.3-1.2.0] - 2020-01-10 - -### Added - -- Make Gunicorn timeout, workers and threads configurable via - an environment variable -- Configure all cache backends - -### Changed - -- Make ORA2 configurable and use filesystem backend by default -- Stop inheriting from MKTG_URL_LINK_MAP default setting - -### Fixed - -- Ensure all required directories exist inside each volume -- Refactor settings to repair and clean what is cms versus lms, configurable - versus defined by code. - -## [dogwood.3-1.1.5] - 2019-12-24 - -### Fixed - -- `AUTH_TOKENS` was wrongly used as a dictionary and default values were lost - -## [dogwood.3-1.1.4] - 2019-12-19 - -### Fixed - -- Add missing setting `LMS_ROOT_URL` used to compute absolute urls -- Fix broken CMS JS build by enabling Pipeline's static files storage -- Configure `general` cache backend including cache keys sanitizing function -- Fix `GITHUB_REPO_ROOT` and `DATA_DIR` settings - -## [dogwood.3-1.1.3] - 2019-12-15 - -### Fixed - -- Properly configure locales -- Use pyOpenSSL instead of local openssl library for SSL certificate checking - -## [dogwood.3-1.1.2] - 2019-12-10 - -### Fixed - -- Set CELERY_ACCEPT_CONTENT CMS setting to 'json' to prevent permission issues - while running in an OpenShift context - -## [dogwood.3-1.1.1] - 2019-11-29 - -### Fixed - -- Add missing RELEASE setting - -## [dogwood.3-1.1.0] - 2019-10-10 - -### Changed - -- Add LOCALE_PATHS to configurable settings - -## [dogwood.3-1.0.0] - 2019-09-24 - -### Added - -First experimental release of OpenEdx `dogwood.3` (bare flavor). - -[unreleased]: https://github.com/openfun/openedx-docker/compare/dogwood.3-1.3.1...HEAD -[dogwood.3-1.3.1]: https://github.com/openfun/openedx-docker/compare/tag/dogwood.3-1.3.0...dogwood.3-1.3.1 -[dogwood.3-1.3.0]: https://github.com/openfun/openedx-docker/compare/tag/dogwood.3-1.2.2...dogwood.3-1.3.0 -[dogwood.3-1.2.2]: https://github.com/openfun/openedx-docker/compare/tag/dogwood.3-1.2.1...dogwood.3-1.2.2 -[dogwood.3-1.2.1]: https://github.com/openfun/openedx-docker/compare/tag/dogwood.3-1.2.0...dogwood.3-1.2.1 -[dogwood.3-1.2.0]: https://github.com/openfun/openedx-docker/compare/tag/dogwood.3-1.1.5...dogwood.3-1.2.0 -[dogwood.3-1.1.5]: https://github.com/openfun/openedx-docker/compare/tag/dogwood.3-1.1.4...dogwood.3-1.1.5 -[dogwood.3-1.1.4]: https://github.com/openfun/openedx-docker/compare/tag/dogwood.3-1.1.3...dogwood.3-1.1.4 -[dogwood.3-1.1.3]: https://github.com/openfun/openedx-docker/compare/tag/dogwood.3-1.1.2...dogwood.3-1.1.3 -[dogwood.3-1.1.2]: https://github.com/openfun/openedx-docker/compare/tag/dogwood.3-1.1.1...dogwood.3-1.1.2 -[dogwood.3-1.1.1]: https://github.com/openfun/openedx-docker/compare/tag/dogwood.3-1.1.0...dogwood.3-1.1.1 -[dogwood.3-1.1.0]: https://github.com/openfun/openedx-docker/compare/tag/dogwood.3-1.0.0...dogwood.3-1.1.0 -[dogwood.3-1.0.0]: https://github.com/openfun/openedx-docker/releases/tag/dogwood.3-1.0.0 diff --git a/releases/dogwood/3/bare/Dockerfile b/releases/dogwood/3/bare/Dockerfile deleted file mode 100644 index 15e99821..00000000 --- a/releases/dogwood/3/bare/Dockerfile +++ /dev/null @@ -1,340 +0,0 @@ -# EDX-PLATFORM multi-stage docker build - -# Change release to build, by providing the EDX_RELEASE_REF build argument to -# your build command: -# -# $ docker build \ -# --build-arg EDX_RELEASE_REF="named-release/dogwood.3" \ -# -t edxapp:dogwood.3 \ -# . -ARG DOCKER_UID=1000 -ARG DOCKER_GID=1000 -ARG EDX_RELEASE_REF=named-release/dogwood.3 -ARG EDXAPP_STATIC_ROOT=/edx/app/edxapp/staticfiles -ARG NGINX_IMAGE_NAME=fundocker/openshift-nginx -ARG NGINX_IMAGE_TAG=1.13 - -# === BASE === -FROM ubuntu:12.04 as base - -# Configure locales and timezone -RUN apt-get update && \ - apt-get install -y \ - gettext \ - libreadline6 \ - locales \ - tzdata && \ - rm -rf /var/lib/apt/lists/* -RUN echo 'en_US.UTF-8 UTF-8' > /var/lib/locales/supported.d/local && \ - dpkg-reconfigure locales -ENV LANG en_US.UTF-8 -ENV LANGUAGE en_US:en -ENV LC_ALL en_US.UTF-8 - - -# === DOWNLOAD === -FROM base as downloads - -WORKDIR /downloads - -# Install curl -RUN apt-get update && \ - apt-get install -y curl - -# Download pip installer for python 2.7 -RUN curl -sLo get-pip.py https://bootstrap.pypa.io/2.7/get-pip.py - -# Download edxapp release -# Get default EDX_RELEASE_REF value (defined on top) -ARG EDX_RELEASE_REF -RUN curl -sLo edxapp.tgz https://github.com/edx/edx-platform/archive/$EDX_RELEASE_REF.tar.gz && \ - tar xzf edxapp.tgz - - -# === EDXAPP === -FROM base as edxapp - -# Install apt https support (required to use node sources repository) -RUN apt-get update && \ - apt-get upgrade -y && \ - apt-get install -y \ - apt-transport-https - -# Add a recent release of nodejs to apt sources (ubuntu package for precise is -# broken) -RUN echo "deb https://deb.nodesource.com/node_10.x trusty main" \ - > /etc/apt/sources.list.d/nodesource.list && \ - curl -s 'https://deb.nodesource.com/gpgkey/nodesource.gpg.key' | apt-key add - - -# Install base system dependencies -RUN apt-get update && \ - apt-get install -y \ - nodejs \ - python && \ - rm -rf /var/lib/apt/lists/* - -WORKDIR /edx/app/edxapp/edx-platform - -# Get default EDX_RELEASE_REF value (defined on top) -ARG EDX_RELEASE_REF -COPY --from=downloads /downloads/edx-platform-* . - -# We copy default configuration files to "/config" and we point to them via -# symlinks. That allows to easily override default configurations by mounting a -# docker volume. -COPY ./config /config -RUN ln -sf /config/lms /edx/app/edxapp/edx-platform/lms/envs/fun && \ - ln -sf /config/cms /edx/app/edxapp/edx-platform/cms/envs/fun - -# Add node_modules/.bin to the PATH so that paver-related commands can execute -# node scripts -ENV PATH="/edx/app/edxapp/edx-platform/node_modules/.bin:${PATH}" - -# OpenEdx requires this environment variable to be defined, or else, it will -# try to get the current Git reference. Since we don't use a Git clone to -# build this release, we force the revision to be the release reference. -ENV EDX_PLATFORM_REVISION=${EDX_RELEASE_REF:-named-release/dogwood.3} - - -# === BUILDER === -FROM edxapp as builder - -WORKDIR /builder - -# Install builder system dependencies -RUN apt-get update && \ - apt-get upgrade -y && \ - apt-get install -y \ - build-essential \ - curl \ - gfortran \ - git-core \ - graphviz \ - graphviz-dev \ - language-pack-en \ - libffi-dev \ - libfreetype6-dev \ - libgeos-dev \ - libjpeg8-dev \ - liblapack-dev \ - libmysqlclient-dev \ - libxml2-dev \ - libxmlsec1-dev \ - libxslt1-dev \ - pkg-config \ - python-apt \ - python-dev \ - rdfind \ - ruby1.9.1-dev \ - rubygems1.9.1 \ - software-properties-common \ - swig && \ - rm -rf /var/lib/apt/lists/* - -WORKDIR /edx/app/edxapp/edx-platform - -# Install Javascript requirements -RUN npm install - -# Install Ruby dependencies -RUN gem install bundler -v 1.17.3 && \ - bundle install - -# Install the latest pip release -COPY --from=downloads /downloads/get-pip.py ./get-pip.py -RUN python get-pip.py - -# Install python dependencies -# -# Note that we force some pinned release installations before installing github -# dependencies to prevent secondary dependencies installation to fail while -# trying to install a python 2.7 incompatible release -RUN pip install -r requirements/edx/pre.txt -RUN pip install \ - astroid==1.6.0 \ - django==1.8.12 \ - pip==9.0.3 \ - splinter==0.13.0 -RUN pip install --src /usr/local/src -r requirements/edx/github.txt -RUN pip install -r requirements/edx/base.txt -RUN pip install -r requirements/edx/paver.txt -RUN pip install -r requirements/edx/post.txt -RUN pip install -r requirements/edx/local.txt -# Install extra dependencies -# -# Redis is an extra requirement of Celery, we need to install it explicitly so -# that celery workers are effective. -# -# Requests should be upgraded with a recent secure flavor of urrllib3 to -# prevent SSL certificate validation failure (we should use pyOpenSSL instead -# of the local openssl library). For reference, see: -# https://urllib3.readthedocs.io/en/latest/user-guide.html#ssl-py2 -# -# The version of gunicorn shipped with Open edX is too old. We want to use a -# recent version to be able to configure threads with gthread worker class. -RUN pip install --upgrade \ - redis==3.3.7 \ - requests==2.22.0 \ - urllib3[secure]==1.25.7 \ - gunicorn==19.9.0 - -# Update assets skipping collectstatic (it should be done during deployment) -RUN NO_PREREQ_INSTALL=1 \ - paver update_assets --settings=fun.docker_build_production --skip-collect - -# === STATIC LINKS COLLECTOR === -FROM builder as links_collector - -ARG EDXAPP_STATIC_ROOT - -RUN python manage.py lms collectstatic --link --noinput --settings=fun.docker_run && \ - python manage.py cms collectstatic --link --noinput --settings=fun.docker_run - -# Replace duplicated file by a symlink to decrease the overall size of the -# final image -RUN rdfind -makesymlinks true -followsymlinks true ${EDXAPP_STATIC_ROOT} - -# === STATIC FILES COLLECTOR === -FROM builder as files_collector - -ARG EDXAPP_STATIC_ROOT - -RUN python manage.py lms collectstatic --noinput --settings=fun.docker_run && \ - python manage.py cms collectstatic --noinput --settings=fun.docker_run - -# Replace duplicated file by a symlink to decrease the overall size of the -# final image -RUN rdfind -makesymlinks true ${EDXAPP_STATIC_ROOT} - -# === DEVELOPMENT === -FROM builder as development - -ARG DOCKER_UID -ARG DOCKER_GID -ARG EDX_RELEASE_REF - -# Install system dependencies -RUN apt-get update && \ - apt-get upgrade -y && \ - apt-get install -y \ - libsqlite3-dev \ - mongodb && \ - rm -rf /var/lib/apt/lists/* - -RUN groupadd --gid ${DOCKER_GID} edx || \ - echo "Group with ID ${DOCKER_GID} already exists." && \ - useradd \ - --create-home \ - --home-dir /home/edx \ - --uid ${DOCKER_UID} \ - --gid ${DOCKER_GID} \ - edx || \ - echo "Skip user creation (user with ID ${DOCKER_UID} already exists?)" && \ - git config --global user.name edx && \ - git config --global user.email edx@example.com - -# To prevent permission issues related to the non-priviledged user running in -# development, we will install development dependencies in a python virtual -# environment belonging to that user -RUN pip install virtualenv==16.7.9 - -# Create the virtualenv directory where we will install python development -# dependencies -RUN mkdir -p /edx/app/edxapp/venv && \ - chown -R ${DOCKER_UID}:${DOCKER_GID} /edx/app/edxapp/venv - -# Change edxapp directory owner to allow the development image docker user to -# perform installations from edxapp sources (yeah, I know...) -RUN chown -R ${DOCKER_UID}:${DOCKER_GID} /edx/app/edxapp - -# Copy the entrypoint that will activate the virtualenv -COPY ./entrypoint.sh /usr/local/bin/entrypoint.sh - -# Change sass-cache owner so that the development user has write permission. -# This is required to run the update_assets paver task in development. -RUN chown -R ${DOCKER_UID}:${DOCKER_GID} /tmp/sass-cache - -# Switch to an un-privileged user matching the host user to prevent permission -# issues with volumes (host folders) -USER ${DOCKER_UID}:${DOCKER_GID} - -# Create the virtualenv with a non-priviledged user -RUN virtualenv -p python2.7 --system-site-packages /edx/app/edxapp/venv - -# Install development dependencies and local libraries in a virtualenv. -RUN bash -c "source /edx/app/edxapp/venv/bin/activate && \ - pip install --upgrade pip==9.0.3 && \ - pip install --no-cache-dir -r requirements/edx/local.txt && \ - pip install --no-cache-dir -r requirements/edx/development.txt" - -ENTRYPOINT [ "/usr/local/bin/entrypoint.sh" ] - - -# === PRODUCTION === -FROM edxapp as production - -ARG EDXAPP_STATIC_ROOT - -# Install runner system dependencies -RUN apt-get update && \ - apt-get upgrade -y && \ - apt-get install -y \ - libgeos-dev \ - libjpeg8 \ - libmysqlclient18 \ - libxml2 \ - libxmlsec1-dev \ - lynx \ - tzdata && \ - rm -rf /var/lib/apt/lists/* - -# Copy installed dependencies -COPY --from=builder /usr/local /usr/local - -# Copy modified sources (sic!) -COPY --from=builder /edx/app/edxapp/edx-platform /edx/app/edxapp/edx-platform - -# Copy static files -COPY --from=links_collector ${EDXAPP_STATIC_ROOT} ${EDXAPP_STATIC_ROOT} - -# Now that dependencies are installed and configuration has been set, the above -# statements will run with a un-privileged user. -USER 10000 - -# To start the CMS, inject the SERVICE_VARIANT=cms environment variable -# (defaults to "lms") -ENV SERVICE_VARIANT=lms - -# Gunicorn configuration -# -# As some synchronous requests may be quite long (e.g. courses import), we -# should make timeout rather high and configurable so that it could be -# increased without having to make a new release of this image -ENV GUNICORN_TIMEOUT 300 - -# In docker we must increase the number of workers and threads created -# by gunicorn. -# This blogpost explains why and how to do that https://pythonspeed.com/articles/gunicorn-in-docker/ -ENV GUNICORN_WORKERS 3 -ENV GUNICORN_THREADS 6 - - -# Use Gunicorn in production as web server -CMD DJANGO_SETTINGS_MODULE=${SERVICE_VARIANT}.envs.fun.docker_run \ - gunicorn \ - --name=${SERVICE_VARIANT} \ - --bind=0.0.0.0:8000 \ - --max-requests=1000 \ - --timeout=${GUNICORN_TIMEOUT} \ - --workers=${GUNICORN_WORKERS} \ - --threads=${GUNICORN_THREADS} \ - ${SERVICE_VARIANT}.wsgi:application - -# === NGINX === -FROM ${NGINX_IMAGE_NAME}:${NGINX_IMAGE_TAG} as nginx - -ARG EDXAPP_STATIC_ROOT - -RUN mkdir -p ${EDXAPP_STATIC_ROOT} - -COPY --from=files_collector ${EDXAPP_STATIC_ROOT} ${EDXAPP_STATIC_ROOT} diff --git a/releases/dogwood/3/bare/activate b/releases/dogwood/3/bare/activate deleted file mode 100644 index 98f3af90..00000000 --- a/releases/dogwood/3/bare/activate +++ /dev/null @@ -1,4 +0,0 @@ -export EDX_RELEASE="dogwood.3" -export FLAVOR="bare" -export EDX_RELEASE_REF="named-release/dogwood.3" -export EDX_DEMO_RELEASE_REF="open-release/eucalyptus.1" diff --git a/releases/dogwood/3/bare/config/cms/__init__.py b/releases/dogwood/3/bare/config/cms/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/releases/dogwood/3/bare/config/cms/docker_build_development.py b/releases/dogwood/3/bare/config/cms/docker_build_development.py deleted file mode 100644 index 68ee9fc6..00000000 --- a/releases/dogwood/3/bare/config/cms/docker_build_development.py +++ /dev/null @@ -1,7 +0,0 @@ -# This is a minimal settings file allowing us to run "update_assets" -# in the Dockerfile -from .docker_run_development import * - -DATABASES = {"default": {}} - -XQUEUE_INTERFACE = {"url": None, "django_auth": None} diff --git a/releases/dogwood/3/bare/config/cms/docker_build_production.py b/releases/dogwood/3/bare/config/cms/docker_build_production.py deleted file mode 100644 index 99f7eee1..00000000 --- a/releases/dogwood/3/bare/config/cms/docker_build_production.py +++ /dev/null @@ -1,7 +0,0 @@ -# This is a minimal settings file allowing us to run "update_assets" -# in the Dockerfile -from .docker_run_production import * - -DATABASES = {"default": {}} - -XQUEUE_INTERFACE = {"url": None, "django_auth": None} diff --git a/releases/dogwood/3/bare/config/cms/docker_run.py b/releases/dogwood/3/bare/config/cms/docker_run.py deleted file mode 100644 index a1e4f25e..00000000 --- a/releases/dogwood/3/bare/config/cms/docker_run.py +++ /dev/null @@ -1,3 +0,0 @@ -# This file is meant to import the environment related settings file - -from docker_run_production import * diff --git a/releases/dogwood/3/bare/config/cms/docker_run_development.py b/releases/dogwood/3/bare/config/cms/docker_run_development.py deleted file mode 100644 index b59abc65..00000000 --- a/releases/dogwood/3/bare/config/cms/docker_run_development.py +++ /dev/null @@ -1,24 +0,0 @@ -# This file includes overrides to build the `development` environment for the CMS, starting from -# the settings of the `production` environment - -from docker_run_production import * -from lms.envs.fun.utils import Configuration - -# Load custom configuration parameters from yaml files -config = Configuration(os.path.dirname(__file__)) - -if "sentry" in LOGGING.get("handlers"): - LOGGING["handlers"]["sentry"]["environment"] = "development" - -DEBUG = True -REQUIRE_DEBUG = True - -EMAIL_BACKEND = config( - "EMAIL_BACKEND", default="django.core.mail.backends.console.EmailBackend" -) - - -PIPELINE_ENABLED = False -STATICFILES_STORAGE = "openedx.core.storage.DevelopmentStorage" - -ALLOWED_HOSTS = ["*"] diff --git a/releases/dogwood/3/bare/config/cms/docker_run_preprod.py b/releases/dogwood/3/bare/config/cms/docker_run_preprod.py deleted file mode 100644 index db742252..00000000 --- a/releases/dogwood/3/bare/config/cms/docker_run_preprod.py +++ /dev/null @@ -1,14 +0,0 @@ -# This file includes overrides to build the `preprod` environment for the LMS -# starting from the settings of the `production` environment - -from docker_run_production import * -from lms.envs.fun.utils import Configuration - -# Load custom configuration parameters from yaml files -config = Configuration(os.path.dirname(__file__)) - -LOGGING["handlers"]["sentry"]["environment"] = "preprod" - -EMAIL_BACKEND = config( - "EMAIL_BACKEND", default="django.core.mail.backends.console.EmailBackend" -) diff --git a/releases/dogwood/3/bare/config/cms/docker_run_production.py b/releases/dogwood/3/bare/config/cms/docker_run_production.py deleted file mode 100644 index 5735862d..00000000 --- a/releases/dogwood/3/bare/config/cms/docker_run_production.py +++ /dev/null @@ -1,626 +0,0 @@ -""" -This is the default template for our main set of AWS servers. -""" - -# We intentionally define lots of variables that aren't used, and -# pylint: disable=wildcard-import, unused-wildcard-import - -# Pylint gets confused by path.py instances, which report themselves as class -# objects. As a result, pylint applies the wrong regex in validating names, -# and throws spurious errors. Therefore, we disable invalid-name checking. -# pylint: disable=invalid-name - -import json -import os -import platform - -from lms.envs.fun.utils import Configuration -from openedx.core.lib.logsettings import get_logger_config -from path import Path as path -from xmodule.modulestore.modulestore_settings import ( - convert_module_store_setting_if_needed, - update_module_store_settings, -) - -from ..common import * - - -# Load custom configuration parameters from yaml files -config = Configuration(os.path.dirname(__file__)) - -# edX has now started using "settings.ENV_TOKENS" and "settings.AUTH_TOKENS" everywhere in the -# project, not just in the settings. Let's make sure our settings still work in this case -ENV_TOKENS = config -AUTH_TOKENS = config - -# SERVICE_VARIANT specifies name of the variant used, which decides what JSON -# configuration files are read during startup. -SERVICE_VARIANT = config("SERVICE_VARIANT", default=None) - -# CONFIG_ROOT specifies the directory where the JSON configuration -# files are expected to be found. If not specified, use the project -# directory. -CONFIG_ROOT = path(config("CONFIG_ROOT", default=ENV_ROOT)) - -# 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 "" - - -############### ALWAYS THE SAME ################################ - -RELEASE = config("RELEASE", default=None) -DEBUG = False - -# IMPORTANT: With this enabled, the server must always be behind a proxy that -# strips the header HTTP_X_FORWARDED_PROTO from client requests. Otherwise, -# a user can fool our server into thinking it was an https connection. -# See -# https://docs.djangoproject.com/en/dev/ref/settings/#secure-proxy-ssl-header -# for other warnings. -SECURE_PROXY_SSL_HEADER = ("HTTP_X_FORWARDED_PROTO", "https") - -###################################### CELERY ################################ - -CELERY_ALWAYS_EAGER = config("CELERY_ALWAYS_EAGER", default=False, formatter=bool) - -# Don't use a connection pool, since connections are dropped by ELB. -BROKER_POOL_LIMIT = 0 -BROKER_CONNECTION_TIMEOUT = 1 - -# For the Result Store, use the django cache named 'celery' -CELERY_RESULT_BACKEND = config( - "CELERY_RESULT_BACKEND", default="djcelery.backends.cache:CacheBackend" -) - -# When the broker is behind an ELB, use a heartbeat to refresh the -# connection and to detect if it has been dropped. -BROKER_HEARTBEAT = 60.0 -BROKER_HEARTBEAT_CHECKRATE = 2 - -# Each worker should only fetch one message at a time -CELERYD_PREFETCH_MULTIPLIER = 1 - -CELERY_DEFAULT_EXCHANGE = "edx.cms.core" - -# Celery queues -DEFAULT_PRIORITY_QUEUE = config( - "DEFAULT_PRIORITY_QUEUE", default="edx.cms.core.default" -) -HIGH_PRIORITY_QUEUE = config("HIGH_PRIORITY_QUEUE", default="edx.cms.core.high") -LOW_PRIORITY_QUEUE = config("LOW_PRIORITY_QUEUE", default="edx.cms.core.low") - -CELERY_DEFAULT_QUEUE = DEFAULT_PRIORITY_QUEUE -CELERY_DEFAULT_ROUTING_KEY = DEFAULT_PRIORITY_QUEUE - -CELERY_QUEUES = config( - "CELERY_QUEUES", - default={ - DEFAULT_PRIORITY_QUEUE: {}, - HIGH_PRIORITY_QUEUE: {}, - LOW_PRIORITY_QUEUE: {}, - }, - formatter=json.loads, -) - -CELERY_ROUTES = "cms.celery.Router" - -# Force accepted content to "json" only. If we also accept pickle-serialized -# messages, the worker will crash when it's running with a privileged user (even -# if it's not the root user but a user belonging to the root group, which is our -# case with OpenShift). -CELERY_ACCEPT_CONTENT = ["json"] - -############# NON-SECURE ENV CONFIG ############################## -# Things like server locations, ports, etc. - -# GITHUB_REPO_ROOT is the base directory for course data -GITHUB_REPO_ROOT = config( - "GITHUB_REPO_ROOT", default=path("/edx/app/edxapp/data"), formatter=path -) - -# DEFAULT_COURSE_ABOUT_IMAGE_URL specifies the default image to show for -# courses that don't provide one -DEFAULT_COURSE_ABOUT_IMAGE_URL = config( - "DEFAULT_COURSE_ABOUT_IMAGE_URL", default="images/pencils.jpg" -) - -STATIC_URL_BASE = "/static/" -STATIC_URL = "/static/studio/" -STATIC_ROOT_BASE = path("/edx/app/edxapp/staticfiles") -STATIC_ROOT = path("/edx/app/edxapp/staticfiles/studio") -STATICFILES_STORAGE = config( - "STATICFILES_STORAGE", default="lms.envs.fun.storage.CDNPipelineCachedStorage" -) -CDN_BASE_URL = config("CDN_BASE_URL", default=None) -PIPELINE = True - -EMAIL_BACKEND = config( - "EMAIL_BACKEND", default="django.core.mail.backends.smtp.EmailBackend" -) -EMAIL_FILE_PATH = config("EMAIL_FILE_PATH", default=None) - -EMAIL_HOST = config("EMAIL_HOST", default="localhost") -EMAIL_PORT = config("EMAIL_PORT", default=25, formatter=int) -EMAIL_USE_TLS = config("EMAIL_USE_TLS", default=False, formatter=bool) - -LMS_BASE = config("LMS_BASE", default="localhost:8072") -CMS_BASE = config("CMS_BASE", default="localhost:8082") - -LMS_ROOT_URL = config("LMS_ROOT_URL", default="http://{:s}".format(LMS_BASE)) -LMS_INTERNAL_ROOT_URL = config("LMS_INTERNAL_ROOT_URL", default=LMS_ROOT_URL) - -SITE_NAME = config("SITE_NAME", default=CMS_BASE) - -ALLOWED_HOSTS = config( - "ALLOWED_HOSTS", default=[CMS_BASE.split(":")[0]], formatter=json.loads -) - -LOG_DIR = config("LOG_DIR", default=path("/edx/var/logs/edx"), formatter=path) - -MEMCACHED_HOST = config("MEMCACHED_HOST", default="memcached") -MEMCACHED_PORT = config("MEMCACHED_PORT", default=11211, formatter=int) - -CACHES = config( - "CACHES", - default={ - "default": { - "BACKEND": "django.core.cache.backends.memcached.MemcachedCache", - "LOCATION": "{}:{}".format(MEMCACHED_HOST, MEMCACHED_PORT), - "KEY_FUNCTION": "util.memcache.safe_key", - "KEY_PREFIX": "default", - }, - "general": { - "BACKEND": "django.core.cache.backends.memcached.MemcachedCache", - "LOCATION": "{}:{}".format(MEMCACHED_HOST, MEMCACHED_PORT), - "KEY_FUNCTION": "util.memcache.safe_key", - "KEY_PREFIX": "general", - }, - "loc_cache": { - "BACKEND": "django.core.cache.backends.locmem.LocMemCache", - "LOCATION": "edx_location_mem_cache", - }, - "celery": { - "BACKEND": "django.core.cache.backends.memcached.MemcachedCache", - "LOCATION": "{}:{}".format(MEMCACHED_HOST, MEMCACHED_PORT), - "KEY_FUNCTION": "util.memcache.safe_key", - "KEY_PREFIX": "celery", - }, - "mongo_metadata_inheritance": { - "BACKEND": "django.core.cache.backends.memcached.MemcachedCache", - "LOCATION": "{}:{}".format(MEMCACHED_HOST, MEMCACHED_PORT), - "KEY_FUNCTION": "util.memcache.safe_key", - "KEY_PREFIX": "mongo_metadata_inheritance", - }, - "openassessment_submissions": { - "BACKEND": "django.core.cache.backends.memcached.MemcachedCache", - "LOCATION": "{}:{}".format(MEMCACHED_HOST, MEMCACHED_PORT), - "KEY_FUNCTION": "util.memcache.safe_key", - "KEY_PREFIX": "openassessment_submissions", - }, - "staticfiles": { - "BACKEND": "django.core.cache.backends.memcached.MemcachedCache", - "LOCATION": "{}:{}".format(MEMCACHED_HOST, MEMCACHED_PORT), - "KEY_FUNCTION": "util.memcache.safe_key", - "KEY_PREFIX": "staticfiles", - }, - }, - formatter=json.loads, -) - -SESSION_COOKIE_DOMAIN = config("SESSION_COOKIE_DOMAIN", default=None) -SESSION_COOKIE_HTTPONLY = config( - "SESSION_COOKIE_HTTPONLY", default=True, formatter=bool -) -SESSION_COOKIE_SECURE = config( - "SESSION_COOKIE_SECURE", default=SESSION_COOKIE_SECURE, formatter=bool -) -SESSION_ENGINE = config( - "SESSION_ENGINE", default="django.contrib.sessions.backends.cache" -) -SESSION_SAVE_EVERY_REQUEST = config( - "SESSION_SAVE_EVERY_REQUEST", default=SESSION_SAVE_EVERY_REQUEST, formatter=bool -) - -# social sharing settings -SOCIAL_SHARING_SETTINGS = config( - "SOCIAL_SHARING_SETTINGS", default=SOCIAL_SHARING_SETTINGS, formatter=json.loads -) - -REGISTRATION_EMAIL_PATTERNS_ALLOWED = config( - "REGISTRATION_EMAIL_PATTERNS_ALLOWED", default=None, formatter=json.loads -) - -# allow for environments to specify what cookie name our login subsystem should use -# this is to fix a bug regarding simultaneous logins between edx.org and edge.edx.org which can -# happen with some browsers (e.g. Firefox) -if config("SESSION_COOKIE_NAME", default=None): - # NOTE, there's a bug in Django (http://bugs.python.org/issue18012) which necessitates this - # being a str() - SESSION_COOKIE_NAME = str(config("SESSION_COOKIE_NAME")) - -# Set the names of cookies shared with the marketing site -# These have the same cookie domain as the session, which in production -# usually includes subdomains. -EDXMKTG_LOGGED_IN_COOKIE_NAME = config( - "EDXMKTG_LOGGED_IN_COOKIE_NAME", default=EDXMKTG_LOGGED_IN_COOKIE_NAME -) -EDXMKTG_USER_INFO_COOKIE_NAME = config( - "EDXMKTG_USER_INFO_COOKIE_NAME", default=EDXMKTG_USER_INFO_COOKIE_NAME -) - -# Email overrides -DEFAULT_FROM_EMAIL = config("DEFAULT_FROM_EMAIL", default=DEFAULT_FROM_EMAIL) -DEFAULT_FEEDBACK_EMAIL = config( - "DEFAULT_FEEDBACK_EMAIL", default=DEFAULT_FEEDBACK_EMAIL -) -ADMINS = config("ADMINS", default=ADMINS, formatter=json.loads) -SERVER_EMAIL = config("SERVER_EMAIL", default=SERVER_EMAIL) -MKTG_URLS = config("MKTG_URLS", default=MKTG_URLS, formatter=json.loads) -TECH_SUPPORT_EMAIL = config("TECH_SUPPORT_EMAIL", default=TECH_SUPPORT_EMAIL) - -COURSES_WITH_UNSAFE_CODE = config( - "COURSES_WITH_UNSAFE_CODE", default=[], formatter=json.loads -) - -LOCALE_PATHS = config("LOCALE_PATHS", default=LOCALE_PATHS, formatter=json.loads) - -ASSET_IGNORE_REGEX = config("ASSET_IGNORE_REGEX", default=ASSET_IGNORE_REGEX) - -# Theme overrides -THEME_NAME = config("THEME_NAME", default=None) -COMPREHENSIVE_THEME_DIR = path( - config("COMPREHENSIVE_THEME_DIR", default=COMPREHENSIVE_THEME_DIR) -) - -# Timezone overrides -TIME_ZONE = config("TIME_ZONE", default=TIME_ZONE) - -# Push to LMS overrides -GIT_REPO_EXPORT_DIR = config( - "GIT_REPO_EXPORT_DIR", - default=path("/edx/var/edxapp/export_course_repos"), - formatter=path, -) - -# Translation overrides -LANGUAGES = config("LANGUAGES", default=LANGUAGES, formatter=json.loads) -LANGUAGE_CODE = config("LANGUAGE_CODE", default=LANGUAGE_CODE) - -USE_I18N = config("USE_I18N", default=USE_I18N, formatter=bool) -ALL_LANGUAGES = config("ALL_LANGUAGES", default=ALL_LANGUAGES, formatter=json.loads) - -# Override feature by feature by whatever is being redefined in the settings.yaml file -CONFIG_FEATURES = config("FEATURES", default={}, formatter=json.loads) -FEATURES.update(CONFIG_FEATURES) - - -# Additional installed apps -for app in config("ADDL_INSTALLED_APPS", default=[], formatter=json.loads): - INSTALLED_APPS.append(app) - -WIKI_ENABLED = config("WIKI_ENABLED", default=WIKI_ENABLED, formatter=bool) - -# Configure Logging - -# Default format for syslog logging -standard_format = "%(asctime)s %(levelname)s %(process)d [%(name)s] %(filename)s:%(lineno)d - %(message)s" -syslog_format = ( - "[variant:cms][%(name)s][env:sandbox] %(levelname)s " - "[{hostname} %(process)d] [%(filename)s:%(lineno)d] - %(message)s" -).format(hostname=platform.node().split(".")[0]) - -LOGGING = { - "version": 1, - "disable_existing_loggers": False, - "handlers": { - "local": { - "formatter": "syslog_format", - "class": "logging.StreamHandler", - "level": "INFO", - }, - "tracking": { - "formatter": "raw", - "class": "logging.StreamHandler", - "level": "DEBUG", - }, - "console": { - "formatter": "standard", - "class": "logging.StreamHandler", - "level": "INFO", - }, - }, - "formatters": { - "raw": {"format": "%(message)s"}, - "syslog_format": {"format": syslog_format}, - "standard": {"format": standard_format}, - }, - "filters": {"require_debug_false": {"()": "django.utils.log.RequireDebugFalse"}}, - "loggers": { - "": {"level": "INFO", "propagate": False, "handlers": ["console", "local"]}, - "tracking": {"level": "DEBUG", "propagate": False, "handlers": ["tracking"]}, - }, -} - -SENTRY_DSN = config("SENTRY_DSN", default=None) -if SENTRY_DSN: - LOGGING["loggers"][""]["handlers"].append("sentry") - LOGGING["handlers"]["sentry"] = { - "class": "raven.handlers.logging.SentryHandler", - "dsn": SENTRY_DSN, - "level": "ERROR", - "environment": "production", - "release": RELEASE, - } - -# FIXME: the PLATFORM_NAME and PLATFORM_DESCRIPTION settings should be set to lazy translatable -# strings but edX tries to serialize them with a default json serializer which breaks. We should -# submit a PR to fix it in edx-platform -PLATFORM_NAME = config("PLATFORM_NAME", default="Your Platform Name Here") -PLATFORM_DESCRIPTION = config( - "PLATFORM_DESCRIPTION", default="Your Platform Description Here" -) -STUDIO_NAME = config("STUDIO_NAME", default=STUDIO_NAME) -STUDIO_SHORT_NAME = config("STUDIO_SHORT_NAME", default=STUDIO_SHORT_NAME) - -# Event Tracking -TRACKING_IGNORE_URL_PATTERNS = config( - "TRACKING_IGNORE_URL_PATTERNS", - default=TRACKING_IGNORE_URL_PATTERNS, - formatter=json.loads, -) - -# Django CAS external authentication settings -CAS_EXTRA_LOGIN_PARAMS = config( - "CAS_EXTRA_LOGIN_PARAMS", default=None, formatter=json.loads -) -if FEATURES.get("AUTH_USE_CAS"): - CAS_SERVER_URL = config("CAS_SERVER_URL", default=None) - AUTHENTICATION_BACKENDS = [ - "django.contrib.auth.backends.ModelBackend", - "django_cas.backends.CASBackend", - ] - INSTALLED_APPS.append("django_cas") - MIDDLEWARE_CLASSES.append("django_cas.middleware.CASMiddleware") - CAS_ATTRIBUTE_CALLBACK = config( - "CAS_ATTRIBUTE_CALLBACK", default=None, formatter=json.loads - ) - if CAS_ATTRIBUTE_CALLBACK: - import importlib - - CAS_USER_DETAILS_RESOLVER = getattr( - importlib.import_module(CAS_ATTRIBUTE_CALLBACK["module"]), - CAS_ATTRIBUTE_CALLBACK["function"], - ) - -################ SECURE AUTH ITEMS ############################### - -############### XBlock filesystem field config ########## -DJFS = config( - "DJFS", - default={ - "directory_root": "/edx/var/edxapp/django-pyfs/static/django-pyfs", - "type": "osfs", - "url_root": "/static/django-pyfs", - }, - formatter=json.loads, -) - -EMAIL_HOST_USER = config("EMAIL_HOST_USER", default=EMAIL_HOST_USER) -EMAIL_HOST_PASSWORD = config("EMAIL_HOST_PASSWORD", default=EMAIL_HOST_PASSWORD) - -# Note that this is the Studio key for Segment. There is a separate key for the LMS. -CMS_SEGMENT_KEY = config("SEGMENT_KEY", default=None) - -SECRET_KEY = config("SECRET_KEY", default="ThisIsAnExampleKeyForDevPurposeOnly") - -DEFAULT_FILE_STORAGE = config( - "DEFAULT_FILE_STORAGE", default="django.core.files.storage.FileSystemStorage" -) - -# Databases - -DATABASE_ENGINE = config("DATABASE_ENGINE", default="django.db.backends.mysql") -DATABASE_HOST = config("DATABASE_HOST", default="mysql") -DATABASE_PORT = config("DATABASE_PORT", default=3306, formatter=int) -DATABASE_NAME = config("DATABASE_NAME", default="edxapp") -DATABASE_USER = config("DATABASE_USER", default="edxapp_user") -DATABASE_PASSWORD = config("DATABASE_PASSWORD", default="password") - -DATABASES = config( - "DATABASES", - default={ - "default": { - "ENGINE": DATABASE_ENGINE, - "HOST": DATABASE_HOST, - "PORT": DATABASE_PORT, - "NAME": DATABASE_NAME, - "USER": DATABASE_USER, - "PASSWORD": DATABASE_PASSWORD, - } - }, - formatter=json.loads, -) - -# Enable automatic transaction management on all databases -# https://docs.djangoproject.com/en/1.8/topics/db/transactions/#tying-transactions-to-http-requests -# This needs to be true for all databases -for database_name in DATABASES: - DATABASES[database_name]["ATOMIC_REQUESTS"] = True - -MODULESTORE = convert_module_store_setting_if_needed( - config("MODULESTORE", default=MODULESTORE, formatter=json.loads) -) - -MONGODB_PASSWORD = config("MONGODB_PASSWORD", default="") -MONGODB_HOST = config("MONGODB_HOST", default="mongodb") -MONGODB_PORT = config("MONGODB_PORT", default=27017, formatter=int) -MONGODB_NAME = config("MONGODB_NAME", default="edxapp") -MONGODB_USER = config("MONGODB_USER", default=None) -MONGODB_SSL = config("MONGODB_SSL", default=False, formatter=bool) - -DOC_STORE_CONFIG = config( - "DOC_STORE_CONFIG", - default={ - "collection": "modulestore", - "host": MONGODB_HOST, - "port": MONGODB_PORT, - "db": MONGODB_NAME, - "user": MONGODB_USER, - "password": MONGODB_PASSWORD, - "ssl": MONGODB_SSL, - }, - formatter=json.loads, -) - -update_module_store_settings(MODULESTORE, doc_store_settings=DOC_STORE_CONFIG) - -MONGODB_LOG = config("MONGODB_LOG", default={}, formatter=json.loads) - -CONTENTSTORE = config( - "CONTENTSTORE", - default={ - "DOC_STORE_CONFIG": DOC_STORE_CONFIG, - "ENGINE": "xmodule.contentstore.mongo.MongoContentStore", - }, - formatter=json.loads, -) - -# Datadog for events! -DATADOG = config("DATADOG", default={}, formatter=json.loads) - -# TODO: deprecated (compatibility with previous settings) -DATADOG["api_key"] = config("DATADOG_API", default=None) - -# Celery Broker -CELERY_BROKER_TRANSPORT = config("CELERY_BROKER_TRANSPORT", default="redis") -CELERY_BROKER_USER = config("CELERY_BROKER_USER", default="") -CELERY_BROKER_PASSWORD = config("CELERY_BROKER_PASSWORD", default="") -CELERY_BROKER_HOST = config("CELERY_BROKER_HOST", default="redis") -CELERY_BROKER_PORT = config("CELERY_BROKER_PORT", default=6379, formatter=int) -CELERY_BROKER_VHOST = config("CELERY_BROKER_VHOST", default=0, formatter=int) - -BROKER_URL = "{transport}://{user}:{password}@{host}:{port}/{vhost}".format( - transport=CELERY_BROKER_TRANSPORT, - user=CELERY_BROKER_USER, - password=CELERY_BROKER_PASSWORD, - host=CELERY_BROKER_HOST, - port=CELERY_BROKER_PORT, - vhost=CELERY_BROKER_VHOST, -) - -# Event tracking -TRACKING_BACKENDS.update(config("TRACKING_BACKENDS", default={}, formatter=json.loads)) -EVENT_TRACKING_BACKENDS["tracking_logs"]["OPTIONS"]["backends"].update( - config("EVENT_TRACKING_BACKENDS", default={}, formatter=json.loads) -) -EVENT_TRACKING_BACKENDS["segmentio"]["OPTIONS"]["processors"][0]["OPTIONS"][ - "whitelist" -].extend( - config("EVENT_TRACKING_SEGMENTIO_EMIT_WHITELIST", default=[], formatter=json.loads) -) - -SUBDOMAIN_BRANDING = config("SUBDOMAIN_BRANDING", default={}, formatter=json.loads) -VIRTUAL_UNIVERSITIES = config("VIRTUAL_UNIVERSITIES", default=[], formatter=json.loads) - -##### ACCOUNT LOCKOUT DEFAULT PARAMETERS ##### -MAX_FAILED_LOGIN_ATTEMPTS_ALLOWED = config( - "MAX_FAILED_LOGIN_ATTEMPTS_ALLOWED", default=5, formatter=int -) -MAX_FAILED_LOGIN_ATTEMPTS_LOCKOUT_PERIOD_SECS = config( - "MAX_FAILED_LOGIN_ATTEMPTS_LOCKOUT_PERIOD_SECS", default=15 * 60, formatter=int -) - -MICROSITE_CONFIGURATION = config( - "MICROSITE_CONFIGURATION", default={}, fomatter=json.loads -) -MICROSITE_ROOT_DIR = path(config("MICROSITE_ROOT_DIR", default="")) - -#### PASSWORD POLICY SETTINGS ##### -PASSWORD_MIN_LENGTH = config("PASSWORD_MIN_LENGTH", default=12, formatter=int) -PASSWORD_MAX_LENGTH = config("PASSWORD_MAX_LENGTH", default=None, formatter=int) - -PASSWORD_COMPLEXITY = config( - "PASSWORD_COMPLEXITY", - default={"UPPER": 1, "LOWER": 1, "DIGITS": 1}, - formatter=json.loads, -) -PASSWORD_DICTIONARY_EDIT_DISTANCE_THRESHOLD = config( - "PASSWORD_DICTIONARY_EDIT_DISTANCE_THRESHOLD", - default=PASSWORD_DICTIONARY_EDIT_DISTANCE_THRESHOLD, - formatter=int, -) -PASSWORD_DICTIONARY = config("PASSWORD_DICTIONARY", default=[], formatter=json.loads) - -### INACTIVITY SETTINGS #### -SESSION_INACTIVITY_TIMEOUT_IN_SECONDS = config( - "SESSION_INACTIVITY_TIMEOUT_IN_SECONDS", default=None, formatter=int -) - -##### X-Frame-Options response header settings ##### -X_FRAME_OPTIONS = config("X_FRAME_OPTIONS", default=X_FRAME_OPTIONS) - -##### ADVANCED_SECURITY_CONFIG ##### -ADVANCED_SECURITY_CONFIG = config( - "ADVANCED_SECURITY_CONFIG", default={}, formatter=json.loads -) - -################ ADVANCED COMPONENT/PROBLEM TYPES ############### - -ADVANCED_COMPONENT_TYPES = config( - "ADVANCED_COMPONENT_TYPES", default=ADVANCED_COMPONENT_TYPES, formatter=json.loads -) -ADVANCED_PROBLEM_TYPES = config( - "ADVANCED_PROBLEM_TYPES", default=ADVANCED_PROBLEM_TYPES, formatter=json.loads -) -DEPRECATED_ADVANCED_COMPONENT_TYPES = config( - "DEPRECATED_ADVANCED_COMPONENT_TYPES", - default=DEPRECATED_ADVANCED_COMPONENT_TYPES, - formatter=json.loads, -) - -################ VIDEO UPLOAD PIPELINE ############### - -VIDEO_UPLOAD_PIPELINE = config( - "VIDEO_UPLOAD_PIPELINE", default=VIDEO_UPLOAD_PIPELINE, formatter=json.loads -) - -################ PUSH NOTIFICATIONS ############### - -PARSE_KEYS = config("PARSE_KEYS", default={}, formatter=json.loads) - - -# Video Caching. Pairing country codes with CDN URLs. -# Example: {'CN': 'http://api.xuetangx.com/edx/video?s3_url='} -VIDEO_CDN_URL = config("VIDEO_CDN_URL", default={}, formatter=json.loads) - -if FEATURES["ENABLE_COURSEWARE_INDEX"] or FEATURES["ENABLE_LIBRARY_INDEX"]: - # Use ElasticSearch for the search engine - SEARCH_ENGINE = "search.elastic.ElasticSearchEngine" - -ELASTIC_SEARCH_CONFIG = config( - "ELASTIC_SEARCH_CONFIG", default=[{}], formatter=json.loads -) - -XBLOCK_SETTINGS = config("XBLOCK_SETTINGS", default={}, formatter=json.loads) -XBLOCK_SETTINGS.setdefault("VideoDescriptor", {})["licensing_enabled"] = FEATURES.get( - "LICENSING", False -) -XBLOCK_SETTINGS.setdefault("VideoModule", {})["YOUTUBE_API_KEY"] = FEATURES.get( - "YOUTUBE_API_KEY", YOUTUBE_API_KEY -) - -################# PROCTORING CONFIGURATION ################## - -PROCTORING_BACKEND_PROVIDER = config( - "PROCTORING_BACKEND_PROVIDER", default=PROCTORING_BACKEND_PROVIDER -) -PROCTORING_SETTINGS = config( - "PROCTORING_SETTINGS", default=PROCTORING_SETTINGS, fomatter=json.loads -) - -############################ OAUTH2 Provider ################################### - -# OpenID Connect issuer ID. Normally the URL of the authentication endpoint. -OAUTH_OIDC_ISSUER = config("OAUTH_OIDC_ISSUER", default=None) diff --git a/releases/dogwood/3/bare/config/cms/docker_run_staging.py b/releases/dogwood/3/bare/config/cms/docker_run_staging.py deleted file mode 100644 index bdf5ffcb..00000000 --- a/releases/dogwood/3/bare/config/cms/docker_run_staging.py +++ /dev/null @@ -1,14 +0,0 @@ -# This file includes overrides to build the `staging` environment for the LMS starting from the -# settings of the `production` environment - -from docker_run_production import * -from lms.envs.fun.utils import Configuration - -# Load custom configuration parameters from yaml files -config = Configuration(os.path.dirname(__file__)) - -LOGGING["handlers"]["sentry"]["environment"] = "staging" - -EMAIL_BACKEND = config( - "EMAIL_BACKEND", default="django.core.mail.backends.console.EmailBackend" -) diff --git a/releases/dogwood/3/bare/config/lms/__init__.py b/releases/dogwood/3/bare/config/lms/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/releases/dogwood/3/bare/config/lms/backends.py b/releases/dogwood/3/bare/config/lms/backends.py deleted file mode 100644 index 11e2ce71..00000000 --- a/releases/dogwood/3/bare/config/lms/backends.py +++ /dev/null @@ -1,11 +0,0 @@ -# -*- coding: utf-8 -*- - -from ratelimitbackend.backends import RateLimitModelBackend - - -class ProxyRateLimitModelBackend(RateLimitModelBackend): - """A rate limiting Backend that works behind a proxy.""" - - def get_ip(self, request): - """Return the end user address string as set by proxies.""" - return request.META["HTTP_X_FORWARDED_FOR"] diff --git a/releases/dogwood/3/bare/config/lms/docker_build_development.py b/releases/dogwood/3/bare/config/lms/docker_build_development.py deleted file mode 100644 index 68ee9fc6..00000000 --- a/releases/dogwood/3/bare/config/lms/docker_build_development.py +++ /dev/null @@ -1,7 +0,0 @@ -# This is a minimal settings file allowing us to run "update_assets" -# in the Dockerfile -from .docker_run_development import * - -DATABASES = {"default": {}} - -XQUEUE_INTERFACE = {"url": None, "django_auth": None} diff --git a/releases/dogwood/3/bare/config/lms/docker_build_production.py b/releases/dogwood/3/bare/config/lms/docker_build_production.py deleted file mode 100644 index 99f7eee1..00000000 --- a/releases/dogwood/3/bare/config/lms/docker_build_production.py +++ /dev/null @@ -1,7 +0,0 @@ -# This is a minimal settings file allowing us to run "update_assets" -# in the Dockerfile -from .docker_run_production import * - -DATABASES = {"default": {}} - -XQUEUE_INTERFACE = {"url": None, "django_auth": None} diff --git a/releases/dogwood/3/bare/config/lms/docker_run.py b/releases/dogwood/3/bare/config/lms/docker_run.py deleted file mode 100644 index a1e4f25e..00000000 --- a/releases/dogwood/3/bare/config/lms/docker_run.py +++ /dev/null @@ -1,3 +0,0 @@ -# This file is meant to import the environment related settings file - -from docker_run_production import * diff --git a/releases/dogwood/3/bare/config/lms/docker_run_development.py b/releases/dogwood/3/bare/config/lms/docker_run_development.py deleted file mode 100644 index 41838ff7..00000000 --- a/releases/dogwood/3/bare/config/lms/docker_run_development.py +++ /dev/null @@ -1,31 +0,0 @@ -# This file includes overrides to build the `development` environment for the LMS starting from the -# settings of the `production` environment - -import json - -from docker_run_production import * -from .utils import Configuration - -# Load custom configuration parameters from yaml files -config = Configuration(os.path.dirname(__file__)) - -if "sentry" in LOGGING.get("handlers"): - LOGGING["handlers"]["sentry"]["environment"] = "development" - -DEBUG = True -REQUIRE_DEBUG = True - -EMAIL_BACKEND = config( - "EMAIL_BACKEND", default="django.core.mail.backends.console.EmailBackend" -) - -PIPELINE_ENABLED = False -STATICFILES_STORAGE = "openedx.core.storage.DevelopmentStorage" - -ALLOWED_HOSTS = ["*"] - -AUTHENTICATION_BACKENDS = config( - "AUTHENTICATION_BACKENDS", - default=["django.contrib.auth.backends.ModelBackend"], - formatter=json.loads -) diff --git a/releases/dogwood/3/bare/config/lms/docker_run_preprod.py b/releases/dogwood/3/bare/config/lms/docker_run_preprod.py deleted file mode 100644 index ed5983f2..00000000 --- a/releases/dogwood/3/bare/config/lms/docker_run_preprod.py +++ /dev/null @@ -1,14 +0,0 @@ -# This file includes overrides to build the `preprod` environment for the LMS -# starting from the settings of the `production` environment - -from docker_run_production import * -from .utils import Configuration - -# Load custom configuration parameters from yaml files -config = Configuration(os.path.dirname(__file__)) - -LOGGING["handlers"]["sentry"]["environment"] = "preprod" - -EMAIL_BACKEND = config( - "EMAIL_BACKEND", default="django.core.mail.backends.console.EmailBackend" -) diff --git a/releases/dogwood/3/bare/config/lms/docker_run_production.py b/releases/dogwood/3/bare/config/lms/docker_run_production.py deleted file mode 100644 index ff746f6e..00000000 --- a/releases/dogwood/3/bare/config/lms/docker_run_production.py +++ /dev/null @@ -1,1116 +0,0 @@ -""" -This is the default template for our main set of servers. This does NOT -cover the content machines, which use content.py - -Common traits: -* Use memcached, and cache-backed sessions -* Use a MySQL 5.1 database -""" - -# We intentionally define lots of variables that aren't used, and -# want to import all variables from base settings files -# pylint: disable=wildcard-import, unused-wildcard-import - -# Pylint gets confused by path.py instances, which report themselves as class -# objects. As a result, pylint applies the wrong regex in validating names, -# and throws spurious errors. Therefore, we disable invalid-name checking. -# pylint: disable=invalid-name - -import datetime -import dateutil -import json -import os -import platform - -from openedx.core.lib.logsettings import get_logger_config -from path import Path as path -from xmodule.modulestore.modulestore_settings import ( - convert_module_store_setting_if_needed, - update_module_store_settings, -) - -from ..common import * -from .utils import Configuration - - -# Load custom configuration parameters from yaml files -config = Configuration(os.path.dirname(__file__)) - -# edX has now started using "settings.ENV_TOKENS" and "settings.AUTH_TOKENS" everywhere in the -# project, not just in the settings. Let's make sure our settings still work in this case -ENV_TOKENS = config -AUTH_TOKENS = config - -# SERVICE_VARIANT specifies name of the variant used, which decides what JSON -# configuration files are read during startup. -SERVICE_VARIANT = config("SERVICE_VARIANT", default=None) - -# CONFIG_ROOT specifies the directory where the JSON configuration -# files are expected to be found. If not specified, use the project -# directory. -CONFIG_ROOT = path(config("CONFIG_ROOT", default=ENV_ROOT)) - -# 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 "" - - -################################ ALWAYS THE SAME ############################## - -RELEASE = config("RELEASE", default=None) -DEBUG = False -DEFAULT_TEMPLATE_ENGINE["OPTIONS"]["debug"] = False - -# IMPORTANT: With this enabled, the server must always be behind a proxy that -# strips the header HTTP_X_FORWARDED_PROTO from client requests. Otherwise, -# a user can fool our server into thinking it was an https connection. -# See -# https://docs.djangoproject.com/en/dev/ref/settings/#secure-proxy-ssl-header -# for other warnings. -SECURE_PROXY_SSL_HEADER = ("HTTP_X_FORWARDED_PROTO", "https") - -###################################### CELERY ################################ - -CELERY_ALWAYS_EAGER = config("CELERY_ALWAYS_EAGER", default=False, formatter=bool) - -# Don't use a connection pool, since connections are dropped by ELB. -BROKER_POOL_LIMIT = 0 -BROKER_CONNECTION_TIMEOUT = 1 - -# For the Result Store, use the django cache named 'celery' -CELERY_RESULT_BACKEND = config( - "CELERY_RESULT_BACKEND", default="djcelery.backends.cache:CacheBackend" -) - -# When the broker is behind an ELB, use a heartbeat to refresh the -# connection and to detect if it has been dropped. -BROKER_HEARTBEAT = 60.0 -BROKER_HEARTBEAT_CHECKRATE = 2 - -# Each worker should only fetch one message at a time -CELERYD_PREFETCH_MULTIPLIER = 1 - -# Celery queues - -DEFAULT_PRIORITY_QUEUE = config( - "DEFAULT_PRIORITY_QUEUE", default="edx.lms.core.default" -) -HIGH_PRIORITY_QUEUE = config("HIGH_PRIORITY_QUEUE", default="edx.lms.core.high") -LOW_PRIORITY_QUEUE = config("LOW_PRIORITY_QUEUE", default="edx.lms.core.low") -HIGH_MEM_QUEUE = config("HIGH_MEM_QUEUE", default="edx.lms.core.high_mem") - -CELERY_DEFAULT_QUEUE = DEFAULT_PRIORITY_QUEUE -CELERY_DEFAULT_ROUTING_KEY = DEFAULT_PRIORITY_QUEUE - -CELERY_QUEUES = config( - "CELERY_QUEUES", - default={ - DEFAULT_PRIORITY_QUEUE: {}, - HIGH_PRIORITY_QUEUE: {}, - LOW_PRIORITY_QUEUE: {}, - HIGH_MEM_QUEUE: {}, - }, - formatter=json.loads, -) - -CELERY_ROUTES = "lms.celery.Router" - -# Force accepted content to "json" only. If we also accept pickle-serialized -# messages, the worker will crash when it's running with a privileged user (even -# if it's not the root user but a user belonging to the root group, which is our -# case with OpenShift). -CELERY_ACCEPT_CONTENT = ["json"] - -CELERYBEAT_SCHEDULE = {} # For scheduling tasks, entries can be added to this dict - -########################## NON-SECURE ENV CONFIG ############################## -# Things like server locations, ports, etc. - -STATIC_ROOT_BASE = path("/edx/app/edxapp/staticfiles") -STATIC_ROOT = STATIC_ROOT_BASE -STATIC_URL = "/static/" -STATICFILES_STORAGE = config( - "STATICFILES_STORAGE", default="lms.envs.fun.storage.CDNProductionStorage" -) -CDN_BASE_URL = config("CDN_BASE_URL", default=None) - -MEDIA_ROOT = path("/edx/var/edxapp/media/") -MEDIA_URL = "/media/" - -LOG_DIR = config("LOG_DIR", default=path("/edx/var/logs/edx"), formatter=path) -DATA_DIR = config("DATA_DIR", default=path("/edx/app/edxapp/data"), formatter=path) - -# DEFAULT_COURSE_ABOUT_IMAGE_URL specifies the default image to show for courses that don't provide one -DEFAULT_COURSE_ABOUT_IMAGE_URL = config( - "DEFAULT_COURSE_ABOUT_IMAGE_URL", default=DEFAULT_COURSE_ABOUT_IMAGE_URL -) - - -PLATFORM_NAME = config("PLATFORM_NAME", default=PLATFORM_NAME) -# For displaying on the receipt. At Stanford PLATFORM_NAME != MERCHANT_NAME, but PLATFORM_NAME is a fine default -PLATFORM_TWITTER_ACCOUNT = config( - "PLATFORM_TWITTER_ACCOUNT", default=PLATFORM_TWITTER_ACCOUNT -) -PLATFORM_FACEBOOK_ACCOUNT = config( - "PLATFORM_FACEBOOK_ACCOUNT", default=PLATFORM_FACEBOOK_ACCOUNT -) - -SOCIAL_SHARING_SETTINGS = config( - "SOCIAL_SHARING_SETTINGS", default=SOCIAL_SHARING_SETTINGS, formatter=json.loads -) - -# Social media links for the page footer -SOCIAL_MEDIA_FOOTER_URLS = config( - "SOCIAL_MEDIA_FOOTER_URLS", default=SOCIAL_MEDIA_FOOTER_URLS, formatter=json.loads -) - -CC_MERCHANT_NAME = config("CC_MERCHANT_NAME", default=PLATFORM_NAME) -EMAIL_BACKEND = config( - "EMAIL_BACKEND", default="django.core.mail.backends.smtp.EmailBackend" -) -EMAIL_FILE_PATH = config("EMAIL_FILE_PATH", default=None) -EMAIL_HOST = config("EMAIL_HOST", default="localhost") -EMAIL_PORT = config("EMAIL_PORT", default=25) # django default is 25 -EMAIL_USE_TLS = config("EMAIL_USE_TLS", default=False) # django default is False -SITE_NAME = config("SITE_NAME", default=None) -HTTPS = config("HTTPS", default=HTTPS) - -SESSION_ENGINE = config( - "SESSION_ENGINE", default="django.contrib.sessions.backends.cache" -) -SESSION_COOKIE_DOMAIN = config("SESSION_COOKIE_DOMAIN", default=None) -SESSION_COOKIE_HTTPONLY = config( - "SESSION_COOKIE_HTTPONLY", default=True, formatter=bool -) -SESSION_COOKIE_SECURE = config( - "SESSION_COOKIE_SECURE", default=SESSION_COOKIE_SECURE, formatter=bool -) -SESSION_SAVE_EVERY_REQUEST = config( - "SESSION_SAVE_EVERY_REQUEST", default=SESSION_SAVE_EVERY_REQUEST, formatter=bool -) - -REGISTRATION_EXTRA_FIELDS = config( - "REGISTRATION_EXTRA_FIELDS", default=REGISTRATION_EXTRA_FIELDS, formatter=json.loads -) - -# Set the names of cookies shared with the marketing site -# These have the same cookie domain as the session, which in production -# usually includes subdomains. -EDXMKTG_LOGGED_IN_COOKIE_NAME = config( - "EDXMKTG_LOGGED_IN_COOKIE_NAME", default=EDXMKTG_LOGGED_IN_COOKIE_NAME -) -EDXMKTG_USER_INFO_COOKIE_NAME = config( - "EDXMKTG_USER_INFO_COOKIE_NAME", default=EDXMKTG_USER_INFO_COOKIE_NAME -) - -# Override feature by feature by whatever is being redefined in the settings.yaml file -CONFIG_FEATURES = config("FEATURES", default={}, formatter=json.loads) -FEATURES.update(CONFIG_FEATURES) - -LMS_BASE = config("LMS_BASE", default="localhost:8072") -CMS_BASE = config("CMS_BASE", default="localhost:8082") - -LMS_ROOT_URL = config("LMS_ROOT_URL", default="http://{:s}".format(LMS_BASE)) -LMS_INTERNAL_ROOT_URL = config("LMS_INTERNAL_ROOT_URL", default=LMS_ROOT_URL) - -SITE_NAME = config("SITE_NAME", default=LMS_BASE) - -ALLOWED_HOSTS = config( - "ALLOWED_HOSTS", default=[LMS_BASE.split(":")[0]], formatter=json.loads -) -if FEATURES.get("PREVIEW_LMS_BASE"): - ALLOWED_HOSTS.append(FEATURES["PREVIEW_LMS_BASE"]) - -# allow for environments to specify what cookie name our login subsystem should use -# this is to fix a bug regarding simultaneous logins between edx.org and edge.edx.org which can -# happen with some browsers (e.g. Firefox) -if config("SESSION_COOKIE_NAME", default=None): - # NOTE, there's a bug in Django (http://bugs.python.org/issue18012) which necessitates this - # being a str() - SESSION_COOKIE_NAME = str(config("SESSION_COOKIE_NAME")) - -MEMCACHED_HOST = config("MEMCACHED_HOST", default="memcached") -MEMCACHED_PORT = config("MEMCACHED_PORT", default=11211, formatter=int) - -CACHES = config( - "CACHES", - default={ - "default": { - "BACKEND": "django.core.cache.backends.memcached.MemcachedCache", - "LOCATION": "{}:{}".format(MEMCACHED_HOST, MEMCACHED_PORT), - "KEY_FUNCTION": "util.memcache.safe_key", - "KEY_PREFIX": "default", - }, - "general": { - "BACKEND": "django.core.cache.backends.memcached.MemcachedCache", - "LOCATION": "{}:{}".format(MEMCACHED_HOST, MEMCACHED_PORT), - "KEY_FUNCTION": "util.memcache.safe_key", - "KEY_PREFIX": "general", - }, - "loc_cache": { - "BACKEND": "django.core.cache.backends.locmem.LocMemCache", - "LOCATION": "edx_location_mem_cache", - }, - "celery": { - "BACKEND": "django.core.cache.backends.memcached.MemcachedCache", - "LOCATION": "{}:{}".format(MEMCACHED_HOST, MEMCACHED_PORT), - "KEY_FUNCTION": "util.memcache.safe_key", - "KEY_PREFIX": "celery", - }, - "mongo_metadata_inheritance": { - "BACKEND": "django.core.cache.backends.memcached.MemcachedCache", - "LOCATION": "{}:{}".format(MEMCACHED_HOST, MEMCACHED_PORT), - "KEY_FUNCTION": "util.memcache.safe_key", - "KEY_PREFIX": "mongo_metadata_inheritance", - }, - "openassessment_submissions": { - "BACKEND": "django.core.cache.backends.memcached.MemcachedCache", - "LOCATION": "{}:{}".format(MEMCACHED_HOST, MEMCACHED_PORT), - "KEY_FUNCTION": "util.memcache.safe_key", - "KEY_PREFIX": "openassessment_submissions", - }, - "staticfiles": { - "BACKEND": "django.core.cache.backends.memcached.MemcachedCache", - "LOCATION": "{}:{}".format(MEMCACHED_HOST, MEMCACHED_PORT), - "KEY_FUNCTION": "util.memcache.safe_key", - "KEY_PREFIX": "staticfiles", - }, - }, - formatter=json.loads, -) - -# Email overrides -DEFAULT_FROM_EMAIL = config("DEFAULT_FROM_EMAIL", default=DEFAULT_FROM_EMAIL) -DEFAULT_FEEDBACK_EMAIL = config( - "DEFAULT_FEEDBACK_EMAIL", default=DEFAULT_FEEDBACK_EMAIL -) -ADMINS = config("ADMINS", default=ADMINS, formatter=json.loads) -SERVER_EMAIL = config("SERVER_EMAIL", default=SERVER_EMAIL) -TECH_SUPPORT_EMAIL = config("TECH_SUPPORT_EMAIL", default=TECH_SUPPORT_EMAIL) -CONTACT_EMAIL = config("CONTACT_EMAIL", default=CONTACT_EMAIL) -BUGS_EMAIL = config("BUGS_EMAIL", default=BUGS_EMAIL) -PAYMENT_SUPPORT_EMAIL = config("PAYMENT_SUPPORT_EMAIL", default=PAYMENT_SUPPORT_EMAIL) -FINANCE_EMAIL = config("FINANCE_EMAIL", default=FINANCE_EMAIL) -UNIVERSITY_EMAIL = config("UNIVERSITY_EMAIL", default=UNIVERSITY_EMAIL) -PRESS_EMAIL = config("PRESS_EMAIL", default=PRESS_EMAIL) - -# Currency -PAID_COURSE_REGISTRATION_CURRENCY = config( - "PAID_COURSE_REGISTRATION_CURRENCY", default=PAID_COURSE_REGISTRATION_CURRENCY -) - -# Payment Report Settings -PAYMENT_REPORT_GENERATOR_GROUP = config( - "PAYMENT_REPORT_GENERATOR_GROUP", default=PAYMENT_REPORT_GENERATOR_GROUP -) - -# Bulk Email overrides -BULK_EMAIL_DEFAULT_FROM_EMAIL = config( - "BULK_EMAIL_DEFAULT_FROM_EMAIL", default=BULK_EMAIL_DEFAULT_FROM_EMAIL -) -BULK_EMAIL_EMAILS_PER_TASK = config( - "BULK_EMAIL_EMAILS_PER_TASK", default=BULK_EMAIL_EMAILS_PER_TASK, formatter=int -) -BULK_EMAIL_DEFAULT_RETRY_DELAY = config( - "BULK_EMAIL_DEFAULT_RETRY_DELAY", - default=BULK_EMAIL_DEFAULT_RETRY_DELAY, - formatter=int, -) -BULK_EMAIL_MAX_RETRIES = config( - "BULK_EMAIL_MAX_RETRIES", default=BULK_EMAIL_MAX_RETRIES, formatter=int -) -BULK_EMAIL_INFINITE_RETRY_CAP = config( - "BULK_EMAIL_INFINITE_RETRY_CAP", - default=BULK_EMAIL_INFINITE_RETRY_CAP, - formatter=int, -) -BULK_EMAIL_LOG_SENT_EMAILS = config( - "BULK_EMAIL_LOG_SENT_EMAILS", default=BULK_EMAIL_LOG_SENT_EMAILS, formatter=bool -) -BULK_EMAIL_RETRY_DELAY_BETWEEN_SENDS = config( - "BULK_EMAIL_RETRY_DELAY_BETWEEN_SENDS", - default=BULK_EMAIL_RETRY_DELAY_BETWEEN_SENDS, - formatter=int, -) -# We want Bulk Email running on the high-priority queue, so we define the -# routing key that points to it. At the moment, the name is the same. -# We have to reset the value here, since we have changed the value of the queue name. -BULK_EMAIL_ROUTING_KEY = config("BULK_EMAIL_ROUTING_KEY", default=HIGH_PRIORITY_QUEUE) - -# We can run smaller jobs on the low priority queue. See note above for why -# we have to reset the value here. -BULK_EMAIL_ROUTING_KEY_SMALL_JOBS = LOW_PRIORITY_QUEUE - -# Theme overrides -THEME_NAME = config("THEME_NAME", default=None) -COMPREHENSIVE_THEME_DIR = path( - config("COMPREHENSIVE_THEME_DIR", default=COMPREHENSIVE_THEME_DIR) -) - -# Marketing link overrides -MKTG_URL_LINK_MAP = config("MKTG_URL_LINK_MAP", default={}, formatter=json.loads) - -SUPPORT_SITE_LINK = config("SUPPORT_SITE_LINK", default=SUPPORT_SITE_LINK) - -# Mobile store URL overrides -MOBILE_STORE_URLS = config("MOBILE_STORE_URLS", default=MOBILE_STORE_URLS) - -# Timezone overrides -TIME_ZONE = config("TIME_ZONE", default=TIME_ZONE) - -# Translation overrides -LANGUAGES = config("LANGUAGES", default=LANGUAGES, formatter=json.loads) -LANGUAGE_DICT = dict(LANGUAGES) -LANGUAGE_CODE = config("LANGUAGE_CODE", default=LANGUAGE_CODE) -USE_I18N = config("USE_I18N", default=USE_I18N) - -# Additional installed apps -for app in config("ADDL_INSTALLED_APPS", default=[], formatter=json.loads): - INSTALLED_APPS.append(app) - -WIKI_ENABLED = config("WIKI_ENABLED", default=WIKI_ENABLED, formatter=bool) -local_loglevel = config("LOCAL_LOGLEVEL", default="INFO") - -# Default format for syslog logging -standard_format = "%(asctime)s %(levelname)s %(process)d [%(name)s] %(filename)s:%(lineno)d - %(message)s" -syslog_format = ( - "[variant:lms][%(name)s][env:sandbox] %(levelname)s " - "[{hostname} %(process)d] [%(filename)s:%(lineno)d] - %(message)s" -).format(hostname=platform.node().split(".")[0]) - -LOGGING = { - "version": 1, - "disable_existing_loggers": False, - "handlers": { - "local": { - "formatter": "syslog_format", - "class": "logging.StreamHandler", - "level": "INFO", - }, - "tracking": { - "formatter": "raw", - "class": "logging.StreamHandler", - "level": "DEBUG", - }, - "console": { - "formatter": "standard", - "class": "logging.StreamHandler", - "level": "INFO", - }, - }, - "formatters": { - "raw": {"format": "%(message)s"}, - "syslog_format": {"format": syslog_format}, - "standard": {"format": standard_format}, - }, - "filters": {"require_debug_false": {"()": "django.utils.log.RequireDebugFalse"}}, - "loggers": { - "": {"level": "INFO", "propagate": False, "handlers": ["console", "local"]}, - "tracking": {"level": "DEBUG", "propagate": False, "handlers": ["tracking"]}, - }, -} - -SENTRY_DSN = config("SENTRY_DSN", default=None) -if SENTRY_DSN: - LOGGING["loggers"][""]["handlers"].append("sentry") - LOGGING["handlers"]["sentry"] = { - "class": "raven.handlers.logging.SentryHandler", - "dsn": SENTRY_DSN, - "level": "ERROR", - "environment": "production", - "release": RELEASE, - } - - -COURSE_LISTINGS = config("COURSE_LISTINGS", default={}, formatter=json.loads) -SUBDOMAIN_BRANDING = config("SUBDOMAIN_BRANDING", default={}, formatter=json.loads) -VIRTUAL_UNIVERSITIES = config("VIRTUAL_UNIVERSITIES", default=[]) -META_UNIVERSITIES = config("META_UNIVERSITIES", default={}, formatter=json.loads) -COMMENTS_SERVICE_URL = config("COMMENTS_SERVICE_URL", default="") -COMMENTS_SERVICE_KEY = config("COMMENTS_SERVICE_KEY", default="") -CERT_NAME_SHORT = config("CERT_NAME_SHORT", default=CERT_NAME_SHORT) -CERT_NAME_LONG = config("CERT_NAME_LONG", default=CERT_NAME_LONG) -CERT_QUEUE = config("CERT_QUEUE", default="test-pull") -ZENDESK_URL = config("ZENDESK_URL", default=None) -FEEDBACK_SUBMISSION_EMAIL = config("FEEDBACK_SUBMISSION_EMAIL", default=None) -MKTG_URLS = config("MKTG_URLS", default=MKTG_URLS, formatter=json.loads) - -# Badgr API -BADGR_API_TOKEN = config("BADGR_API_TOKEN", default=BADGR_API_TOKEN) -BADGR_BASE_URL = config("BADGR_BASE_URL", default=BADGR_BASE_URL) -BADGR_ISSUER_SLUG = config("BADGR_ISSUER_SLUG", default=BADGR_ISSUER_SLUG) - -# git repo loading environment -GIT_REPO_DIR = config( - "GIT_REPO_DIR", default=path("/edx/var/edxapp/course_repos"), formatter=path -) -GIT_IMPORT_STATIC = config("GIT_IMPORT_STATIC", default=True) - -for name, value in config("CODE_JAIL", default={}, formatter=json.loads).items(): - oldvalue = CODE_JAIL.get(name) - if isinstance(oldvalue, dict): - for subname, subvalue in value.items(): - oldvalue[subname] = subvalue - else: - CODE_JAIL[name] = value - -COURSES_WITH_UNSAFE_CODE = config( - "COURSES_WITH_UNSAFE_CODE", default=[], formatter=json.loads -) - -LOCALE_PATHS = config("LOCALE_PATHS", default=LOCALE_PATHS, formatter=json.loads) - -ASSET_IGNORE_REGEX = config("ASSET_IGNORE_REGEX", default=ASSET_IGNORE_REGEX) - -# Event Tracking -TRACKING_IGNORE_URL_PATTERNS = config( - "TRACKING_IGNORE_URL_PATTERNS", - default=TRACKING_IGNORE_URL_PATTERNS, - formatter=json.loads, -) - -# SSL external authentication settings -SSL_AUTH_EMAIL_DOMAIN = config("SSL_AUTH_EMAIL_DOMAIN", default="MIT.EDU") -SSL_AUTH_DN_FORMAT_STRING = config("SSL_AUTH_DN_FORMAT_STRING", default=None) - -# Django CAS external authentication settings -CAS_EXTRA_LOGIN_PARAMS = config( - "CAS_EXTRA_LOGIN_PARAMS", default=None, formatter=json.loads -) -if FEATURES.get("AUTH_USE_CAS"): - CAS_SERVER_URL = config("CAS_SERVER_URL", default=None) - INSTALLED_APPS.append("django_cas") - MIDDLEWARE_CLASSES.append("django_cas.middleware.CASMiddleware") - CAS_ATTRIBUTE_CALLBACK = config( - "CAS_ATTRIBUTE_CALLBACK", default=None, formatter=json.loads - ) - if CAS_ATTRIBUTE_CALLBACK: - import importlib - - CAS_USER_DETAILS_RESOLVER = getattr( - importlib.import_module(CAS_ATTRIBUTE_CALLBACK["module"]), - CAS_ATTRIBUTE_CALLBACK["function"], - ) - -# Video Caching. Pairing country codes with CDN URLs. -# Example: {'CN': 'http://api.xuetangx.com/edx/video?s3_url='} -VIDEO_CDN_URL = config("VIDEO_CDN_URL", default={}, formatter=json.loads) - -# Branded footer -FOOTER_OPENEDX_URL = config("FOOTER_OPENEDX_URL", default=FOOTER_OPENEDX_URL) -FOOTER_OPENEDX_LOGO_IMAGE = config( - "FOOTER_OPENEDX_LOGO_IMAGE", default=FOOTER_OPENEDX_LOGO_IMAGE -) -FOOTER_ORGANIZATION_IMAGE = config( - "FOOTER_ORGANIZATION_IMAGE", default=FOOTER_ORGANIZATION_IMAGE -) -FOOTER_CACHE_TIMEOUT = config( - "FOOTER_CACHE_TIMEOUT", default=FOOTER_CACHE_TIMEOUT, formatter=int -) -FOOTER_BROWSER_CACHE_MAX_AGE = config( - "FOOTER_BROWSER_CACHE_MAX_AGE", default=FOOTER_BROWSER_CACHE_MAX_AGE, formatter=int -) - -# Credit notifications settings -NOTIFICATION_EMAIL_CSS = config( - "NOTIFICATION_EMAIL_CSS", default=NOTIFICATION_EMAIL_CSS -) -NOTIFICATION_EMAIL_EDX_LOGO = config( - "NOTIFICATION_EMAIL_EDX_LOGO", default=NOTIFICATION_EMAIL_EDX_LOGO -) - -############# CORS headers for cross-domain requests ################# - -if FEATURES.get("ENABLE_CORS_HEADERS") or FEATURES.get( - "ENABLE_CROSS_DOMAIN_CSRF_COOKIE" -): - CORS_ALLOW_CREDENTIALS = True - CORS_ORIGIN_WHITELIST = config( - "CORS_ORIGIN_WHITELIST", default=(), formatter=json.loads - ) - CORS_ORIGIN_ALLOW_ALL = config( - "CORS_ORIGIN_ALLOW_ALL", default=False, formatter=bool - ) - CORS_ALLOW_INSECURE = config("CORS_ALLOW_INSECURE", default=False, formatter=bool) - - # If setting a cross-domain cookie, it's really important to choose - # a name for the cookie that is DIFFERENT than the cookies used - # by each subdomain. For example, suppose the applications - # at these subdomains are configured to use the following cookie names: - # - # 1) foo.example.com --> "csrftoken" - # 2) baz.example.com --> "csrftoken" - # 3) bar.example.com --> "csrftoken" - # - # For the cross-domain version of the CSRF cookie, you need to choose - # a name DIFFERENT than "csrftoken"; otherwise, the new token configured - # for ".example.com" could conflict with the other cookies, - # non-deterministically causing 403 responses. - # - # Because of the way Django stores cookies, the cookie name MUST - # be a `str`, not unicode. Otherwise there will `TypeError`s will be raised - # when Django tries to call the unicode `translate()` method with the wrong - # number of parameters. - CROSS_DOMAIN_CSRF_COOKIE_NAME = str(config("CROSS_DOMAIN_CSRF_COOKIE_NAME")) - - # When setting the domain for the "cross-domain" version of the CSRF - # cookie, you should choose something like: ".example.com" - # (note the leading dot), where both the referer and the host - # are subdomains of "example.com". - # - # Browser security rules require that - # the cookie domain matches the domain of the server; otherwise - # the cookie won't get set. And once the cookie gets set, the client - # needs to be on a domain that matches the cookie domain, otherwise - # the client won't be able to read the cookie. - CROSS_DOMAIN_CSRF_COOKIE_DOMAIN = config("CROSS_DOMAIN_CSRF_COOKIE_DOMAIN") - - -# Field overrides. To use the IDDE feature, add -# 'courseware.student_field_overrides.IndividualStudentOverrideProvider'. -FIELD_OVERRIDE_PROVIDERS = tuple( - config("FIELD_OVERRIDE_PROVIDERS", default=[], formatter=json.loads) -) - -############################## SECURE AUTH ITEMS ############### -# Secret things: passwords, access keys, etc. - -############### XBlock filesystem field config ########## -DJFS = config( - "DJFS", - default={ - "directory_root": "/edx/var/edxapp/django-pyfs/static/django-pyfs", - "type": "osfs", - "url_root": "/static/django-pyfs", - }, - formatter=json.loads, -) - -############### Module Store Items ########## -HOSTNAME_MODULESTORE_DEFAULT_MAPPINGS = config( - "HOSTNAME_MODULESTORE_DEFAULT_MAPPINGS", default={}, formatter=json.loads -) - -# PREVIEW DOMAIN must be present in HOSTNAME_MODULESTORE_DEFAULT_MAPPINGS for the preview to show draft changes -if "PREVIEW_LMS_BASE" in FEATURES and FEATURES["PREVIEW_LMS_BASE"] != "": - PREVIEW_DOMAIN = FEATURES["PREVIEW_LMS_BASE"].split(":")[0] - # update dictionary with preview domain regex - HOSTNAME_MODULESTORE_DEFAULT_MAPPINGS.update({PREVIEW_DOMAIN: "draft-preferred"}) - -############### Mixed Related(Secure/Not-Secure) Items ########## -LMS_SEGMENT_KEY = config("LMS_SEGMENT_KEY", default=None) - -CC_PROCESSOR_NAME = config("CC_PROCESSOR_NAME", default=CC_PROCESSOR_NAME) -CC_PROCESSOR = config("CC_PROCESSOR", default=CC_PROCESSOR) - -SECRET_KEY = config("SECRET_KEY", default="ThisisAnExampleKeyForDevPurposeOnly") - -# Authentication backends -# - behind a proxy, use: "lms.envs.fun.backends.ProxyRateLimitModelBackend" -# - for LTI provider, add: "lti_provider.users.LtiBackend" -# - for CAS, add: "django_cas.backends.CASBackend" -AUTHENTICATION_BACKENDS = config( - "AUTHENTICATION_BACKENDS", default=AUTHENTICATION_BACKENDS -) - -DEFAULT_FILE_STORAGE = config( - "DEFAULT_FILE_STORAGE", default="django.core.files.storage.FileSystemStorage" -) - -# Specific setting for the File Upload Service to store media in a bucket. -FILE_UPLOAD_STORAGE_BUCKET_NAME = config( - "FILE_UPLOAD_STORAGE_BUCKET_NAME", default="uploads" -) -FILE_UPLOAD_STORAGE_PREFIX = config( - "FILE_UPLOAD_STORAGE_PREFIX", default=FILE_UPLOAD_STORAGE_PREFIX -) - -# If there is a database called 'read_replica', you can use the use_read_replica_if_available -# function in util/query.py, which is useful for very large database reads - -DATABASE_ENGINE = config("DATABASE_ENGINE", default="django.db.backends.mysql") -DATABASE_HOST = config("DATABASE_HOST", default="mysql") -DATABASE_PORT = config("DATABASE_PORT", default=3306, formatter=int) -DATABASE_NAME = config("DATABASE_NAME", default="edxapp") -DATABASE_USER = config("DATABASE_USER", default="edxapp_user") -DATABASE_PASSWORD = config("DATABASE_PASSWORD", default="password") - -DATABASES = config( - "DATABASES", - default={ - "default": { - "ENGINE": DATABASE_ENGINE, - "HOST": DATABASE_HOST, - "PORT": DATABASE_PORT, - "NAME": DATABASE_NAME, - "USER": DATABASE_USER, - "PASSWORD": DATABASE_PASSWORD, - } - }, - formatter=json.loads, -) - -# Enable automatic transaction management on all databases -# https://docs.djangoproject.com/en/1.8/topics/db/transactions/#tying-transactions-to-http-requests -# This needs to be true for all databases -for database_name in DATABASES: - DATABASES[database_name]["ATOMIC_REQUESTS"] = True - -XQUEUE_INTERFACE = config( - "XQUEUE_INTERFACE", - default={"url": None, "basic_auth": None, "django_auth": None}, - formatter=json.loads, -) - -# Configure the MODULESTORE -MODULESTORE = convert_module_store_setting_if_needed( - config("MODULESTORE", default=MODULESTORE, formatter=json.loads) -) - -MONGODB_PASSWORD = config("MONGODB_PASSWORD", default="") -MONGODB_HOST = config("MONGODB_HOST", default="mongodb") -MONGODB_PORT = config("MONGODB_PORT", default=27017, formatter=int) -MONGODB_NAME = config("MONGODB_NAME", default="edxapp") -MONGODB_USER = config("MONGODB_USER", default=None) -MONGODB_SSL = config("MONGODB_SSL", default=False, formatter=bool) - -DOC_STORE_CONFIG = config( - "DOC_STORE_CONFIG", - default={ - "collection": "modulestore", - "host": MONGODB_HOST, - "port": MONGODB_PORT, - "db": MONGODB_NAME, - "user": MONGODB_USER, - "password": MONGODB_PASSWORD, - "ssl": MONGODB_SSL, - }, - formatter=json.loads, -) - -update_module_store_settings(MODULESTORE, doc_store_settings=DOC_STORE_CONFIG) - -MONGODB_LOG = config("MONGODB_LOG", default={}, formatter=json.loads) - -CONTENTSTORE = config( - "CONTENTSTORE", - default={ - "DOC_STORE_CONFIG": DOC_STORE_CONFIG, - "ENGINE": "xmodule.contentstore.mongo.MongoContentStore", - }, - formatter=json.loads, -) - -EMAIL_HOST_USER = config("EMAIL_HOST_USER", default="") # django default is '' -EMAIL_HOST_PASSWORD = config("EMAIL_HOST_PASSWORD", default="") # django default is '' - -# Datadog for events! -DATADOG = config("DATADOG", default={}, formatter=json.loads) - -# TODO: deprecated (compatibility with previous settings) -DATADOG_API = config("DATADOG_API", default=None) - -# Analytics dashboard server -ANALYTICS_SERVER_URL = config("ANALYTICS_SERVER_URL", default=None) -ANALYTICS_API_KEY = config("ANALYTICS_API_KEY", default="") - -# Analytics data source -ANALYTICS_DATA_URL = config("ANALYTICS_DATA_URL", default=ANALYTICS_DATA_URL) -ANALYTICS_DATA_TOKEN = config("ANALYTICS_DATA_TOKEN", default=ANALYTICS_DATA_TOKEN) - -# Analytics Dashboard -ANALYTICS_DASHBOARD_URL = config( - "ANALYTICS_DASHBOARD_URL", default=ANALYTICS_DASHBOARD_URL -) -ANALYTICS_DASHBOARD_NAME = config( - "ANALYTICS_DASHBOARD_NAME", default=PLATFORM_NAME + " Insights" -) - -# Mailchimp New User List -MAILCHIMP_NEW_USER_LIST_ID = config("MAILCHIMP_NEW_USER_LIST_ID", default=None) - -# Zendesk -ZENDESK_USER = config("ZENDESK_USER", default=None) -ZENDESK_API_KEY = config("ZENDESK_API_KEY", default=None) - -# API Key for inbound requests from Notifier service -EDX_API_KEY = config("EDX_API_KEY", default=None) - -# Celery Broker -CELERY_BROKER_TRANSPORT = config("CELERY_BROKER_TRANSPORT", default="redis") -CELERY_BROKER_USER = config("CELERY_BROKER_USER", default="") -CELERY_BROKER_PASSWORD = config("CELERY_BROKER_PASSWORD", default="") -CELERY_BROKER_HOST = config("CELERY_BROKER_HOST", default="redis") -CELERY_BROKER_PORT = config("CELERY_BROKER_PORT", default=6379, formatter=int) -CELERY_BROKER_VHOST = config("CELERY_BROKER_VHOST", default=0, formatter=int) - -BROKER_URL = "{transport}://{user}:{password}@{host}:{port}/{vhost}".format( - transport=CELERY_BROKER_TRANSPORT, - user=CELERY_BROKER_USER, - password=CELERY_BROKER_PASSWORD, - host=CELERY_BROKER_HOST, - port=CELERY_BROKER_PORT, - vhost=CELERY_BROKER_VHOST, -) - -# upload limits -STUDENT_FILEUPLOAD_MAX_SIZE = config( - "STUDENT_FILEUPLOAD_MAX_SIZE", default=STUDENT_FILEUPLOAD_MAX_SIZE, formatter=int -) - -# Event tracking -TRACKING_BACKENDS.update(config("TRACKING_BACKENDS", default={}, formatter=json.loads)) -EVENT_TRACKING_BACKENDS["tracking_logs"]["OPTIONS"]["backends"].update( - config("EVENT_TRACKING_BACKENDS", default={}, formatter=json.loads) -) -EVENT_TRACKING_BACKENDS["segmentio"]["OPTIONS"]["processors"][0]["OPTIONS"][ - "whitelist" -].extend( - config("EVENT_TRACKING_SEGMENTIO_EMIT_WHITELIST", default=[], formatter=json.loads) -) -TRACKING_SEGMENTIO_WEBHOOK_SECRET = config( - "TRACKING_SEGMENTIO_WEBHOOK_SECRET", default=TRACKING_SEGMENTIO_WEBHOOK_SECRET -) -TRACKING_SEGMENTIO_ALLOWED_TYPES = config( - "TRACKING_SEGMENTIO_ALLOWED_TYPES", - default=TRACKING_SEGMENTIO_ALLOWED_TYPES, - formatter=json.loads, -) -TRACKING_SEGMENTIO_DISALLOWED_SUBSTRING_NAMES = config( - "TRACKING_SEGMENTIO_DISALLOWED_SUBSTRING_NAMES", - default=TRACKING_SEGMENTIO_DISALLOWED_SUBSTRING_NAMES, - formatter=json.loads, -) -TRACKING_SEGMENTIO_SOURCE_MAP = config( - "TRACKING_SEGMENTIO_SOURCE_MAP", - default=TRACKING_SEGMENTIO_SOURCE_MAP, - formatter=json.loads, -) - -# Student identity verification settings -VERIFY_STUDENT = config("VERIFY_STUDENT", default=VERIFY_STUDENT, formatter=json.loads) - -# Grades download -GRADES_DOWNLOAD_ROUTING_KEY = config( - "GRADES_DOWNLOAD_ROUTING_KEY", default=HIGH_MEM_QUEUE -) - -GRADES_DOWNLOAD = config( - "GRADES_DOWNLOAD", default=GRADES_DOWNLOAD, formatter=json.loads -) - -GRADES_DOWNLOAD = config("GRADES_DOWNLOAD", default=GRADES_DOWNLOAD) - -# financial reports -FINANCIAL_REPORTS = config( - "FINANCIAL_REPORTS", default=FINANCIAL_REPORTS, formatter=json.loads -) - -##### ORA2 ###### -ORA2_FILEUPLOAD_BACKEND = config("ORA2_FILEUPLOAD_BACKEND", default="filesystem") - -# Prefix for uploads of example-based assessment AI classifiers -# This can be used to separate uploads for different environments -ORA2_FILE_PREFIX = config("ORA2_FILE_PREFIX", default=ORA2_FILE_PREFIX) - -# If backend is "filesystem" -ORA2_FILEUPLOAD_ROOT = DATA_DIR / "openassessment_submissions" -ORA2_FILEUPLOAD_CACHE_NAME = config( - "ORA2_FILEUPLOAD_CACHE_NAME", default="openassessment_submissions" -) - -# If backend is "swift" -ORA2_SWIFT_KEY = config("ORA2_SWIFT_KEY", default="") -ORA2_SWIFT_URL = config("ORA2_SWIFT_URL", default="") - -##### ACCOUNT LOCKOUT DEFAULT PARAMETERS ##### -MAX_FAILED_LOGIN_ATTEMPTS_ALLOWED = config( - "MAX_FAILED_LOGIN_ATTEMPTS_ALLOWED", default=5, formatter=int -) -MAX_FAILED_LOGIN_ATTEMPTS_LOCKOUT_PERIOD_SECS = config( - "MAX_FAILED_LOGIN_ATTEMPTS_LOCKOUT_PERIOD_SECS", default=15 * 60, formatter=int -) - -MICROSITE_CONFIGURATION = config( - "MICROSITE_CONFIGURATION", default={}, formatter=json.loads -) -MICROSITE_ROOT_DIR = path(config("MICROSITE_ROOT_DIR", default="")) - -#### PASSWORD POLICY SETTINGS ##### -PASSWORD_MIN_LENGTH = config("PASSWORD_MIN_LENGTH", default=12, formatter=int) -PASSWORD_MAX_LENGTH = config("PASSWORD_MAX_LENGTH", default=None, formatter=int) - -PASSWORD_COMPLEXITY = config( - "PASSWORD_COMPLEXITY", - default={"UPPER": 1, "LOWER": 1, "DIGITS": 1}, - formatter=json.loads, -) -PASSWORD_DICTIONARY_EDIT_DISTANCE_THRESHOLD = config( - "PASSWORD_DICTIONARY_EDIT_DISTANCE_THRESHOLD", - default=PASSWORD_DICTIONARY_EDIT_DISTANCE_THRESHOLD, - formatter=int, -) -PASSWORD_DICTIONARY = config("PASSWORD_DICTIONARY", default=[], formatter=json.loads) - -### INACTIVITY SETTINGS #### -SESSION_INACTIVITY_TIMEOUT_IN_SECONDS = config( - "SESSION_INACTIVITY_TIMEOUT_IN_SECONDS", default=None, formatter=int -) - -##### LMS DEADLINE DISPLAY TIME_ZONE ####### -TIME_ZONE_DISPLAYED_FOR_DEADLINES = config( - "TIME_ZONE_DISPLAYED_FOR_DEADLINES", default=TIME_ZONE_DISPLAYED_FOR_DEADLINES -) - -##### X-Frame-Options response header settings ##### -X_FRAME_OPTIONS = config("X_FRAME_OPTIONS", default=X_FRAME_OPTIONS) - -##### Third-party auth options ################################################ -if FEATURES.get("ENABLE_THIRD_PARTY_AUTH"): - # The reduced session expiry time during the third party login pipeline. (Value in seconds) - SOCIAL_AUTH_PIPELINE_TIMEOUT = config("SOCIAL_AUTH_PIPELINE_TIMEOUT", default=600) - - # The SAML private/public key values do not need the delimiter lines (such as - # "-----BEGIN PRIVATE KEY-----", default="-----END PRIVATE KEY-----" etc.) but they may be included - # if you want (though it's easier to format the key values as JSON without the delimiters). - SOCIAL_AUTH_SAML_SP_PRIVATE_KEY = config( - "SOCIAL_AUTH_SAML_SP_PRIVATE_KEY", default="" - ) - SOCIAL_AUTH_SAML_SP_PUBLIC_CERT = config( - "SOCIAL_AUTH_SAML_SP_PUBLIC_CERT", default="" - ) - SOCIAL_AUTH_OAUTH_SECRETS = config( - "SOCIAL_AUTH_OAUTH_SECRETS", default={}, formatter=json.loads - ) - SOCIAL_AUTH_LTI_CONSUMER_SECRETS = config( - "SOCIAL_AUTH_LTI_CONSUMER_SECRETS", default={}, formatter=json.loads - ) - - # third_party_auth config moved to ConfigurationModels. This is for data migration only: - THIRD_PARTY_AUTH_OLD_CONFIG = config("THIRD_PARTY_AUTH", default=None) - - if ( - config("THIRD_PARTY_AUTH_SAML_FETCH_PERIOD_HOURS", default=24, formatter=int) - is not None - ): - CELERYBEAT_SCHEDULE["refresh-saml-metadata"] = { - "task": "third_party_auth.fetch_saml_metadata", - "schedule": datetime.timedelta( - hours=config( - "THIRD_PARTY_AUTH_SAML_FETCH_PERIOD_HOURS", - default=24, - formatter=int, - ) - ), - } - - # The following can be used to integrate a custom login form with third_party_auth. - # It should be a dict where the key is a word passed via ?auth_entry=, and the value is a - # dict with an arbitrary 'secret_key' and a 'url'. - THIRD_PARTY_AUTH_CUSTOM_AUTH_FORMS = config( - "THIRD_PARTY_AUTH_CUSTOM_AUTH_FORMS", default={}, formatter=json.loads - ) - -##### OAUTH2 Provider ############## -if FEATURES.get("ENABLE_OAUTH2_PROVIDER"): - OAUTH_OIDC_ISSUER = config("OAUTH_OIDC_ISSUER", default=None) - OAUTH_ENFORCE_SECURE = config("OAUTH_ENFORCE_SECURE", default=True, formatter=bool) - OAUTH_ENFORCE_CLIENT_SECURE = config( - "OAUTH_ENFORCE_CLIENT_SECURE", default=True, formatter=bool - ) - -##### ADVANCED_SECURITY_CONFIG ##### -ADVANCED_SECURITY_CONFIG = config( - "ADVANCED_SECURITY_CONFIG", default={}, formatter=json.loads -) - -##### GOOGLE ANALYTICS IDS ##### -GOOGLE_ANALYTICS_ACCOUNT = config("GOOGLE_ANALYTICS_ACCOUNT", default=None) -GOOGLE_ANALYTICS_LINKEDIN = config("GOOGLE_ANALYTICS_LINKEDIN", default=None) - -##### OPTIMIZELY PROJECT ID ##### -OPTIMIZELY_PROJECT_ID = config("OPTIMIZELY_PROJECT_ID", default=OPTIMIZELY_PROJECT_ID) - -#### Course Registration Code length #### -REGISTRATION_CODE_LENGTH = config("REGISTRATION_CODE_LENGTH", default=8, formatter=int) - -# REGISTRATION CODES DISPLAY INFORMATION -INVOICE_CORP_ADDRESS = config("INVOICE_CORP_ADDRESS", default=INVOICE_CORP_ADDRESS) -INVOICE_PAYMENT_INSTRUCTIONS = config( - "INVOICE_PAYMENT_INSTRUCTIONS", default=INVOICE_PAYMENT_INSTRUCTIONS -) - -# Which access.py permission names to check; -# We default this to the legacy permission 'see_exists'. -COURSE_CATALOG_VISIBILITY_PERMISSION = config( - "COURSE_CATALOG_VISIBILITY_PERMISSION", default=COURSE_CATALOG_VISIBILITY_PERMISSION -) -COURSE_ABOUT_VISIBILITY_PERMISSION = config( - "COURSE_ABOUT_VISIBILITY_PERMISSION", default=COURSE_ABOUT_VISIBILITY_PERMISSION -) - -# Enrollment API Cache Timeout -ENROLLMENT_COURSE_DETAILS_CACHE_TIMEOUT = config( - "ENROLLMENT_COURSE_DETAILS_CACHE_TIMEOUT", default=60, formatter=int -) - -# PDF RECEIPT/INVOICE OVERRIDES -PDF_RECEIPT_TAX_ID = config("PDF_RECEIPT_TAX_ID", default=PDF_RECEIPT_TAX_ID) -PDF_RECEIPT_FOOTER_TEXT = config( - "PDF_RECEIPT_FOOTER_TEXT", default=PDF_RECEIPT_FOOTER_TEXT -) -PDF_RECEIPT_DISCLAIMER_TEXT = config( - "PDF_RECEIPT_DISCLAIMER_TEXT", default=PDF_RECEIPT_DISCLAIMER_TEXT -) -PDF_RECEIPT_BILLING_ADDRESS = config( - "PDF_RECEIPT_BILLING_ADDRESS", default=PDF_RECEIPT_BILLING_ADDRESS -) -PDF_RECEIPT_TERMS_AND_CONDITIONS = config( - "PDF_RECEIPT_TERMS_AND_CONDITIONS", default=PDF_RECEIPT_TERMS_AND_CONDITIONS -) -PDF_RECEIPT_TAX_ID_LABEL = config( - "PDF_RECEIPT_TAX_ID_LABEL", default=PDF_RECEIPT_TAX_ID_LABEL -) -PDF_RECEIPT_LOGO_PATH = config("PDF_RECEIPT_LOGO_PATH", default=PDF_RECEIPT_LOGO_PATH) -PDF_RECEIPT_COBRAND_LOGO_PATH = config( - "PDF_RECEIPT_COBRAND_LOGO_PATH", default=PDF_RECEIPT_COBRAND_LOGO_PATH -) -PDF_RECEIPT_LOGO_HEIGHT_MM = config( - "PDF_RECEIPT_LOGO_HEIGHT_MM", default=PDF_RECEIPT_LOGO_HEIGHT_MM, formatter=int -) -PDF_RECEIPT_COBRAND_LOGO_HEIGHT_MM = config( - "PDF_RECEIPT_COBRAND_LOGO_HEIGHT_MM", - default=PDF_RECEIPT_COBRAND_LOGO_HEIGHT_MM, - formatter=int, -) - -if ( - FEATURES.get("ENABLE_COURSEWARE_SEARCH") - or FEATURES.get("ENABLE_DASHBOARD_SEARCH") - or FEATURES.get("ENABLE_COURSE_DISCOVERY") - or FEATURES.get("ENABLE_TEAMS") -): - # Use ElasticSearch as the search engine herein - SEARCH_ENGINE = "search.elastic.ElasticSearchEngine" - -ELASTIC_SEARCH_CONFIG = config( - "ELASTIC_SEARCH_CONFIG", default=[{}], formatter=json.loads -) - -# Facebook app -FACEBOOK_API_VERSION = config("FACEBOOK_API_VERSION", default=None) -FACEBOOK_APP_SECRET = config("FACEBOOK_APP_SECRET", default=None) -FACEBOOK_APP_ID = config("FACEBOOK_APP_ID", default=None) - -XBLOCK_SETTINGS = config("XBLOCK_SETTINGS", default={}, formatter=json.loads) -XBLOCK_SETTINGS.setdefault("VideoDescriptor", {})["licensing_enabled"] = FEATURES.get( - "LICENSING", False -) -XBLOCK_SETTINGS.setdefault("VideoModule", {})["YOUTUBE_API_KEY"] = config( - "YOUTUBE_API_KEY", default=YOUTUBE_API_KEY -) - -##### CDN EXPERIMENT/MONITORING FLAGS ##### -CDN_VIDEO_URLS = config("CDN_VIDEO_URLS", default=CDN_VIDEO_URLS) -ONLOAD_BEACON_SAMPLE_RATE = config( - "ONLOAD_BEACON_SAMPLE_RATE", default=ONLOAD_BEACON_SAMPLE_RATE -) - -##### ECOMMERCE API CONFIGURATION SETTINGS ##### -ECOMMERCE_PUBLIC_URL_ROOT = config( - "ECOMMERCE_PUBLIC_URL_ROOT", default=ECOMMERCE_PUBLIC_URL_ROOT -) -ECOMMERCE_API_URL = config("ECOMMERCE_API_URL", default=ECOMMERCE_API_URL) -ECOMMERCE_API_TIMEOUT = config( - "ECOMMERCE_API_TIMEOUT", default=ECOMMERCE_API_TIMEOUT, formatter=int -) - -ECOMMERCE_SERVICE_WORKER_USERNAME = config( - "ECOMMERCE_SERVICE_WORKER_USERNAME", default=ECOMMERCE_SERVICE_WORKER_USERNAME -) -ECOMMERCE_API_TIMEOUT = config("ECOMMERCE_API_TIMEOUT", default=ECOMMERCE_API_TIMEOUT) - -##### Custom Courses for EdX ##### -if FEATURES.get("CUSTOM_COURSES_EDX"): - INSTALLED_APPS += ("lms.djangoapps.ccx",) - FIELD_OVERRIDE_PROVIDERS += ( - "lms.djangoapps.ccx.overrides.CustomCoursesForEdxOverrideProvider", - ) -CCX_MAX_STUDENTS_ALLOWED = config( - "CCX_MAX_STUDENTS_ALLOWED", default=CCX_MAX_STUDENTS_ALLOWED -) - -##### Individual Due Date Extensions ##### -if FEATURES.get("INDIVIDUAL_DUE_DATES"): - FIELD_OVERRIDE_PROVIDERS += ( - "courseware.student_field_overrides.IndividualStudentOverrideProvider", - ) - -##### Self-Paced Course Due Dates ##### -FIELD_OVERRIDE_PROVIDERS += ( - "courseware.self_paced_overrides.SelfPacedDateOverrideProvider", -) - -# PROFILE IMAGE CONFIG -PROFILE_IMAGE_BACKEND = config("PROFILE_IMAGE_BACKEND", default=PROFILE_IMAGE_BACKEND) -PROFILE_IMAGE_SECRET_KEY = config( - "PROFILE_IMAGE_SECRET_KEY", default=PROFILE_IMAGE_SECRET_KEY -) -PROFILE_IMAGE_MAX_BYTES = config( - "PROFILE_IMAGE_MAX_BYTES", default=PROFILE_IMAGE_MAX_BYTES, formatter=int -) -PROFILE_IMAGE_MIN_BYTES = config( - "PROFILE_IMAGE_MIN_BYTES", default=PROFILE_IMAGE_MIN_BYTES, formatter=int -) -PROFILE_IMAGE_DEFAULT_FILENAME = "images/profiles/default" - -# EdxNotes config - -EDXNOTES_PUBLIC_API = config("EDXNOTES_PUBLIC_API", default=EDXNOTES_PUBLIC_API) -EDXNOTES_INTERNAL_API = config("EDXNOTES_INTERNAL_API", default=EDXNOTES_INTERNAL_API) - -##### Credit Provider Integration ##### - -CREDIT_PROVIDER_SECRET_KEYS = config( - "CREDIT_PROVIDER_SECRET_KEYS", default={}, formatter=json.loads -) - -##################### LTI Provider ##################### -if FEATURES.get("ENABLE_LTI_PROVIDER"): - INSTALLED_APPS += ("lti_provider",) - -LTI_USER_EMAIL_DOMAIN = config("LTI_USER_EMAIL_DOMAIN", default="lti.example.com") - -# For more info on this, see the notes in common.py -LTI_AGGREGATE_SCORE_PASSBACK_DELAY = config( - "LTI_AGGREGATE_SCORE_PASSBACK_DELAY", default=LTI_AGGREGATE_SCORE_PASSBACK_DELAY -) - -##################### Credit Provider help link #################### -CREDIT_HELP_LINK_URL = config("CREDIT_HELP_LINK_URL", default=CREDIT_HELP_LINK_URL) - -#### JWT configuration #### -JWT_ISSUER = config("JWT_ISSUER", default=JWT_ISSUER) -JWT_EXPIRATION = config("JWT_EXPIRATION", default=JWT_EXPIRATION) - -################# PROCTORING CONFIGURATION ################## - -PROCTORING_BACKEND_PROVIDER = config( - "PROCTORING_BACKEND_PROVIDER", default=PROCTORING_BACKEND_PROVIDER -) -PROCTORING_SETTINGS = config( - "PROCTORING_SETTINGS", default=PROCTORING_SETTINGS, formatter=json.loads -) - -################# MICROSITE #################### -MICROSITE_CONFIGURATION = config( - "MICROSITE_CONFIGURATION", default={}, formatter=json.loads -) -MICROSITE_ROOT_DIR = path(config("MICROSITE_ROOT_DIR", default="")) - -# Cutoff date for granting audit certificates -if config("AUDIT_CERT_CUTOFF_DATE", default=None): - AUDIT_CERT_CUTOFF_DATE = dateutil.parser.parse( - config("AUDIT_CERT_CUTOFF_DATE", default=AUDIT_CERT_CUTOFF_DATE) - ) diff --git a/releases/dogwood/3/bare/config/lms/docker_run_staging.py b/releases/dogwood/3/bare/config/lms/docker_run_staging.py deleted file mode 100644 index 7c878eb2..00000000 --- a/releases/dogwood/3/bare/config/lms/docker_run_staging.py +++ /dev/null @@ -1,14 +0,0 @@ -# This file includes overrides to build the `staging` environment for the LMS starting from the -# settings of the `production` environment - -from docker_run_production import * -from .utils import Configuration - -# Load custom configuration parameters from yaml files -config = Configuration(os.path.dirname(__file__)) - -LOGGING["handlers"]["sentry"]["environment"] = "staging" - -EMAIL_BACKEND = config( - "EMAIL_BACKEND", default="django.core.mail.backends.console.EmailBackend" -) diff --git a/releases/dogwood/3/bare/config/lms/storage.py b/releases/dogwood/3/bare/config/lms/storage.py deleted file mode 100644 index f78e9d7c..00000000 --- a/releases/dogwood/3/bare/config/lms/storage.py +++ /dev/null @@ -1,28 +0,0 @@ -"""Django static file storage backend for OpenEdX.""" -from django.conf import settings - -from pipeline.storage import PipelineCachedStorage - -from openedx.core.storage import ProductionStorage - - -class CDNMixin(object): - """Mixin to activate CDN urls on a static files storage backend.""" - - def url(self, name, force=False): - """Prepend static files path by the CDN base url when configured in settings.""" - url = super(CDNMixin, self).url(name, force=force) - - cdn_base_url = getattr(settings, "CDN_BASE_URL", None) - if cdn_base_url: - url = "{:s}{:s}".format(cdn_base_url, url) - - return url - - -class CDNProductionStorage(CDNMixin, ProductionStorage): - """Open edX LMS production static files storage backend that can be placed behing a CDN.""" - - -class CDNPipelineCachedStorage(CDNMixin, PipelineCachedStorage): - """Open edX Studio production static files storage backend that can be placed behing a CDN.""" diff --git a/releases/dogwood/3/bare/config/lms/utils.py b/releases/dogwood/3/bare/config/lms/utils.py deleted file mode 100644 index 04175236..00000000 --- a/releases/dogwood/3/bare/config/lms/utils.py +++ /dev/null @@ -1,110 +0,0 @@ -# -*- coding: utf-8 -*- - -import yaml -import os - -from django.core.exceptions import ImproperlyConfigured - - -class Configuration(dict): - """ - Try getting a setting from the settings.yml or secrets.yml files placed in - the directory passed when initializing the configuration instance. - """ - - def __init__(self, dir=None, *args, **kwargs): - """ - Initialize with the path to the directory in which the configuration is - to be found. - """ - super(Configuration, self).__init__(*args, **kwargs) - - if dir is None: - self.settings = {} - - else: - # Load the content of a `settings.yml` file placed in the current - # directory if any. This file is where customizable settings are stored - # for a given environment. - try: - with open(os.path.join(dir, "settings.yml")) as f: - settings = yaml.load(f.read()) or {} - except IOError: - settings = {} - - # Load the content of a `secrets.yml` file placed in the current - # directory if any. This file is where sensitive credentials are stored - # for a given environment. - try: - with open(os.path.join(dir, "secrets.yml")) as f: - credentials = yaml.load(f.read()) or {} - except IOError: - credentials = {} - - settings.update(credentials) - self.settings = settings - - def __call__(self, var_name, formatter=str, *args, **kwargs): - """ - The config returns in order of priority: - - - the value set in the secrets.yml file, - - the value set in the settings.yml file, - - the value set as environment variable - - the value passed as default. - - If the value is passed as a string, a type is forced via the function passed in - the "formatter" kwarg. - - Raise an "ImproperlyConfigured" error if the name is not found, except - if the `default` key is given in kwargs (using kwargs allows to pass a - default to None, which is different from not passing any default): - - $ config = Configuration('path/to/config/directory') - $ config('foo') # raise ImproperlyConfigured error if `foo` is not defined - $ config('foo', default='bar') # return 'bar' if `foo` is not defined - $ config('foo', default=None) # return `None` if `foo` is not defined - """ - try: - value = self.settings[var_name] - except KeyError: - try: - value = formatter(os.environ[var_name]) - except KeyError: - if "default" in kwargs: - value = kwargs["default"] - else: - raise ImproperlyConfigured( - 'Please set the "{:s}" variable in a settings.yml file, a secrets.yml ' - "file or an environment variable.".format(var_name) - ) - # If a formatter is specified, force the value but only if it was passed as a string - if isinstance(value, basestring): - value = formatter(value.encode("utf-8")) - - return value - - def get(self, name, *args, **kwargs): - """ - edX is loading the content of 2 json files to settings.ENV_TOKEN and settings.AUTH_TOKEN - They have started calling these attributes anywhere in the code base, so we must make - sure that the following call works (and the same for AUTH_TOKEN): - - settings.ENV_TOKEN.get('ANY_SETTING_NAME') - - That's what this method will do after we add this to our settings: - ``` - config = Configuration('path/to/my/settings/directory.yml') - ENV_TOKEN = config - AUTH_TOKEN = config - ``` - """ - try: - default = args[0] - except IndexError: - # As a first approach, all defaults that are not provided by Open edX are set to None. - # If this creates a problem, we can either: - # - make sure we provide a value for this setting in our yaml files, - # - make a PR to Open edX to provide a better default for this setting. - default = None - return self(name, default=default) diff --git a/releases/dogwood/3/bare/entrypoint.sh b/releases/dogwood/3/bare/entrypoint.sh deleted file mode 100755 index 07331910..00000000 --- a/releases/dogwood/3/bare/entrypoint.sh +++ /dev/null @@ -1,8 +0,0 @@ -#!/usr/bin/env bash -# -# Development entrypoint -# - -# Activate user's virtualenv -source /edx/app/edxapp/venv/bin/activate -exec "$@"