Merge pull request #29952 from openedx/bseverino/name-affirmation-plugin

[MST-1360] Only enable verified name feature if Name Affirmation is installed
This commit is contained in:
Bianca Severino
2022-02-23 09:18:44 -05:00
committed by GitHub
14 changed files with 188 additions and 56 deletions

View File

@@ -11,7 +11,6 @@ from django.core.exceptions import ObjectDoesNotExist
from django.core.validators import ValidationError, validate_email
from django.utils.translation import override as override_language
from django.utils.translation import gettext as _
from edx_name_affirmation.name_change_validator import NameChangeValidator
from pytz import UTC
from common.djangoapps.student import views as student_views
from common.djangoapps.student.models import (
@@ -38,8 +37,14 @@ from openedx.core.djangoapps.user_authn.utils import check_pwned_password
from openedx.core.djangoapps.user_authn.views.registration_form import validate_name, validate_username
from openedx.core.lib.api.view_utils import add_serializer_errors
from openedx.features.enterprise_support.utils import get_enterprise_readonly_account_fields
from openedx.features.name_affirmation_api.utils import is_name_affirmation_installed
from .serializers import AccountLegacyProfileSerializer, AccountUserSerializer, UserReadOnlySerializer, _visible_fields
name_affirmation_installed = is_name_affirmation_installed()
if name_affirmation_installed:
# pylint: disable=import-error
from edx_name_affirmation.name_change_validator import NameChangeValidator
# Public access point for this function.
visible_fields = _visible_fields
@@ -274,6 +279,9 @@ def _does_name_change_require_verification(user_profile, old_name, new_name):
"""
If name change requires ID verification, do not update it through this API.
"""
if not name_affirmation_installed:
return False
profile_meta = user_profile.get_meta()
old_names_list = profile_meta['old_names'] if 'old_names' in profile_meta else []

View File

@@ -11,7 +11,6 @@ from django.conf import settings
from django.contrib.auth.models import User # lint-amnesty, pylint: disable=imported-auth-user
from django.core.exceptions import ObjectDoesNotExist
from django.urls import reverse
from edx_name_affirmation.api import get_verified_name
from rest_framework import serializers
@@ -29,6 +28,7 @@ from openedx.core.djangoapps.user_api.accounts.utils import is_secondary_email_f
from openedx.core.djangoapps.user_api.models import RetirementState, UserPreference, UserRetirementStatus
from openedx.core.djangoapps.user_api.serializers import ReadOnlyFieldsSerializerMixin
from openedx.core.djangoapps.user_authn.views.registration_form import contains_html, contains_url
from openedx.features.name_affirmation_api.utils import get_name_affirmation_service
from . import (
ACCOUNT_VISIBILITY_PREF_KEY,
@@ -170,11 +170,10 @@ class UserReadOnlySerializer(serializers.Serializer): # lint-amnesty, pylint: d
"extended_profile_fields": None,
"phone_number": None,
"pending_name_change": None,
"verified_name": None,
}
if user_profile:
verified_name_obj = get_verified_name(user, is_verified=True)
verified_name = verified_name_obj.verified_name if verified_name_obj else None
data.update(
{
"bio": AccountLegacyProfileSerializer.convert_empty_to_None(user_profile.bio),
@@ -187,7 +186,6 @@ class UserReadOnlySerializer(serializers.Serializer): # lint-amnesty, pylint: d
user_profile.language_proficiencies.all().order_by('code'), many=True
).data,
"name": user_profile.name,
"verified_name": verified_name,
"gender": AccountLegacyProfileSerializer.convert_empty_to_None(user_profile.gender),
"goals": user_profile.goals,
"year_of_birth": user_profile.year_of_birth,
@@ -211,6 +209,12 @@ class UserReadOnlySerializer(serializers.Serializer): # lint-amnesty, pylint: d
except PendingNameChange.DoesNotExist:
pass
name_affirmation_service = get_name_affirmation_service()
if name_affirmation_service:
verified_name_obj = name_affirmation_service.get_verified_name(user, is_verified=True)
if verified_name_obj:
data.update({"verified_name": verified_name_obj.verified_name})
if is_secondary_email_feature_enabled():
data.update(
{

View File

@@ -14,8 +14,6 @@ from django.conf import settings
from django.test.testcases import TransactionTestCase
from django.test.utils import override_settings
from django.urls import reverse
from edx_name_affirmation.api import create_verified_name
from edx_name_affirmation.statuses import VerifiedNameStatus
from rest_framework import status
from rest_framework.test import APIClient, APITestCase
@@ -26,6 +24,7 @@ from openedx.core.djangoapps.user_api.accounts import ACCOUNT_VISIBILITY_PREF_KE
from openedx.core.djangoapps.user_api.models import UserPreference
from openedx.core.djangoapps.user_api.preferences.api import set_user_preference
from openedx.core.djangolib.testing.utils import CacheIsolationTestCase, skip_unless_lms
from openedx.features.name_affirmation_api.utils import get_name_affirmation_service
from .. import ALL_USERS_VISIBILITY, CUSTOM_VISIBILITY, PRIVATE_VISIBILITY
@@ -55,6 +54,7 @@ class UserAPITestCase(APITestCase):
self.staff_user = UserFactory(is_staff=True, password=TEST_PASSWORD)
self.staff_client = APIClient()
self.user = UserFactory.create(password=TEST_PASSWORD) # will be assigned to self.client by default
self.name_affirmation_service = get_name_affirmation_service()
def login_client(self, api_client, user):
"""Helper method for getting the client and user and logging in. Returns client. """
@@ -142,9 +142,16 @@ class UserAPITestCase(APITestCase):
def create_mock_verified_name(self, user):
"""
Helper method to create an approved VerifiedName entry in name affirmation.
Will not do anything if Name Affirmation is not installed.
"""
legacy_profile = UserProfile.objects.get(id=user.id)
create_verified_name(user, self.VERIFIED_NAME, legacy_profile.name, status=VerifiedNameStatus.APPROVED)
if self.name_affirmation_service:
legacy_profile = UserProfile.objects.get(id=user.id)
self.name_affirmation_service.create_verified_name(
user,
self.VERIFIED_NAME,
legacy_profile.name,
status='approved'
)
def create_user_registration(self, user):
"""
@@ -152,6 +159,14 @@ class UserAPITestCase(APITestCase):
"""
RegistrationFactory(user=user)
def _get_num_queries(self, num_queries):
"""
If Name Affirmation is installed, it will add an extra query
"""
if self.name_affirmation_service:
return num_queries + 1
return num_queries
def _verify_profile_image_data(self, data, has_profile_image):
"""
Verify the profile image data in a GET response for self.user
@@ -240,7 +255,7 @@ class TestAccountsAPI(CacheIsolationTestCase, UserAPITestCase):
"""
ENABLED_CACHES = ['default']
TOTAL_QUERY_COUNT = 27
TOTAL_QUERY_COUNT = 26
FULL_RESPONSE_FIELD_COUNT = 30
def setUp(self):
@@ -324,7 +339,6 @@ class TestAccountsAPI(CacheIsolationTestCase, UserAPITestCase):
# additional admin fields (13)
assert self.user.email == data['email']
assert self.user.id == data['id']
assert self.VERIFIED_NAME == data['verified_name']
assert data['extended_profile'] is not None
assert 'MA' == data['state']
assert 'f' == data['gender']
@@ -335,6 +349,10 @@ class TestAccountsAPI(CacheIsolationTestCase, UserAPITestCase):
assert data['secondary_email'] is None
assert data['secondary_email_enabled'] is None
assert year_of_birth == data['year_of_birth']
if self.name_affirmation_service:
assert self.VERIFIED_NAME == data['verified_name']
else:
assert data['verified_name'] is None
def test_anonymous_access(self):
"""
@@ -501,7 +519,7 @@ class TestAccountsAPI(CacheIsolationTestCase, UserAPITestCase):
"""
self.different_client.login(username=self.different_user.username, password=TEST_PASSWORD)
self.create_mock_profile(self.user)
with self.assertNumQueries(self.TOTAL_QUERY_COUNT):
with self.assertNumQueries(self._get_num_queries(self.TOTAL_QUERY_COUNT)):
response = self.send_get(self.different_client)
self._verify_full_shareable_account_response(response, account_privacy=ALL_USERS_VISIBILITY)
@@ -516,7 +534,7 @@ class TestAccountsAPI(CacheIsolationTestCase, UserAPITestCase):
"""
self.different_client.login(username=self.different_user.username, password=TEST_PASSWORD)
self.create_mock_profile(self.user)
with self.assertNumQueries(self.TOTAL_QUERY_COUNT):
with self.assertNumQueries(self._get_num_queries(self.TOTAL_QUERY_COUNT)):
response = self.send_get(self.different_client)
self._verify_private_account_response(response)
@@ -667,12 +685,12 @@ class TestAccountsAPI(CacheIsolationTestCase, UserAPITestCase):
assert data['accomplishments_shared'] is False
self.client.login(username=self.user.username, password=TEST_PASSWORD)
verify_get_own_information(25)
verify_get_own_information(self._get_num_queries(24))
# Now make sure that the user can get the same information, even if not active
self.user.is_active = False
self.user.save()
verify_get_own_information(17)
verify_get_own_information(self._get_num_queries(16))
def test_get_account_empty_string(self):
"""
@@ -687,7 +705,7 @@ class TestAccountsAPI(CacheIsolationTestCase, UserAPITestCase):
legacy_profile.save()
self.client.login(username=self.user.username, password=TEST_PASSWORD)
with self.assertNumQueries(25):
with self.assertNumQueries(self._get_num_queries(24)):
response = self.send_get(self.client)
for empty_field in ("level_of_education", "gender", "country", "state", "bio",):
assert response.data[empty_field] is None