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 72c03d0f8e..91dc74468b 100644 --- a/openedx/core/djangoapps/user_api/accounts/tests/test_views.py +++ b/openedx/core/djangoapps/user_api/accounts/tests/test_views.py @@ -112,28 +112,6 @@ class UserAPITestCase(APITestCase): legacy_profile.language_proficiencies.add(LanguageProficiency(code='en')) legacy_profile.save() - -@ddt.ddt -@unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Account APIs are only supported in LMS') -@patch('openedx.core.djangoapps.user_api.accounts.image_helpers._PROFILE_IMAGE_SIZES', [50, 10]) -@patch.dict( - 'openedx.core.djangoapps.user_api.accounts.image_helpers.PROFILE_IMAGE_SIZES_MAP', - {'full': 50, 'small': 10}, - clear=True -) -@attr(shard=2) -class TestAccountAPI(CacheIsolationTestCase, UserAPITestCase): - """ - Unit tests for the Account API. - """ - - ENABLED_CACHES = ['default'] - - def setUp(self): - super(TestAccountAPI, self).setUp() - - self.url = reverse("accounts_api", kwargs={'username': self.user.username}) - def _verify_profile_image_data(self, data, has_profile_image): """ Verify the profile image data in a GET response for self.user @@ -160,6 +138,81 @@ class TestAccountAPI(CacheIsolationTestCase, UserAPITestCase): } ) + +@ddt.ddt +@unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Account APIs are only supported in LMS') +@attr(shard=2) +class TestOwnUsernameAPI(CacheIsolationTestCase, UserAPITestCase): + """ + Unit tests for the Accounts API. + """ + + ENABLED_CACHES = ['default'] + + def setUp(self): + super(TestOwnUsernameAPI, self).setUp() + + self.url = reverse("own_username_api") + + def _verify_get_own_username(self, queries, expected_status=200): + """ + Internal helper to perform the actual assertion + """ + with self.assertNumQueries(queries): + response = self.send_get(self.client, expected_status=expected_status) + if expected_status == 200: + data = response.data + self.assertEqual(1, len(data)) + self.assertEqual(self.user.username, data["username"]) + + def test_get_username(self): + """ + Test that a client (logged in) can get her own username. + """ + self.client.login(username=self.user.username, password=self.test_password) + self._verify_get_own_username(15) + + def test_get_username_inactive(self): + """ + Test that a logged-in client can get their + username, even if inactive. + """ + self.client.login(username=self.user.username, password=self.test_password) + self.user.is_active = False + self.user.save() + self._verify_get_own_username(15) + + def test_get_username_not_logged_in(self): + """ + Test that a client (not logged in) gets a 401 + when trying to retrieve their username. + """ + + # verify that the endpoint is inaccessible when not logged in + self._verify_get_own_username(12, expected_status=401) + + +@ddt.ddt +@unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Account APIs are only supported in LMS') +@patch('openedx.core.djangoapps.user_api.accounts.image_helpers._PROFILE_IMAGE_SIZES', [50, 10]) +@patch.dict( + 'openedx.core.djangoapps.user_api.accounts.image_helpers.PROFILE_IMAGE_SIZES_MAP', + {'full': 50, 'small': 10}, + clear=True +) +@attr(shard=2) +class TestAccountsAPI(CacheIsolationTestCase, UserAPITestCase): + """ + Unit tests for the Accounts API. + """ + + ENABLED_CACHES = ['default'] + + def setUp(self): + super(TestAccountsAPI, self).setUp() + + self.url = reverse("accounts_api", kwargs={'username': self.user.username}) + def _verify_full_shareable_account_response(self, response, account_privacy=None, badges_enabled=False): """ Verify that the shareable fields from the account are returned @@ -311,6 +364,7 @@ class TestAccountAPI(CacheIsolationTestCase, UserAPITestCase): Test that a client (logged in) can get her own account information (using default legacy profile information, as created by the test UserFactory). """ + def verify_get_own_information(queries): """ Internal helper to perform the actual assertions diff --git a/openedx/core/djangoapps/user_api/accounts/views.py b/openedx/core/djangoapps/user_api/accounts/views.py index a95a1b6646..a74b1834d3 100644 --- a/openedx/core/djangoapps/user_api/accounts/views.py +++ b/openedx/core/djangoapps/user_api/accounts/views.py @@ -29,12 +29,22 @@ class AccountViewSet(ViewSet): **Example Requests** + GET /api/user/v1/me[?view=shared] GET /api/user/v1/accounts?usernames={username1,username2}[?view=shared] GET /api/user/v1/accounts/{username}/[?view=shared] PATCH /api/user/v1/accounts/{username}/{"key":"value"} "application/merge-patch+json" - **Response Values for GET** + **Response Values for GET requests to the /me endpoint** + If the user is not logged in, an HTTP 401 "Not Authorized" response + is returned. + + Otherwise, an HTTP 200 "OK" response is returned. The response + contains the following value: + + * username: The username associated with the account. + + **Response Values for GET requests to /accounts endpoints** If no user exists with the specified username, an HTTP 404 "Not Found" response is returned. @@ -147,6 +157,12 @@ class AccountViewSet(ViewSet): permission_classes = (permissions.IsAuthenticated,) parser_classes = (MergePatchParser,) + def get(self, request): + """ + GET /api/user/v1/me + """ + return Response({'username': request.user.username}) + def list(self, request): """ GET /api/user/v1/accounts?username={username1,username2} diff --git a/openedx/core/djangoapps/user_api/urls.py b/openedx/core/djangoapps/user_api/urls.py index 8aa44ad9ec..d390ea11f2 100644 --- a/openedx/core/djangoapps/user_api/urls.py +++ b/openedx/core/djangoapps/user_api/urls.py @@ -10,6 +10,9 @@ from .accounts.views import AccountViewSet from .preferences.views import PreferencesView, PreferencesDetailView from .verification_api.views import PhotoVerificationStatusView +ME = AccountViewSet.as_view({ + 'get': 'get', +}) ACCOUNT_LIST = AccountViewSet.as_view({ 'get': 'list', @@ -22,6 +25,7 @@ ACCOUNT_DETAIL = AccountViewSet.as_view({ urlpatterns = patterns( '', + url(r'^v1/me$', ME, name='own_username_api'), url(r'^v1/accounts/{}$'.format(settings.USERNAME_PATTERN), ACCOUNT_DETAIL, name='accounts_api'), url(r'^v1/accounts$', ACCOUNT_LIST, name='accounts_detail_api'), url(