Modified files
storeapi/security.py
---
+++
@@ -2,6 +2,7 @@
import logging
from fastapi import HTTPException, status
+from fastapi.security import OAuth2PasswordBearer
from jose import ExpiredSignatureError, JWTError, jwt
from passlib.context import CryptContext
from storeapi.database import database, user_table
@@ -11,6 +12,7 @@
SECRET_KEY = "9b73f2a1bdd7ae163444473d29a6885ffa22ab26117068f72a5a56a74d12d1fc"
ALGORITHM = "HS256"
+oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")
pwd_context = CryptContext(schemes=["bcrypt"])
credentials_exception = HTTPException(
storeapi/routers/post.py
---
+++
@@ -1,6 +1,6 @@
import logging
-from fastapi import APIRouter, HTTPException
+from fastapi import APIRouter, HTTPException, Request
from storeapi.database import comment_table, database, post_table
from storeapi.models.post import (
Comment,
@@ -9,6 +9,8 @@
UserPostIn,
UserPostWithComments,
)
+from storeapi.models.user import User
+from storeapi.security import get_current_user, oauth2_scheme
router = APIRouter()
@@ -26,8 +28,11 @@
@router.post("/post", response_model=UserPost, status_code=201)
-async def create_post(post: UserPostIn):
+async def create_post(post: UserPostIn, request: Request):
logger.info("Creating post")
+ current_user: User = await get_current_user(
+ await oauth2_scheme(request)
+ ) # noqa: F841
data = post.model_dump() # previously .dict()
query = post_table.insert().values(data)
@@ -50,8 +55,11 @@
@router.post("/comment", response_model=Comment, status_code=201)
-async def create_comment(comment: CommentIn):
+async def create_comment(comment: CommentIn, request: Request):
logger.info("Creating comment")
+ current_user: User = await get_current_user(
+ await oauth2_scheme(request)
+ ) # noqa: F841
post = await find_post(comment.post_id)
storeapi/tests/conftest.py
---
+++
@@ -41,3 +41,9 @@
user = await database.fetch_one(query)
user_details["id"] = user.id
return user_details
+
+
+@pytest.fixture()
+async def logged_in_token(async_client: AsyncClient, registered_user: dict):
+ response = await async_client.post("/token", json=registered_user)
+ return response.json()["access_token"]
storeapi/tests/routers/test_post.py
---
+++
@@ -1,43 +1,81 @@
import pytest
from httpx import AsyncClient
+from storeapi import security
-async def create_post(body: str, async_client: AsyncClient) -> dict:
- response = await async_client.post("/post", json={"body": body})
+async def create_post(
+ body: str, async_client: AsyncClient, logged_in_token: str
+) -> dict:
+ response = await async_client.post(
+ "/post",
+ json={"body": body},
+ headers={"Authorization": f"Bearer {logged_in_token}"},
+ )
return response.json()
-async def create_comment(body: str, post_id: int, async_client: AsyncClient) -> dict:
+async def create_comment(
+ body: str, post_id: int, async_client: AsyncClient, logged_in_token: str
+) -> dict:
response = await async_client.post(
- "/comment", json={"body": body, "post_id": post_id}
+ "/comment",
+ json={"body": body, "post_id": post_id},
+ headers={"Authorization": f"Bearer {logged_in_token}"},
)
return response.json()
@pytest.fixture()
-async def created_post(async_client: AsyncClient):
- return await create_post("Test Post", async_client)
+async def created_post(async_client: AsyncClient, logged_in_token: str):
+ return await create_post("Test Post", async_client, logged_in_token)
@pytest.fixture()
-async def created_comment(async_client: AsyncClient, created_post: dict):
- return await create_comment("Test Comment", created_post["id"], async_client)
+async def created_comment(
+ async_client: AsyncClient, created_post: dict, logged_in_token: str
+):
+ return await create_comment(
+ "Test Comment", created_post["id"], async_client, logged_in_token
+ )
@pytest.mark.anyio
-async def test_create_post(async_client: AsyncClient):
+async def test_create_post(async_client: AsyncClient, logged_in_token: str):
body = "Test Post"
- response = await async_client.post("/post", json={"body": body})
-
+ response = await async_client.post(
+ "/post",
+ json={"body": body},
+ headers={"Authorization": f"Bearer {logged_in_token}"},
+ )
assert response.status_code == 201
assert {"id": 1, "body": body}.items() <= response.json().items()
@pytest.mark.anyio
-async def test_create_post_missing_data(async_client: AsyncClient):
- response = await async_client.post("/post", json={})
+async def test_create_post_expired_token(
+ async_client: AsyncClient, registered_user: dict, mocker
+):
+ mocker.patch("storeapi.security.access_token_expire_minutes", return_value=-1)
+ token = security.create_access_token(registered_user["email"])
+ response = await async_client.post(
+ "/post",
+ json={"body": "Test Post"},
+ headers={"Authorization": f"Bearer {token}"},
+ )
+ assert response.status_code == 401
+ assert "Token has expired" in response.json()["detail"]
+
+@pytest.mark.anyio
+async def test_create_post_missing_data(
+ async_client: AsyncClient, logged_in_token: str
+):
+ response = await async_client.post(
+ "/post",
+ json={},
+ headers={"Authorization": f"Bearer {logged_in_token}"},
+ )
assert response.status_code == 422
@@ -50,11 +88,17 @@
@pytest.mark.anyio
-async def test_create_comment(async_client: AsyncClient, created_post: dict):
+async def test_create_comment(
+ async_client: AsyncClient,
+ created_post: dict,
+ logged_in_token: str,
+):
body = "Test Comment"
response = await async_client.post(
- "/comment", json={"body": body, "post_id": created_post["id"]}
+ "/comment",
+ json={"body": body, "post_id": created_post["id"]},
+ headers={"Authorization": f"Bearer {logged_in_token}"},
)
assert response.status_code == 201
assert {