@hed-hog/core 0.0.299 → 0.0.301
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/dashboard.controller.d.ts +6 -0
- package/dist/dashboard/dashboard/dashboard.controller.d.ts.map +1 -1
- package/dist/dashboard/dashboard/dashboard.service.d.ts +6 -0
- package/dist/dashboard/dashboard/dashboard.service.d.ts.map +1 -1
- package/dist/dashboard/dashboard-component/dashboard-component.controller.d.ts +2 -1
- package/dist/dashboard/dashboard-component/dashboard-component.controller.d.ts.map +1 -1
- package/dist/dashboard/dashboard-component/dashboard-component.controller.js +6 -3
- package/dist/dashboard/dashboard-component/dashboard-component.controller.js.map +1 -1
- package/dist/dashboard/dashboard-component/dashboard-component.service.d.ts +7 -1
- package/dist/dashboard/dashboard-component/dashboard-component.service.d.ts.map +1 -1
- package/dist/dashboard/dashboard-component/dashboard-component.service.js +76 -33
- package/dist/dashboard/dashboard-component/dashboard-component.service.js.map +1 -1
- package/dist/dashboard/dashboard-core/dashboard-core.controller.d.ts +82 -0
- package/dist/dashboard/dashboard-core/dashboard-core.controller.d.ts.map +1 -1
- package/dist/dashboard/dashboard-core/dashboard-core.controller.js +117 -0
- package/dist/dashboard/dashboard-core/dashboard-core.controller.js.map +1 -1
- package/dist/dashboard/dashboard-core/dashboard-core.service.d.ts +93 -0
- package/dist/dashboard/dashboard-core/dashboard-core.service.d.ts.map +1 -1
- package/dist/dashboard/dashboard-core/dashboard-core.service.js +654 -20
- package/dist/dashboard/dashboard-core/dashboard-core.service.js.map +1 -1
- package/dist/dashboard/dashboard-item/dashboard-item.controller.d.ts +2 -0
- package/dist/dashboard/dashboard-item/dashboard-item.controller.d.ts.map +1 -1
- package/dist/dashboard/dashboard-item/dashboard-item.service.d.ts +2 -0
- package/dist/dashboard/dashboard-item/dashboard-item.service.d.ts.map +1 -1
- package/dist/dashboard/dashboard-role/dashboard-role.controller.d.ts +2 -0
- package/dist/dashboard/dashboard-role/dashboard-role.controller.d.ts.map +1 -1
- package/dist/dashboard/dashboard-role/dashboard-role.service.d.ts +2 -0
- package/dist/dashboard/dashboard-role/dashboard-role.service.d.ts.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/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/dashboard.yaml +12 -6
- package/hedhog/data/dashboard_component_role.yaml +66 -0
- package/hedhog/data/dashboard_role.yaml +2 -8
- package/hedhog/data/route.yaml +72 -0
- package/hedhog/data/setting_group.yaml +28 -0
- package/hedhog/frontend/app/dashboard/[slug]/dashboard-content.tsx.ejs +333 -128
- package/hedhog/frontend/app/dashboard/[slug]/widget-renderer.tsx.ejs +277 -53
- package/hedhog/frontend/app/dashboard/components/add-widget-selector-dialog.tsx.ejs +179 -231
- package/hedhog/frontend/app/dashboard/components/draggable-grid.tsx.ejs +64 -18
- package/hedhog/frontend/app/dashboard/dashboard-home-tabs.tsx.ejs +1619 -0
- package/hedhog/frontend/app/dashboard/dashboard.css.ejs +37 -0
- package/hedhog/frontend/app/dashboard/management/page.tsx.ejs +1 -1
- package/hedhog/frontend/app/dashboard/management/tabs/components-tab.tsx.ejs +6 -6
- package/hedhog/frontend/app/dashboard/management/tabs/dashboards-tab.tsx.ejs +8 -8
- package/hedhog/frontend/app/dashboard/management/tabs/items-tab.tsx.ejs +3 -3
- package/hedhog/frontend/app/dashboard/page.tsx.ejs +3 -25
- package/hedhog/frontend/messages/en.json +124 -2
- package/hedhog/frontend/messages/pt.json +123 -1
- package/hedhog/frontend/widgets/account-security.tsx.ejs +1 -1
- package/hedhog/frontend/widgets/active-users-card.tsx.ejs +2 -2
- package/hedhog/frontend/widgets/activity-timeline.tsx.ejs +1 -1
- package/hedhog/frontend/widgets/email-notifications.tsx.ejs +1 -1
- package/hedhog/frontend/widgets/locale-config.tsx.ejs +1 -1
- package/hedhog/frontend/widgets/login-history-chart.tsx.ejs +1 -1
- package/hedhog/frontend/widgets/mail-config.tsx.ejs +1 -1
- package/hedhog/frontend/widgets/mail-sent-card.tsx.ejs +2 -2
- package/hedhog/frontend/widgets/mail-sent-chart.tsx.ejs +1 -1
- package/hedhog/frontend/widgets/menus-card.tsx.ejs +2 -2
- package/hedhog/frontend/widgets/oauth-config.tsx.ejs +1 -1
- package/hedhog/frontend/widgets/permissions-card.tsx.ejs +2 -2
- package/hedhog/frontend/widgets/permissions-chart.tsx.ejs +1 -1
- package/hedhog/frontend/widgets/profile-card.tsx.ejs +1 -1
- package/hedhog/frontend/widgets/routes-card.tsx.ejs +2 -2
- package/hedhog/frontend/widgets/session-activity-chart.tsx.ejs +1 -1
- package/hedhog/frontend/widgets/sessions-today-card.tsx.ejs +2 -2
- package/hedhog/frontend/widgets/stat-access-level.tsx.ejs +1 -1
- package/hedhog/frontend/widgets/stat-actions-today.tsx.ejs +1 -1
- package/hedhog/frontend/widgets/stat-consecutive-days.tsx.ejs +1 -1
- package/hedhog/frontend/widgets/stat-online-time.tsx.ejs +1 -1
- package/hedhog/frontend/widgets/storage-config.tsx.ejs +1 -1
- package/hedhog/frontend/widgets/theme-config.tsx.ejs +1 -1
- package/hedhog/frontend/widgets/user-growth-chart.tsx.ejs +1 -1
- package/hedhog/frontend/widgets/user-roles.tsx.ejs +1 -1
- package/hedhog/frontend/widgets/user-sessions.tsx.ejs +1 -1
- package/hedhog/table/dashboard.yaml +6 -0
- package/package.json +3 -3
- package/src/ai/ai.service.ts +129 -1
- package/src/dashboard/dashboard-component/dashboard-component.controller.ts +15 -2
- package/src/dashboard/dashboard-component/dashboard-component.service.ts +107 -43
- package/src/dashboard/dashboard-core/dashboard-core.controller.ts +119 -1
- package/src/dashboard/dashboard-core/dashboard-core.service.ts +876 -20
- package/src/index.ts +7 -6
- package/src/mail/mail.service.ts +67 -3
- package/src/setting/setting.service.ts +222 -15
- package/hedhog/frontend/app/dashboard/components/widgets/core..gitkeep.ejs +0 -11
- package/hedhog/frontend/app/dashboard/components/widgets/core.account-security.tsx.ejs +0 -192
- package/hedhog/frontend/app/dashboard/components/widgets/core.active-users-card.tsx.ejs +0 -58
- package/hedhog/frontend/app/dashboard/components/widgets/core.activity-timeline.tsx.ejs +0 -223
- package/hedhog/frontend/app/dashboard/components/widgets/core.email-notifications.tsx.ejs +0 -226
- package/hedhog/frontend/app/dashboard/components/widgets/core.locale-config.tsx.ejs +0 -168
- package/hedhog/frontend/app/dashboard/components/widgets/core.login-history-chart.tsx.ejs +0 -115
- package/hedhog/frontend/app/dashboard/components/widgets/core.mail-config.tsx.ejs +0 -199
- package/hedhog/frontend/app/dashboard/components/widgets/core.mail-sent-card.tsx.ejs +0 -58
- package/hedhog/frontend/app/dashboard/components/widgets/core.mail-sent-chart.tsx.ejs +0 -149
- package/hedhog/frontend/app/dashboard/components/widgets/core.menus-card.tsx.ejs +0 -58
- package/hedhog/frontend/app/dashboard/components/widgets/core.oauth-config.tsx.ejs +0 -175
- package/hedhog/frontend/app/dashboard/components/widgets/core.permissions-card.tsx.ejs +0 -61
- package/hedhog/frontend/app/dashboard/components/widgets/core.permissions-chart.tsx.ejs +0 -156
- package/hedhog/frontend/app/dashboard/components/widgets/core.profile-card.tsx.ejs +0 -186
- package/hedhog/frontend/app/dashboard/components/widgets/core.routes-card.tsx.ejs +0 -58
- package/hedhog/frontend/app/dashboard/components/widgets/core.session-activity-chart.tsx.ejs +0 -183
- package/hedhog/frontend/app/dashboard/components/widgets/core.sessions-today-card.tsx.ejs +0 -62
- package/hedhog/frontend/app/dashboard/components/widgets/core.stat-access-level.tsx.ejs +0 -57
- package/hedhog/frontend/app/dashboard/components/widgets/core.stat-actions-today.tsx.ejs +0 -57
- package/hedhog/frontend/app/dashboard/components/widgets/core.stat-consecutive-days.tsx.ejs +0 -57
- package/hedhog/frontend/app/dashboard/components/widgets/core.stat-online-time.tsx.ejs +0 -57
- package/hedhog/frontend/app/dashboard/components/widgets/core.storage-config.tsx.ejs +0 -196
- package/hedhog/frontend/app/dashboard/components/widgets/core.theme-config.tsx.ejs +0 -213
- package/hedhog/frontend/app/dashboard/components/widgets/core.user-growth-chart.tsx.ejs +0 -210
- package/hedhog/frontend/app/dashboard/components/widgets/core.user-roles.tsx.ejs +0 -132
- package/hedhog/frontend/app/dashboard/components/widgets/core.user-sessions.tsx.ejs +0 -236
- package/hedhog/frontend/app/dashboard/components/widgets/finance.alerts.tsx.ejs +0 -108
- package/hedhog/frontend/app/dashboard/components/widgets/finance.cash-balance-kpi.tsx.ejs +0 -66
- package/hedhog/frontend/app/dashboard/components/widgets/finance.cash-flow-chart.tsx.ejs +0 -122
- package/hedhog/frontend/app/dashboard/components/widgets/finance.default-kpi.tsx.ejs +0 -63
- package/hedhog/frontend/app/dashboard/components/widgets/finance.payable-30d-kpi.tsx.ejs +0 -73
- package/hedhog/frontend/app/dashboard/components/widgets/finance.receivable-30d-kpi.tsx.ejs +0 -73
- package/hedhog/frontend/app/dashboard/components/widgets/finance.upcoming-payable.tsx.ejs +0 -123
- package/hedhog/frontend/app/dashboard/components/widgets/finance.upcoming-receivable.tsx.ejs +0 -118
|
@@ -430,6 +430,170 @@ let DashboardCoreService = DashboardCoreService_1 = class DashboardCoreService {
|
|
|
430
430
|
}
|
|
431
431
|
return value.map((provider) => String(provider).toLowerCase());
|
|
432
432
|
}
|
|
433
|
+
slugifyDashboardName(value) {
|
|
434
|
+
const normalized = value
|
|
435
|
+
.normalize('NFD')
|
|
436
|
+
.replace(/[\u0300-\u036f]/g, '')
|
|
437
|
+
.toLowerCase()
|
|
438
|
+
.replace(/[^a-z0-9]+/g, '-')
|
|
439
|
+
.replace(/^-+|-+$/g, '');
|
|
440
|
+
return normalized || `dashboard-${Date.now()}`;
|
|
441
|
+
}
|
|
442
|
+
getDashboardDisplayName(dashboard) {
|
|
443
|
+
var _a, _b;
|
|
444
|
+
return ((_b = (_a = dashboard.dashboard_locale) === null || _a === void 0 ? void 0 : _a[0]) === null || _b === void 0 ? void 0 : _b.name) || dashboard.slug;
|
|
445
|
+
}
|
|
446
|
+
async buildUniqueDashboardSlug(baseSlug) {
|
|
447
|
+
let slug = baseSlug;
|
|
448
|
+
let suffix = 2;
|
|
449
|
+
while (await this.prismaService.dashboard.findFirst({
|
|
450
|
+
where: { slug },
|
|
451
|
+
select: { id: true },
|
|
452
|
+
})) {
|
|
453
|
+
slug = `${baseSlug}-${suffix}`;
|
|
454
|
+
suffix += 1;
|
|
455
|
+
}
|
|
456
|
+
return slug;
|
|
457
|
+
}
|
|
458
|
+
async getDashboardUserOrThrow(userId, slug, locale) {
|
|
459
|
+
const dashboardUser = await this.prismaService.dashboard_user.findFirst({
|
|
460
|
+
where: {
|
|
461
|
+
user_id: userId,
|
|
462
|
+
dashboard: { slug },
|
|
463
|
+
},
|
|
464
|
+
include: {
|
|
465
|
+
dashboard: {
|
|
466
|
+
include: {
|
|
467
|
+
dashboard_locale: {
|
|
468
|
+
where: {
|
|
469
|
+
locale: {
|
|
470
|
+
code: locale,
|
|
471
|
+
},
|
|
472
|
+
},
|
|
473
|
+
},
|
|
474
|
+
},
|
|
475
|
+
},
|
|
476
|
+
},
|
|
477
|
+
});
|
|
478
|
+
if (!dashboardUser) {
|
|
479
|
+
throw new common_1.ForbiddenException((0, api_locale_1.getLocaleText)('dashboardNotFound', locale, 'Dashboard not found.'));
|
|
480
|
+
}
|
|
481
|
+
return dashboardUser;
|
|
482
|
+
}
|
|
483
|
+
async getUserRoleIds(userId) {
|
|
484
|
+
const roleUsers = await this.prismaService.role_user.findMany({
|
|
485
|
+
where: { user_id: userId },
|
|
486
|
+
select: { role_id: true },
|
|
487
|
+
});
|
|
488
|
+
return roleUsers.map((roleUser) => roleUser.role_id);
|
|
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
|
+
}
|
|
545
|
+
async getAccessibleTemplateOrThrow(userId, templateSlug, locale) {
|
|
546
|
+
const userRoleIds = await this.getUserRoleIds(userId);
|
|
547
|
+
const templateAccessFilter = userRoleIds.length > 0
|
|
548
|
+
? {
|
|
549
|
+
OR: [
|
|
550
|
+
{
|
|
551
|
+
dashboard_role: {
|
|
552
|
+
some: {
|
|
553
|
+
role_id: {
|
|
554
|
+
in: userRoleIds,
|
|
555
|
+
},
|
|
556
|
+
},
|
|
557
|
+
},
|
|
558
|
+
},
|
|
559
|
+
{
|
|
560
|
+
dashboard_role: {
|
|
561
|
+
none: {},
|
|
562
|
+
},
|
|
563
|
+
},
|
|
564
|
+
],
|
|
565
|
+
}
|
|
566
|
+
: {
|
|
567
|
+
dashboard_role: {
|
|
568
|
+
none: {},
|
|
569
|
+
},
|
|
570
|
+
};
|
|
571
|
+
const template = await this.prismaService.dashboard.findFirst({
|
|
572
|
+
where: Object.assign({ slug: templateSlug, is_template: true }, templateAccessFilter),
|
|
573
|
+
include: {
|
|
574
|
+
dashboard_locale: {
|
|
575
|
+
where: {
|
|
576
|
+
locale: {
|
|
577
|
+
code: locale,
|
|
578
|
+
},
|
|
579
|
+
},
|
|
580
|
+
},
|
|
581
|
+
dashboard_item: {
|
|
582
|
+
select: {
|
|
583
|
+
component_id: true,
|
|
584
|
+
width: true,
|
|
585
|
+
height: true,
|
|
586
|
+
x_axis: true,
|
|
587
|
+
y_axis: true,
|
|
588
|
+
},
|
|
589
|
+
},
|
|
590
|
+
},
|
|
591
|
+
});
|
|
592
|
+
if (!template) {
|
|
593
|
+
throw new common_1.ForbiddenException((0, api_locale_1.getLocaleText)('dashboardNotFound', locale, 'Dashboard template not found.'));
|
|
594
|
+
}
|
|
595
|
+
return template;
|
|
596
|
+
}
|
|
433
597
|
async getHome(userId, locale) {
|
|
434
598
|
const user = await this.prismaService.user.findUnique({
|
|
435
599
|
where: { id: userId },
|
|
@@ -712,6 +876,7 @@ let DashboardCoreService = DashboardCoreService_1 = class DashboardCoreService {
|
|
|
712
876
|
if (!canAccess) {
|
|
713
877
|
return [];
|
|
714
878
|
}
|
|
879
|
+
await this.assertDashboardRoleAccess(dashboard.id, userId);
|
|
715
880
|
const dashboardItems = await this.prismaService.dashboard_item.findMany({
|
|
716
881
|
where: {
|
|
717
882
|
dashboard_id: dashboard.id,
|
|
@@ -771,26 +936,30 @@ let DashboardCoreService = DashboardCoreService_1 = class DashboardCoreService {
|
|
|
771
936
|
if (!canAccess) {
|
|
772
937
|
throw new common_1.ForbiddenException('Access denied to this dashboard');
|
|
773
938
|
}
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
const
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
},
|
|
781
|
-
});
|
|
782
|
-
if (!dashboardItem) {
|
|
783
|
-
continue;
|
|
939
|
+
await this.assertDashboardRoleAccess(dashboard.id, userId);
|
|
940
|
+
const layoutUpdates = layout.flatMap((item) => {
|
|
941
|
+
const itemId = Number.parseInt(item.i.replace('widget-', ''), 10);
|
|
942
|
+
if (Number.isNaN(itemId)) {
|
|
943
|
+
this.logger.warn(`Skipping dashboard layout item with invalid id: ${item.i}`);
|
|
944
|
+
return [];
|
|
784
945
|
}
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
946
|
+
return [
|
|
947
|
+
this.prismaService.dashboard_item.updateMany({
|
|
948
|
+
where: {
|
|
949
|
+
id: itemId,
|
|
950
|
+
dashboard_id: dashboard.id,
|
|
951
|
+
},
|
|
952
|
+
data: {
|
|
953
|
+
x_axis: item.x,
|
|
954
|
+
y_axis: item.y,
|
|
955
|
+
width: item.w,
|
|
956
|
+
height: item.h,
|
|
957
|
+
},
|
|
958
|
+
}),
|
|
959
|
+
];
|
|
960
|
+
});
|
|
961
|
+
if (layoutUpdates.length > 0) {
|
|
962
|
+
await this.prismaService.$transaction(layoutUpdates);
|
|
794
963
|
}
|
|
795
964
|
return { success: true };
|
|
796
965
|
}
|
|
@@ -812,6 +981,7 @@ let DashboardCoreService = DashboardCoreService_1 = class DashboardCoreService {
|
|
|
812
981
|
if (!canAccess) {
|
|
813
982
|
throw new common_1.ForbiddenException('Access denied to this dashboard');
|
|
814
983
|
}
|
|
984
|
+
await this.assertDashboardRoleAccess(dashboard.id, userId);
|
|
815
985
|
const userRoles = await this.prismaService.role_user.findMany({
|
|
816
986
|
where: { user_id: userId },
|
|
817
987
|
select: { role_id: true },
|
|
@@ -927,6 +1097,7 @@ let DashboardCoreService = DashboardCoreService_1 = class DashboardCoreService {
|
|
|
927
1097
|
if (!canAccess) {
|
|
928
1098
|
throw new common_1.ForbiddenException('Access denied to this dashboard');
|
|
929
1099
|
}
|
|
1100
|
+
await this.assertDashboardRoleAccess(dashboard.id, userId);
|
|
930
1101
|
const parsedWidgetId = Number(widgetId.replace(/^widget-/, ''));
|
|
931
1102
|
if (!Number.isInteger(parsedWidgetId) || parsedWidgetId <= 0) {
|
|
932
1103
|
throw new common_1.BadRequestException('Invalid widget id');
|
|
@@ -975,9 +1146,18 @@ let DashboardCoreService = DashboardCoreService_1 = class DashboardCoreService {
|
|
|
975
1146
|
user_id: userId,
|
|
976
1147
|
},
|
|
977
1148
|
});
|
|
978
|
-
|
|
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;
|
|
979
1158
|
return {
|
|
980
1159
|
hasAccess,
|
|
1160
|
+
accessStatus: roleAccess.accessStatus,
|
|
981
1161
|
dashboard: hasAccess
|
|
982
1162
|
? {
|
|
983
1163
|
id: dashboard.id,
|
|
@@ -988,6 +1168,7 @@ let DashboardCoreService = DashboardCoreService_1 = class DashboardCoreService {
|
|
|
988
1168
|
};
|
|
989
1169
|
}
|
|
990
1170
|
async getUserDashboards(userId, locale) {
|
|
1171
|
+
await this.getHome(userId, locale);
|
|
991
1172
|
const dashboardUsers = await this.prismaService.dashboard_user.findMany({
|
|
992
1173
|
where: { user_id: userId },
|
|
993
1174
|
include: {
|
|
@@ -1003,6 +1184,7 @@ let DashboardCoreService = DashboardCoreService_1 = class DashboardCoreService {
|
|
|
1003
1184
|
},
|
|
1004
1185
|
},
|
|
1005
1186
|
},
|
|
1187
|
+
orderBy: [{ is_home: 'desc' }, { id: 'asc' }],
|
|
1006
1188
|
});
|
|
1007
1189
|
const uniqueByDashboardId = new Map();
|
|
1008
1190
|
for (const dashboardUser of dashboardUsers) {
|
|
@@ -1013,9 +1195,461 @@ let DashboardCoreService = DashboardCoreService_1 = class DashboardCoreService {
|
|
|
1013
1195
|
return Array.from(uniqueByDashboardId.values()).map((dashboardUser) => ({
|
|
1014
1196
|
id: dashboardUser.dashboard.id,
|
|
1015
1197
|
slug: dashboardUser.dashboard.slug,
|
|
1198
|
+
name: this.getDashboardDisplayName(dashboardUser.dashboard),
|
|
1199
|
+
icon: dashboardUser.dashboard.icon,
|
|
1200
|
+
is_home: dashboardUser.is_home,
|
|
1016
1201
|
dashboard_locale: dashboardUser.dashboard.dashboard_locale,
|
|
1017
1202
|
}));
|
|
1018
1203
|
}
|
|
1204
|
+
async getAvailableTemplates(userId, locale) {
|
|
1205
|
+
const userRoleIds = await this.getUserRoleIds(userId);
|
|
1206
|
+
const templateAccessFilter = userRoleIds.length > 0
|
|
1207
|
+
? {
|
|
1208
|
+
OR: [
|
|
1209
|
+
{
|
|
1210
|
+
dashboard_role: {
|
|
1211
|
+
some: {
|
|
1212
|
+
role_id: {
|
|
1213
|
+
in: userRoleIds,
|
|
1214
|
+
},
|
|
1215
|
+
},
|
|
1216
|
+
},
|
|
1217
|
+
},
|
|
1218
|
+
{
|
|
1219
|
+
dashboard_role: {
|
|
1220
|
+
none: {},
|
|
1221
|
+
},
|
|
1222
|
+
},
|
|
1223
|
+
],
|
|
1224
|
+
}
|
|
1225
|
+
: {
|
|
1226
|
+
dashboard_role: {
|
|
1227
|
+
none: {},
|
|
1228
|
+
},
|
|
1229
|
+
};
|
|
1230
|
+
const templates = await this.prismaService.dashboard.findMany({
|
|
1231
|
+
where: Object.assign({ is_template: true }, templateAccessFilter),
|
|
1232
|
+
include: {
|
|
1233
|
+
dashboard_locale: {
|
|
1234
|
+
where: {
|
|
1235
|
+
locale: {
|
|
1236
|
+
code: locale,
|
|
1237
|
+
},
|
|
1238
|
+
},
|
|
1239
|
+
},
|
|
1240
|
+
dashboard_item: {
|
|
1241
|
+
select: { id: true },
|
|
1242
|
+
},
|
|
1243
|
+
},
|
|
1244
|
+
orderBy: [{ id: 'asc' }],
|
|
1245
|
+
});
|
|
1246
|
+
return templates.map((template) => ({
|
|
1247
|
+
id: template.id,
|
|
1248
|
+
slug: template.slug,
|
|
1249
|
+
name: this.getDashboardDisplayName(template),
|
|
1250
|
+
icon: template.icon,
|
|
1251
|
+
itemCount: template.dashboard_item.length,
|
|
1252
|
+
}));
|
|
1253
|
+
}
|
|
1254
|
+
async createUserDashboard(userId, data, locale) {
|
|
1255
|
+
var _a, _b, _c, _d;
|
|
1256
|
+
const templateSlug = this.toNullableString(data === null || data === void 0 ? void 0 : data.templateSlug);
|
|
1257
|
+
const template = templateSlug
|
|
1258
|
+
? await this.getAccessibleTemplateOrThrow(userId, templateSlug, locale)
|
|
1259
|
+
: null;
|
|
1260
|
+
const templateName = template ? this.getDashboardDisplayName(template) : null;
|
|
1261
|
+
const name = this.toNullableString(data === null || data === void 0 ? void 0 : data.name) || templateName;
|
|
1262
|
+
if (!name) {
|
|
1263
|
+
throw new common_1.BadRequestException((0, api_locale_1.getLocaleText)('validation.fieldRequired', locale, 'Dashboard name is required.'));
|
|
1264
|
+
}
|
|
1265
|
+
const requestedSlug = this.toNullableString(data === null || data === void 0 ? void 0 : data.slug);
|
|
1266
|
+
const baseSlug = this.slugifyDashboardName(requestedSlug || name);
|
|
1267
|
+
const slug = await this.buildUniqueDashboardSlug(baseSlug);
|
|
1268
|
+
const icon = (data === null || data === void 0 ? void 0 : data.icon) === undefined
|
|
1269
|
+
? (_a = template === null || template === void 0 ? void 0 : template.icon) !== null && _a !== void 0 ? _a : null
|
|
1270
|
+
: (_c = (_b = this.toNullableString(data === null || data === void 0 ? void 0 : data.icon)) !== null && _b !== void 0 ? _b : template === null || template === void 0 ? void 0 : template.icon) !== null && _c !== void 0 ? _c : null;
|
|
1271
|
+
const [localeRecord, existingCount] = await Promise.all([
|
|
1272
|
+
this.prismaService.locale.findFirst({
|
|
1273
|
+
where: { code: locale },
|
|
1274
|
+
select: { id: true },
|
|
1275
|
+
}),
|
|
1276
|
+
this.prismaService.dashboard_user.count({
|
|
1277
|
+
where: { user_id: userId },
|
|
1278
|
+
}),
|
|
1279
|
+
]);
|
|
1280
|
+
const dashboard = await this.prismaService.dashboard.create({
|
|
1281
|
+
data: {
|
|
1282
|
+
slug,
|
|
1283
|
+
icon,
|
|
1284
|
+
},
|
|
1285
|
+
});
|
|
1286
|
+
if (localeRecord) {
|
|
1287
|
+
await this.prismaService.dashboard_locale.create({
|
|
1288
|
+
data: {
|
|
1289
|
+
dashboard_id: dashboard.id,
|
|
1290
|
+
locale_id: localeRecord.id,
|
|
1291
|
+
name,
|
|
1292
|
+
},
|
|
1293
|
+
});
|
|
1294
|
+
}
|
|
1295
|
+
await this.prismaService.dashboard_user.create({
|
|
1296
|
+
data: {
|
|
1297
|
+
dashboard_id: dashboard.id,
|
|
1298
|
+
user_id: userId,
|
|
1299
|
+
is_home: existingCount === 0,
|
|
1300
|
+
},
|
|
1301
|
+
});
|
|
1302
|
+
if ((_d = template === null || template === void 0 ? void 0 : template.dashboard_item) === null || _d === void 0 ? void 0 : _d.length) {
|
|
1303
|
+
await this.prismaService.dashboard_item.createMany({
|
|
1304
|
+
data: template.dashboard_item.map((item) => ({
|
|
1305
|
+
dashboard_id: dashboard.id,
|
|
1306
|
+
component_id: item.component_id,
|
|
1307
|
+
width: item.width,
|
|
1308
|
+
height: item.height,
|
|
1309
|
+
x_axis: item.x_axis,
|
|
1310
|
+
y_axis: item.y_axis,
|
|
1311
|
+
})),
|
|
1312
|
+
});
|
|
1313
|
+
}
|
|
1314
|
+
return {
|
|
1315
|
+
id: dashboard.id,
|
|
1316
|
+
slug,
|
|
1317
|
+
name,
|
|
1318
|
+
icon,
|
|
1319
|
+
is_home: existingCount === 0,
|
|
1320
|
+
};
|
|
1321
|
+
}
|
|
1322
|
+
async renameUserDashboard(userId, slug, data, locale) {
|
|
1323
|
+
var _a, _b;
|
|
1324
|
+
const dashboardUser = await this.getDashboardUserOrThrow(userId, slug, locale);
|
|
1325
|
+
const name = this.toNullableString(data === null || data === void 0 ? void 0 : data.name);
|
|
1326
|
+
const normalizedIcon = (data === null || data === void 0 ? void 0 : data.icon) === undefined ? undefined : this.toNullableString(data === null || data === void 0 ? void 0 : data.icon);
|
|
1327
|
+
if (!name && (data === null || data === void 0 ? void 0 : data.icon) === undefined) {
|
|
1328
|
+
throw new common_1.BadRequestException((0, api_locale_1.getLocaleText)('validation.fieldRequired', locale, 'Dashboard name or icon is required.'));
|
|
1329
|
+
}
|
|
1330
|
+
if ((data === null || data === void 0 ? void 0 : data.icon) !== undefined) {
|
|
1331
|
+
await this.prismaService.dashboard.update({
|
|
1332
|
+
where: { id: dashboardUser.dashboard_id },
|
|
1333
|
+
data: {
|
|
1334
|
+
icon: normalizedIcon !== null && normalizedIcon !== void 0 ? normalizedIcon : null,
|
|
1335
|
+
},
|
|
1336
|
+
});
|
|
1337
|
+
}
|
|
1338
|
+
if (name) {
|
|
1339
|
+
const localeRecord = await this.prismaService.locale.findFirst({
|
|
1340
|
+
where: { code: locale },
|
|
1341
|
+
select: { id: true },
|
|
1342
|
+
});
|
|
1343
|
+
if (!localeRecord) {
|
|
1344
|
+
throw new common_1.BadRequestException((0, api_locale_1.getLocaleText)('localeNotFound', locale, 'Locale not found.'));
|
|
1345
|
+
}
|
|
1346
|
+
const existingLocale = await this.prismaService.dashboard_locale.findFirst({
|
|
1347
|
+
where: {
|
|
1348
|
+
dashboard_id: dashboardUser.dashboard_id,
|
|
1349
|
+
locale_id: localeRecord.id,
|
|
1350
|
+
},
|
|
1351
|
+
select: { id: true },
|
|
1352
|
+
});
|
|
1353
|
+
if (existingLocale) {
|
|
1354
|
+
await this.prismaService.dashboard_locale.update({
|
|
1355
|
+
where: { id: existingLocale.id },
|
|
1356
|
+
data: { name },
|
|
1357
|
+
});
|
|
1358
|
+
}
|
|
1359
|
+
else {
|
|
1360
|
+
await this.prismaService.dashboard_locale.create({
|
|
1361
|
+
data: {
|
|
1362
|
+
dashboard_id: dashboardUser.dashboard_id,
|
|
1363
|
+
locale_id: localeRecord.id,
|
|
1364
|
+
name,
|
|
1365
|
+
},
|
|
1366
|
+
});
|
|
1367
|
+
}
|
|
1368
|
+
}
|
|
1369
|
+
const updatedDashboard = await this.prismaService.dashboard.findUnique({
|
|
1370
|
+
where: { id: dashboardUser.dashboard_id },
|
|
1371
|
+
include: {
|
|
1372
|
+
dashboard_locale: {
|
|
1373
|
+
where: {
|
|
1374
|
+
locale: {
|
|
1375
|
+
code: locale,
|
|
1376
|
+
},
|
|
1377
|
+
},
|
|
1378
|
+
},
|
|
1379
|
+
},
|
|
1380
|
+
});
|
|
1381
|
+
return {
|
|
1382
|
+
success: true,
|
|
1383
|
+
slug,
|
|
1384
|
+
name: name ||
|
|
1385
|
+
(updatedDashboard
|
|
1386
|
+
? this.getDashboardDisplayName(updatedDashboard)
|
|
1387
|
+
: slug),
|
|
1388
|
+
icon: (_b = (_a = updatedDashboard === null || updatedDashboard === void 0 ? void 0 : updatedDashboard.icon) !== null && _a !== void 0 ? _a : normalizedIcon) !== null && _b !== void 0 ? _b : null,
|
|
1389
|
+
};
|
|
1390
|
+
}
|
|
1391
|
+
async setHomeDashboard(userId, slug, locale) {
|
|
1392
|
+
const dashboardUser = await this.getDashboardUserOrThrow(userId, slug, locale);
|
|
1393
|
+
await this.prismaService.dashboard_user.updateMany({
|
|
1394
|
+
where: { user_id: userId },
|
|
1395
|
+
data: { is_home: false },
|
|
1396
|
+
});
|
|
1397
|
+
await this.prismaService.dashboard_user.update({
|
|
1398
|
+
where: { id: dashboardUser.id },
|
|
1399
|
+
data: { is_home: true },
|
|
1400
|
+
});
|
|
1401
|
+
return {
|
|
1402
|
+
success: true,
|
|
1403
|
+
slug,
|
|
1404
|
+
};
|
|
1405
|
+
}
|
|
1406
|
+
async getDashboardShares(userId, slug, locale) {
|
|
1407
|
+
const dashboardUser = await this.getDashboardUserOrThrow(userId, slug, locale);
|
|
1408
|
+
const dashboardRoleRequirements = await this.getDashboardComponentRoleRequirements(dashboardUser.dashboard_id);
|
|
1409
|
+
const sharedUsers = await this.prismaService.dashboard_user.findMany({
|
|
1410
|
+
where: {
|
|
1411
|
+
dashboard_id: dashboardUser.dashboard_id,
|
|
1412
|
+
},
|
|
1413
|
+
include: {
|
|
1414
|
+
user: {
|
|
1415
|
+
select: {
|
|
1416
|
+
id: true,
|
|
1417
|
+
name: true,
|
|
1418
|
+
role_user: {
|
|
1419
|
+
select: {
|
|
1420
|
+
role_id: true,
|
|
1421
|
+
},
|
|
1422
|
+
},
|
|
1423
|
+
user_identifier: {
|
|
1424
|
+
where: {
|
|
1425
|
+
type: 'email',
|
|
1426
|
+
},
|
|
1427
|
+
select: {
|
|
1428
|
+
value: true,
|
|
1429
|
+
},
|
|
1430
|
+
take: 1,
|
|
1431
|
+
},
|
|
1432
|
+
},
|
|
1433
|
+
},
|
|
1434
|
+
},
|
|
1435
|
+
orderBy: {
|
|
1436
|
+
id: 'asc',
|
|
1437
|
+
},
|
|
1438
|
+
});
|
|
1439
|
+
return sharedUsers.map((sharedDashboardUser) => {
|
|
1440
|
+
var _a, _b;
|
|
1441
|
+
const userRoleIds = sharedDashboardUser.user.role_user.map((roleUser) => roleUser.role_id);
|
|
1442
|
+
const hasRequiredRoles = this.userHasRequiredRolesForDashboard(dashboardRoleRequirements, userRoleIds);
|
|
1443
|
+
return {
|
|
1444
|
+
id: sharedDashboardUser.user.id,
|
|
1445
|
+
name: sharedDashboardUser.user.name,
|
|
1446
|
+
email: (_b = (_a = sharedDashboardUser.user.user_identifier[0]) === null || _a === void 0 ? void 0 : _a.value) !== null && _b !== void 0 ? _b : null,
|
|
1447
|
+
isCurrentUser: sharedDashboardUser.user.id === userId,
|
|
1448
|
+
isHome: sharedDashboardUser.is_home,
|
|
1449
|
+
hasRequiredRoles,
|
|
1450
|
+
accessStatus: hasRequiredRoles ? 'allowed' : 'missing-roles',
|
|
1451
|
+
};
|
|
1452
|
+
});
|
|
1453
|
+
}
|
|
1454
|
+
async getShareableUsers(userId, slug, options, locale) {
|
|
1455
|
+
var _a, _b;
|
|
1456
|
+
const dashboardUser = await this.getDashboardUserOrThrow(userId, slug, locale);
|
|
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',
|
|
1484
|
+
},
|
|
1485
|
+
},
|
|
1486
|
+
{
|
|
1487
|
+
user_identifier: {
|
|
1488
|
+
some: {
|
|
1489
|
+
type: 'email',
|
|
1490
|
+
value: {
|
|
1491
|
+
contains: normalizedSearch,
|
|
1492
|
+
mode: 'insensitive',
|
|
1493
|
+
},
|
|
1494
|
+
},
|
|
1495
|
+
},
|
|
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,
|
|
1505
|
+
select: {
|
|
1506
|
+
id: true,
|
|
1507
|
+
name: true,
|
|
1508
|
+
role_user: {
|
|
1509
|
+
select: {
|
|
1510
|
+
role_id: true,
|
|
1511
|
+
},
|
|
1512
|
+
},
|
|
1513
|
+
user_identifier: {
|
|
1514
|
+
where: {
|
|
1515
|
+
type: 'email',
|
|
1516
|
+
},
|
|
1517
|
+
select: {
|
|
1518
|
+
value: true,
|
|
1519
|
+
},
|
|
1520
|
+
take: 1,
|
|
1521
|
+
},
|
|
1522
|
+
},
|
|
1523
|
+
skip: (safePage - 1) * pageSize,
|
|
1524
|
+
take: pageSize,
|
|
1525
|
+
orderBy: [{ name: 'asc' }, { id: 'asc' }],
|
|
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
|
+
};
|
|
1547
|
+
}
|
|
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) {
|
|
1556
|
+
throw new common_1.BadRequestException((0, api_locale_1.getLocaleText)('validation.fieldRequired', locale, 'User is required.'));
|
|
1557
|
+
}
|
|
1558
|
+
const dashboardUser = await this.getDashboardUserOrThrow(userId, slug, locale);
|
|
1559
|
+
const sanitizedUserIds = requestedIds.filter((candidateUserId) => candidateUserId !== userId);
|
|
1560
|
+
if (sanitizedUserIds.length === 0) {
|
|
1561
|
+
throw new common_1.BadRequestException((0, api_locale_1.getLocaleText)('validation.invalidValue', locale, 'You already have access to this dashboard.'));
|
|
1562
|
+
}
|
|
1563
|
+
const targetUsers = await this.prismaService.user.findMany({
|
|
1564
|
+
where: {
|
|
1565
|
+
id: {
|
|
1566
|
+
in: sanitizedUserIds,
|
|
1567
|
+
},
|
|
1568
|
+
},
|
|
1569
|
+
select: {
|
|
1570
|
+
id: true,
|
|
1571
|
+
},
|
|
1572
|
+
});
|
|
1573
|
+
if (targetUsers.length !== sanitizedUserIds.length) {
|
|
1574
|
+
throw new common_1.BadRequestException((0, api_locale_1.getLocaleText)('userNotFound', locale, 'User not found.'));
|
|
1575
|
+
}
|
|
1576
|
+
const existingShares = await this.prismaService.dashboard_user.findMany({
|
|
1577
|
+
where: {
|
|
1578
|
+
dashboard_id: dashboardUser.dashboard_id,
|
|
1579
|
+
user_id: {
|
|
1580
|
+
in: sanitizedUserIds,
|
|
1581
|
+
},
|
|
1582
|
+
},
|
|
1583
|
+
select: {
|
|
1584
|
+
user_id: true,
|
|
1585
|
+
},
|
|
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
|
+
}
|
|
1599
|
+
return {
|
|
1600
|
+
success: true,
|
|
1601
|
+
sharedCount: newUserIds.length,
|
|
1602
|
+
sharedUserIds: newUserIds,
|
|
1603
|
+
alreadySharedUserIds,
|
|
1604
|
+
};
|
|
1605
|
+
}
|
|
1606
|
+
async revokeDashboardShare(userId, slug, sharedUserId, locale) {
|
|
1607
|
+
const dashboardUser = await this.getDashboardUserOrThrow(userId, slug, locale);
|
|
1608
|
+
if (sharedUserId === userId) {
|
|
1609
|
+
throw new common_1.BadRequestException((0, api_locale_1.getLocaleText)('validation.invalidValue', locale, 'Use the remove dashboard action to leave this tab.'));
|
|
1610
|
+
}
|
|
1611
|
+
await this.prismaService.dashboard_user.deleteMany({
|
|
1612
|
+
where: {
|
|
1613
|
+
dashboard_id: dashboardUser.dashboard_id,
|
|
1614
|
+
user_id: sharedUserId,
|
|
1615
|
+
},
|
|
1616
|
+
});
|
|
1617
|
+
return {
|
|
1618
|
+
success: true,
|
|
1619
|
+
};
|
|
1620
|
+
}
|
|
1621
|
+
async removeUserDashboard(userId, slug, locale) {
|
|
1622
|
+
const dashboardUser = await this.getDashboardUserOrThrow(userId, slug, locale);
|
|
1623
|
+
await this.prismaService.dashboard_user.delete({
|
|
1624
|
+
where: { id: dashboardUser.id },
|
|
1625
|
+
});
|
|
1626
|
+
if (dashboardUser.is_home) {
|
|
1627
|
+
const nextDashboard = await this.prismaService.dashboard_user.findFirst({
|
|
1628
|
+
where: { user_id: userId },
|
|
1629
|
+
orderBy: { id: 'asc' },
|
|
1630
|
+
});
|
|
1631
|
+
if (nextDashboard) {
|
|
1632
|
+
await this.prismaService.dashboard_user.update({
|
|
1633
|
+
where: { id: nextDashboard.id },
|
|
1634
|
+
data: { is_home: true },
|
|
1635
|
+
});
|
|
1636
|
+
}
|
|
1637
|
+
}
|
|
1638
|
+
const remainingShares = await this.prismaService.dashboard_user.count({
|
|
1639
|
+
where: {
|
|
1640
|
+
dashboard_id: dashboardUser.dashboard_id,
|
|
1641
|
+
},
|
|
1642
|
+
});
|
|
1643
|
+
if (remainingShares === 0) {
|
|
1644
|
+
await this.prismaService.dashboard.delete({
|
|
1645
|
+
where: { id: dashboardUser.dashboard_id },
|
|
1646
|
+
});
|
|
1647
|
+
}
|
|
1648
|
+
return {
|
|
1649
|
+
success: true,
|
|
1650
|
+
removedSlug: slug,
|
|
1651
|
+
};
|
|
1652
|
+
}
|
|
1019
1653
|
async getAccountSecurity(userId) {
|
|
1020
1654
|
const now = new Date();
|
|
1021
1655
|
const thirtyDaysAgo = new Date(now.getTime() - 30 * 24 * 60 * 60 * 1000);
|