From eab027577575d5d07c88d90872e4d98d41b58007 Mon Sep 17 00:00:00 2001 From: henrrypg Date: Wed, 16 Nov 2022 09:26:20 -0500 Subject: [PATCH 1/2] feat: add pipelines to add custom registrations fields and custom options in account settings --- eox_core/pipeline.py | 74 ++++++++++++++++++++++++++++++++++++++ requirements/base.txt | 1 + requirements/pip-tools.txt | 1 - 3 files changed, 75 insertions(+), 1 deletion(-) diff --git a/eox_core/pipeline.py b/eox_core/pipeline.py index be5bfbd7a..ea93ac1c1 100644 --- a/eox_core/pipeline.py +++ b/eox_core/pipeline.py @@ -4,8 +4,12 @@ import logging from crum import get_current_request +from django.conf import settings +from django.core.exceptions import ImproperlyConfigured from django.db.models.signals import post_save +from openedx_filters import PipelineStep +from openedx.core.djangoapps.site_configuration import helpers as configuration_helpers # pylint: disable=import-error from eox_core.edxapp_wrapper.users import ( generate_password, get_user_attribute, @@ -219,3 +223,73 @@ def ensure_user_has_signup_source(user=None, *args, **kwargs): "Created new singup source for user during the third party pipeline.", **locals() ) + +class AddCustomOptionsOnAccountSettings(PipelineStep): + """ Pipeline used to add custom option fields in account settings. + + Example usage: + + Add the following configurations to your configuration file: + "OPEN_EDX_FILTERS_CONFIG": { + "org.openedx.learning.student.settings.render.started.v1": { + "fail_silently": false, + "pipeline": [ + "eox_core.pipeline.AddCustomOptionsOnAccountSettings" + ] + } + } + """ + + def run_filter(self, context): # pylint: disable=arguments-differ + """ Run the pipeline filter. """ + extended_profile_fields = context.get("extended_profile_fields", []) + + custom_options, field_labels_map = self._get_custom_context(extended_profile_fields) # pylint: disable=line-too-long + + extended_profile_field_options = configuration_helpers.get_value('EXTRA_FIELD_OPTIONS', custom_options) # pylint: disable=line-too-long + extended_profile_field_option_tuples = {} + for field in extended_profile_field_options.keys(): + field_options = extended_profile_field_options[field] + extended_profile_field_option_tuples[field] = [(option.lower(), option) for option in field_options] # pylint: disable=line-too-long + + for field in custom_options: + field_dict = { + "field_name": field, + "field_label": field_labels_map.get(field, field), + } + + field_options = extended_profile_field_option_tuples.get(field) + if field_options: + field_dict["field_type"] = "ListField" + field_dict["field_options"] = field_options + else: + field_dict["field_type"] = "TextField" + + field_index = next((index for (index, d) in enumerate(extended_profile_fields) if d["field_name"] == field_dict["field_name"]), None) # pylint: disable=line-too-long + if field_index is not None: + context["extended_profile_fields"][field_index] = field_dict + return context + + def _get_custom_context(self, extended_profile_fields): + """ Get custom context for the field. """ + field_labels = {} + field_options = {} + custom_fields = getattr(settings, "EDNX_CUSTOM_REGISTRATION_FIELDS", []) + + for field in custom_fields: + field_name = field.get("name") + + if not field_name: # Required to identify the field. + msg = "Custom fields must have a `name` defined in their configuration." + raise ImproperlyConfigured(msg) + + field_label = field.get("label") + if not any(extended_field['field_name'] == field_name for extended_field in extended_profile_fields) and field_label: # pylint: disable=line-too-long + field_labels[field_name] = _(field_label) # pylint: disable=translation-of-non-string + + options = field.get("options") + + if options: + field_options[field_name] = options + + return field_options, field_labels diff --git a/requirements/base.txt b/requirements/base.txt index b45f787f7..7f5c8a7af 100644 --- a/requirements/base.txt +++ b/requirements/base.txt @@ -69,6 +69,7 @@ django==3.2.16 # event-tracking # jsonfield # openedx-events + # openedx-filters django-crum==0.7.9 # via # edx-django-utils diff --git a/requirements/pip-tools.txt b/requirements/pip-tools.txt index bd3f4f113..968163d01 100644 --- a/requirements/pip-tools.txt +++ b/requirements/pip-tools.txt @@ -10,7 +10,6 @@ click==8.1.3 # via # -c requirements/constraints.txt # pip-tools -packaging==23.0 # via build pip-tools==6.12.1 # via -r requirements/pip-tools.in From a011a31d99d854148c3c0a2f69289070a06521d0 Mon Sep 17 00:00:00 2001 From: Juan David Buitrago Date: Fri, 21 Jul 2023 22:59:34 -0500 Subject: [PATCH 2/2] test: upgrade requirement and fix pipeline problem --- eox_core/pipeline.py | 19 +++++++++++-------- requirements/base.in | 1 + requirements/base.txt | 2 ++ requirements/test.txt | 2 ++ 4 files changed, 16 insertions(+), 8 deletions(-) diff --git a/eox_core/pipeline.py b/eox_core/pipeline.py index ea93ac1c1..2a7a47098 100644 --- a/eox_core/pipeline.py +++ b/eox_core/pipeline.py @@ -7,9 +7,9 @@ from django.conf import settings from django.core.exceptions import ImproperlyConfigured from django.db.models.signals import post_save - from openedx_filters import PipelineStep -from openedx.core.djangoapps.site_configuration import helpers as configuration_helpers # pylint: disable=import-error + +from eox_core.edxapp_wrapper.configuration_helpers import get_configuration_helper from eox_core.edxapp_wrapper.users import ( generate_password, get_user_attribute, @@ -224,6 +224,7 @@ def ensure_user_has_signup_source(user=None, *args, **kwargs): **locals() ) + class AddCustomOptionsOnAccountSettings(PipelineStep): """ Pipeline used to add custom option fields in account settings. @@ -244,13 +245,15 @@ def run_filter(self, context): # pylint: disable=arguments-differ """ Run the pipeline filter. """ extended_profile_fields = context.get("extended_profile_fields", []) - custom_options, field_labels_map = self._get_custom_context(extended_profile_fields) # pylint: disable=line-too-long + custom_options, field_labels_map = self._get_custom_context(extended_profile_fields) + + conf_helper = get_configuration_helper() - extended_profile_field_options = configuration_helpers.get_value('EXTRA_FIELD_OPTIONS', custom_options) # pylint: disable=line-too-long + extended_profile_field_options = conf_helper.get_value('EXTRA_FIELD_OPTIONS', custom_options) extended_profile_field_option_tuples = {} for field in extended_profile_field_options.keys(): field_options = extended_profile_field_options[field] - extended_profile_field_option_tuples[field] = [(option.lower(), option) for option in field_options] # pylint: disable=line-too-long + extended_profile_field_option_tuples[field] = [(option.lower(), option) for option in field_options] for field in custom_options: field_dict = { @@ -265,7 +268,7 @@ def run_filter(self, context): # pylint: disable=arguments-differ else: field_dict["field_type"] = "TextField" - field_index = next((index for (index, d) in enumerate(extended_profile_fields) if d["field_name"] == field_dict["field_name"]), None) # pylint: disable=line-too-long + field_index = next((index for (index, d) in enumerate(extended_profile_fields) if d["field_name"] == field_dict["field_name"]), None) if field_index is not None: context["extended_profile_fields"][field_index] = field_dict return context @@ -284,8 +287,8 @@ def _get_custom_context(self, extended_profile_fields): raise ImproperlyConfigured(msg) field_label = field.get("label") - if not any(extended_field['field_name'] == field_name for extended_field in extended_profile_fields) and field_label: # pylint: disable=line-too-long - field_labels[field_name] = _(field_label) # pylint: disable=translation-of-non-string + if not any(extended_field['field_name'] == field_name for extended_field in extended_profile_fields) and field_label: + field_labels[field_name] = (field_label) options = field.get("options") diff --git a/requirements/base.in b/requirements/base.in index 2a5086485..228ab60a5 100644 --- a/requirements/base.in +++ b/requirements/base.in @@ -14,3 +14,4 @@ edx-opaque-keys[django]==2.3.0 openedx-events==0.13.0 django click +openedx-filters==1.2.0 diff --git a/requirements/base.txt b/requirements/base.txt index 7f5c8a7af..70efce839 100644 --- a/requirements/base.txt +++ b/requirements/base.txt @@ -183,6 +183,8 @@ oauthlib==3.2.2 # via django-oauth-toolkit openedx-events==0.13.0 # via -r requirements/base.in +openedx-filters==1.2.0 + # via -r requirements/base.in packaging==23.0 # via drf-yasg pbr==5.11.1 diff --git a/requirements/test.txt b/requirements/test.txt index dd4295090..f276abff3 100644 --- a/requirements/test.txt +++ b/requirements/test.txt @@ -279,6 +279,8 @@ oauthlib==3.2.2 # django-oauth-toolkit openedx-events==0.13.0 # via -r requirements/base.txt +openedx-filters==1.2.0 + # via -r requirements/base.txt packaging==23.0 # via # -r requirements/base.txt