From 343b4cd71fabebceb9183ec5544938ae3bef7b4e Mon Sep 17 00:00:00 2001 From: Hunia Fatima Date: Tue, 19 Nov 2024 15:52:19 +0500 Subject: [PATCH] chore: add enterprise catalog in devstack --- Makefile | 3 + docker-compose-host.yml | 20 +- docker-compose.yml | 77 +++ docs/service_list.rst | 3 + options.mk | 2 +- provision-enterprise_catalog.sh | 23 + provision-mysql80.sql | 4 + provision.sh | 3 +- provision.sql | 2 + py_configuration_files/analytics_data_api.py | 55 ++ py_configuration_files/anayltics_dashboard.py | 47 ++ py_configuration_files/cms.py | 349 +++++++++++ .../commerce_coordinator.py | 75 +++ py_configuration_files/course_discovery.py | 99 ++++ py_configuration_files/ecommerce.py | 141 +++++ py_configuration_files/edx_exams.py | 62 ++ py_configuration_files/edx_notes_api.py | 34 ++ py_configuration_files/enterprise_access.py | 139 +++++ py_configuration_files/enterprise_catalog.py | 94 +++ py_configuration_files/enterprise_subsidy.py | 102 ++++ py_configuration_files/license_manager.py | 110 ++++ py_configuration_files/lms.py | 561 ++++++++++++++++++ py_configuration_files/portal_designer.py | 51 ++ .../program_intent_management.py | 51 ++ py_configuration_files/registrar.py | 84 +++ py_configuration_files/xqueue.py | 53 ++ repo.sh | 2 + 27 files changed, 2243 insertions(+), 3 deletions(-) create mode 100755 provision-enterprise_catalog.sh create mode 100644 py_configuration_files/analytics_data_api.py create mode 100644 py_configuration_files/anayltics_dashboard.py create mode 100644 py_configuration_files/cms.py create mode 100644 py_configuration_files/commerce_coordinator.py create mode 100644 py_configuration_files/course_discovery.py create mode 100644 py_configuration_files/ecommerce.py create mode 100644 py_configuration_files/edx_exams.py create mode 100644 py_configuration_files/edx_notes_api.py create mode 100644 py_configuration_files/enterprise_access.py create mode 100644 py_configuration_files/enterprise_catalog.py create mode 100644 py_configuration_files/enterprise_subsidy.py create mode 100644 py_configuration_files/license_manager.py create mode 100644 py_configuration_files/lms.py create mode 100644 py_configuration_files/portal_designer.py create mode 100644 py_configuration_files/program_intent_management.py create mode 100644 py_configuration_files/registrar.py create mode 100644 py_configuration_files/xqueue.py diff --git a/Makefile b/Makefile index aba37bc7e2..0ed89619dd 100644 --- a/Makefile +++ b/Makefile @@ -407,6 +407,9 @@ dev.shell.analyticsapi: dev.shell.insights: docker compose exec insights env TERM=$(TERM) bash -c 'eval $$(source /edx/app/insights/insights_env; echo PATH="$$PATH";) && /bin/bash' +dev.shell.enterprise-catalog: + docker exec -it edx.devstack.enterprise-catalog env TERM=$(TERM) bash -c '/bin/bash' + dev.shell.%: ## Run a shell on the specified service's container. docker compose exec $* /bin/bash diff --git a/docker-compose-host.yml b/docker-compose-host.yml index 5941bfbdc2..2fef47a909 100644 --- a/docker-compose-host.yml +++ b/docker-compose-host.yml @@ -12,12 +12,14 @@ services: - discovery_node_modules:/edx/app/discovery/discovery/node_modules - discovery_tox:/edx/app/discovery/discovery/.tox - ${DEVSTACK_WORKSPACE}/src:/edx/src + - ${PWD}/py_configuration_files/course_discovery.py:/edx/app/discovery/discovery/course_discovery/settings/devstack.py ecommerce: volumes: - ${DEVSTACK_WORKSPACE}/ecommerce:/edx/app/ecommerce/ecommerce - ecommerce_node_modules:/edx/app/ecommerce/ecommerce/node_modules - ecommerce_tox:/edx/app/ecommerce/ecommerce/.tox - ${DEVSTACK_WORKSPACE}/src:/edx/src + - ${PWD}/py_configuration_files/ecommerce.py:/edx/app/ecommerce/ecommerce/ecommerce/settings/devstack.py forum: volumes: - ${DEVSTACK_WORKSPACE}/cs_comments_service:/edx/app/forum/cs_comments_service @@ -29,6 +31,8 @@ services: - edxapp_tox:/edx/app/edxapp/edx-platform/.tox - edxapp_uploads:/edx/var/edxapp/uploads - ${DEVSTACK_WORKSPACE}/src:/edx/src + - ${PWD}/py_configuration_files/cms.py:/edx/app/edxapp/edx-platform/cms/envs/devstack.py + - ${PWD}/py_configuration_files/lms.py:/edx/app/edxapp/edx-platform/lms/envs/devstack.py lms-worker: volumes: - ${DEVSTACK_WORKSPACE}/edx-platform:/edx/app/edxapp/edx-platform @@ -36,9 +40,11 @@ services: volumes: - ${DEVSTACK_WORKSPACE}/edx-notes-api:/edx/app/notes/ - ${DEVSTACK_WORKSPACE}/src:/edx/src + - ${PWD}/py_configuration_files/edx_notes_api.py:/edx/app/notes/notesserver/settings/devstack.py registrar: volumes: - ${DEVSTACK_WORKSPACE}/registrar:/edx/app/registrar + - ${PWD}/py_configuration_files/registrar.py:/edx/app/registrar/registrar/registrar/settings/devstack.py registrar-worker: volumes: - ${DEVSTACK_WORKSPACE}/registrar:/edx/app/registrar @@ -50,6 +56,8 @@ services: - edxapp_tox:/edx/app/edxapp/edx-platform/.tox - edxapp_uploads:/edx/var/edxapp/uploads - ${DEVSTACK_WORKSPACE}/src:/edx/src + - ${PWD}/py_configuration_files/cms.py:/edx/app/edxapp/edx-platform/cms/envs/devstack.py + - ${PWD}/py_configuration_files/lms.py:/edx/app/edxapp/edx-platform/lms/envs/devstack.py cms-worker: volumes: - ${DEVSTACK_WORKSPACE}/edx-platform:/edx/app/edxapp/edx-platform @@ -57,11 +65,21 @@ services: volumes: - ${DEVSTACK_WORKSPACE}/edx-analytics-dashboard:/edx/app/insights/insights - insights_node_modules:/edx/app/insights/insights/node_modules + - ${PWD}/py_configuration_files/analytics_dashboard.py:/edx/app/insights/edx_analytics_dashboard/edx_analytics_dashboard/settings/devstack.py analyticsapi: volumes: - ${DEVSTACK_WORKSPACE}/edx-analytics-data-api:/edx/app/analytics_api/analytics_api - ${DEVSTACK_WORKSPACE}/src:/edx/src - + - ${PWD}/py_configuration_files/analytics_data_api.py:/edx/app/analytics_api/analytics_api/analyticsdataserver/settings/devstack.py + enterprise-catalog: + volumes: + - ${DEVSTACK_WORKSPACE}/enterprise-catalog:/edx/app/enterprise_catalog/enterprise_catalog + enterprise-catalog-worker: + volumes: + - ${DEVSTACK_WORKSPACE}/enterprise-catalog:/edx/app/enterprise_catalog/enterprise_catalog + enterprise-catalog-curations_worker: + volumes: + - ${DEVSTACK_WORKSPACE}/enterprise-catalog:/edx/app/enterprise_catalog/enterprise_catalog # Note that frontends mount `src` to /edx/app/src instead of /edx/src. # See ADR #5 for rationale. frontend-app-account: diff --git a/docker-compose.yml b/docker-compose.yml index a165a6bf22..44c56d51c8 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -693,6 +693,82 @@ services: aliases: - edx.devstack.xqueue_consumer + enterprise-catalog: + image: edxops/enterprise-catalog-dev + container_name: edx.devstack.enterprise-catalog + hostname: enterprise-catalog.devstack.edx + command: bash -c 'while true; do python /edx/app/enterprise_catalog/enterprise_catalog/manage.py runserver 0.0.0.0:18160; sleep 2; done' + ports: + - "18160:18160" + depends_on: + - memcached + - mysql80 + - enterprise-catalog-worker + networks: + default: + aliases: + - edx.devstack.enterprise-catalog + # Allows attachment to this container using 'docker attach '. + stdin_open: true + tty: true + environment: + CELERY_ALWAYS_EAGER: 'false' + CELERY_BROKER_TRANSPORT: redis + CELERY_BROKER_HOSTNAME: edx.devstack.redis:6379 + CELERY_BROKER_VHOST: 0 + CELERY_BROKER_PASSWORD: password + DJANGO_SETTINGS_MODULE: enterprise_catalog.settings.devstack + ENABLE_DJANGO_TOOLBAR: 1 + DB_HOST: edx.devstack.mysql80 + DB_NAME: enterprise_catalog + DB_PORT: 3306 + DB_USER: catalog001 + DB_PASSWORD: 'password' + + enterprise-catalog-worker: + image: edxops/enterprise-catalog-dev + command: bash -c 'cd /edx/app/enterprise_catalog/enterprise_catalog && celery -A enterprise_catalog worker -Q enterprise_catalog.default -l DEBUG' + container_name: edx.devstack.enterprise.catalog.worker + depends_on: + - mysql80 + environment: + CELERY_ALWAYS_EAGER: 'false' + CELERY_BROKER_TRANSPORT: redis + CELERY_BROKER_HOSTNAME: edx.devstack.redis:6379 + CELERY_BROKER_VHOST: 0 + CELERY_BROKER_PASSWORD: password + DJANGO_SETTINGS_MODULE: enterprise_catalog.settings.devstack + COLUMNS: 80 + hostname: worker.catalog.enterprise + ports: + - "18161:18161" + restart: always + # Allows attachment to this container using 'docker attach '. + stdin_open: true + tty: true + + enterprise-catalog-curations_worker: + image: edxops/enterprise-catalog-dev + command: bash -c 'cd /edx/app/enterprise_catalog/enterprise_catalog && celery -A enterprise_catalog worker -Q enterprise_catalog.curations -l DEBUG' + container_name: enterprise.catalog.curations + depends_on: + - mysql80 + environment: + CELERY_ALWAYS_EAGER: 'false' + CELERY_BROKER_TRANSPORT: redis + CELERY_BROKER_HOSTNAME: edx.devstack.redis:6379 + CELERY_BROKER_VHOST: 0 + CELERY_BROKER_PASSWORD: password + DJANGO_SETTINGS_MODULE: enterprise_catalog.settings.devstack + COLUMNS: 80 + hostname: curations.catalog.enterprise + ports: + - "18162:18162" + restart: always + # Allows attachment to this container using 'docker attach '. + stdin_open: true + tty: true + # ========================================================================== # edX Microfrontends # @@ -910,3 +986,4 @@ volumes: mysql57_data: mysql80_data: redis_data: + enterprise_catalog_mysql8: diff --git a/docs/service_list.rst b/docs/service_list.rst index 092b8028c6..fd750f117a 100644 --- a/docs/service_list.rst +++ b/docs/service_list.rst @@ -63,6 +63,8 @@ Instead of a service name or list, you can also run commands like ``make dev.pro +------------------------------------+-------------------------------------+----------------+--------------+ | `frontend-app-ora-grading`_ | http://localhost:1993 | MFE (React.js) | Extra | +------------------------------------+-------------------------------------+----------------+--------------+ +| `enterprise-catalog`_ | http://localhost:18160/ | Python/Django | Extra | ++------------------------------------+-------------------------------------+----------------+--------------+ Some common service combinations include: @@ -95,3 +97,4 @@ Some common service combinations include: .. _frontend-app-ora-grading: https://github.com/edx/frontend-app-ora-grading .. _insights: https://github.com/edx/edx-analytics-dashboard .. _analyticsapi: https://github.com/edx/edx-analytics-data-api +.. _enterprise-catalog: https://github.com/openedx/enterprise-catalog diff --git a/options.mk b/options.mk index 5a4d9b4e2c..ad7449435b 100644 --- a/options.mk +++ b/options.mk @@ -67,7 +67,7 @@ credentials+discovery+ecommerce+edx_notes_api+forum+frontend-app-authn+frontend- # Separated by plus signs. # Separated by plus signs. Listed in alphabetical order for clarity. EDX_SERVICES ?= \ -analyticsapi+credentials+cms+cms-worker+cms_watcher+discovery+ecommerce+edx_notes_api+forum+frontend-app-account+frontend-app-learner-dashboard+frontend-app-learner-record+frontend-app-profile+frontend-app-authn+frontend-app-course-authoring+frontend-app-gradebook+frontend-app-ora-grading+frontend-app-learning+frontend-app-library-authoring+frontend-app-payment+frontend-app-program-console+frontend-app-publisher+insights+lms+lms-worker+lms_watcher+registrar+registrar-worker+xqueue+xqueue_consumer +analyticsapi+credentials+cms+cms-worker+cms_watcher+discovery+ecommerce+edx_notes_api+forum+frontend-app-account+frontend-app-learner-dashboard+frontend-app-learner-record+frontend-app-profile+frontend-app-authn+frontend-app-course-authoring+frontend-app-gradebook+frontend-app-ora-grading+frontend-app-learning+frontend-app-library-authoring+frontend-app-payment+frontend-app-program-console+frontend-app-publisher+insights+lms+lms-worker+lms_watcher+registrar+registrar-worker+xqueue+xqueue_consumer+enterprise-catalog # Services with database migrations. # Should be a subset of $(EDX_SERVICES). diff --git a/provision-enterprise_catalog.sh b/provision-enterprise_catalog.sh new file mode 100755 index 0000000000..59dfb85984 --- /dev/null +++ b/provision-enterprise_catalog.sh @@ -0,0 +1,23 @@ +name="enterprise-catalog" +port="18160" + +docker compose up -d $name + +# Run migrations +echo -e "${GREEN}Running migrations for ${name}...${NC}" +docker exec -t enterprise.catalog.app bash -c "cd /edx/app/${name}/${name}/ && make migrate" + +# Create superuser +echo -e "${GREEN}Creating super-user for ${name}...${NC}" +docker exec -t enterprise.catalog.app bash -c "echo 'from django.contrib.auth import get_user_model; User = get_user_model(); User.objects.create_superuser(\"edx\", \"edx@example.com\", \"edx\") if not User.objects.filter(username=\"edx\").exists() else None' | python /edx/app/${name}/${name}/manage.py shell" + +# Provision IDA User in LMS +echo -e "${GREEN}Provisioning ${name}_worker in LMS...${NC}" +docker exec -t edx.devstack.lms bash -c "source /edx/app/edxapp/edxapp_env && python /edx/app/edxapp/edx-platform/manage.py lms --settings=devstack_docker manage_user ${name}_worker ${name}_worker@example.com --staff --superuser" + +# Create the DOT applications - one for single sign-on and one for backend service IDA-to-IDA authentication. +docker exec -t edx.devstack.lms bash -c "source /edx/app/edxapp/edxapp_env && python /edx/app/edxapp/edx-platform/manage.py lms --settings=devstack_docker create_dot_application --grant-type authorization-code --skip-authorization --redirect-uris 'http://localhost:${port}/complete/edx-oauth2/' --client-id '${name}-sso-key' --client-secret '${name}-sso-secret' --scopes 'user_id' ${name}-sso ${name}_worker" +docker exec -t edx.devstack.lms bash -c "source /edx/app/edxapp/edxapp_env && python /edx/app/edxapp/edx-platform/manage.py lms --settings=devstack_docker create_dot_application --grant-type client-credentials --client-id '${name}-backend-service-key' --client-secret '${name}-backend-service-secret' ${name}-backend-service ${name}_worker" + +# Restart enterprise.catalog app and worker containers +docker-compose restart app worker diff --git a/provision-mysql80.sql b/provision-mysql80.sql index 19b32e0ebd..be903f1d7f 100644 --- a/provision-mysql80.sql +++ b/provision-mysql80.sql @@ -6,6 +6,10 @@ CREATE DATABASE IF NOT EXISTS credentials; CREATE USER IF NOT EXISTS 'credentials001'@'%' IDENTIFIED BY 'password'; GRANT ALL ON credentials.* TO 'credentials001'@'%'; +CREATE DATABASE IF NOT EXISTS enterprise_catalog; +CREATE USER IF NOT EXISTS 'catalog001'@'%' IDENTIFIED BY 'password'; +GRANT ALL ON enterprise_catalog.* TO 'catalog001'@'%'; + CREATE DATABASE IF NOT EXISTS discovery; CREATE USER IF NOT EXISTS 'discov001'@'%' IDENTIFIED BY 'password'; GRANT ALL ON discovery.* TO 'discov001'@'%'; diff --git a/provision.sh b/provision.sh index cde27b6fcd..551349ed68 100755 --- a/provision.sh +++ b/provision.sh @@ -3,7 +3,7 @@ # This script will provision the services specified in the argument list, # or all services if no arguments are provided. # -# Non-existant services will be ignored. +# Non-existent services will be ignored. # Specifying services more than once will cause them to be provisioned more # than once. # @@ -49,6 +49,7 @@ xqueue \ coursegraph \ insights \ analyticsapi \ +enterprise-catalog \ " # What should we provision? diff --git a/provision.sql b/provision.sql index 0b672c9986..94c3fd48c0 100644 --- a/provision.sql +++ b/provision.sql @@ -33,5 +33,7 @@ GRANT ALL ON `reports`.* TO 'analytics001'@'%' IDENTIFIED BY 'password'; CREATE DATABASE IF NOT EXISTS `reports_v1`; GRANT ALL ON `reports_v1`.* TO 'analytics001'@'%' IDENTIFIED BY 'password'; +CREATE DATABASE IF NOT EXISTS `enterprise_catalog`; +GRANT ALL ON `enterprise_catalog`.* TO 'catalog001'@'%' IDENTIFIED BY 'password'; FLUSH PRIVILEGES; diff --git a/py_configuration_files/analytics_data_api.py b/py_configuration_files/analytics_data_api.py new file mode 100644 index 0000000000..9fd08cf8da --- /dev/null +++ b/py_configuration_files/analytics_data_api.py @@ -0,0 +1,55 @@ +"""Devstack settings.""" + +import os + +from analyticsdataserver.settings.local import * + +########## DATABASE CONFIGURATION +DATABASES = { + 'default': { + 'ENGINE': 'django.db.backends.mysql', + 'NAME': 'analytics-api', + 'USER': 'api001', + 'PASSWORD': 'password', + 'HOST': 'edx.devstack.mysql', + 'PORT': '3306', + }, + 'analytics_v1': { + 'ENGINE': 'django.db.backends.mysql', + 'NAME': 'reports_v1', + 'USER': 'api001', + 'PASSWORD': 'password', + 'HOST': 'edx.devstack.mysql', + 'PORT': '3306', + }, + 'analytics': { + 'ENGINE': 'django.db.backends.mysql', + 'NAME': 'reports', + 'USER': 'reports001', + 'PASSWORD': 'password', + 'HOST': 'edx.devstack.mysql', + 'PORT': '3306', + } +} + +ANALYTICS_DATABASE_V1 = 'analytics_v1' + +DB_OVERRIDES = dict( + USER=os.environ.get('DB_USER', DATABASES['default']['USER']), + PASSWORD=os.environ.get('DB_PASSWORD', DATABASES['default']['PASSWORD']), + HOST=os.environ.get('DB_HOST', DATABASES['default']['HOST']), + PORT=os.environ.get('DB_PORT', DATABASES['default']['PORT']), +) + +for override, value in DB_OVERRIDES.items(): + DATABASES['default'][override] = value + DATABASES['analytics'][override] = value + DATABASES['analytics_v1'][override] = value + +DATABASE_ROUTERS = ['analyticsdataserver.router.AnalyticsAPIRouter', 'analyticsdataserver.router.AnalyticsModelsRouter'] + +########## END DATABASE CONFIGURATION + +ALLOWED_HOSTS += ['edx.devstack.analyticsapi'] + +LMS_BASE_URL = "http://edx.devstack.lms:18000/" diff --git a/py_configuration_files/anayltics_dashboard.py b/py_configuration_files/anayltics_dashboard.py new file mode 100644 index 0000000000..6164f113dc --- /dev/null +++ b/py_configuration_files/anayltics_dashboard.py @@ -0,0 +1,47 @@ +"""django settings for development on devstack""" + +from analytics_dashboard.settings.dev import * + +DB_OVERRIDES = { + "PASSWORD": os.environ.get('DB_PASSWORD', DATABASES['default']['PASSWORD']), + "USER": os.environ.get('DB_USER', DATABASES['default']['USER']), + "NAME": os.environ.get('DB_NAME', DATABASES['default']['NAME']), + "HOST": os.environ.get('DB_HOST', DATABASES['default']['HOST']), + "PORT": os.environ.get('DB_PORT', DATABASES['default']['PORT']), +} + +for override, value in DB_OVERRIDES.items(): + DATABASES['default'][override] = value + +DATA_API_URL = os.environ.get("API_SERVER_URL", 'http://edx.devstack.analyticsapi:19001/api/v0') +DATA_API_V1_ENABLED = True +DATA_API_URL_V1 = os.environ.get("API_SERVER_URL", 'http://edx.devstack.analyticsapi:19001/api/v1') + +ENROLLMENT_AGE_AVAILABLE = True + +# Set these to the correct values for your OAuth2/OpenID Connect provider (e.g., devstack) +SOCIAL_AUTH_EDX_OAUTH2_KEY = os.environ.get('SOCIAL_AUTH_EDX_OAUTH2_KEY', 'insights-sso-key') +SOCIAL_AUTH_EDX_OAUTH2_SECRET = os.environ.get('SOCIAL_AUTH_EDX_OAUTH2_SECRET', 'insights-sso-secret') +SOCIAL_AUTH_EDX_OAUTH2_ISSUER = os.environ.get('SOCIAL_AUTH_EDX_OAUTH2_ISSUER', 'http://localhost:18000') +SOCIAL_AUTH_EDX_OAUTH2_URL_ROOT = os.environ.get('SOCIAL_AUTH_EDX_OAUTH2_URL_ROOT', 'http://edx.devstack.lms:18000') +SOCIAL_AUTH_EDX_OAUTH2_LOGOUT_URL = os.environ.get('SOCIAL_AUTH_EDX_OAUTH2_LOGOUT_URL', 'http://localhost:18000/logout') +SOCIAL_AUTH_EDX_OAUTH2_PUBLIC_URL_ROOT = os.environ.get( + 'SOCIAL_AUTH_EDX_OAUTH2_PUBLIC_URL_ROOT', 'http://localhost:18000', +) + +BACKEND_SERVICE_EDX_OAUTH2_KEY = os.environ.get('BACKEND_SERVICE_EDX_OAUTH2_KEY', 'insights-backend-service-key') +BACKEND_SERVICE_EDX_OAUTH2_SECRET = os.environ.get( + 'BACKEND_SERVICE_EDX_OAUTH2_SECRET', 'insights-backend-service-secret' +) +BACKEND_SERVICE_EDX_OAUTH2_PROVIDER_URL = os.environ.get( + 'BACKEND_SERVICE_EDX_OAUTH2_PROVIDER_URL', 'http://edx.devstack.lms:18000/oauth2', +) + +COURSE_API_URL = 'http://edx.devstack.lms:18000/api/courses/v1/' +GRADING_POLICY_API_URL = 'http://edx.devstack.lms:18000/api/grades/v1/' + +MODULE_PREVIEW_URL = 'http://edx.devstack.lms:18000/xblock' + +JWT_AUTH = { + 'JWT_AUTH_HEADER_PREFIX': 'JWT', +} diff --git a/py_configuration_files/cms.py b/py_configuration_files/cms.py new file mode 100644 index 0000000000..1200a61b06 --- /dev/null +++ b/py_configuration_files/cms.py @@ -0,0 +1,349 @@ +""" +Specific overrides to the base prod settings to make development easier. +""" + + +import logging +from os.path import abspath, dirname, join + +from .production import * # pylint: disable=wildcard-import, unused-wildcard-import + +# Don't use S3 in devstack, fall back to filesystem +del DEFAULT_FILE_STORAGE +COURSE_IMPORT_EXPORT_STORAGE = 'django.core.files.storage.FileSystemStorage' +USER_TASKS_ARTIFACT_STORAGE = COURSE_IMPORT_EXPORT_STORAGE + +DEBUG = True +USE_I18N = True +DEFAULT_TEMPLATE_ENGINE['OPTIONS']['debug'] = DEBUG +SITE_NAME = 'localhost:8001' +HTTPS = 'off' + +CMS_BASE = 'localhost:18010' +SESSION_COOKIE_NAME = 'studio_sessionid' + +################################ LOGGERS ###################################### + + +# Disable noisy loggers +for pkg_name in ['common.djangoapps.track.contexts', 'common.djangoapps.track.middleware']: + logging.getLogger(pkg_name).setLevel(logging.CRITICAL) + +# Docker does not support the syslog socket at /dev/log. Rely on the console. +LOGGING['handlers']['local'] = LOGGING['handlers']['tracking'] = { + 'class': 'logging.NullHandler', +} + +LOGGING['loggers']['tracking']['handlers'] = ['console'] + +################################ EMAIL ######################################## + +EMAIL_BACKEND = 'django.core.mail.backends.filebased.EmailBackend' +EMAIL_FILE_PATH = '/edx/src/ace_messages/' + +################################# LMS INTEGRATION ############################# + +LMS_BASE = 'localhost:18000' +LMS_ROOT_URL = f'http://{LMS_BASE}' +FEATURES['PREVIEW_LMS_BASE'] = "preview." + LMS_BASE + +FRONTEND_REGISTER_URL = LMS_ROOT_URL + '/register' + +################################## Video Pipeline Settings ######################### + +FEATURES['ENABLE_VIDEO_UPLOAD_PIPELINE'] = True + +########################### PIPELINE ################################# + +# Skip packaging and optimization in development +PIPELINE['PIPELINE_ENABLED'] = False +STATICFILES_STORAGE = 'openedx.core.storage.DevelopmentStorage' + +# Revert to the default set of finders as we don't want the production pipeline +STATICFILES_FINDERS = [ + 'openedx.core.djangoapps.theming.finders.ThemeFilesFinder', + 'django.contrib.staticfiles.finders.FileSystemFinder', + 'django.contrib.staticfiles.finders.AppDirectoriesFinder', +] + +# Load development webpack donfiguration +WEBPACK_CONFIG_PATH = 'webpack.dev.config.js' + +############################ PYFS XBLOCKS SERVICE ############################# +# Set configuration for Django pyfilesystem + +DJFS = { + 'type': 'osfs', + 'directory_root': 'cms/static/djpyfs', + 'url_root': '/static/djpyfs', +} + +################################# CELERY ###################################### + +# By default don't use a worker, execute tasks as if they were local functions +CELERY_ALWAYS_EAGER = True + +# When the celery task is eagerly, it is executed locally while sharing the +# thread and its request cache with the active Django Request. In that case, +# do not clear the cache. +CLEAR_REQUEST_CACHE_ON_TASK_COMPLETION = False + +################################ DEBUG TOOLBAR ################################ + +INSTALLED_APPS += ['debug_toolbar'] + +MIDDLEWARE.append('debug_toolbar.middleware.DebugToolbarMiddleware') +INTERNAL_IPS = ('127.0.0.1',) + +DEBUG_TOOLBAR_PANELS = ( + 'debug_toolbar.panels.versions.VersionsPanel', + 'debug_toolbar.panels.timer.TimerPanel', + 'debug_toolbar.panels.settings.SettingsPanel', + 'debug_toolbar.panels.headers.HeadersPanel', + 'debug_toolbar.panels.request.RequestPanel', + 'debug_toolbar.panels.sql.SQLPanel', + 'debug_toolbar.panels.signals.SignalsPanel', + 'debug_toolbar.panels.profiling.ProfilingPanel', + 'debug_toolbar.panels.history.HistoryPanel', +) + +DEBUG_TOOLBAR_CONFIG = { + # Profile panel is incompatible with wrapped views + # See https://github.com/jazzband/django-debug-toolbar/issues/792 + 'DISABLE_PANELS': ( + 'debug_toolbar.panels.profiling.ProfilingPanel', + ), + 'SHOW_TOOLBAR_CALLBACK': 'cms.envs.devstack.should_show_debug_toolbar', +} + + +def should_show_debug_toolbar(request): # lint-amnesty, pylint: disable=missing-function-docstring + # We always want the toolbar on devstack unless running tests from another Docker container + hostname = request.get_host() + if hostname.startswith('edx.devstack.studio:') or hostname.startswith('studio.devstack.edx:'): + return False + return True + + +################################ MILESTONES ################################ +FEATURES['MILESTONES_APP'] = True + +########################### ORGANIZATIONS ################################# +# Although production studio.edx.org disables `ORGANIZATIONS_AUTOCREATE`, +# we purposefully leave auto-creation enabled in Devstack Studio for developer +# convenience, allowing devs to create test courses for any organization +# without having to first manually create said organizations in the admin panel. +ORGANIZATIONS_AUTOCREATE = True + +################################ ENTRANCE EXAMS ################################ +FEATURES['ENTRANCE_EXAMS'] = True + +################################ COURSE LICENSES ################################ +FEATURES['LICENSING'] = True +# Needed to enable licensing on video blocks +XBLOCK_SETTINGS.update({'VideoBlock': {'licensing_enabled': True}}) + +################################ SEARCH INDEX ################################ +FEATURES['ENABLE_COURSEWARE_INDEX'] = True +FEATURES['ENABLE_LIBRARY_INDEX'] = False +SEARCH_ENGINE = "search.elastic.ElasticSearchEngine" + +ELASTIC_SEARCH_CONFIG = [ + { + 'use_ssl': False, + 'host': 'edx.devstack.elasticsearch710', + 'port': 9200 + } +] + +################################ COURSE DISCUSSIONS ########################### +FEATURES['ENABLE_DISCUSSION_SERVICE'] = True + +################################ CREDENTIALS ########################### +CREDENTIALS_SERVICE_USERNAME = 'credentials_worker' + +########################## Certificates Web/HTML View ####################### +FEATURES['CERTIFICATES_HTML_VIEW'] = True + +########################## AUTHOR PERMISSION ####################### +FEATURES['ENABLE_CREATOR_GROUP'] = True + +########################## Library creation organizations restriction ####################### +FEATURES['ENABLE_ORGANIZATION_STAFF_ACCESS_FOR_CONTENT_LIBRARIES'] = True + +################### FRONTEND APPLICATION PUBLISHER URL ################### +FEATURES['FRONTEND_APP_PUBLISHER_URL'] = 'http://localhost:18400' + +################### FRONTEND APPLICATION COURSE AUTHORING ################### +COURSE_AUTHORING_MICROFRONTEND_URL = 'http://localhost:2001' + +################### FRONTEND APPLICATION DISCUSSIONS ################### +DISCUSSIONS_MICROFRONTEND_URL = 'http://localhost:2002' + +################### FRONTEND APPLICATION DISCUSSIONS FEEDBACK URL################### +DISCUSSIONS_MFE_FEEDBACK_URL = None + +################################# DJANGO-REQUIRE ############################### + +# Whether to run django-require in debug mode. +REQUIRE_DEBUG = DEBUG + +########################### OAUTH2 ################################# +JWT_AUTH.update({ + 'JWT_ISSUER': f'{LMS_ROOT_URL}/oauth2', + 'JWT_ISSUERS': [{ + 'AUDIENCE': 'lms-key', + 'ISSUER': f'{LMS_ROOT_URL}/oauth2', + 'SECRET_KEY': 'lms-secret', + }], + 'JWT_SECRET_KEY': 'lms-secret', + 'JWT_AUDIENCE': 'lms-key', + 'JWT_PUBLIC_SIGNING_JWK_SET': ( + '{"keys": [{"kid": "devstack_key", "e": "AQAB", "kty": "RSA", "n": "smKFSYowG6nNUAdeqH1jQQnH1PmIHphzBmwJ5vRf1vu' + '48BUI5VcVtUWIPqzRK_LDSlZYh9D0YFL0ZTxIrlb6Tn3Xz7pYvpIAeYuQv3_H5p8tbz7Fb8r63c1828wXPITVTv8f7oxx5W3lFFgpFAyYMmROC' + '4Ee9qG5T38LFe8_oAuFCEntimWxN9F3P-FJQy43TL7wG54WodgiM0EgzkeLr5K6cDnyckWjTuZbWI-4ffcTgTZsL_Kq1owa_J2ngEfxMCObnzG' + 'y5ZLcTUomo4rZLjghVpq6KZxfS6I1Vz79ZsMVUWEdXOYePCKKsrQG20ogQEkmTf9FT_SouC6jPcHLXw"}]}' + ), +}) + +# pylint: enable=unicode-format-string # lint-amnesty, pylint: disable=bad-option-value + +IDA_LOGOUT_URI_LIST = [ + 'http://localhost:18130/logout/', # ecommerce + 'http://localhost:18150/logout/', # credentials +] + +ENTERPRISE_BACKEND_SERVICE_EDX_OAUTH2_PROVIDER_URL = "http://edx.devstack.lms/oauth2" + +##################################################################### + +# pylint: disable=wrong-import-order, wrong-import-position +from edx_django_utils.plugins import add_plugins +# pylint: disable=wrong-import-order, wrong-import-position +from openedx.core.djangoapps.plugins.constants import ProjectType, SettingsType + +add_plugins(__name__, ProjectType.CMS, SettingsType.DEVSTACK) + + +OPENAPI_CACHE_TIMEOUT = 0 + +##################################################################### +# set replica set of contentstore to none as we haven't setup any for cms in devstack +CONTENTSTORE['DOC_STORE_CONFIG']['replicaSet'] = None + +##################################################################### +# set replica sets of moduelstore to none as we haven't setup any for cms in devstack +for store in MODULESTORE['default']['OPTIONS']['stores']: + if 'DOC_STORE_CONFIG' in store and 'replicaSet' in store['DOC_STORE_CONFIG']: + store['DOC_STORE_CONFIG']['replicaSet'] = None + + +##################################################################### +# Lastly, run any migrations, if needed. +MODULESTORE = convert_module_store_setting_if_needed(MODULESTORE) + +# Dummy secret key for dev +SECRET_KEY = '85920908f28904ed733fe576320db18cabd7b6cd' + +############# CORS headers for cross-domain requests ################# +FEATURES['ENABLE_CORS_HEADERS'] = True +CORS_ALLOW_CREDENTIALS = True +CORS_ORIGIN_ALLOW_ALL = True + +################### Special Exams (Proctoring) and Prereqs ################### +FEATURES['ENABLE_SPECIAL_EXAMS'] = True +FEATURES['ENABLE_PREREQUISITE_COURSES'] = True + +# Used in edx-proctoring for ID generation in lieu of SECRET_KEY - dummy value +# (ref MST-637) +PROCTORING_USER_OBFUSCATION_KEY = '85920908f28904ed733fe576320db18cabd7b6cd' + +#################### Webpack Configuration Settings ############################## +WEBPACK_LOADER['DEFAULT']['TIMEOUT'] = 5 + +################ Using LMS SSO for login to Studio ################ +SOCIAL_AUTH_EDX_OAUTH2_KEY = 'studio-sso-key' +SOCIAL_AUTH_EDX_OAUTH2_SECRET = 'studio-sso-secret' # in stage, prod would be high-entropy secret +# routed internally server-to-server +SOCIAL_AUTH_EDX_OAUTH2_URL_ROOT = ENV_TOKENS.get('SOCIAL_AUTH_EDX_OAUTH2_URL_ROOT', 'http://edx.devstack.lms:18000') +SOCIAL_AUTH_EDX_OAUTH2_PUBLIC_URL_ROOT = 'http://localhost:18000' # used in browser redirect + +# Don't form the return redirect URL with HTTPS on devstack +SOCIAL_AUTH_REDIRECT_IS_HTTPS = False + +#################### Network configuration #################### +# Devstack is directly exposed to the caller +CLOSEST_CLIENT_IP_FROM_HEADERS = [] + +#################### Credentials Settings #################### +CREDENTIALS_INTERNAL_SERVICE_URL = 'http://edx.devstack.credentials:18150' +CREDENTIALS_PUBLIC_SERVICE_URL = 'http://localhost:18150' + +########################## ORA MFE APP ############################## +ORA_MICROFRONTEND_URL = 'http://localhost:1992' + +############################ AI_TRANSLATIONS ################################## +AI_TRANSLATIONS_API_URL = 'http://localhost:18760/api/v1' + +############################ CSRF ################################## + +# MFEs that will call this service in devstack +CSRF_TRUSTED_ORIGINS = [ + 'http://localhost:3001', # frontend-app-library-authoring + 'http://localhost:2001', # frontend-app-course-authoring + 'http://localhost:1992', # frontend-app-ora + 'http://localhost:1999', # frontend-app-authn +] + +#################### Event bus backend ######################## + +EVENT_BUS_PRODUCER = 'edx_event_bus_redis.create_producer' +EVENT_BUS_REDIS_CONNECTION_URL = 'redis://:password@edx.devstack.redis:6379/' +EVENT_BUS_TOPIC_PREFIX = 'dev' +EVENT_BUS_CONSUMER = 'edx_event_bus_redis.RedisEventConsumer' + +course_catalog_event_setting = EVENT_BUS_PRODUCER_CONFIG['org.openedx.content_authoring.course.catalog_info.changed.v1'] +course_catalog_event_setting['course-catalog-info-changed']['enabled'] = True + +xblock_published_event_setting = EVENT_BUS_PRODUCER_CONFIG['org.openedx.content_authoring.xblock.published.v1'] +xblock_published_event_setting['course-authoring-xblock-lifecycle']['enabled'] = True +xblock_deleted_event_setting = EVENT_BUS_PRODUCER_CONFIG['org.openedx.content_authoring.xblock.deleted.v1'] +xblock_deleted_event_setting['course-authoring-xblock-lifecycle']['enabled'] = True +xblock_duplicated_event_setting = EVENT_BUS_PRODUCER_CONFIG['org.openedx.content_authoring.xblock.duplicated.v1'] +xblock_duplicated_event_setting['course-authoring-xblock-lifecycle']['enabled'] = True + + +################# New settings must go ABOVE this line ################# +######################################################################## +# See if the developer has any local overrides. +if os.path.isfile(join(dirname(abspath(__file__)), 'private.py')): + from .private import * # pylint: disable=import-error,wildcard-import + +############## Authoring API drf-spectacular openapi settings ############## +# These fields override the spectacular settings default values. +# Any fields not included here will use the default values. +SPECTACULAR_SETTINGS = { + 'TITLE': 'Authoring API', + 'DESCRIPTION': f'''Experimental API to edit xblocks and course content. + \n\nDanger: Do not use on running courses! + \n\n - How to gain access: Please email the owners of this openedx service. + \n - How to use: This API uses oauth2 authentication with the + access token endpoint: `{LMS_ROOT_URL}/oauth2/access_token`. + Please see separately provided documentation. + \n - How to test: You must be logged in as course author for whatever course you want to test with. + You can use the [Swagger UI](https://{CMS_BASE}/authoring-api/ui/) to "Try out" the API with your test course. To do this, you must select the "Local" server. + \n - Public vs. Local servers: The "Public" server is where you can reach the API externally. The "Local" server is + for development with a local edx-platform version, and for use via the [Swagger UI](https://{CMS_BASE}/authoring-api/ui/). + \n - Swaggerfile: [Download link](https://{CMS_BASE}/authoring-api/schema/)''', + 'VERSION': '0.1.0', + 'SERVE_INCLUDE_SCHEMA': False, + # restrict spectacular to CMS API endpoints (cms/lib/spectacular.py): + 'PREPROCESSING_HOOKS': ['cms.lib.spectacular.cms_api_filter'], + # remove the default schema path prefix to replace it with server-specific base paths: + 'SCHEMA_PATH_PREFIX': '/api/contentstore', + 'SCHEMA_PATH_PREFIX_TRIM': '/api/contentstore', + 'SERVERS': [ + {'url': AUTHORING_API_URL, 'description': 'Public'}, + {'url': f'http://{CMS_BASE}/api/contentstore', 'description': 'Local'} + ], +} diff --git a/py_configuration_files/commerce_coordinator.py b/py_configuration_files/commerce_coordinator.py new file mode 100644 index 0000000000..290c47ec30 --- /dev/null +++ b/py_configuration_files/commerce_coordinator.py @@ -0,0 +1,75 @@ +from commerce_coordinator.settings.local import * + +# Use edx.devstack.mysql for database. +DATABASES = { + 'default': { + 'ENGINE': 'django.db.backends.mysql', + 'NAME': os.environ.get('DB_NAME', 'commerce_coordinator'), + 'USER': os.environ.get('DB_USER', 'root'), + 'PASSWORD': os.environ.get('DB_PASSWORD', ''), + 'HOST': os.environ.get('DB_HOST', '127.0.0.1'), + 'PORT': os.environ.get('DB_PORT', 3406), + 'ATOMIC_REQUESTS': False, + 'CONN_MAX_AGE': 60, + } +} + +# Wire internal OAuth2 URLs to use internal devstack networking. +OAUTH2_PROVIDER_URL = 'http://edx.devstack.lms:18000/oauth2' + +# OAuth2 variables specific to social-auth/SSO login use case. +SOCIAL_AUTH_EDX_OAUTH2_KEY = os.environ.get('SOCIAL_AUTH_EDX_OAUTH2_KEY', 'commerce_coordinator-sso-key') +SOCIAL_AUTH_EDX_OAUTH2_SECRET = os.environ.get('SOCIAL_AUTH_EDX_OAUTH2_SECRET', 'commerce_coordinator-sso-secret') +SOCIAL_AUTH_EDX_OAUTH2_ISSUER = os.environ.get('SOCIAL_AUTH_EDX_OAUTH2_ISSUER', 'http://localhost:18000') +SOCIAL_AUTH_EDX_OAUTH2_URL_ROOT = os.environ.get('SOCIAL_AUTH_EDX_OAUTH2_URL_ROOT', 'http://edx.devstack.lms:18000') +SOCIAL_AUTH_EDX_OAUTH2_LOGOUT_URL = os.environ.get('SOCIAL_AUTH_EDX_OAUTH2_LOGOUT_URL', 'http://localhost:18000/logout') +SOCIAL_AUTH_EDX_OAUTH2_PUBLIC_URL_ROOT = os.environ.get( + 'SOCIAL_AUTH_EDX_OAUTH2_PUBLIC_URL_ROOT', 'http://localhost:18000', +) + +# OAuth2 variables specific to backend service API calls. +BACKEND_SERVICE_EDX_OAUTH2_PROVIDER_URL = os.environ.get( + 'BACKEND_SERVICE_EDX_OAUTH2_PROVIDER_URL', + 'http://edx.devstack.lms:18000' +) + +BACKEND_SERVICE_EDX_OAUTH2_KEY = os.environ.get( + 'BACKEND_SERVICE_EDX_OAUTH2_KEY', + 'commerce_coordinator-backend-service-key' +) +BACKEND_SERVICE_EDX_OAUTH2_SECRET = os.environ.get( + 'BACKEND_SERVICE_EDX_OAUTH2_SECRET', + 'commerce_coordinator-backend-service-secret' +) + +JWT_AUTH.update({ + 'JWT_SECRET_KEY': 'lms-secret', + 'JWT_ISSUER': 'http://localhost:18000/oauth2', + 'JWT_AUDIENCE': None, + 'JWT_VERIFY_AUDIENCE': False, + 'JWT_PUBLIC_SIGNING_JWK_SET': ( + '{"keys": [{"kid": "devstack_key", "e": "AQAB", "kty": "RSA", "n": "smKFSYowG6nNUAdeqH1jQQnH1PmIHphzBmwJ5vRf1vu' + '48BUI5VcVtUWIPqzRK_LDSlZYh9D0YFL0ZTxIrlb6Tn3Xz7pYvpIAeYuQv3_H5p8tbz7Fb8r63c1828wXPITVTv8f7oxx5W3lFFgpFAyYMmROC' + '4Ee9qG5T38LFe8_oAuFCEntimWxN9F3P-FJQy43TL7wG54WodgiM0EgzkeLr5K6cDnyckWjTuZbWI-4ffcTgTZsL_Kq1owa_J2ngEfxMCObnzG' + 'y5ZLcTUomo4rZLjghVpq6KZxfS6I1Vz79ZsMVUWEdXOYePCKKsrQG20ogQEkmTf9FT_SouC6jPcHLXw"}]}' + ), + 'JWT_ISSUERS': [{ + 'AUDIENCE': 'lms-key', + 'ISSUER': 'http://localhost:18000/oauth2', + 'SECRET_KEY': 'lms-secret', + }], +}) + +# Use edx.devstack.redis for queue. +CELERY_BROKER_URL = "redis://:password@edx.devstack.redis:6379/0" + +# Application URLs in devstack. +ECOMMERCE_URL = "http://edx.devstack.ecommerce:18130" +TITAN_URL = os.environ.get('TITAN_URL_ROOT', 'http://titan_titan-app_1:3000') +ENTERPRISE_URL = 'http://edx.devstack.lms:18000' + +# Set legacy credentials to access edX services. +EDX_API_KEY = 'PUT_YOUR_API_KEY_HERE' # This is the actual API key in devstack. + +# Special timeout for fulfillment. +FULFILLMENT_TIMEOUT = 15 # Devstack is slow! diff --git a/py_configuration_files/course_discovery.py b/py_configuration_files/course_discovery.py new file mode 100644 index 0000000000..889850b911 --- /dev/null +++ b/py_configuration_files/course_discovery.py @@ -0,0 +1,99 @@ +# noinspection PyUnresolvedReferences +from course_discovery.settings._debug_toolbar import * # isort:skip + +from course_discovery.settings.production import * + +DEBUG = True + +# Docker does not support the syslog socket at /dev/log. Rely on the console. +LOGGING['handlers']['local'] = { + 'class': 'logging.NullHandler', +} + +# Determine which requests should render Django Debug Toolbar +INTERNAL_IPS = ('127.0.0.1',) + +CORS_ORIGIN_WHITELIST = ( + 'http://localhost:8734', # frontend-app-learner-portal-enterprise + 'http://localhost:1991', # frontend-app-admin-portal + 'http://localhost:18400', # frontend-app-publisher + 'http://localhost:18450', # frontend-app-support-tools + 'http://localhost:2000', # frontend-app-learning +) + +ELASTICSEARCH_DSL['default']['hosts'] = 'edx.devstack.elasticsearch710:9200' + +# Expand change threshold to something more forgiving, especially in local development scenarios where the count goes +# from 1->2 (100% change). +INDEX_SIZE_CHANGE_THRESHOLD = 1.01 # 101% + +SOCIAL_AUTH_REDIRECT_IS_HTTPS = False + +JWT_AUTH.update({ + 'JWT_SECRET_KEY': 'lms-secret', + 'JWT_ISSUER': 'http://localhost:18000/oauth2', + 'JWT_AUDIENCE': None, + 'JWT_VERIFY_AUDIENCE': False, + 'JWT_PUBLIC_SIGNING_JWK_SET': ( + '{"keys": [{"kid": "devstack_key", "e": "AQAB", "kty": "RSA", "n": "smKFSYowG6nNUAdeqH1jQQnH1PmIHphzBmwJ5vRf1vu' + '48BUI5VcVtUWIPqzRK_LDSlZYh9D0YFL0ZTxIrlb6Tn3Xz7pYvpIAeYuQv3_H5p8tbz7Fb8r63c1828wXPITVTv8f7oxx5W3lFFgpFAyYMmROC' + '4Ee9qG5T38LFe8_oAuFCEntimWxN9F3P-FJQy43TL7wG54WodgiM0EgzkeLr5K6cDnyckWjTuZbWI-4ffcTgTZsL_Kq1owa_J2ngEfxMCObnzG' + 'y5ZLcTUomo4rZLjghVpq6KZxfS6I1Vz79ZsMVUWEdXOYePCKKsrQG20ogQEkmTf9FT_SouC6jPcHLXw"}]}' + ), + 'JWT_ISSUERS': [{ + 'AUDIENCE': 'lms-key', + 'ISSUER': 'http://localhost:18000/oauth2', + 'SECRET_KEY': 'lms-secret', + }], +}) + +# MEDIA CONFIGURATION +# See: https://docs.djangoproject.com/en/dev/ref/settings/#media-url +MEDIA_ROOT = root('media') +# LOCAL_MEDIA_URL was added to support external services like edx-mktg retrieving +# static files in DEBUG and local Devstack +LOCAL_DISCOVERY_MEDIA_URL = '/media/' +MEDIA_URL = 'http://localhost:18381' + LOCAL_DISCOVERY_MEDIA_URL +# END MEDIA CONFIGURATION + +DEFAULT_PARTNER_ID = 1 + +# Allow live changes to JS and CSS +COMPRESS_OFFLINE = False +COMPRESS_ENABLED = False + +PARLER_LANGUAGES = { + 1: ( + {'code': LANGUAGE_CODE, }, + {'code': 'es', }, + ), + 'default': { + 'fallbacks': [PARLER_DEFAULT_LANGUAGE_CODE], + 'hide_untranslated': False, + } +} + +SOCIAL_AUTH_EDX_OAUTH2_ISSUER = "http://localhost:18000" +SOCIAL_AUTH_EDX_OAUTH2_URL_ROOT = "http://edx.devstack.lms:18000" +SOCIAL_AUTH_EDX_OAUTH2_PUBLIC_URL_ROOT = "http://localhost:18000" +SOCIAL_AUTH_EDX_OAUTH2_LOGOUT_URL = "http://localhost:18000/logout" + +BACKEND_SERVICE_EDX_OAUTH2_PROVIDER_URL = "http://edx.devstack.lms:18000/oauth2" + +ENABLE_PUBLISHER = True + +ORG_BASE_LOGO_URL = "http://discovery:18381/media/" + +CELERY_TASK_ALWAYS_EAGER = False + +EVENT_BUS_CONSUMER = 'edx_event_bus_redis.RedisEventConsumer' +EVENT_BUS_PRODUCER = 'edx_event_bus_redis.create_producer' +EVENT_BUS_REDIS_CONNECTION_URL = 'redis://:password@edx.devstack.redis:6379/' +EVENT_BUS_TOPIC_PREFIX = 'dev' + +##################################################################### +# Lastly, see if the developer has any local overrides. +if os.path.isfile(join(dirname(abspath(__file__)), 'private.py')): + from .private import * # pylint: disable=import-error + +DISCOVERY_BASE_URL = "http://edx.devstack.discovery:18381" diff --git a/py_configuration_files/ecommerce.py b/py_configuration_files/ecommerce.py new file mode 100644 index 0000000000..5ce82962b2 --- /dev/null +++ b/py_configuration_files/ecommerce.py @@ -0,0 +1,141 @@ +"""Devstack settings""" + + +from corsheaders.defaults import default_headers as corsheaders_default_headers + +from ecommerce.settings.production import * + +# noinspection PyUnresolvedReferences +from ecommerce.settings._debug_toolbar import * # isort:skip + +DEBUG = True +INTERNAL_IPS = ['127.0.0.1'] +ENABLE_AUTO_AUTH = True + +# The django server cannot handle https calls +PROTOCOL = 'http' + +# Docker does not support the syslog socket at /dev/log. Rely on the console. +LOGGING['handlers']['local'] = { + 'class': 'logging.NullHandler', +} + +SOCIAL_AUTH_REDIRECT_IS_HTTPS = False +SESSION_COOKIE_SECURE = False + +# Allow live changes to JS and CSS +COMPRESS_OFFLINE = False +COMPRESS_ENABLED = False + +BACKEND_SERVICE_EDX_OAUTH2_KEY = "ecommerce-backend-service-key" +BACKEND_SERVICE_EDX_OAUTH2_SECRET = "ecommerce-backend-service-secret" +BACKEND_SERVICE_EDX_OAUTH2_PROVIDER_URL = "http://edx.devstack.lms:18000/oauth2" + +JWT_AUTH.update({ + # Temporarily set JWT_DECODE_HANDLER until new devstack images are built + # with this updated connfiguration: https://github.com/openedx/configuration/pull/6921. + 'JWT_DECODE_HANDLER': 'edx_rest_framework_extensions.auth.jwt.decoder.jwt_decode_handler', + 'JWT_ISSUER': 'http://localhost:18000/oauth2', + 'JWT_ISSUERS': [{ + 'AUDIENCE': 'lms-key', + 'ISSUER': 'http://localhost:18000/oauth2', + 'SECRET_KEY': 'lms-secret', + }], + # Must match public signing key used in LMS. + 'JWT_PUBLIC_SIGNING_JWK_SET': ( + '{"keys": [{"kid": "devstack_key", "e": "AQAB", "kty": "RSA", "n": "smKFSYowG6nNUAdeqH1jQQnH1PmIHphzBmwJ5vRf1vu' + '48BUI5VcVtUWIPqzRK_LDSlZYh9D0YFL0ZTxIrlb6Tn3Xz7pYvpIAeYuQv3_H5p8tbz7Fb8r63c1828wXPITVTv8f7oxx5W3lFFgpFAyYMmROC' + '4Ee9qG5T38LFe8_oAuFCEntimWxN9F3P-FJQy43TL7wG54WodgiM0EgzkeLr5K6cDnyckWjTuZbWI-4ffcTgTZsL_Kq1owa_J2ngEfxMCObnzG' + 'y5ZLcTUomo4rZLjghVpq6KZxfS6I1Vz79ZsMVUWEdXOYePCKKsrQG20ogQEkmTf9FT_SouC6jPcHLXw"}]}' + ), +}) + +CORS_ORIGIN_WHITELIST = ( + 'http://localhost:1991', # Enterprise Admin Portal MFE + 'http://localhost:1996', + 'http://localhost:1997', # Account MFE + 'http://localhost:1998', + 'http://localhost:2000', # Learning MFE + 'http://localhost:8734', # Enterprise Learner Portal MFE +) +CORS_ALLOW_HEADERS = corsheaders_default_headers + ( + 'use-jwt-cookie', +) +CORS_ALLOW_CREDENTIALS = True + +PAYMENT_MICROFRONTEND_URL = 'http://localhost:1998' + +ECOMMERCE_MICROFRONTEND_URL = 'http://localhost:1996' + +ENTERPRISE_CATALOG_API_URL = urljoin(f"{ENTERPRISE_CATALOG_SERVICE_URL}/", 'api/v1/') + +ENTERPRISE_ANALYTICS_API_URL = 'http://edx.devstack.analyticsapi:19001' + +# PAYMENT PROCESSING +PAYMENT_PROCESSOR_CONFIG = { + 'edx': { + 'cybersource': { + 'merchant_id': 'edx_org', + 'transaction_key': '2iJRV1OoAiMxSsFRQfkmdeqYKzwV76R5AY7vs/zKCQf2Dy0gYsno6sEizavo9rz29kcq/s2F+nGP0DrNNwDXyAxI3FW77HY+0jAssnXwd8cW1Pt5aEBcQvnOQ4i9nbN2mr1XJ+MthRbNodz1FgLFuTiZenpjFq1DFmQwFi2u7V1ItQrmG19kvnpk1++mZ8Dx7s4GdN8jxdvesNGoKo7E05X6LZTHdUCP3rfq/1Nn4RDoPvxtv9UMe77yxtUF8LVJ8clAl4VyW+6uhmgfIWninfQiESR0HQ++cNJS1EXHjwNyuDEdEALKxAwgUu4DQpFbTD1bcRRm4VrnDr6MsA8NaA==', + 'soap_api_url': 'https://ics2wstest.ic3.com/commerce/1.x/transactionProcessor/CyberSourceTransaction_1.166.wsdl', + 'cancel_checkout_path': PAYMENT_PROCESSOR_CANCEL_PATH, + 'send_level_2_3_details': True, + 'flex_shared_secret_key_id': 'd2df1f49-dffa-4814-8da2-2751a62b79a6', + 'flex_shared_secret_key': 'c9QEORcKDT7u27zLtuy2S0T/HfKo8gl+JnCy6OHtm9Q=', + }, + 'cybersource-rest': { + 'merchant_id': 'edx_org', + 'transaction_key': '2iJRV1OoAiMxSsFRQfkmdeqYKzwV76R5AY7vs/zKCQf2Dy0gYsno6sEizavo9rz29kcq/s2F+nGP0DrNNwDXyAxI3FW77HY+0jAssnXwd8cW1Pt5aEBcQvnOQ4i9nbN2mr1XJ+MthRbNodz1FgLFuTiZenpjFq1DFmQwFi2u7V1ItQrmG19kvnpk1++mZ8Dx7s4GdN8jxdvesNGoKo7E05X6LZTHdUCP3rfq/1Nn4RDoPvxtv9UMe77yxtUF8LVJ8clAl4VyW+6uhmgfIWninfQiESR0HQ++cNJS1EXHjwNyuDEdEALKxAwgUu4DQpFbTD1bcRRm4VrnDr6MsA8NaA==', + 'soap_api_url': 'https://ics2wstest.ic3.com/commerce/1.x/transactionProcessor/CyberSourceTransaction_1.166.wsdl', + 'cancel_checkout_path': PAYMENT_PROCESSOR_CANCEL_PATH, + 'send_level_2_3_details': True, + 'flex_shared_secret_key_id': 'd2df1f49-dffa-4814-8da2-2751a62b79a6', + 'flex_shared_secret_key': 'c9QEORcKDT7u27zLtuy2S0T/HfKo8gl+JnCy6OHtm9Q=', + }, + 'paypal': { + 'mode': 'sandbox', + 'client_id': 'AVcS4ZWEk7IPqaJibex3bCR0_lykVQ2BHdGz6JWVik0PKWGTOQzWMBOHRppPwFXMCPUqRsoBUDSE-ro5', + 'client_secret': 'EHNgP4mXL5mI54DQI1-EgXo6y0BDUzj5x1_8gQD0dNWSWS6pcLqlmGq8f5En6oos0z2L37a_EJ27mJ_a', + 'cancel_checkout_path': PAYMENT_PROCESSOR_CANCEL_PATH, + 'error_path': PAYMENT_PROCESSOR_ERROR_PATH, + }, + 'stripe': { + 'api_version': '2022-08-01; server_side_confirmation_beta=v1', + 'enable_telemetry': None, + 'log_level': 'debug', + 'max_network_retries': 0, + 'proxy': None, + 'publishable_key': 'SET-ME-PLEASE', + 'secret_key': 'SET-ME-PLEASE', + 'webhook_endpoint_secret': 'SET-ME-PLEASE', + 'error_path': PAYMENT_PROCESSOR_ERROR_PATH, + 'cancel_checkout_path': PAYMENT_PROCESSOR_CANCEL_PATH, + 'receipt_url': PAYMENT_PROCESSOR_RECEIPT_PATH, + }, + 'android-iap': { + 'google_bundle_id': 'org.edx.mobile', + 'google_service_account_key_file': '' + }, + 'ios-iap': { + "apple_id": "", + 'ios_bundle_id': 'org.edx.mobile', + 'issuer_id': '', + 'key_id': '', + 'private_key': "" + } + }, +} +# END PAYMENT PROCESSING + +# Language cookie +LANGUAGE_COOKIE_NAME = 'openedx-language-preference' + +EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend' + +REST_FRAMEWORK['DEFAULT_RENDERER_CLASSES'] = REST_FRAMEWORK['DEFAULT_RENDERER_CLASSES'] + ('rest_framework.renderers.BrowsableAPIRenderer',) + +##################################################################### +# Lastly, see if the developer has any local overrides. +if os.path.isfile(join(dirname(abspath(__file__)), 'private.py')): + # noinspection PyUnresolvedReferences + from .private import * # pylint: disable=import-error diff --git a/py_configuration_files/edx_exams.py b/py_configuration_files/edx_exams.py new file mode 100644 index 0000000000..6a5e549b32 --- /dev/null +++ b/py_configuration_files/edx_exams.py @@ -0,0 +1,62 @@ +from edx_exams.settings.local import * + +DATABASES = { + 'default': { + 'ENGINE': 'django.db.backends.mysql', + 'NAME': os.environ.get('DB_NAME', 'edx_exams'), + 'USER': os.environ.get('DB_USER', 'root'), + 'PASSWORD': os.environ.get('DB_PASSWORD', ''), + 'HOST': os.environ.get('DB_HOST', 'edx_exams.db'), + 'PORT': os.environ.get('DB_PORT', 3306), + 'ATOMIC_REQUESTS': False, + 'CONN_MAX_AGE': 60, + } +} + +# Generic OAuth2 variables irrespective of SSO/backend service key types. +OAUTH2_PROVIDER_URL = 'http://edx.devstack.lms:18000/oauth2' + +# OAuth2 variables specific to social-auth/SSO login use case. +SOCIAL_AUTH_EDX_OAUTH2_KEY = os.environ.get('SOCIAL_AUTH_EDX_OAUTH2_KEY', 'edx_exams-sso-key') +SOCIAL_AUTH_EDX_OAUTH2_SECRET = os.environ.get('SOCIAL_AUTH_EDX_OAUTH2_SECRET', 'edx_exams-sso-secret') +SOCIAL_AUTH_EDX_OAUTH2_ISSUER = os.environ.get('SOCIAL_AUTH_EDX_OAUTH2_ISSUER', 'http://localhost:18000') +SOCIAL_AUTH_EDX_OAUTH2_URL_ROOT = os.environ.get('SOCIAL_AUTH_EDX_OAUTH2_URL_ROOT', 'http://edx.devstack.lms:18000') +SOCIAL_AUTH_EDX_OAUTH2_LOGOUT_URL = os.environ.get('SOCIAL_AUTH_EDX_OAUTH2_LOGOUT_URL', 'http://localhost:18000/logout') +SOCIAL_AUTH_EDX_OAUTH2_PUBLIC_URL_ROOT = os.environ.get( + 'SOCIAL_AUTH_EDX_OAUTH2_PUBLIC_URL_ROOT', 'http://localhost:18000', +) + +# OAuth2 variables specific to backend service API calls. +BACKEND_SERVICE_EDX_OAUTH2_KEY = os.environ.get('BACKEND_SERVICE_EDX_OAUTH2_KEY', 'edx_exams-backend-service-key') +BACKEND_SERVICE_EDX_OAUTH2_SECRET = os.environ.get( + 'BACKEND_SERVICE_EDX_OAUTH2_SECRET', + 'edx_exams-backend-service-secret' +) + +JWT_AUTH.update({ + 'JWT_SECRET_KEY': 'lms-secret', + 'JWT_ISSUER': 'http://localhost:18000/oauth2', + 'JWT_AUDIENCE': None, + 'JWT_VERIFY_AUDIENCE': False, + 'JWT_PUBLIC_SIGNING_JWK_SET': ( + '{"keys": [{"kid": "devstack_key", "e": "AQAB", "kty": "RSA", "n": "smKFSYowG6nNUAdeqH1jQQnH1PmIHphzBmwJ5vRf1vu' + '48BUI5VcVtUWIPqzRK_LDSlZYh9D0YFL0ZTxIrlb6Tn3Xz7pYvpIAeYuQv3_H5p8tbz7Fb8r63c1828wXPITVTv8f7oxx5W3lFFgpFAyYMmROC' + '4Ee9qG5T38LFe8_oAuFCEntimWxN9F3P-FJQy43TL7wG54WodgiM0EgzkeLr5K6cDnyckWjTuZbWI-4ffcTgTZsL_Kq1owa_J2ngEfxMCObnzG' + 'y5ZLcTUomo4rZLjghVpq6KZxfS6I1Vz79ZsMVUWEdXOYePCKKsrQG20ogQEkmTf9FT_SouC6jPcHLXw"}]}' + ), + 'JWT_ISSUERS': [{ + 'AUDIENCE': 'lms-key', + 'ISSUER': 'http://localhost:18000/oauth2', + 'SECRET_KEY': 'lms-secret', + }], +}) + +LMS_ROOT_URL = 'http://edx.devstack.lms:18000' + +# EVENT BUS + +EVENT_BUS_PRODUCER = 'edx_event_bus_kafka.create_producer' +EVENT_BUS_CONSUMER = 'edx_event_bus_kafka.KafkaEventConsumer' +EVENT_BUS_KAFKA_SCHEMA_REGISTRY_URL = 'http://edx.devstack.schema-registry:8081' +EVENT_BUS_KAFKA_BOOTSTRAP_SERVERS = 'edx.devstack.kafka:29092' +EVENT_BUS_TOPIC_PREFIX = 'dev' diff --git a/py_configuration_files/edx_notes_api.py b/py_configuration_files/edx_notes_api.py new file mode 100644 index 0000000000..39922fbf66 --- /dev/null +++ b/py_configuration_files/edx_notes_api.py @@ -0,0 +1,34 @@ +import os + +from notesserver.settings.logger import build_logging_config + +from .common import * # pylint: disable=wildcard-import + +DEBUG = True +LOG_SETTINGS_DEBUG = True +LOG_SETTINGS_DEV_ENV = True + +ALLOWED_HOSTS = ['*'] + +# These values are derived from provision-ida-user.sh in the edx/devstack repo. +CLIENT_ID = 'edx_notes_api-backend-service-key' +CLIENT_SECRET = 'edx_notes_api-backend-service-secret' + +ELASTICSEARCH_INDEX_NAMES = {'notesapi.v1.search_indexes.documents.note': 'notes_index'} +ELASTICSEARCH_DSL['default']['hosts'] = os.environ.get('ELASTICSEARCH_DSL', 'edx.devstack.elasticsearch7:9200') + +DATABASES = { + 'default': { + 'ENGINE': 'django.db.backends.mysql', + 'NAME': os.environ.get('DB_NAME', 'notes'), + 'USER': os.environ.get('DB_USER', 'notes001'), + 'PASSWORD': os.environ.get('DB_PASSWORD', 'password'), + 'HOST': os.environ.get('DB_HOST', 'edx.devstack.mysql'), + 'PORT': os.environ.get('DB_PORT', 3306), + 'CONN_MAX_AGE': 60, + } +} + +JWT_AUTH = {} + +LOGGING = build_logging_config() diff --git a/py_configuration_files/enterprise_access.py b/py_configuration_files/enterprise_access.py new file mode 100644 index 0000000000..c25415275e --- /dev/null +++ b/py_configuration_files/enterprise_access.py @@ -0,0 +1,139 @@ +from enterprise_access.settings.local import * + +DATABASES = { + 'default': { + 'ENGINE': 'django.db.backends.mysql', + 'NAME': os.environ.get('DB_NAME', 'enterprise_access'), + 'USER': os.environ.get('DB_USER', 'root'), + 'PASSWORD': os.environ.get('DB_PASSWORD', ''), + 'HOST': os.environ.get('DB_HOST', 'enterprise_access.mysql80'), + 'PORT': os.environ.get('DB_PORT', 3306), + 'ATOMIC_REQUESTS': False, + 'CONN_MAX_AGE': 60, + } +} + + +CACHES = { + 'default': { + 'BACKEND': 'django.core.cache.backends.memcached.PyMemcacheCache', + 'LOCATION': 'enterprise_access.memcache:11211', + } +} + + +# Generic OAuth2 variables irrespective of SSO/backend service key types. +OAUTH2_PROVIDER_URL = 'http://edx.devstack.lms:18000/oauth2' + +# OAuth2 variables specific to social-auth/SSO login use case. +SOCIAL_AUTH_EDX_OAUTH2_KEY = os.environ.get('SOCIAL_AUTH_EDX_OAUTH2_KEY', 'enterprise_access-sso-key') +SOCIAL_AUTH_EDX_OAUTH2_SECRET = os.environ.get('SOCIAL_AUTH_EDX_OAUTH2_SECRET', 'enterprise_access-sso-secret') +SOCIAL_AUTH_EDX_OAUTH2_ISSUER = os.environ.get('SOCIAL_AUTH_EDX_OAUTH2_ISSUER', 'http://localhost:18000') +SOCIAL_AUTH_EDX_OAUTH2_URL_ROOT = os.environ.get('SOCIAL_AUTH_EDX_OAUTH2_URL_ROOT', 'http://edx.devstack.lms:18000') +SOCIAL_AUTH_EDX_OAUTH2_LOGOUT_URL = os.environ.get('SOCIAL_AUTH_EDX_OAUTH2_LOGOUT_URL', 'http://localhost:18000/logout') +SOCIAL_AUTH_EDX_OAUTH2_PUBLIC_URL_ROOT = os.environ.get( + 'SOCIAL_AUTH_EDX_OAUTH2_PUBLIC_URL_ROOT', 'http://localhost:18000', +) + +# OAuth2 variables specific to backend service API calls. +BACKEND_SERVICE_EDX_OAUTH2_KEY = os.environ.get( + 'BACKEND_SERVICE_EDX_OAUTH2_KEY', 'enterprise_access-backend-service-key') +BACKEND_SERVICE_EDX_OAUTH2_SECRET = os.environ.get( + 'BACKEND_SERVICE_EDX_OAUTH2_SECRET', 'enterprise_access-backend-service-secret') + +JWT_AUTH.update({ + 'JWT_SECRET_KEY': 'lms-secret', + 'JWT_ISSUER': 'http://localhost:18000/oauth2', + 'JWT_AUDIENCE': None, + 'JWT_VERIFY_AUDIENCE': False, + 'JWT_PUBLIC_SIGNING_JWK_SET': ( + '{"keys": [{"kid": "devstack_key", "e": "AQAB", "kty": "RSA", "n": "smKFSYowG6nNUAdeqH1jQQnH1PmIHphzBmwJ5vRf1vu' + '48BUI5VcVtUWIPqzRK_LDSlZYh9D0YFL0ZTxIrlb6Tn3Xz7pYvpIAeYuQv3_H5p8tbz7Fb8r63c1828wXPITVTv8f7oxx5W3lFFgpFAyYMmROC' + '4Ee9qG5T38LFe8_oAuFCEntimWxN9F3P-FJQy43TL7wG54WodgiM0EgzkeLr5K6cDnyckWjTuZbWI-4ffcTgTZsL_Kq1owa_J2ngEfxMCObnzG' + 'y5ZLcTUomo4rZLjghVpq6KZxfS6I1Vz79ZsMVUWEdXOYePCKKsrQG20ogQEkmTf9FT_SouC6jPcHLXw"}]}' + ), + 'JWT_ISSUERS': [{ + 'AUDIENCE': 'lms-key', + 'ISSUER': 'http://localhost:18000/oauth2', + 'SECRET_KEY': 'lms-secret', + }], +}) + +# Install django-extensions for improved dev experiences +# https://github.com/django-extensions/django-extensions#using-it +INSTALLED_APPS += ( + 'django_extensions', + 'edx_event_bus_kafka', +) + +# BEGIN CELERY +CELERY_WORKER_HIJACK_ROOT_LOGGER = True +CELERY_TASK_ALWAYS_EAGER = ( + os.environ.get("CELERY_ALWAYS_EAGER", "false").lower() == "true" +) +# END CELERY + + +# CORS CONFIG +CORS_ORIGIN_WHITELIST = [ + 'http://localhost:1991', # frontend-app-admin-portal + 'http://localhost:8734', # frontend-app-learner-portal-enterprise + 'http://localhost:18450', # frontend-app-support-tools +] +# END CORS + +# CSRF CONFIG +CSRF_TRUSTED_ORIGINS = [ + 'http://localhost:1991', # frontend-app-admin-portal + 'http://localhost:8734', # frontend-app-learner-portal-enterprise + 'http://localhost:18450', # frontend-app-support-tools +] +# END CSRF CONFIG + +ECOMMERCE_URL = 'http://edx.devstack.ecommerce:18130' +LICENSE_MANAGER_URL = 'http://license-manager.app:18170' +LMS_URL = 'http://edx.devstack.lms:18000' +DISCOVERY_URL = 'http://edx.devstack.discovery:18381' +ENTERPRISE_LEARNER_PORTAL_URL = 'http://localhost:8734' +ENTERPRISE_ADMIN_PORTAL_URL = 'http://localhost:1991' +ENTERPRISE_CATALOG_URL = 'http://enterprise.catalog.app:18160' +ENTERPRISE_SUBSIDY_URL = 'http://enterprise-subsidy.app:18280' +ENTERPRISE_ACCESS_URL = 'http://localhost:18270' + +# shell_plus +SHELL_PLUS_IMPORTS = [ + 'from enterprise_access.apps.api.serializers import *', + 'from enterprise_access.apps.api_client import *', + 'from enterprise_access.utils import localized_utcnow', + 'from enterprise_access.apps.content_assignments import api as assignments_api', + 'from pprint import pprint', + 'from enterprise_access.apps.content_assignments import tasks as assignments_tasks', +] + + +################### Kafka Related Settings ############################## + +# "Standard" Kafka settings as defined in https://github.com/openedx/event-bus-kafka/tree/main +EVENT_BUS_KAFKA_SCHEMA_REGISTRY_URL = 'http://edx.devstack.schema-registry:8081' +EVENT_BUS_KAFKA_BOOTSTRAP_SERVERS = 'edx.devstack.kafka:29092' +EVENT_BUS_PRODUCER = 'edx_event_bus_kafka.create_producer' +EVENT_BUS_CONSUMER = 'edx_event_bus_kafka.KafkaEventConsumer' +EVENT_BUS_TOPIC_PREFIX = 'dev' + +# Potentially deprecated kafka settings +KAFKA_ENABLED = False +KAFKA_REPLICATION_FACTOR_PER_TOPIC = 1 +COUPON_CODE_REQUEST_TOPIC_NAME = "coupon-code-request-dev" +LICENSE_REQUEST_TOPIC_NAME = "license-request-dev" +ACCESS_POLICY_TOPIC_NAME = "access-policy-dev" +SUBSIDY_REDEMPTION_TOPIC_NAME = "subsidy-redemption-dev" +KAFKA_TOPICS = [ + COUPON_CODE_REQUEST_TOPIC_NAME, + LICENSE_REQUEST_TOPIC_NAME, + + # Access policy events + ACCESS_POLICY_TOPIC_NAME, + SUBSIDY_REDEMPTION_TOPIC_NAME, +] + +################### End Kafka Related Settings ############################## diff --git a/py_configuration_files/enterprise_catalog.py b/py_configuration_files/enterprise_catalog.py new file mode 100644 index 0000000000..6cc7cdeb1c --- /dev/null +++ b/py_configuration_files/enterprise_catalog.py @@ -0,0 +1,94 @@ +from enterprise_catalog.settings.local import * + +# Generic OAuth2 variables irrespective of SSO/backend service key types. +OAUTH2_PROVIDER_URL = 'http://edx.devstack.lms:18000/oauth2' + +# OAuth2 variables specific to social-auth/SSO login use case. +SOCIAL_AUTH_EDX_OAUTH2_KEY = os.environ.get('SOCIAL_AUTH_EDX_OAUTH2_KEY', 'enterprise_catalog-sso-key') +SOCIAL_AUTH_EDX_OAUTH2_SECRET = os.environ.get('SOCIAL_AUTH_EDX_OAUTH2_SECRET', 'enterprise_catalog-sso-secret') +SOCIAL_AUTH_EDX_OAUTH2_ISSUER = os.environ.get('SOCIAL_AUTH_EDX_OAUTH2_ISSUER', 'http://localhost:18000') +SOCIAL_AUTH_EDX_OAUTH2_URL_ROOT = os.environ.get('SOCIAL_AUTH_EDX_OAUTH2_URL_ROOT', 'http://edx.devstack.lms:18000') +SOCIAL_AUTH_EDX_OAUTH2_LOGOUT_URL = os.environ.get('SOCIAL_AUTH_EDX_OAUTH2_LOGOUT_URL', 'http://localhost:18000/logout') +SOCIAL_AUTH_EDX_OAUTH2_PUBLIC_URL_ROOT = os.environ.get( + 'SOCIAL_AUTH_EDX_OAUTH2_PUBLIC_URL_ROOT', 'http://localhost:18000', +) + +# OAuth2 variables specific to backend service API calls. +BACKEND_SERVICE_EDX_OAUTH2_KEY = os.environ.get('BACKEND_SERVICE_EDX_OAUTH2_KEY', 'enterprise_catalog-backend-service-key') +BACKEND_SERVICE_EDX_OAUTH2_SECRET = os.environ.get('BACKEND_SERVICE_EDX_OAUTH2_SECRET', 'enterprise_catalog-backend-service-secret') + +JWT_AUTH.update({ + 'JWT_SECRET_KEY': 'lms-secret', + 'JWT_ISSUER': 'http://localhost:18000/oauth2', + 'JWT_AUDIENCE': None, + 'JWT_VERIFY_AUDIENCE': False, + 'JWT_PUBLIC_SIGNING_JWK_SET': ( + '{"keys": [{"kid": "devstack_key", "e": "AQAB", "kty": "RSA", "n": "smKFSYowG6nNUAdeqH1jQQnH1PmIHphzBmwJ5vRf1vu' + '48BUI5VcVtUWIPqzRK_LDSlZYh9D0YFL0ZTxIrlb6Tn3Xz7pYvpIAeYuQv3_H5p8tbz7Fb8r63c1828wXPITVTv8f7oxx5W3lFFgpFAyYMmROC' + '4Ee9qG5T38LFe8_oAuFCEntimWxN9F3P-FJQy43TL7wG54WodgiM0EgzkeLr5K6cDnyckWjTuZbWI-4ffcTgTZsL_Kq1owa_J2ngEfxMCObnzG' + 'y5ZLcTUomo4rZLjghVpq6KZxfS6I1Vz79ZsMVUWEdXOYePCKKsrQG20ogQEkmTf9FT_SouC6jPcHLXw"}]}' + ), + 'JWT_ISSUERS': [{ + 'AUDIENCE': 'lms-key', + 'ISSUER': 'http://localhost:18000/oauth2', + 'SECRET_KEY': 'lms-secret', + }], +}) + +DATABASES = { + 'default': { + 'ENGINE': 'django.db.backends.mysql', + 'NAME': os.environ.get('DB_NAME', 'enterprise_catalog'), + 'USER': os.environ.get('DB_USER', 'root'), + 'PASSWORD': os.environ.get('DB_PASSWORD', ''), + 'HOST': os.environ.get('DB_HOST', 'enterprise.catalog.mysql'), + 'PORT': os.environ.get('DB_PORT', 3306), + 'ATOMIC_REQUESTS': False, + 'CONN_MAX_AGE': 60, + # The default isolation level for MySQL is REPEATABLE READ, which is a little too aggressive + # for our needs, particularly around reading celery task state via django-celery-results. + # https://dev.mysql.com/doc/refman/8.0/en/innodb-transaction-isolation-levels.html#isolevel_read-committed + 'OPTIONS': { + 'isolation_level': 'read committed', + }, + } +} + +ALLOWED_HOSTS = ['*'] + +LMS_BASE_URL = 'http://edx.devstack.lms:18000' +DISCOVERY_SERVICE_API_URL = 'http://edx.devstack.discovery:18381/api/v1/' +DISCOVERY_SERVICE_URL = 'http://edx.devstack.discovery:18381/' +ENTERPRISE_LEARNER_PORTAL_BASE_URL = 'http://localhost:8734' +ECOMMERCE_BASE_URL = 'http://edx.devstack.ecommerce:18130' +LICENSE_MANAGER_BASE_URL = 'http://license-manager.app:18170' +STUDIO_BASE_URL = 'http://edx.devstack.lms:18010' + +CELERY_WORKER_HIJACK_ROOT_LOGGER = True +CELERY_TASK_ALWAYS_EAGER = ( + os.environ.get("CELERY_ALWAYS_EAGER", "false").lower() == "true" +) + +CORS_ORIGIN_WHITELIST = [ + # Enterprise learner portal MFE + 'http://localhost:8734', + 'http://localhost:18160', + 'http://localhost:18000', + 'http://localhost:18130', + # Enterprise admin portal MFE + 'http://localhost:1991', + # Enterprise explore catalog MFE + 'http://localhost:8735', +] + +CACHES = { + 'default': { + 'BACKEND': 'django.core.cache.backends.memcached.PyMemcacheCache', + 'LOCATION': 'enterprise.catalog.memcached:11211', + } +} + +CHAT_COMPLETION_API = 'http://test.chat.ai' +CHAT_COMPLETION_API_KEY = 'test chat completion api key' +CHAT_COMPLETION_API_CONNECT_TIMEOUT = 1 +CHAT_COMPLETION_API_READ_TIMEOUT = 15 diff --git a/py_configuration_files/enterprise_subsidy.py b/py_configuration_files/enterprise_subsidy.py new file mode 100644 index 0000000000..42ad121992 --- /dev/null +++ b/py_configuration_files/enterprise_subsidy.py @@ -0,0 +1,102 @@ +from enterprise_subsidy.settings.local import * + +CORS_ORIGIN_WHITELIST = ( + 'http://localhost:18450', # frontend-app-support-tools + 'http://localhost:8734', # frontend-app-learner-portal-enterprise + 'http://localhost:1991', # frontend-app-admin-portal +) + +CSRF_TRUSTED_ORIGINS = [ + 'http://localhost:18450', + 'http://localhost:8734', + 'http://localhost:1991', +] + +DATABASES = { + 'default': { + 'ENGINE': 'django.db.backends.mysql', + 'NAME': os.environ.get('DB_NAME', 'enterprise_subsidy'), + 'USER': os.environ.get('DB_USER', 'root'), + 'PASSWORD': os.environ.get('DB_PASSWORD', ''), + 'HOST': os.environ.get('DB_HOST', 'enterprise-subsidy.mysql80'), + 'PORT': os.environ.get('DB_PORT', 3306), + 'ATOMIC_REQUESTS': False, + 'CONN_MAX_AGE': 60, + } +} + +CACHES = { + 'default': { + 'BACKEND': 'django.core.cache.backends.memcached.PyMemcacheCache', + 'LOCATION': 'enterprise-subsidy.memcache:11211', + } + +} + +INSTALLED_APPS += ( + 'edx_event_bus_kafka', +) + +# Generic OAuth2 variables irrespective of SSO/backend service key types. +OAUTH2_PROVIDER_URL = 'http://edx.devstack.lms:18000/oauth2' + +# OAuth2 variables specific to social-auth/SSO login use case. +SOCIAL_AUTH_EDX_OAUTH2_KEY = os.environ.get('SOCIAL_AUTH_EDX_OAUTH2_KEY', 'enterprise-subsidy-sso-key') +SOCIAL_AUTH_EDX_OAUTH2_SECRET = os.environ.get('SOCIAL_AUTH_EDX_OAUTH2_SECRET', 'enterprise-subsidy-sso-secret') +SOCIAL_AUTH_EDX_OAUTH2_ISSUER = os.environ.get('SOCIAL_AUTH_EDX_OAUTH2_ISSUER', 'http://localhost:18000') +SOCIAL_AUTH_EDX_OAUTH2_URL_ROOT = os.environ.get('SOCIAL_AUTH_EDX_OAUTH2_URL_ROOT', 'http://edx.devstack.lms:18000') +SOCIAL_AUTH_EDX_OAUTH2_LOGOUT_URL = os.environ.get('SOCIAL_AUTH_EDX_OAUTH2_LOGOUT_URL', 'http://localhost:18000/logout') +SOCIAL_AUTH_EDX_OAUTH2_PUBLIC_URL_ROOT = os.environ.get( + 'SOCIAL_AUTH_EDX_OAUTH2_PUBLIC_URL_ROOT', 'http://localhost:18000', +) + +# OAuth2 variables specific to backend service API calls. +BACKEND_SERVICE_EDX_OAUTH2_KEY = os.environ.get( + 'BACKEND_SERVICE_EDX_OAUTH2_KEY', 'enterprise-subsidy-backend-service-key' +) +BACKEND_SERVICE_EDX_OAUTH2_SECRET = os.environ.get( + 'BACKEND_SERVICE_EDX_OAUTH2_SECRET', 'enterprise-subsidy-backend-service-secret' +) + +JWT_AUTH.update({ + 'JWT_SECRET_KEY': 'lms-secret', + 'JWT_ISSUER': 'http://localhost:18000/oauth2', + 'JWT_AUDIENCE': None, + 'JWT_VERIFY_AUDIENCE': False, + 'JWT_PUBLIC_SIGNING_JWK_SET': ( + '{"keys": [{"kid": "devstack_key", "e": "AQAB", "kty": "RSA", "n": "smKFSYowG6nNUAdeqH1jQQnH1PmIHphzBmwJ5vRf1vu' + '48BUI5VcVtUWIPqzRK_LDSlZYh9D0YFL0ZTxIrlb6Tn3Xz7pYvpIAeYuQv3_H5p8tbz7Fb8r63c1828wXPITVTv8f7oxx5W3lFFgpFAyYMmROC' + '4Ee9qG5T38LFe8_oAuFCEntimWxN9F3P-FJQy43TL7wG54WodgiM0EgzkeLr5K6cDnyckWjTuZbWI-4ffcTgTZsL_Kq1owa_J2ngEfxMCObnzG' + 'y5ZLcTUomo4rZLjghVpq6KZxfS6I1Vz79ZsMVUWEdXOYePCKKsrQG20ogQEkmTf9FT_SouC6jPcHLXw"}]}' + ), + 'JWT_ISSUERS': [{ + 'AUDIENCE': 'lms-key', + 'ISSUER': 'http://localhost:18000/oauth2', + 'SECRET_KEY': 'lms-secret', + }], +}) + +LMS_URL = 'http://edx.devstack.lms:18000' +ENTERPRISE_CATALOG_URL = 'http://enterprise.catalog.app:18160' +ENTERPRISE_SUBSIDY_URL = 'http://localhost:18280' +FRONTEND_APP_LEARNING_URL = 'http://localhost:2000' + +# Kafka Settings +# "Standard" Kafka settings as defined in https://github.com/openedx/event-bus-kafka/tree/main +EVENT_BUS_KAFKA_SCHEMA_REGISTRY_URL = 'http://edx.devstack.schema-registry:8081' +EVENT_BUS_KAFKA_BOOTSTRAP_SERVERS = 'edx.devstack.kafka:29092' +EVENT_BUS_PRODUCER = 'edx_event_bus_kafka.create_producer' +EVENT_BUS_CONSUMER = 'edx_event_bus_kafka.KafkaEventConsumer' +EVENT_BUS_TOPIC_PREFIX = 'dev' + +EVENT_BUS_PRODUCER_CONFIG[TRANSACTION_CREATED_EVENT_NAME][TRANSACTION_LIFECYCLE_TOPIC]['enabled'] = True +EVENT_BUS_PRODUCER_CONFIG[TRANSACTION_COMMITTED_EVENT_NAME][TRANSACTION_LIFECYCLE_TOPIC]['enabled'] = True +EVENT_BUS_PRODUCER_CONFIG[TRANSACTION_FAILED_EVENT_NAME][TRANSACTION_LIFECYCLE_TOPIC]['enabled'] = True +EVENT_BUS_PRODUCER_CONFIG[TRANSACTION_REVERSED_EVENT_NAME][TRANSACTION_LIFECYCLE_TOPIC]['enabled'] = True + +# Private settings +# The local.py settings file also does this, but then this current file (devstack.py) +# imports *from* local.py, so anything earlier in this file overrides what's in private.py +# We want private.py to have the highest precedence, so re-import private settings again here. +if os.path.isfile(join(dirname(abspath(__file__)), 'private.py')): + from .private import * # pylint: disable=import-error diff --git a/py_configuration_files/license_manager.py b/py_configuration_files/license_manager.py new file mode 100644 index 0000000000..468e623f87 --- /dev/null +++ b/py_configuration_files/license_manager.py @@ -0,0 +1,110 @@ +from license_manager.settings.local import * + +# Generic OAuth2 variables irrespective of SSO/backend service key types. +OAUTH2_PROVIDER_URL = 'http://edx.devstack.lms:18000/oauth2' +ALLOWED_HOSTS = ['*'] +# API GATEWAY Settings +API_GATEWAY_URL = 'api.gateway.url' + +DATABASES = { + 'default': { + 'ENGINE': 'django.db.backends.mysql', + 'NAME': 'license_manager', + 'USER': 'root', + 'PASSWORD': '', + 'HOST': 'license-manager.mysql', + 'PORT': '3306', + } +} + +# OAuth2 variables specific to social-auth/SSO login use case. +SOCIAL_AUTH_EDX_OAUTH2_KEY = os.environ.get('SOCIAL_AUTH_EDX_OAUTH2_KEY', 'license_manager-sso-key') +SOCIAL_AUTH_EDX_OAUTH2_SECRET = os.environ.get('SOCIAL_AUTH_EDX_OAUTH2_SECRET', 'license_manager-sso-secret') +SOCIAL_AUTH_EDX_OAUTH2_ISSUER = os.environ.get('SOCIAL_AUTH_EDX_OAUTH2_ISSUER', 'http://localhost:18000') +SOCIAL_AUTH_EDX_OAUTH2_URL_ROOT = os.environ.get('SOCIAL_AUTH_EDX_OAUTH2_URL_ROOT', 'http://edx.devstack.lms:18000') +SOCIAL_AUTH_EDX_OAUTH2_LOGOUT_URL = os.environ.get('SOCIAL_AUTH_EDX_OAUTH2_LOGOUT_URL', 'http://localhost:18000/logout') +SOCIAL_AUTH_EDX_OAUTH2_PUBLIC_URL_ROOT = os.environ.get( + 'SOCIAL_AUTH_EDX_OAUTH2_PUBLIC_URL_ROOT', 'http://localhost:18000', +) + +# OAuth2 variables specific to backend service API calls. +BACKEND_SERVICE_EDX_OAUTH2_KEY = os.environ.get('BACKEND_SERVICE_EDX_OAUTH2_KEY', 'license_manager-backend-service-key') +BACKEND_SERVICE_EDX_OAUTH2_SECRET = os.environ.get('BACKEND_SERVICE_EDX_OAUTH2_SECRET', 'license_manager-backend-service-secret') + +JWT_AUTH.update({ + 'JWT_SECRET_KEY': 'lms-secret', + 'JWT_ISSUER': 'http://localhost:18000/oauth2', + 'JWT_AUDIENCE': None, + 'JWT_VERIFY_AUDIENCE': False, + 'JWT_PUBLIC_SIGNING_JWK_SET': ( + '{"keys": [{"kid": "devstack_key", "e": "AQAB", "kty": "RSA", "n": "smKFSYowG6nNUAdeqH1jQQnH1PmIHphzBmwJ5vRf1vu' + '48BUI5VcVtUWIPqzRK_LDSlZYh9D0YFL0ZTxIrlb6Tn3Xz7pYvpIAeYuQv3_H5p8tbz7Fb8r63c1828wXPITVTv8f7oxx5W3lFFgpFAyYMmROC' + '4Ee9qG5T38LFe8_oAuFCEntimWxN9F3P-FJQy43TL7wG54WodgiM0EgzkeLr5K6cDnyckWjTuZbWI-4ffcTgTZsL_Kq1owa_J2ngEfxMCObnzG' + 'y5ZLcTUomo4rZLjghVpq6KZxfS6I1Vz79ZsMVUWEdXOYePCKKsrQG20ogQEkmTf9FT_SouC6jPcHLXw"}]}' + ), + 'JWT_ISSUERS': [{ + 'AUDIENCE': 'lms-key', + 'ISSUER': 'http://localhost:18000/oauth2', + 'SECRET_KEY': 'lms-secret', + }], +}) + + +# BEGIN CELERY +CELERY_WORKER_HIJACK_ROOT_LOGGER = True +CELERY_TASK_ALWAYS_EAGER = ( + os.environ.get("CELERY_ALWAYS_EAGER", "false").lower() == "true" +) +# END CELERY + +# CORS CONFIG +CORS_ORIGIN_WHITELIST = [ + 'http://localhost:1991', # frontend-admin-portal + 'http://localhost:8734', # frontend-app-learner-portal-enterprise + 'http://localhost:18450', # frontend-app-support-tools +] +# END CORS + +# CSRF CONFIG +CSRF_TRUSTED_ORIGINS = [ + 'http://localhost:1991', # frontend-app-admin-portal + 'http://localhost:8734', # frontend-app-learner-portal-enterprise + 'http://localhost:18450', # frontend-app-support-tools +] +# END CSRF CONFIG + +ENTERPRISE_LEARNER_PORTAL_BASE_URL = 'http://localhost:8734' +ENTERPRISE_CATALOG_URL = 'http://enterprise.catalog.app:18160' +LMS_URL = 'http://edx.devstack.lms:18000' +SUPPORT_SITE_URL = 'https://support.edx.org' + +# URLs used for email footers +MOBILE_STORE_URLS = { + 'apple': 'https://itunes.apple.com/us/app/edx/id945480667?mt=8', + 'google': 'https://play.google.com/store/apps/details?id=org.edx.mobile', +} +SOCIAL_MEDIA_FOOTER_URLS = { + 'facebook': 'http://www.facebook.com/EdxOnline', + 'instagram': 'https://www.instagram.com/edxonline/', + 'linkedin': 'http://www.linkedin.com/company/edx', + 'meetup': 'http://www.meetup.com/edX-Global-Community', + 'reddit': 'http://www.reddit.com/r/edx', + 'tumblr': 'http://edxstories.tumblr.com/', + 'twitter': 'https://twitter.com/edXOnline', + 'youtube': 'https://www.youtube.com/user/edxonline', +} + +# Django Admin Settings +VALIDATE_FORM_EXTERNAL_FIELDS = False + +# Feature Toggles + +# Install django-extensions for improved dev experiences +# https://github.com/django-extensions/django-extensions#using-it +INSTALLED_APPS += ('django_extensions',) + +# Make some loggers less noisy (useful during test failure) +import logging + +for logger_to_silence in ['faker', 'jwkest', 'edx_rest_framework_extensions']: + logging.getLogger(logger_to_silence).setLevel(logging.WARNING) diff --git a/py_configuration_files/lms.py b/py_configuration_files/lms.py new file mode 100644 index 0000000000..01100e9240 --- /dev/null +++ b/py_configuration_files/lms.py @@ -0,0 +1,561 @@ +""" +Specific overrides to the base prod settings to make development easier. +""" + + +# Silence noisy logs +import logging +from os.path import abspath, dirname, join + +# pylint: enable=unicode-format-string # lint-amnesty, pylint: disable=bad-option-value +##################################################################### +from edx_django_utils.plugins import add_plugins + +from openedx.core.djangoapps.plugins.constants import ProjectType, SettingsType + +from .production import * # pylint: disable=wildcard-import, unused-wildcard-import + +# Don't use S3 in devstack, fall back to filesystem +del DEFAULT_FILE_STORAGE +ORA2_FILEUPLOAD_BACKEND = 'django' + + +DEBUG = True +USE_I18N = True +DEFAULT_TEMPLATE_ENGINE['OPTIONS']['debug'] = True +LMS_BASE = 'localhost:18000' +CMS_BASE = 'localhost:18010' +SITE_NAME = LMS_BASE + +SESSION_COOKIE_NAME = 'lms_sessionid' + +# By default don't use a worker, execute tasks as if they were local functions +CELERY_ALWAYS_EAGER = True +# When the celery task is run eagerly, it is executed locally while sharing the +# thread and its request cache with the active Django Request. In that case, +# do not clear the cache. +CLEAR_REQUEST_CACHE_ON_TASK_COMPLETION = False +HTTPS = 'off' + +LMS_ROOT_URL = f'http://{LMS_BASE}' +LMS_INTERNAL_ROOT_URL = LMS_ROOT_URL +ENTERPRISE_API_URL = f'{LMS_INTERNAL_ROOT_URL}/enterprise/api/v1/' +IDA_LOGOUT_URI_LIST = [ + 'http://localhost:18130/logout/', # ecommerce + 'http://localhost:18150/logout/', # credentials + 'http://localhost:18381/logout/', # discovery + 'http://localhost:18010/logout/', # studio +] + +################################ LOGGERS ###################################### + +LOG_OVERRIDES = [ + ('common.djangoapps.track.contexts', logging.CRITICAL), + ('common.djangoapps.track.middleware', logging.CRITICAL), + ('lms.djangoapps.discussion.django_comment_client.utils', logging.CRITICAL), +] +for log_name, log_level in LOG_OVERRIDES: + logging.getLogger(log_name).setLevel(log_level) + +# Docker does not support the syslog socket at /dev/log. Rely on the console. +LOGGING['handlers']['local'] = LOGGING['handlers']['tracking'] = { + 'class': 'logging.NullHandler', +} + +LOGGING['loggers']['tracking']['handlers'] = ['console'] + +################################ EMAIL ######################################## + +EMAIL_BACKEND = 'django.core.mail.backends.filebased.EmailBackend' +EMAIL_FILE_PATH = '/edx/src/ace_messages/' + +############################ PYFS XBLOCKS SERVICE ############################# +# Set configuration for Django pyfilesystem + +DJFS = { + 'type': 'osfs', + 'directory_root': 'lms/static/djpyfs', + 'url_root': '/static/djpyfs', +} + +################################ DEBUG TOOLBAR ################################ + +INSTALLED_APPS += ['debug_toolbar'] +MIDDLEWARE += [ + 'lms.djangoapps.discussion.django_comment_client.utils.QueryCountDebugMiddleware', + 'debug_toolbar.middleware.DebugToolbarMiddleware', +] + +INTERNAL_IPS = ('127.0.0.1',) + +DEBUG_TOOLBAR_PANELS = ( + 'debug_toolbar.panels.versions.VersionsPanel', + 'debug_toolbar.panels.timer.TimerPanel', + 'debug_toolbar.panels.settings.SettingsPanel', + 'debug_toolbar.panels.headers.HeadersPanel', + 'debug_toolbar.panels.request.RequestPanel', + 'debug_toolbar.panels.sql.SQLPanel', + 'debug_toolbar.panels.signals.SignalsPanel', + 'debug_toolbar.panels.history.HistoryPanel', + # ProfilingPanel has been intentionally removed for default devstack.py + # runtimes for performance reasons. If you wish to re-enable it in your + # local development environment, please create a new settings file + # that imports and extends devstack.py. +) + +DEBUG_TOOLBAR_CONFIG = { + 'SHOW_TOOLBAR_CALLBACK': 'lms.envs.devstack.should_show_debug_toolbar', +} + + +def should_show_debug_toolbar(request): # lint-amnesty, pylint: disable=missing-function-docstring + # We always want the toolbar on devstack unless running tests from another Docker container + hostname = request.get_host() + if hostname.startswith('edx.devstack.lms:') or hostname.startswith('lms.devstack.edx:'): + return False + return True + +########################### PIPELINE ################################# + +PIPELINE['PIPELINE_ENABLED'] = False +STATICFILES_STORAGE = 'openedx.core.storage.DevelopmentStorage' + +# Revert to the default set of finders as we don't want the production pipeline +STATICFILES_FINDERS = [ + 'openedx.core.djangoapps.theming.finders.ThemeFilesFinder', + 'django.contrib.staticfiles.finders.FileSystemFinder', + 'django.contrib.staticfiles.finders.AppDirectoriesFinder', +] + +# Disable JavaScript compression in development +PIPELINE['JS_COMPRESSOR'] = None + +# Whether to run django-require in debug mode. +REQUIRE_DEBUG = DEBUG + +PIPELINE['SASS_ARGUMENTS'] = '--debug-info' + +# Load development webpack configuration +WEBPACK_CONFIG_PATH = 'webpack.dev.config.js' + +########################### VERIFIED CERTIFICATES ################################# + +FEATURES['AUTOMATIC_VERIFY_STUDENT_IDENTITY_FOR_TESTING'] = True + +########################### External REST APIs ################################# +FEATURES['ENABLE_OAUTH2_PROVIDER'] = True +FEATURES['ENABLE_MOBILE_REST_API'] = True +FEATURES['ENABLE_VIDEO_ABSTRACTION_LAYER_API'] = True + +########################## SECURITY ####################### +FEATURES['ENABLE_MAX_FAILED_LOGIN_ATTEMPTS'] = False +FEATURES['SQUELCH_PII_IN_LOGS'] = False +FEATURES['PREVENT_CONCURRENT_LOGINS'] = False + +########################### Milestones ################################# +FEATURES['MILESTONES_APP'] = True + +########################### Entrance Exams ################################# +FEATURES['ENTRANCE_EXAMS'] = True + +################################ COURSE LICENSES ################################ +FEATURES['LICENSING'] = True + + +########################## Courseware Search ####################### +FEATURES['ENABLE_COURSEWARE_SEARCH'] = True +FEATURES['ENABLE_COURSEWARE_SEARCH_FOR_COURSE_STAFF'] = True +SEARCH_ENGINE = 'search.elastic.ElasticSearchEngine' +SEARCH_COURSEWARE_CONTENT_LOG_PARAMS = True + +ELASTIC_SEARCH_CONFIG = [ + { + 'use_ssl': False, + 'host': 'edx.devstack.elasticsearch710', + 'port': 9200 + } +] + +########################## Dashboard Search ####################### +FEATURES['ENABLE_DASHBOARD_SEARCH'] = False + + +########################## Certificates Web/HTML View ####################### +FEATURES['CERTIFICATES_HTML_VIEW'] = True + + +########################## Course Discovery ####################### +LANGUAGE_MAP = { + 'terms': dict(ALL_LANGUAGES), + 'name': 'Language', +} +COURSE_DISCOVERY_MEANINGS = { + 'org': { + 'name': 'Organization', + }, + 'modes': { + 'name': 'Course Type', + 'terms': { + 'honor': 'Honor', + 'verified': 'Verified', + }, + }, + 'language': LANGUAGE_MAP, +} + +FEATURES['ENABLE_COURSE_DISCOVERY'] = False +# Setting for overriding default filtering facets for Course discovery +# COURSE_DISCOVERY_FILTERS = ["org", "language", "modes"] +FEATURES['COURSES_ARE_BROWSEABLE'] = True +HOMEPAGE_COURSE_MAX = 9 + +# Software secure fake page feature flag +FEATURES['ENABLE_SOFTWARE_SECURE_FAKE'] = True + +# Setting for the testing of Software Secure Result Callback +VERIFY_STUDENT["SOFTWARE_SECURE"] = { + "API_ACCESS_KEY": "BBBBBBBBBBBBBBBBBBBB", + "API_SECRET_KEY": "CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC", +} +DISABLE_ACCOUNT_ACTIVATION_REQUIREMENT_SWITCH = "verify_student_disable_account_activation_requirement" + +# Skip enrollment start date filtering +SEARCH_SKIP_ENROLLMENT_START_DATE_FILTERING = True + + +########################## Shopping cart ########################## +FEATURES['ENABLE_COSMETIC_DISPLAY_PRICE'] = True + +######################### Program Enrollments ##################### +FEATURES['ENABLE_ENROLLMENT_RESET'] = True + +########################## Third Party Auth ####################### + +if FEATURES.get('ENABLE_THIRD_PARTY_AUTH') and ( + 'common.djangoapps.third_party_auth.dummy.DummyBackend' not in AUTHENTICATION_BACKENDS +): + AUTHENTICATION_BACKENDS = ['common.djangoapps.third_party_auth.dummy.DummyBackend'] + list(AUTHENTICATION_BACKENDS) + +########################## Authn MFE Context API ####################### +ENABLE_DYNAMIC_REGISTRATION_FIELDS = True + +############## ECOMMERCE API CONFIGURATION SETTINGS ############### +ECOMMERCE_PUBLIC_URL_ROOT = 'http://localhost:18130' +ECOMMERCE_API_URL = 'http://edx.devstack.ecommerce:18130/api/v2' + +############## Comments CONFIGURATION SETTINGS ############### +COMMENTS_SERVICE_URL = 'http://edx.devstack.forum:4567' + +############## Credentials CONFIGURATION SETTINGS ############### +CREDENTIALS_INTERNAL_SERVICE_URL = 'http://edx.devstack.credentials:18150' +CREDENTIALS_PUBLIC_SERVICE_URL = 'http://localhost:18150' + +############## Exams CONFIGURATION SETTINGS #################### +EXAMS_SERVICE_URL = 'http://localhost:8740/api/v1' + +TOKEN_SIGNING.update({ + 'JWT_PUBLIC_SIGNING_JWK_SET': ( + '{"keys": [{"kid": "localdev_exam_token_key", "e": "AQAB", "kty": "RSA", "n": "o5cn3ljSRi6FaDEKTn0PS-oL9EFyv1pI' + '7dRgffQLD1qf5D6sprmYfWWokSsrWig8u2y0HChSygR6Jn5KXBqQn6FpM0dDJLnWQDRXHLl3Ey1iPYgDSmOIsIGrV9ZyNCQwk03wAgWbfdBTig' + '3QSDYD-sTNOs3pc4UD_PqAvU2nz_1SS2ZiOwOn5F6gulE1L0iE3KEUEvOIagfHNVhz0oxa_VRZILkzV-zr6R_TW1m97h4H8jXl_VJyQGyhMGGy' + 'puDrQ9_vaY_RLEulLCyY0INglHWQ7pckxBtI5q55-Vio2wgewe2_qYcGsnBGaDNbySAsvYcWRrqDiFyzrJYivodqTQ"}]}' + ) +}) + +########################## PROGRAMS LEARNER PORTAL ############################## +LEARNER_PORTAL_URL_ROOT = 'http://localhost:8734' + +########################## ENTERPRISE LEARNER PORTAL ############################## +ENTERPRISE_LEARNER_PORTAL_NETLOC = 'localhost:8734' +ENTERPRISE_LEARNER_PORTAL_BASE_URL = 'http://' + ENTERPRISE_LEARNER_PORTAL_NETLOC + +########################## ENTERPRISE ADMIN PORTAL ############################## +ENTERPRISE_ADMIN_PORTAL_NETLOC = 'localhost:1991' +ENTERPRISE_ADMIN_PORTAL_BASE_URL = 'http://' + ENTERPRISE_ADMIN_PORTAL_NETLOC + +########################## GRADEBOOK APP ############################## +WRITABLE_GRADEBOOK_URL = 'http://localhost:1994' + +########################## ORA STAFF GRADING APP ############################## +ORA_GRADING_MICROFRONTEND_URL = 'http://localhost:1993' + +########################## ORA MFE APP ############################## +ORA_MICROFRONTEND_URL = 'http://localhost:1992' + +########################## LEARNER HOME APP ############################## +LEARNER_HOME_MICROFRONTEND_URL = 'http://localhost:1996' + +###################### Cross-domain requests ###################### +FEATURES['ENABLE_CORS_HEADERS'] = True +CORS_ALLOW_CREDENTIALS = True +CORS_ORIGIN_WHITELIST = () +CORS_ORIGIN_ALLOW_ALL = True + +LOGIN_REDIRECT_WHITELIST.extend([ + CMS_BASE, + # Allow redirection to all micro-frontends. + # Please add your MFE if is not already listed here. + # Note: For this to work, the MFE must set BASE_URL in its .env.development to: + # BASE_URL=http://localhost:$PORT + # as opposed to: + # BASE_URL=localhost:$PORT + 'localhost:18000', # lms + 'localhost:18130', # ecommerce + 'localhost:1997', # frontend-app-account + 'localhost:1976', # frontend-app-program-console + 'localhost:1994', # frontend-app-gradebook + 'localhost:2000', # frontend-app-learning + 'localhost:2001', # frontend-app-course-authoring + 'localhost:3001', # frontend-app-library-authoring + 'localhost:18400', # frontend-app-publisher + 'localhost:1993', # frontend-app-ora-grading + 'localhost:1996', # frontend-app-learner-dashboard + ENTERPRISE_LEARNER_PORTAL_NETLOC, # frontend-app-learner-portal-enterprise + ENTERPRISE_ADMIN_PORTAL_NETLOC, # frontend-app-admin-portal +]) + +###################### JWTs ###################### +JWT_AUTH.update({ + 'JWT_AUDIENCE': 'lms-key', + 'JWT_ISSUER': f'{LMS_ROOT_URL}/oauth2', + 'JWT_ISSUERS': [{ + 'AUDIENCE': 'lms-key', + 'ISSUER': f'{LMS_ROOT_URL}/oauth2', + 'SECRET_KEY': 'lms-secret', + }], + 'JWT_SECRET_KEY': 'lms-secret', + 'JWT_SIGNING_ALGORITHM': 'RS512', + 'JWT_PRIVATE_SIGNING_JWK': """ + { + "kid": "devstack_key", + "kty": "RSA", + "key_ops": [ + "sign" + ], + "n": "smKFSYowG6nNUAdeqH1jQQnH1PmIHphzBmwJ5vRf1vu48BUI5VcVtUWIPqzRK_LDSlZYh9D0YFL0ZTxIrlb6Tn3Xz7pYvpIAeYuQv3_H5p8tbz7Fb8r63c1828wXPITVTv8f7oxx5W3lFFgpFAyYMmROC4Ee9qG5T38LFe8_oAuFCEntimWxN9F3P-FJQy43TL7wG54WodgiM0EgzkeLr5K6cDnyckWjTuZbWI-4ffcTgTZsL_Kq1owa_J2ngEfxMCObnzGy5ZLcTUomo4rZLjghVpq6KZxfS6I1Vz79ZsMVUWEdXOYePCKKsrQG20ogQEkmTf9FT_SouC6jPcHLXw", + "e": "AQAB", + "d": "RQ6k4NpRU3RB2lhwCbQ452W86bMMQiPsa7EJiFJUg-qBJthN0FMNQVbArtrCQ0xA1BdnQHThFiUnHcXfsTZUwmwvTuiqEGR_MI6aI7h5D8vRj_5x-pxOz-0MCB8TY8dcuK9FkljmgtYvV9flVzCk_uUb3ZJIBVyIW8En7n7nV7JXpS9zey1yVLld2AbRG6W5--Pgqr9JCI5-bLdc2otCLuen2sKyuUDHO5NIj30qGTaKUL-OW_PgVmxrwKwccF3w5uGNEvMQ-IcicosCOvzBwdIm1uhdm9rnHU1-fXz8VLRHNhGVv7z6moghjNI0_u4smhUkEsYeshPv7RQEWTdkOQ", + "p": "7KWj7l-ZkfCElyfvwsl7kiosvi-ppOO7Imsv90cribf88DexcO67xdMPesjM9Nh5X209IT-TzbsOtVTXSQyEsy42NY72WETnd1_nAGLAmfxGdo8VV4ZDnRsA8N8POnWjRDwYlVBUEEeuT_MtMWzwIKU94bzkWVnHCY5vbhBYLeM", + "q": "wPkfnjavNV1Hqb5Qqj2crBS9HQS6GDQIZ7WF9hlBb2ofDNe2K2dunddFqCOdvLXr7ydRcK51ZwSeHjcjgD1aJkHA9i1zqyboxgd0uAbxVDo6ohnlVqYLtap2tXXcavKm4C9MTpob_rk6FBfEuq4uSsuxFvCER4yG3CYBBa4gZVU", + "dp": "MO9Ppss-Bl-mC1vGyJDBbMgr2GgivGYbHFLt6ERfTGsvcr0RhDjZu16ZpNpBB6B7-K-uJGHxPmmf8P9KRWDBUAwOSaT2a-pTsuux6PKCwVTZfUq5LxAkiyg6WZTGoWASEtoae0XRHEy2TvIKNl5AiX-h_DwDPDbEYcWCZVAb6-E", + "dq": "m03j7GkGSWRxMGNCeEBtvvBR4vDS9Her7AtjbNSWnRxDMQrKSdRMaiu-m7tOT3n6D9cM7Cr7wZUtzBOENskprHBu47FgzfXakMWfYhv0TV0voxZERKAN_H7cWt4oLsprEzH9r6THsxFPdKxMYBGeoAOe2l9nlk26m6LaX7_rwqE", + "qi": "jnJ0nfARyAcHsezENNrXKnDM-LrMJWMHPh_70ZM_pF5iRMOLojHkTVsUIzYi6Uj2ohX9Jz1zsV207kCuPqQXURbhlt1xEaktwCmySeWU4qkMTptWp4ya2jEwGn8EKJ1iEc0GhDkRyLrgm4ol-sq9DMaKEkhTGy4Y3-8mMCBVqeQ" + } +""", + 'JWT_PUBLIC_SIGNING_JWK_SET': ( + '{"keys": [{"kid": "devstack_key", "e": "AQAB", "kty": "RSA", "n": "smKFSYowG6nNUAdeqH1jQQnH1PmIHphzBmwJ5vRf1vu' + '48BUI5VcVtUWIPqzRK_LDSlZYh9D0YFL0ZTxIrlb6Tn3Xz7pYvpIAeYuQv3_H5p8tbz7Fb8r63c1828wXPITVTv8f7oxx5W3lFFgpFAyYMmROC' + '4Ee9qG5T38LFe8_oAuFCEntimWxN9F3P-FJQy43TL7wG54WodgiM0EgzkeLr5K6cDnyckWjTuZbWI-4ffcTgTZsL_Kq1owa_J2ngEfxMCObnzG' + 'y5ZLcTUomo4rZLjghVpq6KZxfS6I1Vz79ZsMVUWEdXOYePCKKsrQG20ogQEkmTf9FT_SouC6jPcHLXw"}]}' + ), +}) +add_plugins(__name__, ProjectType.LMS, SettingsType.DEVSTACK) + + +######################### Django Rest Framework ######################## + +REST_FRAMEWORK['DEFAULT_RENDERER_CLASSES'] += ( + 'rest_framework.renderers.BrowsableAPIRenderer', +) + +OPENAPI_CACHE_TIMEOUT = 0 + +##################################################################### +# set replica set of contentstore to none as we haven't setup any for lms in devstack +CONTENTSTORE['DOC_STORE_CONFIG']['replicaSet'] = None + +##################################################################### +# set replica sets of moduelstore to none as we haven't setup any for lms in devstack +for store in MODULESTORE['default']['OPTIONS']['stores']: + if 'DOC_STORE_CONFIG' in store and 'replicaSet' in store['DOC_STORE_CONFIG']: + store['DOC_STORE_CONFIG']['replicaSet'] = None + + +##################################################################### +# Lastly, run any migrations, if needed. +MODULESTORE = convert_module_store_setting_if_needed(MODULESTORE) + + +SECRET_KEY = '85920908f28904ed733fe576320db18cabd7b6cd' + +EDXNOTES_INTERNAL_API = 'http://edx.devstack.edxnotesapi:18120/api/v1' +EDXNOTES_CLIENT_NAME = 'edx_notes_api-backend-service' + +############## Settings for Microfrontends ######################### +LEARNING_MICROFRONTEND_URL = 'http://localhost:2000' +ACCOUNT_MICROFRONTEND_URL = 'http://localhost:1997' +COMMUNICATIONS_MICROFRONTEND_URL = 'http://localhost:1984' +AUTHN_MICROFRONTEND_URL = 'http://localhost:1999' +AUTHN_MICROFRONTEND_DOMAIN = 'localhost:1999' +EXAMS_DASHBOARD_MICROFRONTEND_URL = 'http://localhost:2020' + +################### FRONTEND APPLICATION DISCUSSIONS ################### +DISCUSSIONS_MICROFRONTEND_URL = 'http://localhost:2002' + +################### FRONTEND APPLICATION DISCUSSIONS FEEDBACK URL################### +DISCUSSIONS_MFE_FEEDBACK_URL = None + +############## Docker based devstack settings ####################### + +FEATURES.update({ + 'AUTOMATIC_AUTH_FOR_TESTING': True, + 'ENABLE_DISCUSSION_SERVICE': True, + 'SHOW_HEADER_LANGUAGE_SELECTOR': True, + + # Enable enterprise integration by default. + # See https://github.com/openedx/edx-enterprise/blob/master/docs/development.rst for + # more background on edx-enterprise. + # Toggle this off if you don't want anything to do with enterprise in devstack. + 'ENABLE_ENTERPRISE_INTEGRATION': True, +}) + +ENABLE_MKTG_SITE = os.environ.get('ENABLE_MARKETING_SITE', False) +MARKETING_SITE_ROOT = os.environ.get('MARKETING_SITE_ROOT', 'http://localhost:8080') + +MKTG_URLS = { + 'ABOUT': '/about', + 'ACCESSIBILITY': '/accessibility', + 'AFFILIATES': '/affiliate-program', + 'BLOG': '/blog', + 'CAREERS': '/careers', + 'CONTACT': '/support/contact_us', + 'COURSES': '/course', + 'DONATE': '/donate', + 'ENTERPRISE': '/enterprise', + 'FAQ': '/student-faq', + 'HONOR': '/edx-terms-service', + 'HOW_IT_WORKS': '/how-it-works', + 'MEDIA_KIT': '/media-kit', + 'NEWS': '/news-announcements', + 'PRESS': '/press', + 'PRIVACY': '/edx-privacy-policy', + 'ROOT': MARKETING_SITE_ROOT, + 'SCHOOLS': '/schools-partners', + 'SITE_MAP': '/sitemap', + 'TRADEMARKS': '/trademarks', + 'TOS': '/edx-terms-service', + 'TOS_AND_HONOR': '/edx-terms-service', + 'WHAT_IS_VERIFIED_CERT': '/verified-certificate', + 'PROGRAM_SUBSCRIPTIONS': '/program-subscriptions', +} + +ENTERPRISE_MARKETING_FOOTER_QUERY_PARAMS = {} + +ENTERPRISE_BACKEND_SERVICE_EDX_OAUTH2_PROVIDER_URL = "http://edx.devstack.lms:18000/oauth2" + +CREDENTIALS_SERVICE_USERNAME = 'credentials_worker' + +COURSE_CATALOG_URL_ROOT = 'http://edx.devstack.discovery:18381' +COURSE_CATALOG_API_URL = f'{COURSE_CATALOG_URL_ROOT}/api/v1' + +SYSTEM_WIDE_ROLE_CLASSES = os.environ.get("SYSTEM_WIDE_ROLE_CLASSES", SYSTEM_WIDE_ROLE_CLASSES) +SYSTEM_WIDE_ROLE_CLASSES.append( + 'system_wide_roles.SystemWideRoleAssignment', +) + +if FEATURES.get('ENABLE_ENTERPRISE_INTEGRATION'): + SYSTEM_WIDE_ROLE_CLASSES.append( + 'enterprise.SystemWideEnterpriseUserRoleAssignment', + ) + +##################################################################### + +# django-session-cookie middleware +DCS_SESSION_COOKIE_SAMESITE = 'Lax' +DCS_SESSION_COOKIE_SAMESITE_FORCE_ALL = True + +########################## THEMING ####################### +# If you want to enable theming in devstack, uncomment this section and add any relevant +# theme directories to COMPREHENSIVE_THEME_DIRS + +# We have to import the private method here because production.py calls +# derive_settings('lms.envs.production') which runs _make_mako_template_dirs with +# the settings from production, which doesn't include these theming settings. Thus, +# the templating engine is unable to find the themed templates because they don't exist +# in it's path. Re-calling derive_settings doesn't work because the settings was already +# changed from a function to a list, and it can't be derived again. + +# from .common import _make_mako_template_dirs +# ENABLE_COMPREHENSIVE_THEMING = True +# COMPREHENSIVE_THEME_DIRS = [ +# "/edx/app/edxapp/edx-platform/themes/" +# ] +# TEMPLATES[1]["DIRS"] = _make_mako_template_dirs +# derive_settings(__name__) + +# Uncomment the lines below if you'd like to see SQL statements in your devstack LMS log. +# LOGGING['handlers']['console']['level'] = 'DEBUG' +# LOGGING['loggers']['django.db.backends'] = {'handlers': ['console'], 'level': 'DEBUG', 'propagate': False} + +################### Special Exams (Proctoring) and Prereqs ################### +FEATURES['ENABLE_SPECIAL_EXAMS'] = True +FEATURES['ENABLE_PREREQUISITE_COURSES'] = True + +# Used in edx-proctoring for ID generation in lieu of SECRET_KEY - dummy value +# (ref MST-637) +PROCTORING_USER_OBFUSCATION_KEY = '85920908f28904ed733fe576320db18cabd7b6cd' + +#################### Webpack Configuration Settings ############################## +WEBPACK_LOADER['DEFAULT']['TIMEOUT'] = 5 + +#################### Network configuration #################### +# Devstack is directly exposed to the caller +CLOSEST_CLIENT_IP_FROM_HEADERS = [] + +#################### Event bus backend ######################## +EVENT_BUS_PRODUCER = 'edx_event_bus_redis.create_producer' +EVENT_BUS_REDIS_CONNECTION_URL = 'redis://:password@edx.devstack.redis:6379/' +EVENT_BUS_TOPIC_PREFIX = 'dev' +EVENT_BUS_CONSUMER = 'edx_event_bus_redis.RedisEventConsumer' + +certificate_revoked_event_config = EVENT_BUS_PRODUCER_CONFIG['org.openedx.learning.certificate.revoked.v1'] +certificate_revoked_event_config['learning-certificate-lifecycle']['enabled'] = True +certificate_created_event_config = EVENT_BUS_PRODUCER_CONFIG['org.openedx.learning.certificate.created.v1'] +certificate_created_event_config['learning-certificate-lifecycle']['enabled'] = True + +course_access_role_added_event_setting = EVENT_BUS_PRODUCER_CONFIG[ + 'org.openedx.learning.user.course_access_role.added.v1' +] +course_access_role_added_event_setting['learning-course-access-role-lifecycle']['enabled'] = True +course_access_role_removed_event_setting = EVENT_BUS_PRODUCER_CONFIG[ + 'org.openedx.learning.user.course_access_role.removed.v1' +] +course_access_role_removed_event_setting['learning-course-access-role-lifecycle']['enabled'] = True + +lc_enrollment_revoked_setting = \ + EVENT_BUS_PRODUCER_CONFIG['org.openedx.enterprise.learner_credit_course_enrollment.revoked.v1'] +lc_enrollment_revoked_setting['learner-credit-course-enrollment-lifecycle']['enabled'] = True + +# API access management +API_ACCESS_MANAGER_EMAIL = 'api-access@example.com' +API_ACCESS_FROM_EMAIL = 'api-requests@example.com' +API_DOCUMENTATION_URL = 'https://course-catalog-api-guide.readthedocs.io/en/latest/' +AUTH_DOCUMENTATION_URL = 'https://course-catalog-api-guide.readthedocs.io/en/latest/authentication/index.html' + +############################ AI_TRANSLATIONS ################################## +AI_TRANSLATIONS_API_URL = 'http://localhost:18760/api/v1' + +############################ CSRF ################################## + +# MFEs that will call this service in devstack +CSRF_TRUSTED_ORIGINS = [ + 'http://localhost:2000', # frontend-app-learning + 'http://localhost:2001', # frontend-app-course-authoring + 'http://localhost:1997', # frontend-app-account + 'http://localhost:1995', # frontend-app-profile + 'http://localhost:1992', # frontend-app-ora + 'http://localhost:2002', # frontend-app-discussions + 'http://localhost:1991', # frontend-app-admin-portal + 'http://localhost:8734', # frontend-app-learner-portal-enterprise + 'http://localhost:1999', # frontend-app-authn + 'http://localhost:18450', # frontend-app-support-tools + 'http://localhost:1994', # frontend-app-gradebook + 'http://localhost:1996', # frontend-app-learner-dashboard +] + + +################# New settings must go ABOVE this line ################# +######################################################################## +# See if the developer has any local overrides. +if os.path.isfile(join(dirname(abspath(__file__)), 'private.py')): + from .private import * # pylint: disable=import-error,wildcard-import diff --git a/py_configuration_files/portal_designer.py b/py_configuration_files/portal_designer.py new file mode 100644 index 0000000000..0221171ae8 --- /dev/null +++ b/py_configuration_files/portal_designer.py @@ -0,0 +1,51 @@ +from designer.settings.local import * + +from designer.settings.utils import get_logger_config + +LOGGING = get_logger_config(debug=True, dev_env=True, local_loglevel='DEBUG') + +DEBUG = True + +# Generic OAuth2 variables irrespective of SSO/backend service key types. +OAUTH2_PROVIDER_URL = 'http://edx.devstack.lms:18000/oauth2' + +# OAuth2 variables specific to social-auth/SSO login use case. +SOCIAL_AUTH_EDX_OAUTH2_KEY = os.environ.get('SOCIAL_AUTH_EDX_OAUTH2_KEY', 'designer-sso-key') +SOCIAL_AUTH_EDX_OAUTH2_SECRET = os.environ.get('SOCIAL_AUTH_EDX_OAUTH2_SECRET', 'designer-sso-secret') +SOCIAL_AUTH_EDX_OAUTH2_ISSUER = os.environ.get('SOCIAL_AUTH_EDX_OAUTH2_ISSUER', 'http://localhost:18000') +SOCIAL_AUTH_EDX_OAUTH2_URL_ROOT = os.environ.get('SOCIAL_AUTH_EDX_OAUTH2_URL_ROOT', 'http://edx.devstack.lms:18000') +SOCIAL_AUTH_EDX_OAUTH2_LOGOUT_URL = os.environ.get('SOCIAL_AUTH_EDX_OAUTH2_LOGOUT_URL', 'http://localhost:18000/logout') +SOCIAL_AUTH_EDX_OAUTH2_PUBLIC_URL_ROOT = os.environ.get( + 'SOCIAL_AUTH_EDX_OAUTH2_PUBLIC_URL_ROOT', 'http://localhost:18000', +) +SOCIAL_AUTH_EDX_OAUTH2_PUBLIC_URL_ROOT = 'http://localhost:18000' +# OAuth2 variables specific to backend service API calls. +BACKEND_SERVICE_EDX_OAUTH2_KEY = os.environ.get('BACKEND_SERVICE_EDX_OAUTH2_KEY', 'designer-backend-service-key') +BACKEND_SERVICE_EDX_OAUTH2_SECRET = os.environ.get('BACKEND_SERVICE_EDX_OAUTH2_SECRET', 'designer-backend-service-secret') + +JWT_AUTH['JWT_ISSUERS'].append({ + 'AUDIENCE': 'lms-key', + 'ISSUER': 'http://localhost:18000/oauth2', + 'SECRET_KEY': 'lms-secret', +}) + +# CACHES = { +# 'default': { +# 'BACKEND': 'django.core.cache.backends.memcached.PyMemcacheCache', +# 'LOCATION': os.environ.get('CACHE_LOCATION', 'memcached:11211'), +# 'OPTIONS': {"no_delay": True, "ignore_exc": True, "use_pooling": True}, +# } +# } + +DATABASES = { + 'default': { + 'ENGINE': 'django.db.backends.mysql', + 'NAME': os.environ.get('DB_NAME', 'designer'), + 'USER': os.environ.get('DB_USER', 'root'), + 'PASSWORD': os.environ.get('DB_PASSWORD', ''), + 'HOST': os.environ.get('DB_HOST', 'designer.mysql'), + 'PORT': os.environ.get('DB_PORT', 3306), + 'ATOMIC_REQUESTS': False, + 'CONN_MAX_AGE': 60, + } +} diff --git a/py_configuration_files/program_intent_management.py b/py_configuration_files/program_intent_management.py new file mode 100644 index 0000000000..26e58ffe3a --- /dev/null +++ b/py_configuration_files/program_intent_management.py @@ -0,0 +1,51 @@ +from program_intent_engagement.settings.local import * + +DATABASES = { + 'default': { + 'ENGINE': 'django.db.backends.mysql', + 'NAME': os.environ.get('DB_NAME', 'program_intent_engagement'), + 'USER': os.environ.get('DB_USER', 'root'), + 'PASSWORD': os.environ.get('DB_PASSWORD', ''), + 'HOST': os.environ.get('DB_HOST', 'program_intent_engagement.db'), + 'PORT': os.environ.get('DB_PORT', 3306), + 'ATOMIC_REQUESTS': False, + 'CONN_MAX_AGE': 60, + } +} + +# Generic OAuth2 variables irrespective of SSO/backend service key types. +OAUTH2_PROVIDER_URL = 'http://edx.devstack.lms:18000/oauth2' + +# OAuth2 variables specific to social-auth/SSO login use case. +SOCIAL_AUTH_EDX_OAUTH2_KEY = os.environ.get('SOCIAL_AUTH_EDX_OAUTH2_KEY', 'program_intent_engagement-sso-key') +SOCIAL_AUTH_EDX_OAUTH2_SECRET = os.environ.get('SOCIAL_AUTH_EDX_OAUTH2_SECRET', 'program_intent_engagement-sso-secret') +SOCIAL_AUTH_EDX_OAUTH2_ISSUER = os.environ.get('SOCIAL_AUTH_EDX_OAUTH2_ISSUER', 'http://localhost:18000') +SOCIAL_AUTH_EDX_OAUTH2_URL_ROOT = os.environ.get('SOCIAL_AUTH_EDX_OAUTH2_URL_ROOT', 'http://edx.devstack.lms:18000') +SOCIAL_AUTH_EDX_OAUTH2_LOGOUT_URL = os.environ.get('SOCIAL_AUTH_EDX_OAUTH2_LOGOUT_URL', 'http://localhost:18000/logout') +SOCIAL_AUTH_EDX_OAUTH2_PUBLIC_URL_ROOT = os.environ.get( + 'SOCIAL_AUTH_EDX_OAUTH2_PUBLIC_URL_ROOT', 'http://localhost:18000', +) + +# OAuth2 variables specific to backend service API calls. +BACKEND_SERVICE_EDX_OAUTH2_KEY = os.environ.get('BACKEND_SERVICE_EDX_OAUTH2_KEY', + 'program_intent_engagement-backend-service-key') +BACKEND_SERVICE_EDX_OAUTH2_SECRET = os.environ.get('BACKEND_SERVICE_EDX_OAUTH2_SECRET', + 'program_intent_engagement-backend-service-secret') + +JWT_AUTH.update({ + 'JWT_SECRET_KEY': 'lms-secret', + 'JWT_ISSUER': 'http://localhost:18000/oauth2', + 'JWT_AUDIENCE': None, + 'JWT_VERIFY_AUDIENCE': False, + 'JWT_PUBLIC_SIGNING_JWK_SET': ( + '{"keys": [{"kid": "devstack_key", "e": "AQAB", "kty": "RSA", "n": "smKFSYowG6nNUAdeqH1jQQnH1PmIHphzBmwJ5vRf1vu' + '48BUI5VcVtUWIPqzRK_LDSlZYh9D0YFL0ZTxIrlb6Tn3Xz7pYvpIAeYuQv3_H5p8tbz7Fb8r63c1828wXPITVTv8f7oxx5W3lFFgpFAyYMmROC' + '4Ee9qG5T38LFe8_oAuFCEntimWxN9F3P-FJQy43TL7wG54WodgiM0EgzkeLr5K6cDnyckWjTuZbWI-4ffcTgTZsL_Kq1owa_J2ngEfxMCObnzG' + 'y5ZLcTUomo4rZLjghVpq6KZxfS6I1Vz79ZsMVUWEdXOYePCKKsrQG20ogQEkmTf9FT_SouC6jPcHLXw"}]}' + ), + 'JWT_ISSUERS': [{ + 'AUDIENCE': 'lms-key', + 'ISSUER': 'http://localhost:18000/oauth2', + 'SECRET_KEY': 'lms-secret', + }], +}) diff --git a/py_configuration_files/registrar.py b/py_configuration_files/registrar.py new file mode 100644 index 0000000000..df0b6c0cb4 --- /dev/null +++ b/py_configuration_files/registrar.py @@ -0,0 +1,84 @@ +from registrar.settings.local import * +from registrar.settings.utils import get_logger_config + + +ALLOWED_HOSTS = ['*'] + +LOGGING = get_logger_config(debug=True, dev_env=True, local_loglevel='DEBUG') +del LOGGING['handlers']['local'] + +SECRET_KEY = os.environ.get('SECRET_KEY', 'change-me') +LANGUAGE_CODE = os.environ.get('LANGUAGE_CODE', 'en') + +CELERY_TASK_ALWAYS_EAGER = ( + os.environ.get("CELERY_ALWAYS_EAGER", "false").lower() == "true" +) + +CACHES = { + 'default': { + 'BACKEND': 'django.core.cache.backends.memcached.PyMemcacheCache', + 'LOCATION': os.environ.get('CACHE_LOCATION', 'memcached:11211'), + "OPTIONS": {"no_delay": True, "ignore_exc": True, "use_pooling": True}, + } +} + +DATABASES = { + 'default': { + 'ENGINE': 'django.db.backends.mysql', + 'NAME': os.environ.get('DB_NAME', 'regsitrar'), + 'USER': os.environ.get('DB_USER', 'regsitrar001'), + 'PASSWORD': os.environ.get('DB_PASSWORD', 'password'), + 'HOST': os.environ.get('DB_HOST', 'db'), + 'PORT': os.environ.get('DB_PORT', 3306), + 'ATOMIC_REQUESTS': False, + 'CONN_MAX_AGE': 60, + } +} + +STATICFILES_STORAGE = os.environ.get('STATICFILES_STORAGE', 'django.contrib.staticfiles.storage.StaticFilesStorage') +STATIC_URL = os.environ.get('STATIC_URL', '/static/') + +LMS_BASE_URL = 'http://edx.devstack.lms:18000' +DISCOVERY_BASE_URL = 'http://edx.devstack.discovery:18381' + +# Set these to the correct values for your OAuth2/OpenID Connect provider (e.g., devstack) +SOCIAL_AUTH_EDX_OAUTH2_KEY = os.environ.get('SOCIAL_AUTH_EDX_OAUTH2_KEY', 'registrar-sso-key') +SOCIAL_AUTH_EDX_OAUTH2_SECRET = os.environ.get('SOCIAL_AUTH_EDX_OAUTH2_SECRET', 'registrar-sso-secret') +SOCIAL_AUTH_EDX_OAUTH2_ISSUER = os.environ.get('SOCIAL_AUTH_EDX_OAUTH2_ISSUER', 'http://localhost:18000') +SOCIAL_AUTH_EDX_OAUTH2_URL_ROOT = os.environ.get('SOCIAL_AUTH_EDX_OAUTH2_URL_ROOT', 'http://edx.devstack.lms:18000') +SOCIAL_AUTH_EDX_OAUTH2_LOGOUT_URL = os.environ.get('SOCIAL_AUTH_EDX_OAUTH2_LOGOUT_URL', 'http://localhost:18000/logout') +SOCIAL_AUTH_EDX_OAUTH2_PUBLIC_URL_ROOT = os.environ.get( + 'SOCIAL_AUTH_EDX_OAUTH2_PUBLIC_URL_ROOT', 'http://localhost:18000', +) + +# OAuth2 variables specific to backend service API calls. +BACKEND_SERVICE_EDX_OAUTH2_KEY = os.environ.get('BACKEND_SERVICE_EDX_OAUTH2_KEY', 'registrar-backend-service-key') +BACKEND_SERVICE_EDX_OAUTH2_SECRET = os.environ.get('BACKEND_SERVICE_EDX_OAUTH2_SECRET', 'registrar-backend-service-secret') +BACKEND_SERVICE_EDX_OAUTH2_PROVIDER_URL = os.environ.get( + 'BACKEND_SERVICE_EDX_OAUTH2_PROVIDER_URL', 'http://edx.devstack.lms:18000/oauth2', +) + +JWT_AUTH['JWT_ISSUERS'].append({ + 'AUDIENCE': 'lms-key', + 'ISSUER': 'http://localhost:18000/oauth2', + 'SECRET_KEY': 'lms-secret', +}) + +JWT_AUTH.update({ + # Must match public signing key used in LMS. + 'JWT_PUBLIC_SIGNING_JWK_SET': ( + '{"keys": [{"kid": "devstack_key", "e": "AQAB", "kty": "RSA", "n": "smKFSYowG6nNUAdeqH1jQQnH1PmIHphzBmwJ5vRf1vu' + '48BUI5VcVtUWIPqzRK_LDSlZYh9D0YFL0ZTxIrlb6Tn3Xz7pYvpIAeYuQv3_H5p8tbz7Fb8r63c1828wXPITVTv8f7oxx5W3lFFgpFAyYMmROC' + '4Ee9qG5T38LFe8_oAuFCEntimWxN9F3P-FJQy43TL7wG54WodgiM0EgzkeLr5K6cDnyckWjTuZbWI-4ffcTgTZsL_Kq1owa_J2ngEfxMCObnzG' + 'y5ZLcTUomo4rZLjghVpq6KZxfS6I1Vz79ZsMVUWEdXOYePCKKsrQG20ogQEkmTf9FT_SouC6jPcHLXw"}]}' + ), +}) + +SEGMENT_KEY = os.environ.get('SEGMENT_KEY', None) + +##################################################################### +# Lastly, see if the developer has any local overrides. +if os.path.isfile(join(dirname(abspath(__file__)), 'private.py')): + from .private import * # pylint: disable=import-error + +API_ROOT = 'http://localhost:18734/api' diff --git a/py_configuration_files/xqueue.py b/py_configuration_files/xqueue.py new file mode 100644 index 0000000000..a346bdb9c5 --- /dev/null +++ b/py_configuration_files/xqueue.py @@ -0,0 +1,53 @@ +import codecs +from os import environ + +import yaml +# Normally you should not import ANYTHING from Django directly +# into your settings, but ImproperlyConfigured is an exception. +from django.core.exceptions import ImproperlyConfigured + +from .settings import * + + +def get_env_setting(setting): + """ Get the environment setting or return exception """ + try: + return environ[setting] + except KeyError: + error_msg = "Set the %s env variable" % setting + raise ImproperlyConfigured(error_msg) + + +# Keep track of the names of settings that represent dicts. Instead of overriding the values in settings.py, +# the values read from disk should UPDATE the pre-configured dicts. +DICT_UPDATE_KEYS = () + +CONFIG_FILE = get_env_setting('XQUEUE_CFG') +with codecs.open(CONFIG_FILE, encoding='utf-8') as f: + config_from_yaml = yaml.safe_load(f) + + # Remove the items that should be used to update dicts, and apply them separately rather + # than pumping them into the local vars. + dict_updates = {key: config_from_yaml.pop(key, None) for key in DICT_UPDATE_KEYS} + + for key, value in dict_updates.items(): + if value: + vars()[key].update(value) + + vars().update(config_from_yaml) + +# We use the default development logging from settings.py +# but override this to force a console log for docker. +# Stolen from the LMS. +LOGGING['handlers']['local'] = { + 'class': 'logging.NullHandler', +} + +# It's probably ok to search your DB for push queues every minute (or even longer) on a +# development instance, rather than the brief prod timespan. +CONSUMER_DELAY = 60 + +##################################################################### +# See if the developer has any local overrides. +if os.path.isfile(os.path.join(os.path.dirname(os.path.abspath(__file__)), 'private.py')): + from .private import * # pylint: disable=import-error,wildcard-import diff --git a/repo.sh b/repo.sh index cb93108f63..84792fb35c 100755 --- a/repo.sh +++ b/repo.sh @@ -36,6 +36,7 @@ repos=( "https://github.com/openedx/frontend-app-publisher.git" "https://github.com/edx/edx-analytics-dashboard.git" "https://github.com/edx/edx-analytics-data-api.git" + "https://github.com/openedx/enterprise-catalog.git" ) non_release_repos=( @@ -56,6 +57,7 @@ ssh_repos=( "git@github.com:openedx/cs_comments_service.git" "git@github.com:edx/ecommerce.git" "git@github.com:openedx/edx-notes-api.git" + "git@github.com:openedx/enterprise-catalog.git" "git@github.com:openedx/edx-platform.git" "git@github.com:openedx/xqueue.git" "git@github.com:edx/edx-analytics-dashboard.git"