diff options
| author | Christophe Besson <cbesson@gmail.com> | 2026-09-02 12:55:05 +0200 |
|---|---|---|
| committer | Christophe Besson <cbesson@gmail.com> | 2026-09-02 12:55:05 +0200 |
| commit | 16b5e5c463ec998c6434bbf2ef39113ed01da801 (patch) | |
| tree | e8c7f65517af3235013a660641079d02251e679f /packages/meshbay-hub/tests/test_notifications.py | |
| parent | a194b333169efb5e25bc05c94567600eec8bb823 (diff) | |
| download | meshbay-16b5e5c463ec998c6434bbf2ef39113ed01da801.tar.gz | |
fix(hub): dismissing a notification deletes it
The previous commit filtered the list to unread, which corrected what the
reader saw and left every dismissed row in the table, invisible for ever. That
is a place to hide the disagreement rather than a resolution, and the operator
said so: "elles s'accumulent pour rien."
So dismissing drops the row. It is the reasoning `purge_notifications` has
carried all along — "these are signals, not a record: the group is still
there, the message is still in the chat, the invitation is still an
invitation" — applied one at a time instead of only in bulk.
- `DELETE /v1/notifications/{id}` is the honest name and what the SPA calls.
- `POST /{id}/read` reaches the same handler and now deletes too. It has to
keep working: the interface ships inside the desktop package, so a hub is
always answering some client older than itself, and giving the old path the
new behaviour means those clients stop hoarding as well rather than only the
updated ones.
- `read-all` deletes rather than marking, which makes it `DELETE ""` under an
older name. Marking would have made it the one route still filling the
table. Nothing in this repo calls it, but a reachable endpoint is one that
can be called.
`Notification.read` is now vestigial — nothing stored can be read, because
reading it deletes it. It stays because dropping a column is a migration for
no gain, and `unread_only` stays because a SPA newer than its hub still needs
it to be right. Both are said in the module docstring rather than left to be
worked out.
Two existing tests encoded the old semantics and now assert the opposite;
test_notification_dismissal.py gains one for the old `/read` path, because
version skew is the normal case here and not the exception. 617 hub tests
pass. docs/USERGUIDE.md's endpoint table updated in both places it lists them.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014UtzVrzM7e2tG9fSpkR9ML
Diffstat (limited to 'packages/meshbay-hub/tests/test_notifications.py')
| -rw-r--r-- | packages/meshbay-hub/tests/test_notifications.py | 13 |
1 files changed, 10 insertions, 3 deletions
diff --git a/packages/meshbay-hub/tests/test_notifications.py b/packages/meshbay-hub/tests/test_notifications.py index 8da589a..35ed288 100644 --- a/packages/meshbay-hub/tests/test_notifications.py +++ b/packages/meshbay-hub/tests/test_notifications.py @@ -92,7 +92,7 @@ async def test_notification_on_suspend(client): @pytest.mark.asyncio -async def test_mark_notification_read(client): +async def test_dismissing_one_deletes_it(client): _, admin_token = await _setup_admin(client) uid = await _register(client, "alice", email="a@x.com") alice_token = await _login(client, "alice") @@ -105,6 +105,8 @@ async def test_mark_notification_read(client): headers={"Authorization": f"Bearer {alice_token}"}) nid = r.json()["notifications"][0]["id"] + # `/read` is the old path and still the one older clients call. It + # dismisses, like DELETE — see api/notifications.py. r = await client.post(f"/v1/notifications/{nid}/read", headers={"Authorization": f"Bearer {alice_token}"}) assert r.status_code == 200 @@ -112,11 +114,13 @@ async def test_mark_notification_read(client): r = await client.get("/v1/notifications", headers={"Authorization": f"Bearer {alice_token}"}) assert r.json()["unread_count"] == 0 - assert r.json()["notifications"][0]["read"] is True + assert r.json()["notifications"] == [], ( + "a dismissed notification is deleted, not kept as a row nothing can " + "ever show again") @pytest.mark.asyncio -async def test_mark_all_read(client): +async def test_dismissing_all_deletes_them(client): _, admin_token = await _setup_admin(client) uid = await _register(client, "alice", email="a@x.com") alice_token = await _login(client, "alice") @@ -135,10 +139,13 @@ async def test_mark_all_read(client): r = await client.post("/v1/notifications/read-all", headers={"Authorization": f"Bearer {alice_token}"}) assert r.status_code == 200 + assert r.json()["removed"] == 2 r = await client.get("/v1/notifications", headers={"Authorization": f"Bearer {alice_token}"}) assert r.json()["unread_count"] == 0 + assert r.json()["notifications"] == [], ( + "read-all must not be the one route that still hoards rows") @pytest.mark.asyncio |