diff --git a/packages/backend/src/migration/1701546940248-add-notification-masto-id.ts b/packages/backend/src/migration/1701546940248-add-notification-masto-id.ts new file mode 100644 index 000000000..5e073d6ae --- /dev/null +++ b/packages/backend/src/migration/1701546940248-add-notification-masto-id.ts @@ -0,0 +1,15 @@ +import { MigrationInterface, QueryRunner } from "typeorm"; + +export class AddNotificationMastoId1701546940248 implements MigrationInterface { + name = 'AddNotificationMastoId1701546940248' + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query(`ALTER TABLE "notification" ADD "mastoId" SERIAL NOT NULL`); + await queryRunner.query(`CREATE UNIQUE INDEX "IDX_0ee0c7254e5612a8129251997e" ON "notification" ("mastoId") `); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query(`DROP INDEX "public"."IDX_0ee0c7254e5612a8129251997e"`); + await queryRunner.query(`ALTER TABLE "notification" DROP COLUMN "mastoId"`); + } +} diff --git a/packages/backend/src/models/entities/notification.ts b/packages/backend/src/models/entities/notification.ts index da23f7d3e..3ea93d371 100644 --- a/packages/backend/src/models/entities/notification.ts +++ b/packages/backend/src/models/entities/notification.ts @@ -4,7 +4,7 @@ import { JoinColumn, ManyToOne, Column, - PrimaryColumn, + PrimaryColumn, Generated, } from "typeorm"; import { User } from "./user.js"; import { id } from "../id.js"; @@ -181,4 +181,9 @@ export class Notification { }) @JoinColumn() public appAccessToken: AccessToken | null; + + @Index({ unique: true }) + @Column() + @Generated("increment") + public mastoId: number; } diff --git a/packages/backend/src/server/api/mastodon/converters/notification.ts b/packages/backend/src/server/api/mastodon/converters/notification.ts index fa0235e76..f6a4ee209 100644 --- a/packages/backend/src/server/api/mastodon/converters/notification.ts +++ b/packages/backend/src/server/api/mastodon/converters/notification.ts @@ -24,7 +24,7 @@ export class NotificationConverter { : UserConverter.encode(localUser, ctx); let result = { - id: notification.id, + id: notification.mastoId.toString(), account: account, created_at: notification.createdAt.toISOString(), type: this.encodeNotificationType(notification.type), diff --git a/packages/backend/src/server/api/mastodon/endpoints/notifications.ts b/packages/backend/src/server/api/mastodon/endpoints/notifications.ts index 49e791465..1f94f270b 100644 --- a/packages/backend/src/server/api/mastodon/endpoints/notifications.ts +++ b/packages/backend/src/server/api/mastodon/endpoints/notifications.ts @@ -20,7 +20,7 @@ export function setupEndpointsNotifications(router: Router): void { auth(true, ['read:notifications']), filterContext('notifications'), async (ctx) => { - const notification = await NotificationHelpers.getNotificationOr404(ctx.params.id, ctx); + const notification = await NotificationHelpers.getPushNotificationOr404(Number.parseInt(ctx.params.id), ctx); ctx.body = await NotificationConverter.encode(notification, ctx); } ); @@ -36,7 +36,7 @@ export function setupEndpointsNotifications(router: Router): void { router.post("/v1/notifications/:id/dismiss", auth(true, ['write:notifications']), async (ctx) => { - const notification = await NotificationHelpers.getNotificationOr404(ctx.params.id, ctx); + const notification = await NotificationHelpers.getPushNotificationOr404(Number.parseInt(ctx.params.id), ctx); await NotificationHelpers.dismissNotification(notification.id, ctx); ctx.body = {}; } diff --git a/packages/backend/src/server/api/mastodon/helpers/notification.ts b/packages/backend/src/server/api/mastodon/helpers/notification.ts index 7397a2dea..494fb7892 100644 --- a/packages/backend/src/server/api/mastodon/helpers/notification.ts +++ b/packages/backend/src/server/api/mastodon/helpers/notification.ts @@ -51,6 +51,18 @@ export class NotificationHelpers { }); } + public static async getPushNotification(id: number, ctx: MastoContext): Promise { + const user = ctx.user as ILocalUser; + return Notifications.findOneBy({ mastoId: id, notifieeId: user.id }); + } + + public static async getPushNotificationOr404(id: number, ctx: MastoContext): Promise { + return this.getPushNotification(id, ctx).then(p => { + if (p) return p; + throw new MastoApiError(404); + }); + } + public static async dismissNotification(id: string, ctx: MastoContext): Promise { const user = ctx.user as ILocalUser; await Notifications.update({ id: id, notifieeId: user.id }, { isRead: true }); diff --git a/packages/backend/src/server/api/mastodon/push/index.ts b/packages/backend/src/server/api/mastodon/push/index.ts index 417e217ca..d69a334b7 100644 --- a/packages/backend/src/server/api/mastodon/push/index.ts +++ b/packages/backend/src/server/api/mastodon/push/index.ts @@ -7,7 +7,6 @@ import { notificationTypes } from "@/types.js"; export class MastodonPushHandler { public static async sendPushNotification(n: Notification) { - const id = n.id; const userId = n.notifieeId; const type = this.encodeType(n.type); if (type === null) return; @@ -24,7 +23,7 @@ export class MastodonPushHandler { access_token: subscription.token?.token, title: meta.name ?? "Iceshrimp", body: "You have unread notifications", - notification_id: id, + notification_id: n.mastoId, notification_type: type, };