diff --git a/tom_common/apps.py b/tom_common/apps.py index b242634f..8eb4ddd9 100644 --- a/tom_common/apps.py +++ b/tom_common/apps.py @@ -20,3 +20,15 @@ def ready(self): plotly_theme = 'plotly_white' pio.templates.default = plotly_theme + + def profile_details(self): + """ + Integration point for adding items to the user profile page. + + This method should return a list of dictionaries that include a `partial` key pointing to the path of the html + profile partial. The `context` key should point to the dot separated string path to the templatetag that will + return a dictionary containing new context for the accompanying partial. + Typically, this partial will be a bootstrap card displaying some app specific user data. + """ + return [{'partial': 'tom_common/partials/user_data.html', + 'context': 'tom_common.templatetags.user_extras.user_data'}] diff --git a/tom_common/templates/tom_common/partials/profile_app_addons.html b/tom_common/templates/tom_common/partials/profile_app_addons.html new file mode 100644 index 00000000..910e1284 --- /dev/null +++ b/tom_common/templates/tom_common/partials/profile_app_addons.html @@ -0,0 +1,19 @@ +{% load user_extras %} +{% load bootstrap4 %} + +
+ +
+ {% for profile in profile_list %} +
+ {% include profile %} +
+ {% if forloop.counter|divisibleby:2 %} +
+
+ {% endif %} + {% empty %} + This user has no profile. + {% endfor %} +
+
\ No newline at end of file diff --git a/tom_common/templates/tom_common/user_profile.html b/tom_common/templates/tom_common/user_profile.html index 8bb78403..02afdcc2 100644 --- a/tom_common/templates/tom_common/user_profile.html +++ b/tom_common/templates/tom_common/user_profile.html @@ -11,14 +11,6 @@

{% endif %}

-
-
-
- {% user_data user %} -
-
-
-
-
+{% profile_app_addons user %} {% endblock %} diff --git a/tom_common/templatetags/user_extras.py b/tom_common/templatetags/user_extras.py index 8018d7f3..db0b1e3c 100644 --- a/tom_common/templatetags/user_extras.py +++ b/tom_common/templatetags/user_extras.py @@ -1,8 +1,12 @@ +import logging from django import template from django.contrib.auth.models import Group, User from django.forms.models import model_to_dict +from django.apps import apps +from django.utils.module_loading import import_string register = template.Library() +logger = logging.getLogger(__name__) @register.inclusion_tag('auth/partials/group_list.html', takes_context=True) @@ -42,3 +46,36 @@ def user_data(user): 'user_data': user_dict, 'profile_data': profile_dict, } + + +@register.inclusion_tag('tom_common/partials/profile_app_addons.html', takes_context=True) +def profile_app_addons(context, user): + """ + Imports the profile content from relevant apps. + + Each profile should be contained in a list of dictionaries in an app's apps.py `profile_details` method. + Each profile dictionary should contain a 'context' key with the path to the context processor class (typically a + templatetag), and a 'partial' key with the path to the html partial template. + """ + partial_list = [] + for app in apps.get_app_configs(): + try: + profile_details = app.profile_details() + if profile_details: + for profile in profile_details: + try: + clazz = import_string(profile['context']) + except ImportError: + logger.warning(f'WARNING: Could not import context for {app.name} profile from ' + f'{profile["context"]}.\n' + f'Are you sure you have the right path?') + continue + new_context = clazz(user) + for item in new_context: + context[item] = new_context[item] + partial_list.append(profile['partial']) + except AttributeError: + pass + context['user'] = user + context['profile_list'] = partial_list + return context