From a7b60c6a8318c6653b82c77d2b5449ff53205ca5 Mon Sep 17 00:00:00 2001
From: Kristina <kristin.fefelova@gmail.com>
Date: Wed, 11 Sep 2024 06:15:11 +0400
Subject: [PATCH] Request push subscriptions with one find (#6518)

---
 .../activity-resources/src/references.ts      |  6 +++-
 server-plugins/love-resources/src/index.ts    | 11 ++++--
 .../notification-resources/src/index.ts       | 36 ++++++++++++++-----
 server-plugins/request-resources/src/index.ts |  7 ++--
 4 files changed, 47 insertions(+), 13 deletions(-)

diff --git a/server-plugins/activity-resources/src/references.ts b/server-plugins/activity-resources/src/references.ts
index 512b7e90d4..d2e66a7531 100644
--- a/server-plugins/activity-resources/src/references.ts
+++ b/server-plugins/activity-resources/src/references.ts
@@ -253,6 +253,9 @@ export async function getPersonNotificationTxes (
         modifiedOn: originTx.modifiedOn,
         modifiedBy: sender._id
       }
+      const subscriptions = await control.findAll(control.ctx, notification.class.PushSubscription, {
+        user: receiverInfo._id
+      })
       await applyNotificationProviders(
         notificationData,
         notifyResult,
@@ -262,7 +265,8 @@ export async function getPersonNotificationTxes (
         res,
         doc,
         receiverInfo,
-        senderInfo
+        senderInfo,
+        subscriptions
       )
     }
   }
diff --git a/server-plugins/love-resources/src/index.ts b/server-plugins/love-resources/src/index.ts
index 372d962c7a..c575789107 100644
--- a/server-plugins/love-resources/src/index.ts
+++ b/server-plugins/love-resources/src/index.ts
@@ -284,8 +284,12 @@ export async function OnKnock (tx: Tx, control: TriggerControl): Promise<Tx[]> {
             const body = await translate(love.string.IsKnocking, {
               name: formatName(from.name, control.branding?.lastNameFirst)
             })
+
+            const subscriptions = await control.findAll(control.ctx, notification.class.PushSubscription, {
+              user: userAcc[0]._id
+            })
             // TODO: Select proper account target
-            await createPushNotification(control, userAcc[0]._id, title, body, request._id, from, path)
+            await createPushNotification(control, userAcc[0]._id, title, body, request._id, subscriptions, from, path)
           }
         }
         return res
@@ -323,8 +327,11 @@ export async function OnInvite (tx: Tx, control: TriggerControl): Promise<Tx[]>
               name: formatName(from.name, control.branding?.lastNameFirst)
             })
             : await translate(love.string.InivitingLabel, {})
+        const subscriptions = await control.findAll(control.ctx, notification.class.PushSubscription, {
+          user: userAcc[0]._id
+        })
         // TODO: Select a proper user
-        await createPushNotification(control, userAcc[0]._id, title, body, invite._id, from, path)
+        await createPushNotification(control, userAcc[0]._id, title, body, invite._id, subscriptions, from, path)
       }
     }
   }
