From 325f7605f2134f28cf6258ec982856349d681f6f Mon Sep 17 00:00:00 2001 From: thepra Date: Mon, 5 Oct 2026 04:18:46 +0200 Subject: [PATCH] A notifications marker reads what it passes Saving the notifications marker (/api/v1/markers) moved the marker but left every notification unread, so a Mastodon client's unread count never fell. The marker now marks read every notification up to it. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01LsXgEaXee4GCU1hwYgPJXw --- PrivaPub.Tests/Http/OneAnswerTests.cs | 5 +++++ PrivaPub/Api/Mastodon/Controllers/TimelinesController.cs | 4 ++++ 2 files changed, 9 insertions(+) diff --git a/PrivaPub.Tests/Http/OneAnswerTests.cs b/PrivaPub.Tests/Http/OneAnswerTests.cs index c5f42b2..afde234 100644 --- a/PrivaPub.Tests/Http/OneAnswerTests.cs +++ b/PrivaPub.Tests/Http/OneAnswerTests.cs @@ -176,6 +176,11 @@ namespace PrivaPub.Tests.Http Assert.True((await author.Client.Get("/api/v2/notifications/unread_count")).Ok().Body.Number("count") >= 1); Assert.Equal(key, Assert.Single((await author.Client.Get($"/api/v2/notifications/{key}")).Ok().Body["notification_groups"]!.AsArray())!.Text("group_key")); Assert.Equal(2, (await author.Client.Get($"/api/v2/notifications/{key}/accounts")).Ok().Array.Count); + // a notifications marker past them reads them + var newest = (await author.Client.Get("/api/v1/notifications")).Ok().Ids.First(); + (await author.Client.Post("/api/v1/markers", ("notifications[last_read_id]", newest))).Ok(); + Assert.Equal(0, (await author.Client.Get("/api/v2/notifications/unread_count")).Ok().Body.Number("count")); + Assert.Equal(0, (await author.Client.Get("/api/v1/notifications/unread_count")).Ok().Body.Number("count")); Assert.Equal(HttpStatusCode.OK, (await author.Client.Post($"/api/v2/notifications/{key}/dismiss")).Status); Assert.Equal(HttpStatusCode.NotFound, (await author.Client.Get($"/api/v2/notifications/{key}")).Status); } diff --git a/PrivaPub/Api/Mastodon/Controllers/TimelinesController.cs b/PrivaPub/Api/Mastodon/Controllers/TimelinesController.cs index 506f645..c99f298 100644 --- a/PrivaPub/Api/Mastodon/Controllers/TimelinesController.cs +++ b/PrivaPub/Api/Mastodon/Controllers/TimelinesController.cs @@ -146,6 +146,10 @@ namespace PrivaPub.Api.Mastodon.Controllers .Option(o => o.IsUpsert = true) .ExecuteAsync(token); result[timeline] = new Entities.Marker { LastReadId = marker.LastReadId, Version = marker.Version, UpdatedAt = MastodonJson.Time(marker.UpdatedAt) }; + // what the marker passes is read: the unread count (v1 and v2) counts only what is newer + if (timeline == "notifications") + await DB.Default.Update().Match(n => n.AvatarId == MyId && !n.IsRead) + .Match(f => f.Lte(n => n.ID, lastRead)).Modify(n => n.IsRead, true).ExecuteAsync(token); } return Json(result); }