From 4d6f34ac743bade893eb903bbd95e4dfabc64af4 Mon Sep 17 00:00:00 2001 From: Bob Silverberg Date: Tue, 1 Sep 2015 15:45:02 -0400 Subject: [PATCH] Bug 1050417 - Remove One and Done User REST API --- oneanddone/settings/base.py | 2 +- oneanddone/tasks/mixins.py | 1 + oneanddone/tasks/views.py | 1 + oneanddone/users/serializers.py | 30 ------- oneanddone/users/tests/test_api.py | 135 ----------------------------- oneanddone/users/urls.py | 7 +- oneanddone/users/views.py | 24 +---- 7 files changed, 7 insertions(+), 193 deletions(-) delete mode 100644 oneanddone/users/serializers.py delete mode 100644 oneanddone/users/tests/test_api.py diff --git a/oneanddone/settings/base.py b/oneanddone/settings/base.py index 7c927582..ef968b62 100644 --- a/oneanddone/settings/base.py +++ b/oneanddone/settings/base.py @@ -323,7 +323,7 @@ def JINJA_CONFIG(): LESS_BIN = config('LESSC_BIN', default='lessc') # Testing configuration. -NOSE_ARGS = ['--logging-clear-handlers', '--logging-filter=-factory,-south'] +NOSE_ARGS = ['--logging-clear-handlers', '--logging-filter=-factory,-south,-django.db'] # Should robots.txt deny everything or disallow a calculated list of URLs we # don't want to be crawled? Default is false, disallow everything. diff --git a/oneanddone/tasks/mixins.py b/oneanddone/tasks/mixins.py index f4f575c3..dfc6b462 100644 --- a/oneanddone/tasks/mixins.py +++ b/oneanddone/tasks/mixins.py @@ -1,6 +1,7 @@ # This Source Code Form is subject to the terms of the Mozilla Public # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at http://mozilla.org/MPL/2.0/. + from django.core.exceptions import PermissionDenied from django.http import Http404 from django.shortcuts import get_object_or_404 diff --git a/oneanddone/tasks/views.py b/oneanddone/tasks/views.py index a4e9ec0a..20d55f92 100644 --- a/oneanddone/tasks/views.py +++ b/oneanddone/tasks/views.py @@ -1,6 +1,7 @@ # This Source Code Form is subject to the terms of the Mozilla Public # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at http://mozilla.org/MPL/2.0/. + from django.contrib import messages from django.core.urlresolvers import reverse from django.forms.models import model_to_dict diff --git a/oneanddone/users/serializers.py b/oneanddone/users/serializers.py deleted file mode 100644 index 63eb2adf..00000000 --- a/oneanddone/users/serializers.py +++ /dev/null @@ -1,30 +0,0 @@ -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -from django.contrib.auth.models import User - -from rest_framework import serializers - -from oneanddone.users.models import UserProfile - - -class UserProfileSerializer(serializers.ModelSerializer): - - class Meta: - model = UserProfile - fields = ('name', 'username', 'privacy_policy_accepted') - - -class UserSerializer(serializers.ModelSerializer): - profile = UserProfileSerializer(required=False, many=False) - - class Meta: - model = User - fields = ('id', 'username', 'email', 'groups', 'profile') - - def create(self, validated_data): - profile_data = validated_data.pop('profile') - user = User.objects.create(**validated_data) - UserProfile.objects.create(user=user, **profile_data) - return user diff --git a/oneanddone/users/tests/test_api.py b/oneanddone/users/tests/test_api.py deleted file mode 100644 index 30626e9c..00000000 --- a/oneanddone/users/tests/test_api.py +++ /dev/null @@ -1,135 +0,0 @@ -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. -import random -import json - -from django.contrib.auth.models import Permission - -from rest_framework import status -from rest_framework.test import APITestCase -from rest_framework.reverse import reverse -from rest_framework.authtoken.models import Token -from nose.tools import eq_ - -from oneanddone.users.tests import UserFactory - - -class APITests(APITestCase): - - def assert_response_status(self, response, expected_status): - eq_(response.status_code, expected_status, - "Test Failed, got response status: %s, expected status: %s" % - (response.status_code, expected_status)) - - def setUp(self): - self.client_user = UserFactory.create() - - # Add add/change/delete user permission for client - delete_permission = Permission.objects.get(codename='delete_user') - add_permission = Permission.objects.get(codename='add_user') - change_permission = Permission.objects.get(codename='change_user') - self.client_user.user_permissions.add(add_permission, change_permission, - delete_permission) - - self.token = Token.objects.create(user=self.client_user) - self.uri = '/api/v1/user/' - - def test_create_new_user(self): - """ - Test Create new user with Profile Data(name, username and privacy_policy_accepted) - """ - self.client.credentials(HTTP_AUTHORIZATION='Token ' + self.token.key) - user_data = {'username': 'testuser', 'email': 'test@test.com', - 'profile': {'name': 'Test Name', 'username': 'testuser', 'privacy_policy_accepted': True}} - response = self.client.post(self.uri, user_data, format='json') - self.assert_response_status(response, status.HTTP_201_CREATED) - response_data = json.loads(response.content) - eq_(response_data['profile'], user_data['profile']) - - def test_client_with_false_token(self): - """ - Test user list, user details, user deletion for user with false token - """ - invalid_key = 'd81e33c57b2d9471f4d6849bab3cb233b3b30468' - false_token = ''.join(random.sample(invalid_key, len(invalid_key))) - - self.client.credentials(HTTP_AUTHORIZATION='Token ' + false_token) - - response = self.client.get(reverse('api-user')) - self.assert_response_status(response, status.HTTP_401_UNAUTHORIZED) - - test_user = UserFactory.create() - user_uri = self.uri + test_user.email + '/' - - get_response = self.client.get(user_uri) - self.assert_response_status(get_response, status.HTTP_401_UNAUTHORIZED) - - delete_response = self.client.delete(user_uri) - self.assert_response_status(delete_response, status.HTTP_401_UNAUTHORIZED) - - def test_delete_user(self): - """ - Test DELETE user with particular email for authenticated user - """ - self.client.credentials(HTTP_AUTHORIZATION='Token ' + self.token.key) - test_user = UserFactory.create() - user_uri = self.uri + test_user.email + '/' - - # Make a DELETE request - delete_response = self.client.delete(user_uri) - self.assert_response_status(delete_response, status.HTTP_204_NO_CONTENT) - - # Verify that the user has been deleted - get_response = self.client.get(user_uri) - self.assert_response_status(get_response, status.HTTP_404_NOT_FOUND) - - def test_forbidden_client(self): - """ - Test user deletion by an authenticated but forbidden client - """ - forbidden_user = UserFactory.create() - forbidden_token = Token.objects.create(user=forbidden_user) - - self.client.credentials(HTTP_AUTHORIZATION='Token ' + forbidden_token.key) - - test_user = UserFactory.create() - user_uri = self.uri + test_user.email + '/' - - # Make a DELETE request - delete_response = self.client.delete(user_uri) - self.assert_response_status(delete_response, status.HTTP_403_FORBIDDEN) - - def test_get_user_details(self): - """ - Test GET details of a user with particular email for authenticated user - """ - self.client.credentials(HTTP_AUTHORIZATION='Token ' + self.token.key) - test_user = UserFactory.create() - user_uri = self.uri + test_user.email + '/' - response = self.client.get(user_uri) - self.assert_response_status(response, status.HTTP_200_OK) - - def test_get_user_list(self): - """ - Test GET user list for authenticated user - """ - header = {'HTTP_AUTHORIZATION': 'Token {}'.format(self.token)} - response = self.client.get(reverse('api-user'), {}, **header) - self.assert_response_status(response, status.HTTP_200_OK) - - def test_unauthenticated_client(self): - """ - Test user list, user details, user deletion for unauthenticated user - """ - response = self.client.get(reverse('api-user')) - self.assert_response_status(response, status.HTTP_401_UNAUTHORIZED) - - test_user = UserFactory.create() - user_uri = self.uri + test_user.email + '/' - - get_response = self.client.get(user_uri) - self.assert_response_status(get_response, status.HTTP_401_UNAUTHORIZED) - - delete_response = self.client.delete(user_uri) - self.assert_response_status(delete_response, status.HTTP_401_UNAUTHORIZED) diff --git a/oneanddone/users/urls.py b/oneanddone/users/urls.py index 58fb4f80..c455d2f4 100644 --- a/oneanddone/users/urls.py +++ b/oneanddone/users/urls.py @@ -6,7 +6,8 @@ from oneanddone.users import views -urlpatterns = patterns('', +urlpatterns = patterns( + '', url(r'^login/$', views.LoginView.as_view(), name='users.login'), url(r'^profile/new/$', views.CreateProfileView.as_view(), name='users.profile.create'), url(r'^profile/edit/$', views.UpdateProfileView.as_view(), name='users.profile.update'), @@ -14,8 +15,4 @@ url(r'^profile/$', views.MyProfileDetailsView.as_view(), name='users.profile.mydetails'), url(r'^profile/(?P\d+)/$', views.ProfileDetailsView.as_view(), name='users.profile.details'), url(r'^profile/(?P[^/\\]+)/$', views.ProfileDetailsView.as_view(), name='users.profile.details'), - - # API URL's for interacting with User objects - url(r'^api/v1/user/$', views.UserListAPI.as_view(), name='api-user'), - url(r'^api/v1/user/(?P[^/\\]+)/$', views.UserDetailAPI.as_view(), name='api-user-detail'), ) diff --git a/oneanddone/users/views.py b/oneanddone/users/views.py index 4779cd5e..9b813aa2 100644 --- a/oneanddone/users/views.py +++ b/oneanddone/users/views.py @@ -1,27 +1,25 @@ # This Source Code Form is subject to the terms of the Mozilla Public # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at http://mozilla.org/MPL/2.0/. + from django.contrib import messages -from django.contrib.auth.models import User from django.core.exceptions import ObjectDoesNotExist, MultipleObjectsReturned from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger from django.http import Http404 from django.shortcuts import redirect from django.views import generic -from rest_framework import generics from braces.views import LoginRequiredMixin import django_browserid.views -from tower import ugettext as _ from random import randint import re +from tower import ugettext as _ from oneanddone.base.urlresolvers import reverse_lazy from oneanddone.tasks.models import TaskAttempt from oneanddone.users.forms import UserProfileForm, SignUpForm from oneanddone.users.mixins import UserProfileRequiredMixin from oneanddone.users.models import UserProfile -from serializers import UserSerializer def default_username(email, counter): @@ -155,21 +153,3 @@ def login_failure(self, *args, **kwargs): logging in, let us know by emailing {email}. """).format(email='oneanddone@mozilla.com'), extra_tags='safe') return super(Verify, self).login_failure(*args, **kwargs) - - -class UserDetailAPI(generics.RetrieveDestroyAPIView): - """ - API endpoint used to get and delete user data. - """ - lookup_field = 'email' - queryset = User.objects.all() - serializer_class = UserSerializer - - -class UserListAPI(generics.ListCreateAPIView): - """ - API endpoint used to get a complete list of users - and create a new user. - """ - queryset = User.objects.all() - serializer_class = UserSerializer