Skip to content

Commit 83c739a

Browse files
committed
chapter 18 listings done
1 parent ab6d0e1 commit 83c739a

File tree

4 files changed

+60
-52
lines changed

4 files changed

+60
-52
lines changed

chapter_18_spiking_custom_auth.asciidoc

Lines changed: 45 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -29,43 +29,49 @@ account on the site. So, without further ado, let's dive into authentication.
2929
((("passwords")))
3030
Naturally we're not going to mess about with remembering passwords
3131
ourselves--besides being 'so' '90s, secure storage of user passwords is a
32-
security nightmare we'd rather leave to someone else. We'll use something
33-
fun called passwordless auth instead.
32+
security nightmare we'd rather leave to someone else.
33+
We'll use something fun called passwordless auth instead.
3434

35-
(If you 'insist' on storing your own passwords, Django's default auth
36-
module is ready and waiting for you. It's nice and straightforward, and I'll
37-
leave it to you to discover on your own.)
35+
(If you 'insist' on storing your own passwords,
36+
Django's default auth module is ready and waiting for you.
37+
It's nice and straightforward, and I'll leave it to you to discover on your own.)
3838

3939

4040
[role="pagebreak-before less_space"]
4141
=== Passwordless Auth
4242

43+
//TODO: this is called "magic links" these days,
44+
// this section probably needs an update
45+
4346

4447
((("authentication", "passwordless")))
4548
((("Oauth")))
4649
((("Openid")))
4750
What authentication system could we use to avoid storing passwords ourselves?
48-
Oauth? Openid? "Login with Facebook"? Ugh. For me those all have
49-
unacceptable creepy overtones; why should Google or Facebook know what sites
50-
you're logging into and when?
51+
Oauth? Openid? "Login with Facebook"? Ugh.
52+
For me those all have unacceptable creepy overtones;
53+
why should Google or Facebook know what sites you're logging into and when?
5154

5255
In the first edition I used an experimental project called "Persona",
53-
cooked up by a some of the wonderful techno-hippy-idealists at Mozilla, but
54-
sadly that project was abandoned.
56+
cooked up by a some of the wonderful techno-hippy-idealists at Mozilla,
57+
but sadly that project was abandoned.
5558

5659
Instead I've found a fun approach to authentication that goes by the name
5760
of "Passwordless", but you might call it "just use email".
5861

59-
The system was invented by someone annoyed at having to create
60-
new passwords for so many websites, who found himself just using random,
61-
throwaway passwords, not even trying to remember them, and using the
62-
"forgot my password" feature whenever he needed to log in again. You can
62+
The system was invented (or at least popularised) back in 2014
63+
by someone annoyed at having to create new passwords for so many websites.
64+
They found themselves just using random, throwaway passwords,
65+
not even trying to remember them, and using the "forgot my password" feature
66+
whenever he needed to log in again.
67+
You can
6368
https://medium.com/@ninjudd/passwords-are-obsolete-9ed56d483eb#.cx8iber30[read
6469
all about it on Medium].
6570

66-
The concept is: just use email to verify someone's identity. If you're
67-
going to have a "forgot my password" feature, then you're trusting email
68-
anyway, so why not just go the whole hog? Whenever someone wants to log in,
71+
The concept is: just use email to verify someone's identity.
72+
If you're going to have a "forgot my password" feature,
73+
then you're trusting email anyway, so why not just go the whole hog?
74+
Whenever someone wants to log in,
6975
we generate a unique URL for them to use, email it to them, and they then
7076
click through that to get into the site.
7177

@@ -894,14 +900,20 @@ unless you absolutely must,
894900
so a user model that records an email address and nothing else
895901
sounds good to me!
896902

897-
By now I'm sure you can manage to create the tests folder and its pass:[<em>__init__.py</em>],
898-
remove _tests.py_, and then add a _test_models.py_ to say:
903+
Let's start straight away with a tests folder instead of _tests.py_
904+
in this app:
899905

906+
[subs=""]
907+
----
908+
$ <strong>rm src/accounts/tests.py</strong>
909+
$ <strong>mkdir src/accounts/tests</strong>
910+
$ <strong>touch src/accounts/tests/__init__.py</strong>
911+
----
900912

901-
// TODO: l022 doesnt work with dofirst because it has two files in,
902-
// change to separate commits for __init__ and model or somefink
913+
And now let's add add a _test_models.py_ to say:
903914

904-
[role="sourcecode dofirst-ch18l022"]
915+
916+
[role="sourcecode"]
905917
.src/accounts/tests/test_models.py (ch18l023)
906918
====
907919
[source,python]
@@ -922,6 +934,7 @@ class UserModelTest(TestCase):
922934

923935
That gives us an expected failure:
924936

