public async create()

in source/packages/services/assetlibrary/src/devices/devices.full.service.ts [377:517]


    public async create(device: DeviceItem, applyProfile?: string): Promise<string> {
        logger.debug(
            `device.full.service create: in: device: ${JSON.stringify(
                device
            )}, applyProfile:${applyProfile}`
        );

        ow(device, ow.object.nonEmpty);
        ow(device.templateId, ow.string.nonEmpty);
        ow(device.deviceId, ow.string.nonEmpty);

        // if a profile to apply has been provided, apply it first
        if (applyProfile !== undefined) {
            device = await this.applyProfile(device, applyProfile);
        }

        // remove any non printable characters from the id
        device.deviceId = device.deviceId.replace(/[^\x20-\x7E]+/g, '');

        // any ids need to be lowercase
        this.setIdsToLowercase(device);

        // default initial associations if none provided
        if (
            device.groups?.in === undefined &&
            device.groups?.out === undefined &&
            device.devices?.in === undefined &&
            device.devices?.out === undefined &&
            (this.defaultDeviceParentRelation ?? '') !== '' &&
            (this.defaultDeviceParentGroup ?? '') !== ''
        ) {
            device.groups = {
                out: {
                    [this.defaultDeviceParentRelation]: [
                        {
                            id: this.defaultDeviceParentGroup,
                        },
                    ],
                },
            };
        }

        // we can't check authz til here, as we need to understand any related devices and groups first
        await this.authServiceFull.authorizationCheck(
            device.listRelatedDeviceIds(),
            device.listRelatedGroupPaths(),
            ClaimAccess.C
        );

        // default initial state if none provided
        if (device.state === undefined && this.defaultDeviceState !== undefined) {
            device.state = <DeviceState>this.defaultDeviceState;
        }

        // perform validation of the device...
        const template = await this.typesService.get(
            device.templateId,
            TypeCategory.Device,
            TypeDefinitionStatus.published
        );
        if (template === undefined) {
            throw new TemplateNotFoundError(device.templateId);
        }
        const validateSubTypeFuture = this.validator.validateSubType(
            template,
            device,
            Operation.CREATE
        );
        const validateRelationshipsFuture = this.validator.validateRelationshipsByIds(
            template,
            device.groups,
            device.devices
        );
        const [subTypeValidation, validateRelationships] = await Promise.all([
            validateSubTypeFuture,
            validateRelationshipsFuture,
        ]);

        // schema validation results
        if (!subTypeValidation.isValid) {
            throw new SchemaValidationError(subTypeValidation.errors);
        }

        // validate the id associations
        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
        if (this.isAuthzEnabled) {
            const incomingAuthRelations = template.schema.relations.incomingAuthRelations();
            const outgoingAuthRelations = template.schema.relations.outgoingAuthRelations();
            this.authServiceFull.updateRelsIdentifyingAuth(
                device.groups?.in,
                validateRelationships.groupLabels,
                incomingAuthRelations
            );
            this.authServiceFull.updateRelsIdentifyingAuth(
                device.groups?.out,
                validateRelationships.groupLabels,
                outgoingAuthRelations
            );
            this.authServiceFull.updateRelsIdentifyingAuth(
                device.devices?.in,
                validateRelationships.deviceLabels,
                incomingAuthRelations
            );
            this.authServiceFull.updateRelsIdentifyingAuth(
                device.devices?.out,
                validateRelationships.deviceLabels,
                outgoingAuthRelations
            );
        }

        // Assemble devicemodel into node
        device.category = TypeCategory.Device;
        const node = this.devicesAssembler.toNode(device);

        // Assemble the devices components
        const components: Node[] = [];
        if (device.components !== undefined) {
            device.components.forEach((c) => {
                c.category = TypeCategory.Component;
                components.push(this.devicesAssembler.toNode(c));
            });
        }

        // Save to datastore
        const id = await this.devicesDao.create(node, device.groups, device.devices, components);

        // fire event
        await this.eventEmitter.fire({
            objectId: device.deviceId,
            type: Type.device,
            event: Event.create,
            payload: JSON.stringify(device),
        });

        logger.debug(`device.full.service create: exit: id: ${id}`);
        return id;
    }