mirror of
https://gitlab.com/soapbox-pub/ditto.git
synced 2025-12-06 11:29:46 +00:00
Move push notification rendering to its own view
This commit is contained in:
parent
8bf0a443db
commit
7fbda4a56b
3 changed files with 65 additions and 23 deletions
|
|
@ -2,7 +2,6 @@ import { NKinds, NostrEvent, NSchema as n } from '@nostrify/nostrify';
|
||||||
import { Stickynotes } from '@soapbox/stickynotes';
|
import { Stickynotes } from '@soapbox/stickynotes';
|
||||||
import { Kysely, sql } from 'kysely';
|
import { Kysely, sql } from 'kysely';
|
||||||
import { LRUCache } from 'lru-cache';
|
import { LRUCache } from 'lru-cache';
|
||||||
import { nip19 } from 'nostr-tools';
|
|
||||||
import { z } from 'zod';
|
import { z } from 'zod';
|
||||||
|
|
||||||
import { Conf } from '@/config.ts';
|
import { Conf } from '@/config.ts';
|
||||||
|
|
@ -14,7 +13,6 @@ import { RelayError } from '@/RelayError.ts';
|
||||||
import { AdminSigner } from '@/signers/AdminSigner.ts';
|
import { AdminSigner } from '@/signers/AdminSigner.ts';
|
||||||
import { hydrateEvents } from '@/storages/hydrate.ts';
|
import { hydrateEvents } from '@/storages/hydrate.ts';
|
||||||
import { Storages } from '@/storages.ts';
|
import { Storages } from '@/storages.ts';
|
||||||
import { MastodonPush } from '@/types/MastodonPush.ts';
|
|
||||||
import { eventAge, parseNip05, Time } from '@/utils.ts';
|
import { eventAge, parseNip05, Time } from '@/utils.ts';
|
||||||
import { getAmount } from '@/utils/bolt11.ts';
|
import { getAmount } from '@/utils/bolt11.ts';
|
||||||
import { detectLanguage } from '@/utils/language.ts';
|
import { detectLanguage } from '@/utils/language.ts';
|
||||||
|
|
@ -22,7 +20,7 @@ import { nip05Cache } from '@/utils/nip05.ts';
|
||||||
import { purifyEvent } from '@/utils/purify.ts';
|
import { purifyEvent } from '@/utils/purify.ts';
|
||||||
import { updateStats } from '@/utils/stats.ts';
|
import { updateStats } from '@/utils/stats.ts';
|
||||||
import { getTagSet } from '@/utils/tags.ts';
|
import { getTagSet } from '@/utils/tags.ts';
|
||||||
import { renderNotification } from '@/views/mastodon/notifications.ts';
|
import { renderWebPushNotification } from '@/views/mastodon/push.ts';
|
||||||
import { policyWorker } from '@/workers/policy.ts';
|
import { policyWorker } from '@/workers/policy.ts';
|
||||||
import { verifyEventWorker } from '@/workers/verify.ts';
|
import { verifyEventWorker } from '@/workers/verify.ts';
|
||||||
|
|
||||||
|
|
@ -257,12 +255,14 @@ async function webPush(event: NostrEvent): Promise<void> {
|
||||||
.execute();
|
.execute();
|
||||||
|
|
||||||
for (const row of rows) {
|
for (const row of rows) {
|
||||||
if (row.pubkey === event.pubkey) {
|
const viewerPubkey = row.pubkey;
|
||||||
|
|
||||||
|
if (viewerPubkey === event.pubkey) {
|
||||||
continue; // Don't notify authors about their own events.
|
continue; // Don't notify authors about their own events.
|
||||||
}
|
}
|
||||||
|
|
||||||
const notification = await renderNotification(event, { viewerPubkey: row.pubkey });
|
const message = await renderWebPushNotification(event, viewerPubkey);
|
||||||
if (!notification) {
|
if (!message) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -274,18 +274,8 @@ async function webPush(event: NostrEvent): Promise<void> {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
const message: MastodonPush = {
|
|
||||||
notification_id: notification.id,
|
|
||||||
notification_type: notification.type,
|
|
||||||
access_token: nip19.npubEncode(row.pubkey),
|
|
||||||
preferred_locale: 'en',
|
|
||||||
title: notification.account.display_name || notification.account.username,
|
|
||||||
icon: notification.account.avatar_static,
|
|
||||||
body: event.content,
|
|
||||||
};
|
|
||||||
|
|
||||||
await DittoPush.push(subscription, message);
|
await DittoPush.push(subscription, message);
|
||||||
webPushNotificationsCounter.inc({ type: notification.type });
|
webPushNotificationsCounter.inc({ type: message.notification_type });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -44,7 +44,7 @@ async function renderMention(event: DittoEvent, opts: RenderNotificationOpts) {
|
||||||
|
|
||||||
return {
|
return {
|
||||||
id: notificationId(event),
|
id: notificationId(event),
|
||||||
type: 'mention',
|
type: 'mention' as const,
|
||||||
created_at: nostrDate(event.created_at).toISOString(),
|
created_at: nostrDate(event.created_at).toISOString(),
|
||||||
account: status.account,
|
account: status.account,
|
||||||
status: status,
|
status: status,
|
||||||
|
|
@ -59,7 +59,7 @@ async function renderReblog(event: DittoEvent, opts: RenderNotificationOpts) {
|
||||||
|
|
||||||
return {
|
return {
|
||||||
id: notificationId(event),
|
id: notificationId(event),
|
||||||
type: 'reblog',
|
type: 'reblog' as const,
|
||||||
created_at: nostrDate(event.created_at).toISOString(),
|
created_at: nostrDate(event.created_at).toISOString(),
|
||||||
account,
|
account,
|
||||||
status,
|
status,
|
||||||
|
|
@ -74,7 +74,7 @@ async function renderFavourite(event: DittoEvent, opts: RenderNotificationOpts)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
id: notificationId(event),
|
id: notificationId(event),
|
||||||
type: 'favourite',
|
type: 'favourite' as const,
|
||||||
created_at: nostrDate(event.created_at).toISOString(),
|
created_at: nostrDate(event.created_at).toISOString(),
|
||||||
account,
|
account,
|
||||||
status,
|
status,
|
||||||
|
|
@ -89,7 +89,7 @@ async function renderReaction(event: DittoEvent, opts: RenderNotificationOpts) {
|
||||||
|
|
||||||
return {
|
return {
|
||||||
id: notificationId(event),
|
id: notificationId(event),
|
||||||
type: 'pleroma:emoji_reaction',
|
type: 'pleroma:emoji_reaction' as const,
|
||||||
emoji: event.content,
|
emoji: event.content,
|
||||||
emoji_url: event.tags.find(([name, value]) => name === 'emoji' && `:${value}:` === event.content)?.[2],
|
emoji_url: event.tags.find(([name, value]) => name === 'emoji' && `:${value}:` === event.content)?.[2],
|
||||||
created_at: nostrDate(event.created_at).toISOString(),
|
created_at: nostrDate(event.created_at).toISOString(),
|
||||||
|
|
@ -106,7 +106,7 @@ async function renderNameGrant(event: DittoEvent) {
|
||||||
|
|
||||||
return {
|
return {
|
||||||
id: notificationId(event),
|
id: notificationId(event),
|
||||||
type: 'ditto:name_grant',
|
type: 'ditto:name_grant' as const,
|
||||||
name: d,
|
name: d,
|
||||||
created_at: nostrDate(event.created_at).toISOString(),
|
created_at: nostrDate(event.created_at).toISOString(),
|
||||||
account,
|
account,
|
||||||
|
|
@ -125,7 +125,7 @@ async function renderZap(event: DittoEvent, opts: RenderNotificationOpts) {
|
||||||
|
|
||||||
return {
|
return {
|
||||||
id: notificationId(event),
|
id: notificationId(event),
|
||||||
type: 'ditto:zap',
|
type: 'ditto:zap' as const,
|
||||||
amount: zap_amount,
|
amount: zap_amount,
|
||||||
message: zap_message,
|
message: zap_message,
|
||||||
created_at: nostrDate(event.created_at).toISOString(),
|
created_at: nostrDate(event.created_at).toISOString(),
|
||||||
|
|
|
||||||
52
src/views/mastodon/push.ts
Normal file
52
src/views/mastodon/push.ts
Normal file
|
|
@ -0,0 +1,52 @@
|
||||||
|
import type { NostrEvent } from '@nostrify/nostrify';
|
||||||
|
import { nip19 } from 'nostr-tools';
|
||||||
|
|
||||||
|
import { MastodonPush } from '@/types/MastodonPush.ts';
|
||||||
|
import { renderNotification } from '@/views/mastodon/notifications.ts';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Render a web push notification for the viewer.
|
||||||
|
* Unlike other views, only one will be rendered at a time, so making use of async calls is okay.
|
||||||
|
*/
|
||||||
|
export async function renderWebPushNotification(
|
||||||
|
event: NostrEvent,
|
||||||
|
viewerPubkey: string,
|
||||||
|
): Promise<MastodonPush | undefined> {
|
||||||
|
const notification = await renderNotification(event, { viewerPubkey });
|
||||||
|
if (!notification) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
notification_id: notification.id,
|
||||||
|
notification_type: notification.type,
|
||||||
|
access_token: nip19.npubEncode(viewerPubkey),
|
||||||
|
preferred_locale: 'en',
|
||||||
|
title: renderTitle(notification),
|
||||||
|
icon: notification.account.avatar_static,
|
||||||
|
body: event.content,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
type MastodonNotification = NonNullable<Awaited<ReturnType<typeof renderNotification>>>;
|
||||||
|
|
||||||
|
function renderTitle(notification: MastodonNotification): string {
|
||||||
|
const { account } = notification;
|
||||||
|
|
||||||
|
switch (notification.type) {
|
||||||
|
case 'ditto:name_grant':
|
||||||
|
return `You were granted the name ${notification.name}`;
|
||||||
|
case 'ditto:zap':
|
||||||
|
return `${account.display_name} zapped you ${notification.amount} sats`;
|
||||||
|
case 'pleroma:emoji_reaction':
|
||||||
|
return `${account.display_name} reacted to your post`;
|
||||||
|
case 'favourite':
|
||||||
|
return `${account.display_name} liked your post`;
|
||||||
|
case 'mention':
|
||||||
|
return `${account.display_name} mentioned you`;
|
||||||
|
case 'reblog':
|
||||||
|
return `${account.display_name} reposted your post`;
|
||||||
|
default:
|
||||||
|
return account.display_name || account.username;
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Add table
Reference in a new issue