Fakultas Ilmu Komputer UI

Commit e0814a85 authored by EMIL's avatar EMIL
Browse files

Merge branch 'testinggoat/ch19' into 'master'

Exercise 8

See merge request !6
parents 5a41de92 64d14dec
import sys
from accounts.models import ListUser, Token
from accounts.models import User, Token
class PasswordlessAuthenticationBackend(object):
def authenticate(self, uid):
print('uid', uid, file=sys.stderr)
if not Token.objects.filter(uid=uid).exists():
print('no token found', file=sys.stderr)
return None
token = Token.objects.get(uid=uid)
print('got token', file=sys.stderr)
def authenticate(self, uid):
try:
user = ListUser.objects.get(email=token.email)
print('got user', file=sys.stderr)
return user
except ListUser.DoesNotExist:
print('new user', file=sys.stderr)
return ListUser.objects.create(email=token.email)
token = Token.objects.get(uid=uid)
return User.objects.get(email=token.email)
except User.DoesNotExist:
return User.objects.create(email=token.email)
except Token.DoesNotExist:
return None
def get_user(self, email):
return ListUser.objects.get(email=email)
\ No newline at end of file
def get_user(self, email):
try:
return User.objects.get(email=email)
except User.DoesNotExist:
return None
\ No newline at end of file
from django.db import models
from django.contrib.auth.models import (
AbstractBaseUser, BaseUserManager, PermissionsMixin
)
import uuid
from django.contrib import auth
from django.db import models
auth.signals.user_logged_in.disconnect(auth.models.update_last_login)
class Token(models.Model):
class User(models.Model):
email = models.EmailField()
uid = models.CharField(max_length=255)
......
from django.test import TestCase
from django.contrib.auth import get_user_model
from accounts.authentication import PasswordlessAuthenticationBackend
from accounts.models import Token
User = get_user_model()
class AuthenticateTest(TestCase):
def test_returns_None_if_no_such_token(self):
result = PasswordlessAuthenticationBackend().authenticate(
'no-such-token'
)
self.assertIsNone(result)
def test_returns_new_user_with_correct_email_if_token_exists(self):
email = 'edith@example.com'
token = Token.objects.create(email=email)
user = PasswordlessAuthenticationBackend().authenticate(token.uid)
new_user = User.objects.get(email=email)
self.assertEqual(user, new_user)
def test_returns_existing_user_with_correct_email_if_token_exists(self):
email = 'edith@example.com'
existing_user = User.objects.create(email=email)
token = Token.objects.create(email=email)
user = PasswordlessAuthenticationBackend().authenticate(token.uid)
self.assertEqual(user, existing_user)
class GetUserTest(TestCase):
def test_gets_user_by_email(self):
User.objects.create(email='another@example.com')
desired_user = User.objects.create(email='edith@example.com')
found_user = PasswordlessAuthenticationBackend().get_user(
'edith@example.com'
)
self.assertEqual(found_user, desired_user)
def test_returns_None_if_no_user_with_that_email(self):
self.assertIsNone(
PasswordlessAuthenticationBackend().get_user('edith@example.com')
)
\ No newline at end of file
from django.test import TestCase
from django.contrib.auth import get_user_model
from django.contrib import auth
from accounts.models import Token
User = get_user_model()
User = auth.get_user_model()
class UserModelTest(TestCase):
......@@ -15,6 +14,12 @@ class UserModelTest(TestCase):
user = User(email='a@b.com')
self.assertEqual(user.pk, 'a@b.com')
def test_no_problem_with_auth_login(self):
user = User.objects.create(email='edith@example.com')
user.backend = ''
request = self.client.request().wsgi_request
auth.login(request, user) # should not raise
class TokenModelTest(TestCase):
......
from django.test import TestCase
from unittest.mock import patch, call
from accounts.models import Token
import accounts.views
@patch('accounts.views.auth')
class LoginViewTest(TestCase):
def test_creates_token_associated_with_email(self):
self.client.post('/accounts/send_login_email', data={
'email': 'edith@example.com'
})
token = Token.objects.first()
self.assertEqual(token.email, 'edith@example.com')
@patch('accounts.views.send_mail')
def test_sends_link_to_login_using_token_uid(self, mock_send_mail):
self.client.post('/accounts/send_login_email', data={
'email': 'edith@example.com'
})
token = Token.objects.first()
expected_url = f'http://testserver/accounts/login?token={token.uid}'
(subject, body, from_email, to_list), kwargs = mock_send_mail.call_args
self.assertIn(expected_url, body)
def test_redirects_to_home_page(self):
response = self.client.post('/accounts/send_login_email', data={
'email': 'edith@example.com'
})
self.assertRedirects(response, '/')
def test_adds_success_message(self):
response = self.client.post('/accounts/send_login_email', data={
'email': 'edith@example.com'
}, follow=True)
message = list(response.context['messages'])[0]
self.assertEqual(
message.message,
"Check your email, we've sent you a link you can use to log in."
)
self.assertEqual(message.tags, "success")
@patch('accounts.views.send_mail')
def test_sends_mail_to_address_from_post(self, mock_send_mail):
self.client.post('/accounts/send_login_email', data={
'email': 'edith@example.com'
})
self.assertEqual(mock_send_mail.called, True)
(subject, body, from_email, to_list), kwargs = mock_send_mail.call_args
self.assertEqual(subject, 'Your login link for Superlists')
self.assertEqual(from_email, 'noreply@superlists')
self.assertEqual(to_list, ['edith@example.com'])
def fake_send_mail(subject, body, from_email, to_list):
self.send_mail_called = True
self.subject = subject
self.body = body
self.from_email = from_email
self.to_list = to_list
accounts.views.send_mail = fake_send_mail
self.client.post('/accounts/send_login_email', data={
'email': 'edith@example.com'
})
self.assertTrue(self.send_mail_called)
self.assertEqual(self.subject, 'Your login link for Superlists')
self.assertEqual(self.from_email, 'noreply@superlists')
self.assertEqual(self.to_list, ['edith@example.com'])
def test_calls_authenticate_with_uid_from_get_request(self, mock_auth):
self.client.get('/accounts/login?token=abcd123')
self.assertEqual(
mock_auth.authenticate.call_args,
((,), {'uid': 'abcd123'})
)
# or this
args, kwargs = mock_auth.authenticate.call_args
self.assertEqual(args, (,))
self.assertEqual(kwargs, {'uid': 'abcd123'}
def test_calls_auth_login_with_user_if_there_is_one(self, mock_auth):
response = self.client.get('/accounts/login?token=abcd123')
self.assertEqual(
mock_auth.login.call_args,
call(response.wsgi_request, mock_auth.authenticate.return_value)
)
def test_does_not_login_if_user_is_not_authenticated(self, mock_auth):
mock_auth.authenticate.return_value = None
self.client.get('/accounts/login?token=abcd123')
self.assertEqual(mock_auth.login.called, False)
\ No newline at end of file
from django.contrib.auth.views import logout
from django.conf.urls import url
from accounts import views
urlpatterns = [
url(r'^send_login_email$', views.send_login_email, name='send_login_email'),
url(r'^login$', views.login, name='login'),
url(r'^logout$', logout, {'next_page': '/'}, name='logout'),
]
\ No newline at end of file
import uuid
import sys
from django.contrib.auth import authenticate
from django.contrib.auth import login as auth_login
from django.core.mail import send_mail
from django.shortcuts import redirect, render
from django.contrib.auth import login as auth_login, logout as auth_logout
from django.shortcuts import redirect
from accounts.models import Token
def login(request):
print('login view', file=sys.stderr)
uid = request.GET.get('uid')
user = authenticate(uid=uid)
if user is not None:
auth_login(request, user)
return redirect('/')
def logout(request):
auth_logout(request)
return redirect('/')
from django.core.urlresolvers import reverse
from django.contrib import auth, messages
def send_login_email(request):
email = request.POST['email']
uid = str(uuid.uuid4())
Token.objects.create(email=email, uid=uid)
print('saving uid', uid, 'for email', email, file=sys.stderr)
url = request.build_absolute_uri(f'/accounts/login?uid={uid}')
token = Token.objects.create(email=email)
url = request.build_absolute_uri(
reverse('login') + '?token=' + str(token.uid)
)
message_body = f'Use this link to log in:\n\n{url}'
send_mail(
'Your login link for Superlists',
f'Use this link to log in:\n\n{url}',
message_body,
'noreply@superlists',
[email],
[email]
)
return render(request, 'login_email_sent.html')
\ No newline at end of file
return redirect('/')
def login(request):
user = auth.authenticate(uid=request.GET.get('token'))
if user:
auth.login(request, user)
return redirect('/')
\ No newline at end of file
......@@ -41,8 +41,18 @@ class LoginTest(FunctionalTest):
self.browser.get(url)
# she is logged in!
self.wait_for(
lambda: self.browser.find_element_by_link_text('Log out')
)
navbar = self.browser.find_element_by_css_selector('.navbar')
self.assertIn(TEST_EMAIL, navbar.text)
\ No newline at end of file
self.wait_for(
lambda: self.browser.find_element_by_link_text('Log out')
)
navbar = self.browser.find_element_by_css_selector('.navbar')
self.assertIn(TEST_EMAIL, navbar.text)
# Now she logs out
self.browser.find_element_by_link_text('Log out').click()
# She is logged out
self.wait_for(
lambda: self.browser.find_element_by_name('email')
)
navbar = self.browser.find_element_by_css_selector('.navbar')
self.assertNotIn(TEST_EMAIL, navbar.text)
\ No newline at end of file
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment