@hed-hog/core 0.0.300 → 0.0.302
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/dist/ai/ai.service.d.ts +13 -2
- package/dist/ai/ai.service.d.ts.map +1 -1
- package/dist/ai/ai.service.js +104 -2
- package/dist/ai/ai.service.js.map +1 -1
- package/dist/dashboard/dashboard-core/dashboard-core.controller.d.ts +26 -9
- package/dist/dashboard/dashboard-core/dashboard-core.controller.d.ts.map +1 -1
- package/dist/dashboard/dashboard-core/dashboard-core.controller.js +11 -5
- package/dist/dashboard/dashboard-core/dashboard-core.controller.js.map +1 -1
- package/dist/dashboard/dashboard-core/dashboard-core.service.d.ts +34 -10
- package/dist/dashboard/dashboard-core/dashboard-core.service.d.ts.map +1 -1
- package/dist/dashboard/dashboard-core/dashboard-core.service.js +196 -69
- package/dist/dashboard/dashboard-core/dashboard-core.service.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/integration/services/integration-link.service.d.ts +5 -1
- package/dist/integration/services/integration-link.service.d.ts.map +1 -1
- package/dist/integration/services/integration-link.service.js +141 -53
- package/dist/integration/services/integration-link.service.js.map +1 -1
- package/dist/mail/mail.service.d.ts +9 -2
- package/dist/mail/mail.service.d.ts.map +1 -1
- package/dist/mail/mail.service.js +56 -4
- package/dist/mail/mail.service.js.map +1 -1
- package/dist/setting/setting.service.d.ts +6 -1
- package/dist/setting/setting.service.d.ts.map +1 -1
- package/dist/setting/setting.service.js +188 -15
- package/dist/setting/setting.service.js.map +1 -1
- package/hedhog/data/setting_group.yaml +28 -0
- package/hedhog/frontend/app/dashboard/dashboard-home-tabs.tsx.ejs +305 -75
- package/hedhog/frontend/messages/en.json +15 -3
- package/hedhog/frontend/messages/pt.json +15 -3
- package/package.json +5 -5
- package/src/ai/ai.service.ts +129 -1
- package/src/dashboard/dashboard-core/dashboard-core.controller.ts +9 -2
- package/src/dashboard/dashboard-core/dashboard-core.service.ts +276 -75
- package/src/index.ts +7 -6
- package/src/integration/services/integration-link.service.ts +190 -55
- package/src/mail/mail.service.ts +67 -3
- package/src/setting/setting.service.ts +222 -15
|
@@ -487,6 +487,61 @@ let DashboardCoreService = DashboardCoreService_1 = class DashboardCoreService {
|
|
|
487
487
|
});
|
|
488
488
|
return roleUsers.map((roleUser) => roleUser.role_id);
|
|
489
489
|
}
|
|
490
|
+
async getDashboardComponentRoleRequirements(dashboardId) {
|
|
491
|
+
const dashboardItems = await this.prismaService.dashboard_item.findMany({
|
|
492
|
+
where: {
|
|
493
|
+
dashboard_id: dashboardId,
|
|
494
|
+
},
|
|
495
|
+
select: {
|
|
496
|
+
component_id: true,
|
|
497
|
+
dashboard_component: {
|
|
498
|
+
select: {
|
|
499
|
+
dashboard_component_role: {
|
|
500
|
+
select: {
|
|
501
|
+
role_id: true,
|
|
502
|
+
},
|
|
503
|
+
},
|
|
504
|
+
},
|
|
505
|
+
},
|
|
506
|
+
},
|
|
507
|
+
});
|
|
508
|
+
const uniqueByComponentId = new Map();
|
|
509
|
+
for (const item of dashboardItems) {
|
|
510
|
+
if (uniqueByComponentId.has(item.component_id)) {
|
|
511
|
+
continue;
|
|
512
|
+
}
|
|
513
|
+
uniqueByComponentId.set(item.component_id, item.dashboard_component.dashboard_component_role.map((relation) => relation.role_id));
|
|
514
|
+
}
|
|
515
|
+
return Array.from(uniqueByComponentId.values());
|
|
516
|
+
}
|
|
517
|
+
userHasRequiredRolesForDashboard(componentRoleRequirements, userRoleIds) {
|
|
518
|
+
if (componentRoleRequirements.length === 0) {
|
|
519
|
+
return true;
|
|
520
|
+
}
|
|
521
|
+
if (userRoleIds.length === 0) {
|
|
522
|
+
return componentRoleRequirements.every((requiredRoles) => requiredRoles.length === 0);
|
|
523
|
+
}
|
|
524
|
+
const userRoleIdSet = new Set(userRoleIds);
|
|
525
|
+
return componentRoleRequirements.every((requiredRoles) => requiredRoles.length === 0 ||
|
|
526
|
+
requiredRoles.some((roleId) => userRoleIdSet.has(roleId)));
|
|
527
|
+
}
|
|
528
|
+
async getDashboardRoleAccessState(dashboardId, userId) {
|
|
529
|
+
const [componentRoleRequirements, userRoleIds] = await Promise.all([
|
|
530
|
+
this.getDashboardComponentRoleRequirements(dashboardId),
|
|
531
|
+
this.getUserRoleIds(userId),
|
|
532
|
+
]);
|
|
533
|
+
const hasRequiredRoles = this.userHasRequiredRolesForDashboard(componentRoleRequirements, userRoleIds);
|
|
534
|
+
return {
|
|
535
|
+
hasRequiredRoles,
|
|
536
|
+
accessStatus: hasRequiredRoles ? 'allowed' : 'missing-roles',
|
|
537
|
+
};
|
|
538
|
+
}
|
|
539
|
+
async assertDashboardRoleAccess(dashboardId, userId) {
|
|
540
|
+
const { hasRequiredRoles } = await this.getDashboardRoleAccessState(dashboardId, userId);
|
|
541
|
+
if (!hasRequiredRoles) {
|
|
542
|
+
throw new common_1.ForbiddenException('Access denied to this dashboard');
|
|
543
|
+
}
|
|
544
|
+
}
|
|
490
545
|
async getAccessibleTemplateOrThrow(userId, templateSlug, locale) {
|
|
491
546
|
const userRoleIds = await this.getUserRoleIds(userId);
|
|
492
547
|
const templateAccessFilter = userRoleIds.length > 0
|
|
@@ -821,6 +876,7 @@ let DashboardCoreService = DashboardCoreService_1 = class DashboardCoreService {
|
|
|
821
876
|
if (!canAccess) {
|
|
822
877
|
return [];
|
|
823
878
|
}
|
|
879
|
+
await this.assertDashboardRoleAccess(dashboard.id, userId);
|
|
824
880
|
const dashboardItems = await this.prismaService.dashboard_item.findMany({
|
|
825
881
|
where: {
|
|
826
882
|
dashboard_id: dashboard.id,
|
|
@@ -880,6 +936,7 @@ let DashboardCoreService = DashboardCoreService_1 = class DashboardCoreService {
|
|
|
880
936
|
if (!canAccess) {
|
|
881
937
|
throw new common_1.ForbiddenException('Access denied to this dashboard');
|
|
882
938
|
}
|
|
939
|
+
await this.assertDashboardRoleAccess(dashboard.id, userId);
|
|
883
940
|
const layoutUpdates = layout.flatMap((item) => {
|
|
884
941
|
const itemId = Number.parseInt(item.i.replace('widget-', ''), 10);
|
|
885
942
|
if (Number.isNaN(itemId)) {
|
|
@@ -924,6 +981,7 @@ let DashboardCoreService = DashboardCoreService_1 = class DashboardCoreService {
|
|
|
924
981
|
if (!canAccess) {
|
|
925
982
|
throw new common_1.ForbiddenException('Access denied to this dashboard');
|
|
926
983
|
}
|
|
984
|
+
await this.assertDashboardRoleAccess(dashboard.id, userId);
|
|
927
985
|
const userRoles = await this.prismaService.role_user.findMany({
|
|
928
986
|
where: { user_id: userId },
|
|
929
987
|
select: { role_id: true },
|
|
@@ -1039,6 +1097,7 @@ let DashboardCoreService = DashboardCoreService_1 = class DashboardCoreService {
|
|
|
1039
1097
|
if (!canAccess) {
|
|
1040
1098
|
throw new common_1.ForbiddenException('Access denied to this dashboard');
|
|
1041
1099
|
}
|
|
1100
|
+
await this.assertDashboardRoleAccess(dashboard.id, userId);
|
|
1042
1101
|
const parsedWidgetId = Number(widgetId.replace(/^widget-/, ''));
|
|
1043
1102
|
if (!Number.isInteger(parsedWidgetId) || parsedWidgetId <= 0) {
|
|
1044
1103
|
throw new common_1.BadRequestException('Invalid widget id');
|
|
@@ -1087,9 +1146,18 @@ let DashboardCoreService = DashboardCoreService_1 = class DashboardCoreService {
|
|
|
1087
1146
|
user_id: userId,
|
|
1088
1147
|
},
|
|
1089
1148
|
});
|
|
1090
|
-
|
|
1149
|
+
if (!dashboardUser) {
|
|
1150
|
+
return {
|
|
1151
|
+
hasAccess: false,
|
|
1152
|
+
accessStatus: 'not-shared',
|
|
1153
|
+
dashboard: null,
|
|
1154
|
+
};
|
|
1155
|
+
}
|
|
1156
|
+
const roleAccess = await this.getDashboardRoleAccessState(dashboard.id, userId);
|
|
1157
|
+
const hasAccess = roleAccess.hasRequiredRoles;
|
|
1091
1158
|
return {
|
|
1092
1159
|
hasAccess,
|
|
1160
|
+
accessStatus: roleAccess.accessStatus,
|
|
1093
1161
|
dashboard: hasAccess
|
|
1094
1162
|
? {
|
|
1095
1163
|
id: dashboard.id,
|
|
@@ -1337,6 +1405,7 @@ let DashboardCoreService = DashboardCoreService_1 = class DashboardCoreService {
|
|
|
1337
1405
|
}
|
|
1338
1406
|
async getDashboardShares(userId, slug, locale) {
|
|
1339
1407
|
const dashboardUser = await this.getDashboardUserOrThrow(userId, slug, locale);
|
|
1408
|
+
const dashboardRoleRequirements = await this.getDashboardComponentRoleRequirements(dashboardUser.dashboard_id);
|
|
1340
1409
|
const sharedUsers = await this.prismaService.dashboard_user.findMany({
|
|
1341
1410
|
where: {
|
|
1342
1411
|
dashboard_id: dashboardUser.dashboard_id,
|
|
@@ -1346,6 +1415,11 @@ let DashboardCoreService = DashboardCoreService_1 = class DashboardCoreService {
|
|
|
1346
1415
|
select: {
|
|
1347
1416
|
id: true,
|
|
1348
1417
|
name: true,
|
|
1418
|
+
role_user: {
|
|
1419
|
+
select: {
|
|
1420
|
+
role_id: true,
|
|
1421
|
+
},
|
|
1422
|
+
},
|
|
1349
1423
|
user_identifier: {
|
|
1350
1424
|
where: {
|
|
1351
1425
|
type: 'email',
|
|
@@ -1364,55 +1438,78 @@ let DashboardCoreService = DashboardCoreService_1 = class DashboardCoreService {
|
|
|
1364
1438
|
});
|
|
1365
1439
|
return sharedUsers.map((sharedDashboardUser) => {
|
|
1366
1440
|
var _a, _b;
|
|
1367
|
-
|
|
1441
|
+
const userRoleIds = sharedDashboardUser.user.role_user.map((roleUser) => roleUser.role_id);
|
|
1442
|
+
const hasRequiredRoles = this.userHasRequiredRolesForDashboard(dashboardRoleRequirements, userRoleIds);
|
|
1443
|
+
return {
|
|
1368
1444
|
id: sharedDashboardUser.user.id,
|
|
1369
1445
|
name: sharedDashboardUser.user.name,
|
|
1370
1446
|
email: (_b = (_a = sharedDashboardUser.user.user_identifier[0]) === null || _a === void 0 ? void 0 : _a.value) !== null && _b !== void 0 ? _b : null,
|
|
1371
1447
|
isCurrentUser: sharedDashboardUser.user.id === userId,
|
|
1372
1448
|
isHome: sharedDashboardUser.is_home,
|
|
1373
|
-
|
|
1449
|
+
hasRequiredRoles,
|
|
1450
|
+
accessStatus: hasRequiredRoles ? 'allowed' : 'missing-roles',
|
|
1451
|
+
};
|
|
1374
1452
|
});
|
|
1375
1453
|
}
|
|
1376
|
-
async getShareableUsers(userId, slug,
|
|
1454
|
+
async getShareableUsers(userId, slug, options, locale) {
|
|
1455
|
+
var _a, _b;
|
|
1377
1456
|
const dashboardUser = await this.getDashboardUserOrThrow(userId, slug, locale);
|
|
1378
|
-
const normalizedSearch = this.toNullableString(search);
|
|
1379
|
-
const
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1457
|
+
const normalizedSearch = this.toNullableString(options === null || options === void 0 ? void 0 : options.search);
|
|
1458
|
+
const requestedPage = Number.parseInt(String((_a = options === null || options === void 0 ? void 0 : options.page) !== null && _a !== void 0 ? _a : '1'), 10);
|
|
1459
|
+
const requestedPageSize = Number.parseInt(String((_b = options === null || options === void 0 ? void 0 : options.pageSize) !== null && _b !== void 0 ? _b : '10'), 10);
|
|
1460
|
+
const page = Number.isFinite(requestedPage) && requestedPage > 0 ? requestedPage : 1;
|
|
1461
|
+
const pageSize = Number.isFinite(requestedPageSize) && requestedPageSize > 0
|
|
1462
|
+
? Math.min(requestedPageSize, 50)
|
|
1463
|
+
: 10;
|
|
1464
|
+
const [existingUsers, dashboardRoleRequirements] = await Promise.all([
|
|
1465
|
+
this.prismaService.dashboard_user.findMany({
|
|
1466
|
+
where: {
|
|
1467
|
+
dashboard_id: dashboardUser.dashboard_id,
|
|
1468
|
+
},
|
|
1469
|
+
select: {
|
|
1470
|
+
user_id: true,
|
|
1471
|
+
},
|
|
1472
|
+
}),
|
|
1473
|
+
this.getDashboardComponentRoleRequirements(dashboardUser.dashboard_id),
|
|
1474
|
+
]);
|
|
1475
|
+
const where = Object.assign({ id: {
|
|
1476
|
+
notIn: existingUsers.map((item) => item.user_id),
|
|
1477
|
+
} }, (normalizedSearch
|
|
1478
|
+
? {
|
|
1479
|
+
OR: [
|
|
1480
|
+
{
|
|
1481
|
+
name: {
|
|
1482
|
+
contains: normalizedSearch,
|
|
1483
|
+
mode: 'insensitive',
|
|
1398
1484
|
},
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1485
|
+
},
|
|
1486
|
+
{
|
|
1487
|
+
user_identifier: {
|
|
1488
|
+
some: {
|
|
1489
|
+
type: 'email',
|
|
1490
|
+
value: {
|
|
1491
|
+
contains: normalizedSearch,
|
|
1492
|
+
mode: 'insensitive',
|
|
1407
1493
|
},
|
|
1408
1494
|
},
|
|
1409
1495
|
},
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1496
|
+
},
|
|
1497
|
+
],
|
|
1498
|
+
}
|
|
1499
|
+
: {}));
|
|
1500
|
+
const total = await this.prismaService.user.count({ where });
|
|
1501
|
+
const lastPage = total > 0 ? Math.ceil(total / pageSize) : 1;
|
|
1502
|
+
const safePage = Math.min(page, lastPage);
|
|
1503
|
+
const users = await this.prismaService.user.findMany({
|
|
1504
|
+
where,
|
|
1413
1505
|
select: {
|
|
1414
1506
|
id: true,
|
|
1415
1507
|
name: true,
|
|
1508
|
+
role_user: {
|
|
1509
|
+
select: {
|
|
1510
|
+
role_id: true,
|
|
1511
|
+
},
|
|
1512
|
+
},
|
|
1416
1513
|
user_identifier: {
|
|
1417
1514
|
where: {
|
|
1418
1515
|
type: 'email',
|
|
@@ -1423,57 +1520,87 @@ let DashboardCoreService = DashboardCoreService_1 = class DashboardCoreService {
|
|
|
1423
1520
|
take: 1,
|
|
1424
1521
|
},
|
|
1425
1522
|
},
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
},
|
|
1430
|
-
});
|
|
1431
|
-
return users.map((candidateUser) => {
|
|
1432
|
-
var _a, _b;
|
|
1433
|
-
return ({
|
|
1434
|
-
id: candidateUser.id,
|
|
1435
|
-
name: candidateUser.name,
|
|
1436
|
-
email: (_b = (_a = candidateUser.user_identifier[0]) === null || _a === void 0 ? void 0 : _a.value) !== null && _b !== void 0 ? _b : null,
|
|
1437
|
-
});
|
|
1523
|
+
skip: (safePage - 1) * pageSize,
|
|
1524
|
+
take: pageSize,
|
|
1525
|
+
orderBy: [{ name: 'asc' }, { id: 'asc' }],
|
|
1438
1526
|
});
|
|
1527
|
+
return {
|
|
1528
|
+
data: users.map((candidateUser) => {
|
|
1529
|
+
var _a, _b;
|
|
1530
|
+
const userRoleIds = candidateUser.role_user.map((roleUser) => roleUser.role_id);
|
|
1531
|
+
const hasRequiredRoles = this.userHasRequiredRolesForDashboard(dashboardRoleRequirements, userRoleIds);
|
|
1532
|
+
return {
|
|
1533
|
+
id: candidateUser.id,
|
|
1534
|
+
name: candidateUser.name,
|
|
1535
|
+
email: (_b = (_a = candidateUser.user_identifier[0]) === null || _a === void 0 ? void 0 : _a.value) !== null && _b !== void 0 ? _b : null,
|
|
1536
|
+
hasRequiredRoles,
|
|
1537
|
+
accessStatus: hasRequiredRoles ? 'allowed' : 'missing-roles',
|
|
1538
|
+
};
|
|
1539
|
+
}),
|
|
1540
|
+
total,
|
|
1541
|
+
page: safePage,
|
|
1542
|
+
pageSize,
|
|
1543
|
+
lastPage,
|
|
1544
|
+
prev: safePage > 1 ? safePage - 1 : null,
|
|
1545
|
+
next: safePage < lastPage ? safePage + 1 : null,
|
|
1546
|
+
};
|
|
1439
1547
|
}
|
|
1440
|
-
async shareDashboard(userId, slug, sharedUserId, locale) {
|
|
1441
|
-
|
|
1548
|
+
async shareDashboard(userId, slug, sharedUserIds, sharedUserId, locale) {
|
|
1549
|
+
const requestedIds = Array.from(new Set([
|
|
1550
|
+
...(Array.isArray(sharedUserIds) ? sharedUserIds : []),
|
|
1551
|
+
...(sharedUserId !== undefined ? [sharedUserId] : []),
|
|
1552
|
+
]
|
|
1553
|
+
.map((value) => Number(value))
|
|
1554
|
+
.filter((value) => Number.isInteger(value) && value > 0)));
|
|
1555
|
+
if (requestedIds.length === 0) {
|
|
1442
1556
|
throw new common_1.BadRequestException((0, api_locale_1.getLocaleText)('validation.fieldRequired', locale, 'User is required.'));
|
|
1443
1557
|
}
|
|
1444
1558
|
const dashboardUser = await this.getDashboardUserOrThrow(userId, slug, locale);
|
|
1445
|
-
|
|
1559
|
+
const sanitizedUserIds = requestedIds.filter((candidateUserId) => candidateUserId !== userId);
|
|
1560
|
+
if (sanitizedUserIds.length === 0) {
|
|
1446
1561
|
throw new common_1.BadRequestException((0, api_locale_1.getLocaleText)('validation.invalidValue', locale, 'You already have access to this dashboard.'));
|
|
1447
1562
|
}
|
|
1448
|
-
const
|
|
1449
|
-
where: {
|
|
1450
|
-
|
|
1563
|
+
const targetUsers = await this.prismaService.user.findMany({
|
|
1564
|
+
where: {
|
|
1565
|
+
id: {
|
|
1566
|
+
in: sanitizedUserIds,
|
|
1567
|
+
},
|
|
1568
|
+
},
|
|
1569
|
+
select: {
|
|
1570
|
+
id: true,
|
|
1571
|
+
},
|
|
1451
1572
|
});
|
|
1452
|
-
if (
|
|
1573
|
+
if (targetUsers.length !== sanitizedUserIds.length) {
|
|
1453
1574
|
throw new common_1.BadRequestException((0, api_locale_1.getLocaleText)('userNotFound', locale, 'User not found.'));
|
|
1454
1575
|
}
|
|
1455
|
-
const
|
|
1576
|
+
const existingShares = await this.prismaService.dashboard_user.findMany({
|
|
1456
1577
|
where: {
|
|
1457
1578
|
dashboard_id: dashboardUser.dashboard_id,
|
|
1458
|
-
user_id:
|
|
1579
|
+
user_id: {
|
|
1580
|
+
in: sanitizedUserIds,
|
|
1581
|
+
},
|
|
1459
1582
|
},
|
|
1460
|
-
select: {
|
|
1461
|
-
|
|
1462
|
-
if (existingShare) {
|
|
1463
|
-
return {
|
|
1464
|
-
success: true,
|
|
1465
|
-
alreadyShared: true,
|
|
1466
|
-
};
|
|
1467
|
-
}
|
|
1468
|
-
await this.prismaService.dashboard_user.create({
|
|
1469
|
-
data: {
|
|
1470
|
-
dashboard_id: dashboardUser.dashboard_id,
|
|
1471
|
-
user_id: sharedUserId,
|
|
1472
|
-
is_home: false,
|
|
1583
|
+
select: {
|
|
1584
|
+
user_id: true,
|
|
1473
1585
|
},
|
|
1474
1586
|
});
|
|
1587
|
+
const alreadySharedUserIds = existingShares.map((item) => item.user_id);
|
|
1588
|
+
const alreadySharedSet = new Set(alreadySharedUserIds);
|
|
1589
|
+
const newUserIds = sanitizedUserIds.filter((candidateUserId) => !alreadySharedSet.has(candidateUserId));
|
|
1590
|
+
if (newUserIds.length > 0) {
|
|
1591
|
+
await this.prismaService.dashboard_user.createMany({
|
|
1592
|
+
data: newUserIds.map((candidateUserId) => ({
|
|
1593
|
+
dashboard_id: dashboardUser.dashboard_id,
|
|
1594
|
+
user_id: candidateUserId,
|
|
1595
|
+
is_home: false,
|
|
1596
|
+
})),
|
|
1597
|
+
});
|
|
1598
|
+
}
|
|
1475
1599
|
return {
|
|
1476
1600
|
success: true,
|
|
1601
|
+
sharedCount: newUserIds.length,
|
|
1602
|
+
sharedUserIds: newUserIds,
|
|
1603
|
+
alreadySharedUserIds,
|
|
1477
1604
|
};
|
|
1478
1605
|
}
|
|
1479
1606
|
async revokeDashboardShare(userId, slug, sharedUserId, locale) {
|