@dereekb/firebase-server 11.0.21 → 11.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +13 -0
- package/mailgun/package.json +1 -1
- package/model/package.json +6 -0
- package/model/src/index.d.ts +1 -0
- package/model/src/index.js +5 -0
- package/model/src/index.js.map +1 -0
- package/model/src/lib/index.d.ts +2 -0
- package/model/src/lib/index.js +6 -0
- package/model/src/lib/index.js.map +1 -0
- package/model/src/lib/mailgun/index.d.ts +1 -0
- package/model/src/lib/mailgun/index.js +5 -0
- package/model/src/lib/mailgun/index.js.map +1 -0
- package/model/src/lib/mailgun/notification.send.service.mailgun.d.ts +51 -0
- package/model/src/lib/mailgun/notification.send.service.mailgun.js +67 -0
- package/model/src/lib/mailgun/notification.send.service.mailgun.js.map +1 -0
- package/model/src/lib/notification/index.d.ts +11 -0
- package/model/src/lib/notification/index.js +15 -0
- package/model/src/lib/notification/index.js.map +1 -0
- package/model/src/lib/notification/notification.action.init.server.d.ts +72 -0
- package/model/src/lib/notification/notification.action.init.server.js +228 -0
- package/model/src/lib/notification/notification.action.init.server.js.map +1 -0
- package/model/src/lib/notification/notification.action.server.d.ts +70 -0
- package/model/src/lib/notification/notification.action.server.js +1049 -0
- package/model/src/lib/notification/notification.action.server.js.map +1 -0
- package/model/src/lib/notification/notification.config.d.ts +31 -0
- package/model/src/lib/notification/notification.config.js +13 -0
- package/model/src/lib/notification/notification.config.js.map +1 -0
- package/model/src/lib/notification/notification.config.service.d.ts +49 -0
- package/model/src/lib/notification/notification.config.service.js +59 -0
- package/model/src/lib/notification/notification.config.service.js.map +1 -0
- package/model/src/lib/notification/notification.error.d.ts +9 -0
- package/model/src/lib/notification/notification.error.js +74 -0
- package/model/src/lib/notification/notification.error.js.map +1 -0
- package/model/src/lib/notification/notification.module.d.ts +49 -0
- package/model/src/lib/notification/notification.module.js +69 -0
- package/model/src/lib/notification/notification.module.js.map +1 -0
- package/model/src/lib/notification/notification.send.d.ts +4 -0
- package/model/src/lib/notification/notification.send.js +3 -0
- package/model/src/lib/notification/notification.send.js.map +1 -0
- package/model/src/lib/notification/notification.send.service.d.ts +65 -0
- package/model/src/lib/notification/notification.send.service.js +10 -0
- package/model/src/lib/notification/notification.send.service.js.map +1 -0
- package/model/src/lib/notification/notification.send.service.notificationsummary.d.ts +18 -0
- package/model/src/lib/notification/notification.send.service.notificationsummary.js +105 -0
- package/model/src/lib/notification/notification.send.service.notificationsummary.js.map +1 -0
- package/model/src/lib/notification/notification.send.service.text.d.ts +9 -0
- package/model/src/lib/notification/notification.send.service.text.js +30 -0
- package/model/src/lib/notification/notification.send.service.text.js.map +1 -0
- package/model/src/lib/notification/notification.util.d.ts +128 -0
- package/model/src/lib/notification/notification.util.js +465 -0
- package/model/src/lib/notification/notification.util.js.map +1 -0
- package/package.json +7 -1
- package/test/package.json +1 -1
- package/zoho/package.json +1 -1
|
@@ -0,0 +1,1049 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.cleanupSentNotificationsFactory = exports.sendQueuedNotificationsFactory = exports.sendNotificationFactory = exports.NOTIFICATION_BOX_NOT_INITIALIZED_DELAY_MINUTES = exports.NOTIFICATION_MAX_SEND_ATTEMPTS = exports.KNOWN_BUT_UNCONFIGURED_NOTIFICATION_TEMPLATE_TYPE_DELETE_AFTER_RETRY_ATTEMPTS = exports.KNOWN_BUT_UNCONFIGURED_NOTIFICATION_TEMPLATE_TYPE_HOURS_DELAY = exports.UNKNOWN_NOTIFICATION_TEMPLATE_TYPE_DELETE_AFTER_RETRY_ATTEMPTS = exports.UNKNOWN_NOTIFICATION_TEMPLATE_TYPE_HOURS_DELAY = exports.updateNotificationBoxRecipientFactory = exports.updateNotificationBoxFactory = exports.createNotificationBoxFactory = exports.createNotificationBoxInTransactionFactory = exports.updateNotificationSummaryFactory = exports.createNotificationSummaryFactory = exports.resyncAllNotificationUsersFactory = exports.resyncNotificationUserFactory = exports.updateNotificationUserFactory = exports.createNotificationUserFactory = exports.notificationServerActions = exports.NotificationServerActions = exports.NOTIFICATION_SERVER_ACTION_CONTEXT_TOKEN = exports.BASE_NOTIFICATION_SERVER_ACTION_CONTEXT_TOKEN = void 0;
|
|
4
|
+
const date_1 = require("@dereekb/date");
|
|
5
|
+
const firebase_1 = require("@dereekb/firebase");
|
|
6
|
+
const firebase_server_1 = require("@dereekb/firebase-server");
|
|
7
|
+
const util_1 = require("@dereekb/util");
|
|
8
|
+
const date_fns_1 = require("date-fns");
|
|
9
|
+
const notification_error_1 = require("./notification.error");
|
|
10
|
+
const notification_util_1 = require("./notification.util");
|
|
11
|
+
/**
|
|
12
|
+
* Injection token for the BaseNotificationServerActionsContext
|
|
13
|
+
*/
|
|
14
|
+
exports.BASE_NOTIFICATION_SERVER_ACTION_CONTEXT_TOKEN = 'BASE_NOTIFICATION_SERVER_ACTION_CONTEXT';
|
|
15
|
+
/**
|
|
16
|
+
* Injection token for the NotificationServerActionsContext
|
|
17
|
+
*/
|
|
18
|
+
exports.NOTIFICATION_SERVER_ACTION_CONTEXT_TOKEN = 'NOTIFICATION_SERVER_ACTION_CONTEXT';
|
|
19
|
+
class NotificationServerActions {
|
|
20
|
+
}
|
|
21
|
+
exports.NotificationServerActions = NotificationServerActions;
|
|
22
|
+
function notificationServerActions(context) {
|
|
23
|
+
return {
|
|
24
|
+
createNotificationUser: createNotificationUserFactory(context),
|
|
25
|
+
updateNotificationUser: updateNotificationUserFactory(context),
|
|
26
|
+
resyncNotificationUser: resyncNotificationUserFactory(context),
|
|
27
|
+
resyncAllNotificationUsers: resyncAllNotificationUsersFactory(context),
|
|
28
|
+
createNotificationSummary: createNotificationSummaryFactory(context),
|
|
29
|
+
updateNotificationSummary: updateNotificationSummaryFactory(context),
|
|
30
|
+
createNotificationBox: createNotificationBoxFactory(context),
|
|
31
|
+
updateNotificationBox: updateNotificationBoxFactory(context),
|
|
32
|
+
updateNotificationBoxRecipient: updateNotificationBoxRecipientFactory(context),
|
|
33
|
+
sendNotification: sendNotificationFactory(context),
|
|
34
|
+
sendQueuedNotifications: sendQueuedNotificationsFactory(context),
|
|
35
|
+
cleanupSentNotifications: cleanupSentNotificationsFactory(context)
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
exports.notificationServerActions = notificationServerActions;
|
|
39
|
+
// MARK: Actions
|
|
40
|
+
function createNotificationUserFactory(context) {
|
|
41
|
+
const { firebaseServerActionTransformFunctionFactory, notificationUserCollection, authService } = context;
|
|
42
|
+
return firebaseServerActionTransformFunctionFactory(firebase_1.CreateNotificationUserParams, async (params) => {
|
|
43
|
+
const { uid } = params;
|
|
44
|
+
return async () => {
|
|
45
|
+
// assert they exist in the auth system
|
|
46
|
+
const userContext = authService.userContext(uid);
|
|
47
|
+
const userExistsInAuth = await userContext.exists();
|
|
48
|
+
if (!userExistsInAuth) {
|
|
49
|
+
throw (0, notification_error_1.notificationUserInvalidUidForCreateError)(uid);
|
|
50
|
+
}
|
|
51
|
+
const notificationUserDocument = notificationUserCollection.documentAccessor().loadDocumentForId(uid);
|
|
52
|
+
const newUserTemplate = {
|
|
53
|
+
uid,
|
|
54
|
+
bc: [],
|
|
55
|
+
b: [],
|
|
56
|
+
dc: {
|
|
57
|
+
c: {}
|
|
58
|
+
},
|
|
59
|
+
gc: {
|
|
60
|
+
c: {}
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
await notificationUserDocument.create(newUserTemplate);
|
|
64
|
+
return notificationUserDocument;
|
|
65
|
+
};
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
exports.createNotificationUserFactory = createNotificationUserFactory;
|
|
69
|
+
function updateNotificationUserFactory(context) {
|
|
70
|
+
const { firestoreContext, firebaseServerActionTransformFunctionFactory, notificationUserCollection, appNotificationTemplateTypeInfoRecordService } = context;
|
|
71
|
+
return firebaseServerActionTransformFunctionFactory(firebase_1.UpdateNotificationUserParams, async (params) => {
|
|
72
|
+
const { gc: inputGc, dc: inputDc, bc: inputBc } = params;
|
|
73
|
+
return async (notificationUserDocument) => {
|
|
74
|
+
await firestoreContext.runTransaction(async (transaction) => {
|
|
75
|
+
const notificationUserDocumentInTransaction = notificationUserCollection.documentAccessorForTransaction(transaction).loadDocumentFrom(notificationUserDocument);
|
|
76
|
+
const notificationUser = await (0, firebase_server_1.assertSnapshotData)(notificationUserDocumentInTransaction);
|
|
77
|
+
const updateTemplate = {};
|
|
78
|
+
const allKnownNotificationTypes = appNotificationTemplateTypeInfoRecordService.getAllKnownTemplateTypes();
|
|
79
|
+
if (inputDc != null) {
|
|
80
|
+
updateTemplate.dc = (0, firebase_1.updateNotificationUserDefaultNotificationBoxRecipientConfig)(notificationUser.dc, inputDc, allKnownNotificationTypes);
|
|
81
|
+
}
|
|
82
|
+
if (inputGc != null) {
|
|
83
|
+
const nextGc = (0, firebase_1.updateNotificationUserDefaultNotificationBoxRecipientConfig)(notificationUser.gc, inputGc, allKnownNotificationTypes);
|
|
84
|
+
if (!(0, util_1.areEqualPOJOValues)(notificationUser.gc, nextGc)) {
|
|
85
|
+
updateTemplate.gc = nextGc;
|
|
86
|
+
// iterate and update any box config that has the effective recipient change
|
|
87
|
+
updateTemplate.bc = notificationUser.bc.map((currentConfig) => {
|
|
88
|
+
// check item isn't already marked for sync or marked as removed
|
|
89
|
+
if (currentConfig.ns === true || currentConfig.rm === true) {
|
|
90
|
+
return currentConfig;
|
|
91
|
+
}
|
|
92
|
+
const currentEffectiveRecipient = (0, firebase_1.effectiveNotificationBoxRecipientConfig)({
|
|
93
|
+
uid: notificationUser.uid,
|
|
94
|
+
appNotificationTemplateTypeInfoRecordService,
|
|
95
|
+
gc: notificationUser.gc,
|
|
96
|
+
boxConfig: currentConfig
|
|
97
|
+
});
|
|
98
|
+
const nextEffectiveRecipient = (0, firebase_1.effectiveNotificationBoxRecipientConfig)({
|
|
99
|
+
uid: notificationUser.uid,
|
|
100
|
+
appNotificationTemplateTypeInfoRecordService,
|
|
101
|
+
gc: nextGc,
|
|
102
|
+
boxConfig: currentConfig
|
|
103
|
+
});
|
|
104
|
+
const effectiveConfigChanged = !(0, util_1.areEqualPOJOValues)(currentEffectiveRecipient, nextEffectiveRecipient);
|
|
105
|
+
return effectiveConfigChanged ? { ...currentConfig, ns: true } : currentConfig;
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
if (inputBc != null) {
|
|
110
|
+
const updateTemplateBc = (0, firebase_1.updateNotificationUserNotificationBoxRecipientConfigs)(updateTemplate.bc ?? notificationUser.bc, inputBc, appNotificationTemplateTypeInfoRecordService);
|
|
111
|
+
if (updateTemplateBc != null) {
|
|
112
|
+
updateTemplate.bc = updateTemplateBc;
|
|
113
|
+
updateTemplate.b = updateTemplateBc.map((x) => x.nb);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
// if bc is being updated, then also update ns
|
|
117
|
+
if (updateTemplate.bc != null) {
|
|
118
|
+
updateTemplate.ns = updateTemplate.bc.some((x) => x.ns);
|
|
119
|
+
}
|
|
120
|
+
await notificationUserDocumentInTransaction.update(updateTemplate);
|
|
121
|
+
});
|
|
122
|
+
return notificationUserDocument;
|
|
123
|
+
};
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
exports.updateNotificationUserFactory = updateNotificationUserFactory;
|
|
127
|
+
const MAX_NOTIFICATION_BOXES_TO_UPDATE_PER_BATCH = 50;
|
|
128
|
+
function resyncNotificationUserFactory(context) {
|
|
129
|
+
const { firestoreContext, firebaseServerActionTransformFunctionFactory, notificationBoxCollection, notificationUserCollection, appNotificationTemplateTypeInfoRecordService } = context;
|
|
130
|
+
return firebaseServerActionTransformFunctionFactory(firebase_1.ResyncNotificationUserParams, async (params) => {
|
|
131
|
+
return async (notificationUserDocument) => {
|
|
132
|
+
// run updates in batches
|
|
133
|
+
let notificationBoxesUpdated = 0;
|
|
134
|
+
let hasMoreNotificationBoxesToSync = true;
|
|
135
|
+
while (hasMoreNotificationBoxesToSync) {
|
|
136
|
+
const batchResult = await firestoreContext.runTransaction(async (transaction) => {
|
|
137
|
+
const notificationUserDocumentInTransaction = notificationUserCollection.documentAccessorForTransaction(transaction).loadDocumentFrom(notificationUserDocument);
|
|
138
|
+
const notificationUser = await (0, firebase_server_1.assertSnapshotData)(notificationUserDocumentInTransaction);
|
|
139
|
+
const { gc } = notificationUser;
|
|
140
|
+
const notificationBoxConfigsToSync = notificationUser.bc.filter((x) => x.ns);
|
|
141
|
+
const notificationBoxConfigsToSyncInThisBatch = (0, util_1.takeFront)(notificationBoxConfigsToSync, MAX_NOTIFICATION_BOXES_TO_UPDATE_PER_BATCH);
|
|
142
|
+
/**
|
|
143
|
+
* These are the actual number of NotificationBox values that had recipients updated.
|
|
144
|
+
*/
|
|
145
|
+
let notificationBoxesUpdatedInBatch = 0;
|
|
146
|
+
let hasUnsyncedNotificationBoxConfigs = false;
|
|
147
|
+
if (notificationBoxConfigsToSyncInThisBatch.length > 0) {
|
|
148
|
+
const notificationBoxConfigsToSyncInThisBatchMap = (0, util_1.makeModelMap)(notificationBoxConfigsToSyncInThisBatch, (x) => x.nb);
|
|
149
|
+
const notificationBoxIdsToSyncInThisBatch = Array.from(notificationBoxConfigsToSyncInThisBatchMap.keys());
|
|
150
|
+
const notificationBoxDocuments = (0, firebase_1.loadDocumentsForIds)(notificationBoxCollection.documentAccessorForTransaction(transaction), notificationBoxIdsToSyncInThisBatch);
|
|
151
|
+
const notificationBoxDocumentSnapshotDataPairs = await (0, firebase_1.getDocumentSnapshotDataPairs)(notificationBoxDocuments);
|
|
152
|
+
const notificationBoxConfigsToRemoveFromNotificationUser = new Set();
|
|
153
|
+
const notificationUserNotificationBoxConfigsToMarkAsRemoved = new Set();
|
|
154
|
+
const nextRecipientsMap = new Map();
|
|
155
|
+
// update each NotificationBoxDocument
|
|
156
|
+
await (0, util_1.performAsyncTasks)(notificationBoxDocumentSnapshotDataPairs, async (notificationBoxDocumentSnapshotDataPair) => {
|
|
157
|
+
const { data: notificationBox, document } = notificationBoxDocumentSnapshotDataPair;
|
|
158
|
+
const nb = document.id;
|
|
159
|
+
const notificationUserNotificationBoxConfig = notificationBoxConfigsToSyncInThisBatchMap.get(nb); // always exists
|
|
160
|
+
if (!notificationBox) {
|
|
161
|
+
// if the entire NotificationBox no longer exists, flag to remove it from the user as a cleanup measure
|
|
162
|
+
notificationBoxConfigsToRemoveFromNotificationUser.add(nb);
|
|
163
|
+
}
|
|
164
|
+
else {
|
|
165
|
+
// update in the NotificationBox
|
|
166
|
+
const recipientIndex = notificationBox.r.findIndex((x) => x.uid === notificationUser.uid);
|
|
167
|
+
let r;
|
|
168
|
+
if (recipientIndex === -1) {
|
|
169
|
+
// if they are not in the NotificationBox, then mark them as removed on the user
|
|
170
|
+
notificationUserNotificationBoxConfigsToMarkAsRemoved.add(nb);
|
|
171
|
+
}
|
|
172
|
+
else if (notificationUserNotificationBoxConfig.rm) {
|
|
173
|
+
// remove from the notification box if it is flagged
|
|
174
|
+
r = (0, util_1.removeValuesAtIndexesFromArrayCopy)(notificationBox.r, recipientIndex);
|
|
175
|
+
}
|
|
176
|
+
else {
|
|
177
|
+
const { m } = notificationBox;
|
|
178
|
+
const recipient = notificationBox.r[recipientIndex];
|
|
179
|
+
const nextRecipient = (0, firebase_1.effectiveNotificationBoxRecipientConfig)({
|
|
180
|
+
uid: notificationUser.uid,
|
|
181
|
+
m,
|
|
182
|
+
appNotificationTemplateTypeInfoRecordService,
|
|
183
|
+
gc,
|
|
184
|
+
boxConfig: notificationUserNotificationBoxConfig,
|
|
185
|
+
recipient
|
|
186
|
+
});
|
|
187
|
+
const recipientHasChange = !(0, util_1.areEqualPOJOValues)(nextRecipient, recipient);
|
|
188
|
+
// only update recipients if the next/new recipient is not equal to the existing one
|
|
189
|
+
if (recipientHasChange) {
|
|
190
|
+
r = [...notificationBox.r];
|
|
191
|
+
r[recipientIndex] = nextRecipient;
|
|
192
|
+
nextRecipientsMap.set(nb, nextRecipient);
|
|
193
|
+
}
|
|
194
|
+
else {
|
|
195
|
+
nextRecipientsMap.set(nb, recipient);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
// update recipients if needed
|
|
199
|
+
if (r != null) {
|
|
200
|
+
await document.update({ r });
|
|
201
|
+
notificationBoxesUpdatedInBatch += 1;
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
});
|
|
205
|
+
// Update the NotificationUser
|
|
206
|
+
const notificationBoxIdsSynced = new Set(notificationBoxIdsToSyncInThisBatch);
|
|
207
|
+
// start nextConfigs off as a new array with none of the sync'd ids
|
|
208
|
+
const nextConfigs = notificationBoxConfigsToSyncInThisBatch.filter((x) => !notificationBoxIdsSynced.has(x.nb));
|
|
209
|
+
notificationBoxIdsToSyncInThisBatch.forEach((nb) => {
|
|
210
|
+
let nextConfig;
|
|
211
|
+
if (notificationBoxConfigsToRemoveFromNotificationUser.has(nb)) {
|
|
212
|
+
// do nothing, as it should be removed
|
|
213
|
+
}
|
|
214
|
+
else {
|
|
215
|
+
const existingConfig = notificationBoxConfigsToSyncInThisBatchMap.get(nb);
|
|
216
|
+
if (notificationUserNotificationBoxConfigsToMarkAsRemoved.has(nb) || existingConfig.rm) {
|
|
217
|
+
// if the recipient was being removed or is marked as removed, then update the config to confirm removal
|
|
218
|
+
nextConfig = {
|
|
219
|
+
...existingConfig,
|
|
220
|
+
nb,
|
|
221
|
+
rm: true,
|
|
222
|
+
i: util_1.UNSET_INDEX_NUMBER
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
else {
|
|
226
|
+
// else, use the updated recipient and keep/copy the
|
|
227
|
+
const updatedRecipient = nextRecipientsMap.get(nb);
|
|
228
|
+
nextConfig = {
|
|
229
|
+
...existingConfig,
|
|
230
|
+
nb,
|
|
231
|
+
rm: false,
|
|
232
|
+
i: updatedRecipient.i ?? util_1.UNSET_INDEX_NUMBER
|
|
233
|
+
};
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
if (nextConfig != null) {
|
|
237
|
+
nextConfig.ns = false; // mark as synced
|
|
238
|
+
nextConfigs.push(nextConfig);
|
|
239
|
+
}
|
|
240
|
+
});
|
|
241
|
+
const ns = nextConfigs.some((x) => x.ns);
|
|
242
|
+
await notificationUserDocumentInTransaction.update({ bc: nextConfigs, ns });
|
|
243
|
+
hasUnsyncedNotificationBoxConfigs = ns;
|
|
244
|
+
}
|
|
245
|
+
const batchResult = {
|
|
246
|
+
hasMoreNotificationBoxesToSync: hasUnsyncedNotificationBoxConfigs,
|
|
247
|
+
notificationBoxesUpdatedInBatch
|
|
248
|
+
};
|
|
249
|
+
return batchResult;
|
|
250
|
+
});
|
|
251
|
+
hasMoreNotificationBoxesToSync = batchResult.hasMoreNotificationBoxesToSync;
|
|
252
|
+
notificationBoxesUpdated += batchResult.notificationBoxesUpdatedInBatch;
|
|
253
|
+
}
|
|
254
|
+
const result = {
|
|
255
|
+
notificationBoxesUpdated
|
|
256
|
+
};
|
|
257
|
+
return result;
|
|
258
|
+
};
|
|
259
|
+
});
|
|
260
|
+
}
|
|
261
|
+
exports.resyncNotificationUserFactory = resyncNotificationUserFactory;
|
|
262
|
+
function resyncAllNotificationUsersFactory(context) {
|
|
263
|
+
const { firestoreContext, firebaseServerActionTransformFunctionFactory, notificationUserCollection } = context;
|
|
264
|
+
const resyncNotificationUser = resyncNotificationUserFactory(context);
|
|
265
|
+
return async (params) => {
|
|
266
|
+
let notificationBoxesUpdated = 0;
|
|
267
|
+
const resyncNotificationUserParams = { key: (0, firebase_1.firestoreDummyKey)() };
|
|
268
|
+
const resyncNotificationUserInstance = await resyncNotificationUser(resyncNotificationUserParams);
|
|
269
|
+
const iterateResult = await (0, firebase_1.iterateFirestoreDocumentSnapshotPairs)({
|
|
270
|
+
documentAccessor: notificationUserCollection.documentAccessor(),
|
|
271
|
+
iterateSnapshotPair: async (snapshotPair) => {
|
|
272
|
+
const { document: notificationUserDocument } = snapshotPair;
|
|
273
|
+
const result = await resyncNotificationUserInstance(notificationUserDocument);
|
|
274
|
+
notificationBoxesUpdated += result.notificationBoxesUpdated;
|
|
275
|
+
},
|
|
276
|
+
constraintsFactory: () => (0, firebase_1.notificationUsersFlaggedForNeedsSyncQuery)(),
|
|
277
|
+
snapshotsPerformTasksConfig: {
|
|
278
|
+
// prevent NotificationUsers with the same NotificationBoxes from being updated/sync'd at the same time
|
|
279
|
+
nonConcurrentTaskKeyFactory: (x) => {
|
|
280
|
+
const notificationBoxIdsToSync = x
|
|
281
|
+
.data()
|
|
282
|
+
.bc.filter((x) => x.ns)
|
|
283
|
+
.map((x) => x.nb);
|
|
284
|
+
return notificationBoxIdsToSync;
|
|
285
|
+
}
|
|
286
|
+
},
|
|
287
|
+
queryFactory: notificationUserCollection,
|
|
288
|
+
batchSize: undefined,
|
|
289
|
+
performTasksConfig: {
|
|
290
|
+
maxParallelTasks: 10
|
|
291
|
+
}
|
|
292
|
+
});
|
|
293
|
+
const result = {
|
|
294
|
+
notificationUsersResynced: iterateResult.totalSnapshotsVisited,
|
|
295
|
+
notificationBoxesUpdated
|
|
296
|
+
};
|
|
297
|
+
return result;
|
|
298
|
+
};
|
|
299
|
+
}
|
|
300
|
+
exports.resyncAllNotificationUsersFactory = resyncAllNotificationUsersFactory;
|
|
301
|
+
function createNotificationSummaryFactory(context) {
|
|
302
|
+
const { firebaseServerActionTransformFunctionFactory, notificationSummaryCollection, authService } = context;
|
|
303
|
+
return firebaseServerActionTransformFunctionFactory(firebase_1.CreateNotificationSummaryParams, async (params) => {
|
|
304
|
+
const { model } = params;
|
|
305
|
+
return async () => {
|
|
306
|
+
const notificationSummaryId = (0, firebase_1.notificationSummaryIdForModel)(model);
|
|
307
|
+
const notificationSummaryDocument = notificationSummaryCollection.documentAccessor().loadDocumentForId(notificationSummaryId);
|
|
308
|
+
const newSummaryTemplate = (0, notification_util_1.makeNewNotificationSummaryTemplate)(model);
|
|
309
|
+
await notificationSummaryDocument.create(newSummaryTemplate);
|
|
310
|
+
return notificationSummaryDocument;
|
|
311
|
+
};
|
|
312
|
+
});
|
|
313
|
+
}
|
|
314
|
+
exports.createNotificationSummaryFactory = createNotificationSummaryFactory;
|
|
315
|
+
function updateNotificationSummaryFactory(context) {
|
|
316
|
+
const { firebaseServerActionTransformFunctionFactory, notificationSummaryCollection } = context;
|
|
317
|
+
return firebaseServerActionTransformFunctionFactory(firebase_1.UpdateNotificationSummaryParams, async (params) => {
|
|
318
|
+
const { setReadAtTime, flagAllRead } = params;
|
|
319
|
+
return async (notificationSummaryDocument) => {
|
|
320
|
+
let updateTemplate;
|
|
321
|
+
if (setReadAtTime != null) {
|
|
322
|
+
updateTemplate = { rat: setReadAtTime };
|
|
323
|
+
}
|
|
324
|
+
else if (flagAllRead === true) {
|
|
325
|
+
updateTemplate = { rat: new Date() };
|
|
326
|
+
}
|
|
327
|
+
if (updateTemplate != null) {
|
|
328
|
+
await notificationSummaryDocument.update(updateTemplate);
|
|
329
|
+
}
|
|
330
|
+
return notificationSummaryDocument;
|
|
331
|
+
};
|
|
332
|
+
});
|
|
333
|
+
}
|
|
334
|
+
exports.updateNotificationSummaryFactory = updateNotificationSummaryFactory;
|
|
335
|
+
function createNotificationBoxInTransactionFactory(context) {
|
|
336
|
+
const { notificationBoxCollection } = context;
|
|
337
|
+
return async (params, transaction) => {
|
|
338
|
+
const { now = new Date(), model } = params;
|
|
339
|
+
const notificationBoxId = (0, firebase_1.notificationBoxIdForModel)(model);
|
|
340
|
+
const notificationBoxDocument = notificationBoxCollection.documentAccessorForTransaction(transaction).loadDocumentForId(notificationBoxId);
|
|
341
|
+
const notificationBoxTemplate = {
|
|
342
|
+
m: model,
|
|
343
|
+
o: (0, firebase_1.firestoreDummyKey)(),
|
|
344
|
+
r: [],
|
|
345
|
+
cat: now,
|
|
346
|
+
w: (0, date_1.yearWeekCode)(now),
|
|
347
|
+
s: true // requires initialization
|
|
348
|
+
};
|
|
349
|
+
await notificationBoxDocument.create(notificationBoxTemplate);
|
|
350
|
+
return {
|
|
351
|
+
notificationBoxTemplate,
|
|
352
|
+
notificationBoxDocument
|
|
353
|
+
};
|
|
354
|
+
};
|
|
355
|
+
}
|
|
356
|
+
exports.createNotificationBoxInTransactionFactory = createNotificationBoxInTransactionFactory;
|
|
357
|
+
function createNotificationBoxFactory(context) {
|
|
358
|
+
const { firestoreContext, authService, notificationBoxCollection, firebaseServerActionTransformFunctionFactory } = context;
|
|
359
|
+
const createNotificationBoxInTransaction = createNotificationBoxInTransactionFactory(context);
|
|
360
|
+
return firebaseServerActionTransformFunctionFactory(firebase_1.CreateNotificationBoxParams, async (params) => {
|
|
361
|
+
const { model } = params;
|
|
362
|
+
return async () => {
|
|
363
|
+
const result = await firestoreContext.runTransaction(async (transaction) => {
|
|
364
|
+
const { notificationBoxDocument } = await createNotificationBoxInTransaction({
|
|
365
|
+
model
|
|
366
|
+
}, transaction);
|
|
367
|
+
return notificationBoxDocument;
|
|
368
|
+
});
|
|
369
|
+
return notificationBoxCollection.documentAccessor().loadDocumentFrom(result);
|
|
370
|
+
};
|
|
371
|
+
});
|
|
372
|
+
}
|
|
373
|
+
exports.createNotificationBoxFactory = createNotificationBoxFactory;
|
|
374
|
+
function updateNotificationBoxFactory({ firebaseServerActionTransformFunctionFactory }) {
|
|
375
|
+
return firebaseServerActionTransformFunctionFactory(firebase_1.UpdateNotificationBoxParams, async () => {
|
|
376
|
+
return async (notificationBoxDocument) => {
|
|
377
|
+
// does nothing currently.
|
|
378
|
+
return notificationBoxDocument;
|
|
379
|
+
};
|
|
380
|
+
});
|
|
381
|
+
}
|
|
382
|
+
exports.updateNotificationBoxFactory = updateNotificationBoxFactory;
|
|
383
|
+
function updateNotificationBoxRecipientFactory({ firestoreContext, authService, notificationBoxCollection, notificationUserCollection, firebaseServerActionTransformFunctionFactory }) {
|
|
384
|
+
return firebaseServerActionTransformFunctionFactory(firebase_1.UpdateNotificationBoxRecipientParams, async (params) => {
|
|
385
|
+
const { uid, i, insert, remove, configs: inputC } = params;
|
|
386
|
+
const findRecipientFn = (x) => (uid != null && x.uid === uid) || (i != null && i === i);
|
|
387
|
+
return async (notificationBoxDocument) => {
|
|
388
|
+
await firestoreContext.runTransaction(async (transaction) => {
|
|
389
|
+
const notificationBoxDocumentInTransaction = notificationBoxCollection.documentAccessorForTransaction(transaction).loadDocumentFrom(notificationBoxDocument);
|
|
390
|
+
const notificationBox = await (0, firebase_server_1.assertSnapshotData)(notificationBoxDocumentInTransaction);
|
|
391
|
+
const { m } = notificationBox;
|
|
392
|
+
let r;
|
|
393
|
+
let targetRecipientIndex = notificationBox.r.findIndex(findRecipientFn);
|
|
394
|
+
const targetRecipient = notificationBox.r[targetRecipientIndex];
|
|
395
|
+
let nextRecipient;
|
|
396
|
+
if (remove) {
|
|
397
|
+
if (targetRecipientIndex != null) {
|
|
398
|
+
r = [...notificationBox.r]; // remove if they exist.
|
|
399
|
+
delete r[targetRecipientIndex];
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
else {
|
|
403
|
+
if (!targetRecipient && !insert) {
|
|
404
|
+
throw (0, notification_error_1.notificationBoxRecipientDoesNotExistsError)();
|
|
405
|
+
}
|
|
406
|
+
const c = (inputC != null ? (0, firebase_1.notificationBoxRecipientTemplateConfigArrayToRecord)(inputC) : targetRecipient?.c) ?? {};
|
|
407
|
+
nextRecipient = {
|
|
408
|
+
uid,
|
|
409
|
+
i: targetRecipient?.i ?? util_1.UNSET_INDEX_NUMBER,
|
|
410
|
+
c,
|
|
411
|
+
...(0, firebase_1.updateNotificationRecipient)(targetRecipient ?? {}, params)
|
|
412
|
+
};
|
|
413
|
+
r = [...notificationBox.r];
|
|
414
|
+
if (targetRecipient) {
|
|
415
|
+
nextRecipient.i = targetRecipient.i;
|
|
416
|
+
nextRecipient = (0, firebase_1.mergeNotificationBoxRecipients)(targetRecipient, nextRecipient);
|
|
417
|
+
r[targetRecipientIndex] = nextRecipient; // override in the array
|
|
418
|
+
}
|
|
419
|
+
else {
|
|
420
|
+
const nextI = (0, util_1.computeNextFreeIndexOnSortedValuesFunction)(util_1.readIndexNumber)(notificationBox.r); // r is sorted by index in ascending order, so the last value is the largest i
|
|
421
|
+
nextRecipient.i = nextI;
|
|
422
|
+
// should have the greatest i value, push to end
|
|
423
|
+
r.push(nextRecipient);
|
|
424
|
+
targetRecipientIndex = r.length - 1;
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
// save changes to r if it changed
|
|
428
|
+
if (r != null) {
|
|
429
|
+
const notificationUserId = targetRecipient?.uid ?? nextRecipient?.uid;
|
|
430
|
+
// sync with the notification user's document, if it exists
|
|
431
|
+
if (notificationUserId != null) {
|
|
432
|
+
const notificationBoxId = notificationBoxDocument.id;
|
|
433
|
+
const notificationUserDocument = await notificationUserCollection.documentAccessorForTransaction(transaction).loadDocumentForId(notificationUserId);
|
|
434
|
+
let notificationUser = await notificationUserDocument.snapshotData();
|
|
435
|
+
const createNotificationUser = !notificationUser && !remove && insert;
|
|
436
|
+
if (createNotificationUser) {
|
|
437
|
+
// assert they exist in the auth system
|
|
438
|
+
const userContext = authService.userContext(notificationUserId);
|
|
439
|
+
const userExistsInAuth = await userContext.exists();
|
|
440
|
+
if (!userExistsInAuth) {
|
|
441
|
+
throw (0, notification_error_1.notificationUserInvalidUidForCreateError)(notificationUserId);
|
|
442
|
+
}
|
|
443
|
+
const notificationUserTemplate = {
|
|
444
|
+
uid: notificationUserId,
|
|
445
|
+
b: [],
|
|
446
|
+
bc: [],
|
|
447
|
+
ns: false,
|
|
448
|
+
dc: {
|
|
449
|
+
c: {}
|
|
450
|
+
},
|
|
451
|
+
gc: {
|
|
452
|
+
c: {}
|
|
453
|
+
}
|
|
454
|
+
};
|
|
455
|
+
notificationUser = notificationUserTemplate;
|
|
456
|
+
}
|
|
457
|
+
// if the user is being inserted or exists, then make updates
|
|
458
|
+
if (notificationUser != null) {
|
|
459
|
+
const { updatedBc, updatedNotificationBoxRecipient } = (0, notification_util_1.updateNotificationUserNotificationBoxRecipientConfig)({
|
|
460
|
+
notificationBoxId,
|
|
461
|
+
notificationUserId,
|
|
462
|
+
notificationBoxAssociatedModelKey: m,
|
|
463
|
+
notificationUser,
|
|
464
|
+
insertingRecipientIntoNotificationBox: insert,
|
|
465
|
+
removeRecipientFromNotificationBox: remove,
|
|
466
|
+
notificationBoxRecipient: nextRecipient
|
|
467
|
+
});
|
|
468
|
+
const updatedB = updatedBc ? updatedBc.map((x) => x.nb) : undefined;
|
|
469
|
+
if (createNotificationUser) {
|
|
470
|
+
const newUserTemplate = {
|
|
471
|
+
...notificationUser,
|
|
472
|
+
bc: updatedBc ?? [],
|
|
473
|
+
b: updatedB ?? []
|
|
474
|
+
};
|
|
475
|
+
await notificationUserDocument.create(newUserTemplate);
|
|
476
|
+
}
|
|
477
|
+
else if (updatedBc != null) {
|
|
478
|
+
await notificationUserDocument.update({ bc: updatedBc, b: updatedB });
|
|
479
|
+
}
|
|
480
|
+
// Set if nextRecipient is updated/influence from existing configuration
|
|
481
|
+
if (targetRecipientIndex != null && updatedNotificationBoxRecipient && !remove) {
|
|
482
|
+
r[targetRecipientIndex] = updatedNotificationBoxRecipient; // set the updated value in r
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
// else, if removing and they don't exist, nothing to update
|
|
486
|
+
}
|
|
487
|
+
await notificationBoxDocumentInTransaction.update({ r });
|
|
488
|
+
}
|
|
489
|
+
});
|
|
490
|
+
return notificationBoxDocument;
|
|
491
|
+
};
|
|
492
|
+
});
|
|
493
|
+
}
|
|
494
|
+
exports.updateNotificationBoxRecipientFactory = updateNotificationBoxRecipientFactory;
|
|
495
|
+
exports.UNKNOWN_NOTIFICATION_TEMPLATE_TYPE_HOURS_DELAY = 8;
|
|
496
|
+
exports.UNKNOWN_NOTIFICATION_TEMPLATE_TYPE_DELETE_AFTER_RETRY_ATTEMPTS = 1;
|
|
497
|
+
exports.KNOWN_BUT_UNCONFIGURED_NOTIFICATION_TEMPLATE_TYPE_HOURS_DELAY = exports.UNKNOWN_NOTIFICATION_TEMPLATE_TYPE_HOURS_DELAY;
|
|
498
|
+
exports.KNOWN_BUT_UNCONFIGURED_NOTIFICATION_TEMPLATE_TYPE_DELETE_AFTER_RETRY_ATTEMPTS = 5;
|
|
499
|
+
exports.NOTIFICATION_MAX_SEND_ATTEMPTS = 5;
|
|
500
|
+
exports.NOTIFICATION_BOX_NOT_INITIALIZED_DELAY_MINUTES = 8;
|
|
501
|
+
function sendNotificationFactory(context) {
|
|
502
|
+
const { appNotificationTemplateTypeInfoRecordService, notificationSendService, notificationTemplateService, authService, notificationBoxCollection, notificationCollectionGroup, notificationUserCollection, firestoreContext, firebaseServerActionTransformFunctionFactory } = context;
|
|
503
|
+
const createNotificationBoxInTransaction = createNotificationBoxInTransactionFactory(context);
|
|
504
|
+
const notificationUserAccessor = notificationUserCollection.documentAccessor();
|
|
505
|
+
return firebaseServerActionTransformFunctionFactory(firebase_1.SendNotificationParams, async (params) => {
|
|
506
|
+
const { ignoreSendAtThrottle } = params;
|
|
507
|
+
return async (notificationDocument) => {
|
|
508
|
+
// does nothing currently.
|
|
509
|
+
const { throttled, tryRun, notification, createdBox, notificationBoxNeedsInitialization, notificationBox, notificationBoxModelKey, deletedNotification, templateInstance, isConfiguredTemplateType, isKnownTemplateType } = await firestoreContext.runTransaction(async (transaction) => {
|
|
510
|
+
const notificationBoxDocument = notificationBoxCollection.documentAccessorForTransaction(transaction).loadDocument(notificationDocument.parent);
|
|
511
|
+
const notificationDocumentInTransaction = notificationCollectionGroup.documentAccessorForTransaction(transaction).loadDocumentFrom(notificationDocument);
|
|
512
|
+
let [notificationBox, notification] = await Promise.all([notificationBoxDocument.snapshotData(), (0, firebase_1.getDocumentSnapshotData)(notificationDocumentInTransaction)]);
|
|
513
|
+
const model = (0, firebase_1.inferKeyFromTwoWayFlatFirestoreModelKey)(notificationBoxDocument.id);
|
|
514
|
+
let tryRun = true;
|
|
515
|
+
let throttled = false;
|
|
516
|
+
let nextSat;
|
|
517
|
+
if (!notification) {
|
|
518
|
+
tryRun = false;
|
|
519
|
+
}
|
|
520
|
+
else if (!ignoreSendAtThrottle) {
|
|
521
|
+
tryRun = (0, date_fns_1.isPast)(notification.sat);
|
|
522
|
+
if (tryRun) {
|
|
523
|
+
nextSat = (0, date_fns_1.addMinutes)(new Date(), 10); // try again in 10 minutes if not successful
|
|
524
|
+
}
|
|
525
|
+
else {
|
|
526
|
+
throttled = true;
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
let createdBox = false;
|
|
530
|
+
let deletedNotification = false;
|
|
531
|
+
let notificationBoxNeedsInitialization = false;
|
|
532
|
+
let isKnownTemplateType;
|
|
533
|
+
let isConfiguredTemplateType;
|
|
534
|
+
let templateInstance;
|
|
535
|
+
async function deleteNotification() {
|
|
536
|
+
tryRun = false;
|
|
537
|
+
await notificationDocumentInTransaction.accessor.delete();
|
|
538
|
+
deletedNotification = true;
|
|
539
|
+
}
|
|
540
|
+
// create/init the notification box if necessary/configured.
|
|
541
|
+
if (notification && tryRun) {
|
|
542
|
+
// if we're still trying to run, check the template is ok. If not, cancel the run.
|
|
543
|
+
const { t } = notification.n;
|
|
544
|
+
templateInstance = notificationTemplateService.templateInstanceForType(t);
|
|
545
|
+
isKnownTemplateType = isConfiguredTemplateType = templateInstance.isConfiguredType;
|
|
546
|
+
if (!isConfiguredTemplateType) {
|
|
547
|
+
// log the issue that an notification with an unconfigured type was queued
|
|
548
|
+
const templateInfo = appNotificationTemplateTypeInfoRecordService.appNotificationTemplateTypeInfoRecord[t];
|
|
549
|
+
isKnownTemplateType = templateInfo != null;
|
|
550
|
+
const retryAttempts = isKnownTemplateType ? exports.KNOWN_BUT_UNCONFIGURED_NOTIFICATION_TEMPLATE_TYPE_DELETE_AFTER_RETRY_ATTEMPTS : exports.UNKNOWN_NOTIFICATION_TEMPLATE_TYPE_DELETE_AFTER_RETRY_ATTEMPTS;
|
|
551
|
+
const delay = isKnownTemplateType ? exports.KNOWN_BUT_UNCONFIGURED_NOTIFICATION_TEMPLATE_TYPE_HOURS_DELAY : exports.UNKNOWN_NOTIFICATION_TEMPLATE_TYPE_HOURS_DELAY;
|
|
552
|
+
if (notification.a < retryAttempts) {
|
|
553
|
+
if (isKnownTemplateType) {
|
|
554
|
+
console.warn(`Unconfigured but known template type of "${t}" (${templateInfo.name}) was found in a Notification. Send is being delayed by ${delay} hours.`);
|
|
555
|
+
}
|
|
556
|
+
else {
|
|
557
|
+
console.warn(`Unknown template type of "${t}" was found in a Notification. Send is being delayed by ${delay} hours.`);
|
|
558
|
+
}
|
|
559
|
+
// delay send for 12 hours, for a max of 24 hours incase it is an issue.
|
|
560
|
+
nextSat = (0, date_fns_1.addHours)(new Date(), delay);
|
|
561
|
+
tryRun = false;
|
|
562
|
+
}
|
|
563
|
+
else {
|
|
564
|
+
console.warn(`Unconfigured template type of "${t}" was found in a Notification. The Notification has reached the delete threshhold after failing to send due to misconfiguration multiple times and is being deleted.`);
|
|
565
|
+
// after attempting to send 3 times, delete it.
|
|
566
|
+
await deleteNotification();
|
|
567
|
+
}
|
|
568
|
+
}
|
|
569
|
+
// handle the notification box's absence
|
|
570
|
+
if (!notificationBox && tryRun) {
|
|
571
|
+
switch (notification.st) {
|
|
572
|
+
case firebase_1.NotificationSendType.INIT_BOX_AND_SEND:
|
|
573
|
+
const { notificationBoxTemplate } = await createNotificationBoxInTransaction({
|
|
574
|
+
model
|
|
575
|
+
}, transaction);
|
|
576
|
+
notificationBox = notificationBoxTemplate;
|
|
577
|
+
createdBox = true;
|
|
578
|
+
break;
|
|
579
|
+
case firebase_1.NotificationSendType.SEND_IF_BOX_EXISTS:
|
|
580
|
+
// delete the notification since it won't get sent.
|
|
581
|
+
await deleteNotification();
|
|
582
|
+
break;
|
|
583
|
+
case firebase_1.NotificationSendType.SEND_WITHOUT_CREATING_BOX:
|
|
584
|
+
// continue with current tryRun
|
|
585
|
+
break;
|
|
586
|
+
}
|
|
587
|
+
}
|
|
588
|
+
// if the notification box is not initialized/synchronized yet, do not run.
|
|
589
|
+
if (tryRun && notificationBox && notificationBox.s) {
|
|
590
|
+
notificationBoxNeedsInitialization = true;
|
|
591
|
+
tryRun = false;
|
|
592
|
+
nextSat = (0, date_fns_1.addMinutes)(new Date(), exports.NOTIFICATION_BOX_NOT_INITIALIZED_DELAY_MINUTES);
|
|
593
|
+
}
|
|
594
|
+
}
|
|
595
|
+
// update the notification send at time and attempt count
|
|
596
|
+
if (notification != null && nextSat != null && !deletedNotification) {
|
|
597
|
+
const isAtMaxAttempts = notification.a >= exports.NOTIFICATION_MAX_SEND_ATTEMPTS;
|
|
598
|
+
if (isAtMaxAttempts && notificationBoxNeedsInitialization) {
|
|
599
|
+
await deleteNotification(); // just delete the notification if the box still hasn't been initialized successfully at this point.
|
|
600
|
+
}
|
|
601
|
+
if (!deletedNotification) {
|
|
602
|
+
await notificationDocumentInTransaction.update({ sat: nextSat, a: notification.a + 1 });
|
|
603
|
+
}
|
|
604
|
+
}
|
|
605
|
+
return {
|
|
606
|
+
throttled,
|
|
607
|
+
deletedNotification,
|
|
608
|
+
createdBox,
|
|
609
|
+
notificationBoxModelKey: model,
|
|
610
|
+
notificationBoxNeedsInitialization,
|
|
611
|
+
notificationBox,
|
|
612
|
+
notification,
|
|
613
|
+
templateInstance,
|
|
614
|
+
isKnownTemplateType,
|
|
615
|
+
isConfiguredTemplateType,
|
|
616
|
+
tryRun
|
|
617
|
+
};
|
|
618
|
+
});
|
|
619
|
+
let success = false;
|
|
620
|
+
let sendEmailsResult;
|
|
621
|
+
let sendTextsResult;
|
|
622
|
+
let sendNotificationSummaryResult;
|
|
623
|
+
let loadMessageFunctionFailure = false;
|
|
624
|
+
let buildMessageFailure = false;
|
|
625
|
+
let notificationMarkedDone = false;
|
|
626
|
+
const notificationTemplateType = templateInstance?.type;
|
|
627
|
+
// notification is only null/undefined if it didn't exist.
|
|
628
|
+
if (notification != null) {
|
|
629
|
+
if (tryRun && templateInstance != null) {
|
|
630
|
+
// first load the message function
|
|
631
|
+
const messageFunction = await templateInstance
|
|
632
|
+
.loadMessageFunction({
|
|
633
|
+
item: notification.n,
|
|
634
|
+
notification,
|
|
635
|
+
notificationBox: {
|
|
636
|
+
m: notificationBoxModelKey
|
|
637
|
+
}
|
|
638
|
+
})
|
|
639
|
+
.catch((e) => {
|
|
640
|
+
loadMessageFunctionFailure = true;
|
|
641
|
+
success = false;
|
|
642
|
+
console.error(`Failed loading message function for type ${notificationTemplateType}: `, e);
|
|
643
|
+
return undefined;
|
|
644
|
+
});
|
|
645
|
+
if (messageFunction) {
|
|
646
|
+
// expand recipients
|
|
647
|
+
const { emails: emailRecipients, texts: textRecipients, notificationSummaries: notificationSummaryRecipients } = await (0, notification_util_1.expandNotificationRecipients)({
|
|
648
|
+
notification,
|
|
649
|
+
notificationBox,
|
|
650
|
+
authService,
|
|
651
|
+
notificationUserAccessor,
|
|
652
|
+
globalRecipients: messageFunction.globalRecipients,
|
|
653
|
+
notificationSummaryIdForUid: notificationSendService.notificationSummaryIdForUidFunction
|
|
654
|
+
});
|
|
655
|
+
let { es, ts, ps, ns, esr: currentEsr, tsr: currentTsr } = notification;
|
|
656
|
+
// do emails
|
|
657
|
+
let esr;
|
|
658
|
+
if (es === firebase_1.NotificationSendState.QUEUED || es === firebase_1.NotificationSendState.SENT_PARTIAL) {
|
|
659
|
+
const emailRecipientsAlreadySentTo = new Set(currentEsr.map((x) => x.toLowerCase()));
|
|
660
|
+
const emailInputContexts = emailRecipients
|
|
661
|
+
.filter((x) => !emailRecipientsAlreadySentTo.has(x.emailAddress.toLowerCase()))
|
|
662
|
+
.map((x) => {
|
|
663
|
+
const context = {
|
|
664
|
+
recipient: {
|
|
665
|
+
n: x.name,
|
|
666
|
+
e: x.emailAddress,
|
|
667
|
+
t: x.phoneNumber
|
|
668
|
+
}
|
|
669
|
+
};
|
|
670
|
+
return context;
|
|
671
|
+
});
|
|
672
|
+
const emailMessages = await Promise.all(emailInputContexts.map(messageFunction)).catch((e) => {
|
|
673
|
+
console.error(`Failed building message function for type ${notificationTemplateType}: `, e);
|
|
674
|
+
buildMessageFailure = true;
|
|
675
|
+
return undefined;
|
|
676
|
+
});
|
|
677
|
+
if (emailMessages?.length) {
|
|
678
|
+
if (notificationSendService.emailSendService != null) {
|
|
679
|
+
let sendInstance;
|
|
680
|
+
try {
|
|
681
|
+
sendInstance = await notificationSendService.emailSendService.buildSendInstanceForEmailNotificationMessages(emailMessages);
|
|
682
|
+
}
|
|
683
|
+
catch (e) {
|
|
684
|
+
console.error(`Failed building email send instance for notification "${notification.id}" with type "${notificationTemplateType}": `, e);
|
|
685
|
+
es = firebase_1.NotificationSendState.CONFIG_ERROR;
|
|
686
|
+
}
|
|
687
|
+
if (sendInstance) {
|
|
688
|
+
try {
|
|
689
|
+
sendEmailsResult = await sendInstance();
|
|
690
|
+
}
|
|
691
|
+
catch (e) {
|
|
692
|
+
console.error(`Failed sending email notification "${notification.id}" with type "${notificationTemplateType}": `, e);
|
|
693
|
+
es = firebase_1.NotificationSendState.SEND_ERROR;
|
|
694
|
+
}
|
|
695
|
+
}
|
|
696
|
+
}
|
|
697
|
+
else {
|
|
698
|
+
console.error(`Failed sending email notification "${notification.id}" with type "${notificationTemplateType}" due to no email service being configured.`);
|
|
699
|
+
es = firebase_1.NotificationSendState.CONFIG_ERROR;
|
|
700
|
+
}
|
|
701
|
+
if (sendEmailsResult != null) {
|
|
702
|
+
const { success, failed } = sendEmailsResult;
|
|
703
|
+
esr = success.length ? currentEsr.concat(success.map((x) => x.toLowerCase())) : undefined;
|
|
704
|
+
if (failed.length > 0) {
|
|
705
|
+
es = firebase_1.NotificationSendState.SENT_PARTIAL;
|
|
706
|
+
}
|
|
707
|
+
else {
|
|
708
|
+
es = firebase_1.NotificationSendState.SENT;
|
|
709
|
+
}
|
|
710
|
+
}
|
|
711
|
+
}
|
|
712
|
+
else {
|
|
713
|
+
es = firebase_1.NotificationSendState.SENT;
|
|
714
|
+
}
|
|
715
|
+
}
|
|
716
|
+
// do phone numbers
|
|
717
|
+
let tsr;
|
|
718
|
+
if (ts === firebase_1.NotificationSendState.QUEUED || ts === firebase_1.NotificationSendState.SENT_PARTIAL) {
|
|
719
|
+
const textRecipientsAlreadySentTo = new Set(currentTsr);
|
|
720
|
+
const textInputContexts = textRecipients
|
|
721
|
+
.filter((x) => !textRecipientsAlreadySentTo.has(x.phoneNumber))
|
|
722
|
+
.map((x) => {
|
|
723
|
+
const context = {
|
|
724
|
+
recipient: {
|
|
725
|
+
n: x.name,
|
|
726
|
+
e: x.emailAddress,
|
|
727
|
+
t: x.phoneNumber
|
|
728
|
+
}
|
|
729
|
+
};
|
|
730
|
+
return context;
|
|
731
|
+
});
|
|
732
|
+
const textMessages = await Promise.all(textInputContexts.map(messageFunction)).catch((e) => {
|
|
733
|
+
console.error(`Failed building message function for type ${notificationTemplateType}: `, e);
|
|
734
|
+
buildMessageFailure = true;
|
|
735
|
+
return undefined;
|
|
736
|
+
});
|
|
737
|
+
if (textMessages?.length) {
|
|
738
|
+
if (notificationSendService.textSendService != null) {
|
|
739
|
+
let sendInstance;
|
|
740
|
+
try {
|
|
741
|
+
sendInstance = await notificationSendService.textSendService.buildSendInstanceForTextNotificationMessages(textMessages);
|
|
742
|
+
}
|
|
743
|
+
catch (e) {
|
|
744
|
+
console.error(`Failed building text send instance for notification "${notification.id}" with type "${notificationTemplateType}": `, e);
|
|
745
|
+
ts = firebase_1.NotificationSendState.CONFIG_ERROR;
|
|
746
|
+
}
|
|
747
|
+
if (sendInstance) {
|
|
748
|
+
try {
|
|
749
|
+
sendTextsResult = await sendInstance();
|
|
750
|
+
}
|
|
751
|
+
catch (e) {
|
|
752
|
+
console.error(`Failed sending text notification "${notification.id}" with type "${notificationTemplateType}": `, e);
|
|
753
|
+
ts = firebase_1.NotificationSendState.SEND_ERROR;
|
|
754
|
+
}
|
|
755
|
+
}
|
|
756
|
+
}
|
|
757
|
+
else {
|
|
758
|
+
console.error(`Failed sending text notification "${notification.id}" with type "${notificationTemplateType}" due to no text service being configured.`);
|
|
759
|
+
ts = firebase_1.NotificationSendState.CONFIG_ERROR;
|
|
760
|
+
}
|
|
761
|
+
if (sendTextsResult != null) {
|
|
762
|
+
const { success, failed, ignored } = sendTextsResult;
|
|
763
|
+
tsr = success.length ? currentTsr.concat(success) : undefined;
|
|
764
|
+
if (failed.length > 0) {
|
|
765
|
+
ts = firebase_1.NotificationSendState.SENT_PARTIAL;
|
|
766
|
+
}
|
|
767
|
+
else {
|
|
768
|
+
ts = firebase_1.NotificationSendState.SENT;
|
|
769
|
+
}
|
|
770
|
+
}
|
|
771
|
+
}
|
|
772
|
+
else {
|
|
773
|
+
ts = firebase_1.NotificationSendState.SENT;
|
|
774
|
+
}
|
|
775
|
+
}
|
|
776
|
+
ps = firebase_1.NotificationSendState.NO_TRY;
|
|
777
|
+
// NOTE: FCM token management will probably done with a separate system within Notification that stores FCMs for specific users in the app. May also use UIDs to determine who got the push notificdation or not...
|
|
778
|
+
// do notification summaries
|
|
779
|
+
if (ns === firebase_1.NotificationSendState.QUEUED || ns === firebase_1.NotificationSendState.SENT_PARTIAL) {
|
|
780
|
+
const notificationSummaryInputContexts = notificationSummaryRecipients.map((x) => {
|
|
781
|
+
const context = {
|
|
782
|
+
recipient: {
|
|
783
|
+
n: x.name,
|
|
784
|
+
s: x.notificationSummaryId
|
|
785
|
+
}
|
|
786
|
+
};
|
|
787
|
+
return context;
|
|
788
|
+
});
|
|
789
|
+
const notificationSummaryMessages = await Promise.all(notificationSummaryInputContexts.map(messageFunction)).catch((e) => {
|
|
790
|
+
console.error(`Failed building message function for type ${notificationTemplateType}: `, e);
|
|
791
|
+
buildMessageFailure = true;
|
|
792
|
+
return undefined;
|
|
793
|
+
});
|
|
794
|
+
if (notificationSummaryMessages?.length) {
|
|
795
|
+
if (notificationSendService.notificationSummarySendService != null) {
|
|
796
|
+
let sendInstance;
|
|
797
|
+
try {
|
|
798
|
+
sendInstance = await notificationSendService.notificationSummarySendService.buildSendInstanceForNotificationSummaryMessages(notificationSummaryMessages);
|
|
799
|
+
}
|
|
800
|
+
catch (e) {
|
|
801
|
+
console.error(`Failed building notification summary send instance for notification "${notification.id}" with type "${notificationTemplateType}": `, e);
|
|
802
|
+
ns = firebase_1.NotificationSendState.CONFIG_ERROR;
|
|
803
|
+
}
|
|
804
|
+
if (sendInstance) {
|
|
805
|
+
try {
|
|
806
|
+
sendNotificationSummaryResult = await sendInstance();
|
|
807
|
+
ns = firebase_1.NotificationSendState.SENT;
|
|
808
|
+
}
|
|
809
|
+
catch (e) {
|
|
810
|
+
console.error(`Failed sending notification summary notification "${notification.id}" with type "${notificationTemplateType}": `, e);
|
|
811
|
+
ns = firebase_1.NotificationSendState.SEND_ERROR;
|
|
812
|
+
}
|
|
813
|
+
}
|
|
814
|
+
}
|
|
815
|
+
else {
|
|
816
|
+
console.error(`Failed sending notification summary notification "${notification.id}" with type "${notificationTemplateType}" due to no notification summary service being configured.`);
|
|
817
|
+
ns = firebase_1.NotificationSendState.CONFIG_ERROR;
|
|
818
|
+
}
|
|
819
|
+
}
|
|
820
|
+
else {
|
|
821
|
+
ns = firebase_1.NotificationSendState.SENT;
|
|
822
|
+
}
|
|
823
|
+
}
|
|
824
|
+
// calculate results
|
|
825
|
+
const notificationTemplate = { es, ts, ps, ns, esr, tsr };
|
|
826
|
+
success = (0, firebase_1.notificationSendFlagsImplyIsComplete)(notificationTemplate);
|
|
827
|
+
if (success) {
|
|
828
|
+
notificationTemplate.d = true;
|
|
829
|
+
}
|
|
830
|
+
else {
|
|
831
|
+
notificationTemplate.a = notification.a + 1;
|
|
832
|
+
if (notificationTemplate.a >= exports.NOTIFICATION_MAX_SEND_ATTEMPTS) {
|
|
833
|
+
notificationTemplate.d = true;
|
|
834
|
+
}
|
|
835
|
+
}
|
|
836
|
+
await notificationDocument.update(notificationTemplate);
|
|
837
|
+
notificationMarkedDone = notificationTemplate.d === true;
|
|
838
|
+
}
|
|
839
|
+
}
|
|
840
|
+
else {
|
|
841
|
+
switch (notification.st) {
|
|
842
|
+
case firebase_1.NotificationSendType.SEND_IF_BOX_EXISTS:
|
|
843
|
+
// deleted successfully
|
|
844
|
+
success = deletedNotification;
|
|
845
|
+
break;
|
|
846
|
+
}
|
|
847
|
+
}
|
|
848
|
+
}
|
|
849
|
+
const result = {
|
|
850
|
+
notificationTemplateType,
|
|
851
|
+
isKnownTemplateType,
|
|
852
|
+
isConfiguredTemplateType,
|
|
853
|
+
throttled,
|
|
854
|
+
exists: notification != null,
|
|
855
|
+
boxExists: notificationBox != null,
|
|
856
|
+
notificationBoxNeedsInitialization,
|
|
857
|
+
createdBox,
|
|
858
|
+
deletedNotification,
|
|
859
|
+
notificationMarkedDone,
|
|
860
|
+
tryRun,
|
|
861
|
+
success,
|
|
862
|
+
sendEmailsResult,
|
|
863
|
+
sendTextsResult,
|
|
864
|
+
sendNotificationSummaryResult,
|
|
865
|
+
loadMessageFunctionFailure,
|
|
866
|
+
buildMessageFailure
|
|
867
|
+
};
|
|
868
|
+
return result;
|
|
869
|
+
};
|
|
870
|
+
});
|
|
871
|
+
}
|
|
872
|
+
exports.sendNotificationFactory = sendNotificationFactory;
|
|
873
|
+
function sendQueuedNotificationsFactory(context) {
|
|
874
|
+
const { firebaseServerActionTransformFunctionFactory, notificationCollectionGroup } = context;
|
|
875
|
+
const sendNotification = sendNotificationFactory(context);
|
|
876
|
+
return firebaseServerActionTransformFunctionFactory(firebase_1.SendQueuedNotificationsParams, async () => {
|
|
877
|
+
return async () => {
|
|
878
|
+
let notificationBoxesCreated = 0;
|
|
879
|
+
let notificationsDeleted = 0;
|
|
880
|
+
let notificationsVisited = 0;
|
|
881
|
+
let notificationsSucceeded = 0;
|
|
882
|
+
let notificationsDelayed = 0;
|
|
883
|
+
let notificationsFailed = 0;
|
|
884
|
+
let sendEmailsResult;
|
|
885
|
+
let sendTextsResult;
|
|
886
|
+
let sendNotificationSummaryResult;
|
|
887
|
+
const sendNotificationParams = { key: (0, firebase_1.firestoreDummyKey)(), throwErrorIfSent: false };
|
|
888
|
+
const sendNotificationInstance = await sendNotification(sendNotificationParams);
|
|
889
|
+
// iterate through all JobApplication items that need to be synced
|
|
890
|
+
while (true) {
|
|
891
|
+
const sendQueuedNotificationsResults = await sendQueuedNotifications();
|
|
892
|
+
sendQueuedNotificationsResults.results.forEach((x) => {
|
|
893
|
+
const result = x[1];
|
|
894
|
+
if (result.success) {
|
|
895
|
+
notificationsSucceeded += 1;
|
|
896
|
+
}
|
|
897
|
+
else if (result.createdBox || result.notificationBoxNeedsInitialization) {
|
|
898
|
+
notificationsDelayed = 1;
|
|
899
|
+
}
|
|
900
|
+
else {
|
|
901
|
+
notificationsFailed += 1;
|
|
902
|
+
}
|
|
903
|
+
if (result.deletedNotification) {
|
|
904
|
+
notificationsDeleted += 1;
|
|
905
|
+
}
|
|
906
|
+
if (result.createdBox) {
|
|
907
|
+
notificationBoxesCreated += 1;
|
|
908
|
+
}
|
|
909
|
+
sendEmailsResult = (0, firebase_1.mergeNotificationSendMessagesResult)(sendEmailsResult, result.sendEmailsResult);
|
|
910
|
+
sendTextsResult = (0, firebase_1.mergeNotificationSendMessagesResult)(sendTextsResult, result.sendTextsResult);
|
|
911
|
+
sendNotificationSummaryResult = (0, firebase_1.mergeNotificationSendMessagesResult)(sendNotificationSummaryResult, result.sendNotificationSummaryResult);
|
|
912
|
+
});
|
|
913
|
+
const found = sendQueuedNotificationsResults.results.length;
|
|
914
|
+
notificationsVisited += found;
|
|
915
|
+
if (!found) {
|
|
916
|
+
break;
|
|
917
|
+
}
|
|
918
|
+
}
|
|
919
|
+
async function sendQueuedNotifications() {
|
|
920
|
+
const query = notificationCollectionGroup.queryDocument((0, firebase_1.notificationsPastSendAtTimeQuery)());
|
|
921
|
+
const notificationDocuments = await query.getDocs();
|
|
922
|
+
const result = await (0, util_1.performAsyncTasks)(notificationDocuments, async (notificationDocument) => {
|
|
923
|
+
const result = await sendNotificationInstance(notificationDocument);
|
|
924
|
+
return result;
|
|
925
|
+
}, {
|
|
926
|
+
maxParallelTasks: 10
|
|
927
|
+
});
|
|
928
|
+
return result;
|
|
929
|
+
}
|
|
930
|
+
const result = {
|
|
931
|
+
notificationBoxesCreated,
|
|
932
|
+
notificationsDeleted,
|
|
933
|
+
notificationsVisited,
|
|
934
|
+
notificationsSucceeded,
|
|
935
|
+
notificationsDelayed,
|
|
936
|
+
notificationsFailed,
|
|
937
|
+
sendEmailsResult,
|
|
938
|
+
sendTextsResult,
|
|
939
|
+
sendNotificationSummaryResult
|
|
940
|
+
};
|
|
941
|
+
return result;
|
|
942
|
+
};
|
|
943
|
+
});
|
|
944
|
+
}
|
|
945
|
+
exports.sendQueuedNotificationsFactory = sendQueuedNotificationsFactory;
|
|
946
|
+
function cleanupSentNotificationsFactory(context) {
|
|
947
|
+
const { firestoreContext, firebaseServerActionTransformFunctionFactory, notificationCollectionGroup, notificationCollectionFactory, notificationBoxCollection, notificationWeekCollectionFactory } = context;
|
|
948
|
+
return firebaseServerActionTransformFunctionFactory(firebase_1.CleanupSentNotificationsParams, async () => {
|
|
949
|
+
return async () => {
|
|
950
|
+
let notificationBoxesUpdatesCount = 0;
|
|
951
|
+
let notificationsDeleted = 0;
|
|
952
|
+
let notificationWeeksCreated = 0;
|
|
953
|
+
let notificationWeeksUpdated = 0;
|
|
954
|
+
// iterate through all JobApplication items that need to be synced
|
|
955
|
+
while (true) {
|
|
956
|
+
const cleanupSentNotificationsResults = await cleanupSentNotifications();
|
|
957
|
+
cleanupSentNotificationsResults.results.forEach((x) => {
|
|
958
|
+
const { itemsDeleted, weeksCreated, weeksUpdated } = x[1];
|
|
959
|
+
notificationsDeleted += itemsDeleted;
|
|
960
|
+
notificationWeeksCreated += weeksCreated;
|
|
961
|
+
notificationWeeksUpdated += weeksUpdated;
|
|
962
|
+
});
|
|
963
|
+
const notificationBoxesUpdated = cleanupSentNotificationsResults.results.length;
|
|
964
|
+
notificationBoxesUpdatesCount += notificationBoxesUpdated;
|
|
965
|
+
if (!notificationBoxesUpdated) {
|
|
966
|
+
break;
|
|
967
|
+
}
|
|
968
|
+
}
|
|
969
|
+
async function cleanupSentNotifications() {
|
|
970
|
+
const query = notificationCollectionGroup.queryDocument((0, firebase_1.notificationsReadyForCleanupQuery)());
|
|
971
|
+
const notificationDocuments = await query.getDocs();
|
|
972
|
+
const notificationDocumentsGroupedByNotificationBox = Array.from((0, util_1.makeValuesGroupMap)(notificationDocuments, (x) => x.parent.id).values());
|
|
973
|
+
const result = await (0, util_1.performAsyncTasks)(notificationDocumentsGroupedByNotificationBox, async (notificationDocumentsInSameBox) => {
|
|
974
|
+
const allPairs = await (0, firebase_1.getDocumentSnapshotDataPairs)(notificationDocumentsInSameBox);
|
|
975
|
+
const allPairsWithDataAndMarkedDeleted = allPairs.filter((x) => x.data?.d);
|
|
976
|
+
const pairsGroupedByWeek = Array.from((0, util_1.makeValuesGroupMap)(allPairsWithDataAndMarkedDeleted, (x) => (0, date_1.yearWeekCode)(x.data.sat)).entries());
|
|
977
|
+
// batch incase there are a lot of new notifications to move to week
|
|
978
|
+
const pairsGroupedByWeekInBatches = pairsGroupedByWeek
|
|
979
|
+
.map((x) => {
|
|
980
|
+
const batches = (0, util_1.batch)(x[1], 40);
|
|
981
|
+
return batches.map((batch) => [x[0], batch]);
|
|
982
|
+
})
|
|
983
|
+
.flat();
|
|
984
|
+
const notificationBoxDocument = await notificationBoxCollection.documentAccessor().loadDocument(notificationDocumentsInSameBox[0].parent);
|
|
985
|
+
// create/update the NotificationWeek
|
|
986
|
+
const notificationWeekResults = await (0, util_1.performAsyncTasks)(pairsGroupedByWeekInBatches, async ([yearWeekCode, notificationDocumentsInSameWeek]) => {
|
|
987
|
+
return firestoreContext.runTransaction(async (transaction) => {
|
|
988
|
+
const notificationWeekDocument = notificationWeekCollectionFactory(notificationBoxDocument).documentAccessorForTransaction(transaction).loadDocumentForId(`${yearWeekCode}`);
|
|
989
|
+
const notificationDocumentsInTransaction = (0, firebase_1.loadDocumentsForDocumentReferencesFromValues)(notificationCollectionGroup.documentAccessorForTransaction(transaction), notificationDocumentsInSameWeek, (x) => x.snapshot.ref);
|
|
990
|
+
const notificationWeek = await notificationWeekDocument.snapshotData();
|
|
991
|
+
const newItems = (0, util_1.filterMaybeArrayValues)(notificationDocumentsInSameWeek.map((x) => {
|
|
992
|
+
const data = x.data;
|
|
993
|
+
const shouldSaveToNotificationWeek = (0, firebase_1.shouldSaveNotificationToNotificationWeek)(data);
|
|
994
|
+
return shouldSaveToNotificationWeek ? data.n : undefined;
|
|
995
|
+
}));
|
|
996
|
+
const n = [...(notificationWeek?.n ?? []), ...newItems];
|
|
997
|
+
if (!notificationWeek) {
|
|
998
|
+
// create
|
|
999
|
+
await notificationWeekDocument.create({
|
|
1000
|
+
w: yearWeekCode,
|
|
1001
|
+
n
|
|
1002
|
+
});
|
|
1003
|
+
}
|
|
1004
|
+
else {
|
|
1005
|
+
// update
|
|
1006
|
+
await notificationWeekDocument.update({
|
|
1007
|
+
n
|
|
1008
|
+
});
|
|
1009
|
+
}
|
|
1010
|
+
// delete the notification items
|
|
1011
|
+
await Promise.all(notificationDocumentsInTransaction.map((x) => x.accessor.delete()));
|
|
1012
|
+
return {
|
|
1013
|
+
created: !notificationWeek
|
|
1014
|
+
};
|
|
1015
|
+
});
|
|
1016
|
+
});
|
|
1017
|
+
let weeksCreated = 0;
|
|
1018
|
+
let weeksUpdated = 0;
|
|
1019
|
+
notificationWeekResults.results.forEach((x) => {
|
|
1020
|
+
if (x[1].created) {
|
|
1021
|
+
weeksCreated += 1;
|
|
1022
|
+
}
|
|
1023
|
+
else {
|
|
1024
|
+
weeksUpdated += 1;
|
|
1025
|
+
}
|
|
1026
|
+
});
|
|
1027
|
+
const result = {
|
|
1028
|
+
weeksCreated,
|
|
1029
|
+
weeksUpdated,
|
|
1030
|
+
itemsDeleted: allPairsWithDataAndMarkedDeleted.length
|
|
1031
|
+
};
|
|
1032
|
+
return result;
|
|
1033
|
+
}, {
|
|
1034
|
+
maxParallelTasks: 10
|
|
1035
|
+
});
|
|
1036
|
+
return result;
|
|
1037
|
+
}
|
|
1038
|
+
const result = {
|
|
1039
|
+
notificationBoxesUpdatesCount,
|
|
1040
|
+
notificationsDeleted,
|
|
1041
|
+
notificationWeeksCreated,
|
|
1042
|
+
notificationWeeksUpdated
|
|
1043
|
+
};
|
|
1044
|
+
return result;
|
|
1045
|
+
};
|
|
1046
|
+
});
|
|
1047
|
+
}
|
|
1048
|
+
exports.cleanupSentNotificationsFactory = cleanupSentNotificationsFactory;
|
|
1049
|
+
//# sourceMappingURL=notification.action.server.js.map
|