This commit is contained in:
Bastian Wagner
2026-06-29 15:25:14 +02:00
parent cadb198949
commit 9519409ec7
4 changed files with 267 additions and 38 deletions

View File

@@ -17,6 +17,13 @@ interface TaskDigestPushPayload {
overdueTasks: TaskDigestEmailItem[];
}
export interface TaskPushDigestResult {
enabled: boolean;
subscriptionCount: number;
sentCount: number;
failedCount: number;
}
@Injectable()
export class TaskPushService {
private readonly logger = new Logger(TaskPushService.name);
@@ -89,34 +96,47 @@ export class TaskPushService {
async sendTaskDigest(
userId: string,
payload: TaskDigestPushPayload,
): Promise<void> {
): Promise<TaskPushDigestResult> {
if (!this.configureWebPush()) {
this.logger.warn(
'Task push digest skipped because VAPID keys are not configured.',
);
return;
return {
enabled: false,
subscriptionCount: 0,
sentCount: 0,
failedCount: 0,
};
}
const subscriptions = await this.subscriptionsRepository.find({
where: { userId },
});
await Promise.all(
const results = await Promise.all(
subscriptions.map((subscription) =>
this.sendToSubscription(subscription, payload),
),
);
const sentCount = results.filter(Boolean).length;
return {
enabled: true,
subscriptionCount: subscriptions.length,
sentCount,
failedCount: subscriptions.length - sentCount,
};
}
private async sendToSubscription(
subscription: TaskPushSubscriptionEntity,
payload: TaskDigestPushPayload,
): Promise<void> {
): Promise<boolean> {
try {
await webPush.sendNotification(
this.toPushSubscription(subscription),
JSON.stringify(this.toNotificationPayload(payload)),
);
return true;
} catch (error) {
const statusCode =
typeof error === 'object' && error !== null && 'statusCode' in error
@@ -125,13 +145,14 @@ export class TaskPushService {
if (statusCode === 404 || statusCode === 410) {
await this.subscriptionsRepository.delete({ id: subscription.id });
return;
return false;
}
this.logger.error(
`Task push notification could not be sent to subscription ${subscription.id}.`,
error instanceof Error ? error.stack : undefined,
);
return false;
}
}