Account API: Fix Enterprise enforcement when NOT sync profile_data

ARCH-740
This commit is contained in:
Nimisha Asthagiri
2019-05-03 10:47:39 -04:00
parent a72d71deea
commit d2d6f81278
2 changed files with 69 additions and 22 deletions

View File

@@ -4,6 +4,7 @@ Unit tests for behavior that is specific to the api methods (vs. the view method
Most of the functionality is covered in test_views.py.
"""
import itertools
import re
import unicodedata
@@ -231,20 +232,54 @@ class TestAccountApi(UserSettingsEventTestMixin, EmailTemplateTagMixin, Retireme
account_settings = get_account_settings(self.default_request)[0]
self.assertEqual(level_of_education, account_settings["level_of_education"])
@patch('openedx.features.enterprise_support.api.get_enterprise_customer_for_learner')
@patch('openedx.features.enterprise_support.utils.third_party_auth.provider.Registry.get')
@ddt.data(
("email", "new_email@example.com"),
("name", "New Name"),
("country", "New Country"),
*itertools.product(
# field_name_value values
(("email", "new_email@example.com"), ("name", "new name"), ("country", "IN")),
# is_enterprise_user
(True, False),
# is_synch_learner_profile_data
(True, False),
)
)
@ddt.unpack
def test_update_validation_error_for_enterprise(self, field_name, field_value):
EnterpriseCustomerUserFactory(user_id=self.user.id)
update_data = {field_name: field_value}
def test_update_validation_error_for_enterprise(
self,
field_name_value,
is_enterprise_user,
is_synch_learner_profile_data,
mock_auth_provider,
mock_customer,
):
mock_customer.return_value = {}
if is_enterprise_user:
mock_customer.return_value.update({
'uuid': 'real-ent-uuid',
'name': 'Dummy Enterprise',
'identity_provider': 'saml-ubc'
})
mock_auth_provider.return_value.sync_learner_profile_data = is_synch_learner_profile_data
with self.assertRaises(AccountValidationError) as validation_error:
update_account_settings(self.user, update_data)
field_errors = validation_error.exception.field_errors
self.assertEqual("This field is not editable via this API", field_errors[field_name]["developer_message"])
update_data = {field_name_value[0]: field_name_value[1]}
# prevent actual email change requests
with patch('openedx.core.djangoapps.user_api.accounts.api.student_views.do_email_change_request'):
# expect field un-editability only when both of the following conditions are met
if is_enterprise_user and is_synch_learner_profile_data:
with self.assertRaises(AccountValidationError) as validation_error:
update_account_settings(self.user, update_data)
field_errors = validation_error.exception.field_errors
self.assertEqual(
"This field is not editable via this API",
field_errors[field_name_value[0]]["developer_message"],
)
else:
update_account_settings(self.user, update_data)
account_settings = get_account_settings(self.default_request)[0]
if field_name_value[0] != "email":
self.assertEqual(field_name_value[1], account_settings[field_name_value[0]])
def test_update_error_validating(self):
"""Test that AccountValidationError is thrown if incorrect values are supplied."""

View File

@@ -242,22 +242,13 @@ def update_account_settings_context_for_enterprise(context, enterprise_customer)
"""
enterprise_context = {
'enterprise_name': None,
'sync_learner_profile_data': False,
'enterprise_name': enterprise_customer['name'] if enterprise_customer else None,
'sync_learner_profile_data': _get_sync_learner_profile_data(enterprise_customer),
'edx_support_url': configuration_helpers.get_value('SUPPORT_SITE_LINK', settings.SUPPORT_SITE_LINK),
'enterprise_readonly_account_fields': {
'fields': settings.ENTERPRISE_READONLY_ACCOUNT_FIELDS
}
}
if enterprise_customer:
enterprise_context['enterprise_name'] = enterprise_customer['name']
identity_provider = third_party_auth.provider.Registry.get(
provider_id=enterprise_customer['identity_provider'],
)
if identity_provider:
enterprise_context['sync_learner_profile_data'] = identity_provider.sync_learner_profile_data
context.update(enterprise_context)
@@ -265,7 +256,27 @@ def get_enterprise_readonly_account_fields(user):
"""
Returns a set of account fields that are read-only for enterprise users.
"""
return set(settings.ENTERPRISE_READONLY_ACCOUNT_FIELDS) if is_enterprise_learner(user) else set()
# TODO circular dependency between enterprise_support.api and enterprise_support.utils
from openedx.features.enterprise_support.api import get_enterprise_customer_for_learner
enterprise_customer = get_enterprise_customer_for_learner(user)
sync_learner_profile_data = _get_sync_learner_profile_data(enterprise_customer)
return set(settings.ENTERPRISE_READONLY_ACCOUNT_FIELDS) if sync_learner_profile_data else set()
def _get_sync_learner_profile_data(enterprise_customer):
"""
Returns whether the configuration of the given enterprise customer supports
synching learner profile data.
"""
if enterprise_customer:
identity_provider = third_party_auth.provider.Registry.get(
provider_id=enterprise_customer['identity_provider'],
)
if identity_provider:
return identity_provider.sync_learner_profile_data
return False
def get_enterprise_learner_generic_name(request):
@@ -278,6 +289,7 @@ def get_enterprise_learner_generic_name(request):
# Prevent a circular import. This function makes sense to be in this module though. And see function description.
from openedx.features.enterprise_support.api import enterprise_customer_for_request
enterprise_customer = enterprise_customer_for_request(request)
return (
enterprise_customer['name'] + 'Learner'
if enterprise_customer and enterprise_customer['replace_sensitive_sso_username']