source/packages/services/assetlibrary-export/src/groups/groups.assembler.ts (377 lines of code) (raw):

/********************************************************************************************************************* * Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. * * * * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance * * with the License. A copy of the License is located at * * * * http://www.apache.org/licenses/LICENSE-2.0 * * * * or in the 'license' file accompanying this file. This file is distributed on an 'AS IS' BASIS, WITHOUT WARRANTIES * * OR CONDITIONS OF ANY KIND, express or implied. See the License for the specific language governing permissions * * and limitations under the License. * *********************************************************************************************************************/ import { logger } from '@awssolutions/simple-cdf-logger'; import { inject, injectable } from 'inversify'; import { FullAssembler } from '../data/full.assembler'; import { Node } from '../data/node'; import { DevicesAssembler } from '../devices/devices.assembler'; import { determineIfDeviceItem } from '../devices/devices.models'; import { TYPES } from '../di/types'; import { TypeCategory } from '../types/constants'; import { BulkGroupsResource, Group10Resource, Group20Resource, GroupBaseResource, GroupItem, GroupItemList, GroupMemberItemList, GroupMemberResourceList, GroupResourceList, determineIfGroup20Resource, determineIfGroupItem, } from './groups.models'; @injectable() export class GroupsAssembler { constructor( @inject(TYPES.DevicesAssembler) private devicesAssembler: DevicesAssembler, @inject(TYPES.FullAssembler) private fullAssembler: FullAssembler ) {} public toNode(model: GroupItem): Node { logger.silly(`groups.assembler toNode: in: model: ${JSON.stringify(model)}`); const node = new Node(); node.types.push(model.category); node.types.push(model.templateId); node.attributes['name'] = model.name; node.attributes['groupPath'] = model.groupPath; node.attributes['parentPath'] = model.parentPath; node.attributes['description'] = model.description; node.version = model.version; for (const p in model.attributes) { if (model.attributes.hasOwnProperty(p)) { node.attributes[p] = model.attributes[p]; } } logger.silly(`groups.assembler toNode: exit: node: ${JSON.stringify(node)}`); return node; } public toGroupItems(nodes: Node[]): GroupItem[] { logger.silly(`groups.assembler toGroupItems: in: nodes: ${JSON.stringify(nodes)}`); const groups: GroupItem[] = []; for (const node of nodes) { groups.push(this.toGroupItem(node)); } return groups; } public toGroupItem(node: Node): GroupItem { logger.silly(`groups.assembler toGroupItem: in: node: ${JSON.stringify(node)}`); if (node === undefined) { logger.silly(`groups.assembler toGroupItem: exit: model: undefined`); return undefined; } const model = new GroupItem(); model.category = TypeCategory.Group; model.version = node.version; try { model.templateId = node.types.filter((t) => t !== TypeCategory.Group)[0]; } catch (err) { // do nothing, as templates don't exist in 'lite' mode } Object.keys(node.attributes).forEach((key) => { switch (key) { case 'name': model.name = <string>( this.fullAssembler.extractPropertyValue(node.attributes[key]) ); break; case 'groupPath': model.groupPath = <string>( this.fullAssembler.extractPropertyValue(node.attributes[key]) ); break; case 'parentPath': model.parentPath = <string>( this.fullAssembler.extractPropertyValue(node.attributes[key]) ); break; case 'description': model.description = <string>( this.fullAssembler.extractPropertyValue(node.attributes[key]) ); break; default: model.attributes[key] = this.fullAssembler.extractPropertyValue( node.attributes[key] ); } }); if (model.name === undefined) { model.name = model.groupPath; } Object.keys(node.in).forEach((key) => { const others = node.in[key]; if (others !== undefined) { if (model.groups === undefined) { model.groups = {}; } if (model.groups.in === undefined) { model.groups.in = {}; } others.forEach((other) => { if (other.category === TypeCategory.Group) { if (model.groups.in[key] === undefined) { model.groups.in[key] = []; } model.groups.in[key].push((other.attributes['groupPath'] as string[])[0]); } }); } }); Object.keys(node.out).forEach((key) => { const others = node.out[key]; if (others !== undefined) { if (model.groups === undefined) { model.groups = {}; } if (model.groups.out === undefined) { model.groups.out = {}; } others.forEach((other) => { if (other.category === TypeCategory.Group) { if (model.groups.out[key] === undefined) { model.groups.out[key] = []; } model.groups.out[key].push((other.attributes['groupPath'] as string[])[0]); } }); } }); // remove any empty collection attributes if (model.groups) { if (model.groups.in && Object.keys(model.groups.in).length === 0) { delete model.groups.in; } if (model.groups.out && Object.keys(model.groups.out).length === 0) { delete model.groups.out; } if (Object.keys(model.groups).length === 0) { delete model.groups; } } logger.silly(`groups.assembler toGroupItem: exit: model: ${JSON.stringify(model)}`); return model; } public fromGroupResource(res: GroupBaseResource): GroupItem { logger.silly(`group.assembler fromGroupResource: in: res: ${JSON.stringify(res)}`); if (res === undefined) { logger.silly(`group.assembler fromGroupResource: exit: res: undefined`); return undefined; } const item = new GroupItem(); // common properties Object.keys(res).forEach((key) => { if (key !== 'groups') { item[key] = res[key]; } }); // populate version specific device info if (determineIfGroup20Resource(res)) { // v2.0 supports both incoming and outgoing links const res_2_0 = res as Group20Resource; item.groups = res_2_0.groups; } else { // as v1.0 only supports outgoing links, we default all to outgoing const res_1_0 = res as Group10Resource; if (res_1_0.groups) { item.groups = { out: {} }; Object.keys(res_1_0.groups).forEach( (rel) => (item.groups.out[rel] = res_1_0.groups[rel]) ); } } logger.silly(`group.assembler fromGroupResource: exit: item: ${JSON.stringify(item)}`); return item; } public fromBulkGroupsResource(res: BulkGroupsResource): GroupItem[] { logger.silly(`group.assembler fromBulkGroupsResource: in: res: ${JSON.stringify(res)}`); if (res === undefined) { logger.silly(`group.assembler fromBulkGroupsResource: exit: res: undefined`); return undefined; } const items: GroupItem[] = []; res.groups.forEach((resource) => items.push(this.fromGroupResource(resource))); logger.silly( `group.assembler fromBulkGroupsResource: exit: items: ${JSON.stringify(items)}` ); return items; } public toGroupResource(item: GroupItem, version: string): GroupBaseResource { logger.silly( `group.assembler toGroupResource: in: item: ${JSON.stringify( item )}, version:${version}` ); if (item === undefined) { logger.silly(`group.assembler toGroupResource: exit: item: undefined`); return undefined; } let resource: GroupBaseResource; if (version.startsWith('1.')) { // v1 specific... resource = new Group10Resource(); const typedResource: Group10Resource = resource; // populate version specific device info if (item.groups) { typedResource.groups = {}; if (item.groups.in) { Object.keys(item.groups.in).forEach((rel) => { typedResource.groups[rel] = item.groups.in[rel]; }); } if (item.groups.out) { Object.keys(item.groups.out).forEach((rel) => { if (typedResource.groups[rel]) { typedResource.groups[rel].push(...item.groups.out[rel]); } else { typedResource.groups[rel] = item.groups.out[rel]; } }); } } else { delete typedResource.groups; } } else { // v2 specific... resource = new Group20Resource(); const typedResource: Group20Resource = resource; // populate version specific device info typedResource.groups = item.groups; } // common properties Object.keys(item).forEach((key) => { if (key !== 'groups' && key !== 'devices') { resource[key] = item[key]; } }); logger.silly( `group.assembler toGroupResource: exit: resource: ${JSON.stringify(resource)}` ); return resource; } public toGroupResourceList(items: GroupItemList, version: string): GroupResourceList { logger.silly( `group.assembler toGroupResourceList: in: items: ${JSON.stringify( items )}, version:${version}` ); if (items === undefined) { logger.silly(`group.assembler toGroupResourceList: exit: items: undefined`); return undefined; } const resources = new GroupResourceList(); resources.pagination = items.pagination; resources.results = []; items.results.forEach((item) => resources.results.push(this.toGroupResource(item, version)) ); logger.silly( `group.assembler toGroupResourceList: exit: resources: ${JSON.stringify(resources)}` ); return resources; } public toGroupMemberResourceList( items: GroupMemberItemList, version: string ): GroupMemberResourceList { logger.silly( `group.assembler toGroupMemberResourceList: in: items: ${JSON.stringify( items )}, version:${version}` ); if (items === undefined) { logger.silly(`group.assembler toGroupMemberResourceList: exit: items: undefined`); return undefined; } const resources: GroupMemberResourceList = { results: [], pagination: items.pagination, }; items.results.forEach((item) => { if (determineIfDeviceItem(item)) { resources.results.push(this.devicesAssembler.toDeviceResource(item, version)); } else if (determineIfGroupItem(item)) { resources.results.push(this.toGroupResource(item, version)); } }); logger.silly( `group.assembler toGroupMemberResourceList: exit: resources: ${JSON.stringify( resources )}` ); return resources; } public toGroupItemList(nodes: Node[]): GroupItem[] { logger.silly(`groups.assembler toGroupItemList: in: nodes: ${JSON.stringify(nodes)}`); if (nodes === undefined) { return []; } const models: GroupItem[] = []; for (const node of nodes) { models.push(this.toGroupItem(node)); } logger.silly(`groups.assembler toGroupItemList: exit: models: ${JSON.stringify(models)}`); return models; } public toRelatedGroupItemList( node: Node, offset?: number | string, count?: number ): GroupItemList { logger.silly(`groups.assembler toRelatedGroupItemList: in: node: ${JSON.stringify(node)}`); const r: GroupItemList = { results: [], }; if (node === undefined) { return r; } if (offset !== undefined || count !== undefined) { r.pagination = { offset, count, }; } Object.keys(node.in).forEach((relationship) => { const others = node.in[relationship]; if (others !== undefined) { others.forEach((other) => { const group: GroupItem = this.toGroupItem(other) as GroupItem; group.relation = relationship; group.direction = 'in'; r.results.push(group); }); } }); Object.keys(node.out).forEach((relationship) => { const others = node.out[relationship]; if (others !== undefined) { others.forEach((other) => { const group: GroupItem = this.toGroupItem(other) as GroupItem; group.relation = relationship; group.direction = 'out'; r.results.push(group); }); } }); logger.silly(`groups.assembler toRelatedGroupItemList: exit: r: ${JSON.stringify(r)}`); return r; } public toGroupMembersList( nodes: Node[], offset?: number | string, count?: number ): GroupMemberItemList { logger.silly(`groups.assembler toGroupMembersList: in: nodes: ${JSON.stringify(nodes)}`); const r: GroupMemberItemList = { results: [], }; if (nodes === undefined) { return r; } if (offset !== undefined || count !== undefined) { r.pagination = { offset, count, }; } for (const node of nodes) { if (node.types.indexOf(TypeCategory.Device) >= 0) { r.results.push(this.devicesAssembler.toDeviceItem(node)); } else if (node.types.indexOf(TypeCategory.Group) >= 0) { r.results.push(this.toGroupItem(node)); } else { logger.warn( `groups.assembler toGroupMembersList: unsupported template: ${node.types}` ); } } logger.silly(`groups.assembler toGroupModelList: exit: r: ${JSON.stringify(r)}`); return r; } }