Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ Unreleased

* nothing unreleased

[8.0.6] - 2026-05-05
---------------------
* fix: gate plugin_settings on ENABLE_ENTERPRISE_INTEGRATION

[8.0.5] - 2026-05-04
---------------------
* feat: add TPA pipeline step and social auth disconnect handler
Expand Down
2 changes: 1 addition & 1 deletion consent/settings/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ def plugin_settings(settings): # pylint: disable=unused-argument
Override platform settings for the consent app.

This is called by the Open edX plugin system during LMS/CMS startup. Add
any Django settings overrides here (e.g. ``settings.FEATURES['...'] = True``).
any Django settings overrides here (e.g. ``settings.SOME_FLAG = True``).

Args:
settings: The Django settings module being configured.
Expand Down
2 changes: 1 addition & 1 deletion enterprise/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@
Your project description goes here.
"""

__version__ = "8.0.5"
__version__ = "8.0.6"
3 changes: 1 addition & 2 deletions enterprise/admin/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -776,8 +776,7 @@ def has_delete_permission(self, request, obj=None):
"""
Disable deletion for EnterpriseCourseEnrollment.
"""
features = getattr(settings, 'FEATURES', {})
return features.get(constants.ALLOW_ADMIN_ENTERPRISE_COURSE_ENROLLMENT_DELETION, False)
return getattr(settings, constants.ALLOW_ADMIN_ENTERPRISE_COURSE_ENROLLMENT_DELETION, False)

def changelist_view(self, request, extra_context=None):
"""
Expand Down
6 changes: 5 additions & 1 deletion enterprise/settings/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,15 @@ def plugin_settings(settings):
Override platform settings for the enterprise app.

This is called by the Open edX plugin system during LMS/CMS startup. Add
any Django settings overrides here (e.g. ``settings.FEATURES['...'] = True``).
any Django settings overrides here (e.g. ``settings.SOME_FLAG = True``).

Args:
settings: The Django settings module being configured.
"""
# Skip injecting ANY default enterprise settings if the enterprise feature is entirely disabled.
if not getattr(settings, 'ENABLE_ENTERPRISE_INTEGRATION', False):
Comment thread
pwnage101 marked this conversation as resolved.
return

pipeline = getattr(settings, 'SOCIAL_AUTH_PIPELINE', None)
if pipeline is not None:
email_step = 'enterprise.tpa_pipeline.enterprise_associate_by_email'
Expand Down
194 changes: 116 additions & 78 deletions enterprise/settings/test.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
from os.path import abspath, dirname, join

from celery import Celery
from edx_django_utils.plugins import add_plugins

from enterprise.constants import (
DEFAULT_ENTERPRISE_ENROLLMENT_INTENTIONS_ROLE,
Expand All @@ -25,6 +26,8 @@
SYSTEM_ENTERPRISE_PROVISIONING_ADMIN_ROLE,
)

############################ BASE LMS TEST SETTINGS ############################
# Only non-enterprise settings live in this section.

def here(*args):
"""
Expand Down Expand Up @@ -62,8 +65,11 @@ def root(*args):
"django.contrib.staticfiles",
"waffle",

# Force install enterprise and consent. This is automatically accomplished
# in prod via stevedore, but we need to do it manually here for unit tests.
"enterprise",
"consent",

"integrated_channels.integrated_channel",
"integrated_channels.cornerstone",
"integrated_channels.degreed",
Expand Down Expand Up @@ -143,19 +149,6 @@ def root(*args):
LMS_INTERNAL_ROOT_URL = "http://localhost:8000"
LMS_ENROLLMENT_API_PATH = "/api/enrollment/v1/"
ECOMMERCE_PUBLIC_URL_ROOT = "http://localhost:18130"
ENTERPRISE_CATALOG_INTERNAL_ROOT_URL = "http://localhost:18160"

ENTERPRISE_ENROLLMENT_API_URL = LMS_INTERNAL_ROOT_URL + LMS_ENROLLMENT_API_PATH

ENTERPRISE_LEARNER_PORTAL_BASE_URL = 'http://localhost:8734'

ENTERPRISE_PUBLIC_ENROLLMENT_API_URL = ENTERPRISE_ENROLLMENT_API_URL

ENTERPRISE_API_CACHE_TIMEOUT = 60

ENTERPRISE_SUPPORT_URL = "http://foo"

