Skip to content

Commit

Permalink
autofilling user details from sso pipeline (openedx#33051)
Browse files Browse the repository at this point in the history
* refactor: mfe_context response to serialize object keys to camelcase (openedx#31930)

* test: add tests for MFE Context API serializser (openedx#32179)

* fix: empty pipelineUserDetail object

pipelineUserDetail object should be empty when pipeline is not running

---------

Co-authored-by: Shahbaz Shabbir <32649010+shahbaz-arbisoft@users.noreply.github.com>
  • Loading branch information
2 people authored and shURenZHOUluxun committed Jan 3, 2024
1 parent f6ad297 commit 4716bbb
Show file tree
Hide file tree
Showing 5 changed files with 329 additions and 16 deletions.
141 changes: 141 additions & 0 deletions openedx/core/djangoapps/user_authn/api/tests/test_data.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
""" Mocked data for testing """

mfe_context_data_keys = {
'contextData',
'registrationFields',
'optionalFields'
}

mock_mfe_context_data = {
'context_data': {
'currentProvider': 'edX',
'platformName': 'edX',
'providers': [
{
'id': 'oa2-facebook',
'name': 'Facebook',
'iconClass': 'fa-facebook',
'iconImage': None,
'skipHintedLogin': False,
'skipRegistrationForm': False,
'loginUrl': 'https://facebook.com/login',
'registerUrl': 'https://facebook.com/register'
},
{
'id': 'oa2-google-oauth2',
'name': 'Google',
'iconClass': 'fa-google-plus',
'iconImage': None,
'skipHintedLogin': False,
'skipRegistrationForm': False,
'loginUrl': 'https://google.com/login',
'registerUrl': 'https://google.com/register'
}
],
'secondaryProviders': [],
'finishAuthUrl': 'https://edx.com/auth/finish',
'errorMessage': None,
'registerFormSubmitButtonText': 'Create Account',
'autoSubmitRegForm': False,
'syncLearnerProfileData': False,
'countryCode': '',
'pipeline_user_details': {
'username': 'test123',
'email': 'test123@edx.com',
'fullname': 'Test Test',
'first_name': 'Test',
'last_name': 'Test'
}
},
'registration_fields': {},
'optional_fields': {
'extended_profile': []
}
}

mock_default_mfe_context_data = {
'context_data': {
'currentProvider': None,
'platformName': 'édX',
'providers': [],
'secondaryProviders': [],
'finishAuthUrl': None,
'errorMessage': None,
'registerFormSubmitButtonText': 'Create Account',
'autoSubmitRegForm': False,
'syncLearnerProfileData': False,
'countryCode': '',
'pipeline_user_details': {}
},
'registration_fields': {},
'optional_fields': {
'extended_profile': []
}
}

expected_mfe_context_data = {
'contextData': {
'currentProvider': 'edX',
'platformName': 'edX',
'providers': [
{
'id': 'oa2-facebook',
'name': 'Facebook',
'iconClass': 'fa-facebook',
'iconImage': None,
'skipHintedLogin': False,
'skipRegistrationForm': False,
'loginUrl': 'https://facebook.com/login',
'registerUrl': 'https://facebook.com/register'
},
{
'id': 'oa2-google-oauth2',
'name': 'Google',
'iconClass': 'fa-google-plus',
'iconImage': None,
'skipHintedLogin': False,
'skipRegistrationForm': False,
'loginUrl': 'https://google.com/login',
'registerUrl': 'https://google.com/register'
}
],
'secondaryProviders': [],
'finishAuthUrl': 'https://edx.com/auth/finish',
'errorMessage': None,
'registerFormSubmitButtonText': 'Create Account',
'autoSubmitRegForm': False,
'syncLearnerProfileData': False,
'countryCode': '',
'pipelineUserDetails': {
'username': 'test123',
'email': 'test123@edx.com',
'name': 'Test Test',
'firstName': 'Test',
'lastName': 'Test'
}
},
'registrationFields': {},
'optionalFields': {
'extended_profile': []
}
}

default_expected_mfe_context_data = {
'contextData': {
'currentProvider': None,
'platformName': 'édX',
'providers': [],
'secondaryProviders': [],
'finishAuthUrl': None,
'errorMessage': None,
'registerFormSubmitButtonText': 'Create Account',
'autoSubmitRegForm': False,
'syncLearnerProfileData': False,
'countryCode': '',
'pipelineUserDetails': {}
},
'registrationFields': {},
'optionalFields': {
'extended_profile': []
}
}
44 changes: 44 additions & 0 deletions openedx/core/djangoapps/user_authn/api/tests/test_serializers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
"""Tests for serializers for the MFE Context"""

from django.test import TestCase

from openedx.core.djangoapps.user_authn.api.tests.test_data import (
mock_mfe_context_data,
expected_mfe_context_data,
mock_default_mfe_context_data,
default_expected_mfe_context_data,
)
from openedx.core.djangoapps.user_authn.serializers import MFEContextSerializer


class TestMFEContextSerializer(TestCase):
"""
High-level unit tests for MFEContextSerializer
"""

def test_mfe_context_serializer(self):
"""
Test MFEContextSerializer with mock data that serializes data correctly
"""

output_data = MFEContextSerializer(
mock_mfe_context_data
).data

self.assertDictEqual(
output_data,
expected_mfe_context_data
)

def test_mfe_context_serializer_default_response(self):
"""
Test MFEContextSerializer with default data
"""
serialized_data = MFEContextSerializer(
mock_default_mfe_context_data
).data

self.assertDictEqual(
serialized_data,
default_expected_mfe_context_data
)
72 changes: 57 additions & 15 deletions openedx/core/djangoapps/user_authn/api/tests/test_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,10 @@
from common.djangoapps.student.tests.factories import UserFactory
from common.djangoapps.third_party_auth import pipeline
from common.djangoapps.third_party_auth.tests.testutil import ThirdPartyAuthTestMixin, simulate_running_pipeline
from openedx.core.djangoapps.site_configuration.tests.test_util import with_site_configuration
from openedx.core.djangoapps.geoinfo.api import country_code_from_ip
from openedx.core.djangoapps.site_configuration.tests.test_util import with_site_configuration
from openedx.core.djangoapps.user_api.tests.test_views import UserAPITestCase
from openedx.core.djangoapps.user_authn.api.tests.test_data import mfe_context_data_keys
from openedx.core.djangolib.testing.utils import skip_unless_lms


Expand All @@ -42,6 +43,7 @@ def setUp(self): # pylint: disable=arguments-differ
hostname = socket.gethostname()
ip_address = socket.gethostbyname(hostname)
self.country_code = country_code_from_ip(ip_address)
self.pipeline_user_details = {}

# Several third party auth providers are created for these tests:
self.configure_google_provider(enabled=True, visible=True)
Expand Down Expand Up @@ -93,21 +95,34 @@ def get_context(self, params=None, current_provider=None, backend_name=None, add
"""
Returns the MFE context
"""

if add_user_details:
self.pipeline_user_details.update(
{
'username': None,
'email': 'test@test.com',
'name': None,
'firstName': None,
'lastName': None
}
)

return {
'context_data': {
'contextData': {
'currentProvider': current_provider,
'platformName': settings.PLATFORM_NAME,
'providers': self.get_provider_data(params) if params else [],
'secondaryProviders': [],
'finishAuthUrl': pipeline.get_complete_url(backend_name) if backend_name else None,
'errorMessage': None,
'registerFormSubmitButtonText': 'Create Account',
'autoSubmitRegForm': False,
'syncLearnerProfileData': False,
'pipeline_user_details': {'email': 'test@test.com'} if add_user_details else {},
'countryCode': self.country_code
'countryCode': self.country_code,
'pipelineUserDetails': self.pipeline_user_details,
},
'registration_fields': {},
'optional_fields': {
'registrationFields': {},
'optionalFields': {
'extended_profile': [],
},
}
Expand Down Expand Up @@ -182,7 +197,7 @@ def test_tpa_hint(self):
})

response = self.client.get(self.url, self.query_params)
assert response.data['context_data']['providers'] == provider_data
assert response.data['contextData']['providers'] == provider_data

def test_user_country_code(self):
"""
Expand All @@ -191,7 +206,7 @@ def test_user_country_code(self):
response = self.client.get(self.url, self.query_params)

assert response.status_code == 200
assert response.data['context_data']['countryCode'] == self.country_code
assert response.data['contextData']['countryCode'] == self.country_code

@override_settings(
ENABLE_DYNAMIC_REGISTRATION_FIELDS=True,
Expand All @@ -205,7 +220,7 @@ def test_required_fields_not_configured(self):
self.query_params.update({'is_register_page': True})
response = self.client.get(self.url, self.query_params)
assert response.status_code == status.HTTP_200_OK
assert response.data['registration_fields']['fields'] == {}
assert response.data['registrationFields']['fields'] == {}

@with_site_configuration(
configuration={
Expand All @@ -223,8 +238,9 @@ def test_required_field_order(self):
"""
self.query_params.update({'is_register_page': True})
response = self.client.get(self.url, self.query_params)

assert response.status_code == status.HTTP_200_OK
assert list(response.data['registration_fields']['fields'].keys()) == ['first_name', 'last_name', 'state']
assert list(response.data['registrationFields']['fields'].keys()) == ['first_name', 'last_name', 'state']

@override_settings(
ENABLE_DYNAMIC_REGISTRATION_FIELDS=True,
Expand All @@ -248,7 +264,7 @@ def test_optional_field_has_no_description(self):
self.query_params.update({'is_register_page': True})
response = self.client.get(self.url, self.query_params)
assert response.status_code == status.HTTP_200_OK
assert response.data['optional_fields']['fields'] == expected_response
assert response.data['optionalFields']['fields'] == expected_response

@with_site_configuration(
configuration={
Expand Down Expand Up @@ -282,8 +298,9 @@ def test_configurable_select_option_fields(self):
}
self.query_params.update({'is_register_page': True})
response = self.client.get(self.url, self.query_params)

assert response.status_code == status.HTTP_200_OK
assert response.data['optional_fields']['fields'] == expected_response
assert response.data['optionalFields']['fields'] == expected_response

@with_site_configuration(
configuration={
Expand All @@ -302,7 +319,7 @@ def test_optional_field_order(self):
self.query_params.update({'is_register_page': True})
response = self.client.get(self.url, self.query_params)
assert response.status_code == status.HTTP_200_OK
assert list(response.data['optional_fields']['fields'].keys()) == ['specialty', 'goals']
assert list(response.data['optionalFields']['fields'].keys()) == ['specialty', 'goals']

@with_site_configuration(
configuration={
Expand All @@ -322,7 +339,7 @@ def test_field_not_available_in_extended_profile_config(self):
self.query_params.update({'is_register_page': True})
response = self.client.get(self.url, self.query_params)
assert response.status_code == status.HTTP_200_OK
assert list(response.data['registration_fields']['fields'].keys()) == ['specialty']
assert list(response.data['registrationFields']['fields'].keys()) == ['specialty']

@override_settings(
ENABLE_DYNAMIC_REGISTRATION_FIELDS=True,
Expand All @@ -333,9 +350,34 @@ def test_response_structure(self):
Test that API return valid response dictionary with both required and optional fields
"""
response = self.client.get(self.url, self.query_params)

assert response.data == self.get_context()

def test_mfe_context_api_serialized_response(self):
"""
Test MFE Context API serialized response
"""
response = self.client.get(self.url, self.query_params)
self.assertEqual(response.status_code, status.HTTP_200_OK)

params = {
'next': self.query_params['next']
}

self.assertEqual(
response.data,
self.get_context(params)
)

def test_mfe_context_api_response_keys(self):
"""
Test MFE Context API response keys
"""
response = self.client.get(self.url, self.query_params)
self.assertEqual(response.status_code, status.HTTP_200_OK)

response_keys = set(response.data.keys())
self.assertSetEqual(response_keys, mfe_context_data_keys)


@skip_unless_lms
class SendAccountActivationEmail(UserAPITestCase):
Expand Down
6 changes: 5 additions & 1 deletion openedx/core/djangoapps/user_authn/api/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
from common.djangoapps.student.views import compose_and_send_activation_email
from openedx.core.djangoapps.site_configuration import helpers as configuration_helpers
from openedx.core.djangoapps.user_authn.api.helper import RegistrationFieldsContext
from openedx.core.djangoapps.user_authn.serializers import MFEContextSerializer
from openedx.core.djangoapps.user_authn.views.utils import get_mfe_context


Expand Down Expand Up @@ -65,6 +66,7 @@ def get(self, request, **kwargs): # lint-amnesty, pylint: disable=unused-argume
context['registration_fields'].update({
'fields': registration_fields,
})

optional_fields = RegistrationFieldsContext('optional').get_fields()
if optional_fields:
context['optional_fields'].update({
Expand All @@ -74,7 +76,9 @@ def get(self, request, **kwargs): # lint-amnesty, pylint: disable=unused-argume

return Response(
status=status.HTTP_200_OK,
data=context
data=MFEContextSerializer(
context
).data
)


Expand Down
Loading

0 comments on commit 4716bbb

Please sign in to comment.