Allow plugins to update contexts in specific views
Instead of requiring views like the dashboard to know about plugins so they can include their data in the context, this allows plugins to define a mapping between a view and a function where the function returns a dictionary of new context for the view. Each view would have to purposefully enable this additional context before it could be used. This will allow new content to be added to the pages without updating the core with a combination of a plugin to add new context, and a theme override of that page to use the new context.
This commit is contained in:
@@ -47,6 +47,8 @@ from openedx.core.djangoapps.catalog.utils import (
|
||||
get_visible_sessions_for_entitlement
|
||||
)
|
||||
from openedx.core.djangoapps.credit.email_utils import get_credit_provider_attribute_values, make_providers_strings
|
||||
from openedx.core.djangoapps.plugins.plugin_contexts import get_plugins_view_context
|
||||
from openedx.core.djangoapps.plugins import constants as plugin_constants
|
||||
from openedx.core.djangoapps.programs.models import ProgramsApiConfig
|
||||
from openedx.core.djangoapps.programs.utils import ProgramDataExtender, ProgramProgressMeter
|
||||
from openedx.core.djangoapps.site_configuration import helpers as configuration_helpers
|
||||
@@ -880,6 +882,13 @@ def student_dashboard(request):
|
||||
# TODO START: clean up as part of REVEM-199 (END)
|
||||
}
|
||||
|
||||
context_from_plugins = get_plugins_view_context(
|
||||
plugin_constants.ProjectType.LMS,
|
||||
plugin_constants.PluginContexts.VIEWS.STUDENT_DASHBOARD,
|
||||
context
|
||||
)
|
||||
context.update(context_from_plugins)
|
||||
|
||||
if ecommerce_service.is_enabled(request.user):
|
||||
context.update({
|
||||
'use_ecommerce_payment_flow': True,
|
||||
|
||||
@@ -106,7 +106,7 @@ class::
|
||||
|
||||
from django.apps import AppConfig
|
||||
from openedx.core.djangoapps.plugins.constants import (
|
||||
ProjectType, SettingsType, PluginURLs, PluginSettings
|
||||
ProjectType, SettingsType, PluginURLs, PluginSettings, PluginContexts
|
||||
)
|
||||
class MyAppConfig(AppConfig):
|
||||
name = u'full_python_path.my_app'
|
||||
@@ -184,6 +184,19 @@ class::
|
||||
PluginSignals.SENDER_PATH: u'full_path_to_sender_app.ModelZ',
|
||||
}],
|
||||
}
|
||||
},
|
||||
|
||||
# Configuration setting for Plugin Contexts for this app.
|
||||
PluginContexts.CONFIG: {
|
||||
|
||||
# Configure the Plugin Signals for each Project Type, as needed.
|
||||
ProjectType.LMS: {
|
||||
|
||||
# Key is the view that the app wishes to add context to and the value
|
||||
# is the function within the app that will return additional context
|
||||
# when called with the original context
|
||||
PluginContexts.VIEWS.STUDENT_DASHBOARD: u'my_app.context_api.get_dashboard_context'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -217,6 +230,11 @@ OR use string constants when they cannot import from djangoapps.plugins::
|
||||
u'sender_path': u'full_path_to_sender_app.ModelZ',
|
||||
}],
|
||||
}
|
||||
},
|
||||
u'context_config': {
|
||||
u'lms.djangoapp': {
|
||||
'student_dashboard': u'my_app.context_api.get_dashboard_context'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -76,3 +76,19 @@ class PluginSignals(object):
|
||||
|
||||
RELATIVE_PATH = u'relative_path'
|
||||
DEFAULT_RELATIVE_PATH = u'signals'
|
||||
|
||||
|
||||
class PluginContextsViews(object):
|
||||
STUDENT_DASHBOARD = u'student_dashboard'
|
||||
|
||||
|
||||
class PluginContexts(object):
|
||||
"""
|
||||
The PluginContexts enum defines dictionary field names (and defaults)
|
||||
that can be specified by a Plugin App in order to configure the
|
||||
additional views it would like to add context into.
|
||||
"""
|
||||
CONFIG = u"context_config"
|
||||
|
||||
VIEWS = PluginContextsViews
|
||||
|
||||
|
||||
35
openedx/core/djangoapps/plugins/plugin_contexts.py
Normal file
35
openedx/core/djangoapps/plugins/plugin_contexts.py
Normal file
@@ -0,0 +1,35 @@
|
||||
from importlib import import_module
|
||||
|
||||
from logging import getLogger
|
||||
from . import constants, registry
|
||||
|
||||
log = getLogger(__name__)
|
||||
|
||||
|
||||
def get_plugins_view_context(project_type, view_name, existing_context={}):
|
||||
"""
|
||||
Returns a dict of additonal view context. Will check if any plugin apps
|
||||
have that view in their context_config, and if so will call their
|
||||
selected function to get their context dicts.
|
||||
"""
|
||||
aggregate_context = {}
|
||||
|
||||
for app_config in registry.get_app_configs(project_type):
|
||||
context_function_path = _get_context_function(app_config, project_type, view_name)
|
||||
if context_function_path:
|
||||
module_path, _, name = context_function_path.rpartition('.')
|
||||
context_function = getattr(import_module(module_path), name)
|
||||
plugin_context = context_function(existing_context)
|
||||
|
||||
# NOTE: If two plugins have try to set the same context keys, the last one
|
||||
# called will overwrite the others.
|
||||
aggregate_context.update(plugin_context)
|
||||
|
||||
return aggregate_context
|
||||
|
||||
|
||||
def _get_context_function(app_config, project_type, view_name):
|
||||
plugin_config = getattr(app_config, constants.PLUGIN_APP_CLASS_ATTRIBUTE_NAME, {})
|
||||
context_config = plugin_config.get(constants.PluginContexts.CONFIG, {})
|
||||
project_type_settings = context_config.get(project_type, {})
|
||||
return project_type_settings.get(view_name)
|
||||
Reference in New Issue
Block a user