Skip to content

Commit

Permalink
chore(api): add notification subscription database entity (#910)
Browse files Browse the repository at this point in the history
* chore(api): add notification subscription database entity

* chore(repo): fix typo in watchtower cron job

* feat(api): persist notification subscription in database

---------

Co-authored-by: Johan Book <{ID}+{username}@users.noreply.github.com>
  • Loading branch information
johanbook and Johan Book authored Jul 20, 2024
1 parent 0466036 commit 5a6aa2b
Show file tree
Hide file tree
Showing 7 changed files with 77 additions and 9 deletions.
2 changes: 1 addition & 1 deletion docker-compose.prod.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ services:
command:
- "--cleanup"
- "--schedule"
- "0 0 * * * * *"
- "0 0 * * * *"
volumes:
- /var/run/docker.sock:/var/run/docker.sock

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ export class SaveNotificationSubscriptionHandler
},
};

this.notificationSubscriptionService.saveSubscription(
await this.notificationSubscriptionService.saveSubscription(
currentProfileId,
subscription,
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ export class NotificationWebPushGateway {
notification: INotification,
): Promise<boolean> {
const pushSubscription =
this.notificationSubscriptionService.getSubscription(profileId);
await this.notificationSubscriptionService.getSubscription(profileId);

if (!pushSubscription) {
return false;
Expand Down
Original file line number Diff line number Diff line change
@@ -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<number, PushSubscription> = {};
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<NotificationSubscription>,
) {}

async getSubscription(
profileId: number,
): Promise<PushSubscription | undefined> {
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);
}
}
Original file line number Diff line number Diff line change
@@ -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;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { MigrationInterface, QueryRunner } from "typeorm";

export class AddNotificationSubscription1721483513933 implements MigrationInterface {
name = 'AddNotificationSubscription1721483513933'

public async up(queryRunner: QueryRunner): Promise<void> {
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<void> {
await queryRunner.query(`ALTER TABLE "notification_subscription" DROP CONSTRAINT "FK_9ce8c93447319240e642238bff4"`);
await queryRunner.query(`DROP TABLE "notification_subscription"`);
}

}
8 changes: 7 additions & 1 deletion services/api/src/core/notifications/notification.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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({
Expand All @@ -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,
Expand Down

0 comments on commit 5a6aa2b

Please sign in to comment.