| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183 |
- """The notes bundle (goal 8 task 3): the dashboard scratchpad — a
- personal todo list for batches of changes that are not ready to be
- full-on goals yet, with promote-to-goal (a DRAFT goal whose brief is
- the whole note body, the note frozen and linked to the goal)."""
- from harness import * # noqa: F401,F403 — the shared wire helpers
- def run(ctx):
- auth = ctx.auth
- def dashboard():
- return slot_public(auth, "/", "dashboard")
- def note_rows():
- return dashboard()["notes"]
- def note_by_body(fragment):
- rows = [n for n in note_rows() if fragment in n["body"]]
- return rows[0] if rows else None
- def db_one(sql, params=()):
- conn = db()
- try:
- return conn.execute(sql, params).fetchone()
- finally:
- conn.close()
- print("== notes: the dashboard carries the scratchpad ==")
- dash = dashboard()
- check(dash.get("add_note") is not None,
- "the dashboard exposes the add-note action")
- check(dash["notes"] == [],
- "the scratchpad starts empty")
- check(len(dash["projects"]) >= 1,
- "the promote form's project options list the projects")
- check(any(p["name"] == "demo" for p in dash["projects"]),
- "the demo project is a promote option")
- print("== notes: add ==")
- result = act(auth, dash["add_note"], {"body": ""})
- check(any(d.get("type") == "notify" and d.get("kind") == "error" for d in result),
- "an empty note body refuses")
- act(auth, dash["add_note"],
- {"body": "Fix the login redirect\n\nAlso cover the remember-me path in tests."})
- act(auth, dashboard()["add_note"], {"body": "Second note, older work"})
- rows = note_rows()
- check(len(rows) == 2,
- "added notes land in the list")
- check(rows[0]["body"] == "Second note, older work"
- and rows[1]["body"].startswith("Fix the login redirect"),
- "notes list newest first")
- first = note_by_body("Fix the login redirect")
- check(first["done"] is False and str(first["goal_id"]) == "0",
- "a fresh note is undone and unpromoted")
- check(first.get("toggle") is not None and first.get("delete") is not None
- and first.get("promote") is not None,
- "an undone unpromoted note carries toggle, delete and promote actions")
- print("== notes: toggle done -> ordering flips ==")
- act(auth, first["toggle"], {})
- rows = note_rows()
- check(rows[0]["body"] == "Second note, older work"
- and rows[1]["body"].startswith("Fix the login redirect"),
- "a done note sinks below every undone note")
- done_row = note_by_body("Fix the login redirect")
- check(done_row["done"] is True and len(done_row.get("done_display") or "") > 0,
- "the done flag sticks with its stamp")
- check(done_row.get("promote") is None,
- "a done note offers no promote action")
- conn = db()
- stamped = conn.execute(
- "select done, done_at from notes where id = ?", (first["id"],)).fetchone()
- conn.close()
- check(stamped is not None and stamped[0] == 1 and stamped[1] is not None,
- "the done transition stamped done_at in the database")
- # Toggle back: the note returns to the top and promote returns.
- act(auth, done_row["toggle"], {})
- rows = note_rows()
- check(rows[0]["body"] == "Second note, older work"
- and rows[1]["body"].startswith("Fix the login redirect"),
- "untoggling restores the newest-first ordering among undone notes")
- reopened = note_by_body("Fix the login redirect")
- check(reopened["done"] is False and reopened.get("promote") is not None,
- "an undone note regains its promote action")
- conn = db()
- cleared = conn.execute(
- "select done, done_at from notes where id = ?", (first["id"],)).fetchone()
- conn.close()
- check(cleared[0] == 0 and cleared[1] is None,
- "untoggling clears the done stamp")
- print("== notes: delete ==")
- act(auth, dashboard()["add_note"], {"body": "Throwaway note"})
- doomed = note_by_body("Throwaway note")
- act(auth, doomed["delete"], {})
- check(note_by_body("Throwaway note") is None,
- "a deleted note disappears from the list")
- conn = db()
- leftover = conn.execute(
- "select count(*) from notes where body like 'Throwaway%'").fetchone()[0]
- conn.close()
- check(leftover == 0, "the deleted note's row is gone")
- print("== notes: promote to goal ==")
- body = ("Fix the login redirect\n\nAlso cover the remember-me path in tests.\n"
- "The redirect should honour the originally requested page.")
- act(auth, dashboard()["add_note"], {"body": body})
- note = note_by_body("Fix the login redirect")
- promote = note["promote"]
- result = act(auth, promote,
- {"project_id": "1", "branch_name": "goal/note-promote"})
- navigated = [d for d in result if d.get("type") == "navigate"]
- check(len(navigated) == 1 and navigated[0].get("uri", "").startswith("/goals/"),
- "promoting navigates to the created goal's page")
- goal_id = int(navigated[0]["uri"].rsplit("/", 1)[1])
- goal_row = db_one("select id, project_id, title, brief, branch_name, status"
- " from goals where id = ?", (goal_id,))
- check(goal_row is not None,
- "promoting created a goal row")
- check(goal_row[1] == 1 and goal_row[4] == "goal/note-promote"
- and goal_row[5] == "draft",
- "the promoted goal sits on the chosen project and branch in draft")
- check(goal_row[3] == body,
- "the promoted goal's brief is the full note body")
- check(goal_row[2] == "Fix the login redirect",
- "the promoted goal's title is the note's first line")
- state = goal_state(goal_id)
- check(state.get("exists") and state.get("title") == "Fix the login redirect",
- "the goal page shows the promoted goal")
- rows = note_rows()
- promoted = [n for n in rows if n["id"] == note["id"]][0]
- check(str(promoted["goal_id"]) == str(goal_id)
- and promoted["goal_title"] == "Fix the login redirect",
- "the promoted note links its goal with the goal's title")
- check(promoted.get("promote") is None,
- "a promoted note is frozen (no further promote)")
- # Promoting a promoted note refuses — the action DTO is gone from
- # the slot, so the service-level guard is exercised via a direct
- # re-promote attempt through the old DTO.
- again = act(auth, promote, {"project_id": "1", "branch_name": "goal/note-promote-2"})
- check(any(d.get("type") == "notify" and d.get("kind") == "error"
- and "already promoted" in (d.get("message") or "") for d in again),
- "re-promoting a promoted note refuses with the frozen error")
- conn = db()
- duplicates = conn.execute(
- "select count(*) from goals where branch_name = 'goal/note-promote-2'"
- ).fetchone()[0]
- conn.close()
- check(duplicates == 0, "the refused re-promotion created no second goal")
- print("== notes: promote validation ==")
- act(auth, dashboard()["add_note"], {"body": "Never promoted\nbody"})
- bad = note_by_body("Never promoted")
- missing = act(auth, bad["promote"], {"project_id": "9999",
- "branch_name": "goal/notes-bad"})
- check(any(d.get("type") == "notify" and d.get("kind") == "error" for d in missing),
- "promoting onto a missing project refuses")
- nobranch = act(auth, note_by_body("Never promoted")["promote"],
- {"project_id": "1", "branch_name": ""})
- check(any(d.get("type") == "notify" and d.get("kind") == "error" for d in nobranch),
- "promoting without a branch name refuses")
- survivor = note_by_body("Never promoted")
- check(str(survivor["goal_id"]) == "0" and survivor.get("promote") is not None,
- "the refused promotions left the note unpromoted")
- print("== notes: the long-title clamp ==")
- long_line = "L" * 120 + "\nand a second line"
- act(auth, dashboard()["add_note"], {"body": long_line})
- clamped = note_by_body("LLLL")
- result = act(auth, clamped["promote"],
- {"project_id": "1", "branch_name": "goal/note-clamp"})
- goal_id2 = int([d for d in result if d.get("type") == "navigate"][0]["uri"]
- .rsplit("/", 1)[1])
- title = db_one("select title from goals where id = ?", (goal_id2,))[0]
- check(len(title) <= 81 and title.endswith("…"),
- "a first line over 80 characters clamps with an ellipsis")
- brief = db_one("select brief from goals where id = ?", (goal_id2,))[0]
- check(brief == long_line,
- "the clamped title never truncates the brief (the full body rides along)")
|