937+
[role=""]
925938
----
926939
django.core.exceptions.ValidationError: {'password': ['This field cannot be
927940
blank.'], 'username': ['This field cannot be blank.']}
@@ -937,6 +950,7 @@ Password? Username? Bah! How about this?
937950
----
938951
from django.db import models
939952
953+
940954
class User(models.Model):
941955
email = models.EmailField()
942956
----
@@ -971,6 +985,7 @@ Now when we run our tests, Django complains
971985
that our custom user model is missing a couple of bits of metadata:
972986

973987

988+
[role="ignore-errors"]
974989
[subs="specialcharacters,macros"]
975990
----
976991
$ pass:quotes[*python src/manage.py makemigrations*]
@@ -996,6 +1011,7 @@ Here you go:
9961011
----
9971012
class User(models.Model):
9981013
email = models.EmailField()
1014+
9991015
REQUIRED_FIELDS = []
10001016
----
10011017
====
@@ -1023,7 +1039,7 @@ class User(models.Model):
10231039
email = models.EmailField()
10241040
10251041
REQUIRED_FIELDS = []
1026-
USERNAME_FIELD = 'email'
1042+
USERNAME_FIELD = "email"
10271043
is_anonymous = False
10281044
is_authenticated = True
10291045
----
@@ -1033,6 +1049,7 @@ class User(models.Model):
10331049
And now we get a slightly different error:
10341050

10351051

1052+
[role="ignore-errors"]
10361053
[subs="specialcharacters,macros"]
10371054
----
10381055
$ pass:quotes[*python src/manage.py makemigrations*]
@@ -1118,16 +1135,16 @@ it would be better to have a specific test:
11181135
[source,python]
11191136
----
11201137
def test_email_is_primary_key(self):
1121-
user = User(email='[email protected]')
1122-
self.assertEqual(user.pk, '[email protected]')
1138+
user = User(email="[email protected]")
1139+
self.assertEqual(user.pk, "[email protected]")
11231140
----
11241141
====
11251142

11261143
It'll help us remember if we ever come back and look at the code again
11271144
in future:
11281145

11291146
----
1130-
self.assertEqual(user.pk, '[email protected]')
1147+
self.assertEqual(user.pk, "[email protected]")
11311148
AssertionError: None != '[email protected]'
11321149
----
11331150

@@ -1240,7 +1257,7 @@ AttributeError: 'Token' object has no attribute 'uid'. Did you mean: 'id'?
12401257

12411258
Eventually you should get to this code...
12421259

1243-
[role="sourcecode"]
1260+
[role="sourcecode dofirst-ch18l038-1"]
12441261
.src/accounts/models.py (ch18l038)
12451262
====
12461263
[source,python]
@@ -1290,6 +1307,7 @@ And, perhaps with a bit more wrangling of migrations,
12901307
that should get us to passing tests:
12911308

12921309

1310+
[role="dofirst-ch18l041"]
12931311
[subs="specialcharacters,quotes"]
12941312
----
12951313
$ *python src/manage.py test accounts*

tests/sourcetree.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -202,7 +202,7 @@ def patch_from_commit(self, commit_ref, path=None):
202202

203203
def tidy_up_after_patches(self):
204204
# tidy up any .origs from patches
205-
self.sourcetree.run_command('find . -name "*.orig" -exec rm {} \\;')
205+
self.run_command('find . -name "*.orig" -exec rm {} \\;')
206206

207207
def apply_listing_from_commit(self, listing):
208208
commit_spec = self.get_commit_spec(listing.commit_ref)

tests/test_chapter_18_spiking_custom_auth.py

Lines changed: 13 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -5,21 +5,21 @@
55

66

77
class Chapter18Test(ChapterTest):
8-
chapter_name = 'chapter_18_spiking_custom_auth'
9-
previous_chapter = 'chapter_17_second_deploy'
8+
chapter_name = "chapter_18_spiking_custom_auth"
9+
previous_chapter = "chapter_17_second_deploy"
1010

1111
def test_listings_and_commands_and_output(self):
1212
self.parse_listings()
1313

1414
# sanity checks
1515
# self.assertEqual(self.listings[0].type, 'other command')
16-
self.assertEqual(self.listings[1].type, 'code listing with git ref')
17-
self.assertEqual(self.listings[2].type, 'other command')
18-
#self.assertTrue(self.listings[88].dofirst)
16+
self.assertEqual(self.listings[1].type, "code listing with git ref")
17+
self.assertEqual(self.listings[2].type, "other command")
18+
# self.assertTrue(self.listings[88].dofirst)
1919

2020
# skips
21-
self.skip_with_check(28, 'switch back to main') # comment
22-
self.skip_with_check(30, 'remove any trace') # comment
21+
self.skip_with_check(28, "switch back to main") # comment
22+
self.skip_with_check(30, "remove any trace") # comment
2323

2424
# prep
2525
self.start_with_checkout()
@@ -28,31 +28,21 @@ def test_listings_and_commands_and_output(self):
2828
# hack fast-forward
2929
skip = False
3030
if skip:
31-
self.pos = 39
32-
self.sourcetree.run_command('git checkout {0}'.format(
33-
self.sourcetree.get_commit_spec('ch15l020')
34-
))
31+
self.pos = 38
32+
self.sourcetree.run_command(
33+
"git checkout {}".format(self.sourcetree.get_commit_spec("ch18l020"))
34+
)
3535

3636
while self.pos < len(self.listings):
3737
print(self.pos)
3838
self.recognise_listing_and_process_it()
3939

4040
self.assert_all_listings_checked(self.listings)
41-
# fix incomplete moves from dofirst-ch14l019
42-
# self.sourcetree.run_command('git rm lists/static/base.css')
43-
# self.sourcetree.run_command('git rm -r lists/static/bootstrap')
44-
# self.sourcetree.run_command('git rm lists/static/tests/qunit.css')
45-
# self.sourcetree.run_command('git rm lists/static/tests/qunit.js')
46-
47-
# and from the diff-version of settings.py
48-
# self.sourcetree.run_command('rm superlists/settings.py.orig')
49-
50-
self.sourcetree.tidy_up_after_patches()
5141

5242
# and do a final commit
5343
self.sourcetree.run_command('git add . && git commit -m"final commit"')
54-
self.check_final_diff(ignore=["Generated by Django 1.11"])
44+
self.check_final_diff(ignore=["Generated by Django 4.2"])
5545

5646

57-
if __name__ == '__main__':
47+
if __name__ == "__main__":
5848
unittest.main()

0 commit comments

Comments
 (0)