diff --git a/.github/workflows/python.yml b/.github/workflows/python.yml index 1602f2b..a8ef98b 100644 --- a/.github/workflows/python.yml +++ b/.github/workflows/python.yml @@ -30,5 +30,7 @@ jobs: run: black --check fooder - name: Run flake8 run: flake8 fooder + - name: Run mypy + run: mypy fooder - name: Run tests run: ./test.sh diff --git a/Makefile b/Makefile index fcfc10e..ab27f81 100644 --- a/Makefile +++ b/Makefile @@ -34,7 +34,7 @@ version: .PHONY: create-venv create-venv: python3 -m venv .venv --prompt="fooderapi-venv" --system-site-packages - bash -c "source .venv/bin/activate && pip install -r requirements_local.txt && (echo y | mypy --install-types)" + bash -c "source .venv/bin/activate && pip install -r requirements_local.txt" .PHONY: test test: diff --git a/fooder/auth.py b/fooder/auth.py index 20faa20..a07c21f 100644 --- a/fooder/auth.py +++ b/fooder/auth.py @@ -1,6 +1,5 @@ from passlib.context import CryptContext -from sqlalchemy.ext.asyncio import AsyncSession -from sqlalchemy.ext.asyncio import async_sessionmaker +from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker from jose import JWTError, jwt from fastapi.security import OAuth2PasswordBearer from fastapi import Depends, HTTPException @@ -108,10 +107,8 @@ async def create_refresh_token(session: AsyncSession, user: User) -> RefreshToke return await RefreshToken.create(session, token=encoded_jwt, user_id=user.id) -async def get_current_user( - session: AsyncSessionDependency, token: TokenDependency -) -> User: - async with session() as session: +async def get_current_user(ssn: AsyncSessionDependency, token: TokenDependency) -> User: + async with ssn() as session: try: payload = jwt.decode( token, settings.SECRET_KEY, algorithms=[settings.ALGORITHM] @@ -141,9 +138,7 @@ async def get_current_user( return user -async def authorize_api_key( - session: AsyncSessionDependency, token: TokenDependency -) -> None: +async def authorize_api_key(token: TokenDependency) -> None: if token == settings.API_KEY: return None raise HTTPException(status_code=401, detail="Unathorized") diff --git a/fooder/controller/base.py b/fooder/controller/base.py index b7cbaf2..6b0cce3 100644 --- a/fooder/controller/base.py +++ b/fooder/controller/base.py @@ -8,7 +8,7 @@ from ..domain.user import User AsyncSession = Annotated[async_sessionmaker, Depends(get_session)] UserDependency = Annotated[User, Depends(get_current_user)] -ApiKeyDependency = Annotated[bool, Depends(authorize_api_key)] +ApiKeyDependency = Annotated[None, Depends(authorize_api_key)] class BaseController: diff --git a/fooder/controller/entry.py b/fooder/controller/entry.py index 04d419e..fedee25 100644 --- a/fooder/controller/entry.py +++ b/fooder/controller/entry.py @@ -39,7 +39,7 @@ class UpdateEntry(AuthorizedController): class DeleteEntry(AuthorizedController): - async def call(self, entry_id: int) -> Entry: + async def call(self, entry_id: int) -> None: async with self.async_session.begin() as session: entry = await DBEntry.get_by_id(session, self.user.id, entry_id) if entry is None: diff --git a/fooder/controller/meal.py b/fooder/controller/meal.py index dafee32..aa2216f 100644 --- a/fooder/controller/meal.py +++ b/fooder/controller/meal.py @@ -29,7 +29,7 @@ class CreateMeal(AuthorizedController): class SaveMeal(AuthorizedController): - async def call(self, meal_id: id, payload: SaveMealPayload) -> Preset: + async def call(self, meal_id: int, payload: SaveMealPayload) -> Preset: async with self.async_session.begin() as session: meal = await DBMeal.get_by_id(session, self.user.id, meal_id) if meal is None: @@ -38,7 +38,10 @@ class SaveMeal(AuthorizedController): try: return Preset.from_orm( await DBPreset.create( - session, user_id=self.user.id, name=payload.name, meal=meal + session, + user_id=self.user.id, + name=payload.name or meal.name, + meal=meal, ) ) except AssertionError as e: @@ -46,7 +49,7 @@ class SaveMeal(AuthorizedController): class DeleteMeal(AuthorizedController): - async def call(self, meal_id: id) -> None: + async def call(self, meal_id: int) -> None: async with self.async_session.begin() as session: meal = await DBMeal.get_by_id(session, self.user.id, meal_id) if meal is None: diff --git a/fooder/controller/preset.py b/fooder/controller/preset.py index 15a9d6f..2bfb9e2 100644 --- a/fooder/controller/preset.py +++ b/fooder/controller/preset.py @@ -32,7 +32,7 @@ class DeletePreset(AuthorizedController): async def call( self, id: int, - ) -> AsyncIterator[Preset]: + ) -> None: async with self.async_session.begin() as session: preset = await DBPreset.get(session, self.user.id, id) diff --git a/fooder/controller/token.py b/fooder/controller/token.py index 05d1055..4ffa688 100644 --- a/fooder/controller/token.py +++ b/fooder/controller/token.py @@ -41,6 +41,11 @@ class RefreshToken(BaseController): raise HTTPException(status_code=401, detail="Invalid token") user = await DBUser.get(session, current_token.user_id) + + if user is None: + raise HTTPException(status_code=401, detail="Invalid token") + + assert user is not None await current_token.delete(session) refresh_token = await create_refresh_token(session, user) diff --git a/mypy.ini b/mypy.ini index ce7e0b0..3358d6b 100644 --- a/mypy.ini +++ b/mypy.ini @@ -10,4 +10,6 @@ platform = linux warn_unused_configs = True warn_unused_ignores = True -allow_redefinition = True + +[mypy-fooder.controller.*] +disable_error_code=override diff --git a/requirements_local.txt b/requirements_local.txt index 412570b..82188d7 100644 --- a/requirements_local.txt +++ b/requirements_local.txt @@ -15,3 +15,5 @@ httpx aiosqlite mypy types-requests +types-passlib +types-python-jose