diff --git a/server-plugins/notification-resources/src/index.ts b/server-plugins/notification-resources/src/index.ts
index d326a20b35..fc080e0c6d 100644
--- a/server-plugins/notification-resources/src/index.ts
+++ b/server-plugins/notification-resources/src/index.ts
@@ -164,6 +164,7 @@ export async function getCommonNotificationTxes (
 
   if (notificationTx !== undefined) {
     const notificationData = TxProcessor.createDoc2Doc(notificationTx)
+    const subscriptions = await control.findAll(ctx, notification.class.PushSubscription, { user: receiver._id })
     await applyNotificationProviders(
       notificationData,
       notifyResult,
@@ -173,7 +174,8 @@ export async function getCommonNotificationTxes (
       res,
       doc,
       receiver,
-      sender
+      sender,
+      subscriptions
     )
   }
 
@@ -492,6 +494,7 @@ export async function createPushFromInbox (
   _class: Ref<Class<InboxNotification>>,
   sender: SenderInfo,
   _id: Ref<Doc>,
+  subscriptions: PushSubscription[],
   cache: Map<Ref<Doc>, Doc> = new Map<Ref<Doc>, Doc>()
 ): Promise<Tx | undefined> {
   let { title, body } = await getTranslatedNotificationContent(data, _class, control)
@@ -521,7 +524,16 @@ export async function createPushFromInbox (
   }
 
   const path = [workbenchId, control.workspace.workspaceUrl, notificationId, encodeObjectURI(id, attachedToClass)]
-  await createPushNotification(control, receiver._id as Ref<PersonAccount>, title, body, _id, senderPerson, path)
+  await createPushNotification(
+    control,
+    receiver._id as Ref<PersonAccount>,
+    title,
+    body,
+    _id,
+    subscriptions,
+    senderPerson,
+    path
+  )
   return control.txFactory.createTxCreateDoc(notification.class.BrowserNotification, receiver.space, {
     user: receiver._id,
     status: NotificationStatus.New,
@@ -541,6 +553,7 @@ export async function createPushNotification (
   title: string,
   body: string,
   _id: string,
+  subscriptions: PushSubscription[],
   senderAvatar?: Data<AvatarInfo>,
   path?: string[]
 ): Promise<void> {
@@ -548,7 +561,7 @@ export async function createPushNotification (
   const privateKey = getMetadata(serverNotification.metadata.PushPrivateKey)
   const subject = getMetadata(serverNotification.metadata.PushSubject) ?? 'mailto:hey@huly.io'
   if (privateKey === undefined || publicKey === undefined) return
-  const subscriptions = await control.findAll(control.ctx, notification.class.PushSubscription, { user: target })
+  const userSubscriptions = subscriptions.filter((it) => it.user === target)
   const data: PushData = {
     title,
     body
@@ -576,7 +589,7 @@ export async function createPushNotification (
 
   webpush.setVapidDetails(subject, publicKey, privateKey)
 
-  for (const subscription of subscriptions) {
+  for (const subscription of userSubscriptions) {
     void sendPushToSubscription(control, target, subscription, data)
   }
 }
@@ -648,6 +661,7 @@ export async function applyNotificationProviders (
   object: Doc,
   receiver: ReceiverInfo,
   sender: SenderInfo,
+  subscriptions: PushSubscription[],
   message?: ActivityMessage
 ): Promise<void> {
   const resources = control.modelDb.findAllSync(serverNotification.class.NotificationProviderResources, {})
@@ -662,7 +676,8 @@ export async function applyNotificationProviders (
         data,
         notification.class.ActivityInboxNotification,
         sender,
-        data._id
+        data._id,
+        subscriptions
       )
       if (pushTx !== undefined) {
         res.push(pushTx)
@@ -727,7 +742,8 @@ export async function getNotificationTxes (
   params: NotifyParams,
   docNotifyContexts: DocNotifyContext[],
   activityMessages: ActivityMessage[],
-  settings: NotificationProviderControl
+  settings: NotificationProviderControl,
+  subscriptions: PushSubscription[]
 ): Promise<Tx[]> {
   if (receiver.account === undefined) {
     return []
@@ -776,6 +792,7 @@ export async function getNotificationTxes (
           object,
           receiver,
           sender,
+          subscriptions,
           message
         )
       }
@@ -940,7 +957,9 @@ export async function createCollabDocInfo (
   }
 
   const settings = await getNotificationProviderControl(ctx, control)
-
+  const subscriptions = await control.findAll(ctx, notification.class.PushSubscription, {
+    user: { $in: Array.from(targets) }
+  })
   for (const target of targets) {
     const info: ReceiverInfo | undefined = toReceiverInfo(control.hierarchy, usersInfo.get(target))
 
@@ -957,7 +976,8 @@ export async function createCollabDocInfo (
       params,
       notifyContexts,
       docMessages,
-      settings
+      settings,
+      subscriptions
     )
     const ids = new Set(targetRes.map((it) => it._id))
     if (info.account?.email !== undefined) {
diff --git a/server-plugins/request-resources/src/index.ts b/server-plugins/request-resources/src/index.ts
index d25e6a0286..26dfdf9c34 100644
--- a/server-plugins/request-resources/src/index.ts
+++ b/server-plugins/request-resources/src/index.ts
@@ -168,7 +168,9 @@ async function getRequestNotificationTx (
   }
 
   const notificationControl = await getNotificationProviderControl(ctx, control)
-
+  const subscriptions = await control.findAll(control.ctx, notification.class.PushSubscription, {
+    user: { $in: collaborators }
+  })
   for (const target of collaborators) {
     const targetInfo = toReceiverInfo(control.hierarchy, usersInfo.get(target))
     if (targetInfo === undefined) continue
@@ -184,7 +186,8 @@ async function getRequestNotificationTx (
       { isOwn: true, isSpace: false, shouldUpdateTimestamp: true },
       notifyContexts,
       messages,
-      notificationControl
+      notificationControl,
+      subscriptions
     )
     res.push(...txes)
   }