@abtnode/core 1.16.35 → 1.16.37-beta-20241224-013714-a79db7d3
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/lib/api/team.js +36 -7
- package/lib/blocklet/manager/disk.js +100 -63
- package/lib/blocklet/manager/helper/install-application-from-backup.js +1 -0
- package/lib/blocklet/manager/helper/install-application-from-general.js +2 -0
- package/lib/blocklet/manager/helper/install-component-from-url.js +1 -0
- package/lib/blocklet/manager/helper/upgrade-components.js +1 -0
- package/lib/blocklet/migration-dist/migration.cjs +3 -1
- package/lib/index.js +10 -0
- package/lib/states/index.js +9 -0
- package/lib/states/notification-receiver.js +59 -0
- package/lib/states/notification.js +159 -30
- package/lib/states/user.js +49 -2
- package/lib/team/manager.js +66 -5
- package/lib/webhook/index.js +36 -3
- package/lib/webhook/sender/wallet/index.js +3 -1
- package/package.json +22 -22
package/lib/api/team.js
CHANGED
|
@@ -1517,23 +1517,48 @@ class TeamAPI extends EventEmitter {
|
|
|
1517
1517
|
return this.teamManager.updateStoreList(teamDid, storeList);
|
|
1518
1518
|
}
|
|
1519
1519
|
|
|
1520
|
+
getNotificationReceivers(payload) {
|
|
1521
|
+
return this.teamManager.getNotificationReceivers(payload);
|
|
1522
|
+
}
|
|
1523
|
+
|
|
1520
1524
|
createNotification = (payload) => {
|
|
1521
1525
|
return this.teamManager.createNotification(payload);
|
|
1522
1526
|
};
|
|
1523
1527
|
|
|
1524
|
-
async getNotification({ teamDid, ...rest }) {
|
|
1528
|
+
async getNotification({ teamDid, ...rest }, context) {
|
|
1525
1529
|
const notificationState = await this.getNotificationState(teamDid);
|
|
1526
|
-
return notificationState.findPaginated({ teamDid, ...rest });
|
|
1530
|
+
return notificationState.findPaginated({ teamDid, ...rest }, context);
|
|
1527
1531
|
}
|
|
1528
1532
|
|
|
1529
|
-
async
|
|
1533
|
+
async getNotificationById({ teamDid, id }) {
|
|
1530
1534
|
const notificationState = await this.getNotificationState(teamDid);
|
|
1531
|
-
|
|
1535
|
+
const notification = await notificationState.findNotification({ id });
|
|
1536
|
+
return notification;
|
|
1537
|
+
}
|
|
1538
|
+
|
|
1539
|
+
async getBlockletNotificationsUnreadCount({ teamDid, receiver }) {
|
|
1540
|
+
const notificationReceiverState = await this.getNotificationReceiverState(teamDid);
|
|
1541
|
+
return notificationReceiverState.getUnreadCount({ receiver });
|
|
1532
1542
|
}
|
|
1533
1543
|
|
|
1534
|
-
async
|
|
1544
|
+
async markAllBlockletNotificationsAsRead({ teamDid, receiver }) {
|
|
1545
|
+
const notificationReceiverState = await this.getNotificationReceiverState(teamDid);
|
|
1546
|
+
return notificationReceiverState.makeAllAsRead({ receiver });
|
|
1547
|
+
}
|
|
1548
|
+
|
|
1549
|
+
async updateBlockletNotificationStatus({ teamDid, receivers, notificationId, updates }) {
|
|
1550
|
+
const notificationReceiverState = await this.getNotificationReceiverState(teamDid);
|
|
1551
|
+
return notificationReceiverState.updateStatus({ receivers, notificationId, updates });
|
|
1552
|
+
}
|
|
1553
|
+
|
|
1554
|
+
async readNotifications({ teamDid, ...rest }, context) {
|
|
1555
|
+
const notificationState = await this.getNotificationState(teamDid);
|
|
1556
|
+
return notificationState.read({ teamDid, ...rest }, context);
|
|
1557
|
+
}
|
|
1558
|
+
|
|
1559
|
+
async unreadNotifications({ teamDid, ...rest }, context) {
|
|
1535
1560
|
const notificationState = await this.getNotificationState(teamDid);
|
|
1536
|
-
return notificationState.unread({ teamDid, ...rest });
|
|
1561
|
+
return notificationState.unread({ teamDid, ...rest }, context);
|
|
1537
1562
|
}
|
|
1538
1563
|
|
|
1539
1564
|
// =======
|
|
@@ -1565,7 +1590,11 @@ class TeamAPI extends EventEmitter {
|
|
|
1565
1590
|
}
|
|
1566
1591
|
|
|
1567
1592
|
getNotificationState(did) {
|
|
1568
|
-
return this.teamManager.
|
|
1593
|
+
return this.teamManager.getNotificationState(did);
|
|
1594
|
+
}
|
|
1595
|
+
|
|
1596
|
+
getNotificationReceiverState(did) {
|
|
1597
|
+
return this.teamManager.getNotificationReceiverState(did);
|
|
1569
1598
|
}
|
|
1570
1599
|
|
|
1571
1600
|
// =============
|
|
@@ -36,6 +36,7 @@ const {
|
|
|
36
36
|
FEDERATED,
|
|
37
37
|
CHECK_UPDATE,
|
|
38
38
|
SESSION_CACHE_TTL,
|
|
39
|
+
ROLES,
|
|
39
40
|
} = require('@abtnode/constant');
|
|
40
41
|
|
|
41
42
|
const { getBlockletEngine } = require('@blocklet/meta/lib/engine');
|
|
@@ -640,7 +641,7 @@ class DiskBlockletManager extends BaseBlockletManager {
|
|
|
640
641
|
if (!blocklet.children) {
|
|
641
642
|
return componentDids;
|
|
642
643
|
}
|
|
643
|
-
const targetDid = !inputComponentDids?.length ? componentDids[0] : inputComponentDids[0];
|
|
644
|
+
const targetDid = !inputComponentDids?.length ? componentDids?.[0] : inputComponentDids[0];
|
|
644
645
|
|
|
645
646
|
const canStartStatus = {
|
|
646
647
|
[BlockletStatus.installed]: true,
|
|
@@ -877,6 +878,7 @@ class DiskBlockletManager extends BaseBlockletManager {
|
|
|
877
878
|
entityType: 'blocklet',
|
|
878
879
|
entityId: did,
|
|
879
880
|
severity: 'error',
|
|
881
|
+
componentDid: componentDids?.[0],
|
|
880
882
|
});
|
|
881
883
|
|
|
882
884
|
await this.deleteProcess({ did, componentDids });
|
|
@@ -984,6 +986,7 @@ class DiskBlockletManager extends BaseBlockletManager {
|
|
|
984
986
|
entityType: 'blocklet',
|
|
985
987
|
entityId: did,
|
|
986
988
|
severity: 'success',
|
|
989
|
+
componentDid: componentDids?.[0],
|
|
987
990
|
});
|
|
988
991
|
|
|
989
992
|
return res;
|
|
@@ -1080,6 +1083,7 @@ class DiskBlockletManager extends BaseBlockletManager {
|
|
|
1080
1083
|
entityType: 'blocklet',
|
|
1081
1084
|
entityId: did,
|
|
1082
1085
|
severity: 'error',
|
|
1086
|
+
componentDid: componentDids?.[0],
|
|
1083
1087
|
});
|
|
1084
1088
|
});
|
|
1085
1089
|
|
|
@@ -1168,6 +1172,7 @@ class DiskBlockletManager extends BaseBlockletManager {
|
|
|
1168
1172
|
entityType: 'blocklet',
|
|
1169
1173
|
entityId: doc.meta.did,
|
|
1170
1174
|
severity: 'success',
|
|
1175
|
+
componentDid: did,
|
|
1171
1176
|
});
|
|
1172
1177
|
return doc;
|
|
1173
1178
|
} catch (error) {
|
|
@@ -1181,6 +1186,7 @@ class DiskBlockletManager extends BaseBlockletManager {
|
|
|
1181
1186
|
entityType: 'blocklet',
|
|
1182
1187
|
entityId: doc.meta.did,
|
|
1183
1188
|
severity: 'success',
|
|
1189
|
+
componentDid: did,
|
|
1184
1190
|
});
|
|
1185
1191
|
|
|
1186
1192
|
return doc;
|
|
@@ -1371,6 +1377,7 @@ class DiskBlockletManager extends BaseBlockletManager {
|
|
|
1371
1377
|
severity: 'success',
|
|
1372
1378
|
action: `/blocklets/${newBlocklet.meta.did}/components`,
|
|
1373
1379
|
blockletDashboardAction: '/.well-known/service/admin/components',
|
|
1380
|
+
componentDid: child.meta.did,
|
|
1374
1381
|
});
|
|
1375
1382
|
|
|
1376
1383
|
this.emit(BlockletEvents.componentRemoved, {
|
|
@@ -2734,6 +2741,7 @@ class DiskBlockletManager extends BaseBlockletManager {
|
|
|
2734
2741
|
entityType: 'blocklet',
|
|
2735
2742
|
entityId: did,
|
|
2736
2743
|
severity: 'error',
|
|
2744
|
+
componentDid: childrenToDownload[0]?.meta.did,
|
|
2737
2745
|
});
|
|
2738
2746
|
|
|
2739
2747
|
// rollback on download failed
|
|
@@ -2916,6 +2924,7 @@ class DiskBlockletManager extends BaseBlockletManager {
|
|
|
2916
2924
|
entityType: 'blocklet',
|
|
2917
2925
|
entityId: did,
|
|
2918
2926
|
severity: 'success',
|
|
2927
|
+
componentDid: componentDids?.[0],
|
|
2919
2928
|
});
|
|
2920
2929
|
|
|
2921
2930
|
launcher.notifyBlockletUpdated(blocklet);
|
|
@@ -2946,6 +2955,7 @@ class DiskBlockletManager extends BaseBlockletManager {
|
|
|
2946
2955
|
entityType: 'blocklet',
|
|
2947
2956
|
entityId: did,
|
|
2948
2957
|
severity: 'error',
|
|
2958
|
+
componentDid: componentDids?.[0],
|
|
2949
2959
|
});
|
|
2950
2960
|
|
|
2951
2961
|
this.emit(BlockletEvents.startFailed, { ...doc, componentDids, error: { message: error.message } });
|
|
@@ -3164,6 +3174,7 @@ class DiskBlockletManager extends BaseBlockletManager {
|
|
|
3164
3174
|
if (!list || !list.updateList?.length) {
|
|
3165
3175
|
return;
|
|
3166
3176
|
}
|
|
3177
|
+
const componentDids = list.updateList.map((item) => item.meta.did);
|
|
3167
3178
|
const updateList = list.updateList.map((item) => {
|
|
3168
3179
|
return { title: item.meta.title, description: item.meta.description, version: item.meta.version };
|
|
3169
3180
|
});
|
|
@@ -3240,6 +3251,7 @@ class DiskBlockletManager extends BaseBlockletManager {
|
|
|
3240
3251
|
appSk: wallet.secretKey,
|
|
3241
3252
|
},
|
|
3242
3253
|
users,
|
|
3254
|
+
componentDids,
|
|
3243
3255
|
});
|
|
3244
3256
|
await states.blockletExtras.setSettings(did, { checkUpdateMd5 });
|
|
3245
3257
|
} catch (err) {
|
|
@@ -3280,20 +3292,10 @@ class DiskBlockletManager extends BaseBlockletManager {
|
|
|
3280
3292
|
* blockletDashboardAction: string,
|
|
3281
3293
|
* sender: { appDid: string, appSk: string },
|
|
3282
3294
|
* users: Array<{ did: string, locale: string }>
|
|
3295
|
+
* componentDids: Array<string>
|
|
3283
3296
|
* */
|
|
3284
|
-
|
|
3285
|
-
|
|
3286
|
-
blocklet,
|
|
3287
|
-
title,
|
|
3288
|
-
body,
|
|
3289
|
-
button,
|
|
3290
|
-
description,
|
|
3291
|
-
attachments,
|
|
3292
|
-
action,
|
|
3293
|
-
blockletDashboardAction,
|
|
3294
|
-
sender,
|
|
3295
|
-
users,
|
|
3296
|
-
}) {
|
|
3297
|
+
_sendAllMessageToUser({ did, title, description, action, blockletDashboardAction, componentDids }) {
|
|
3298
|
+
// 这个方法会向用户发送消息
|
|
3297
3299
|
this._createNotification(did, {
|
|
3298
3300
|
title: title.en,
|
|
3299
3301
|
description: description.en,
|
|
@@ -3302,50 +3304,52 @@ class DiskBlockletManager extends BaseBlockletManager {
|
|
|
3302
3304
|
severity: 'success',
|
|
3303
3305
|
action,
|
|
3304
3306
|
blockletDashboardAction,
|
|
3307
|
+
componentDid: componentDids?.[0],
|
|
3305
3308
|
});
|
|
3306
3309
|
|
|
3307
|
-
|
|
3308
|
-
const
|
|
3309
|
-
const
|
|
3310
|
-
|
|
3311
|
-
|
|
3312
|
-
|
|
3310
|
+
// _createNotification 会将消息通过 sendToUser 发送
|
|
3311
|
+
// const zhUsers = users.filter((x) => x.locale === 'zh');
|
|
3312
|
+
// const enUsers = users.filter((x) => x.locale !== 'zh');
|
|
3313
|
+
// const url = `http://${getDidDomainForBlocklet({
|
|
3314
|
+
// did: blocklet.appPid,
|
|
3315
|
+
// })}`;
|
|
3316
|
+
// const link = `${url}${blockletDashboardAction}`;
|
|
3313
3317
|
|
|
3314
3318
|
// send in batches by language
|
|
3315
|
-
if (zhUsers.length) {
|
|
3316
|
-
|
|
3317
|
-
|
|
3318
|
-
|
|
3319
|
-
|
|
3320
|
-
|
|
3321
|
-
|
|
3322
|
-
|
|
3323
|
-
|
|
3324
|
-
|
|
3325
|
-
|
|
3326
|
-
|
|
3327
|
-
|
|
3328
|
-
|
|
3329
|
-
|
|
3330
|
-
|
|
3331
|
-
}
|
|
3332
|
-
if (enUsers.length) {
|
|
3333
|
-
|
|
3334
|
-
|
|
3335
|
-
|
|
3336
|
-
|
|
3337
|
-
|
|
3338
|
-
|
|
3339
|
-
|
|
3340
|
-
|
|
3341
|
-
|
|
3342
|
-
|
|
3343
|
-
|
|
3344
|
-
|
|
3345
|
-
|
|
3346
|
-
|
|
3347
|
-
|
|
3348
|
-
}
|
|
3319
|
+
// if (zhUsers.length) {
|
|
3320
|
+
// await sendToUser(
|
|
3321
|
+
// zhUsers.map((x) => x.did),
|
|
3322
|
+
// {
|
|
3323
|
+
// title: title.zh,
|
|
3324
|
+
// body: body.zh,
|
|
3325
|
+
// attachments,
|
|
3326
|
+
// actions: [
|
|
3327
|
+
// {
|
|
3328
|
+
// name: button.zh,
|
|
3329
|
+
// link,
|
|
3330
|
+
// },
|
|
3331
|
+
// ],
|
|
3332
|
+
// },
|
|
3333
|
+
// sender
|
|
3334
|
+
// );
|
|
3335
|
+
// }
|
|
3336
|
+
// if (enUsers.length) {
|
|
3337
|
+
// await sendToUser(
|
|
3338
|
+
// enUsers.map((x) => x.did),
|
|
3339
|
+
// {
|
|
3340
|
+
// title: title.en,
|
|
3341
|
+
// body: body.en,
|
|
3342
|
+
// attachments,
|
|
3343
|
+
// actions: [
|
|
3344
|
+
// {
|
|
3345
|
+
// name: button.en,
|
|
3346
|
+
// link,
|
|
3347
|
+
// },
|
|
3348
|
+
// ],
|
|
3349
|
+
// },
|
|
3350
|
+
// sender
|
|
3351
|
+
// );
|
|
3352
|
+
// }
|
|
3349
3353
|
}
|
|
3350
3354
|
|
|
3351
3355
|
async getBlockletEnvironments(did) {
|
|
@@ -3757,6 +3761,7 @@ class DiskBlockletManager extends BaseBlockletManager {
|
|
|
3757
3761
|
entityId: did,
|
|
3758
3762
|
severity: 'success',
|
|
3759
3763
|
extra: { wallet: walletExtra },
|
|
3764
|
+
componentDid: meta.did,
|
|
3760
3765
|
});
|
|
3761
3766
|
} catch (error) {
|
|
3762
3767
|
logger.error('create installed notification failed', { error, did });
|
|
@@ -3784,6 +3789,7 @@ class DiskBlockletManager extends BaseBlockletManager {
|
|
|
3784
3789
|
entityType: 'blocklet',
|
|
3785
3790
|
entityId: did,
|
|
3786
3791
|
severity: 'error',
|
|
3792
|
+
componentDid: meta.did,
|
|
3787
3793
|
});
|
|
3788
3794
|
} catch (e) {
|
|
3789
3795
|
logger.error('failed to remove blocklet on install error', { did: meta.did, error: e });
|
|
@@ -3997,6 +4003,7 @@ class DiskBlockletManager extends BaseBlockletManager {
|
|
|
3997
4003
|
entityType: 'blocklet',
|
|
3998
4004
|
entityId: did,
|
|
3999
4005
|
severity: 'success',
|
|
4006
|
+
componentDid: componentDids?.[0],
|
|
4000
4007
|
});
|
|
4001
4008
|
} catch (error) {
|
|
4002
4009
|
logger.error('emit upgrade notification failed', { name, version, error });
|
|
@@ -4046,6 +4053,7 @@ class DiskBlockletManager extends BaseBlockletManager {
|
|
|
4046
4053
|
entityType: 'blocklet',
|
|
4047
4054
|
entityId: did,
|
|
4048
4055
|
severity: 'error',
|
|
4056
|
+
componentDid: componentDids?.[0],
|
|
4049
4057
|
});
|
|
4050
4058
|
throw err;
|
|
4051
4059
|
}
|
|
@@ -4342,15 +4350,26 @@ class DiskBlockletManager extends BaseBlockletManager {
|
|
|
4342
4350
|
await forEachBlocklet(blocklet, hookFn, { parallel: true, concurrencyLimit: 4 });
|
|
4343
4351
|
}
|
|
4344
4352
|
|
|
4353
|
+
async getReceiverDids(teamDid) {
|
|
4354
|
+
const receivers = await this.teamAPI.getNotificationReceivers({
|
|
4355
|
+
teamDid,
|
|
4356
|
+
roles: [ROLES.ADMIN, ROLES.OWNER],
|
|
4357
|
+
selection: { did: 1 },
|
|
4358
|
+
});
|
|
4359
|
+
return receivers.map((r) => r.did);
|
|
4360
|
+
}
|
|
4361
|
+
|
|
4362
|
+
// 目前:Blocklet 的安装消息都会聚合在这里。
|
|
4345
4363
|
async _createNotification(did, notification) {
|
|
4346
4364
|
if (isCLI()) {
|
|
4347
|
-
return;
|
|
4365
|
+
return undefined;
|
|
4348
4366
|
}
|
|
4349
4367
|
|
|
4350
4368
|
try {
|
|
4351
4369
|
let blockletUrl;
|
|
4370
|
+
let blocklet;
|
|
4352
4371
|
try {
|
|
4353
|
-
|
|
4372
|
+
blocklet = await this.getBlocklet(did);
|
|
4354
4373
|
if (blocklet) {
|
|
4355
4374
|
const urls = blocklet.site?.domainAliases || [];
|
|
4356
4375
|
const customUrl = urls.find((x) => !x.isProtected)?.value;
|
|
@@ -4367,16 +4386,34 @@ class DiskBlockletManager extends BaseBlockletManager {
|
|
|
4367
4386
|
const isExternal = !!extra?.controller;
|
|
4368
4387
|
|
|
4369
4388
|
if (!isExternal) {
|
|
4370
|
-
|
|
4389
|
+
// 将 notification 信息保存在 server 中
|
|
4390
|
+
const serverReceivers = await this.getReceiverDids(this.teamManager.nodeDid);
|
|
4391
|
+
await states.notification.create({
|
|
4392
|
+
...notification,
|
|
4393
|
+
blockletUrl,
|
|
4394
|
+
receiver: serverReceivers,
|
|
4395
|
+
sender: did,
|
|
4396
|
+
source: 'system',
|
|
4397
|
+
});
|
|
4371
4398
|
}
|
|
4372
|
-
|
|
4373
|
-
|
|
4374
|
-
|
|
4375
|
-
|
|
4376
|
-
|
|
4377
|
-
|
|
4399
|
+
|
|
4400
|
+
if (blocklet) {
|
|
4401
|
+
const blockletReceivers = await this.getReceiverDids(did);
|
|
4402
|
+
const doc = await this.teamManager.createNotification({
|
|
4403
|
+
teamDid: did,
|
|
4404
|
+
...notification,
|
|
4405
|
+
action: notification.blockletDashboardAction || notification.action,
|
|
4406
|
+
blockletUrl,
|
|
4407
|
+
sender: did,
|
|
4408
|
+
source: 'system',
|
|
4409
|
+
receiver: blockletReceivers,
|
|
4410
|
+
});
|
|
4411
|
+
return doc;
|
|
4412
|
+
}
|
|
4413
|
+
return undefined;
|
|
4378
4414
|
} catch (error) {
|
|
4379
4415
|
logger.error('create notification failed', { did, error });
|
|
4416
|
+
return undefined;
|
|
4380
4417
|
}
|
|
4381
4418
|
}
|
|
4382
4419
|
|
|
@@ -132,6 +132,7 @@ const installApplicationFromGeneral = async ({
|
|
|
132
132
|
entityType: 'blocklet',
|
|
133
133
|
entityId: did,
|
|
134
134
|
severity: 'error',
|
|
135
|
+
componentDid,
|
|
135
136
|
});
|
|
136
137
|
|
|
137
138
|
throw err;
|
|
@@ -187,6 +188,7 @@ const installApplicationFromGeneral = async ({
|
|
|
187
188
|
entityType: 'blocklet',
|
|
188
189
|
entityId: did,
|
|
189
190
|
severity: 'error',
|
|
191
|
+
componentDid,
|
|
190
192
|
});
|
|
191
193
|
});
|
|
192
194
|
}, delay || 0);
|
|
@@ -610,6 +610,8 @@ module.exports = Object.freeze({
|
|
|
610
610
|
STORE_DETAIL_PAGE_PATH_PREFIX: '/blocklets',
|
|
611
611
|
|
|
612
612
|
MAX_USER_PAGE_SIZE: 100,
|
|
613
|
+
// 默认最大 page size
|
|
614
|
+
MAX_PAGE_SIZE: 100,
|
|
613
615
|
|
|
614
616
|
SERVER_STATUS: {
|
|
615
617
|
RUNNING: 1,
|
|
@@ -38551,7 +38553,7 @@ module.exports = require("zlib");
|
|
|
38551
38553
|
/***/ ((module) => {
|
|
38552
38554
|
|
|
38553
38555
|
"use strict";
|
|
38554
|
-
module.exports = JSON.parse('{"name":"@abtnode/core","publishConfig":{"access":"public"},"version":"1.16.
|
|
38556
|
+
module.exports = JSON.parse('{"name":"@abtnode/core","publishConfig":{"access":"public"},"version":"1.16.36","description":"","main":"lib/index.js","files":["lib"],"scripts":{"lint":"eslint tests lib --ignore-pattern \'tests/assets/*\'","lint:fix":"eslint --fix tests lib","test":"node tools/jest.js","coverage":"npm run test -- --coverage"},"keywords":[],"author":"wangshijun <wangshijun2010@gmail.com> (http://github.com/wangshijun)","license":"Apache-2.0","dependencies":{"@abtnode/analytics":"1.16.36","@abtnode/auth":"1.16.36","@abtnode/certificate-manager":"1.16.36","@abtnode/constant":"1.16.36","@abtnode/cron":"1.16.36","@abtnode/logger":"1.16.36","@abtnode/models":"1.16.36","@abtnode/queue":"1.16.36","@abtnode/rbac":"1.16.36","@abtnode/router-provider":"1.16.36","@abtnode/static-server":"1.16.36","@abtnode/timemachine":"1.16.36","@abtnode/util":"1.16.36","@arcblock/did":"1.18.162","@arcblock/did-auth":"1.18.162","@arcblock/did-ext":"^1.18.162","@arcblock/did-motif":"^1.1.13","@arcblock/did-util":"1.18.162","@arcblock/event-hub":"1.18.162","@arcblock/jwt":"^1.18.162","@arcblock/pm2-events":"^0.0.5","@arcblock/validator":"^1.18.162","@arcblock/vc":"1.18.162","@blocklet/constant":"1.16.36","@blocklet/did-space-js":"^0.6.0","@blocklet/env":"1.16.36","@blocklet/meta":"1.16.36","@blocklet/resolver":"1.16.36","@blocklet/sdk":"1.16.36","@blocklet/store":"1.16.36","@fidm/x509":"^1.2.1","@ocap/mcrypto":"1.18.162","@ocap/util":"1.18.162","@ocap/wallet":"1.18.162","@slack/webhook":"^5.0.4","archiver":"^7.0.1","axios":"^1.7.5","axon":"^2.0.3","chalk":"^4.1.2","cross-spawn":"^7.0.3","deep-diff":"^1.0.2","detect-port":"^1.5.1","envfile":"^7.1.0","escape-string-regexp":"^4.0.0","fast-glob":"^3.3.2","filesize":"^10.1.1","flat":"^5.0.2","fs-extra":"^11.2.0","get-port":"^5.1.1","hasha":"^5.2.2","is-base64":"^1.1.0","is-cidr":"4","is-ip":"3","is-url":"^1.2.4","joi":"17.12.2","joi-extension-semver":"^5.0.0","js-yaml":"^4.1.0","kill-port":"^2.0.1","lodash":"^4.17.21","lru-cache":"^11.0.2","node-stream-zip":"^1.15.0","p-all":"^3.0.0","p-limit":"^3.1.0","p-map":"^4.0.0","p-retry":"^4.6.2","read-last-lines":"^1.8.0","semver":"^7.6.3","sequelize":"^6.35.0","shelljs":"^0.8.5","ssri":"^8.0.1","stream-throttle":"^0.1.3","stream-to-promise":"^3.0.0","systeminformation":"^5.23.3","tail":"^2.2.4","tar":"^6.1.11","transliteration":"^2.3.5","ua-parser-js":"^1.0.2","ufo":"^1.5.3","uuid":"^9.0.1","valid-url":"^1.0.9","which":"^2.0.2","xbytes":"^1.8.0"},"devDependencies":{"expand-tilde":"^2.0.2","express":"^4.18.2","jest":"^29.7.0","unzipper":"^0.10.11"},"gitHead":"e5764f753181ed6a7c615cd4fc6682aacf0cb7cd"}');
|
|
38555
38557
|
|
|
38556
38558
|
/***/ }),
|
|
38557
38559
|
|
package/lib/index.js
CHANGED
|
@@ -537,17 +537,27 @@ function ABTNode(options) {
|
|
|
537
537
|
addBlockletStore: teamAPI.addStore.bind(teamAPI),
|
|
538
538
|
deleteBlockletStore: teamAPI.deleteStore.bind(teamAPI),
|
|
539
539
|
|
|
540
|
+
getNotificationReceivers: teamAPI.getNotificationReceivers.bind(teamAPI),
|
|
541
|
+
|
|
540
542
|
// Notifications
|
|
541
543
|
createNotification: states.notification.create.bind(states.notification),
|
|
542
544
|
getNotifications: states.notification.findPaginated.bind(states.notification),
|
|
543
545
|
readNotifications: states.notification.read.bind(states.notification),
|
|
544
546
|
unreadNotifications: states.notification.unread.bind(states.notification),
|
|
547
|
+
getNotificationById: states.notification.findNotification.bind(states.notification),
|
|
548
|
+
getNotificationsUnreadCount: states.notificationReceiver.getUnreadCount.bind(states.notificationReceiver),
|
|
549
|
+
makeAllAsRead: states.notificationReceiver.makeAllAsRead.bind(states.notificationReceiver),
|
|
550
|
+
updateNotificationStatus: states.notificationReceiver.updateStatus.bind(states.notificationReceiver),
|
|
545
551
|
|
|
546
552
|
// Blocklet Notifications
|
|
547
553
|
createBlockletNotification: teamAPI.createNotification.bind(teamAPI),
|
|
548
554
|
getBlockletNotifications: teamAPI.getNotification.bind(teamAPI),
|
|
549
555
|
readBlockletNotifications: teamAPI.readNotifications.bind(teamAPI),
|
|
550
556
|
unreadBlockletNotifications: teamAPI.unreadNotifications.bind(teamAPI),
|
|
557
|
+
getBlockletNotificationById: teamAPI.getNotificationById.bind(teamAPI),
|
|
558
|
+
getBlockletNotificationsUnreadCount: teamAPI.getBlockletNotificationsUnreadCount.bind(teamAPI),
|
|
559
|
+
makeAllBlockletNotificationsAsRead: teamAPI.markAllBlockletNotificationsAsRead.bind(teamAPI),
|
|
560
|
+
updateBlockletNotificationStatus: teamAPI.updateBlockletNotificationStatus.bind(teamAPI),
|
|
551
561
|
|
|
552
562
|
// AuditLog
|
|
553
563
|
createAuditLog: (params) => states.auditLog.create(params, instance),
|
package/lib/states/index.js
CHANGED
|
@@ -5,6 +5,7 @@ const logger = require('@abtnode/logger')('@abtnode/core:states');
|
|
|
5
5
|
const NodeState = require('./node');
|
|
6
6
|
const BlockletState = require('./blocklet');
|
|
7
7
|
const NotificationState = require('./notification');
|
|
8
|
+
const NotificationReceiverState = require('./notification-receiver');
|
|
8
9
|
const SiteState = require('./site');
|
|
9
10
|
const AccessKeyState = require('./access-key');
|
|
10
11
|
const WebhookState = require('./webhook');
|
|
@@ -29,6 +30,12 @@ const init = (dataDirs, config = {}) => {
|
|
|
29
30
|
logger.info(`Init server states in ${dbPath}`);
|
|
30
31
|
|
|
31
32
|
const notificationState = new NotificationState(models.Notification, config);
|
|
33
|
+
const notificationReceiverState = new NotificationReceiverState(models.NotificationReceivers, config);
|
|
34
|
+
|
|
35
|
+
// bind notification model
|
|
36
|
+
notificationState.setNotificationReceiversState(notificationReceiverState);
|
|
37
|
+
notificationReceiverState.setNotificationState(notificationState);
|
|
38
|
+
|
|
32
39
|
const nodeState = new NodeState(models.Server, config, dataDirs, notificationState);
|
|
33
40
|
const blockletState = new BlockletState(models.Blocklet, config);
|
|
34
41
|
const siteState = new SiteState(models.Site, config);
|
|
@@ -48,6 +55,7 @@ const init = (dataDirs, config = {}) => {
|
|
|
48
55
|
node: nodeState,
|
|
49
56
|
blocklet: blockletState,
|
|
50
57
|
notification: notificationState,
|
|
58
|
+
notificationReceiver: notificationReceiverState,
|
|
51
59
|
site: siteState,
|
|
52
60
|
accessKey: accessKeyState,
|
|
53
61
|
webhook: webhookState,
|
|
@@ -68,6 +76,7 @@ const init = (dataDirs, config = {}) => {
|
|
|
68
76
|
* blocklet: import('./blocklet'),
|
|
69
77
|
* blockletExtras: import('./blocklet-extras'),
|
|
70
78
|
* notification: import('./notification'),
|
|
79
|
+
* notificationReceiver: import('./notification-receiver'),
|
|
71
80
|
* job: import('./job'),
|
|
72
81
|
* node: import('./node'),
|
|
73
82
|
* [key: string]: any
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
const logger = require('@abtnode/logger')('@abtnode/core:states:notification');
|
|
2
|
+
const BaseState = require('./base');
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* @extends BaseState<import('@abtnode/models').NotificationReceiverState>
|
|
6
|
+
*/
|
|
7
|
+
class NotificationReceiverState extends BaseState {
|
|
8
|
+
constructor(baseDir, config = {}) {
|
|
9
|
+
super(baseDir, { ...config });
|
|
10
|
+
|
|
11
|
+
this.defaultReceiver = config.defaultReceiver || '';
|
|
12
|
+
this.notificationState = config.notificationState;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
setNotificationState(state) {
|
|
16
|
+
this.notificationState = state;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
getNotificationState() {
|
|
20
|
+
return this.notificationState;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// 更新消息状态
|
|
24
|
+
async updateStatus({ notificationId, receivers, updates }) {
|
|
25
|
+
if (!notificationId || !receivers.length) {
|
|
26
|
+
logger.error('notification is not exist', notificationId, receivers);
|
|
27
|
+
}
|
|
28
|
+
const [numAffected] = await this.update({ receiver: { $in: receivers }, notificationId }, { $set: { ...updates } });
|
|
29
|
+
return numAffected;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* 获取当前用户未读消息数量
|
|
34
|
+
*/
|
|
35
|
+
async getUnreadCount({ receiver }) {
|
|
36
|
+
if (!receiver) {
|
|
37
|
+
logger.error('receiver is not as empty');
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const count = await this.count({
|
|
41
|
+
receiver,
|
|
42
|
+
read: false,
|
|
43
|
+
});
|
|
44
|
+
return count;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* 将当前用户所有消息标记为已读
|
|
49
|
+
*/
|
|
50
|
+
async makeAllAsRead({ receiver }) {
|
|
51
|
+
if (!receiver) {
|
|
52
|
+
logger.error('receiver is not as empty');
|
|
53
|
+
}
|
|
54
|
+
const [numAffected] = await this.update({ receiver }, { $set: { read: true } });
|
|
55
|
+
return numAffected;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
module.exports = NotificationReceiverState;
|
|
@@ -1,8 +1,29 @@
|
|
|
1
1
|
const logger = require('@abtnode/logger')('@abtnode/core:states:notification');
|
|
2
2
|
const { EVENTS } = require('@abtnode/constant');
|
|
3
|
+
const { MAX_PAGE_SIZE } = require('@abtnode/constant');
|
|
4
|
+
const { Sequelize, Op } = require('sequelize');
|
|
5
|
+
const { isValid } = require('@arcblock/did');
|
|
3
6
|
|
|
4
7
|
const BaseState = require('./base');
|
|
5
8
|
|
|
9
|
+
const receiverDidValidation = (receiver, context) => {
|
|
10
|
+
const { did } = context?.user ?? {};
|
|
11
|
+
if (!receiver || did !== receiver) {
|
|
12
|
+
return "You are not allowed to mark other user's notification as read";
|
|
13
|
+
}
|
|
14
|
+
if (!isValid(receiver)) {
|
|
15
|
+
return 'Please provide a valid receiver DID.';
|
|
16
|
+
}
|
|
17
|
+
return '';
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
const readUnreadInputValidation = ({ notificationIds, receiver }, context) => {
|
|
21
|
+
if (!notificationIds.length) {
|
|
22
|
+
return 'Please provide the notificationId(s) to mark as read.';
|
|
23
|
+
}
|
|
24
|
+
return receiverDidValidation(receiver, context);
|
|
25
|
+
};
|
|
26
|
+
|
|
6
27
|
/**
|
|
7
28
|
* @extends BaseState<import('@abtnode/models').NotificationState>
|
|
8
29
|
*/
|
|
@@ -12,6 +33,7 @@ class NotificationState extends BaseState {
|
|
|
12
33
|
|
|
13
34
|
this.defaultSender = config.defaultSender || '';
|
|
14
35
|
this.defaultReceiver = config.defaultReceiver || '';
|
|
36
|
+
this.notificationReceiverState = config.notificationReceiverState;
|
|
15
37
|
}
|
|
16
38
|
|
|
17
39
|
setDefaultSender(sender) {
|
|
@@ -22,58 +44,165 @@ class NotificationState extends BaseState {
|
|
|
22
44
|
this.defaultReceiver = receiver;
|
|
23
45
|
}
|
|
24
46
|
|
|
47
|
+
setNotificationReceiversState(state) {
|
|
48
|
+
this.notificationReceiverState = state;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
getNotificationReceiversState() {
|
|
52
|
+
return this.notificationReceiverState;
|
|
53
|
+
}
|
|
54
|
+
|
|
25
55
|
async create(payload) {
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
56
|
+
if (!this.notificationReceiverState) {
|
|
57
|
+
throw new Error('Invalid database: missing notification_receivers tables');
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const title = payload.title || '';
|
|
61
|
+
const description = payload.description || payload.body;
|
|
62
|
+
|
|
63
|
+
// 校验必填字段
|
|
64
|
+
if (!title) {
|
|
65
|
+
throw new Error('Invalid notification payload: title is required');
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
if (!description) {
|
|
69
|
+
throw new Error('Invalid notification payload: description is required');
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const sender = payload?.sender?.did || this.defaultSender;
|
|
73
|
+
const receiverRaws = payload.receiver || this.defaultReceiver;
|
|
74
|
+
|
|
75
|
+
const actions = payload.actions ?? [];
|
|
76
|
+
if (payload.action) {
|
|
77
|
+
actions.push({
|
|
78
|
+
name: 'Visit',
|
|
79
|
+
link: payload.action,
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
let { severity } = payload;
|
|
84
|
+
if (severity === 'normal') {
|
|
85
|
+
severity = 'info';
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
const notificationData = {
|
|
89
|
+
sender,
|
|
90
|
+
receiver: '',
|
|
38
91
|
entityType: payload.entityType || '',
|
|
39
92
|
entityId: payload.entityId || '',
|
|
40
|
-
|
|
93
|
+
action: payload.action || '',
|
|
94
|
+
title,
|
|
41
95
|
read: false,
|
|
42
|
-
|
|
96
|
+
description,
|
|
97
|
+
severity: severity || 'info',
|
|
98
|
+
attachments: payload.attachments ? payload.attachments : [],
|
|
99
|
+
actions,
|
|
100
|
+
blocks: payload.blocks ? payload.blocks : [],
|
|
101
|
+
type: payload.type || 'notification',
|
|
102
|
+
source: payload.source || (sender === payload.teamDid ? 'system' : 'component'),
|
|
103
|
+
componentDid: payload.componentDid || sender,
|
|
104
|
+
};
|
|
105
|
+
const receivers = Array.isArray(receiverRaws) ? receiverRaws : [receiverRaws];
|
|
106
|
+
const doc = await this.insert(notificationData);
|
|
107
|
+
|
|
108
|
+
const receiverEntries = receivers.map((receiverId) => ({
|
|
109
|
+
receiver: receiverId,
|
|
110
|
+
notificationId: doc.id,
|
|
111
|
+
}));
|
|
43
112
|
|
|
113
|
+
const receiverDoc = await this.notificationReceiverState.insertMany(receiverEntries);
|
|
114
|
+
if (receiverDoc) {
|
|
115
|
+
doc.receivers = receiverDoc;
|
|
116
|
+
}
|
|
44
117
|
if (!payload.teamDid) {
|
|
45
118
|
this.emit(EVENTS.NOTIFICATION_CREATE, {
|
|
46
119
|
...payload,
|
|
47
120
|
...doc,
|
|
121
|
+
receiver: receiverDoc.map((item) => item.receiver),
|
|
48
122
|
});
|
|
49
123
|
}
|
|
50
|
-
|
|
51
124
|
return doc;
|
|
52
125
|
}
|
|
53
126
|
|
|
54
|
-
findPaginated({ read, paging,
|
|
55
|
-
const
|
|
127
|
+
findPaginated({ read, paging, receiver, severity, componentDid, entityId, pageSize = 10 } = {}, context) {
|
|
128
|
+
const errorMsg = receiverDidValidation(receiver, context);
|
|
129
|
+
if (errorMsg) {
|
|
130
|
+
throw new Error(errorMsg);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
const where = {};
|
|
134
|
+
const includeConditions = {};
|
|
56
135
|
if (typeof read === 'boolean') {
|
|
57
|
-
|
|
136
|
+
includeConditions.read = read;
|
|
137
|
+
}
|
|
138
|
+
if (receiver) {
|
|
139
|
+
includeConditions.receiver = receiver;
|
|
58
140
|
}
|
|
59
|
-
|
|
60
|
-
|
|
141
|
+
where.id = {
|
|
142
|
+
[Op.in]: Sequelize.literal(`
|
|
143
|
+
(SELECT DISTINCT notificationId FROM notification_receivers WHERE receiver = '${receiver}')
|
|
144
|
+
`),
|
|
145
|
+
};
|
|
146
|
+
|
|
147
|
+
if (componentDid) {
|
|
148
|
+
where.componentDid = componentDid;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
if (severity) {
|
|
152
|
+
where.severity = severity;
|
|
61
153
|
}
|
|
62
|
-
|
|
154
|
+
if (entityId) {
|
|
155
|
+
where.entityId = entityId;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
const include = [
|
|
159
|
+
{
|
|
160
|
+
model: this.notificationReceiverState.model,
|
|
161
|
+
as: 'receivers', // 关联的别名
|
|
162
|
+
where: includeConditions,
|
|
163
|
+
required: true,
|
|
164
|
+
separate: true, // 会对主查询和关联查询分开执行,而不是通过单个 SQL 查询一次性完成
|
|
165
|
+
},
|
|
166
|
+
];
|
|
167
|
+
|
|
168
|
+
const curPageSize = pageSize > MAX_PAGE_SIZE ? MAX_PAGE_SIZE : pageSize;
|
|
169
|
+
|
|
170
|
+
return this.paginate({ where, include }, { createdAt: -1 }, { ...paging, pageSize: curPageSize });
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
async findNotification({ id }) {
|
|
174
|
+
if (!id) {
|
|
175
|
+
throw new Error('notification id is not allow empty');
|
|
176
|
+
}
|
|
177
|
+
const doc = await this.findOne({ id });
|
|
178
|
+
return doc;
|
|
63
179
|
}
|
|
64
180
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
181
|
+
async read({ notificationIds, receiver }, context) {
|
|
182
|
+
const errorMsg = readUnreadInputValidation({ notificationIds, receiver }, context);
|
|
183
|
+
if (errorMsg) {
|
|
184
|
+
throw new Error(errorMsg);
|
|
185
|
+
}
|
|
186
|
+
logger.info('mark notification as read', { notificationIds });
|
|
187
|
+
const conditions = {
|
|
188
|
+
notificationId: { $in: notificationIds },
|
|
189
|
+
receiver,
|
|
190
|
+
};
|
|
191
|
+
const [numAffected] = await this.notificationReceiverState.update(conditions, { $set: { read: true } });
|
|
70
192
|
return numAffected;
|
|
71
193
|
}
|
|
72
194
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
195
|
+
async unread({ notificationIds, receiver }, context) {
|
|
196
|
+
const errorMsg = readUnreadInputValidation({ notificationIds, receiver }, context);
|
|
197
|
+
if (errorMsg) {
|
|
198
|
+
throw new Error(errorMsg);
|
|
199
|
+
}
|
|
200
|
+
logger.info('mark notification as unread', { notificationIds });
|
|
201
|
+
const conditions = {
|
|
202
|
+
notificationId: { $in: notificationIds },
|
|
203
|
+
receiver,
|
|
204
|
+
};
|
|
205
|
+
const [numAffected] = await this.notificationReceiverState.update(conditions, { $set: { read: false } });
|
|
77
206
|
return numAffected;
|
|
78
207
|
}
|
|
79
208
|
}
|
package/lib/states/user.js
CHANGED
|
@@ -367,7 +367,14 @@ SELECT did,inviter,generation FROM UserTree`.trim();
|
|
|
367
367
|
|
|
368
368
|
// eslint-disable-next-line require-await
|
|
369
369
|
async getUsersByDids({ dids, query }) {
|
|
370
|
-
const {
|
|
370
|
+
const {
|
|
371
|
+
approved,
|
|
372
|
+
includeTags,
|
|
373
|
+
includePassports,
|
|
374
|
+
includeUserSessions,
|
|
375
|
+
enableConnectedAccounts = false,
|
|
376
|
+
selection = {},
|
|
377
|
+
} = query || {};
|
|
371
378
|
const condition = { did: dids };
|
|
372
379
|
if (isNullOrUndefined(approved) === false) {
|
|
373
380
|
condition.approved = !!approved;
|
|
@@ -392,8 +399,12 @@ SELECT did,inviter,generation FROM UserTree`.trim();
|
|
|
392
399
|
required: false,
|
|
393
400
|
});
|
|
394
401
|
}
|
|
402
|
+
if (enableConnectedAccounts) {
|
|
403
|
+
include.push(this.getConnectedInclude());
|
|
404
|
+
}
|
|
395
405
|
|
|
396
|
-
|
|
406
|
+
const result = await this.find({ where: condition, include }, selection);
|
|
407
|
+
return result;
|
|
397
408
|
}
|
|
398
409
|
|
|
399
410
|
// eslint-disable-next-line require-await
|
|
@@ -681,6 +692,14 @@ SELECT did,inviter,generation FROM UserTree`.trim();
|
|
|
681
692
|
return result;
|
|
682
693
|
}
|
|
683
694
|
|
|
695
|
+
getConnectedInclude() {
|
|
696
|
+
return {
|
|
697
|
+
model: this.models.ConnectedAccount,
|
|
698
|
+
as: 'connectedAccounts',
|
|
699
|
+
required: false,
|
|
700
|
+
};
|
|
701
|
+
}
|
|
702
|
+
|
|
684
703
|
async getPassports(did) {
|
|
685
704
|
const passports = await this.passport.find({ userDid: did });
|
|
686
705
|
return passports;
|
|
@@ -726,6 +745,34 @@ SELECT did,inviter,generation FROM UserTree`.trim();
|
|
|
726
745
|
}
|
|
727
746
|
return user;
|
|
728
747
|
}
|
|
748
|
+
|
|
749
|
+
/**
|
|
750
|
+
* 查询一个 Role 下的所有用户
|
|
751
|
+
* @returns
|
|
752
|
+
*/
|
|
753
|
+
async getUsersByRoles({ roles = [], enableConnectedAccounts = false, selection = {} }) {
|
|
754
|
+
if (!roles.length) {
|
|
755
|
+
return [];
|
|
756
|
+
}
|
|
757
|
+
const replacements = {
|
|
758
|
+
status: PASSPORT_STATUS.VALID,
|
|
759
|
+
roles,
|
|
760
|
+
};
|
|
761
|
+
const condition = {
|
|
762
|
+
approved: true,
|
|
763
|
+
did: {
|
|
764
|
+
[Op.in]: Sequelize.literal(
|
|
765
|
+
'(SELECT DISTINCT userDid FROM passports WHERE name IN (:roles) AND status = :status)'
|
|
766
|
+
),
|
|
767
|
+
},
|
|
768
|
+
};
|
|
769
|
+
const include = [];
|
|
770
|
+
if (enableConnectedAccounts) {
|
|
771
|
+
include.push(this.getConnectedInclude());
|
|
772
|
+
}
|
|
773
|
+
const result = await this.find({ where: condition, replacements, include }, selection);
|
|
774
|
+
return result;
|
|
775
|
+
}
|
|
729
776
|
}
|
|
730
777
|
|
|
731
778
|
module.exports = User;
|
package/lib/team/manager.js
CHANGED
|
@@ -38,6 +38,7 @@ const States = {
|
|
|
38
38
|
Project: require('../states/project'),
|
|
39
39
|
Release: require('../states/release'),
|
|
40
40
|
Notification: require('../states/notification'),
|
|
41
|
+
NotificationReceivers: require('../states/notification-receiver'),
|
|
41
42
|
VerifyCode: require('../states/verify-code'),
|
|
42
43
|
SecurityRule: SecurityRuleState,
|
|
43
44
|
AccessPolicy: AccessPolicyState,
|
|
@@ -54,6 +55,7 @@ const getDefaultTeamState = () => ({
|
|
|
54
55
|
project: null,
|
|
55
56
|
release: null,
|
|
56
57
|
notification: null,
|
|
58
|
+
notificationReceivers: null,
|
|
57
59
|
verifyCode: null,
|
|
58
60
|
securityRule: null,
|
|
59
61
|
accessPolicy: null,
|
|
@@ -115,6 +117,7 @@ class TeamManager extends EventEmitter {
|
|
|
115
117
|
connectedAccount: await this.createState(this.nodeDid, 'ConnectedAccount'),
|
|
116
118
|
session: await this.createState(this.nodeDid, 'Session'),
|
|
117
119
|
notification: await this.createState(this.nodeDid, 'Notification'),
|
|
120
|
+
NotificationReceivers: await this.createState(this.nodeDid, 'NotificationReceivers'),
|
|
118
121
|
verifyCode: await this.createState(this.nodeDid, 'VerifyCode'),
|
|
119
122
|
securityRule: await this.createState(this.nodeDid, 'SecurityRule'),
|
|
120
123
|
accessPolicy: await this.createState(this.nodeDid, 'AccessPolicy'),
|
|
@@ -146,19 +149,77 @@ class TeamManager extends EventEmitter {
|
|
|
146
149
|
return this.getState(teamDid, 'session');
|
|
147
150
|
}
|
|
148
151
|
|
|
149
|
-
|
|
150
|
-
|
|
152
|
+
async getNotificationState(teamDid) {
|
|
153
|
+
const state = await this.getState(teamDid, 'notification');
|
|
154
|
+
const receiverState = await this.getState(teamDid, 'notificationReceivers');
|
|
155
|
+
state.setNotificationReceiversState(receiverState);
|
|
156
|
+
return state;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
async getNotificationReceiverState(teamDid) {
|
|
160
|
+
const state = await this.getState(teamDid, 'notificationReceivers');
|
|
161
|
+
const notificationState = await this.getState(teamDid, 'notification');
|
|
162
|
+
state.setNotificationState(notificationState);
|
|
163
|
+
return state;
|
|
151
164
|
}
|
|
152
165
|
|
|
153
166
|
getVerifyCodeState(teamDid) {
|
|
154
167
|
return this.getState(teamDid, 'verifyCode');
|
|
155
168
|
}
|
|
156
169
|
|
|
170
|
+
async getNotificationReceivers(payload) {
|
|
171
|
+
const { teamDid, userDids = [], roles = [], selection = {}, enableConnectedAccounts = false } = payload;
|
|
172
|
+
// 会根据 teamDid 返回对应 state
|
|
173
|
+
const userState = await this.getUserState(teamDid);
|
|
174
|
+
if (!userDids.length && !roles.length) {
|
|
175
|
+
return [];
|
|
176
|
+
}
|
|
177
|
+
try {
|
|
178
|
+
// 这些用户信息已经是 approved 的用户,不需要再次确认
|
|
179
|
+
let users = [];
|
|
180
|
+
if (roles.length > 0) {
|
|
181
|
+
const roleUsers = await userState.getUsersByRoles({ roles, selection, enableConnectedAccounts });
|
|
182
|
+
users = users.concat(roleUsers);
|
|
183
|
+
}
|
|
184
|
+
if (userDids.length > 0) {
|
|
185
|
+
const queryUsers = await userState.getUsersByDids({
|
|
186
|
+
dids: userDids,
|
|
187
|
+
query: {
|
|
188
|
+
approved: true,
|
|
189
|
+
selection,
|
|
190
|
+
enableConnectedAccounts,
|
|
191
|
+
},
|
|
192
|
+
});
|
|
193
|
+
users = users.concat(queryUsers);
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
return users;
|
|
197
|
+
} catch (error) {
|
|
198
|
+
logger.error('get receivers failed: ', error);
|
|
199
|
+
return [];
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
|
|
157
203
|
async createNotification({ teamDid, receiver, ...payload }) {
|
|
158
|
-
const notification = await this.getState(teamDid, 'notification');
|
|
159
|
-
const
|
|
204
|
+
// const notification = await this.getState(teamDid, 'notification');
|
|
205
|
+
const notification = await this.getNotificationState(teamDid);
|
|
206
|
+
const doc = await notification.create({ ...payload, receiver, teamDid });
|
|
160
207
|
const metaDid = await this.states.blocklet.getBlockletMetaDid(teamDid);
|
|
161
|
-
|
|
208
|
+
if (!payload.ignoreBroadcast) {
|
|
209
|
+
// 是否需要广播到页面
|
|
210
|
+
this.emit(EVENTS.NOTIFICATION_BLOCKLET_CREATE, {
|
|
211
|
+
meta: { did: metaDid },
|
|
212
|
+
...payload,
|
|
213
|
+
...doc,
|
|
214
|
+
teamDid,
|
|
215
|
+
appInfo: {
|
|
216
|
+
did: teamDid,
|
|
217
|
+
},
|
|
218
|
+
receiver: doc?.receivers?.map((item) => item.receiver),
|
|
219
|
+
});
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
return doc;
|
|
162
223
|
}
|
|
163
224
|
|
|
164
225
|
async getProjectState(teamDid) {
|
package/lib/webhook/index.js
CHANGED
|
@@ -4,6 +4,8 @@ const checkURLAccessible = require('@abtnode/util/lib/url-evaluation/check-acces
|
|
|
4
4
|
const { EVENTS } = require('@abtnode/constant');
|
|
5
5
|
const isEmpty = require('lodash/isEmpty');
|
|
6
6
|
|
|
7
|
+
const { joinURL } = require('ufo');
|
|
8
|
+
const isUrl = require('is-url');
|
|
7
9
|
const WebHookSender = require('./sender');
|
|
8
10
|
const WalletSender = require('./sender/wallet');
|
|
9
11
|
const createQueue = require('../util/queue');
|
|
@@ -108,6 +110,24 @@ module.exports = ({ events, dataDirs, instance }) => {
|
|
|
108
110
|
serverUrls: baseUrls,
|
|
109
111
|
});
|
|
110
112
|
} else if (item.type === WalletSender.type && !isEmpty(extra?.wallet)) {
|
|
113
|
+
// 要将 logo 的 URL 拼接为完整的地址
|
|
114
|
+
const { attachments } = extra.wallet ?? {};
|
|
115
|
+
if (Array.isArray(attachments)) {
|
|
116
|
+
const newAttachments = attachments.map((attachment) => {
|
|
117
|
+
if (attachment.data.url && attachment.data.logo && !isUrl(attachment.data.log)) {
|
|
118
|
+
attachment.data.logo = joinURL(attachment.data.url, attachment.data.logo);
|
|
119
|
+
return attachment;
|
|
120
|
+
}
|
|
121
|
+
return attachment;
|
|
122
|
+
});
|
|
123
|
+
options = {
|
|
124
|
+
...options,
|
|
125
|
+
...{
|
|
126
|
+
...extra.wallet,
|
|
127
|
+
attachments: newAttachments,
|
|
128
|
+
},
|
|
129
|
+
};
|
|
130
|
+
}
|
|
111
131
|
options = { ...options, ...extra.wallet };
|
|
112
132
|
}
|
|
113
133
|
|
|
@@ -139,9 +159,22 @@ module.exports = ({ events, dataDirs, instance }) => {
|
|
|
139
159
|
|
|
140
160
|
[EVENTS.NOTIFICATION_CREATE, EVENTS.NOTIFICATION_BLOCKLET_CREATE].forEach((event) => {
|
|
141
161
|
events.on(event, (data) => {
|
|
142
|
-
const { title, description, severity, action, entityType, blockletUrl, entityId, extra, receiver } =
|
|
143
|
-
|
|
144
|
-
|
|
162
|
+
const { id, title, description, severity, action, entityType, blockletUrl, entityId, extra, receiver, appInfo } =
|
|
163
|
+
data;
|
|
164
|
+
if (!reduceQueue({ id, title, description, entityType, entityId, severity, extra })) {
|
|
165
|
+
queue.push({
|
|
166
|
+
title,
|
|
167
|
+
description,
|
|
168
|
+
status: severity,
|
|
169
|
+
action,
|
|
170
|
+
entityType,
|
|
171
|
+
blockletUrl,
|
|
172
|
+
extra,
|
|
173
|
+
receiver,
|
|
174
|
+
id,
|
|
175
|
+
appInfo,
|
|
176
|
+
teamDid: data.teamDid,
|
|
177
|
+
});
|
|
145
178
|
}
|
|
146
179
|
});
|
|
147
180
|
});
|
|
@@ -5,7 +5,7 @@ const BaseSender = require('../base');
|
|
|
5
5
|
|
|
6
6
|
class WalletSender extends BaseSender {
|
|
7
7
|
async send(params, data = {}) {
|
|
8
|
-
const { title, description, nodeInfo, node, receiver, actions, attachments } = data;
|
|
8
|
+
const { id, title, description, nodeInfo, node, receiver, actions, attachments, appInfo } = data;
|
|
9
9
|
|
|
10
10
|
try {
|
|
11
11
|
const sender = {
|
|
@@ -15,10 +15,12 @@ class WalletSender extends BaseSender {
|
|
|
15
15
|
};
|
|
16
16
|
|
|
17
17
|
const message = {
|
|
18
|
+
id,
|
|
18
19
|
title,
|
|
19
20
|
body: description,
|
|
20
21
|
actions,
|
|
21
22
|
attachments,
|
|
23
|
+
appInfo,
|
|
22
24
|
};
|
|
23
25
|
|
|
24
26
|
let to = [];
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"publishConfig": {
|
|
4
4
|
"access": "public"
|
|
5
5
|
},
|
|
6
|
-
"version": "1.16.
|
|
6
|
+
"version": "1.16.37-beta-20241224-013714-a79db7d3",
|
|
7
7
|
"description": "",
|
|
8
8
|
"main": "lib/index.js",
|
|
9
9
|
"files": [
|
|
@@ -19,19 +19,19 @@
|
|
|
19
19
|
"author": "wangshijun <wangshijun2010@gmail.com> (http://github.com/wangshijun)",
|
|
20
20
|
"license": "Apache-2.0",
|
|
21
21
|
"dependencies": {
|
|
22
|
-
"@abtnode/analytics": "1.16.
|
|
23
|
-
"@abtnode/auth": "1.16.
|
|
24
|
-
"@abtnode/certificate-manager": "1.16.
|
|
25
|
-
"@abtnode/constant": "1.16.
|
|
26
|
-
"@abtnode/cron": "1.16.
|
|
27
|
-
"@abtnode/logger": "1.16.
|
|
28
|
-
"@abtnode/models": "1.16.
|
|
29
|
-
"@abtnode/queue": "1.16.
|
|
30
|
-
"@abtnode/rbac": "1.16.
|
|
31
|
-
"@abtnode/router-provider": "1.16.
|
|
32
|
-
"@abtnode/static-server": "1.16.
|
|
33
|
-
"@abtnode/timemachine": "1.16.
|
|
34
|
-
"@abtnode/util": "1.16.
|
|
22
|
+
"@abtnode/analytics": "1.16.37-beta-20241224-013714-a79db7d3",
|
|
23
|
+
"@abtnode/auth": "1.16.37-beta-20241224-013714-a79db7d3",
|
|
24
|
+
"@abtnode/certificate-manager": "1.16.37-beta-20241224-013714-a79db7d3",
|
|
25
|
+
"@abtnode/constant": "1.16.37-beta-20241224-013714-a79db7d3",
|
|
26
|
+
"@abtnode/cron": "1.16.37-beta-20241224-013714-a79db7d3",
|
|
27
|
+
"@abtnode/logger": "1.16.37-beta-20241224-013714-a79db7d3",
|
|
28
|
+
"@abtnode/models": "1.16.37-beta-20241224-013714-a79db7d3",
|
|
29
|
+
"@abtnode/queue": "1.16.37-beta-20241224-013714-a79db7d3",
|
|
30
|
+
"@abtnode/rbac": "1.16.37-beta-20241224-013714-a79db7d3",
|
|
31
|
+
"@abtnode/router-provider": "1.16.37-beta-20241224-013714-a79db7d3",
|
|
32
|
+
"@abtnode/static-server": "1.16.37-beta-20241224-013714-a79db7d3",
|
|
33
|
+
"@abtnode/timemachine": "1.16.37-beta-20241224-013714-a79db7d3",
|
|
34
|
+
"@abtnode/util": "1.16.37-beta-20241224-013714-a79db7d3",
|
|
35
35
|
"@arcblock/did": "1.18.162",
|
|
36
36
|
"@arcblock/did-auth": "1.18.162",
|
|
37
37
|
"@arcblock/did-ext": "^1.18.162",
|
|
@@ -42,13 +42,13 @@
|
|
|
42
42
|
"@arcblock/pm2-events": "^0.0.5",
|
|
43
43
|
"@arcblock/validator": "^1.18.162",
|
|
44
44
|
"@arcblock/vc": "1.18.162",
|
|
45
|
-
"@blocklet/constant": "1.16.
|
|
46
|
-
"@blocklet/did-space-js": "^0.
|
|
47
|
-
"@blocklet/env": "1.16.
|
|
48
|
-
"@blocklet/meta": "1.16.
|
|
49
|
-
"@blocklet/resolver": "1.16.
|
|
50
|
-
"@blocklet/sdk": "1.16.
|
|
51
|
-
"@blocklet/store": "1.16.
|
|
45
|
+
"@blocklet/constant": "1.16.37-beta-20241224-013714-a79db7d3",
|
|
46
|
+
"@blocklet/did-space-js": "^0.6.0",
|
|
47
|
+
"@blocklet/env": "1.16.37-beta-20241224-013714-a79db7d3",
|
|
48
|
+
"@blocklet/meta": "1.16.37-beta-20241224-013714-a79db7d3",
|
|
49
|
+
"@blocklet/resolver": "1.16.37-beta-20241224-013714-a79db7d3",
|
|
50
|
+
"@blocklet/sdk": "1.16.37-beta-20241224-013714-a79db7d3",
|
|
51
|
+
"@blocklet/store": "1.16.37-beta-20241224-013714-a79db7d3",
|
|
52
52
|
"@fidm/x509": "^1.2.1",
|
|
53
53
|
"@ocap/mcrypto": "1.18.162",
|
|
54
54
|
"@ocap/util": "1.18.162",
|
|
@@ -108,5 +108,5 @@
|
|
|
108
108
|
"jest": "^29.7.0",
|
|
109
109
|
"unzipper": "^0.10.11"
|
|
110
110
|
},
|
|
111
|
-
"gitHead": "
|
|
111
|
+
"gitHead": "040363d1ac077f7d4b4ee29e6c3bfc3e61c3ce3f"
|
|
112
112
|
}
|