in source/packages/services/assetlibrary/src/devices/devices.full.service.ts [948:1057]
public async attachToDevice(
deviceId: string,
relationship: string,
direction: RelationDirection,
otherDeviceId: string
): Promise<void> {
logger.debug(
`device.full.service attachToDevice: in: deviceId:${deviceId}, relationship:${relationship}, direction:${direction}, otherDeviceId:${otherDeviceId}`
);
ow(deviceId, 'deviceId', ow.string.nonEmpty);
ow(relationship, 'relationship', ow.string.nonEmpty);
ow(direction, 'direction', ow.string.oneOf(['in', 'out']));
ow(otherDeviceId, 'otherDeviceId', ow.string.nonEmpty);
// any ids need to be lowercase
deviceId = deviceId.toLowerCase();
relationship = relationship.toLowerCase();
otherDeviceId = otherDeviceId.toLowerCase();
await this.authServiceFull.authorizationCheck(
[deviceId, otherDeviceId],
[],
ClaimAccess.U
);
// fetch the existing device / group
const deviceFuture = this.get(deviceId, false, [], false);
const otherDeviceFuture = this.get(otherDeviceId, false, [], false);
const [device, otherDevice] = await Promise.all([deviceFuture, otherDeviceFuture]);
// make sure they exist
if (device === undefined) {
throw new DeviceNotFoundError(deviceId);
}
if (otherDevice === undefined) {
throw new DeviceNotFoundError(otherDeviceId);
}
// if the relation already exists, there's no need to continue
if (device.devices?.[direction]?.[relationship]?.find((e) => e.id === otherDeviceId)) {
logger.debug(`device.full.service attachToDevice: relation already exits:`);
return;
}
// ensure that the relation is allowed
const relatedDevice: DirectionToRelatedEntityArrayMap = {
[direction]: {
[relationship]: [
{
id: otherDeviceId,
},
],
},
};
const template = await this.typesService.get(
device.templateId,
TypeCategory.Device,
TypeDefinitionStatus.published
);
if (template === undefined) {
throw new TemplateNotFoundError(device.templateId);
}
const validateRelationships = await this.validator.validateRelationshipsByIds(
template,
undefined,
relatedDevice
);
if (!validateRelationships.isValid) {
throw new RelationValidationError(validateRelationships);
}
// if fgac is enabled, we need to ensure any relations configured as identifying auth in its template are flagged to be saved as so
let isAuthCheck = true;
if (this.isAuthzEnabled) {
const authRelations =
direction === 'in'
? template.schema.relations.incomingAuthRelations()
: template.schema.relations.outgoingAuthRelations();
this.authServiceFull.updateRelsIdentifyingAuth(
relatedDevice[direction],
validateRelationships.deviceLabels,
authRelations
);
isAuthCheck = relatedDevice[direction][relationship][0].isAuthCheck ?? false;
}
// Save to datastore
await this.devicesDao.attachToDevice(
deviceId,
relationship,
direction,
otherDeviceId,
isAuthCheck
);
// fire event
await this.eventEmitter.fire({
objectId: deviceId,
type: Type.device,
event: Event.modify,
attributes: {
deviceId,
attachedToDevice: otherDeviceId,
relationship,
},
});
logger.debug(`device.full.service attachToDevice: exit:`);
}