ENTERPRISE_TAGLINE = "High-quality online learning opportunities from the world's best universities"

OAUTH_ID_TOKEN_EXPIRATION = 60 * 60 # in seconds

Expand Down Expand Up @@ -186,22 +179,7 @@ def root(*args):
ALLOWED_HOSTS = ["testserver.enterprise"]
MEDIA_URL = "/"

# Defines the usernames of service users who should be throttled
# at a higher rate than normal users.
ENTERPRISE_ALL_SERVICE_USERNAMES = [
'ecommerce_worker',
'enterprise_worker',
'license-manager_worker',
'enterprise-catalog_worker',
'enterprise-subsidy_worker',
]

ECOMMERCE_SERVICE_WORKER_USERNAME = 'ecommerce_worker'
ENTERPRISE_SERVICE_WORKER_USERNAME = 'enterprise_worker'

ENTERPRISE_CUSTOMER_LOGO_IMAGE_SIZE = 512 # Enterprise logo image size limit in KB's

ENTERPRISE_COURSE_ENROLLMENT_AUDIT_MODES = ['audit', 'honor']

# These are standard regexes for pulling out info like course_ids, usage_ids, etc.
COURSE_KEY_PATTERN = r'(?P<course_key_string>[^/+]+(/|\+)[^/+]+(/|\+)[^/?]+)'
Expand All @@ -211,31 +189,8 @@ def root(*args):

TIME_ZONE = 'UTC'

# Business logic should be allowed to assume that FEATURES is set. In a
# running app, it's set by the platform, but in enterprise unit tests we'll
# just seed one here.
FEATURES = {
'ENABLE_ENTERPRISE_INTEGRATION': True,
}

MKTG_URLS = {}

ENTERPRISE_CUSTOMER_CATALOG_DEFAULT_CONTENT_FILTER = {
'content_type': 'course',
'partner': 'edx',
'level_type': [
'Introductory',
'Intermediate',
'Advanced'
],
'availability': [
'Current',
'Starting Soon',
'Upcoming'
],
'status': 'published'
}

SNOWFLAKE_SERVICE_USER = '[email protected]'
SNOWFLAKE_SERVICE_USER_PASSWORD = 'secret'

Expand Down Expand Up @@ -282,8 +237,6 @@ def root(*args):
},
}

################################### TRACKING ###################################

LMS_SEGMENT_KEY = 'SOME_KEY'
EVENT_TRACKING_ENABLED = True
EVENT_TRACKING_BACKENDS = {
Expand All @@ -306,18 +259,13 @@ def root(*args):
}
EVENT_TRACKING_PROCESSORS = []

#################################### CELERY ####################################

# Celery settings
app = Celery('enterprise')
app.conf.task_protocol = 1
app.config_from_object('django.conf:settings')

CELERY_ALWAYS_EAGER = True

CLEAR_REQUEST_CACHE_ON_TASK_COMPLETION = False

##### END CELERY #####

JWT_AUTH = {
'JWT_AUDIENCE': 'test-aud',
'JWT_DECODE_HANDLER': 'edx_rest_framework_extensions.auth.jwt.decoder.jwt_decode_handler',
Expand Down Expand Up @@ -346,17 +294,9 @@ def root(*args):
}


INTEGRATED_CHANNELS_API_CHUNK_TRANSMISSION_LIMIT = {
'SAP': 1,
}

LANGUAGE_COOKIE_NAME = "openedx-language-preference"
SHARED_COOKIE_DOMAIN = ''

ENTERPRISE_BACKEND_SERVICE_EDX_OAUTH2_PROVIDER_URL = f'{LMS_INTERNAL_ROOT_URL}/oauth2'
ENTERPRISE_BACKEND_SERVICE_EDX_OAUTH2_KEY = 'test_backend_oauth2_key'
ENTERPRISE_BACKEND_SERVICE_EDX_OAUTH2_SECRET = 'test_backend_oauth2_secret'

ECOMMERCE_API_URL = 'https://ecommerce.example.com/api/v2/'

LOGIN_REDIRECT_WHITELIST = [
Expand All @@ -366,13 +306,118 @@ def root(*args):
'facebook.com'
]

ENTERPRISE_MANUAL_REPORTING_CUSTOMER_UUIDS = ['12aacfee8ffa4cb3bed1059565a57f06',]
EXEC_ED_LANDING_PAGE = 'https://www.edx-external.com/account'


