Add BIM viewer service launch integration
This commit is contained in:
parent
ec021d1a95
commit
4584c227ff
|
|
@ -62,6 +62,48 @@ const publicPoolClient = {
|
|||
createdAt: "2026-05-09T00:00:00.000Z",
|
||||
updatedAt: "2026-05-09T00:00:00.000Z",
|
||||
};
|
||||
const bimViewerService = {
|
||||
id: "service_bim_viewer",
|
||||
slug: "bim-viewer",
|
||||
title: "BIM VIEWER",
|
||||
subtitle: "BIM и CAD просмотр",
|
||||
description: "Персональный просмотр BIM/CAD моделей, версий и публичных ссылок.",
|
||||
fullDescription:
|
||||
"Standalone BIM/CAD viewer NODE.DC для рабочих моделей, вложений Operational Core, персонального модельного хранилища и безопасного внешнего просмотра по share-ссылкам.",
|
||||
url: "https://bim.nodedc.ru",
|
||||
launchUrl: "https://bim.nodedc.ru",
|
||||
accentColor: "#8FE3C8",
|
||||
fallbackGradient: "linear-gradient(132deg, rgba(143, 227, 200, 0.78), rgba(24, 70, 64, 0.9) 46%, #080B0F 84%)",
|
||||
status: "active",
|
||||
order: 25,
|
||||
authentikApplicationSlug: "bim-viewer",
|
||||
authentikGroupName: "nodedc:bim:access",
|
||||
isAvailableForAllNewClients: true,
|
||||
createdAt: "2026-06-18T00:00:00.000Z",
|
||||
updatedAt: "2026-06-18T00:00:00.000Z",
|
||||
};
|
||||
const bimViewerDefaultGrants = [
|
||||
{
|
||||
id: "grant_bim_viewer_client_romashka",
|
||||
serviceId: "service_bim_viewer",
|
||||
targetType: "client",
|
||||
targetId: "client_romashka",
|
||||
appRole: "member",
|
||||
status: "active",
|
||||
createdAt: "2026-06-18T00:00:00.000Z",
|
||||
updatedAt: "2026-06-18T00:00:00.000Z",
|
||||
},
|
||||
{
|
||||
id: "grant_bim_viewer_client_public_pool",
|
||||
serviceId: "service_bim_viewer",
|
||||
targetType: "client",
|
||||
targetId: publicPoolClientId,
|
||||
appRole: "member",
|
||||
status: "active",
|
||||
createdAt: "2026-06-18T00:00:00.000Z",
|
||||
updatedAt: "2026-06-18T00:00:00.000Z",
|
||||
},
|
||||
];
|
||||
const defaultSettings = {
|
||||
brand: {
|
||||
logoLinkUrl: "/",
|
||||
|
|
@ -2281,9 +2323,89 @@ function normalizeData(payload) {
|
|||
data.taskerInviteRequests = data.taskerInviteRequests.map(normalizeTaskerInviteRequest).filter(Boolean);
|
||||
data.engineWorkflowAccessRequests = data.engineWorkflowAccessRequests.map(normalizeEngineWorkflowAccessRequest).filter(Boolean);
|
||||
applyProtectedLauncherUserInvariants(data);
|
||||
applyBimViewerServiceInvariants(data);
|
||||
return data;
|
||||
}
|
||||
|
||||
function applyBimViewerServiceInvariants(data) {
|
||||
let service = data.services.find(
|
||||
(candidate) => candidate.id === bimViewerService.id || candidate.slug === bimViewerService.slug
|
||||
);
|
||||
|
||||
if (!service) {
|
||||
service = normalizeService({ ...bimViewerService });
|
||||
data.services.push(service);
|
||||
} else {
|
||||
service.id = service.id || bimViewerService.id;
|
||||
service.slug = service.slug || bimViewerService.slug;
|
||||
service.title = service.title || bimViewerService.title;
|
||||
service.subtitle = service.subtitle || bimViewerService.subtitle;
|
||||
service.description = service.description || bimViewerService.description;
|
||||
service.fullDescription = service.fullDescription || bimViewerService.fullDescription;
|
||||
service.url = service.url || bimViewerService.url;
|
||||
service.launchUrl = service.launchUrl || service.url || bimViewerService.launchUrl;
|
||||
service.accentColor = service.accentColor || bimViewerService.accentColor;
|
||||
service.fallbackGradient = service.fallbackGradient || bimViewerService.fallbackGradient;
|
||||
service.status = service.status || bimViewerService.status;
|
||||
service.order = service.order ?? bimViewerService.order;
|
||||
service.authentikApplicationSlug = service.authentikApplicationSlug || bimViewerService.authentikApplicationSlug;
|
||||
service.authentikGroupName = service.authentikGroupName || bimViewerService.authentikGroupName;
|
||||
service.isAvailableForAllNewClients = service.isAvailableForAllNewClients ?? true;
|
||||
service.createdAt = service.createdAt || bimViewerService.createdAt;
|
||||
service.updatedAt = service.updatedAt || bimViewerService.updatedAt;
|
||||
}
|
||||
|
||||
const serviceId = service.id || bimViewerService.id;
|
||||
for (const defaultGrant of bimViewerDefaultGrants) {
|
||||
const grant = { ...defaultGrant, serviceId };
|
||||
const exists = data.grants.some(
|
||||
(candidate) =>
|
||||
candidate.serviceId === grant.serviceId &&
|
||||
candidate.targetType === grant.targetType &&
|
||||
candidate.targetId === grant.targetId
|
||||
);
|
||||
if (!exists) {
|
||||
data.grants.push({ ...grant });
|
||||
}
|
||||
}
|
||||
|
||||
ensureStaticSyncStatus(data, {
|
||||
id: "sync_bim_viewer_authentik",
|
||||
objectId: serviceId,
|
||||
objectName: bimViewerService.title,
|
||||
objectType: "service",
|
||||
});
|
||||
for (const defaultGrant of bimViewerDefaultGrants) {
|
||||
const grant = { ...defaultGrant, serviceId };
|
||||
ensureStaticSyncStatus(data, {
|
||||
id: `sync_${grant.id}`,
|
||||
objectId: grant.id,
|
||||
objectName: `${bimViewerService.slug}:${grant.targetType}:${grant.targetId}`,
|
||||
objectType: "grant",
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function ensureStaticSyncStatus(data, status) {
|
||||
const exists = data.syncStatuses.some(
|
||||
(candidate) => candidate.target === "authentik" && candidate.objectType === status.objectType && candidate.objectId === status.objectId
|
||||
);
|
||||
if (exists) {
|
||||
return;
|
||||
}
|
||||
data.syncStatuses.push({
|
||||
id: status.id,
|
||||
objectId: status.objectId,
|
||||
objectName: status.objectName,
|
||||
objectType: status.objectType,
|
||||
target: "authentik",
|
||||
state: "pending",
|
||||
lastSyncAt: null,
|
||||
error: null,
|
||||
updatedAt: "2026-06-18T00:00:00.000Z",
|
||||
});
|
||||
}
|
||||
|
||||
function applyProtectedLauncherUserInvariants(data) {
|
||||
const rootUser = data.users.find((user) => isProtectedLauncherUserId(user.id));
|
||||
if (!rootUser) return;
|
||||
|
|
|
|||
|
|
@ -422,6 +422,21 @@ app.get("/api/services/:serviceSlug/launch", requireSession, (req, res) => {
|
|||
return;
|
||||
}
|
||||
|
||||
if (isBimViewerServiceSlug(serviceSlug)) {
|
||||
const handoffToken = createServiceHandoff(serviceSlug, runtimeContext.user);
|
||||
const targetUrl = new URL("/auth/nodedc/handoff", getBimViewerBaseUrl(app));
|
||||
const nextPath = sanitizeReturnTo(req.query.next_path || req.query.returnTo || "/");
|
||||
|
||||
targetUrl.searchParams.set("token", handoffToken);
|
||||
|
||||
if (nextPath && nextPath !== "/") {
|
||||
targetUrl.searchParams.set("next_path", nextPath);
|
||||
}
|
||||
|
||||
res.redirect(targetUrl.toString());
|
||||
return;
|
||||
}
|
||||
|
||||
if (serviceSlug !== "task-manager") {
|
||||
res.redirect(app.openUrl || app.url || "/");
|
||||
return;
|
||||
|
|
@ -3031,6 +3046,11 @@ function isEngineServiceSlug(serviceSlug) {
|
|||
return slug === "nodedc" || slug === "engine" || slug === "nodedc-engine";
|
||||
}
|
||||
|
||||
function isBimViewerServiceSlug(serviceSlug) {
|
||||
const slug = sanitizeServiceSlug(serviceSlug);
|
||||
return slug === "bim-viewer" || slug === "beam-viewer" || slug === "bim";
|
||||
}
|
||||
|
||||
function specialRequiredGroups(serviceOrSlug) {
|
||||
const slug = typeof serviceOrSlug === "string" ? serviceOrSlug : serviceOrSlug?.slug;
|
||||
const applicationSlug = typeof serviceOrSlug === "string" ? null : serviceOrSlug?.authentikApplicationSlug;
|
||||
|
|
@ -3046,7 +3066,7 @@ function specialRequiredGroups(serviceOrSlug) {
|
|||
}
|
||||
|
||||
function getServiceUrl(service) {
|
||||
if (service.slug === "task-manager" || isEngineServiceSlug(service.slug)) {
|
||||
if (service.slug === "task-manager" || isEngineServiceSlug(service.slug) || isBimViewerServiceSlug(service.slug)) {
|
||||
return `/api/services/${encodeURIComponent(service.slug)}/launch`;
|
||||
}
|
||||
|
||||
|
|
@ -3066,6 +3086,17 @@ function getTaskBaseUrl() {
|
|||
return taskBaseUrl.replace(/\/$/, "");
|
||||
}
|
||||
|
||||
function getBimViewerBaseUrl(app = null) {
|
||||
return String(
|
||||
process.env.NODEDC_BIM_VIEWER_PUBLIC_URL ||
|
||||
process.env.BIM_VIEWER_BASE_URL ||
|
||||
app?.launchTargetUrl ||
|
||||
app?.openUrl ||
|
||||
app?.url ||
|
||||
"http://localhost:8080"
|
||||
).replace(/\/$/, "");
|
||||
}
|
||||
|
||||
function getEnginePublicBaseUrl() {
|
||||
return String(
|
||||
process.env.NODEDC_ENGINE_PUBLIC_URL ||
|
||||
|
|
|
|||
|
|
@ -113,6 +113,26 @@ export const mockServices: Service[] = [
|
|||
createdAt: "2026-04-01T10:00:00Z",
|
||||
updatedAt: now,
|
||||
},
|
||||
{
|
||||
id: "service_bim_viewer",
|
||||
slug: "bim-viewer",
|
||||
title: "BIM VIEWER",
|
||||
subtitle: "BIM и CAD просмотр",
|
||||
description: "Персональный просмотр BIM/CAD моделей, версий и публичных ссылок.",
|
||||
fullDescription:
|
||||
"Standalone BIM/CAD viewer NODE.DC для рабочих моделей, вложений Operational Core, персонального модельного хранилища и безопасного внешнего просмотра по share-ссылкам.",
|
||||
url: "https://bim.nodedc.ru",
|
||||
launchUrl: "https://bim.nodedc.ru",
|
||||
accentColor: "#8FE3C8",
|
||||
fallbackGradient: "linear-gradient(132deg, rgba(143, 227, 200, 0.78), rgba(24, 70, 64, 0.9) 46%, #080B0F 84%)",
|
||||
status: "active",
|
||||
order: 25,
|
||||
authentikApplicationSlug: "bim-viewer",
|
||||
authentikGroupName: "nodedc:bim:access",
|
||||
isAvailableForAllNewClients: true,
|
||||
createdAt: "2026-06-18T00:00:00.000Z",
|
||||
updatedAt: now,
|
||||
},
|
||||
{
|
||||
id: "service_1c",
|
||||
slug: "1c-assistant",
|
||||
|
|
@ -211,6 +231,8 @@ export const mockGrants: ServiceGrant[] = [
|
|||
grant("grant_dctouch_nodedc_admins", "service_nodedc", "group", "group_dctouch_admins", "admin"),
|
||||
grant("grant_engine_user_silver_psih_yahoo_com", "service_nodedc", "user", "user_silver_psih", "member"),
|
||||
grant("grant_engine_user_constr_dc_yahoo_com", "service_nodedc", "user", "user_constr_dc_yahoo_com", "viewer"),
|
||||
grant("grant_bim_viewer_client_romashka", "service_bim_viewer", "client", "client_romashka", "member"),
|
||||
grant("grant_bim_viewer_client_public_pool", "service_bim_viewer", "client", "client_public_pool", "member"),
|
||||
];
|
||||
|
||||
export const mockExceptions: ServiceAccessException[] = [];
|
||||
|
|
@ -235,6 +257,23 @@ export const mockSyncStatuses: SyncStatus[] = [
|
|||
),
|
||||
sync("sync_dctouch_groups_authentik", "client_romashka:groups", "DCTOUCH groups", "group", "authentik", "pending"),
|
||||
sync("sync_task_manager_authentik", "service_task_manager", "OPERATIONAL CORE", "service", "authentik", "synced"),
|
||||
sync("sync_bim_viewer_authentik", "service_bim_viewer", "BIM VIEWER", "service", "authentik", "pending"),
|
||||
sync(
|
||||
"sync_grant_bim_viewer_client_romashka",
|
||||
"grant_bim_viewer_client_romashka",
|
||||
"bim-viewer:client:client_romashka",
|
||||
"grant",
|
||||
"authentik",
|
||||
"pending"
|
||||
),
|
||||
sync(
|
||||
"sync_grant_bim_viewer_client_public_pool",
|
||||
"grant_bim_viewer_client_public_pool",
|
||||
"bim-viewer:client:client_public_pool",
|
||||
"grant",
|
||||
"authentik",
|
||||
"pending"
|
||||
),
|
||||
];
|
||||
|
||||
export const mockAuditEvents: AuditEvent[] = [
|
||||
|
|
|
|||
Loading…
Reference in New Issue