diff --git a/lms/envs/common.py b/lms/envs/common.py index e21b9e87d81151e3b9c0fc4932f72db2c5a8a8aa..e0aa467b3a8db4a4235c2fa0be78cf9e7f5dbd59 100644 --- a/lms/envs/common.py +++ b/lms/envs/common.py @@ -3902,6 +3902,7 @@ ACCOUNT_VISIBILITY_CONFIGURATION["admin_fields"] = ( "secondary_email_enabled", "year_of_birth", "phone_number", + "activation_key", ] ) diff --git a/openedx/core/djangoapps/user_api/accounts/serializers.py b/openedx/core/djangoapps/user_api/accounts/serializers.py index b3e1070702274921a15766773cad67a3fd7fd931..1569fcfaab34059a6edb893f422507e38c2a0fa1 100644 --- a/openedx/core/djangoapps/user_api/accounts/serializers.py +++ b/openedx/core/djangoapps/user_api/accounts/serializers.py @@ -123,6 +123,11 @@ class UserReadOnlySerializer(serializers.Serializer): # lint-amnesty, pylint: d except ObjectDoesNotExist: account_recovery = None + try: + activation_key = user.registration.activation_key + except ObjectDoesNotExist: + activation_key = None + accomplishments_shared = badges_enabled() data = { "username": user.username, @@ -138,6 +143,7 @@ class UserReadOnlySerializer(serializers.Serializer): # lint-amnesty, pylint: d "date_joined": user.date_joined.replace(microsecond=0), "last_login": user.last_login, "is_active": user.is_active, + "activation_key": activation_key, "bio": None, "country": None, "state": None, diff --git a/openedx/core/djangoapps/user_api/accounts/tests/test_api.py b/openedx/core/djangoapps/user_api/accounts/tests/test_api.py index ca2d5968eb4d6247209c8d9a610c0dd19314f789..79a52e409bd2ef651fb6c360c67c6df1faf9561a 100644 --- a/openedx/core/djangoapps/user_api/accounts/tests/test_api.py +++ b/openedx/core/djangoapps/user_api/accounts/tests/test_api.py @@ -508,14 +508,12 @@ class AccountSettingsOnCreationTest(CreateAccountMixin, TestCase): USERNAME = 'frank-underwood' PASSWORD = 'ṕáśśẃőŕd' EMAIL = 'frank+underwood@example.com' - ID = -1 def test_create_account(self): # Create a new account, which should have empty account settings by default. self.create_account(self.USERNAME, self.PASSWORD, self.EMAIL) # Retrieve the account settings user = User.objects.get(username=self.USERNAME) - self.ID = user.id request = RequestFactory().get("/api/user/v1/accounts/") request.user = user account_settings = get_account_settings(request)[0] @@ -530,8 +528,9 @@ class AccountSettingsOnCreationTest(CreateAccountMixin, TestCase): assert account_settings == { 'username': self.USERNAME, 'email': self.EMAIL, - 'id': self.ID, + 'id': user.id, 'name': self.USERNAME, + 'activation_key': user.registration.activation_key, 'gender': None, 'goals': '', 'is_active': False, 'level_of_education': None, diff --git a/openedx/core/djangoapps/user_api/accounts/tests/test_views.py b/openedx/core/djangoapps/user_api/accounts/tests/test_views.py index 73214cee1112269d62eb9e842e40d016aa8ab301..c748cc7e0797037d819c32e1ea43a7797931eae7 100644 --- a/openedx/core/djangoapps/user_api/accounts/tests/test_views.py +++ b/openedx/core/djangoapps/user_api/accounts/tests/test_views.py @@ -23,7 +23,7 @@ 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 common.djangoapps.student.models import PendingEmailChange, UserProfile -from common.djangoapps.student.tests.factories import TEST_PASSWORD, UserFactory +from common.djangoapps.student.tests.factories import TEST_PASSWORD, UserFactory, RegistrationFactory from .. import ALL_USERS_VISIBILITY, CUSTOM_VISIBILITY, PRIVATE_VISIBILITY @@ -126,6 +126,12 @@ class UserAPITestCase(APITestCase): legacy_profile.phone_number = "+18005555555" legacy_profile.save() + def create_user_registration(self, user): + """ + Helper method that creates a registration object for the specified user + """ + RegistrationFactory(user=user) + def _verify_profile_image_data(self, data, has_profile_image): """ Verify the profile image data in a GET response for self.user @@ -275,7 +281,7 @@ class TestAccountsAPI(CacheIsolationTestCase, UserAPITestCase): Verify that all account fields are returned (even those that are not shareable). """ data = response.data - assert 27 == len(data) + assert 28 == len(data) # public fields (3) expected_account_privacy = ( @@ -298,7 +304,7 @@ class TestAccountsAPI(CacheIsolationTestCase, UserAPITestCase): assert data['accomplishments_shared'] is not None assert ((self.user.first_name + ' ') + self.user.last_name) == data['name'] - # additional admin fields (11) + # additional admin fields (12) assert self.user.email == data['email'] assert self.user.id == data['id'] assert data['extended_profile'] is not None @@ -341,6 +347,24 @@ class TestAccountsAPI(CacheIsolationTestCase, UserAPITestCase): response = client.get(reverse("accounts_api", kwargs={'username': "does_not_exist"})) assert 404 == response.status_code + @ddt.data( + ("client", "user"), + ) + @ddt.unpack + def test_regsitration_activation_key(self, api_client, user): + """ + Test that registration activation key has a value. + + UserFactory does not auto-generate registration object for the test users. + It is created only for users that signup via email/API. Therefore, activation key has to be tested manually. + """ + self.create_user_registration(self.user) + + client = self.login_client(api_client, user) + response = self.send_get(client) + + assert response.data["activation_key"] is not None + @ddt.data( ("client", "user"), ("staff_client", "staff_user"), @@ -389,7 +413,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(24): + with self.assertNumQueries(25): response = self.send_get(self.different_client) self._verify_full_shareable_account_response(response, account_privacy=ALL_USERS_VISIBILITY) @@ -404,7 +428,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(24): + with self.assertNumQueries(25): response = self.send_get(self.different_client) self._verify_private_account_response(response) @@ -530,7 +554,7 @@ class TestAccountsAPI(CacheIsolationTestCase, UserAPITestCase): with self.assertNumQueries(queries): response = self.send_get(self.client) data = response.data - assert 27 == len(data) + assert 28 == len(data) assert self.user.username == data['username'] assert ((self.user.first_name + ' ') + self.user.last_name) == data['name'] for empty_field in ("year_of_birth", "level_of_education", "mailing_address", "bio"): @@ -553,12 +577,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(22) + verify_get_own_information(23) # 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(14) + verify_get_own_information(15) def test_get_account_empty_string(self): """ @@ -573,7 +597,7 @@ class TestAccountsAPI(CacheIsolationTestCase, UserAPITestCase): legacy_profile.save() self.client.login(username=self.user.username, password=TEST_PASSWORD) - with self.assertNumQueries(22): + with self.assertNumQueries(23): response = self.send_get(self.client) for empty_field in ("level_of_education", "gender", "country", "state", "bio",): assert response.data[empty_field] is None @@ -929,7 +953,7 @@ class TestAccountsAPI(CacheIsolationTestCase, UserAPITestCase): response = self.send_get(client) if has_full_access: data = response.data - assert 27 == len(data) + assert 28 == len(data) assert self.user.username == data['username'] assert ((self.user.first_name + ' ') + self.user.last_name) == data['name'] assert self.user.email == data['email'] diff --git a/openedx/core/djangoapps/user_api/accounts/views.py b/openedx/core/djangoapps/user_api/accounts/views.py index 96db1c0ea214cf86263a1771aa6380c2befe4e15..24bee3b55ab05c64322e6bb8a0d447ab20c0ec79 100644 --- a/openedx/core/djangoapps/user_api/accounts/views.py +++ b/openedx/core/djangoapps/user_api/accounts/views.py @@ -170,6 +170,7 @@ class AccountViewSet(ViewSet): values. * id: numerical lms user id in db + * activation_key: auto-genrated activation key when signed up via email * bio: null or textual representation of user biographical information ("about me"). * country: An ISO 3166 country code or null.