# disable indexing on history_date. Otherwise it will add new alter migrations.
SIMPLE_HISTORY_DATE_INDEX = False

STORAGES = {
'default': {
'BACKEND': 'django.core.files.storage.FileSystemStorage',
},
'staticfiles': {
'BACKEND': 'django.contrib.staticfiles.storage.StaticFilesStorage',
},
}

# Enterprise-free social auth / TPA pipeline which is conditionally augmented by add_plugins() below.
SOCIAL_AUTH_PIPELINE = [
'common.djangoapps.third_party_auth.pipeline.parse_query_params',
'social_core.pipeline.social_auth.social_details',
'social_core.pipeline.social_auth.social_uid',
'social_core.pipeline.social_auth.auth_allowed',
'social_core.pipeline.social_auth.social_user',
'common.djangoapps.third_party_auth.pipeline.associate_by_email_if_login_api',
'common.djangoapps.third_party_auth.pipeline.associate_by_email_if_oauth',
'common.djangoapps.third_party_auth.pipeline.get_username',
'common.djangoapps.third_party_auth.pipeline.set_pipeline_timeout',
'common.djangoapps.third_party_auth.pipeline.ensure_user_information',
'social_core.pipeline.user.create_user',
'social_core.pipeline.social_auth.associate_user',
'social_core.pipeline.social_auth.load_extra_data',
'social_core.pipeline.user.user_details',
'common.djangoapps.third_party_auth.pipeline.user_details_force_sync',
'common.djangoapps.third_party_auth.pipeline.set_id_verification_status',
'common.djangoapps.third_party_auth.pipeline.set_logged_in_cookies',
'common.djangoapps.third_party_auth.pipeline.login_analytics',
'common.djangoapps.third_party_auth.pipeline.ensure_redirect_url_is_safe',
]

# Force the enterprise integration to be enabled so that plugin_settings() will activate.
ENABLE_ENTERPRISE_INTEGRATION = True

##### END BASE LMS TEST SETTINGS #####

########################### PLUGIN COMMON SETTINGS #############################

# Apply plugin_settings() from every plugin registered in this repo's setup.py
# entry points so that all tests automatically pick up the post-startup state
# that openedx-platform sees in production.
# Notes:
# - We apply the "common" settings_type which seeds most of the basic enterprise settings needed.
# - Must be applied **after** LMS settings but **before** enterprise-specific test overrides.
add_plugins(__name__, 'lms.djangoapp', 'common')

##### END PLUGIN COMMON SETTINGS #####

###################### ENTERPRISE-SPECIFIC TEST OVERRIDES #######################

ENTERPRISE_CATALOG_INTERNAL_ROOT_URL = "http://localhost:18160"

ENTERPRISE_ENROLLMENT_API_URL = LMS_INTERNAL_ROOT_URL + LMS_ENROLLMENT_API_PATH

ENTERPRISE_LEARNER_PORTAL_BASE_URL = 'http://localhost:8734'

ENTERPRISE_PUBLIC_ENROLLMENT_API_URL = ENTERPRISE_ENROLLMENT_API_URL

ENTERPRISE_API_CACHE_TIMEOUT = 60

ENTERPRISE_SUPPORT_URL = "http://foo"

ENTERPRISE_TAGLINE = "High-quality online learning opportunities from the world's best universities"

ENTERPRISE_SERVICE_WORKER_USERNAME = 'enterprise_worker'

ENTERPRISE_CUSTOMER_LOGO_IMAGE_SIZE = 512 # Enterprise logo image size limit in KB's

ENTERPRISE_COURSE_ENROLLMENT_AUDIT_MODES = ['audit', 'honor']

ENTERPRISE_CUSTOMER_CATALOG_DEFAULT_CONTENT_FILTER = {
'content_type': 'course',
'partner': 'edx',
'level_type': [
'Introductory',
'Intermediate',
'Advanced'
],
'availability': [
'Current',
'Starting Soon',
'Upcoming'
],
'status': 'published'
}

# Defines the usernames of service users who should be throttled
# at a higher rate than normal users.
ENTERPRISE_ALL_SERVICE_USERNAMES = [
'ecommerce_worker',
'enterprise_worker',
'license-manager_worker',
'enterprise-catalog_worker',
'enterprise-subsidy_worker',
]

