Skip to content

Commit f034214

Browse files
dahliaclaude
andcommitted
Implement Mastodon 4.5.0 quote notification types
Add support for 'quote' and 'quoted_update' notification types introduced in Mastodon 4.5.0 (API v7) to improve quote post interaction tracking. New notification types: - 'quote': Notifies when someone quotes your post, showing the quote post itself - 'quoted_update': Notifies when a post you quoted is edited, showing your quote post for context Both types are non-groupable (individual notifications) and self-quotes don't generate notifications. Existing quote posts are automatically backfilled with notifications during migration. Database changes: - Added 'quote' and 'quoted_update' to notification_type enum - Added partial index on posts.quote_target_id for performance - Single migration with explicit COMMIT for enum and backfill Implementation: - src/notification.ts: New createQuoteNotification and createQuotedUpdateNotifications functions - src/federation/inbox.ts: Quote notification creation in onPostCreated and onPostUpdated handlers - src/api/v1/notifications.ts, src/api/v2/notifications.ts: Added new types to API endpoints - src/notification.test.ts: 7 test cases covering all scenarios Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
1 parent ffee1a6 commit f034214

File tree

10 files changed

+4350
-1
lines changed

10 files changed

+4350
-1
lines changed

CHANGES.md

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,26 @@ To be released.
9797
URL-encoded form data even when `Content-Type` is missing or set to
9898
`text/plain`.
9999

100+
- Implemented Mastodon 4.5.0 quote notification types (`quote` and
101+
`quoted_update`) for improved quote post interaction tracking.
102+
Users now receive notifications when their posts are quoted by others
103+
and when posts they've quoted are edited by the original authors.
104+
Key features include:
105+
106+
- Added `quote` notification type that triggers when someone quotes
107+
your post, with the notification showing the quote post itself.
108+
- Added `quoted_update` notification type that triggers when a post
109+
you quoted is edited, with the notification showing your quote post
110+
to provide context.
111+
- Both notification types are non-groupable, meaning each quote or edit
112+
generates an individual notification for better visibility.
113+
- Self-quotes (quoting your own posts) do not generate notifications
114+
to avoid unnecessary noise.
115+
- Existing quote posts are automatically backfilled with notifications
116+
during migration to ensure consistent notification history.
117+
- Added database index on `posts.quote_target_id` for improved query
118+
performance when looking up quote relationships.
119+
100120
[#94]: https://github.com/fedify-dev/hollo/issues/94
101121
[#312]: https://github.com/fedify-dev/hollo/issues/312
102122
[#170]: https://github.com/fedify-dev/hollo/issues/170

drizzle/0076_fair_frank_castle.sql

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
ALTER TYPE "public"."notification_type" ADD VALUE 'quote';--> statement-breakpoint
2+
ALTER TYPE "public"."notification_type" ADD VALUE 'quoted_update';--> statement-breakpoint
3+
COMMIT;--> statement-breakpoint
4+
5+
-- Backfill notifications for existing quote posts
6+
INSERT INTO notifications (id, account_owner_id, type, actor_account_id, target_post_id, group_key, created)
7+
SELECT
8+
gen_random_uuid(),
9+
ao.id as account_owner_id,
10+
'quote'::notification_type as type,
11+
p.actor_id as actor_account_id,
12+
p.id as target_post_id,
13+
'ungrouped:' || gen_random_uuid() as group_key,
14+
p.published as created
15+
FROM posts p
16+
INNER JOIN posts target ON p.quote_target_id = target.id
17+
INNER JOIN accounts target_account ON target.actor_id = target_account.id
18+
INNER JOIN account_owners ao ON target_account.id = ao.id
19+
WHERE p.quote_target_id IS NOT NULL
20+
AND p.actor_id != target.actor_id -- Exclude self-quotes
21+
ON CONFLICT DO NOTHING;--> statement-breakpoint
22+
23+
-- Create notification groups for backfilled quote notifications
24+
INSERT INTO notification_groups (group_key, account_owner_id, type, notifications_count, most_recent_notification_id, sample_account_ids)
25+
SELECT DISTINCT
26+
n.group_key,
27+
n.account_owner_id,
28+
'quote'::notification_type,
29+
1,
30+
n.id,
31+
ARRAY[n.actor_account_id]
32+
FROM notifications n
33+
WHERE n.type = 'quote'
34+
AND NOT EXISTS (
35+
SELECT 1 FROM notification_groups ng WHERE ng.group_key = n.group_key
36+
)
37+
ON CONFLICT DO NOTHING;--> statement-breakpoint
38+
39+
CREATE INDEX "posts_quote_target_id_index" ON "posts" USING btree ("quote_target_id") WHERE "posts"."quote_target_id" is not null;

0 commit comments

Comments
 (0)