User email confirmation

Requiring user confirmation for authenticated requests

Want more?

This lesson for enrolled students only. Join the course to unlock it!

You can see the code changes implemented in this lecture below.

If you have purchased the course in a different platform, you still have access to the code changes per lecture here on Teclado. The lecture video and lecture notes remain locked.
Join course for $30

Modified files

storeapi/security.py
--- 
+++ 
@@ -98,6 +98,8 @@
         raise create_unauthorized_exception("Invalid email or password")
     if not verify_password(password, user.password):
         raise create_unauthorized_exception("Invalid email or password")
+    if not user.confirmed:
+        raise create_unauthorized_exception("User has not confirmed email")
     return user
storeapi/tests/test_security.py
--- 
+++ 
@@ -94,11 +94,11 @@


 @pytest.mark.anyio
-async def test_authenticate_user(registered_user: dict):
+async def test_authenticate_user(confirmed_user: dict):
     user = await security.authenticate_user(
-        registered_user["email"], registered_user["password"]
+        confirmed_user["email"], confirmed_user["password"]
     )
-    assert user.email == registered_user["email"]
+    assert user.email == confirmed_user["email"]


 @pytest.mark.anyio
storeapi/tests/conftest.py
--- 
+++ 
@@ -44,6 +44,17 @@


 @pytest.fixture()
-async def logged_in_token(async_client: AsyncClient, registered_user: dict) -> str:
-    response = await async_client.post("/token", json=registered_user)
+async def confirmed_user(registered_user: dict) -> dict:
+    query = (
+        user_table.update()
+        .where(user_table.c.email == registered_user["email"])
+        .values(confirmed=True)
+    )
+    await database.execute(query)
+    return registered_user
+
+
+@pytest.fixture()
+async def logged_in_token(async_client: AsyncClient, confirmed_user: dict) -> str:
+    response = await async_client.post("/token", json=confirmed_user)
     return response.json()["access_token"]
storeapi/tests/routers/test_user.py
--- 
+++ 
@@ -70,7 +70,9 @@


 @pytest.mark.anyio
-async def test_login_user(async_client: AsyncClient, registered_user: dict):
+async def test_login_user_not_confirmed(
+    async_client: AsyncClient, registered_user: dict
+):
     response = await async_client.post(
         "/token",
         json={
@@ -78,4 +80,13 @@
             "password": registered_user["password"],
         },
     )
+    assert response.status_code == 400
+
+
+@pytest.mark.anyio
+async def test_login_user(async_client: AsyncClient, confirmed_user: dict):
+    response = await async_client.post(
+        "/token",
+        json={"email": confirmed_user["email"], "password": confirmed_user["password"]},
+    )
     assert response.status_code == 200
storeapi/tests/routers/test_post.py
--- 
+++ 
@@ -53,7 +53,7 @@

 @pytest.mark.anyio
 async def test_create_post(
-    async_client: AsyncClient, registered_user: dict, logged_in_token: str
+    async_client: AsyncClient, confirmed_user: dict, logged_in_token: str
 ):
     body = "Test Post"

@@ -67,16 +67,16 @@
     assert {
         "id": 1,
         "body": body,
-        "user_id": registered_user["id"],
+        "user_id": confirmed_user["id"],
     }.items() <= response.json().items()


 @pytest.mark.anyio
 async def test_create_post_expired_token(
-    async_client: AsyncClient, registered_user: dict, mocker
+    async_client: AsyncClient, confirmed_user: dict, mocker
 ):
     mocker.patch("storeapi.security.access_token_expire_minutes", return_value=-1)
-    token = security.create_access_token(registered_user["email"])
+    token = security.create_access_token(confirmed_user["email"])
     response = await async_client.post(
         "/post",
         json={"body": "Test Post"},
@@ -168,7 +168,7 @@
 async def test_create_comment(
     async_client: AsyncClient,
     created_post: dict,
-    registered_user: dict,
+    confirmed_user: dict,
     logged_in_token: str,
 ):
     body = "Test Comment"
@@ -183,7 +183,7 @@
         "id": 1,
         "body": body,
         "post_id": created_post["id"],
-        "user_id": registered_user["id"],
+        "user_id": confirmed_user["id"],
     }.items() <= response.json().items()