getting there
This commit is contained in:
parent
f87480e79d
commit
5ac6633d40
20 changed files with 898 additions and 112 deletions
|
|
@ -94,7 +94,7 @@ async def get_data(
|
|||
|
||||
block_rows = conn.execute(
|
||||
"""
|
||||
SELECT id, tag, description, is_done, created_at
|
||||
SELECT id, tag, description, is_done, difficulty, created_at
|
||||
FROM blocks
|
||||
WHERE tower_id = ?
|
||||
ORDER BY position
|
||||
|
|
@ -108,6 +108,7 @@ async def get_data(
|
|||
tag=b["tag"],
|
||||
description=b["description"],
|
||||
is_done=bool(b["is_done"]),
|
||||
difficulty=b["difficulty"],
|
||||
created_at=b["created_at"],
|
||||
)
|
||||
for b in block_rows
|
||||
|
|
@ -213,8 +214,9 @@ async def put_data(
|
|||
"""
|
||||
INSERT INTO blocks
|
||||
(id, tower_id, user_id, position, tag,
|
||||
description, is_done, created_at, updated_at)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
description, is_done, difficulty,
|
||||
created_at, updated_at)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
""",
|
||||
(
|
||||
block.id,
|
||||
|
|
@ -224,6 +226,7 @@ async def put_data(
|
|||
block.tag,
|
||||
block.description,
|
||||
1 if block.is_done else 0,
|
||||
block.difficulty,
|
||||
created_at,
|
||||
now,
|
||||
),
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ CREATE TABLE IF NOT EXISTS pages (
|
|||
position INTEGER NOT NULL,
|
||||
name TEXT NOT NULL,
|
||||
hide_create_tower_button INTEGER NOT NULL DEFAULT 0 CHECK (hide_create_tower_button IN (0, 1)),
|
||||
keep_tasks_open INTEGER NOT NULL DEFAULT 0 CHECK (keep_tasks_open IN (0, 1)),
|
||||
default_date_from INTEGER,
|
||||
default_date_to INTEGER,
|
||||
created_at INTEGER NOT NULL,
|
||||
|
|
@ -47,6 +48,7 @@ CREATE TABLE IF NOT EXISTS blocks (
|
|||
tag TEXT NOT NULL DEFAULT '',
|
||||
description TEXT NOT NULL DEFAULT '',
|
||||
is_done INTEGER NOT NULL DEFAULT 0 CHECK (is_done IN (0, 1)),
|
||||
difficulty INTEGER NOT NULL DEFAULT 1 CHECK (difficulty >= 1),
|
||||
created_at INTEGER NOT NULL,
|
||||
updated_at INTEGER NOT NULL
|
||||
) STRICT;
|
||||
|
|
|
|||
|
|
@ -1,2 +0,0 @@
|
|||
ALTER TABLE pages ADD COLUMN keep_tasks_open INTEGER NOT NULL DEFAULT 0
|
||||
CHECK (keep_tasks_open IN (0, 1));
|
||||
|
|
@ -27,6 +27,7 @@ class BlockIn(BaseModel):
|
|||
tag: str = Field(max_length=200)
|
||||
description: str = Field(max_length=10_000)
|
||||
is_done: bool
|
||||
difficulty: int = Field(default=1, ge=1, le=100)
|
||||
created_at: Optional[int] = None
|
||||
|
||||
@field_validator("id")
|
||||
|
|
@ -42,6 +43,7 @@ class BlockOut(BaseModel):
|
|||
tag: str
|
||||
description: str
|
||||
is_done: bool
|
||||
difficulty: int
|
||||
created_at: int
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -215,6 +215,7 @@ def _make_tree() -> dict:
|
|||
"tag": f"tag-{pi}-{ti}-{bi}",
|
||||
"description": f"desc-{pi}-{ti}-{bi}",
|
||||
"is_done": False,
|
||||
"difficulty": bi + 1,
|
||||
"created_at": 1700000000 + bi,
|
||||
}
|
||||
)
|
||||
|
|
@ -266,6 +267,42 @@ async def test_round_trip(client: AsyncClient) -> None:
|
|||
for bi, block in enumerate(tower["blocks"]):
|
||||
assert block["id"] == tree["pages"][pi]["towers"][ti]["blocks"][bi]["id"]
|
||||
assert block["tag"] == tree["pages"][pi]["towers"][ti]["blocks"][bi]["tag"]
|
||||
assert (
|
||||
block["difficulty"]
|
||||
== tree["pages"][pi]["towers"][ti]["blocks"][bi]["difficulty"]
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_difficulty_defaults_to_one_when_omitted(client: AsyncClient) -> None:
|
||||
"""A block sent without `difficulty` is stored and returned as 1."""
|
||||
token = make_uuidv4()
|
||||
await client.post("/api/v1/register", json={"token": token})
|
||||
headers = {"Authorization": f"Bearer {token}"}
|
||||
|
||||
tree = _make_tree()
|
||||
# Drop difficulty from the very first block.
|
||||
del tree["pages"][0]["towers"][0]["blocks"][0]["difficulty"]
|
||||
|
||||
put_resp = await client.put("/api/v1/data", json=tree, headers=headers)
|
||||
assert put_resp.status_code == 204
|
||||
|
||||
data = (await client.get("/api/v1/data", headers=headers)).json()
|
||||
assert data["pages"][0]["towers"][0]["blocks"][0]["difficulty"] == 1
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_difficulty_must_be_positive(client: AsyncClient) -> None:
|
||||
"""difficulty < 1 is rejected by validation."""
|
||||
token = make_uuidv4()
|
||||
await client.post("/api/v1/register", json={"token": token})
|
||||
headers = {"Authorization": f"Bearer {token}"}
|
||||
|
||||
tree = _make_tree()
|
||||
tree["pages"][0]["towers"][0]["blocks"][0]["difficulty"] = 0
|
||||
|
||||
resp = await client.put("/api/v1/data", json=tree, headers=headers)
|
||||
assert resp.status_code == 400
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue