Merge branch 'master' into sameeramin/ENT-10688
This commit is contained in:
@@ -32,13 +32,19 @@ from django.core.exceptions import PermissionDenied
|
||||
from django.http import HttpResponse
|
||||
from django.shortcuts import redirect
|
||||
from django.utils.translation import gettext as _
|
||||
from django.utils.decorators import method_decorator
|
||||
from django.views.decorators.csrf import ensure_csrf_cookie
|
||||
from django.views.decorators.http import require_http_methods
|
||||
from rest_framework.views import APIView
|
||||
from rest_framework.permissions import IsAuthenticated
|
||||
from rest_framework.response import Response
|
||||
from rest_framework import status
|
||||
from common.djangoapps.course_modes.models import CourseMode
|
||||
from eventtracking import tracker
|
||||
from opaque_keys import InvalidKeyError
|
||||
from opaque_keys.edx.keys import AssetKey, CourseKey
|
||||
|
||||
from openedx.core.lib.api.view_utils import DeveloperErrorViewMixin
|
||||
from common.djangoapps.edxmako.shortcuts import render_to_response
|
||||
from common.djangoapps.student.auth import has_studio_write_access
|
||||
from common.djangoapps.student.roles import GlobalStaff
|
||||
@@ -47,6 +53,10 @@ from common.djangoapps.util.json_request import JsonResponse
|
||||
from xmodule.modulestore import EdxJSONEncoder # lint-amnesty, pylint: disable=wrong-import-order
|
||||
from xmodule.modulestore.django import modulestore # lint-amnesty, pylint: disable=wrong-import-order
|
||||
|
||||
from cms.djangoapps.contentstore.views.serializers import CertificateActivationSerializer
|
||||
from cms.djangoapps.contentstore.views.permissions import HasStudioWriteAccess
|
||||
|
||||
|
||||
from ..exceptions import AssetNotFoundException
|
||||
from ..toggles import use_new_certificates_page
|
||||
from ..utils import (
|
||||
@@ -360,39 +370,56 @@ class Certificate:
|
||||
return self._certificate_data
|
||||
|
||||
|
||||
@login_required
|
||||
@require_http_methods(("POST",))
|
||||
@ensure_csrf_cookie
|
||||
def certificate_activation_handler(request, course_key_string):
|
||||
class ModulestoreMixin:
|
||||
"""
|
||||
A handler for Certificate Activation/Deactivation
|
||||
|
||||
POST
|
||||
json: is_active. update the activation state of certificate
|
||||
Mixin to provide a get_modulestore() method for views.
|
||||
Makes it easier to override or patch in tests.
|
||||
"""
|
||||
course_key = CourseKey.from_string(course_key_string)
|
||||
store = modulestore()
|
||||
try:
|
||||
course = _get_course_and_check_access(course_key, request.user)
|
||||
except PermissionDenied:
|
||||
msg = _('PermissionDenied: Failed in authenticating {user}').format(user=request.user)
|
||||
return JsonResponse({"error": msg}, status=403)
|
||||
def get_modulestore(self):
|
||||
return modulestore()
|
||||
|
||||
data = json.loads(request.body.decode('utf8'))
|
||||
is_active = data.get('is_active', False)
|
||||
certificates = CertificateManager.get_certificates(course)
|
||||
|
||||
# for certificate activation/deactivation, we are assuming one certificate in certificates collection.
|
||||
for certificate in certificates:
|
||||
certificate['is_active'] = is_active
|
||||
break
|
||||
class CertificateActivationAPIView(
|
||||
DeveloperErrorViewMixin,
|
||||
ModulestoreMixin,
|
||||
APIView
|
||||
):
|
||||
"""
|
||||
View for activating or deactivating course certificates.
|
||||
This view allows instructors to toggle the activation state of course certificates.
|
||||
"""
|
||||
permission_classes = [IsAuthenticated, HasStudioWriteAccess]
|
||||
serializer_class = CertificateActivationSerializer
|
||||
|
||||
store.update_item(course, request.user.id)
|
||||
cert_event_type = 'activated' if is_active else 'deactivated'
|
||||
CertificateManager.track_event(cert_event_type, {
|
||||
'course_id': str(course.id),
|
||||
})
|
||||
return HttpResponse(status=200)
|
||||
@method_decorator(ensure_csrf_cookie)
|
||||
def post(self, request, course_key_string):
|
||||
"""
|
||||
A handler for Certificate Activation/Deactivation
|
||||
|
||||
POST
|
||||
json: is_active. update the activation state of certificate
|
||||
"""
|
||||
course_key = CourseKey.from_string(course_key_string)
|
||||
course = self.get_modulestore().get_course(course_key, depth=0)
|
||||
|
||||
serializer = self.serializer_class(data=request.data)
|
||||
if not serializer.is_valid():
|
||||
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
is_active = serializer.validated_data['is_active']
|
||||
certificates = CertificateManager.get_certificates(course)
|
||||
|
||||
# for certificate activation/deactivation, we are assuming one certificate in certificates collection.
|
||||
for certificate in certificates:
|
||||
certificate['is_active'] = is_active
|
||||
break
|
||||
|
||||
self.get_modulestore().update_item(course, request.user.id)
|
||||
cert_event_type = 'activated' if is_active else 'deactivated'
|
||||
CertificateManager.track_event(cert_event_type, {
|
||||
'course_id': str(course.id),
|
||||
})
|
||||
return Response(status=status.HTTP_200_OK)
|
||||
|
||||
|
||||
@login_required
|
||||
|
||||
22
cms/djangoapps/contentstore/views/permissions.py
Normal file
22
cms/djangoapps/contentstore/views/permissions.py
Normal file
@@ -0,0 +1,22 @@
|
||||
"""
|
||||
Custom permissions for the content store views.
|
||||
"""
|
||||
|
||||
from rest_framework.permissions import BasePermission
|
||||
|
||||
from common.djangoapps.student.auth import has_studio_write_access
|
||||
from openedx.core.lib.api.view_utils import validate_course_key
|
||||
|
||||
|
||||
class HasStudioWriteAccess(BasePermission):
|
||||
"""
|
||||
Check if the user has write access to studio.
|
||||
"""
|
||||
|
||||
def has_permission(self, request, view):
|
||||
"""
|
||||
Check if the user has write access to studio.
|
||||
"""
|
||||
course_key_string = view.kwargs.get("course_key_string")
|
||||
course_key = validate_course_key(course_key_string)
|
||||
return has_studio_write_access(request.user, course_key)
|
||||
16
cms/djangoapps/contentstore/views/serializers.py
Normal file
16
cms/djangoapps/contentstore/views/serializers.py
Normal file
@@ -0,0 +1,16 @@
|
||||
"""
|
||||
Serializers for the contentstore.views module.
|
||||
|
||||
This module contains DRF serializers for various features such as certificates, blocks, and others.
|
||||
Add new serializers here as needed for API endpoints in this module.
|
||||
"""
|
||||
|
||||
from rest_framework import serializers
|
||||
|
||||
|
||||
class CertificateActivationSerializer(serializers.Serializer):
|
||||
"""
|
||||
Serializer for activating or deactivating course certificates.
|
||||
"""
|
||||
# This field indicates whether the certificate should be activated or deactivated.
|
||||
is_active = serializers.BooleanField(required=False, default=False)
|
||||
@@ -1303,13 +1303,12 @@ def create_xblock_info( # lint-amnesty, pylint: disable=too-many-statements
|
||||
|
||||
# Update with gating info
|
||||
xblock_info.update(_get_gating_info(course, xblock))
|
||||
# Also add upstream info
|
||||
xblock_info["upstream_info"] = UpstreamLink.try_get_for_block(xblock, log_error=False).to_json()
|
||||
if is_xblock_unit:
|
||||
# if xblock is a Unit we add the discussion_enabled option
|
||||
xblock_info["discussion_enabled"] = xblock.discussion_enabled
|
||||
|
||||
# Also add upstream info
|
||||
xblock_info["upstream_info"] = UpstreamLink.try_get_for_block(xblock, log_error=False).to_json()
|
||||
|
||||
if xblock.category == "sequential":
|
||||
# Entrance exam subsection should be hidden. in_entrance_exam is
|
||||
# inherited metadata, all children will have it.
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
"""
|
||||
Settings for running management commands for the Analytics Exporter.
|
||||
|
||||
The Analytics Exporter jobs run edxapp management commands using production
|
||||
settings and configuration, however they currently DO NOT use edxapp production
|
||||
environments (such as edxapp Amazon AMIs or Docker images) where theme files
|
||||
get installed. As a result we must disable comprehensive theming or else
|
||||
startup checks from the theming app will throw an error due to missing themes.
|
||||
"""
|
||||
|
||||
from .production import * # pylint: disable=wildcard-import, unused-wildcard-import
|
||||
|
||||
ENABLE_COMPREHENSIVE_THEMING = False
|
||||
@@ -1,553 +0,0 @@
|
||||
# This file is an experimental extraction of /edx/etc/studio.yml from
|
||||
# a CMS devstack container.
|
||||
#
|
||||
# When devstack is configured to use the new `openedx/` images
|
||||
# instead of the old `edxops/edxapp` image, it will use this file
|
||||
# as input to cms/envs/production.py (and, in turn, cms/envs/devstack.py).
|
||||
# If you are using devstack with the `edxops/edxapp` image, though,
|
||||
# this file is NOT used.
|
||||
#
|
||||
# Q. Should I update this file when I update devstack.py?
|
||||
# A. You don't *have* to, because settings in devstack.py
|
||||
# override these settings. But, it doesn't harm to also make them
|
||||
# here in order to quell confusion. The hope is that we'll
|
||||
# adpot OEP-45 eventually, which recommends against having
|
||||
# a devstack.py at all.
|
||||
#
|
||||
# This is part of the effort to move our dev tools off of Ansible and
|
||||
# Paver, described here: https://github.com/openedx/devstack/pull/866
|
||||
# TODO: If the effort described above is abandoned, then this file should
|
||||
# probably be deleted.
|
||||
ACTIVATION_EMAIL_SUPPORT_LINK: ''
|
||||
AFFILIATE_COOKIE_NAME: dev_affiliate_id
|
||||
ALTERNATE_WORKER_QUEUES: lms
|
||||
ANALYTICS_DASHBOARD_NAME: Your Platform Name Here Insights
|
||||
ANALYTICS_DASHBOARD_URL: http://localhost:18110/courses
|
||||
AUTH_PASSWORD_VALIDATORS:
|
||||
- NAME: django.contrib.auth.password_validation.UserAttributeSimilarityValidator
|
||||
- NAME: common.djangoapps.util.password_policy_validators.MinimumLengthValidator
|
||||
OPTIONS:
|
||||
min_length: 2
|
||||
- NAME: common.djangoapps.util.password_policy_validators.MaximumLengthValidator
|
||||
OPTIONS:
|
||||
max_length: 75
|
||||
AUTHORING_API_URL: https://example.com
|
||||
AWS_ACCESS_KEY_ID: null
|
||||
AWS_QUERYSTRING_AUTH: false
|
||||
AWS_S3_CUSTOM_DOMAIN: SET-ME-PLEASE (ex. bucket-name.s3.amazonaws.com)
|
||||
AWS_SECRET_ACCESS_KEY: null
|
||||
AWS_SES_REGION_ENDPOINT: email.us-east-1.amazonaws.com
|
||||
AWS_SES_REGION_NAME: us-east-1
|
||||
AWS_STORAGE_BUCKET_NAME: SET-ME-PLEASE (ex. bucket-name)
|
||||
BASE_COOKIE_DOMAIN: localhost
|
||||
BLOCK_STRUCTURES_SETTINGS:
|
||||
COURSE_PUBLISH_TASK_DELAY: 30
|
||||
TASK_DEFAULT_RETRY_DELAY: 30
|
||||
TASK_MAX_RETRIES: 5
|
||||
BRANCH_IO_KEY: ''
|
||||
BUGS_EMAIL: bugs@example.com
|
||||
BULK_EMAIL_DEFAULT_FROM_EMAIL: no-reply@example.com
|
||||
BULK_EMAIL_EMAILS_PER_TASK: 500
|
||||
BULK_EMAIL_LOG_SENT_EMAILS: false
|
||||
CACHES:
|
||||
celery:
|
||||
BACKEND: django.core.cache.backends.memcached.PyMemcacheCache
|
||||
OPTIONS:
|
||||
no_delay: true
|
||||
ignore_exc: true
|
||||
use_pooling: true
|
||||
connect_timeout: 0.5
|
||||
KEY_FUNCTION: common.djangoapps.util.memcache.safe_key
|
||||
KEY_PREFIX: celery
|
||||
LOCATION:
|
||||
- edx.devstack.memcached:11211
|
||||
TIMEOUT: '7200'
|
||||
configuration:
|
||||
BACKEND: django.core.cache.backends.memcached.PyMemcacheCache
|
||||
OPTIONS:
|
||||
no_delay: true
|
||||
ignore_exc: true
|
||||
use_pooling: true
|
||||
connect_timeout: 0.5
|
||||
KEY_FUNCTION: common.djangoapps.util.memcache.safe_key
|
||||
KEY_PREFIX: 78f87108afce
|
||||
LOCATION:
|
||||
- edx.devstack.memcached:11211
|
||||
course_structure_cache:
|
||||
BACKEND: django.core.cache.backends.memcached.PyMemcacheCache
|
||||
OPTIONS:
|
||||
no_delay: true
|
||||
ignore_exc: true
|
||||
use_pooling: true
|
||||
connect_timeout: 0.5
|
||||
KEY_FUNCTION: common.djangoapps.util.memcache.safe_key
|
||||
KEY_PREFIX: course_structure
|
||||
LOCATION:
|
||||
- edx.devstack.memcached:11211
|
||||
TIMEOUT: '604800'
|
||||
default:
|
||||
BACKEND: django.core.cache.backends.memcached.PyMemcacheCache
|
||||
OPTIONS:
|
||||
ignore_exc: true
|
||||
no_delay: true
|
||||
use_pooling: true
|
||||
connect_timeout: 0.5
|
||||
KEY_FUNCTION: common.djangoapps.util.memcache.safe_key
|
||||
KEY_PREFIX: default
|
||||
LOCATION:
|
||||
- edx.devstack.memcached:11211
|
||||
VERSION: '1'
|
||||
general:
|
||||
BACKEND: django.core.cache.backends.memcached.PyMemcacheCache
|
||||
OPTIONS:
|
||||
no_delay: true
|
||||
ignore_exc: true
|
||||
use_pooling: true
|
||||
connect_timeout: 0.5
|
||||
KEY_FUNCTION: common.djangoapps.util.memcache.safe_key
|
||||
KEY_PREFIX: general
|
||||
LOCATION:
|
||||
- edx.devstack.memcached:11211
|
||||
mongo_metadata_inheritance:
|
||||
BACKEND: django.core.cache.backends.memcached.PyMemcacheCache
|
||||
OPTIONS:
|
||||
no_delay: true
|
||||
ignore_exc: true
|
||||
use_pooling: true
|
||||
connect_timeout: 0.5
|
||||
KEY_FUNCTION: common.djangoapps.util.memcache.safe_key
|
||||
KEY_PREFIX: mongo_metadata_inheritance
|
||||
LOCATION:
|
||||
- edx.devstack.memcached:11211
|
||||
TIMEOUT: 300
|
||||
staticfiles:
|
||||
BACKEND: django.core.cache.backends.memcached.PyMemcacheCache
|
||||
OPTIONS:
|
||||
no_delay: true
|
||||
ignore_exc: true
|
||||
use_pooling: true
|
||||
connect_timeout: 0.5
|
||||
KEY_FUNCTION: common.djangoapps.util.memcache.safe_key
|
||||
KEY_PREFIX: 78f87108afce_general
|
||||
LOCATION:
|
||||
- edx.devstack.memcached:11211
|
||||
CAS_ATTRIBUTE_CALLBACK: ''
|
||||
CAS_EXTRA_LOGIN_PARAMS: ''
|
||||
CAS_SERVER_URL: ''
|
||||
CELERYBEAT_SCHEDULER: celery.beat:PersistentScheduler
|
||||
CELERY_BROKER_HOSTNAME: localhost
|
||||
CELERY_BROKER_PASSWORD: ''
|
||||
CELERY_BROKER_TRANSPORT: redis
|
||||
CELERY_BROKER_USER: ''
|
||||
CELERY_BROKER_USE_SSL: false
|
||||
CELERY_BROKER_VHOST: ''
|
||||
CELERY_EVENT_QUEUE_TTL: null
|
||||
CELERY_QUEUES:
|
||||
- edx.cms.core.default
|
||||
- edx.cms.core.high
|
||||
CELERY_TIMEZONE: UTC
|
||||
CERTIFICATE_TEMPLATE_LANGUAGES:
|
||||
en: English
|
||||
es: Español
|
||||
CERT_QUEUE: certificates
|
||||
CMS_BASE: edx.devstack.studio:18010
|
||||
CODE_JAIL:
|
||||
limits:
|
||||
CPU: 1
|
||||
FSIZE: 1048576
|
||||
PROXY: 0
|
||||
REALTIME: 3
|
||||
VMEM: 536870912
|
||||
python_bin: /edx/app/edxapp/venvs/edxapp-sandbox/bin/python
|
||||
user: sandbox
|
||||
COMMENTS_SERVICE_KEY: password
|
||||
COMMENTS_SERVICE_URL: http://localhost:18080
|
||||
COMPREHENSIVE_THEME_DIRS:
|
||||
- ''
|
||||
COMPREHENSIVE_THEME_LOCALE_PATHS: []
|
||||
CONTACT_EMAIL: info@example.com
|
||||
CONTENTSTORE:
|
||||
ADDITIONAL_OPTIONS: {}
|
||||
DOC_STORE_CONFIG:
|
||||
authsource: ''
|
||||
collection: modulestore
|
||||
connectTimeoutMS: 2000
|
||||
db: edxapp
|
||||
host:
|
||||
- edx.devstack.mongo
|
||||
password: password
|
||||
port: 27017
|
||||
read_preference: PRIMARY
|
||||
replicaSet: ''
|
||||
socketTimeoutMS: 3000
|
||||
ssl: false
|
||||
user: edxapp
|
||||
ENGINE: xmodule.contentstore.mongo.MongoContentStore
|
||||
OPTIONS:
|
||||
auth_source: ''
|
||||
db: edxapp
|
||||
host:
|
||||
- edx.devstack.mongo
|
||||
password: password
|
||||
port: 27017
|
||||
ssl: false
|
||||
user: edxapp
|
||||
CORS_ORIGIN_ALLOW_ALL: false
|
||||
CORS_ORIGIN_WHITELIST: []
|
||||
COURSES_WITH_UNSAFE_CODE: []
|
||||
COURSE_ABOUT_VISIBILITY_PERMISSION: see_exists
|
||||
COURSE_AUTHORING_MICROFRONTEND_URL: null
|
||||
COURSE_CATALOG_API_URL: http://localhost:8008/api/v1
|
||||
COURSE_CATALOG_URL_ROOT: http://localhost:8008
|
||||
COURSE_CATALOG_VISIBILITY_PERMISSION: see_exists
|
||||
COURSE_IMPORT_EXPORT_BUCKET: ''
|
||||
CREDENTIALS_INTERNAL_SERVICE_URL: http://localhost:8005
|
||||
CREDENTIALS_PUBLIC_SERVICE_URL: http://localhost:8005
|
||||
CREDIT_PROVIDER_SECRET_KEYS: {}
|
||||
CROSS_DOMAIN_CSRF_COOKIE_DOMAIN: ''
|
||||
CROSS_DOMAIN_CSRF_COOKIE_NAME: ''
|
||||
CSRF_COOKIE_SECURE: false
|
||||
CSRF_TRUSTED_ORIGINS: []
|
||||
DASHBOARD_COURSE_LIMIT: null
|
||||
DATABASES:
|
||||
default:
|
||||
ATOMIC_REQUESTS: true
|
||||
CONN_MAX_AGE: 0
|
||||
ENGINE: django.db.backends.mysql
|
||||
HOST: edx.devstack.mysql80
|
||||
NAME: edxapp
|
||||
OPTIONS:
|
||||
isolation_level: read committed
|
||||
PASSWORD: password
|
||||
PORT: '3306'
|
||||
USER: edxapp001
|
||||
read_replica:
|
||||
CONN_MAX_AGE: 0
|
||||
ENGINE: django.db.backends.mysql
|
||||
HOST: edx.devstack.mysql80
|
||||
NAME: edxapp
|
||||
OPTIONS:
|
||||
isolation_level: read committed
|
||||
PASSWORD: password
|
||||
PORT: '3306'
|
||||
USER: edxapp001
|
||||
student_module_history:
|
||||
CONN_MAX_AGE: 0
|
||||
ENGINE: django.db.backends.mysql
|
||||
HOST: edx.devstack.mysql80
|
||||
NAME: edxapp_csmh
|
||||
OPTIONS:
|
||||
isolation_level: read committed
|
||||
PASSWORD: password
|
||||
PORT: '3306'
|
||||
USER: edxapp001
|
||||
DATA_DIR: /edx/var/edxapp
|
||||
DEFAULT_COURSE_VISIBILITY_IN_CATALOG: both
|
||||
DEFAULT_FEEDBACK_EMAIL: feedback@example.com
|
||||
DEFAULT_FILE_STORAGE: django.core.files.storage.FileSystemStorage
|
||||
DEFAULT_FROM_EMAIL: registration@example.com
|
||||
DEFAULT_JWT_ISSUER:
|
||||
AUDIENCE: lms-key
|
||||
ISSUER: http://edx.devstack.lms:18000/oauth2
|
||||
SECRET_KEY: lms-secret
|
||||
DEFAULT_MOBILE_AVAILABLE: false
|
||||
DEFAULT_SITE_THEME: ''
|
||||
DEPRECATED_ADVANCED_COMPONENT_TYPES: []
|
||||
DJFS:
|
||||
directory_root: /edx/var/edxapp/django-pyfs/static/django-pyfs
|
||||
type: osfs
|
||||
url_root: /static/django-pyfs
|
||||
DOC_STORE_CONFIG:
|
||||
authsource: ''
|
||||
collection: modulestore
|
||||
connectTimeoutMS: 2000
|
||||
db: edxapp
|
||||
host:
|
||||
- edx.devstack.mongo
|
||||
password: password
|
||||
port: 27017
|
||||
read_preference: PRIMARY
|
||||
replicaSet: ''
|
||||
socketTimeoutMS: 3000
|
||||
ssl: false
|
||||
user: edxapp
|
||||
ECOMMERCE_API_SIGNING_KEY: lms-secret
|
||||
ECOMMERCE_API_URL: http://localhost:8002/api/v2
|
||||
ECOMMERCE_PUBLIC_URL_ROOT: http://localhost:8002
|
||||
EDXMKTG_USER_INFO_COOKIE_NAME: edx-user-info
|
||||
EDX_PLATFORM_REVISION: master
|
||||
ELASTIC_SEARCH_CONFIG:
|
||||
- host: edx.devstack.elasticsearch
|
||||
port: 9200
|
||||
use_ssl: false
|
||||
EMAIL_BACKEND: django.core.mail.backends.smtp.EmailBackend
|
||||
EMAIL_HOST: localhost
|
||||
EMAIL_HOST_PASSWORD: ''
|
||||
EMAIL_HOST_USER: ''
|
||||
EMAIL_PORT: 25
|
||||
EMAIL_USE_TLS: false
|
||||
ENABLE_COMPREHENSIVE_THEMING: false
|
||||
ENTERPRISE_API_URL: http://edx.devstack.lms:18000/enterprise/api/v1
|
||||
ENTERPRISE_MARKETING_FOOTER_QUERY_PARAMS: {}
|
||||
ENTERPRISE_SERVICE_WORKER_USERNAME: enterprise_worker
|
||||
EVENT_TRACKING_SEGMENTIO_EMIT_WHITELIST: []
|
||||
EXAMS_API_URL: http://localhost:8740/api/v1
|
||||
EXTRA_MIDDLEWARE_CLASSES: []
|
||||
FACEBOOK_API_VERSION: v2.1
|
||||
FACEBOOK_APP_ID: FACEBOOK_APP_ID
|
||||
FACEBOOK_APP_SECRET: FACEBOOK_APP_SECRET
|
||||
FEATURES:
|
||||
AUTH_USE_OPENID_PROVIDER: true
|
||||
AUTOMATIC_AUTH_FOR_TESTING: false
|
||||
CUSTOM_COURSES_EDX: false
|
||||
ENABLE_BULK_ENROLLMENT_VIEW: false
|
||||
ENABLE_COMBINED_LOGIN_REGISTRATION: true
|
||||
ENABLE_CORS_HEADERS: false
|
||||
ENABLE_COUNTRY_ACCESS: false
|
||||
ENABLE_CREDIT_API: false
|
||||
ENABLE_CREDIT_ELIGIBILITY: false
|
||||
ENABLE_CROSS_DOMAIN_CSRF_COOKIE: false
|
||||
ENABLE_CSMH_EXTENDED: true
|
||||
ENABLE_DISCUSSION_HOME_PANEL: true
|
||||
ENABLE_DISCUSSION_SERVICE: true
|
||||
ENABLE_EDXNOTES: true
|
||||
ENABLE_ENROLLMENT_RESET: false
|
||||
ENABLE_EXPORT_GIT: false
|
||||
ENABLE_GRADE_DOWNLOADS: true
|
||||
ENABLE_LTI_PROVIDER: false
|
||||
ENABLE_MKTG_SITE: false
|
||||
ENABLE_MOBILE_REST_API: false
|
||||
ENABLE_OAUTH2_PROVIDER: false
|
||||
ENABLE_PUBLISHER: false
|
||||
ENABLE_READING_FROM_MULTIPLE_HISTORY_TABLES: true
|
||||
ENABLE_SPECIAL_EXAMS: false
|
||||
ENABLE_SYSADMIN_DASHBOARD: false
|
||||
ENABLE_THIRD_PARTY_AUTH: true
|
||||
ENABLE_VIDEO_UPLOAD_PIPELINE: false
|
||||
SHOW_FOOTER_LANGUAGE_SELECTOR: false
|
||||
SHOW_HEADER_LANGUAGE_SELECTOR: false
|
||||
FEEDBACK_SUBMISSION_EMAIL: ''
|
||||
FERNET_KEYS:
|
||||
- DUMMY KEY CHANGE BEFORE GOING TO PRODUCTION
|
||||
FILE_UPLOAD_STORAGE_BUCKET_NAME: SET-ME-PLEASE (ex. bucket-name)
|
||||
FILE_UPLOAD_STORAGE_PREFIX: submissions_attachments
|
||||
FINANCIAL_REPORTS:
|
||||
BUCKET: null
|
||||
ROOT_PATH: sandbox
|
||||
STORAGE_TYPE: localfs
|
||||
GITHUB_REPO_ROOT: /edx/var/edxapp/data
|
||||
GIT_REPO_EXPORT_DIR: /edx/var/edxapp/export_course_repos
|
||||
GOOGLE_ANALYTICS_ACCOUNT: null
|
||||
GRADES_DOWNLOAD:
|
||||
BUCKET: ''
|
||||
ROOT_PATH: ''
|
||||
STORAGE_CLASS: django.core.files.storage.FileSystemStorage
|
||||
STORAGE_KWARGS:
|
||||
location: /tmp/edx-s3/grades
|
||||
STORAGE_TYPE: ''
|
||||
HELP_TOKENS_BOOKS:
|
||||
course_author: http://edx.readthedocs.io/projects/open-edx-building-and-running-a-course
|
||||
learner: http://edx.readthedocs.io/projects/open-edx-learner-guide
|
||||
ICP_LICENSE: null
|
||||
ICP_LICENSE_INFO: {}
|
||||
IDA_LOGOUT_URI_LIST: []
|
||||
ID_VERIFICATION_SUPPORT_LINK: ''
|
||||
INTEGRATED_CHANNELS_API_CHUNK_TRANSMISSION_LIMIT:
|
||||
SAP: 1
|
||||
JWT_AUTH:
|
||||
JWT_AUDIENCE: lms-key
|
||||
JWT_AUTH_COOKIE_HEADER_PAYLOAD: edx-jwt-cookie-header-payload
|
||||
JWT_AUTH_COOKIE_SIGNATURE: edx-jwt-cookie-signature
|
||||
JWT_ISSUER: http://edx.devstack.lms:18000/oauth2
|
||||
JWT_ISSUERS:
|
||||
- AUDIENCE: lms-key
|
||||
ISSUER: http://edx.devstack.lms:18000/oauth2
|
||||
SECRET_KEY: lms-secret
|
||||
JWT_PUBLIC_SIGNING_JWK_SET: ''
|
||||
JWT_SECRET_KEY: lms-secret
|
||||
JWT_SIGNING_ALGORITHM: null
|
||||
JWT_EXPIRATION: 30
|
||||
JWT_ISSUER: http://edx.devstack.lms:18000/oauth2
|
||||
JWT_PRIVATE_SIGNING_KEY: null
|
||||
LANGUAGE_CODE: en
|
||||
LANGUAGE_COOKIE: openedx-language-preference
|
||||
LEARNER_PORTAL_URL_ROOT: https://learner-portal-edx.devstack.lms:18000
|
||||
LMS_BASE: edx.devstack.lms:18000
|
||||
LMS_INTERNAL_ROOT_URL: http://edx.devstack.lms:18000
|
||||
LMS_ROOT_URL: http://edx.devstack.lms:18000
|
||||
LOCAL_LOGLEVEL: INFO
|
||||
LOGGING_ENV: sandbox
|
||||
LOGIN_REDIRECT_WHITELIST: []
|
||||
LOG_DIR: /edx/var/log/edx
|
||||
MAINTENANCE_BANNER_TEXT: Sample banner message
|
||||
MEDIA_ROOT: /edx/var/edxapp/media/
|
||||
MEDIA_URL: /media/
|
||||
MKTG_URLS: {}
|
||||
MKTG_URL_LINK_MAP: {}
|
||||
MOBILE_STORE_ACE_URLS: {}
|
||||
MODULESTORE:
|
||||
default:
|
||||
ENGINE: xmodule.modulestore.mixed.MixedModuleStore
|
||||
OPTIONS:
|
||||
mappings: {}
|
||||
stores:
|
||||
- DOC_STORE_CONFIG:
|
||||
authsource: ''
|
||||
collection: modulestore
|
||||
connectTimeoutMS: 2000
|
||||
db: edxapp
|
||||
host:
|
||||
- edx.devstack.mongo
|
||||
password: password
|
||||
port: 27017
|
||||
read_preference: PRIMARY
|
||||
replicaSet: ''
|
||||
socketTimeoutMS: 3000
|
||||
ssl: false
|
||||
user: edxapp
|
||||
ENGINE: xmodule.modulestore.split_mongo.split_draft.DraftVersioningModuleStore
|
||||
NAME: split
|
||||
OPTIONS:
|
||||
default_class: xmodule.hidden_block.HiddenBlock
|
||||
fs_root: /edx/var/edxapp/data
|
||||
render_template: common.djangoapps.edxmako.shortcuts.render_to_string
|
||||
- DOC_STORE_CONFIG:
|
||||
authsource: ''
|
||||
collection: modulestore
|
||||
connectTimeoutMS: 2000
|
||||
db: edxapp
|
||||
host:
|
||||
- edx.devstack.mongo
|
||||
password: password
|
||||
port: 27017
|
||||
read_preference: PRIMARY
|
||||
replicaSet: ''
|
||||
socketTimeoutMS: 3000
|
||||
ssl: false
|
||||
user: edxapp
|
||||
ENGINE: xmodule.modulestore.mongo.DraftMongoModuleStore
|
||||
NAME: draft
|
||||
OPTIONS:
|
||||
default_class: xmodule.hidden_block.HiddenBlock
|
||||
fs_root: /edx/var/edxapp/data
|
||||
render_template: common.djangoapps.edxmako.shortcuts.render_to_string
|
||||
ORA2_FILE_PREFIX: default_env-default_deployment/ora2
|
||||
PARSE_KEYS: {}
|
||||
PARTNER_SUPPORT_EMAIL: ''
|
||||
PASSWORD_POLICY_COMPLIANCE_ROLLOUT_CONFIG:
|
||||
ENFORCE_COMPLIANCE_ON_LOGIN: false
|
||||
PASSWORD_RESET_SUPPORT_LINK: ''
|
||||
PAYMENT_SUPPORT_EMAIL: billing@example.com
|
||||
PLATFORM_DESCRIPTION: Your Platform Description Here
|
||||
PLATFORM_FACEBOOK_ACCOUNT: http://www.facebook.com/YourPlatformFacebookAccount
|
||||
PLATFORM_NAME: Your Platform Name Here
|
||||
PLATFORM_TWITTER_ACCOUNT: '@YourPlatformTwitterAccount'
|
||||
POLICY_CHANGE_GRADES_ROUTING_KEY: edx.lms.core.default
|
||||
SINGLE_LEARNER_COURSE_REGRADE_ROUTING_KEY: edx.lms.core.default
|
||||
PREPEND_LOCALE_PATHS: []
|
||||
PRESS_EMAIL: press@example.com
|
||||
PROCTORING_BACKENDS:
|
||||
DEFAULT: 'null'
|
||||
'null': {}
|
||||
PROCTORING_SETTINGS: {}
|
||||
REGISTRATION_EXTRA_FIELDS:
|
||||
city: hidden
|
||||
confirm_email: hidden
|
||||
country: required
|
||||
gender: optional
|
||||
goals: optional
|
||||
honor_code: required
|
||||
level_of_education: optional
|
||||
mailing_address: hidden
|
||||
terms_of_service: hidden
|
||||
year_of_birth: optional
|
||||
RETIRED_EMAIL_DOMAIN: retired.invalid
|
||||
RETIRED_EMAIL_PREFIX: retired__user_
|
||||
RETIRED_USERNAME_PREFIX: retired__user_
|
||||
RETIRED_USER_SALTS:
|
||||
- OVERRIDE ME WITH A RANDOM VALUE
|
||||
- ROTATE SALTS BY APPENDING NEW VALUES
|
||||
RETIREMENT_SERVICE_WORKER_USERNAME: retirement_worker
|
||||
RETIREMENT_STATES:
|
||||
- PENDING
|
||||
- ERRORED
|
||||
- ABORTED
|
||||
- COMPLETE
|
||||
SECRET_KEY: DUMMY KEY ONLY FOR TO DEVSTACK
|
||||
SEGMENT_KEY: null
|
||||
SERVER_EMAIL: sre@example.com
|
||||
SESSION_COOKIE_DOMAIN: ''
|
||||
SESSION_COOKIE_NAME: sessionid
|
||||
SESSION_COOKIE_SECURE: false
|
||||
SESSION_SAVE_EVERY_REQUEST: false
|
||||
SITE_NAME: localhost
|
||||
SOCIAL_AUTH_SAML_SP_PRIVATE_KEY: ''
|
||||
SOCIAL_AUTH_SAML_SP_PRIVATE_KEY_DICT: {}
|
||||
SOCIAL_AUTH_SAML_SP_PUBLIC_CERT: ''
|
||||
SOCIAL_AUTH_SAML_SP_PUBLIC_CERT_DICT: {}
|
||||
SOCIAL_MEDIA_FOOTER_URLS: {}
|
||||
SOCIAL_SHARING_SETTINGS:
|
||||
CERTIFICATE_FACEBOOK: false
|
||||
CERTIFICATE_TWITTER: false
|
||||
CUSTOM_COURSE_URLS: false
|
||||
DASHBOARD_FACEBOOK: false
|
||||
DASHBOARD_TWITTER: false
|
||||
STATIC_ROOT_BASE: /edx/var/edxapp/staticfiles
|
||||
STATIC_URL_BASE: /static/
|
||||
STUDIO_NAME: Studio
|
||||
STUDIO_SHORT_NAME: Studio
|
||||
SUPPORT_SITE_LINK: ''
|
||||
SWIFT_AUTH_URL: null
|
||||
SWIFT_AUTH_VERSION: null
|
||||
SWIFT_KEY: null
|
||||
SWIFT_REGION_NAME: null
|
||||
SWIFT_TEMP_URL_DURATION: 1800
|
||||
SWIFT_TEMP_URL_KEY: null
|
||||
SWIFT_TENANT_ID: null
|
||||
SWIFT_TENANT_NAME: null
|
||||
SWIFT_USERNAME: null
|
||||
SWIFT_USE_TEMP_URLS: false
|
||||
SYSLOG_SERVER: ''
|
||||
SYSTEM_WIDE_ROLE_CLASSES: []
|
||||
TECH_SUPPORT_EMAIL: technical@example.com
|
||||
TIME_ZONE: America/New_York
|
||||
UNIVERSITY_EMAIL: university@example.com
|
||||
USERNAME_REPLACEMENT_WORKER: OVERRIDE THIS WITH A VALID USERNAME
|
||||
VIDEO_IMAGE_MAX_AGE: 31536000
|
||||
VIDEO_IMAGE_SETTINGS:
|
||||
DIRECTORY_PREFIX: video-images/
|
||||
STORAGE_KWARGS:
|
||||
location: /edx/var/edxapp/media/
|
||||
VIDEO_IMAGE_MAX_BYTES: 2097152
|
||||
VIDEO_IMAGE_MIN_BYTES: 2048
|
||||
BASE_URL: /media/
|
||||
VIDEO_TRANSCRIPTS_MAX_AGE: 31536000
|
||||
VIDEO_TRANSCRIPTS_SETTINGS:
|
||||
DIRECTORY_PREFIX: video-transcripts/
|
||||
STORAGE_KWARGS:
|
||||
location: /edx/var/edxapp/media/
|
||||
VIDEO_TRANSCRIPTS_MAX_BYTES: 3145728
|
||||
BASE_URL: /media/
|
||||
VIDEO_UPLOAD_PIPELINE:
|
||||
BUCKET: ''
|
||||
ROOT_PATH: ''
|
||||
WIKI_ENABLED: true
|
||||
XBLOCK_FS_STORAGE_BUCKET: null
|
||||
XBLOCK_FS_STORAGE_PREFIX: null
|
||||
XBLOCK_SETTINGS: {}
|
||||
XQUEUE_INTERFACE:
|
||||
basic_auth:
|
||||
- edx
|
||||
- edx
|
||||
django_auth:
|
||||
password: password
|
||||
username: lms
|
||||
url: http://edx.devstack.xqueue:18040
|
||||
X_FRAME_OPTIONS: DENY
|
||||
YOUTUBE_API_KEY: PUT_YOUR_API_KEY_HERE
|
||||
ZENDESK_API_KEY: ''
|
||||
ZENDESK_CUSTOM_FIELDS: {}
|
||||
ZENDESK_GROUP_ID_MAPPING: {}
|
||||
ZENDESK_OAUTH_ACCESS_TOKEN: ''
|
||||
ZENDESK_URL: ''
|
||||
ZENDESK_USER: ''
|
||||
@@ -1,3 +0,0 @@
|
||||
""" Overrides for Docker-based devstack. """
|
||||
|
||||
from .devstack import * # pylint: disable=wildcard-import, unused-wildcard-import
|
||||
@@ -1,46 +0,0 @@
|
||||
"""
|
||||
Settings to run Studio in devstack using optimized static assets.
|
||||
|
||||
This configuration changes Studio to use the optimized static assets generated for testing,
|
||||
rather than picking up the files directly from the source tree.
|
||||
|
||||
The following Paver command can be used to run Studio in optimized mode:
|
||||
|
||||
paver devstack studio --optimized
|
||||
|
||||
You can also generate the assets explicitly and then run Studio:
|
||||
|
||||
paver update_assets cms --settings=test_static_optimized
|
||||
paver devstack studio --settings=devstack_optimized --fast
|
||||
|
||||
Note that changes to JavaScript assets will not be picked up automatically
|
||||
as they are for non-optimized devstack. Instead, update_assets must be
|
||||
invoked each time that changes have been made.
|
||||
"""
|
||||
|
||||
########################## Devstack settings ###################################
|
||||
|
||||
from .devstack import * # pylint: disable=wildcard-import
|
||||
|
||||
TEST_ROOT = REPO_ROOT / "test_root"
|
||||
|
||||
############################ STATIC FILES #############################
|
||||
|
||||
# Enable debug so that static assets are served by Django
|
||||
DEBUG = True
|
||||
|
||||
# Set REQUIRE_DEBUG to false so that it behaves like production
|
||||
REQUIRE_DEBUG = False
|
||||
|
||||
# Fetch static files out of the pipeline's static root
|
||||
STATICFILES_STORAGE = 'pipeline.storage.PipelineManifestStorage'
|
||||
|
||||
# Serve static files at /static directly from the staticfiles directory under test root.
|
||||
# Note: optimized files for testing are generated with settings from test_static_optimized
|
||||
STATIC_URL = "/static/"
|
||||
STATICFILES_FINDERS = [
|
||||
'django.contrib.staticfiles.finders.FileSystemFinder',
|
||||
]
|
||||
STATICFILES_DIRS = [
|
||||
(TEST_ROOT / "staticfiles" / "cms").abspath(),
|
||||
]
|
||||
@@ -1,22 +0,0 @@
|
||||
"""
|
||||
This config file follows the devstack enviroment, but adds the
|
||||
requirement of a celery worker running in the background to process
|
||||
celery tasks.
|
||||
|
||||
When testing locally, run lms/cms with this settings file as well, to test queueing
|
||||
of tasks onto the appropriate workers.
|
||||
|
||||
In two separate processes on devstack:
|
||||
paver devstack studio --settings=devstack_with_worker
|
||||
DJANGO_SETTINGS_MODULE=cms.envs.devstack_with_worker celery worker --app=cms.celery:APP
|
||||
"""
|
||||
|
||||
# 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
|
||||
from cms.envs.devstack import *
|
||||
|
||||
# Require a separate celery worker
|
||||
CELERY_ALWAYS_EAGER = False
|
||||
CLEAR_REQUEST_CACHE_ON_TASK_COMPLETION = True
|
||||
BROKER_URL = 'redis://:password@edx.devstack.redis:6379/'
|
||||
@@ -1,32 +0,0 @@
|
||||
"""
|
||||
Settings for OpenStack deployments.
|
||||
"""
|
||||
|
||||
from .production import * # pylint: disable=wildcard-import, unused-wildcard-import
|
||||
|
||||
SWIFT_AUTH_URL = AUTH_TOKENS.get('SWIFT_AUTH_URL')
|
||||
SWIFT_AUTH_VERSION = AUTH_TOKENS.get('SWIFT_AUTH_VERSION', 1)
|
||||
SWIFT_USERNAME = AUTH_TOKENS.get('SWIFT_USERNAME')
|
||||
SWIFT_KEY = AUTH_TOKENS.get('SWIFT_KEY')
|
||||
SWIFT_TENANT_NAME = AUTH_TOKENS.get('SWIFT_TENANT_NAME')
|
||||
SWIFT_TENANT_ID = AUTH_TOKENS.get('SWIFT_TENANT_ID')
|
||||
SWIFT_CONTAINER_NAME = FILE_UPLOAD_STORAGE_BUCKET_NAME
|
||||
SWIFT_NAME_PREFIX = FILE_UPLOAD_STORAGE_PREFIX
|
||||
SWIFT_USE_TEMP_URLS = AUTH_TOKENS.get('SWIFT_USE_TEMP_URLS', False)
|
||||
SWIFT_TEMP_URL_KEY = AUTH_TOKENS.get('SWIFT_TEMP_URL_KEY')
|
||||
SWIFT_TEMP_URL_DURATION = AUTH_TOKENS.get('SWIFT_TEMP_URL_DURATION', 1800) # seconds
|
||||
SWIFT_CONTENT_LENGTH_FROM_FD = AUTH_TOKENS.get('SWIFT_CONTENT_LENGTH_FROM_FD', False)
|
||||
SWIFT_LAZY_CONNECT = AUTH_TOKENS.get('SWIFT_LAZY_CONNECT', True)
|
||||
|
||||
if AUTH_TOKENS.get('SWIFT_REGION_NAME'):
|
||||
SWIFT_EXTRA_OPTIONS = {'region_name': AUTH_TOKENS['SWIFT_REGION_NAME']}
|
||||
|
||||
if AUTH_TOKENS.get('DEFAULT_FILE_STORAGE'):
|
||||
DEFAULT_FILE_STORAGE = AUTH_TOKENS.get('DEFAULT_FILE_STORAGE')
|
||||
elif SWIFT_AUTH_URL and SWIFT_USERNAME and SWIFT_KEY:
|
||||
DEFAULT_FILE_STORAGE = 'swift.storage.SwiftStorage'
|
||||
else:
|
||||
DEFAULT_FILE_STORAGE = 'django.core.files.storage.FileSystemStorage'
|
||||
|
||||
# Use default file storage class set above for course import/export
|
||||
COURSE_IMPORT_EXPORT_STORAGE = DEFAULT_FILE_STORAGE
|
||||
@@ -1,54 +0,0 @@
|
||||
"""
|
||||
Settings used when generating static assets for use in tests.
|
||||
|
||||
Note: it isn't possible to have a single settings file, because Django doesn't
|
||||
support both generating static assets to a directory and also serving static
|
||||
from the same directory.
|
||||
"""
|
||||
|
||||
# Start with the common settings
|
||||
|
||||
|
||||
from openedx.core.lib.derived import derive_settings
|
||||
from openedx.core.lib.django_require.staticstorage import OptimizedCachedRequireJsStorage
|
||||
|
||||
from .common import * # pylint: disable=wildcard-import, unused-wildcard-import
|
||||
|
||||
# Use an in-memory database since this settings file is only used for updating assets
|
||||
DATABASES = {
|
||||
'default': {
|
||||
'ENGINE': 'django.db.backends.sqlite3',
|
||||
'ATOMIC_REQUESTS': True,
|
||||
},
|
||||
|
||||
}
|
||||
|
||||
|
||||
######################### PIPELINE ####################################
|
||||
|
||||
# Use RequireJS optimized storage
|
||||
STATICFILES_STORAGE = f"{OptimizedCachedRequireJsStorage.__module__}.{OptimizedCachedRequireJsStorage.__name__}"
|
||||
|
||||
# Revert to the default set of finders as we don't want to dynamically pick up files from the pipeline
|
||||
STATICFILES_FINDERS = [
|
||||
'django.contrib.staticfiles.finders.FileSystemFinder',
|
||||
'django.contrib.staticfiles.finders.AppDirectoriesFinder',
|
||||
'openedx.core.lib.xblock_pipeline.finder.XBlockPipelineFinder',
|
||||
]
|
||||
|
||||
# Redirect to the test_root folder within the repo
|
||||
TEST_ROOT = REPO_ROOT / "test_root"
|
||||
LOG_DIR = (TEST_ROOT / "log").abspath()
|
||||
|
||||
# Store the static files under test root so that they don't overwrite existing static assets
|
||||
STATIC_ROOT = (TEST_ROOT / "staticfiles" / "cms").abspath()
|
||||
WEBPACK_LOADER['DEFAULT']['STATS_FILE'] = STATIC_ROOT / "webpack-stats.json"
|
||||
|
||||
# Disable uglify when tests are running (used by build.js).
|
||||
# 1. Uglify is by far the slowest part of the build process
|
||||
# 2. Having full source code makes debugging tests easier for developers
|
||||
os.environ['REQUIRE_BUILD_PROFILE_OPTIMIZE'] = 'none'
|
||||
|
||||
########################## Derive Any Derived Settings #######################
|
||||
|
||||
derive_settings(__name__)
|
||||
@@ -264,7 +264,7 @@ if core_toggles.ENTRANCE_EXAMS.is_enabled():
|
||||
# Enable Web/HTML Certificates
|
||||
if settings.FEATURES.get('CERTIFICATES_HTML_VIEW'):
|
||||
from cms.djangoapps.contentstore.views.certificates import (
|
||||
certificate_activation_handler,
|
||||
CertificateActivationAPIView,
|
||||
signatory_detail_handler,
|
||||
certificates_detail_handler,
|
||||
certificates_list_handler
|
||||
@@ -272,7 +272,7 @@ if settings.FEATURES.get('CERTIFICATES_HTML_VIEW'):
|
||||
|
||||
urlpatterns += [
|
||||
re_path(fr'^certificates/activation/{settings.COURSE_KEY_PATTERN}/',
|
||||
certificate_activation_handler,
|
||||
CertificateActivationAPIView.as_view(),
|
||||
name='certificate_activation_handler'),
|
||||
re_path(r'^certificates/{}/(?P<certificate_id>\d+)/signatories/(?P<signatory_id>\d+)?$'.format(
|
||||
settings.COURSE_KEY_PATTERN), signatory_detail_handler, name='signatory_detail_handler'),
|
||||
|
||||
@@ -21,7 +21,7 @@ class Command(BaseCommand):
|
||||
Example usage:
|
||||
|
||||
# Change entitlement_mode for given order_number with course_uuid to new_mode:
|
||||
$ ./manage.py lms --settings=devstack_docker update_entitlement_mode \
|
||||
$ ./manage.py lms --settings=devstack update_entitlement_mode \
|
||||
ORDER_NUMBER_123,ORDER_NUMBER_456 1234567-0000-1111-2222-123456789012 professional
|
||||
"""
|
||||
help = dedent(__doc__).strip()
|
||||
|
||||
@@ -19,7 +19,7 @@ class Command(BaseCommand):
|
||||
"""
|
||||
help = """This command back-populates domain of the site the user account was created on.
|
||||
Example: ./manage.py lms populate_created_on_site_user_attribute --users <user_id1>,<user_id2>...
|
||||
'--activation-keys <key1>,<key2>... --site-domain <site_domain> --settings=devstack_docker"""
|
||||
'--activation-keys <key1>,<key2>... --site-domain <site_domain> --settings=devstack"""
|
||||
|
||||
def add_arguments(self, parser):
|
||||
"""
|
||||
|
||||
@@ -320,10 +320,7 @@ def update_settings_module(service='lms'):
|
||||
Set the "DJANGO_SETTINGS_MODULE" environment variable appropriately
|
||||
for the module sphinx-apidoc is about to be run on.
|
||||
"""
|
||||
if os.environ.get('EDX_PLATFORM_SETTINGS') == 'devstack_docker':
|
||||
settings_module = f'{service}.envs.devstack_docker'
|
||||
else:
|
||||
settings_module = f'{service}.envs.devstack'
|
||||
settings_module = f'{service}.envs.devstack'
|
||||
os.environ['DJANGO_SETTINGS_MODULE'] = settings_module
|
||||
|
||||
|
||||
|
||||
@@ -287,6 +287,16 @@ class StudentModuleHistory(BaseStudentModuleHistory):
|
||||
|
||||
student_module = models.ForeignKey(StudentModule, db_index=True, db_constraint=False, on_delete=models.CASCADE)
|
||||
|
||||
def __repr__(self):
|
||||
student_dict = {
|
||||
"course_id": str(self.student_module.course_id),
|
||||
"module_type": self.student_module.module_type,
|
||||
"student_id": self.student_module.student_id,
|
||||
"grade": self.grade,
|
||||
}
|
||||
|
||||
return f"StudentModuleHistory<{student_dict!r}>"
|
||||
|
||||
def __str__(self):
|
||||
return str(repr(self))
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ from celery import shared_task
|
||||
from django.contrib.auth import get_user_model
|
||||
from edx_django_utils.monitoring import set_code_owner_attribute
|
||||
from opaque_keys.edx.locator import CourseKey
|
||||
from eventtracking import tracker
|
||||
|
||||
from common.djangoapps.student.roles import CourseStaffRole, CourseInstructorRole
|
||||
from lms.djangoapps.courseware.courses import get_course_with_access
|
||||
@@ -92,12 +93,18 @@ def send_response_endorsed_notifications(thread_id, response_id, course_key_str,
|
||||
|
||||
@shared_task
|
||||
@set_code_owner_attribute
|
||||
def delete_course_post_for_user(user_id, username, course_ids):
|
||||
def delete_course_post_for_user(user_id, username, course_ids, event_data=None):
|
||||
"""
|
||||
Deletes all posts for user in a course.
|
||||
"""
|
||||
event_data = event_data or {}
|
||||
log.info(f"<<Bulk Delete>> Deleting all posts for {username} in course {course_ids}")
|
||||
threads_deleted = Thread.delete_user_threads(user_id, course_ids)
|
||||
comments_deleted = Comment.delete_user_comments(user_id, course_ids)
|
||||
log.info(f"<<Bulk Delete>> Deleted {threads_deleted} posts and {comments_deleted} comments for {username} "
|
||||
f"in course {course_ids}")
|
||||
event_data.update({
|
||||
"number_of_posts_deleted": threads_deleted,
|
||||
"number_of_comments_deleted": comments_deleted,
|
||||
})
|
||||
tracker.emit('edx.discussion.bulk_delete_user_posts', event_data)
|
||||
|
||||
@@ -1585,8 +1585,14 @@ class BulkDeleteUserPosts(DeveloperErrorViewMixin, APIView):
|
||||
thread_count = Thread.get_user_threads_count(user.id, course_ids)
|
||||
|
||||
if execute_task:
|
||||
event_data = {
|
||||
"triggered_by": request.user.username,
|
||||
"username": username,
|
||||
"course_or_org": course_or_org,
|
||||
"course_key": course_id,
|
||||
}
|
||||
delete_course_post_for_user.apply_async(
|
||||
args=(user.id, username, course_ids),
|
||||
args=(user.id, username, course_ids, event_data),
|
||||
)
|
||||
return Response(
|
||||
{"comment_count": comment_count, "thread_count": thread_count},
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
"""
|
||||
Settings for running management commands for the Analytics Exporter.
|
||||
|
||||
The Analytics Exporter jobs run edxapp management commands using production
|
||||
settings and configuration, however they currently DO NOT use edxapp production
|
||||
environments (such as edxapp Amazon AMIs or Docker images) where theme files
|
||||
get installed. As a result we must disable comprehensive theming or else
|
||||
startup checks from the theming app will throw an error due to missing themes.
|
||||
"""
|
||||
|
||||
from .production import * # pylint: disable=wildcard-import, unused-wildcard-import
|
||||
|
||||
ENABLE_COMPREHENSIVE_THEMING = False
|
||||
@@ -1,655 +0,0 @@
|
||||
# This file is an experimental extraction of /edx/etc/lms.yml from
|
||||
# a LMS devstack container.
|
||||
#
|
||||
# When devstack is configured to use the new `openedx/` images
|
||||
# instead of the old `edxops/edxapp` image, it will use this file
|
||||
# as input to lms/envs/production.py (and, in turn, lms/envs/devstack.py).
|
||||
# If you are using devstack with the `edxops/edxapp` image, though,
|
||||
# this file is NOT used.
|
||||
#
|
||||
# Q. Should I update this file when I update devstack.py?
|
||||
# A. You don't *have* to, because settings in devstack.py
|
||||
# override these settings. But, it doesn't harm to also make them
|
||||
# here in order to quell confusion. The hope is that we'll
|
||||
# adopt OEP-45 eventually, which recommends against having
|
||||
# a devstack.py at all.
|
||||
#
|
||||
# This is part of the effort to move our dev tools off of Ansible and
|
||||
# Paver, described here: https://github.com/openedx/devstack/pull/866
|
||||
# TODO: If the effort described above is abandoned, then this file should
|
||||
# probably be deleted.
|
||||
ACCOUNT_MICROFRONTEND_URL: null
|
||||
ACE_CHANNEL_DEFAULT_EMAIL: django_email
|
||||
ACE_CHANNEL_SAILTHRU_API_KEY: ''
|
||||
ACE_CHANNEL_SAILTHRU_API_SECRET: ''
|
||||
ACE_CHANNEL_SAILTHRU_DEBUG: true
|
||||
ACE_CHANNEL_SAILTHRU_TEMPLATE_NAME: null
|
||||
ACE_CHANNEL_TRANSACTIONAL_EMAIL: django_email
|
||||
ACE_ENABLED_CHANNELS:
|
||||
- django_email
|
||||
ACE_ENABLED_POLICIES:
|
||||
- bulk_email_optout
|
||||
ACE_ROUTING_KEY: edx.lms.core.default
|
||||
ACTIVATION_EMAIL_SUPPORT_LINK: ''
|
||||
AFFILIATE_COOKIE_NAME: dev_affiliate_id
|
||||
ALTERNATE_WORKER_QUEUES: cms
|
||||
ANALYTICS_API_KEY: ''
|
||||
ANALYTICS_API_URL: http://localhost:18100
|
||||
ANALYTICS_DASHBOARD_NAME: Your Platform Name Here Insights
|
||||
ANALYTICS_DASHBOARD_URL: http://localhost:18110/courses
|
||||
API_ACCESS_FROM_EMAIL: api-requests@example.com
|
||||
API_ACCESS_MANAGER_EMAIL: api-access@example.com
|
||||
API_DOCUMENTATION_URL: http://course-catalog-api-guide.readthedocs.io/en/latest/
|
||||
AUTH_DOCUMENTATION_URL: http://course-catalog-api-guide.readthedocs.io/en/latest/authentication/index.html
|
||||
AUTH_PASSWORD_VALIDATORS:
|
||||
- NAME: django.contrib.auth.password_validation.UserAttributeSimilarityValidator
|
||||
- NAME: common.djangoapps.util.password_policy_validators.MinimumLengthValidator
|
||||
OPTIONS:
|
||||
min_length: 2
|
||||
- NAME: common.djangoapps.util.password_policy_validators.MaximumLengthValidator
|
||||
OPTIONS:
|
||||
max_length: 75
|
||||
AWS_ACCESS_KEY_ID: null
|
||||
AWS_QUERYSTRING_AUTH: false
|
||||
AWS_S3_CUSTOM_DOMAIN: SET-ME-PLEASE (ex. bucket-name.s3.amazonaws.com)
|
||||
AWS_SECRET_ACCESS_KEY: null
|
||||
AWS_SES_REGION_ENDPOINT: email.us-east-1.amazonaws.com
|
||||
AWS_SES_REGION_NAME: us-east-1
|
||||
AWS_STORAGE_BUCKET_NAME: SET-ME-PLEASE (ex. bucket-name)
|
||||
BASE_COOKIE_DOMAIN: localhost
|
||||
BLOCK_STRUCTURES_SETTINGS:
|
||||
COURSE_PUBLISH_TASK_DELAY: 30
|
||||
TASK_DEFAULT_RETRY_DELAY: 30
|
||||
TASK_MAX_RETRIES: 5
|
||||
BRANCH_IO_KEY: ''
|
||||
BUGS_EMAIL: bugs@example.com
|
||||
BULK_EMAIL_DEFAULT_FROM_EMAIL: no-reply@example.com
|
||||
BULK_EMAIL_EMAILS_PER_TASK: 500
|
||||
BULK_EMAIL_LOG_SENT_EMAILS: false
|
||||
BULK_EMAIL_ROUTING_KEY_SMALL_JOBS: edx.lms.core.default
|
||||
CACHES:
|
||||
celery:
|
||||
BACKEND: django.core.cache.backends.memcached.PyMemcacheCache
|
||||
OPTIONS:
|
||||
no_delay: true
|
||||
ignore_exc: true
|
||||
use_pooling: true
|
||||
connect_timeout: 0.5
|
||||
KEY_FUNCTION: common.djangoapps.util.memcache.safe_key
|
||||
KEY_PREFIX: celery
|
||||
LOCATION:
|
||||
- edx.devstack.memcached:11211
|
||||
TIMEOUT: '7200'
|
||||
configuration:
|
||||
BACKEND: django.core.cache.backends.memcached.PyMemcacheCache
|
||||
OPTIONS:
|
||||
no_delay: true
|
||||
ignore_exc: true
|
||||
use_pooling: true
|
||||
connect_timeout: 0.5
|
||||
KEY_FUNCTION: common.djangoapps.util.memcache.safe_key
|
||||
KEY_PREFIX: 78f87108afce
|
||||
LOCATION:
|
||||
- edx.devstack.memcached:11211
|
||||
course_structure_cache:
|
||||
BACKEND: django.core.cache.backends.memcached.PyMemcacheCache
|
||||
OPTIONS:
|
||||
no_delay: true
|
||||
ignore_exc: true
|
||||
use_pooling: true
|
||||
connect_timeout: 0.5
|
||||
KEY_FUNCTION: common.djangoapps.util.memcache.safe_key
|
||||
KEY_PREFIX: course_structure
|
||||
LOCATION:
|
||||
- edx.devstack.memcached:11211
|
||||
TIMEOUT: '604800'
|
||||
default:
|
||||
BACKEND: django.core.cache.backends.memcached.PyMemcacheCache
|
||||
OPTIONS:
|
||||
no_delay: true
|
||||
ignore_exc: true
|
||||
use_pooling: true
|
||||
connect_timeout: 0.5
|
||||
KEY_FUNCTION: common.djangoapps.util.memcache.safe_key
|
||||
KEY_PREFIX: default
|
||||
LOCATION:
|
||||
- edx.devstack.memcached:11211
|
||||
VERSION: '1'
|
||||
general:
|
||||
BACKEND: django.core.cache.backends.memcached.PyMemcacheCache
|
||||
OPTIONS:
|
||||
no_delay: true
|
||||
ignore_exc: true
|
||||
use_pooling: true
|
||||
connect_timeout: 0.5
|
||||
KEY_FUNCTION: common.djangoapps.util.memcache.safe_key
|
||||
KEY_PREFIX: general
|
||||
LOCATION:
|
||||
- edx.devstack.memcached:11211
|
||||
mongo_metadata_inheritance:
|
||||
BACKEND: django.core.cache.backends.memcached.PyMemcacheCache
|
||||
OPTIONS:
|
||||
no_delay: true
|
||||
ignore_exc: true
|
||||
use_pooling: true
|
||||
connect_timeout: 0.5
|
||||
KEY_FUNCTION: common.djangoapps.util.memcache.safe_key
|
||||
KEY_PREFIX: mongo_metadata_inheritance
|
||||
LOCATION:
|
||||
- edx.devstack.memcached:11211
|
||||
TIMEOUT: 300
|
||||
staticfiles:
|
||||
BACKEND: django.core.cache.backends.memcached.PyMemcacheCache
|
||||
OPTIONS:
|
||||
no_delay: true
|
||||
ignore_exc: true
|
||||
use_pooling: true
|
||||
connect_timeout: 0.5
|
||||
KEY_FUNCTION: common.djangoapps.util.memcache.safe_key
|
||||
KEY_PREFIX: 78f87108afce_general
|
||||
LOCATION:
|
||||
- edx.devstack.memcached:11211
|
||||
CAS_ATTRIBUTE_CALLBACK: ''
|
||||
CAS_EXTRA_LOGIN_PARAMS: ''
|
||||
CAS_SERVER_URL: ''
|
||||
CELERYBEAT_SCHEDULER: celery.beat:PersistentScheduler
|
||||
CELERY_BROKER_HOSTNAME: localhost
|
||||
CELERY_BROKER_PASSWORD: ''
|
||||
CELERY_BROKER_TRANSPORT: redis
|
||||
CELERY_BROKER_USER: ''
|
||||
CELERY_BROKER_USE_SSL: false
|
||||
CELERY_BROKER_VHOST: ''
|
||||
CELERY_EVENT_QUEUE_TTL: null
|
||||
CELERY_QUEUES:
|
||||
- edx.lms.core.default
|
||||
- edx.lms.core.high
|
||||
- edx.lms.core.high_mem
|
||||
CELERY_TIMEZONE: UTC
|
||||
CERTIFICATE_TEMPLATE_LANGUAGES:
|
||||
en: English
|
||||
es: Español
|
||||
CERT_QUEUE: certificates
|
||||
CMS_BASE: edx.devstack.studio:18010
|
||||
CODE_JAIL:
|
||||
limits:
|
||||
CPU: 1
|
||||
FSIZE: 1048576
|
||||
PROXY: 0
|
||||
REALTIME: 3
|
||||
VMEM: 536870912
|
||||
python_bin: /edx/app/edxapp/venvs/edxapp-sandbox/bin/python
|
||||
user: sandbox
|
||||
COMMENTS_SERVICE_KEY: password
|
||||
COMMENTS_SERVICE_URL: http://localhost:18080
|
||||
COMPREHENSIVE_THEME_DIRS:
|
||||
- ''
|
||||
COMPREHENSIVE_THEME_LOCALE_PATHS: []
|
||||
CONTACT_EMAIL: info@example.com
|
||||
CONTACT_MAILING_ADDRESS: SET-ME-PLEASE
|
||||
CONTENTSTORE:
|
||||
ADDITIONAL_OPTIONS: {}
|
||||
DOC_STORE_CONFIG:
|
||||
authsource: ''
|
||||
collection: modulestore
|
||||
connectTimeoutMS: 2000
|
||||
db: edxapp
|
||||
host:
|
||||
- edx.devstack.mongo
|
||||
password: password
|
||||
port: 27017
|
||||
read_preference: SECONDARY_PREFERRED
|
||||
replicaSet: ''
|
||||
socketTimeoutMS: 3000
|
||||
ssl: false
|
||||
user: edxapp
|
||||
ENGINE: xmodule.contentstore.mongo.MongoContentStore
|
||||
OPTIONS:
|
||||
auth_source: ''
|
||||
db: edxapp
|
||||
host:
|
||||
- edx.devstack.mongo
|
||||
password: password
|
||||
port: 27017
|
||||
ssl: false
|
||||
user: edxapp
|
||||
CORS_ORIGIN_ALLOW_ALL: false
|
||||
CORS_ORIGIN_WHITELIST: []
|
||||
COURSES_WITH_UNSAFE_CODE: []
|
||||
COURSE_ABOUT_VISIBILITY_PERMISSION: see_exists
|
||||
COURSE_CATALOG_API_URL: http://localhost:8008/api/v1
|
||||
COURSE_CATALOG_URL_ROOT: http://localhost:8008
|
||||
COURSE_CATALOG_VISIBILITY_PERMISSION: see_exists
|
||||
CREDENTIALS_INTERNAL_SERVICE_URL: http://localhost:8005
|
||||
CREDENTIALS_PUBLIC_SERVICE_URL: http://localhost:8005
|
||||
CREDIT_HELP_LINK_URL: ''
|
||||
CREDIT_PROVIDER_SECRET_KEYS: {}
|
||||
CROSS_DOMAIN_CSRF_COOKIE_DOMAIN: ''
|
||||
CROSS_DOMAIN_CSRF_COOKIE_NAME: ''
|
||||
CSRF_COOKIE_SECURE: false
|
||||
CSRF_TRUSTED_ORIGINS: []
|
||||
DASHBOARD_COURSE_LIMIT: null
|
||||
DATABASES:
|
||||
default:
|
||||
ATOMIC_REQUESTS: true
|
||||
CONN_MAX_AGE: 0
|
||||
ENGINE: django.db.backends.mysql
|
||||
HOST: edx.devstack.mysql80
|
||||
NAME: edxapp
|
||||
OPTIONS:
|
||||
isolation_level: read committed
|
||||
PASSWORD: password
|
||||
PORT: '3306'
|
||||
USER: edxapp001
|
||||
read_replica:
|
||||
CONN_MAX_AGE: 0
|
||||
ENGINE: django.db.backends.mysql
|
||||
HOST: edx.devstack.mysql80
|
||||
NAME: edxapp
|
||||
OPTIONS:
|
||||
isolation_level: read committed
|
||||
PASSWORD: password
|
||||
PORT: '3306'
|
||||
USER: edxapp001
|
||||
student_module_history:
|
||||
CONN_MAX_AGE: 0
|
||||
ENGINE: django.db.backends.mysql
|
||||
HOST: edx.devstack.mysql80
|
||||
NAME: edxapp_csmh
|
||||
OPTIONS:
|
||||
isolation_level: read committed
|
||||
PASSWORD: password
|
||||
PORT: '3306'
|
||||
USER: edxapp001
|
||||
DATA_DIR: /edx/var/edxapp
|
||||
DCS_SESSION_COOKIE_SAMESITE: Lax
|
||||
DCS_SESSION_COOKIE_SAMESITE_FORCE_ALL: true
|
||||
DEFAULT_COURSE_VISIBILITY_IN_CATALOG: both
|
||||
DEFAULT_FEEDBACK_EMAIL: feedback@example.com
|
||||
DEFAULT_FILE_STORAGE: django.core.files.storage.FileSystemStorage
|
||||
DEFAULT_FROM_EMAIL: registration@example.com
|
||||
DEFAULT_JWT_ISSUER:
|
||||
AUDIENCE: lms-key
|
||||
ISSUER: http://edx.devstack.lms:18000/oauth2
|
||||
SECRET_KEY: lms-secret
|
||||
DEFAULT_MOBILE_AVAILABLE: false
|
||||
DEFAULT_SITE_THEME: ''
|
||||
DEPRECATED_ADVANCED_COMPONENT_TYPES: []
|
||||
DJFS:
|
||||
directory_root: /edx/var/edxapp/django-pyfs/static/django-pyfs
|
||||
type: osfs
|
||||
url_root: /static/django-pyfs
|
||||
DOC_STORE_CONFIG:
|
||||
authsource: ''
|
||||
collection: modulestore
|
||||
connectTimeoutMS: 2000
|
||||
db: edxapp
|
||||
host:
|
||||
- edx.devstack.mongo
|
||||
password: password
|
||||
port: 27017
|
||||
read_preference: SECONDARY_PREFERRED
|
||||
replicaSet: ''
|
||||
socketTimeoutMS: 3000
|
||||
ssl: false
|
||||
user: edxapp
|
||||
ECOMMERCE_API_SIGNING_KEY: lms-secret
|
||||
ECOMMERCE_API_URL: http://localhost:8002/api/v2
|
||||
ECOMMERCE_PUBLIC_URL_ROOT: http://localhost:8002
|
||||
EDXMKTG_USER_INFO_COOKIE_NAME: edx-user-info
|
||||
EDXNOTES_INTERNAL_API: http://edx.devstack.edx_notes_api:18120/api/v1
|
||||
EDXNOTES_PUBLIC_API: http://localhost:18120/api/v1
|
||||
EDX_API_KEY: PUT_YOUR_API_KEY_HERE
|
||||
EDX_PLATFORM_REVISION: master
|
||||
ELASTIC_SEARCH_CONFIG:
|
||||
- host: edx.devstack.elasticsearch
|
||||
port: 9200
|
||||
use_ssl: false
|
||||
EMAIL_BACKEND: django.core.mail.backends.smtp.EmailBackend
|
||||
EMAIL_HOST: localhost
|
||||
EMAIL_HOST_PASSWORD: ''
|
||||
EMAIL_HOST_USER: ''
|
||||
EMAIL_PORT: 25
|
||||
EMAIL_USE_TLS: false
|
||||
ENABLE_COMPREHENSIVE_THEMING: false
|
||||
ENTERPRISE_API_URL: http://edx.devstack.lms:18000/enterprise/api/v1
|
||||
ENTERPRISE_COURSE_ENROLLMENT_AUDIT_MODES:
|
||||
- audit
|
||||
- honor
|
||||
ENTERPRISE_CUSTOMER_SUCCESS_EMAIL: customersuccess@edx.org
|
||||
ENTERPRISE_ENROLLMENT_API_URL: http://edx.devstack.lms:18000/api/enrollment/v1/
|
||||
ENTERPRISE_INTEGRATIONS_EMAIL: enterprise-integrations@edx.org
|
||||
ENTERPRISE_MARKETING_FOOTER_QUERY_PARAMS: {}
|
||||
ENTERPRISE_SERVICE_WORKER_USERNAME: enterprise_worker
|
||||
ENTERPRISE_SUPPORT_URL: ''
|
||||
ENTERPRISE_TAGLINE: ''
|
||||
EVENT_TRACKING_SEGMENTIO_EMIT_WHITELIST: []
|
||||
EXTRA_MIDDLEWARE_CLASSES: []
|
||||
FACEBOOK_API_VERSION: v2.1
|
||||
FACEBOOK_APP_ID: FACEBOOK_APP_ID
|
||||
FACEBOOK_APP_SECRET: FACEBOOK_APP_SECRET
|
||||
FEATURES:
|
||||
AUTH_USE_OPENID_PROVIDER: true
|
||||
AUTOMATIC_AUTH_FOR_TESTING: false
|
||||
CUSTOM_COURSES_EDX: false
|
||||
ENABLE_BULK_ENROLLMENT_VIEW: false
|
||||
ENABLE_COMBINED_LOGIN_REGISTRATION: true
|
||||
ENABLE_CORS_HEADERS: false
|
||||
ENABLE_COUNTRY_ACCESS: false
|
||||
ENABLE_CREDIT_API: false
|
||||
ENABLE_CREDIT_ELIGIBILITY: false
|
||||
ENABLE_CROSS_DOMAIN_CSRF_COOKIE: false
|
||||
ENABLE_CSMH_EXTENDED: true
|
||||
ENABLE_DISCUSSION_HOME_PANEL: true
|
||||
ENABLE_DISCUSSION_SERVICE: true
|
||||
ENABLE_EDXNOTES: true
|
||||
ENABLE_ENROLLMENT_RESET: false
|
||||
ENABLE_EXPORT_GIT: false
|
||||
ENABLE_GRADE_DOWNLOADS: true
|
||||
ENABLE_LTI_PROVIDER: false
|
||||
ENABLE_MKTG_SITE: false
|
||||
ENABLE_MOBILE_REST_API: false
|
||||
ENABLE_OAUTH2_PROVIDER: false
|
||||
ENABLE_PUBLISHER: false
|
||||
ENABLE_READING_FROM_MULTIPLE_HISTORY_TABLES: true
|
||||
ENABLE_SPECIAL_EXAMS: false
|
||||
ENABLE_SYSADMIN_DASHBOARD: false
|
||||
ENABLE_THIRD_PARTY_AUTH: true
|
||||
ENABLE_VIDEO_UPLOAD_PIPELINE: false
|
||||
SHOW_FOOTER_LANGUAGE_SELECTOR: false
|
||||
SHOW_HEADER_LANGUAGE_SELECTOR: false
|
||||
FEEDBACK_SUBMISSION_EMAIL: ''
|
||||
FERNET_KEYS:
|
||||
- DUMMY KEY CHANGE BEFORE GOING TO PRODUCTION
|
||||
FILE_UPLOAD_STORAGE_BUCKET_NAME: SET-ME-PLEASE (ex. bucket-name)
|
||||
FILE_UPLOAD_STORAGE_PREFIX: submissions_attachments
|
||||
FINANCIAL_REPORTS:
|
||||
BUCKET: null
|
||||
ROOT_PATH: sandbox
|
||||
STORAGE_TYPE: localfs
|
||||
GITHUB_REPO_ROOT: /edx/var/edxapp/data
|
||||
GIT_REPO_DIR: /edx/var/edxapp/course_repos
|
||||
GOOGLE_ANALYTICS_ACCOUNT: null
|
||||
GOOGLE_ANALYTICS_LINKEDIN: ''
|
||||
GOOGLE_ANALYTICS_TRACKING_ID: ''
|
||||
GOOGLE_SITE_VERIFICATION_ID: ''
|
||||
GRADES_DOWNLOAD:
|
||||
BUCKET: ''
|
||||
ROOT_PATH: ''
|
||||
STORAGE_CLASS: django.core.files.storage.FileSystemStorage
|
||||
STORAGE_KWARGS:
|
||||
location: /tmp/edx-s3/grades
|
||||
STORAGE_TYPE: ''
|
||||
HELP_TOKENS_BOOKS:
|
||||
course_author: http://edx.readthedocs.io/projects/open-edx-building-and-running-a-course
|
||||
learner: http://edx.readthedocs.io/projects/open-edx-learner-guide
|
||||
HTTPS: 'on'
|
||||
ICP_LICENSE: null
|
||||
ICP_LICENSE_INFO: {}
|
||||
IDA_LOGOUT_URI_LIST: []
|
||||
ID_VERIFICATION_SUPPORT_LINK: ''
|
||||
INTEGRATED_CHANNELS_API_CHUNK_TRANSMISSION_LIMIT:
|
||||
SAP: 1
|
||||
JWT_AUTH:
|
||||
JWT_AUDIENCE: lms-key
|
||||
JWT_AUTH_COOKIE_HEADER_PAYLOAD: edx-jwt-cookie-header-payload
|
||||
JWT_AUTH_COOKIE_SIGNATURE: edx-jwt-cookie-signature
|
||||
JWT_ISSUER: http://edx.devstack.lms:18000/oauth2
|
||||
JWT_ISSUERS:
|
||||
- AUDIENCE: lms-key
|
||||
ISSUER: http://edx.devstack.lms:18000/oauth2
|
||||
SECRET_KEY: lms-secret
|
||||
JWT_PRIVATE_SIGNING_JWK: None
|
||||
JWT_PUBLIC_SIGNING_JWK_SET: ''
|
||||
JWT_SECRET_KEY: lms-secret
|
||||
JWT_SIGNING_ALGORITHM: null
|
||||
JWT_EXPIRATION: 30
|
||||
JWT_ISSUER: http://edx.devstack.lms:18000/oauth2
|
||||
JWT_PRIVATE_SIGNING_KEY: null
|
||||
LANGUAGE_CODE: en
|
||||
LANGUAGE_COOKIE: openedx-language-preference
|
||||
LEARNER_PORTAL_URL_ROOT: https://learner-portal-edx.devstack.lms:18000
|
||||
LEARNING_MICROFRONTEND_URL: null
|
||||
LMS_BASE: edx.devstack.lms:18000
|
||||
LMS_INTERNAL_ROOT_URL: http://edx.devstack.lms:18000
|
||||
LMS_ROOT_URL: http://edx.devstack.lms:18000
|
||||
LOCAL_LOGLEVEL: INFO
|
||||
LOGGING_ENV: sandbox
|
||||
LOGIN_REDIRECT_WHITELIST: []
|
||||
LOG_DIR: /edx/var/log/edx
|
||||
LTI_AGGREGATE_SCORE_PASSBACK_DELAY: 900
|
||||
LTI_USER_EMAIL_DOMAIN: lti.example.com
|
||||
MAILCHIMP_NEW_USER_LIST_ID: null
|
||||
MAINTENANCE_BANNER_TEXT: Sample banner message
|
||||
MEDIA_ROOT: /edx/var/edxapp/media/
|
||||
MEDIA_URL: /media/
|
||||
MKTG_URLS: {}
|
||||
MKTG_URL_LINK_MAP: {}
|
||||
MOBILE_STORE_URLS: {}
|
||||
MODULESTORE:
|
||||
default:
|
||||
ENGINE: xmodule.modulestore.mixed.MixedModuleStore
|
||||
OPTIONS:
|
||||
mappings: {}
|
||||
stores:
|
||||
- DOC_STORE_CONFIG:
|
||||
authsource: ''
|
||||
collection: modulestore
|
||||
connectTimeoutMS: 2000
|
||||
db: edxapp
|
||||
host:
|
||||
- edx.devstack.mongo
|
||||
password: password
|
||||
port: 27017
|
||||
read_preference: SECONDARY_PREFERRED
|
||||
replicaSet: ''
|
||||
socketTimeoutMS: 3000
|
||||
ssl: false
|
||||
user: edxapp
|
||||
ENGINE: xmodule.modulestore.split_mongo.split_draft.DraftVersioningModuleStore
|
||||
NAME: split
|
||||
OPTIONS:
|
||||
default_class: xmodule.hidden_block.HiddenBlock
|
||||
fs_root: /edx/var/edxapp/data
|
||||
render_template: common.djangoapps.edxmako.shortcuts.render_to_string
|
||||
- DOC_STORE_CONFIG:
|
||||
authsource: ''
|
||||
collection: modulestore
|
||||
connectTimeoutMS: 2000
|
||||
db: edxapp
|
||||
host:
|
||||
- edx.devstack.mongo
|
||||
password: password
|
||||
port: 27017
|
||||
read_preference: PRIMARY
|
||||
replicaSet: ''
|
||||
socketTimeoutMS: 3000
|
||||
ssl: false
|
||||
user: edxapp
|
||||
ENGINE: xmodule.modulestore.mongo.DraftMongoModuleStore
|
||||
NAME: draft
|
||||
OPTIONS:
|
||||
default_class: xmodule.hidden_block.HiddenBlock
|
||||
fs_root: /edx/var/edxapp/data
|
||||
render_template: common.djangoapps.edxmako.shortcuts.render_to_string
|
||||
OAUTH_DELETE_EXPIRED: true
|
||||
OAUTH_ENFORCE_SECURE: false
|
||||
OAUTH_EXPIRE_CONFIDENTIAL_CLIENT_DAYS: 365
|
||||
OAUTH_EXPIRE_PUBLIC_CLIENT_DAYS: 30
|
||||
OPTIMIZELY_PROJECT_ID: null
|
||||
ORA2_FILE_PREFIX: default_env-default_deployment/ora2
|
||||
ORDER_HISTORY_MICROFRONTEND_URL: null
|
||||
ORGANIZATIONS_AUTOCREATE: true
|
||||
PAID_COURSE_REGISTRATION_CURRENCY:
|
||||
- usd
|
||||
- $
|
||||
PARENTAL_CONSENT_AGE_LIMIT: 13
|
||||
PARTNER_SUPPORT_EMAIL: ''
|
||||
PASSWORD_POLICY_COMPLIANCE_ROLLOUT_CONFIG:
|
||||
ENFORCE_COMPLIANCE_ON_LOGIN: false
|
||||
PASSWORD_RESET_SUPPORT_LINK: ''
|
||||
PAYMENT_SUPPORT_EMAIL: billing@example.com
|
||||
PDF_RECEIPT_BILLING_ADDRESS: 'Enter your receipt billing
|
||||
|
||||
address here.
|
||||
|
||||
'
|
||||
PDF_RECEIPT_COBRAND_LOGO_PATH: ''
|
||||
PDF_RECEIPT_DISCLAIMER_TEXT: 'ENTER YOUR RECEIPT DISCLAIMER TEXT HERE.
|
||||
|
||||
'
|
||||
PDF_RECEIPT_FOOTER_TEXT: 'Enter your receipt footer text here.
|
||||
|
||||
'
|
||||
PDF_RECEIPT_LOGO_PATH: ''
|
||||
PDF_RECEIPT_TAX_ID: 00-0000000
|
||||
PDF_RECEIPT_TAX_ID_LABEL: fake Tax ID
|
||||
PDF_RECEIPT_TERMS_AND_CONDITIONS: 'Enter your receipt terms and conditions here.
|
||||
|
||||
'
|
||||
PLATFORM_DESCRIPTION: Your Platform Description Here
|
||||
PLATFORM_FACEBOOK_ACCOUNT: http://www.facebook.com/YourPlatformFacebookAccount
|
||||
PLATFORM_NAME: Your Platform Name Here
|
||||
PLATFORM_TWITTER_ACCOUNT: '@YourPlatformTwitterAccount'
|
||||
POLICY_CHANGE_GRADES_ROUTING_KEY: edx.lms.core.default
|
||||
SINGLE_LEARNER_COURSE_REGRADE_ROUTING_KEY: edx.lms.core.default
|
||||
PREPEND_LOCALE_PATHS: []
|
||||
PRESS_EMAIL: press@example.com
|
||||
PROCTORING_BACKENDS:
|
||||
DEFAULT: 'null'
|
||||
'null': {}
|
||||
PROCTORING_SETTINGS: {}
|
||||
PROFILE_IMAGE_BACKEND:
|
||||
class: openedx.core.storage.OverwriteStorage
|
||||
options:
|
||||
base_url: /media/profile-images/
|
||||
location: /edx/var/edxapp/media/profile-images/
|
||||
PROFILE_IMAGE_HASH_SEED: placeholder_secret_key
|
||||
PROFILE_IMAGE_MAX_BYTES: 1048576
|
||||
PROFILE_IMAGE_MIN_BYTES: 100
|
||||
PROFILE_IMAGE_SIZES_MAP:
|
||||
full: 500
|
||||
large: 120
|
||||
medium: 50
|
||||
small: 30
|
||||
PROFILE_MICROFRONTEND_URL: null
|
||||
PROGRAM_CERTIFICATES_ROUTING_KEY: edx.lms.core.default
|
||||
PROGRAM_CONSOLE_MICROFRONTEND_URL: null
|
||||
RECALCULATE_GRADES_ROUTING_KEY: edx.lms.core.default
|
||||
REGISTRATION_EXTRA_FIELDS:
|
||||
city: hidden
|
||||
confirm_email: hidden
|
||||
country: required
|
||||
gender: optional
|
||||
goals: optional
|
||||
honor_code: required
|
||||
level_of_education: optional
|
||||
mailing_address: hidden
|
||||
terms_of_service: hidden
|
||||
year_of_birth: optional
|
||||
RETIRED_EMAIL_DOMAIN: retired.invalid
|
||||
RETIRED_EMAIL_PREFIX: retired__user_
|
||||
RETIRED_USERNAME_PREFIX: retired__user_
|
||||
RETIRED_USER_SALTS:
|
||||
- OVERRIDE ME WITH A RANDOM VALUE
|
||||
- ROTATE SALTS BY APPENDING NEW VALUES
|
||||
RETIREMENT_SERVICE_WORKER_USERNAME: retirement_worker
|
||||
RETIREMENT_STATES:
|
||||
- PENDING
|
||||
- ERRORED
|
||||
- ABORTED
|
||||
- COMPLETE
|
||||
SECRET_KEY: DUMMY KEY ONLY FOR TO DEVSTACK
|
||||
SEGMENT_KEY: null
|
||||
SERVER_EMAIL: sre@example.com
|
||||
SESSION_COOKIE_DOMAIN: ''
|
||||
SESSION_COOKIE_NAME: sessionid
|
||||
SESSION_COOKIE_SECURE: false
|
||||
SESSION_SAVE_EVERY_REQUEST: false
|
||||
SITE_NAME: localhost
|
||||
SOCIAL_AUTH_OAUTH_SECRETS: ''
|
||||
SOCIAL_AUTH_SAML_SP_PRIVATE_KEY: ''
|
||||
SOCIAL_AUTH_SAML_SP_PRIVATE_KEY_DICT: {}
|
||||
SOCIAL_AUTH_SAML_SP_PUBLIC_CERT: ''
|
||||
SOCIAL_AUTH_SAML_SP_PUBLIC_CERT_DICT: {}
|
||||
SOCIAL_MEDIA_FOOTER_URLS: {}
|
||||
SOCIAL_SHARING_SETTINGS:
|
||||
CERTIFICATE_FACEBOOK: false
|
||||
CERTIFICATE_TWITTER: false
|
||||
CUSTOM_COURSE_URLS: false
|
||||
DASHBOARD_FACEBOOK: false
|
||||
DASHBOARD_TWITTER: false
|
||||
STATIC_ROOT_BASE: /edx/var/edxapp/staticfiles
|
||||
STATIC_URL_BASE: /static/
|
||||
STUDIO_NAME: Studio
|
||||
STUDIO_SHORT_NAME: Studio
|
||||
SUPPORT_SITE_LINK: ''
|
||||
SWIFT_AUTH_URL: null
|
||||
SWIFT_AUTH_VERSION: null
|
||||
SWIFT_KEY: null
|
||||
SWIFT_REGION_NAME: null
|
||||
SWIFT_TEMP_URL_DURATION: 1800
|
||||
SWIFT_TEMP_URL_KEY: null
|
||||
SWIFT_TENANT_ID: null
|
||||
SWIFT_TENANT_NAME: null
|
||||
SWIFT_USERNAME: null
|
||||
SWIFT_USE_TEMP_URLS: false
|
||||
SYSLOG_SERVER: ''
|
||||
SYSTEM_WIDE_ROLE_CLASSES: []
|
||||
TECH_SUPPORT_EMAIL: technical@example.com
|
||||
THIRD_PARTY_AUTH_BACKENDS:
|
||||
- social_core.backends.google.GoogleOAuth2
|
||||
- social_core.backends.linkedin.LinkedinOAuth2
|
||||
- social_core.backends.facebook.FacebookOAuth2
|
||||
- social_core.backends.azuread.AzureADOAuth2
|
||||
- common.djangoapps.third_party_auth.appleid.AppleIdAuth
|
||||
- common.djangoapps.third_party_auth.identityserver3.IdentityServer3
|
||||
- common.djangoapps.third_party_auth.saml.SAMLAuthBackend
|
||||
- common.djangoapps.third_party_auth.lti.LTIAuthBackend
|
||||
TIME_ZONE: America/New_York
|
||||
TRACKING_SEGMENTIO_WEBHOOK_SECRET: ''
|
||||
UNIVERSITY_EMAIL: university@example.com
|
||||
USERNAME_REPLACEMENT_WORKER: OVERRIDE THIS WITH A VALID USERNAME
|
||||
VERIFY_STUDENT:
|
||||
DAYS_GOOD_FOR: 365
|
||||
EXPIRING_SOON_WINDOW: 28
|
||||
VIDEO_CDN_URL:
|
||||
EXAMPLE_COUNTRY_CODE: http://example.com/edx/video?s3_url=
|
||||
VIDEO_IMAGE_MAX_AGE: 31536000
|
||||
VIDEO_IMAGE_SETTINGS:
|
||||
DIRECTORY_PREFIX: video-images/
|
||||
STORAGE_KWARGS:
|
||||
location: /edx/var/edxapp/media/
|
||||
VIDEO_IMAGE_MAX_BYTES: 2097152
|
||||
VIDEO_IMAGE_MIN_BYTES: 2048
|
||||
BASE_URL: /media/
|
||||
VIDEO_TRANSCRIPTS_MAX_AGE: 31536000
|
||||
VIDEO_TRANSCRIPTS_SETTINGS:
|
||||
DIRECTORY_PREFIX: video-transcripts/
|
||||
STORAGE_KWARGS:
|
||||
location: /edx/var/edxapp/media/
|
||||
VIDEO_TRANSCRIPTS_MAX_BYTES: 3145728
|
||||
BASE_URL: /media/
|
||||
VIDEO_UPLOAD_PIPELINE:
|
||||
BUCKET: ''
|
||||
ROOT_PATH: ''
|
||||
WIKI_ENABLED: true
|
||||
WRITABLE_GRADEBOOK_URL: null
|
||||
XBLOCK_FS_STORAGE_BUCKET: null
|
||||
XBLOCK_FS_STORAGE_PREFIX: null
|
||||
XBLOCK_SETTINGS: {}
|
||||
XQUEUE_INTERFACE:
|
||||
basic_auth:
|
||||
- edx
|
||||
- edx
|
||||
django_auth:
|
||||
password: password
|
||||
username: lms
|
||||
url: http://edx.devstack.xqueue:18040
|
||||
X_FRAME_OPTIONS: DENY
|
||||
YOUTUBE_API_KEY: PUT_YOUR_API_KEY_HERE
|
||||
ZENDESK_API_KEY: ''
|
||||
ZENDESK_CUSTOM_FIELDS: {}
|
||||
ZENDESK_GROUP_ID_MAPPING: {}
|
||||
ZENDESK_OAUTH_ACCESS_TOKEN: ''
|
||||
ZENDESK_URL: ''
|
||||
ZENDESK_USER: ''
|
||||
@@ -1,9 +0,0 @@
|
||||
"""
|
||||
Left over environment file from before the transition of devstack from
|
||||
vagrant to docker was complete.
|
||||
|
||||
This file should no longer be used, and is only around in case something
|
||||
still refers to it.
|
||||
"""
|
||||
|
||||
from .devstack import * # pylint: disable=wildcard-import, unused-wildcard-import
|
||||
@@ -1,45 +0,0 @@
|
||||
"""
|
||||
Settings to run LMS in devstack using optimized static assets.
|
||||
|
||||
This configuration changes LMS to use the optimized static assets generated for testing,
|
||||
rather than picking up the files directly from the source tree.
|
||||
|
||||
The following Paver command can be used to run LMS in optimized mode:
|
||||
|
||||
paver devstack lms --optimized
|
||||
|
||||
You can also generate the assets explicitly and then run Studio:
|
||||
|
||||
paver update_assets lms --settings=test_static_optimized
|
||||
paver devstack lms --settings=devstack_optimized --fast
|
||||
|
||||
Note that changes to JavaScript assets will not be picked up automatically
|
||||
as they are for non-optimized devstack. Instead, update_assets must be
|
||||
invoked each time that changes have been made.
|
||||
"""
|
||||
|
||||
|
||||
########################## Devstack settings ###################################
|
||||
|
||||
from .devstack import * # pylint: disable=wildcard-import
|
||||
|
||||
TEST_ROOT = REPO_ROOT / "test_root"
|
||||
|
||||
############################ STATIC FILES #############################
|
||||
|
||||
# Enable debug so that static assets are served by Django
|
||||
DEBUG = True
|
||||
|
||||
# Set REQUIRE_DEBUG to false so that it behaves like production
|
||||
REQUIRE_DEBUG = False
|
||||
|
||||
# Fetch static files out of the pipeline's static root
|
||||
STATICFILES_STORAGE = 'pipeline.storage.PipelineManifestStorage'
|
||||
|
||||
# Serve static files at /static directly from the staticfiles directory under test root.
|
||||
# Note: optimized files for testing are generated with settings from test_static_optimized
|
||||
STATIC_URL = "/static/"
|
||||
STATICFILES_FINDERS = ['django.contrib.staticfiles.finders.FileSystemFinder']
|
||||
STATICFILES_DIRS = [
|
||||
(TEST_ROOT / "staticfiles" / "lms").abspath(),
|
||||
]
|
||||
@@ -1,23 +0,0 @@
|
||||
"""
|
||||
This config file follows the devstack environment, but adds the
|
||||
requirement of a celery worker running in the background to process
|
||||
celery tasks.
|
||||
|
||||
When testing locally, run lms/cms with this settings file as well, to test queueing
|
||||
of tasks onto the appropriate workers.
|
||||
|
||||
In two separate processes on devstack:
|
||||
paver devstack lms --settings=devstack_with_worker
|
||||
DJANGO_SETTINGS_MODULE=lms.envs.devstack_with_worker celery worker --app=lms.celery:APP
|
||||
"""
|
||||
|
||||
|
||||
# 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
|
||||
from lms.envs.devstack import *
|
||||
|
||||
# Require a separate celery worker
|
||||
CELERY_ALWAYS_EAGER = False
|
||||
CLEAR_REQUEST_CACHE_ON_TASK_COMPLETION = True
|
||||
BROKER_URL = 'redis://:password@edx.devstack.redis:6379/'
|
||||
@@ -1,9 +0,0 @@
|
||||
"""
|
||||
Specific overrides to the base prod settings for a docker production deployment.
|
||||
"""
|
||||
|
||||
from .production import * # pylint: disable=wildcard-import, unused-wildcard-import
|
||||
|
||||
from openedx.core.lib.logsettings import get_docker_logger_config
|
||||
|
||||
LOGGING = get_docker_logger_config()
|
||||
@@ -1,32 +0,0 @@
|
||||
"""
|
||||
Settings for OpenStack deployments.
|
||||
"""
|
||||
|
||||
from .production import * # pylint: disable=wildcard-import, unused-wildcard-import
|
||||
|
||||
SWIFT_AUTH_URL = AUTH_TOKENS.get('SWIFT_AUTH_URL')
|
||||
SWIFT_AUTH_VERSION = AUTH_TOKENS.get('SWIFT_AUTH_VERSION', 1)
|
||||
SWIFT_USERNAME = AUTH_TOKENS.get('SWIFT_USERNAME')
|
||||
SWIFT_KEY = AUTH_TOKENS.get('SWIFT_KEY')
|
||||
SWIFT_TENANT_NAME = AUTH_TOKENS.get('SWIFT_TENANT_NAME')
|
||||
SWIFT_TENANT_ID = AUTH_TOKENS.get('SWIFT_TENANT_ID')
|
||||
SWIFT_CONTAINER_NAME = FILE_UPLOAD_STORAGE_BUCKET_NAME
|
||||
SWIFT_NAME_PREFIX = FILE_UPLOAD_STORAGE_PREFIX
|
||||
SWIFT_USE_TEMP_URLS = AUTH_TOKENS.get('SWIFT_USE_TEMP_URLS', False)
|
||||
SWIFT_TEMP_URL_KEY = AUTH_TOKENS.get('SWIFT_TEMP_URL_KEY')
|
||||
SWIFT_TEMP_URL_DURATION = AUTH_TOKENS.get('SWIFT_TEMP_URL_DURATION', 1800) # seconds
|
||||
SWIFT_CONTENT_TYPE_FROM_FD = AUTH_TOKENS.get('SWIFT_CONTENT_TYPE_FROM_FD', True)
|
||||
SWIFT_CONTENT_LENGTH_FROM_FD = AUTH_TOKENS.get('SWIFT_CONTENT_LENGTH_FROM_FD', False)
|
||||
SWIFT_LAZY_CONNECT = AUTH_TOKENS.get('SWIFT_LAZY_CONNECT', True)
|
||||
|
||||
if AUTH_TOKENS.get('SWIFT_REGION_NAME'):
|
||||
SWIFT_EXTRA_OPTIONS = {'region_name': AUTH_TOKENS['SWIFT_REGION_NAME']}
|
||||
|
||||
if AUTH_TOKENS.get('DEFAULT_FILE_STORAGE'):
|
||||
DEFAULT_FILE_STORAGE = AUTH_TOKENS.get('DEFAULT_FILE_STORAGE')
|
||||
elif SWIFT_AUTH_URL and SWIFT_USERNAME and SWIFT_KEY:
|
||||
DEFAULT_FILE_STORAGE = 'swift.storage.SwiftStorage'
|
||||
else:
|
||||
DEFAULT_FILE_STORAGE = 'django.core.files.storage.FileSystemStorage'
|
||||
|
||||
ORA2_FILEUPLOAD_BACKEND = "django"
|
||||
@@ -1,76 +0,0 @@
|
||||
"""
|
||||
This config file runs the simplest dev environment using sqlite, and db-based
|
||||
sessions. Assumes structure:
|
||||
|
||||
/envroot/
|
||||
/db # This is where it'll write the database file
|
||||
/edx-platform # The location of this repo
|
||||
/log # Where we're going to write log files
|
||||
"""
|
||||
|
||||
# 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
|
||||
|
||||
|
||||
from openedx.core.lib.derived import derive_settings
|
||||
from openedx.core.lib.logsettings import get_logger_config
|
||||
|
||||
from .common import *
|
||||
|
||||
STATIC_GRAB = True
|
||||
|
||||
LOGGING = get_logger_config(ENV_ROOT / "log",
|
||||
logging_env="dev")
|
||||
|
||||
DATABASES = {
|
||||
'default': {
|
||||
'ENGINE': 'django.db.backends.sqlite3',
|
||||
'NAME': ENV_ROOT / "db" / "edx.db",
|
||||
'ATOMIC_REQUESTS': True,
|
||||
},
|
||||
'student_module_history': {
|
||||
'ENGINE': 'django.db.backends.sqlite3',
|
||||
'NAME': ENV_ROOT / "db" / "student_module_history.db",
|
||||
'ATOMIC_REQUESTS': True,
|
||||
}
|
||||
}
|
||||
|
||||
CACHES = {
|
||||
# This is the cache used for most things.
|
||||
# In staging/prod envs, the sessions also live here.
|
||||
'default': {
|
||||
'BACKEND': 'django.core.cache.backends.locmem.LocMemCache',
|
||||
'LOCATION': 'edx_loc_mem_cache',
|
||||
'KEY_FUNCTION': 'common.djangoapps.util.memcache.safe_key',
|
||||
},
|
||||
|
||||
# The general cache is what you get if you use our util.cache. It's used for
|
||||
# things like caching the course.xml file for different A/B test groups.
|
||||
# We set it to be a DummyCache to force reloading of course.xml in dev.
|
||||
# In staging environments, we would grab VERSION from data uploaded by the
|
||||
# push process.
|
||||
'general': {
|
||||
'BACKEND': 'django.core.cache.backends.dummy.DummyCache',
|
||||
'KEY_PREFIX': 'general',
|
||||
'VERSION': 4,
|
||||
'KEY_FUNCTION': 'common.djangoapps.util.memcache.safe_key',
|
||||
}
|
||||
}
|
||||
|
||||
# Dummy secret key for dev
|
||||
SECRET_KEY = '85920908f28904ed733fe576320db18cabd7b6cd'
|
||||
|
||||
############################ FILE UPLOADS (for discussion forums) #############################
|
||||
DEFAULT_FILE_STORAGE = 'django.core.files.storage.FileSystemStorage'
|
||||
MEDIA_ROOT = ENV_ROOT / "uploads"
|
||||
MEDIA_URL = "/discussion/upfiles/"
|
||||
FILE_UPLOAD_TEMP_DIR = ENV_ROOT / "uploads"
|
||||
FILE_UPLOAD_HANDLERS = [
|
||||
'django.core.files.uploadhandler.MemoryFileUploadHandler',
|
||||
'django.core.files.uploadhandler.TemporaryFileUploadHandler',
|
||||
]
|
||||
|
||||
########################## Derive Any Derived Settings #######################
|
||||
|
||||
derive_settings(__name__)
|
||||
@@ -1,71 +0,0 @@
|
||||
"""
|
||||
Settings used when generating static assets for use in tests.
|
||||
|
||||
Note: it isn't possible to have a single settings file, because Django doesn't
|
||||
support both generating static assets to a directory and also serving static
|
||||
from the same directory.
|
||||
"""
|
||||
|
||||
# Start with the common settings
|
||||
|
||||
|
||||
from openedx.core.lib.derived import derive_settings
|
||||
from openedx.core.lib.django_require.staticstorage import OptimizedCachedRequireJsStorage
|
||||
|
||||
from .common import * # pylint: disable=wildcard-import, unused-wildcard-import
|
||||
|
||||
# Use an in-memory database since this settings file is only used for updating assets
|
||||
DATABASES = {
|
||||
'default': {
|
||||
'ENGINE': 'django.db.backends.sqlite3',
|
||||
'ATOMIC_REQUESTS': True,
|
||||
},
|
||||
'student_module_history': {
|
||||
'ENGINE': 'django.db.backends.sqlite3',
|
||||
},
|
||||
}
|
||||
|
||||
# Provide a dummy XQUEUE_INTERFACE setting as LMS expects it to exist on start up
|
||||
XQUEUE_INTERFACE = {
|
||||
"url": "https://sandbox-xqueue.edx.org",
|
||||
"django_auth": {
|
||||
"username": "lms",
|
||||
"password": "***REMOVED***"
|
||||
},
|
||||
"basic_auth": ('anant', 'agarwal'),
|
||||
}
|
||||
|
||||
PROCTORING_BACKENDS = {
|
||||
'DEFAULT': 'mock',
|
||||
'mock': {},
|
||||
'mock_proctoring_without_rules': {},
|
||||
}
|
||||
|
||||
######################### PIPELINE ####################################
|
||||
|
||||
# Use RequireJS optimized storage
|
||||
STATICFILES_STORAGE = f"{OptimizedCachedRequireJsStorage.__module__}.{OptimizedCachedRequireJsStorage.__name__}"
|
||||
|
||||
# Revert to the default set of finders as we don't want to dynamically pick up files from the pipeline
|
||||
STATICFILES_FINDERS = [
|
||||
'django.contrib.staticfiles.finders.FileSystemFinder',
|
||||
'django.contrib.staticfiles.finders.AppDirectoriesFinder',
|
||||
'openedx.core.lib.xblock_pipeline.finder.XBlockPipelineFinder',
|
||||
]
|
||||
|
||||
# Redirect to the test_root folder within the repo
|
||||
TEST_ROOT = REPO_ROOT / "test_root"
|
||||
LOG_DIR = (TEST_ROOT / "log").abspath()
|
||||
|
||||
# Store the static files under test root so that they don't overwrite existing static assets
|
||||
STATIC_ROOT = (TEST_ROOT / "staticfiles" / "lms").abspath()
|
||||
WEBPACK_LOADER['DEFAULT']['STATS_FILE'] = STATIC_ROOT / "webpack-stats.json"
|
||||
|
||||
# Disable uglify when tests are running (used by build.js).
|
||||
# 1. Uglify is by far the slowest part of the build process
|
||||
# 2. Having full source code makes debugging tests easier for developers
|
||||
os.environ['REQUIRE_BUILD_PROFILE_OPTIMIZE'] = 'none'
|
||||
|
||||
########################## Derive Any Derived Settings #######################
|
||||
|
||||
derive_settings(__name__)
|
||||
@@ -39,7 +39,7 @@ def parse_args():
|
||||
lms.add_argument(
|
||||
'--settings',
|
||||
help="Which django settings module to use under lms.envs. If not provided, the DJANGO_SETTINGS_MODULE "
|
||||
"environment variable will be used if it is set, otherwise it will default to lms.envs.devstack_docker")
|
||||
"environment variable will be used if it is set, otherwise it will default to lms.envs.devstack")
|
||||
lms.add_argument(
|
||||
'--service-variant',
|
||||
choices=['lms', 'lms-xml', 'lms-preview'],
|
||||
@@ -48,7 +48,7 @@ def parse_args():
|
||||
lms.set_defaults(
|
||||
help_string=lms.format_help(),
|
||||
settings_base='lms/envs',
|
||||
default_settings='lms.envs.devstack_docker',
|
||||
default_settings='lms.envs.devstack',
|
||||
)
|
||||
|
||||
cms = subparsers.add_parser(
|
||||
@@ -60,12 +60,12 @@ def parse_args():
|
||||
cms.add_argument(
|
||||
'--settings',
|
||||
help="Which django settings module to use under cms.envs. If not provided, the DJANGO_SETTINGS_MODULE "
|
||||
"environment variable will be used if it is set, otherwise it will default to cms.envs.devstack_docker")
|
||||
"environment variable will be used if it is set, otherwise it will default to cms.envs.devstack")
|
||||
cms.add_argument('-h', '--help', action='store_true', help='show this help message and exit')
|
||||
cms.set_defaults(
|
||||
help_string=cms.format_help(),
|
||||
settings_base='cms/envs',
|
||||
default_settings='cms.envs.devstack_docker',
|
||||
default_settings='cms.envs.devstack',
|
||||
service_variant='cms',
|
||||
)
|
||||
|
||||
|
||||
@@ -41,11 +41,11 @@ class Command(BaseCommand):
|
||||
Example usage:
|
||||
|
||||
# Process all certs/grades changes for a given course:
|
||||
$ ./manage.py lms --settings=devstack_docker notify_credentials \
|
||||
$ ./manage.py lms --settings=devstack notify_credentials \
|
||||
--courses course-v1:edX+DemoX+Demo_Course
|
||||
|
||||
# Process all certs/grades changes in a given time range:
|
||||
$ ./manage.py lms --settings=devstack_docker notify_credentials \
|
||||
$ ./manage.py lms --settings=devstack notify_credentials \
|
||||
--start-date 2018-06-01 --end-date 2018-07-31
|
||||
|
||||
A Dry Run will produce output that looks like:
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
"""
|
||||
Management command to fix NotificationPreference records with invalid 'Mixed' email_cadence values
|
||||
created during migration.
|
||||
"""
|
||||
|
||||
import logging
|
||||
from django.core.management.base import BaseCommand
|
||||
|
||||
from openedx.core.djangoapps.notifications.models import NotificationPreference
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
"""
|
||||
Management command to identify and correct NotificationPreference records
|
||||
with an invalid 'Mixed' value in the email_cadence field.
|
||||
|
||||
By default, the command runs in dry-run mode and only logs the count of
|
||||
affected records. Use the `--fix` flag to replace all 'Mixed' values with
|
||||
'Daily', ensuring data consistency with defined model choices.
|
||||
Invoke with:
|
||||
python manage.py [lms] fix_mixed_email_cadence --fix
|
||||
"""
|
||||
help = (
|
||||
"Identifies NotificationPreference records with 'Mixed' as email_cadence "
|
||||
"and optionally replaces it with a valid value (default: 'Daily')."
|
||||
)
|
||||
|
||||
def add_arguments(self, parser):
|
||||
parser.add_argument(
|
||||
'--fix',
|
||||
action='store_true',
|
||||
help='Apply the fix by replacing "Mixed" with "Daily". Default is dry-run mode.'
|
||||
)
|
||||
|
||||
def handle(self, *args, **options):
|
||||
fix_mode = options['fix']
|
||||
invalid_records = NotificationPreference.objects.filter(email_cadence='Mixed')
|
||||
count = invalid_records.count()
|
||||
|
||||
if count == 0:
|
||||
logger.info("No records found with invalid 'Mixed' value in email_cadence.")
|
||||
return
|
||||
|
||||
logger.info(f"Found {count} NotificationPreference records with 'Mixed' email_cadence.")
|
||||
|
||||
if fix_mode:
|
||||
updated_count = invalid_records.update(
|
||||
email_cadence=NotificationPreference.EmailCadenceChoices.DAILY
|
||||
)
|
||||
logger.info(f"Successfully updated {updated_count} records. 'Mixed' replaced with 'Daily'.")
|
||||
else:
|
||||
logger.warning(
|
||||
"Dry-run mode: no changes were made.\n"
|
||||
"To apply changes, re-run the command with the --fix flag."
|
||||
)
|
||||
@@ -130,21 +130,21 @@ can use:
|
||||
|
||||
::
|
||||
|
||||
./manage.py lms --settings devstack_docker send_recurring_nudge example.com
|
||||
./manage.py lms --settings devstack send_recurring_nudge example.com
|
||||
|
||||
You can override the “current date” when running a command. The app will run,
|
||||
using the date you specify as its "today":
|
||||
|
||||
::
|
||||
|
||||
./manage.py lms --settings devstack_docker send_recurring_nudge example.com --date 2017-11-13
|
||||
./manage.py lms --settings devstack send_recurring_nudge example.com --date 2017-11-13
|
||||
|
||||
If the app is paired with Sailthru, you can override which email addresses the
|
||||
app sends to. The app will send all emails to the address you specify:
|
||||
|
||||
::
|
||||
|
||||
./manage.py lms --settings devstack_docker send_recurring_nudge example.com --override-recipient-email developer@example.com
|
||||
./manage.py lms --settings devstack send_recurring_nudge example.com --override-recipient-email developer@example.com
|
||||
|
||||
These management commands are meant to be run daily. We schedule them to
|
||||
run automatically in a Jenkins job. You can use a similar automation
|
||||
@@ -419,7 +419,7 @@ To begin using Litmus, follow these steps:
|
||||
|
||||
::
|
||||
|
||||
./manage.py lms --settings devstack_docker send_recurring_nudge example.com --override-recipient-email PUT-LITMUS-ADDRESS-HERE
|
||||
./manage.py lms --settings devstack send_recurring_nudge example.com --override-recipient-email PUT-LITMUS-ADDRESS-HERE
|
||||
|
||||
Using the Litmus Browser Extenstion to test emails saved as local files
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
@@ -7,13 +7,7 @@ from django.core import checks
|
||||
|
||||
_DEVSTACK_SETTINGS_MODULES = [
|
||||
"lms.envs.devstack",
|
||||
"lms.envs.devstack_docker",
|
||||
"lms.envs.devstack_optimized",
|
||||
"lms.envs.devstack_with_worker",
|
||||
"cms.envs.devstack",
|
||||
"cms.envs.devstack_docker",
|
||||
"cms.envs.devstack_optimized",
|
||||
"cms.envs.devstack_with_worker",
|
||||
]
|
||||
|
||||
|
||||
@@ -26,7 +20,7 @@ def warn_if_devstack_settings(**kwargs):
|
||||
return [
|
||||
checks.Warning(
|
||||
"Open edX Devstack is deprecated, so the Django settings module you are using "
|
||||
f"({settings.SETTINGS_MODULE}) will be removed from openedx/edx-platform by October 2024. "
|
||||
f"({settings.SETTINGS_MODULE}) will be removed from openedx/edx-platform in 2025. "
|
||||
"Please either migrate off of Devstack, or modify your Devstack fork to work with an externally-"
|
||||
"managed Django settings file. "
|
||||
"For details and discussion, see: https://github.com/openedx/public-engineering/issues/247.",
|
||||
|
||||
@@ -51,7 +51,7 @@ django-stubs<6
|
||||
# The team that owns this package will manually bump this package rather than having it pulled in automatically.
|
||||
# This is to allow them to better control its deployment and to do it in a process that works better
|
||||
# for them.
|
||||
edx-enterprise==6.2.11
|
||||
edx-enterprise==6.2.13
|
||||
|
||||
# Date: 2023-07-26
|
||||
# Our legacy Sass code is incompatible with anything except this ancient libsass version.
|
||||
@@ -70,7 +70,7 @@ numpy<2.0.0
|
||||
# Date: 2023-09-18
|
||||
# pinning this version to avoid updates while the library is being developed
|
||||
# Issue for unpinning: https://github.com/openedx/edx-platform/issues/35269
|
||||
openedx-learning==0.26.0
|
||||
openedx-learning==0.27.0
|
||||
|
||||
# Date: 2023-11-29
|
||||
# Open AI version 1.0.0 dropped support for openai.ChatCompletion which is currently in use in enterprise.
|
||||
|
||||
@@ -473,7 +473,7 @@ edx-drf-extensions==10.6.0
|
||||
# edxval
|
||||
# enterprise-integrated-channels
|
||||
# openedx-learning
|
||||
edx-enterprise==6.2.11
|
||||
edx-enterprise==6.2.13
|
||||
# via
|
||||
# -c requirements/edx/../constraints.txt
|
||||
# -r requirements/edx/kernel.in
|
||||
@@ -566,7 +566,7 @@ enmerkar==0.7.1
|
||||
# via enmerkar-underscore
|
||||
enmerkar-underscore==2.4.0
|
||||
# via -r requirements/edx/kernel.in
|
||||
enterprise-integrated-channels==0.1.11
|
||||
enterprise-integrated-channels==0.1.13
|
||||
# via -r requirements/edx/bundled.in
|
||||
event-tracking==3.3.0
|
||||
# via
|
||||
@@ -840,7 +840,7 @@ openedx-filters==2.1.0
|
||||
# ora2
|
||||
openedx-forum==0.3.0
|
||||
# via -r requirements/edx/kernel.in
|
||||
openedx-learning==0.26.0
|
||||
openedx-learning==0.27.0
|
||||
# via
|
||||
# -c requirements/edx/../constraints.txt
|
||||
# -r requirements/edx/kernel.in
|
||||
@@ -1174,7 +1174,9 @@ text-unidecode==1.3
|
||||
tinycss2==1.4.0
|
||||
# via bleach
|
||||
tomlkit==0.13.2
|
||||
# via snowflake-connector-python
|
||||
# via
|
||||
# openedx-learning
|
||||
# snowflake-connector-python
|
||||
tqdm==4.67.1
|
||||
# via
|
||||
# nltk
|
||||
|
||||
@@ -750,7 +750,7 @@ edx-drf-extensions==10.6.0
|
||||
# edxval
|
||||
# enterprise-integrated-channels
|
||||
# openedx-learning
|
||||
edx-enterprise==6.2.11
|
||||
edx-enterprise==6.2.13
|
||||
# via
|
||||
# -c requirements/edx/../constraints.txt
|
||||
# -r requirements/edx/doc.txt
|
||||
@@ -879,7 +879,7 @@ enmerkar-underscore==2.4.0
|
||||
# via
|
||||
# -r requirements/edx/doc.txt
|
||||
# -r requirements/edx/testing.txt
|
||||
enterprise-integrated-channels==0.1.11
|
||||
enterprise-integrated-channels==0.1.13
|
||||
# via
|
||||
# -r requirements/edx/doc.txt
|
||||
# -r requirements/edx/testing.txt
|
||||
@@ -1400,7 +1400,7 @@ openedx-forum==0.3.0
|
||||
# via
|
||||
# -r requirements/edx/doc.txt
|
||||
# -r requirements/edx/testing.txt
|
||||
openedx-learning==0.26.0
|
||||
openedx-learning==0.27.0
|
||||
# via
|
||||
# -c requirements/edx/../constraints.txt
|
||||
# -r requirements/edx/doc.txt
|
||||
@@ -2104,6 +2104,7 @@ tomlkit==0.13.2
|
||||
# via
|
||||
# -r requirements/edx/doc.txt
|
||||
# -r requirements/edx/testing.txt
|
||||
# openedx-learning
|
||||
# pylint
|
||||
# snowflake-connector-python
|
||||
tox==4.26.0
|
||||
|
||||
@@ -555,7 +555,7 @@ edx-drf-extensions==10.6.0
|
||||
# edxval
|
||||
# enterprise-integrated-channels
|
||||
# openedx-learning
|
||||
edx-enterprise==6.2.11
|
||||
edx-enterprise==6.2.13
|
||||
# via
|
||||
# -c requirements/edx/../constraints.txt
|
||||
# -r requirements/edx/base.txt
|
||||
@@ -653,7 +653,7 @@ enmerkar==0.7.1
|
||||
# enmerkar-underscore
|
||||
enmerkar-underscore==2.4.0
|
||||
# via -r requirements/edx/base.txt
|
||||
enterprise-integrated-channels==0.1.11
|
||||
enterprise-integrated-channels==0.1.13
|
||||
# via -r requirements/edx/base.txt
|
||||
event-tracking==3.3.0
|
||||
# via
|
||||
@@ -1005,7 +1005,7 @@ openedx-filters==2.1.0
|
||||
# ora2
|
||||
openedx-forum==0.3.0
|
||||
# via -r requirements/edx/base.txt
|
||||
openedx-learning==0.26.0
|
||||
openedx-learning==0.27.0
|
||||
# via
|
||||
# -c requirements/edx/../constraints.txt
|
||||
# -r requirements/edx/base.txt
|
||||
@@ -1474,6 +1474,7 @@ tinycss2==1.4.0
|
||||
tomlkit==0.13.2
|
||||
# via
|
||||
# -r requirements/edx/base.txt
|
||||
# openedx-learning
|
||||
# snowflake-connector-python
|
||||
tqdm==4.67.1
|
||||
# via
|
||||
|
||||
@@ -580,7 +580,7 @@ edx-drf-extensions==10.6.0
|
||||
# edxval
|
||||
# enterprise-integrated-channels
|
||||
# openedx-learning
|
||||
edx-enterprise==6.2.11
|
||||
edx-enterprise==6.2.13
|
||||
# via
|
||||
# -c requirements/edx/../constraints.txt
|
||||
# -r requirements/edx/base.txt
|
||||
@@ -680,7 +680,7 @@ enmerkar==0.7.1
|
||||
# enmerkar-underscore
|
||||
enmerkar-underscore==2.4.0
|
||||
# via -r requirements/edx/base.txt
|
||||
enterprise-integrated-channels==0.1.11
|
||||
enterprise-integrated-channels==0.1.13
|
||||
# via -r requirements/edx/base.txt
|
||||
event-tracking==3.3.0
|
||||
# via
|
||||
@@ -1064,7 +1064,7 @@ openedx-filters==2.1.0
|
||||
# ora2
|
||||
openedx-forum==0.3.0
|
||||
# via -r requirements/edx/base.txt
|
||||
openedx-learning==0.26.0
|
||||
openedx-learning==0.27.0
|
||||
# via
|
||||
# -c requirements/edx/../constraints.txt
|
||||
# -r requirements/edx/base.txt
|
||||
@@ -1563,6 +1563,7 @@ tinycss2==1.4.0
|
||||
tomlkit==0.13.2
|
||||
# via
|
||||
# -r requirements/edx/base.txt
|
||||
# openedx-learning
|
||||
# pylint
|
||||
# snowflake-connector-python
|
||||
tox==4.26.0
|
||||
|
||||
@@ -1,24 +1,21 @@
|
||||
"""
|
||||
Template block
|
||||
"""
|
||||
|
||||
import logging
|
||||
from string import Template
|
||||
from xblock.core import XBlock
|
||||
|
||||
from lxml import etree
|
||||
from web_fragments.fragment import Fragment
|
||||
from xblock.core import XBlock
|
||||
|
||||
from xmodule.editing_block import EditingMixin
|
||||
from xmodule.modulestore.exceptions import ItemNotFoundError
|
||||
from xmodule.raw_block import RawMixin
|
||||
from xmodule.util.builtin_assets import add_webpack_js_to_fragment, add_css_to_fragment
|
||||
from xmodule.x_module import (
|
||||
ResourceTemplates,
|
||||
shim_xmodule_js,
|
||||
XModuleMixin,
|
||||
XModuleToXBlockMixin,
|
||||
)
|
||||
from xmodule.util.builtin_assets import add_css_to_fragment, add_webpack_js_to_fragment
|
||||
from xmodule.x_module import ResourceTemplates, XModuleMixin, XModuleToXBlockMixin, shim_xmodule_js
|
||||
from xmodule.xml_block import XmlMixin
|
||||
|
||||
from openedx.core.djangolib.markup import Text
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class CustomTagTemplateBlock( # pylint: disable=abstract-method
|
||||
@@ -76,8 +73,10 @@ class CustomTagBlock(CustomTagTemplateBlock): # pylint: disable=abstract-method
|
||||
|
||||
def render_template(self, system, xml_data):
|
||||
'''Render the template, given the definition xml_data'''
|
||||
if not xml_data:
|
||||
return "Please set the template for this custom tag."
|
||||
xmltree = etree.fromstring(xml_data)
|
||||
if 'impl' in xmltree.attrib:
|
||||
if 'impl' in xmltree.attrib and xmltree.attrib['impl']:
|
||||
template_name = xmltree.attrib['impl']
|
||||
else:
|
||||
# VS[compat] backwards compatibility with old nested customtag structure
|
||||
@@ -86,16 +85,19 @@ class CustomTagBlock(CustomTagTemplateBlock): # pylint: disable=abstract-method
|
||||
template_name = child_impl.text
|
||||
else:
|
||||
# TODO (vshnayder): better exception type
|
||||
raise Exception("Could not find impl attribute in customtag {}"
|
||||
.format(self.location))
|
||||
return Template("Could not find impl attribute in customtag {}").safe_substitute({})
|
||||
|
||||
params = dict(list(xmltree.items()))
|
||||
|
||||
# cdodge: look up the template as a module
|
||||
template_loc = self.location.replace(category='custom_tag_template', name=template_name)
|
||||
try:
|
||||
template_block = system.get_block(template_loc)
|
||||
template_block_data = template_block.data
|
||||
except ItemNotFoundError as ex:
|
||||
template_block_data = f"Could not find template block for custom tag with Id {template_name}"
|
||||
log.info(template_block_data)
|
||||
|
||||
template_block = system.get_block(template_loc)
|
||||
template_block_data = template_block.data
|
||||
template = Template(template_block_data)
|
||||
return template.safe_substitute(params)
|
||||
|
||||
@@ -120,8 +122,7 @@ class CustomTagBlock(CustomTagTemplateBlock): # pylint: disable=abstract-method
|
||||
|
||||
|
||||
class TranslateCustomTagBlock( # pylint: disable=abstract-method
|
||||
XModuleToXBlockMixin,
|
||||
XModuleMixin,
|
||||
CustomTagBlock,
|
||||
):
|
||||
"""
|
||||
Converts olx of the form `<$custom_tag attr="" attr=""/>` to CustomTagBlock
|
||||
@@ -129,19 +130,20 @@ class TranslateCustomTagBlock( # pylint: disable=abstract-method
|
||||
"""
|
||||
resources_dir = None
|
||||
|
||||
@classmethod
|
||||
def parse_xml(cls, node, runtime, _keys):
|
||||
"""
|
||||
Transforms the xml_data from <$custom_tag attr="" attr=""/> to
|
||||
<customtag attr="" attr="" impl="$custom_tag"/>
|
||||
"""
|
||||
|
||||
runtime.error_tracker(Text('WARNING: the <{tag}> tag is deprecated. '
|
||||
'Instead, use <customtag impl="{tag}" attr1="..." attr2="..."/>. ')
|
||||
.format(tag=node.tag))
|
||||
def render_template(self, system, xml_data):
|
||||
xml_string = ""
|
||||
if xml_data:
|
||||
xmltree = etree.fromstring(xml_data)
|
||||
xmltree = self.replace_xml(xmltree)
|
||||
xml_string = etree.tostring(xmltree, pretty_print=True).decode("utf-8")
|
||||
return super().render_template(system, xml_string or xml_data)
|
||||
|
||||
def replace_xml(self, node):
|
||||
"""
|
||||
Replaces the xml_data from <$custom_tag attr="" attr=""/> to
|
||||
<customtag attr="" attr="" impl="$custom_tag"/>.
|
||||
"""
|
||||
tag = node.tag
|
||||
node.tag = 'customtag'
|
||||
node.attrib['impl'] = tag
|
||||
|
||||
return runtime.process_xml(etree.tostring(node))
|
||||
return node
|
||||
|
||||
Reference in New Issue
Block a user