def test_post_user_list_with_existing_account(self): """POSTing to the user-list with username/email for an existing account should fail to create a new user, but should return an http 400 response. """ # Generate an existing user. user = { "email": "*****@*****.**", "first_name": "F", "last_name": "L" } user['username'] = user_utils.username_hash(user['email']) user = self.User.objects.create(**user) url = reverse('user-list') expected_error = "This user account already exists." # First try to create with an existing email data = {'email': user.email, 'password': '******'} response = self.client.post(url, data) self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) self.assertContains(response, expected_error, status_code=400) # Then with an existing username data = {'username': user.username, 'password': '******'} response = self.client.post(url, data) self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
def _generate_username(self, data): """NOTE: We allow users to sign up with an email/password pair. This method will generate a (hopefully unique) username hash using the email address (the first 30 chars from an md5 hex digest). """ if not data.get('username', False) and 'email' in data: data['username'] = user_utils.username_hash(data['email']) return data
def create_account(request): """Yet another way to create an account.""" if request.method == "POST": form = UserForm(request.POST) password_form = SetNewPasswordForm(request.POST, prefix="pw") if form.is_valid() and password_form.is_valid(): User = get_user_model() email = form.cleaned_data['email'].strip().lower() try: # Ensure the email isn't already tied to an account user = User.objects.get(email__iexact=email) messages.info( request, "It looks like you already have an " "account! Log in to continue.") return redirect("officehours:login") except User.DoesNotExist: # Create & activate the account # XXX This is a hack to keep these users from getting the # XXX `selected_by_default` content from the `goals` app. # XXX We *must* set this before we craete the user, hence the # XXX use of the email in the key. _key = "omit-default-selections-{}".format(slugify(email)) cache.set(_key, True, 30) user = form.save(commit=False) user.is_active = True user.username = username_hash(email) user.set_password(password_form.cleaned_data['password']) user.save() # Set their IP address. user.userprofile.ip_address = get_client_ip(request) user.userprofile.save() user = authenticate( email=email, password=password_form.cleaned_data['password']) login_user(request, user) return redirect("officehours:index") else: messages.error( request, "We could not process your request. " "Please see the details, below.") else: password_form = SetNewPasswordForm(prefix='pw') form = UserForm() context = { 'form': form, 'password_form': password_form, } return render(request, "officehours/create_account.html", context)
def validate_email(self, value): """Validate several things, given a user's email: * this is a valid email address * there are no existing users with this email * there are no users with a username hashed from this email """ User = get_user_model() criteria = (Q(email=value) | Q(username=user_utils.username_hash(value))) if not self.partial and User.objects.filter(criteria).exists(): raise serializers.ValidationError("This user account already exists.") validators.validate_email(value) return value
def test_post_oauth_create_when_authenticated(self): """Authenticated POSTs should return the user's data.""" # Create a test user. User = get_user_model() email = '*****@*****.**' user = User.objects.create(username=username_hash(email), email=email) profile = UserProfile.objects.get(user=user) profile.google_token = "A-TOKEN-STRING" profile.save() url = self.get_url("user-oauth") payload = { 'email': email, 'first_name': 'Existing', 'last_name': 'User', 'image_url': 'http://example.com/avatar.jpg', 'oauth_token': 'A-TOKEN-STRING', } with patch('userprofile.api.verify_token') as mock_verify: mock_verify.return_value = 'A-TOKEN-STRING' response = self.client.post(url, payload) self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual(response.data['email'], '*****@*****.**') # No data was updated, we're only returning existing info. self.assertEqual(response.data['first_name'], 'Existing') self.assertEqual(response.data['last_name'], 'User') self.assertEqual(response.data['google_image'], 'http://example.com/avatar.jpg') self.assertEqual(response.data['google_token'], 'A-TOKEN-STRING') self.assertEqual(response.data['token'], user.auth_token.key) # Clean up profile.delete() user.delete()
def test_post_user_list_with_existing_account_email_as_username(self): """POSTing to the user-list with the email address for an existing account (even if provided as the username) should fail to create a new user, but should return an http 400 response. """ # Generate an existing user. user = { "email": "*****@*****.**", "first_name": "F", "last_name": "L" } user['username'] = user_utils.username_hash(user['email']) user = self.User.objects.create(**user) url = self.get_url('user-list') expected_error = "This user account already exists." # First try to create this account, but include the email in the # username field. data = {'username': user.email, 'password': '******'} response = self.client.post(url, data) self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) self.assertContains(response, expected_error, status_code=400)
def oauth_create(self, request, pk=None): """GET: List the current user's profile / google details. POST: Create the user if they don't already exist and return their profile details. The POST payload should include the following: { 'email': '...', 'first_name': '...', 'last_name': '...', 'image_url': '...', 'oauth_token': '...', } Of the above values, the `email` and `oauth_token` fields are required. """ content = {} authed = request.user.is_authenticated() user = request.user if authed else None result_status = status.HTTP_200_OK # Not authenticated, return empty list. if not authed and request.method == 'GET': return Response(content, status=result_status) # Not authenticated & this is a POST: get or create the user. elif not authed and request.method == "POST": User = get_user_model() try: data = request.data # Verify the given token info: https://goo.gl/MIKN9X token = verify_token(data.get('oauth_token')) if token is None: return Response( data={'error': 'Invalid auth token'}, status=status.HTTP_400_BAD_REQUEST ) # Note: email + (a verified) token serves as username + password. email = data.get('email').strip().lower() # XXX This is a hack to keep these users from getting the # XXX `selected_by_default` content from the `goals` app. # XXX We *must* set this before we craete the user, hence the # XXX use of the email in the key. _key = "omit-default-selections-{}".format(slugify(email)) cache.set(_key, True, 30) # XXX The only unique thing about user accounts is email. created = False try: user = User.objects.get(email__iexact=email) except User.DoesNotExist: user = User.objects.create( email=email, username=username_hash(email) ) created = True # Update the Profile fields. profile = user.userprofile profile.google_token = token # This will change periodically profile.google_image = data.get('image_url', '') profile.app_logins += 1 if created: # Save the IP address on the user's profile try: profile.ip_address = get_client_ip(request) except: # XXX: Don't let any exception prevent signup. pass profile.save() # Update user fields. if not user.username: user.username = username_hash(email) user.first_name = data.get('first_name', '') user.last_name = data.get('last_name', '') user.is_active = True # Auto-activate accounts from Google user.save() if created: result_status = status.HTTP_201_CREATED else: result_status = status.HTTP_200_OK except Exception as err: # Log the traceback. exc_type, exc_value, exc_traceback = sys.exc_info() tb = traceback.format_exception(exc_type, exc_value, exc_traceback) tb_string = "{}\n".format("\n".join(tb)) logger.error(tb_string) return Response( data={'error': '{}'.format(err)}, status=status.HTTP_400_BAD_REQUEST ) if user: content = { 'id': user.id, 'profile_id': user.userprofile.id, 'email': user.email, 'first_name': user.first_name, 'last_name': user.last_name, 'google_image': user.userprofile.google_image, 'google_token': user.userprofile.google_token, 'phone': user.userprofile.phone, 'token': user.auth_token.key, 'needs_onboarding': user.userprofile.needs_onboarding, } return Response(content, status=result_status)