diff --git a/.github/workflows/checks.yml b/.github/workflows/checks.yml index 80de9ef..c16b898 100644 --- a/.github/workflows/checks.yml +++ b/.github/workflows/checks.yml @@ -99,8 +99,6 @@ jobs: steps: - name: Checkout uses: actions/checkout@v4 - - name: cd into folder - run: cd frontend - uses: actions/setup-node@v3 with: node-version: '18' diff --git a/backend/migrations/env.py b/backend/migrations/env.py index 2752340..303791d 100644 --- a/backend/migrations/env.py +++ b/backend/migrations/env.py @@ -1,11 +1,9 @@ from logging.config import fileConfig from alembic import context -from sqlalchemy import engine_from_config, pool - from my_app_api.models.base import Base from my_app_api.settings import get_settings - +from sqlalchemy import engine_from_config, pool # this is the Alembic Config object, which provides # access to the values within the .ini file in use. @@ -61,7 +59,7 @@ def run_migrations_online(): """ configuration = config.get_section(config.config_ini_section) - configuration['sqlalchemy.url'] = str(settings.DB_DSN) + configuration["sqlalchemy.url"] = str(settings.DB_DSN) connectable = engine_from_config( configuration, prefix="sqlalchemy.", diff --git a/backend/my_app_api/__init__.py b/backend/my_app_api/__init__.py index aed50a4..4ed3366 100644 --- a/backend/my_app_api/__init__.py +++ b/backend/my_app_api/__init__.py @@ -1,4 +1,3 @@ import os - __version__ = os.getenv("APP_VERSION", "dev") diff --git a/backend/my_app_api/__main__.py b/backend/my_app_api/__main__.py index 7415f52..70ad503 100644 --- a/backend/my_app_api/__main__.py +++ b/backend/my_app_api/__main__.py @@ -1,7 +1,5 @@ import uvicorn - from my_app_api.routes import app - -if __name__ == '__main__': +if __name__ == "__main__": uvicorn.run(app) diff --git a/backend/my_app_api/exceptions.py b/backend/my_app_api/exceptions.py index e69de29..31fcb41 100644 --- a/backend/my_app_api/exceptions.py +++ b/backend/my_app_api/exceptions.py @@ -0,0 +1,5 @@ +class APIError(Exception): + """Base class for API errors""" + + def __init__(self, message: str) -> None: + super().__init__(message) diff --git a/backend/my_app_api/routes/__init__.py b/backend/my_app_api/routes/__init__.py index 8500154..fbf71a6 100644 --- a/backend/my_app_api/routes/__init__.py +++ b/backend/my_app_api/routes/__init__.py @@ -4,22 +4,20 @@ from fastapi.middleware.cors import CORSMiddleware from fastapi.staticfiles import StaticFiles from fastapi_sqlalchemy import DBSessionMiddleware - from my_app_api import __version__ from my_app_api.settings import get_settings -from .click import router as click_router - +from .touch import router as touch_router settings = get_settings() logger = logging.getLogger(__name__) app = FastAPI( - title='Мое приложение', - description='Бэкэнд приложения-примера', + title="Мое приложение", + description="Бэкэнд приложения-примера", version=__version__, # Отключаем нелокальную документацию - root_path=settings.ROOT_PATH if __version__ != 'dev' else '', - docs_url='/swagger', + root_path=settings.ROOT_PATH if __version__ != "dev" else "", + docs_url="/swagger", redoc_url=None, ) @@ -39,10 +37,16 @@ if settings.UI_DIR_PATH: logger.debug("Enabling UI") - app.mount("/ui", app=StaticFiles(directory=settings.UI_DIR_PATH, html=True), name="ui") + app.mount( + "/ui", app=StaticFiles(directory=settings.UI_DIR_PATH, html=True), name="ui" + ) if settings.DOCS_DIR_PATH: logger.debug("Enabling Docs") - app.mount("/docs", app=StaticFiles(directory=settings.DOCS_DIR_PATH, html=True), name="docs") + app.mount( + "/docs", + app=StaticFiles(directory=settings.DOCS_DIR_PATH, html=True), + name="docs", + ) -app.include_router(click_router) +app.include_router(touch_router) diff --git a/backend/my_app_api/routes/click.py b/backend/my_app_api/routes/click.py deleted file mode 100644 index a75896d..0000000 --- a/backend/my_app_api/routes/click.py +++ /dev/null @@ -1,25 +0,0 @@ -import logging - -from fastapi import APIRouter -from pydantic import BaseModel - - -logger = logging.getLogger(__name__) -router = APIRouter(prefix='/click', tags=['Click']) - - -# region schemas -class ClickResponse(BaseModel): - count: int - - -# endregion - - -# region routes -@router.get('') -def get_clicks() -> ClickResponse: - return ClickResponse(count=1) - - -# endregion diff --git a/backend/my_app_api/routes/touch.py b/backend/my_app_api/routes/touch.py new file mode 100644 index 0000000..d64a2b9 --- /dev/null +++ b/backend/my_app_api/routes/touch.py @@ -0,0 +1,31 @@ +import logging + +from auth_lib.fastapi import UnionAuth +from fastapi import APIRouter, Depends +from pydantic import BaseModel + +logger = logging.getLogger(__name__) +router = APIRouter(prefix="/example", tags=["Example"]) + +CLICKS: dict[int, int] = {} + + +class WhoAmI(BaseModel): + id: int + + +class TouchGet(WhoAmI): + count: int + + +@router.get("/whoami", response_model=WhoAmI) +def whoami(auth=Depends(UnionAuth(allow_none=False))): + return {"id": auth["id"]} + + +@router.post("/touch", response_model=TouchGet) +def touch(auth=Depends(UnionAuth(allow_none=False))): + if auth["id"] not in CLICKS: + CLICKS[auth["id"]] = 0 + CLICKS[auth["id"]] += 1 + return {"id": auth["id"], "count": CLICKS[auth["id"]]} diff --git a/backend/pyproject.toml b/backend/pyproject.toml index 3360995..bf2a06d 100644 --- a/backend/pyproject.toml +++ b/backend/pyproject.toml @@ -1,6 +1,6 @@ [tool.black] line-length = 120 -target-version = ['py312'] +target-version = ['py311'] skip-string-normalization = true [tool.isort] diff --git a/backend/requirements.dev.txt b/backend/requirements.dev.txt index c8d847a..5d09b7b 100644 --- a/backend/requirements.dev.txt +++ b/backend/requirements.dev.txt @@ -5,3 +5,4 @@ isort pytest pytest-cov pytest-mock +auth-lib-profcomff[testing] diff --git a/backend/tests/conftest.py b/backend/tests/conftest.py index e69de29..d8161c6 100644 --- a/backend/tests/conftest.py +++ b/backend/tests/conftest.py @@ -0,0 +1,9 @@ +import pytest +from fastapi.testclient import TestClient +from my_app_api.routes import app + + +@pytest.fixture +def client(): + client = TestClient(app) + yield client diff --git a/backend/tests/test_routes/.gitkeep b/backend/tests/test_routes/.gitkeep deleted file mode 100644 index 8b13789..0000000 --- a/backend/tests/test_routes/.gitkeep +++ /dev/null @@ -1 +0,0 @@ - diff --git a/backend/tests/test_routes/test_click.py b/backend/tests/test_routes/test_click.py new file mode 100644 index 0000000..7f2fd99 --- /dev/null +++ b/backend/tests/test_routes/test_click.py @@ -0,0 +1,21 @@ +import pytest + + +@pytest.mark.authenticated() +def test_whoami(client): + resp = client.get("/example/whoami") + assert resp.status_code == 200 + assert resp.json()["id"] == 0 + + +@pytest.mark.authenticated() +def test_touch(client): + resp = client.post("/example/touch") + assert resp.status_code == 200 + assert resp.json()["id"] == 0 + assert resp.json()["count"] == 1 + + resp = client.post("/example/touch") + assert resp.status_code == 200 + assert resp.json()["id"] == 0 + assert resp.json()["count"] == 2 diff --git a/frontend/package.json b/frontend/package.json index 1a06494..5ac02ca 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -10,7 +10,7 @@ "lint": "eslint --ext ts,vue src/ --fix", "format": "prettier src/ --write", "stylelint": "stylelint 'src/**/*.{vue,css}' --fix", - "check": "vue-tsc && pnpm run format && pnpm run lint && pnpm run stylelint" + "check": "vue-tsc && npm run format && npm run lint && npm run stylelint" }, "dependencies": { "axios": "^1.6.5",