diff --git a/docker-compose.prod.yaml b/docker-compose.prod.yaml index ff59b203..c00e5808 100644 --- a/docker-compose.prod.yaml +++ b/docker-compose.prod.yaml @@ -111,7 +111,7 @@ services: command: - "--cleanup" - "--schedule" - - "0 0 * * * * *" + - "0 0 * * * *" volumes: - /var/run/docker.sock:/var/run/docker.sock diff --git a/services/api/src/core/notifications/application/handlers/command-handlers/save-notification-subscription.handler.ts b/services/api/src/core/notifications/application/handlers/command-handlers/save-notification-subscription.handler.ts index 01ca8888..c39577b6 100644 --- a/services/api/src/core/notifications/application/handlers/command-handlers/save-notification-subscription.handler.ts +++ b/services/api/src/core/notifications/application/handlers/command-handlers/save-notification-subscription.handler.ts @@ -27,7 +27,7 @@ export class SaveNotificationSubscriptionHandler }, }; - this.notificationSubscriptionService.saveSubscription( + await this.notificationSubscriptionService.saveSubscription( currentProfileId, subscription, ); diff --git a/services/api/src/core/notifications/client/gateways/notification.web-push.gateway.ts b/services/api/src/core/notifications/client/gateways/notification.web-push.gateway.ts index 29c1d99a..2605037a 100644 --- a/services/api/src/core/notifications/client/gateways/notification.web-push.gateway.ts +++ b/services/api/src/core/notifications/client/gateways/notification.web-push.gateway.ts @@ -23,7 +23,7 @@ export class NotificationWebPushGateway { notification: INotification, ): Promise { const pushSubscription = - this.notificationSubscriptionService.getSubscription(profileId); + await this.notificationSubscriptionService.getSubscription(profileId); if (!pushSubscription) { return false; diff --git a/services/api/src/core/notifications/domain/services/notification-subscription.service.ts b/services/api/src/core/notifications/domain/services/notification-subscription.service.ts index a29c2af1..95617f16 100644 --- a/services/api/src/core/notifications/domain/services/notification-subscription.service.ts +++ b/services/api/src/core/notifications/domain/services/notification-subscription.service.ts @@ -1,15 +1,45 @@ import { Injectable } from "@nestjs/common"; +import { InjectRepository } from "@nestjs/typeorm"; +import { Repository } from "typeorm"; import { PushSubscription } from "web-push"; -const SUBSCRIPTIONS: Record = {}; +import { NotificationSubscription } from "../../infrastructure/entities/notification-subscription.entity"; @Injectable() export class NotificationSubscriptionService { - getSubscription(profileId: number): PushSubscription | undefined { - return SUBSCRIPTIONS[profileId]; + constructor( + @InjectRepository(NotificationSubscription) + private readonly notificationSubscriptions: Repository, + ) {} + + async getSubscription( + profileId: number, + ): Promise { + const notificationSubscription = + await this.notificationSubscriptions.findOne({ + where: { profileId }, + }); + + if (!notificationSubscription) { + return; + } + + return notificationSubscription.subscription as unknown as PushSubscription; } - saveSubscription(profileId: number, subscription: PushSubscription) { - SUBSCRIPTIONS[profileId] = subscription; + async saveSubscription(profileId: number, subscription: PushSubscription) { + let notificationSubscription = await this.notificationSubscriptions.findOne( + { + where: { profileId }, + }, + ); + + if (!notificationSubscription) { + notificationSubscription = new NotificationSubscription(); + notificationSubscription.profileId = profileId; + } + + notificationSubscription.subscription = subscription; + await this.notificationSubscriptions.save(notificationSubscription); } } diff --git a/services/api/src/core/notifications/infrastructure/entities/notification-subscription.entity.ts b/services/api/src/core/notifications/infrastructure/entities/notification-subscription.entity.ts new file mode 100644 index 00000000..a44d9b14 --- /dev/null +++ b/services/api/src/core/notifications/infrastructure/entities/notification-subscription.entity.ts @@ -0,0 +1,16 @@ +import { Column, Entity, ManyToOne } from "typeorm"; + +import { BaseEntity } from "src/core/database"; +import { Profile } from "src/core/profiles"; + +@Entity() +export class NotificationSubscription extends BaseEntity { + @ManyToOne(() => Profile, { onDelete: "CASCADE" }) + profile!: Profile; + + @Column() + profileId!: number; + + @Column("json") + subscription!: object; +} diff --git a/services/api/src/core/notifications/infrastructure/migrations/1721483513933-AddNotificationSubscription.ts b/services/api/src/core/notifications/infrastructure/migrations/1721483513933-AddNotificationSubscription.ts new file mode 100644 index 00000000..d3196c34 --- /dev/null +++ b/services/api/src/core/notifications/infrastructure/migrations/1721483513933-AddNotificationSubscription.ts @@ -0,0 +1,16 @@ +import { MigrationInterface, QueryRunner } from "typeorm"; + +export class AddNotificationSubscription1721483513933 implements MigrationInterface { + name = 'AddNotificationSubscription1721483513933' + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query(`CREATE TABLE "notification_subscription" ("id" uuid NOT NULL DEFAULT uuid_generate_v4(), "createdAt" TIMESTAMP NOT NULL DEFAULT now(), "updatedAt" TIMESTAMP NOT NULL DEFAULT now(), "profileId" integer NOT NULL, "subscription" json NOT NULL, CONSTRAINT "PK_d5c0b2efb91da0d584fddab9542" PRIMARY KEY ("id"))`); + await queryRunner.query(`ALTER TABLE "notification_subscription" ADD CONSTRAINT "FK_9ce8c93447319240e642238bff4" FOREIGN KEY ("profileId") REFERENCES "profile"("id") ON DELETE CASCADE ON UPDATE NO ACTION`); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query(`ALTER TABLE "notification_subscription" DROP CONSTRAINT "FK_9ce8c93447319240e642238bff4"`); + await queryRunner.query(`DROP TABLE "notification_subscription"`); + } + +} diff --git a/services/api/src/core/notifications/notification.module.ts b/services/api/src/core/notifications/notification.module.ts index 86d65c21..04031ccc 100644 --- a/services/api/src/core/notifications/notification.module.ts +++ b/services/api/src/core/notifications/notification.module.ts @@ -17,6 +17,7 @@ import { NotificationGateway } from "./client/gateways/notification.gateway"; import { NotificationWebPushGateway } from "./client/gateways/notification.web-push.gateway"; import { NotificationSubscriptionService } from "./domain/services/notification-subscription.service"; import { NotificationService } from "./domain/services/notification.service"; +import { NotificationSubscription } from "./infrastructure/entities/notification-subscription.entity"; import { Notification } from "./infrastructure/entities/notification.entity"; @Module({ @@ -29,7 +30,12 @@ import { Notification } from "./infrastructure/entities/notification.entity"; CqrsModule, EmailModule, QueryModule, - TypeOrmModule.forFeature([Notification, OrganizationMembership, Profile]), + TypeOrmModule.forFeature([ + Notification, + NotificationSubscription, + OrganizationMembership, + Profile, + ]), ], providers: [ NotificationGateway,