UNPKG

rhombus-node-mcp

Version:
257 lines (256 loc) 9.87 kB
import { postApi } from "../network/network.js"; const PERMISSION_RANK = { LIVEONLY: 0, READONLY: 1, ADMIN: 2, }; function hasAtLeastReadonly(perm) { return PERMISSION_RANK[perm ?? ""] >= PERMISSION_RANK.READONLY; } export async function unlockDoor(doorUuid, requestModifiers, sessionId) { const res = await postApi({ route: "/accesscontrol/unlockAccessControlledDoor", body: { accessControlledDoorUuid: doorUuid }, modifiers: requestModifiers, sessionId, }); if (res.error) { throw new Error(JSON.stringify(res)); } return { success: true, doorUuid }; } export async function getAccessControlGroups(requestModifiers, sessionId) { const res = await postApi({ route: "/accesscontrol/findAccessControlGroupsByOrg", body: {}, modifiers: requestModifiers, sessionId, }); if (res.error) { throw new Error(JSON.stringify(res)); } return (res.groups?.map((group) => ({ uuid: group.uuid ?? undefined, name: group.name ?? undefined, description: group.description ?? undefined, orgUuid: group.orgUuid ?? undefined, userUuids: group.userUuids?.filter((u) => u !== null) ?? [], })) ?? []); } export async function getCredentialsByUser(userUuid, requestModifiers, sessionId) { const res = await postApi({ route: "/accesscontrol/findAccessControlCredentialByUser", body: { userUuid }, modifiers: requestModifiers, sessionId, }); if (res.error) { throw new Error(JSON.stringify(res)); } return (res.credentials?.map((cred) => ({ uuid: cred.uuid ?? undefined, userUuid: cred.userUuid ?? undefined, credentialType: cred.credentialType ?? undefined, status: cred.workflowStatus ?? undefined, note: cred.note ?? undefined, })) ?? []); } export async function getLockdownPlans(requestModifiers, sessionId) { const res = await postApi({ route: "/accesscontrol/lockdownPlan/findLockdownPlans", body: {}, modifiers: requestModifiers, sessionId, }); if (res.error) { throw new Error(JSON.stringify(res)); } return (res.lockdownPlans?.map((plan) => ({ uuid: plan.uuid ?? undefined, name: plan.name ?? undefined, locationUuid: plan.locationUuid ?? undefined, description: plan.description ?? undefined, active: plan.active ?? undefined, })) ?? []); } export async function activateLockdown(locationUuid, lockdownPlanUuid, requestModifiers, sessionId) { const res = await postApi({ route: "/accesscontrol/lockdownPlan/activateLockdownForLocation", body: { locationUuid, lockdownPlanUuids: [lockdownPlanUuid] }, modifiers: requestModifiers, sessionId, }); if (res.error) { throw new Error(JSON.stringify(res)); } return { success: true, locationUuid, action: "activated" }; } export async function deactivateLockdown(locationUuid, lockdownPlanUuid, requestModifiers, sessionId) { const res = await postApi({ route: "/accesscontrol/lockdownPlan/deactivateLockdownForLocation", body: { locationUuid, lockdownPlanUuids: [lockdownPlanUuid] }, modifiers: requestModifiers, sessionId, }); if (res.error) { throw new Error(JSON.stringify(res)); } return { success: true, locationUuid, action: "deactivated" }; } export async function getDoorScheduleExceptions(locationUuid, requestModifiers, sessionId) { const res = await postApi({ route: "/accesscontrol/doorScheduleException/findExceptionsV2", body: { locationUuid }, modifiers: requestModifiers, sessionId, }); if (res.error) { throw new Error(JSON.stringify(res)); } return (res.exceptions?.map((exc) => ({ uuid: exc.uuid ?? undefined, name: exc.name ?? undefined, startTime: exc.startTimeMs ?? undefined, endTime: exc.endTimeMs ?? undefined, doorUuids: exc.doorUuids?.filter((d) => d !== null) ?? [], })) ?? []); } export async function getAccessGrants(locationUuid, requestModifiers, sessionId) { const res = locationUuid ? await postApi({ route: "/accesscontrol/findLocationAccessGrantsByLocation", body: { locationUuid }, modifiers: requestModifiers, sessionId, }) : await postApi({ route: "/accesscontrol/findLocationAccessGrantsByOrg", body: {}, modifiers: requestModifiers, sessionId, }); if (res.error) { throw new Error(JSON.stringify(res)); } const filterNulls = (arr) => arr?.filter((v) => v !== null) ?? []; return (res.accessGrants?.map((grant) => ({ uuid: grant.uuid ?? undefined, name: grant.name ?? undefined, locationUuid: grant.locationUuid ?? undefined, userUuids: filterNulls(grant.userUuids), groupUuids: filterNulls(grant.groupUuids), doorUuids: filterNulls(grant.accessControlledDoorUuids), scheduleUuid: grant.scheduleUuid ?? undefined, })) ?? []); } function canRoleUnlockDoor(role, doorLocationUuid, doorAssociatedCameras) { if (role.superAdmin) return true; const hasDoorAdmin = role.functionalityList?.includes("DOOR_ACCESS_ADMINISTRATION"); if (!hasDoorAdmin) return false; const acMap = role.accessControlLocationAccessMap ?? {}; const granularMap = role.locationGranularAccessMap ?? {}; const acLocationPerm = acMap[doorLocationUuid]; const granularLocationPerms = granularMap[doorLocationUuid] ?? {}; const accessConditionsPerm = granularLocationPerms["ACCESS_CONDITIONS"]; if (hasAtLeastReadonly(acLocationPerm) && hasAtLeastReadonly(accessConditionsPerm)) { return true; } if (doorAssociatedCameras.length > 0) { const locationMap = role.locationAccessMap ?? {}; const deviceMap = role.deviceAccessMap ?? {}; if (hasAtLeastReadonly(locationMap[doorLocationUuid])) return true; for (const cameraUuid of doorAssociatedCameras) { if (hasAtLeastReadonly(deviceMap[cameraUuid])) return true; } } return false; } export async function getRemoteUnlockUsers(locationUuid, requestModifiers, sessionId) { const [permGroupsRes, doorsRes, usersRes] = await Promise.all([ postApi({ route: "/permission/getPermissionGroups", body: {}, modifiers: requestModifiers, sessionId, }), postApi({ route: "/component/findAccessControlledDoors", body: {}, modifiers: requestModifiers, sessionId, }), postApi({ route: "/user/getUsersInOrg", body: {}, modifiers: requestModifiers, sessionId, }), ]); if (permGroupsRes.error) throw new Error(JSON.stringify(permGroupsRes)); if (doorsRes.error) throw new Error(JSON.stringify(doorsRes)); if (usersRes.error) throw new Error(JSON.stringify(usersRes)); const permissionGroups = permGroupsRes.permissionGroups ?? []; const groupMembership = {}; for (const [groupUuid, userUuids] of Object.entries(permGroupsRes.groupMembership ?? {})) { groupMembership[groupUuid] = (userUuids ?? []).filter((u) => u !== null); } const userMap = new Map(); for (const user of usersRes.users ?? []) { if (user.uuid) { userMap.set(user.uuid, { uuid: user.uuid, firstName: user.firstName ?? undefined, lastName: user.lastName ?? undefined, email: user.email ?? undefined, }); } } const doors = (doorsRes.accessControlledDoors ?? []).filter((door) => door.locationUuid === locationUuid && door.remoteUnlockEnabled === true); const doorNames = doors.map((d) => d.name ?? "Unknown"); const totalDoors = doorNames.length; const groupResults = new Map(); const seenUsers = new Set(); for (const door of doors) { const doorLocationUuid = door.locationUuid ?? ""; const doorName = door.name ?? "Unknown"; const associatedCameras = door.associatedCameras?.filter((c) => c !== null) ?? []; for (const role of permissionGroups) { if (!role.uuid) continue; if (!canRoleUnlockDoor(role, doorLocationUuid, associatedCameras)) continue; const roleName = role.name ?? "Unknown"; let group = groupResults.get(roleName); if (!group) { group = { doorNames: new Set(), userEntries: new Set() }; groupResults.set(roleName, group); } group.doorNames.add(doorName); for (const userUuid of groupMembership[role.uuid] ?? []) { if (!userMap.has(userUuid) || seenUsers.has(userUuid)) continue; seenUsers.add(userUuid); const user = userMap.get(userUuid); const name = [user.firstName, user.lastName].filter(Boolean).join(" "); const label = name ? `${name} (${user.email ?? "no email"})` : (user.email ?? userUuid); group.userEntries.add(label); } } } const groups = Array.from(groupResults.entries()).map(([name, g]) => ({ permissionGroup: name, doors: g.doorNames.size === totalDoors ? "all" : Array.from(g.doorNames), users: Array.from(g.userEntries), })); const totalUsers = seenUsers.size; return { doors: doorNames, totalUsers, groups }; }