Skip to content

Commit

Permalink
Delete all notification subscriptions
Browse files Browse the repository at this point in the history
  • Loading branch information
PooyaRaki committed Dec 24, 2024
1 parent a76b391 commit ebd1e7d
Show file tree
Hide file tree
Showing 5 changed files with 61 additions and 14 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,13 @@ export interface INotificationsRepositoryV2 {
notification: FirebaseNotification;
}): Promise<void>;

upsertSubscriptions(args: {
authPayload: AuthPayload;
upsertSubscriptionsDto: UpsertSubscriptionsDto;
}): Promise<{
upsertSubscriptions(
args: {
authPayload: AuthPayload;
upsertSubscriptionsDto: UpsertSubscriptionsDto;
},
deleteAllDeviceOwners?: boolean,
): Promise<{
deviceUuid: UUID;
}>;

Expand Down
34 changes: 30 additions & 4 deletions src/domain/notifications/v2/notifications.repository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,15 +92,24 @@ export class NotificationsRepositoryV2 implements INotificationsRepositoryV2 {
return isNotFound && isUnregistered;
}

public async upsertSubscriptions(args: {
authPayload: AuthPayload;
upsertSubscriptionsDto: UpsertSubscriptionsDto;
}): Promise<{
public async upsertSubscriptions(
args: {
authPayload: AuthPayload;
upsertSubscriptionsDto: UpsertSubscriptionsDto;
},
deleteAllDeviceOwners?: boolean,
): Promise<{
deviceUuid: UUID;
}> {
const deviceUuid = await this.postgresDatabaseService.transaction(
async (entityManager: EntityManager): Promise<UUID> => {
const device = await this.upsertDevice(entityManager, args);
if (deleteAllDeviceOwners) {
// Some clients, such as the mobile app, do not call the delete endpoint to remove an owner key.
// Instead, they resend the updated list of owners without the key they want to delete.
// In such cases, we need to clear all the previous owners to ensure the update is applied correctly.
await this.deleteDeviceOwners(entityManager, device.id);
}
await this.deletePreviousSubscriptions(entityManager, {
deviceId: device.id,
signerAddress: args.authPayload.signer_address,
Expand Down Expand Up @@ -147,6 +156,23 @@ export class NotificationsRepositoryV2 implements INotificationsRepositoryV2 {
return { id: queryResult.identifiers[0].id, device_uuid: deviceUuid };
}

private async deleteDeviceOwners(
entityManager: EntityManager,
deviceId: number,
): Promise<void> {
const deviceSubscriptions = await entityManager.find(
NotificationSubscription,
{
where: {
push_notification_device: {
id: deviceId,
},
},
},
);
await entityManager.remove(deviceSubscriptions);
}

private async deletePreviousSubscriptions(
entityManager: EntityManager,
args: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ import {
LoggingService,
type ILoggingService,
} from '@/logging/logging.interface';
import { DeviceType } from '@/domain/notifications/v1/entities/device.entity';

describe('Notifications Controller (Unit)', () => {
let app: INestApplication<Server>;
Expand Down Expand Up @@ -167,6 +168,9 @@ describe('Notifications Controller (Unit)', () => {
.expect(200)
.expect({});

const deleteAllDeviceOwners =
registerDeviceDto.deviceType !== DeviceType.Web;

// @TODO Remove NotificationModuleV2 after all clients have migrated and compatibility is no longer needed.
// We call V2 as many times as we have a registration with at least one safe
const safeRegistrationsWithSafe =
Expand All @@ -185,7 +189,11 @@ describe('Notifications Controller (Unit)', () => {
const nthCall = index + 1; // Convert zero-based index to a one-based call number
expect(
notificationServiceV2.upsertSubscriptions,
).toHaveBeenNthCalledWith(nthCall, upsertSubscriptionsV2);
).toHaveBeenNthCalledWith(
nthCall,
upsertSubscriptionsV2,
deleteAllDeviceOwners,
);
}
},
);
Expand Down
4 changes: 4 additions & 0 deletions src/routes/notifications/v1/notifications.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,10 +77,14 @@ export class NotificationsController {

const v2Requests = [];

const deleteAllDeviceOwners =
registerDeviceDto.deviceType !== DeviceType.Web;

for (const compatibleV2Request of compatibleV2Requests) {
v2Requests.push(
await this.notificationServiceV2.upsertSubscriptions(
compatibleV2Request,
deleteAllDeviceOwners,
),
);
}
Expand Down
16 changes: 11 additions & 5 deletions src/routes/notifications/v2/notifications.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,19 @@ export class NotificationsServiceV2 {
private readonly notificationsRepository: INotificationsRepositoryV2,
) {}

async upsertSubscriptions(args: {
authPayload: AuthPayload;
upsertSubscriptionsDto: UpsertSubscriptionsDto;
}): Promise<{
async upsertSubscriptions(
args: {
authPayload: AuthPayload;
upsertSubscriptionsDto: UpsertSubscriptionsDto;
},
deleteAllDeviceOwners?: boolean,
): Promise<{
deviceUuid: UUID;
}> {
return this.notificationsRepository.upsertSubscriptions(args);
return this.notificationsRepository.upsertSubscriptions(
args,
deleteAllDeviceOwners,
);
}

async getSafeSubscription(args: {
Expand Down

0 comments on commit ebd1e7d

Please sign in to comment.