INTEGRATED_CHANNELS_API_CHUNK_TRANSMISSION_LIMIT = {
'SAP': 1,
}

ENTERPRISE_BACKEND_SERVICE_EDX_OAUTH2_PROVIDER_URL = f'{LMS_INTERNAL_ROOT_URL}/oauth2'
ENTERPRISE_BACKEND_SERVICE_EDX_OAUTH2_KEY = 'test_backend_oauth2_key'
ENTERPRISE_BACKEND_SERVICE_EDX_OAUTH2_SECRET = 'test_backend_oauth2_secret'

ENTERPRISE_MANUAL_REPORTING_CUSTOMER_UUIDS = ['12aacfee8ffa4cb3bed1059565a57f06',]

CHAT_COMPLETION_API_V2 = 'https://example.com/chat/completion'
ENTERPRISE_ANALYSIS_CLIENT_ID = 'test_client_id'
ENTERPRISE_ANALYSIS_SYSTEM_PROMPT = 'This is a test prompt'
Expand All @@ -395,15 +440,6 @@ def root(*args):
BRAZE_ADMIN_INVITE_CAMPAIGN_ID = 'test-admin-invite-campaign-id'
BRAZE_LEARNER_INVITE_CAMPAIGN_ID = 'test-learner-invite-campaign-id'

STORAGES = {
'default': {
'BACKEND': 'django.core.files.storage.FileSystemStorage',
},
'staticfiles': {
'BACKEND': 'django.contrib.staticfiles.storage.StaticFilesStorage',
},
}

ENTERPRISE_ADMIN_PORTAL_BASE_URL = 'http://localhost:1991'

# Admin invite reminder settings
Expand Down Expand Up @@ -432,3 +468,5 @@ def root(*args):
# addresses (including cloud metadata endpoints like 169.254.169.254) are always
# blocked regardless of this setting.
SAML_METADATA_URL_ALLOW_PRIVATE_IPS = False

##### END ENTERPRISE-SPECIFIC TEST OVERRIDES #####
2 changes: 1 addition & 1 deletion enterprise/signals.py
Original file line number Diff line number Diff line change
Expand Up @@ -552,6 +552,6 @@ def handle_social_auth_disconnect(
saml_backend: the SAML auth backend instance.
**kwargs: forward-compatible catch-all.
"""
if not settings.FEATURES.get('ENABLE_ENTERPRISE_INTEGRATION', False):
if not getattr(settings, 'ENABLE_ENTERPRISE_INTEGRATION', False):
Comment thread
pwnage101 marked this conversation as resolved.
return
_unlink_enterprise_user_from_idp(request, user, saml_backend.name)
2 changes: 1 addition & 1 deletion enterprise/tpa_pipeline.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ def enterprise_associate_by_email(strategy, details, user=None, *args, **kwargs)

ENT-11577: This step replaces the now-defunct ``associate_by_email_if_saml`` step from openedx-platform.
"""
if not getattr(settings, 'FEATURES', {}).get('ENABLE_ENTERPRISE_INTEGRATION', False):
if not getattr(settings, 'ENABLE_ENTERPRISE_INTEGRATION', False):
Comment thread
pwnage101 marked this conversation as resolved.
return None

def associate_by_email_if_enterprise_user(current_user, current_provider):
Expand Down
4 changes: 2 additions & 2 deletions tests/test_enterprise/test_signals.py
Original file line number Diff line number Diff line change
Expand Up @@ -1325,7 +1325,7 @@ class TestHandleSocialAuthDisconnect(unittest.TestCase):
Tests for handle_social_auth_disconnect signal handler.
"""

@override_settings(FEATURES={'ENABLE_ENTERPRISE_INTEGRATION': True})
@override_settings(ENABLE_ENTERPRISE_INTEGRATION=True)
@mock.patch(
'enterprise.signals._unlink_enterprise_user_from_idp',
)
Expand All @@ -1345,7 +1345,7 @@ def test_calls_unlink(self, mock_unlink):
)
mock_unlink.assert_called_once_with(request, user, saml_backend.name)

@override_settings(FEATURES={'ENABLE_ENTERPRISE_INTEGRATION': False})
@override_settings(ENABLE_ENTERPRISE_INTEGRATION=False)
@mock.patch(
'enterprise.signals._unlink_enterprise_user_from_idp',
)
Expand Down
Loading
Loading