generated from MinBZK/python-project-template
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
# This is a combination of 2 commits.
# This is the 1st commit message: Add setup for tasks card # This is the commit message #2: Rewrite database test functions to a class with a fixture
- Loading branch information
1 parent
ccc8dd5
commit 5507b2c
Showing
69 changed files
with
5,448 additions
and
40 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -27,6 +27,7 @@ __pypackages__/ | |
|
||
#mypyr | ||
.mypy_cache/ | ||
/.idea/ | ||
|
||
# macos | ||
.DS_Store | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,9 @@ | ||
from fastapi import APIRouter | ||
|
||
from tad.api.routes import health, root | ||
from tad.api.routes import health, pages, root, tasks | ||
|
||
api_router = APIRouter() | ||
api_router.include_router(root.router) | ||
api_router.include_router(health.router, prefix="/health", tags=["health"]) | ||
api_router.include_router(pages.router, prefix="/pages", tags=["pages"]) | ||
api_router.include_router(tasks.router, prefix="/tasks", tags=["tasks"]) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
from typing import Annotated | ||
|
||
from fastapi import APIRouter, Depends, Request | ||
from fastapi.responses import HTMLResponse | ||
from fastapi.templating import Jinja2Templates | ||
|
||
from tad.services.statuses import StatusesService | ||
from tad.services.tasks import TasksService | ||
|
||
router = APIRouter() | ||
templates = Jinja2Templates(directory="tad/site/templates") | ||
|
||
|
||
@router.get("/", response_class=HTMLResponse) | ||
async def default_layout( | ||
request: Request, | ||
status_service: Annotated[StatusesService, Depends(StatusesService)], | ||
tasks_service: Annotated[TasksService, Depends(TasksService)], | ||
): | ||
context = { | ||
"page_title": "This is the page title", | ||
"tasks_service": tasks_service, | ||
"statuses_service": status_service, | ||
} | ||
return templates.TemplateResponse(request=request, name="default_layout.jinja", context=context) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
from typing import Annotated, Any | ||
|
||
from fastapi import APIRouter, Depends, Request, status | ||
from fastapi.responses import HTMLResponse | ||
from fastapi.templating import Jinja2Templates | ||
|
||
from tad.models.task import MoveTask | ||
from tad.services.tasks import TasksService | ||
|
||
router = APIRouter() | ||
templates = Jinja2Templates(directory="tad/site/templates") | ||
|
||
|
||
@router.post("/move", response_class=HTMLResponse) | ||
async def move_task( | ||
request: Request, move_task: MoveTask, tasks_service: Annotated[TasksService, Depends(TasksService)] | ||
) -> HTMLResponse: | ||
""" | ||
Move a task through an API call. | ||
:param tasks_service: the task service | ||
:param request: the request object | ||
:param move_task: the move task object | ||
:return: a HTMLResponse object, in this case the html code of the card that was moved | ||
""" | ||
try: | ||
task = tasks_service.move_task( | ||
convert_to_int_if_is_int(move_task.id), | ||
convert_to_int_if_is_int(move_task.status_id), | ||
convert_to_int_if_is_int(move_task.previous_sibling_id), | ||
convert_to_int_if_is_int(move_task.next_sibling_id), | ||
) | ||
# todo(Robbert) add error handling for input error or task error handling | ||
return templates.TemplateResponse(request=request, name="task.jinja", context={"task": task}) | ||
except Exception: | ||
return templates.TemplateResponse( | ||
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, request=request, name="error.jinja" | ||
) | ||
|
||
|
||
def convert_to_int_if_is_int(value: Any) -> int | Any: | ||
""" | ||
If the given value is of type int, return it as int, otherwise return the input value as is. | ||
:param value: the value to convert | ||
:return: the value as int or the original type | ||
""" | ||
if value is not None and isinstance(value, str) and value.isdigit(): | ||
return int(value) | ||
return value |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,10 +1,18 @@ | ||
from sqlalchemy.engine.base import Engine | ||
from sqlmodel import Session, create_engine, select | ||
|
||
from tad.core.config import settings | ||
|
||
engine = create_engine(settings.SQLALCHEMY_DATABASE_URI) | ||
_engine: None | Engine = None | ||
|
||
|
||
def get_engine() -> Engine: | ||
global _engine | ||
if _engine is None: | ||
_engine = create_engine(settings.SQLALCHEMY_DATABASE_URI) | ||
return _engine | ||
|
||
|
||
async def check_db(): | ||
with Session(engine) as session: | ||
with Session(get_engine()) as session: | ||
session.exec(select(1)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
"""a message | ||
Revision ID: eb2eed884ae9 | ||
Revises: | ||
Create Date: 2024-05-14 13:36:23.551663 | ||
""" | ||
|
||
from collections.abc import Sequence | ||
|
||
import sqlalchemy as sa | ||
import sqlmodel.sql.sqltypes | ||
from alembic import op | ||
|
||
# revision identifiers, used by Alembic. | ||
revision: str = "eb2eed884ae9" | ||
down_revision: str | None = None | ||
branch_labels: str | Sequence[str] | None = None | ||
depends_on: str | Sequence[str] | None = None | ||
|
||
|
||
def upgrade() -> None: | ||
# ### commands auto generated by Alembic - please adjust! ### | ||
op.create_table( | ||
"hero", | ||
sa.Column("id", sa.Integer(), nullable=False), | ||
sa.Column("name", sqlmodel.sql.sqltypes.AutoString(), nullable=False), | ||
sa.PrimaryKeyConstraint("id"), | ||
) | ||
op.create_table( | ||
"status", | ||
sa.Column("id", sa.Integer(), nullable=False), | ||
sa.Column("name", sqlmodel.sql.sqltypes.AutoString(), nullable=False), | ||
sa.Column("sort_order", sa.Float(), nullable=False), | ||
sa.PrimaryKeyConstraint("id"), | ||
) | ||
op.create_table( | ||
"user", | ||
sa.Column("id", sa.Integer(), nullable=False), | ||
sa.Column("name", sqlmodel.sql.sqltypes.AutoString(), nullable=False), | ||
sa.Column("avatar", sqlmodel.sql.sqltypes.AutoString(), nullable=True), | ||
sa.PrimaryKeyConstraint("id"), | ||
) | ||
op.create_table( | ||
"task", | ||
sa.Column("id", sa.Integer(), nullable=False), | ||
sa.Column("title", sqlmodel.sql.sqltypes.AutoString(), nullable=False), | ||
sa.Column("description", sqlmodel.sql.sqltypes.AutoString(), nullable=False), | ||
sa.Column("sort_order", sa.Float(), nullable=False), | ||
sa.Column("status_id", sa.Integer(), nullable=False), | ||
sa.Column("user_id", sa.Integer(), nullable=True), | ||
sa.ForeignKeyConstraint( | ||
["user_id"], | ||
["user.id"], | ||
), | ||
sa.PrimaryKeyConstraint("id"), | ||
) | ||
# ### end Alembic commands ### | ||
|
||
|
||
def downgrade() -> None: | ||
# ### commands auto generated by Alembic - please adjust! ### | ||
op.drop_table("task") | ||
op.drop_table("user") | ||
op.drop_table("status") | ||
op.drop_table("hero") | ||
# ### end Alembic commands ### |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,6 @@ | ||
from .hero import Hero | ||
from .status import Status | ||
from .task import Task | ||
from .user import User | ||
|
||
__all__ = ["Hero"] | ||
__all__ = ["Hero", "Task", "Status", "User"] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
from sqlmodel import Field, SQLModel # type: ignore | ||
|
||
|
||
class Status(SQLModel, table=True): | ||
id: int = Field(default=None, primary_key=True) | ||
name: str | ||
sort_order: float |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
from pydantic import BaseModel, ValidationInfo, field_validator | ||
from pydantic import Field as PydanticField # type: ignore | ||
from sqlmodel import Field as SQLField # type: ignore | ||
from sqlmodel import SQLModel | ||
|
||
|
||
class Task(SQLModel, table=True): | ||
id: int = SQLField(default=None, primary_key=True) | ||
title: str | ||
description: str | ||
sort_order: float | ||
status_id: int | None = SQLField(default=None, foreign_key="status.id") | ||
user_id: int | None = SQLField(default=None, foreign_key="user.id") | ||
# todo(robbert) Tasks probably are grouped (and sub-grouped), so we probably need a reference to a group_id | ||
|
||
|
||
class MoveTask(BaseModel): | ||
# todo(robbert) values from htmx json are all strings, using type int does not work for | ||
# sibling variables (they are optional) | ||
id: str = PydanticField(None, alias="taskId", strict=False) | ||
status_id: str = PydanticField(None, alias="statusId", strict=False) | ||
previous_sibling_id: str | None = PydanticField(None, alias="previousSiblingId", strict=False) | ||
next_sibling_id: str | None = PydanticField(None, alias="nextSiblingId", strict=False) | ||
|
||
@field_validator("id", "status_id", "previous_sibling_id", "next_sibling_id") | ||
@classmethod | ||
def check_is_int(cls, value: str, info: ValidationInfo) -> str: | ||
if isinstance(value, str) and value.isdigit(): | ||
assert value.isdigit(), f"{info.field_name} must be an integer" # noqa: S101 | ||
return value |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
from sqlmodel import Field, SQLModel # type: ignore | ||
|
||
|
||
class User(SQLModel, table=True): | ||
id: int = Field(default=None, primary_key=True) | ||
name: str | ||
avatar: str | None |
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,19 +1,14 @@ | ||
from collections.abc import Generator | ||
from typing import Annotated | ||
|
||
from fastapi import Depends | ||
from fastapi.templating import Jinja2Templates | ||
from sqlmodel import Session | ||
|
||
from tad.core.config import settings | ||
from tad.core.db import engine | ||
from tad.core.db import get_engine | ||
|
||
templates = Jinja2Templates(directory=settings.TEMPLATE_DIR) | ||
|
||
|
||
def get_db() -> Generator[Session, None, None]: | ||
with Session(engine) as session: | ||
def get_session() -> Generator[Session, None, None]: | ||
with Session(get_engine()) as session: | ||
yield session | ||
|
||
|
||
SessionDep = Annotated[Session, Depends(get_db)] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
from tad.core.exceptions import TADError | ||
|
||
|
||
class RepositoryError(TADError): | ||
def __init__(self, message: str = "Repository error"): | ||
self.message: str = message | ||
exception_name: str = self.__class__.__name__ | ||
super().__init__(f"{exception_name}: {self.message}") |
Oops, something went wrong.