Skip to content
Snippets Groups Projects
Commit 47255197 authored by Matt Tuchfarber's avatar Matt Tuchfarber
Browse files

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.
parent 6c7a3ca0
No related branches found
Tags release-2020-03-24-13.32
No related merge requests found
......@@ -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
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)
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment